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:
authorAntony Riakiotakis <kalast@gmail.com>2015-06-10 19:38:23 +0300
committerAntony Riakiotakis <kalast@gmail.com>2015-06-10 19:38:23 +0300
commit080cf9332bc9d71e0e14326bc8efdf06b738dea1 (patch)
treee8531a509dca4d8253aa19d89edc68152421f9e5
parent6d495cc4ef071171ff0686b2be898a41e05b8051 (diff)
parent9676642cc94599b3419c9aaa5cf1aae2fbbd235f (diff)
Merge branch 'gooseberry' into temp_motionpathstemp_motionpaths
Conflicts: source/blender/blenkernel/intern/object.c
-rw-r--r--CMakeLists.txt179
-rw-r--r--GNUmakefile6
-rw-r--r--SConstruct90
-rwxr-xr-xbuild_files/build_environment/install_deps.sh225
-rw-r--r--build_files/buildbot/config/user-config-glibc211-i686.py13
-rw-r--r--build_files/buildbot/config/user-config-glibc211-x86_64.py13
-rw-r--r--build_files/buildbot/config/user-config-mac-i386.py2
-rw-r--r--build_files/buildbot/config/user-config-mac-x86_64.py3
-rw-r--r--build_files/buildbot/config/user-config-player-glibc211-i686.py13
-rw-r--r--build_files/buildbot/config/user-config-player-glibc211-x86_64.py13
-rw-r--r--build_files/buildbot/master_unpack.py4
-rw-r--r--build_files/buildbot/slave_compile.py4
-rw-r--r--build_files/cmake/Modules/FindAlembic.cmake103
-rw-r--r--build_files/cmake/Modules/FindEigen3.cmake56
-rw-r--r--build_files/cmake/Modules/FindHDF5.cmake75
-rw-r--r--build_files/cmake/Modules/FindLLVM.cmake94
-rw-r--r--build_files/cmake/Modules/FindLZO.cmake68
-rw-r--r--build_files/cmake/Modules/FindPCRE.cmake1
-rw-r--r--build_files/cmake/Modules/FindPythonLibsUnix.cmake46
-rw-r--r--build_files/cmake/buildinfo.cmake3
-rwxr-xr-xbuild_files/cmake/cmake_consistency_check.py174
-rw-r--r--build_files/cmake/cmake_consistency_check_config.py3
-rwxr-xr-xbuild_files/cmake/cmake_netbeans_project.py25
-rwxr-xr-xbuild_files/cmake/cmake_qtcreator_project.py42
-rw-r--r--build_files/cmake/macros.cmake34
-rw-r--r--build_files/cmake/packaging.cmake9
-rw-r--r--build_files/package_spec/pacman/PKGBUILD10
-rw-r--r--build_files/scons/config/linux-config.py20
-rw-r--r--build_files/scons/tools/Blender.py50
-rw-r--r--build_files/scons/tools/btools.py25
-rw-r--r--doc/doxygen/Doxyfile2386
-rw-r--r--doc/doxygen/doxygen.extern.h (renamed from doc/doxygen/doxygen.extern)0
-rw-r--r--doc/doxygen/doxygen.intern.h (renamed from doc/doxygen/doxygen.intern)12
-rw-r--r--doc/doxygen/doxygen.main.h (renamed from doc/doxygen/doxygen.main)0
-rw-r--r--doc/doxygen/doxygen.source.h (renamed from doc/doxygen/doxygen.source)40
-rw-r--r--doc/python_api/examples/bge.constraints.py8
-rw-r--r--doc/python_api/examples/bpy.ops.2.py13
-rw-r--r--doc/python_api/examples/bpy.props.2.py2
-rw-r--r--doc/python_api/examples/bpy.props.py2
-rw-r--r--doc/python_api/examples/bpy.types.Menu.2.py7
-rw-r--r--doc/python_api/examples/bpy.types.Menu.py13
-rw-r--r--doc/python_api/rst/bge.constraints.rst57
-rw-r--r--doc/python_api/rst/bge.render.rst127
-rw-r--r--doc/python_api/rst/bge_types/bge.types.KX_ConstraintWrapper.rst31
-rw-r--r--doc/python_api/rst/bge_types/bge.types.KX_FontObject.rst22
-rw-r--r--doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst36
-rw-r--r--doc/python_api/rst/bge_types/bge.types.KX_Scene.rst22
-rw-r--r--doc/python_api/rst/bge_types/bge.types.KX_WorldInfo.rst79
-rw-r--r--doc/python_api/rst/bge_types/bge.types.SCA_ISensor.rst10
-rw-r--r--doc/python_api/rst/info_gotcha.rst8
-rw-r--r--doc/python_api/sphinx_doc_gen.py79
-rw-r--r--extern/CMakeLists.txt7
-rw-r--r--extern/bullet2/src/Bullet-C-Api.h1
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h2
-rw-r--r--extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp6
-rw-r--r--extern/clew/include/clew.h24
-rw-r--r--extern/libmv/CMakeLists.txt2
-rwxr-xr-xextern/libmv/bundle.sh2
-rw-r--r--extern/libmv/intern/stub.cc14
-rw-r--r--extern/libmv/libmv/autotrack/autotrack.cc1
-rw-r--r--extern/libmv/libmv/multiview/homography.cc25
-rw-r--r--extern/libmv/third_party/ceres/CMakeLists.txt2
-rwxr-xr-xextern/libmv/third_party/ceres/bundle.sh2
-rw-r--r--extern/rangetree/range_tree_c_api.h6
-rw-r--r--intern/atomic/atomic_ops.h21
-rw-r--r--intern/audaspace/CMakeLists.txt2
-rw-r--r--intern/audaspace/OpenAL/AUD_OpenALDevice.cpp83
-rw-r--r--intern/audaspace/OpenAL/AUD_OpenALDevice.h2
-rw-r--r--intern/audaspace/intern/AUD_AnimateableProperty.cpp10
-rw-r--r--intern/audaspace/intern/AUD_C-API.cpp4
-rw-r--r--intern/audaspace/intern/AUD_Sequencer.cpp3
-rw-r--r--intern/audaspace/intern/AUD_Sequencer.h2
-rw-r--r--intern/audaspace/intern/AUD_SequencerReader.cpp5
-rw-r--r--intern/cycles/CMakeLists.txt25
-rw-r--r--intern/cycles/SConscript22
-rw-r--r--intern/cycles/app/CMakeLists.txt23
-rw-r--r--intern/cycles/app/cycles_alembic.cpp426
-rw-r--r--intern/cycles/app/cycles_alembic.h36
-rw-r--r--intern/cycles/app/cycles_server.cpp3
-rw-r--r--intern/cycles/app/cycles_standalone.cpp82
-rw-r--r--intern/cycles/app/cycles_xml.cpp115
-rw-r--r--intern/cycles/blender/CMakeLists.txt2
-rw-r--r--intern/cycles/blender/addon/__init__.py10
-rw-r--r--intern/cycles/blender/addon/engine.py4
-rw-r--r--intern/cycles/blender/addon/properties.py38
-rw-r--r--intern/cycles/blender/addon/ui.py172
-rw-r--r--intern/cycles/blender/addon/version_update.py34
-rw-r--r--intern/cycles/blender/blender_camera.cpp71
-rw-r--r--intern/cycles/blender/blender_curves.cpp743
-rw-r--r--intern/cycles/blender/blender_mesh.cpp101
-rw-r--r--intern/cycles/blender/blender_object.cpp131
-rw-r--r--intern/cycles/blender/blender_particles.cpp2
-rw-r--r--intern/cycles/blender/blender_python.cpp37
-rw-r--r--intern/cycles/blender/blender_session.cpp188
-rw-r--r--intern/cycles/blender/blender_session.h5
-rw-r--r--intern/cycles/blender/blender_shader.cpp320
-rw-r--r--intern/cycles/blender/blender_sync.cpp42
-rw-r--r--intern/cycles/blender/blender_sync.h30
-rw-r--r--intern/cycles/blender/blender_texture.cpp116
-rw-r--r--intern/cycles/blender/blender_texture.h (renamed from intern/cycles/render/blackbody.h)15
-rw-r--r--intern/cycles/blender/blender_util.h46
-rw-r--r--intern/cycles/bvh/bvh.cpp253
-rw-r--r--intern/cycles/bvh/bvh.h11
-rw-r--r--intern/cycles/bvh/bvh_binning.cpp8
-rw-r--r--intern/cycles/bvh/bvh_build.cpp21
-rw-r--r--intern/cycles/bvh/bvh_node.h3
-rw-r--r--intern/cycles/bvh/bvh_params.h8
-rw-r--r--intern/cycles/bvh/bvh_split.cpp2
-rw-r--r--intern/cycles/cmake/external_libs.cmake2
-rw-r--r--intern/cycles/device/device.cpp85
-rw-r--r--intern/cycles/device/device.h82
-rw-r--r--intern/cycles/device/device_cpu.cpp25
-rw-r--r--intern/cycles/device/device_cuda.cpp93
-rw-r--r--intern/cycles/device/device_multi.cpp11
-rw-r--r--intern/cycles/device/device_network.cpp21
-rw-r--r--intern/cycles/device/device_opencl.cpp2665
-rw-r--r--intern/cycles/device/device_task.cpp2
-rw-r--r--intern/cycles/device/device_task.h11
-rw-r--r--intern/cycles/kernel/CMakeLists.txt84
-rw-r--r--intern/cycles/kernel/SConscript9
-rw-r--r--intern/cycles/kernel/closure/bsdf.h100
-rw-r--r--intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h14
-rw-r--r--intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h6
-rw-r--r--intern/cycles/kernel/closure/bsdf_diffuse_ramp.h2
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet.h193
-rw-r--r--intern/cycles/kernel/closure/bsdf_oren_nayar.h2
-rw-r--r--intern/cycles/kernel/closure/bsdf_phong_ramp.h4
-rw-r--r--intern/cycles/kernel/closure/bsdf_toon.h8
-rw-r--r--intern/cycles/kernel/closure/bssrdf.h8
-rw-r--r--intern/cycles/kernel/geom/geom.h2
-rw-r--r--intern/cycles/kernel/geom/geom_attribute.h8
-rw-r--r--intern/cycles/kernel/geom/geom_bvh.h113
-rw-r--r--intern/cycles/kernel/geom/geom_bvh_shadow.h6
-rw-r--r--intern/cycles/kernel/geom/geom_bvh_subsurface.h4
-rw-r--r--intern/cycles/kernel/geom/geom_bvh_traversal.h4
-rw-r--r--intern/cycles/kernel/geom/geom_bvh_volume.h4
-rw-r--r--intern/cycles/kernel/geom/geom_bvh_volume_all.h454
-rw-r--r--intern/cycles/kernel/geom/geom_curve.h130
-rw-r--r--intern/cycles/kernel/geom/geom_motion_triangle.h44
-rw-r--r--intern/cycles/kernel/geom/geom_object.h75
-rw-r--r--intern/cycles/kernel/geom/geom_primitive.h38
-rw-r--r--intern/cycles/kernel/geom/geom_qbvh_shadow.h10
-rw-r--r--intern/cycles/kernel/geom/geom_qbvh_subsurface.h4
-rw-r--r--intern/cycles/kernel/geom/geom_qbvh_traversal.h4
-rw-r--r--intern/cycles/kernel/geom/geom_qbvh_volume.h4
-rw-r--r--intern/cycles/kernel/geom/geom_qbvh_volume_all.h446
-rw-r--r--intern/cycles/kernel/geom/geom_triangle.h42
-rw-r--r--intern/cycles/kernel/geom/geom_triangle_intersect.h171
-rw-r--r--intern/cycles/kernel/geom/geom_volume.h22
-rw-r--r--intern/cycles/kernel/kernel_accumulate.h2
-rw-r--r--intern/cycles/kernel/kernel_bake.h6
-rw-r--r--intern/cycles/kernel/kernel_camera.h57
-rw-r--r--intern/cycles/kernel/kernel_compat_cpu.h10
-rw-r--r--intern/cycles/kernel/kernel_compat_cuda.h9
-rw-r--r--intern/cycles/kernel/kernel_compat_opencl.h16
-rw-r--r--intern/cycles/kernel/kernel_debug.h2
-rw-r--r--intern/cycles/kernel/kernel_differential.h6
-rw-r--r--intern/cycles/kernel/kernel_emission.h91
-rw-r--r--intern/cycles/kernel/kernel_film.h10
-rw-r--r--intern/cycles/kernel/kernel_globals.h6
-rw-r--r--intern/cycles/kernel/kernel_jitter.h10
-rw-r--r--intern/cycles/kernel/kernel_light.h411
-rw-r--r--intern/cycles/kernel/kernel_passes.h40
-rw-r--r--intern/cycles/kernel/kernel_path.h97
-rw-r--r--intern/cycles/kernel/kernel_path_common.h50
-rw-r--r--intern/cycles/kernel/kernel_path_state.h8
-rw-r--r--intern/cycles/kernel/kernel_path_surface.h48
-rw-r--r--intern/cycles/kernel/kernel_path_volume.h10
-rw-r--r--intern/cycles/kernel/kernel_projection.h8
-rw-r--r--intern/cycles/kernel/kernel_queues.h132
-rw-r--r--intern/cycles/kernel/kernel_random.h18
-rw-r--r--intern/cycles/kernel/kernel_shader.h309
-rw-r--r--intern/cycles/kernel/kernel_shaderdata_vars.h99
-rw-r--r--intern/cycles/kernel/kernel_shadow.h68
-rw-r--r--intern/cycles/kernel/kernel_textures.h1
-rw-r--r--intern/cycles/kernel/kernel_types.h251
-rw-r--r--intern/cycles/kernel/kernel_volume.h113
-rw-r--r--intern/cycles/kernel/kernel_work_stealing.h193
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel.cpp (renamed from intern/cycles/kernel/kernel.cpp)4
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_avx.cpp (renamed from intern/cycles/kernel/kernel_avx.cpp)0
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_avx2.cpp (renamed from intern/cycles/kernel/kernel_avx2.cpp)0
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_sse2.cpp (renamed from intern/cycles/kernel/kernel_sse2.cpp)0
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_sse3.cpp (renamed from intern/cycles/kernel/kernel_sse3.cpp)0
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_sse41.cpp (renamed from intern/cycles/kernel/kernel_sse41.cpp)0
-rw-r--r--intern/cycles/kernel/kernels/cuda/kernel.cu (renamed from intern/cycles/kernel/kernel.cu)14
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel.cl (renamed from intern/cycles/kernel/kernel.cl)106
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_background_buffer_update.cl128
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_data_init.cl241
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_direct_lighting.cl90
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl124
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_lamp_emission.cl84
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_next_iteration_setup.cl115
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_queue_enqueue.cl106
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_scene_intersect.cl82
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_shader_eval.cl69
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_shadow_blocked.cl83
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_sum_all_radiance.cl38
-rw-r--r--intern/cycles/kernel/osl/SConscript12
-rw-r--r--intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp1
-rw-r--r--intern/cycles/kernel/osl/bsdf_phong_ramp.cpp1
-rw-r--r--intern/cycles/kernel/osl/osl_bssrdf.cpp1
-rw-r--r--intern/cycles/kernel/osl/osl_closures.h8
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp182
-rw-r--r--intern/cycles/kernel/osl/osl_shader.cpp45
-rw-r--r--intern/cycles/kernel/shaders/node_image_texture.osl6
-rw-r--r--intern/cycles/kernel/shaders/node_math.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_musgrave_texture.osl25
-rw-r--r--intern/cycles/kernel/shaders/node_noise_texture.osl17
-rw-r--r--intern/cycles/kernel/shaders/node_texture.h106
-rw-r--r--intern/cycles/kernel/shaders/node_voronoi_texture.osl2
-rw-r--r--intern/cycles/kernel/shaders/node_wave_texture.osl2
-rw-r--r--intern/cycles/kernel/split/kernel_background_buffer_update.h255
-rw-r--r--intern/cycles/kernel/split/kernel_data_init.h418
-rw-r--r--intern/cycles/kernel/split/kernel_direct_lighting.h116
-rw-r--r--intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h264
-rw-r--r--intern/cycles/kernel/split/kernel_lamp_emission.h179
-rw-r--r--intern/cycles/kernel/split/kernel_next_iteration_setup.h145
-rw-r--r--intern/cycles/kernel/split/kernel_scene_intersect.h135
-rw-r--r--intern/cycles/kernel/split/kernel_shader_eval.h75
-rw-r--r--intern/cycles/kernel/split/kernel_shadow_blocked.h99
-rw-r--r--intern/cycles/kernel/split/kernel_split_common.h62
-rw-r--r--intern/cycles/kernel/split/kernel_sum_all_radiance.h59
-rw-r--r--intern/cycles/kernel/svm/svm.h298
-rw-r--r--intern/cycles/kernel/svm/svm_attribute.h6
-rw-r--r--intern/cycles/kernel/svm/svm_blackbody.h40
-rw-r--r--intern/cycles/kernel/svm/svm_brick.h2
-rw-r--r--intern/cycles/kernel/svm/svm_brightness.h2
-rw-r--r--intern/cycles/kernel/svm/svm_camera.h8
-rw-r--r--intern/cycles/kernel/svm/svm_closure.h158
-rw-r--r--intern/cycles/kernel/svm/svm_displace.h10
-rw-r--r--intern/cycles/kernel/svm/svm_fresnel.h14
-rw-r--r--intern/cycles/kernel/svm/svm_gamma.h8
-rw-r--r--intern/cycles/kernel/svm/svm_geometry.h42
-rw-r--r--intern/cycles/kernel/svm/svm_gradient.h2
-rw-r--r--intern/cycles/kernel/svm/svm_hsv.h4
-rw-r--r--intern/cycles/kernel/svm/svm_image.h16
-rw-r--r--intern/cycles/kernel/svm/svm_invert.h2
-rw-r--r--intern/cycles/kernel/svm/svm_light_path.h14
-rw-r--r--intern/cycles/kernel/svm/svm_math_util.h64
-rw-r--r--intern/cycles/kernel/svm/svm_mix.h8
-rw-r--r--intern/cycles/kernel/svm/svm_musgrave.h24
-rw-r--r--intern/cycles/kernel/svm/svm_noisetex.h13
-rw-r--r--intern/cycles/kernel/svm/svm_normal.h4
-rw-r--r--intern/cycles/kernel/svm/svm_ramp.h2
-rw-r--r--intern/cycles/kernel/svm/svm_sepcomb_hsv.h8
-rw-r--r--intern/cycles/kernel/svm/svm_sepcomb_vector.h8
-rw-r--r--intern/cycles/kernel/svm/svm_tex_coord.h114
-rw-r--r--intern/cycles/kernel/svm/svm_texture.h258
-rw-r--r--intern/cycles/kernel/svm/svm_types.h53
-rw-r--r--intern/cycles/kernel/svm/svm_vector_transform.h6
-rw-r--r--intern/cycles/kernel/svm/svm_voronoi.h86
-rw-r--r--intern/cycles/kernel/svm/svm_voxel.h61
-rw-r--r--intern/cycles/kernel/svm/svm_wave.h2
-rw-r--r--intern/cycles/kernel/svm/svm_wavelength.h2
-rw-r--r--intern/cycles/kernel/svm/svm_wireframe.h45
-rw-r--r--intern/cycles/render/CMakeLists.txt2
-rw-r--r--intern/cycles/render/attribute.cpp2
-rw-r--r--intern/cycles/render/attribute.h1
-rw-r--r--intern/cycles/render/background.cpp2
-rw-r--r--intern/cycles/render/bake.cpp12
-rw-r--r--intern/cycles/render/bake.h1
-rw-r--r--intern/cycles/render/blackbody.cpp140
-rw-r--r--intern/cycles/render/buffers.cpp10
-rw-r--r--intern/cycles/render/camera.cpp30
-rw-r--r--intern/cycles/render/camera.h6
-rw-r--r--intern/cycles/render/curves.cpp10
-rw-r--r--intern/cycles/render/film.cpp8
-rw-r--r--intern/cycles/render/graph.cpp93
-rw-r--r--intern/cycles/render/graph.h24
-rw-r--r--intern/cycles/render/image.cpp60
-rw-r--r--intern/cycles/render/image.h7
-rw-r--r--intern/cycles/render/integrator.cpp2
-rw-r--r--intern/cycles/render/light.cpp239
-rw-r--r--intern/cycles/render/light.h2
-rw-r--r--intern/cycles/render/mesh.cpp139
-rw-r--r--intern/cycles/render/mesh.h15
-rw-r--r--intern/cycles/render/nodes.cpp185
-rw-r--r--intern/cycles/render/nodes.h118
-rw-r--r--intern/cycles/render/object.cpp50
-rw-r--r--intern/cycles/render/object.h6
-rw-r--r--intern/cycles/render/osl.cpp50
-rw-r--r--intern/cycles/render/particles.cpp6
-rw-r--r--intern/cycles/render/scene.cpp20
-rw-r--r--intern/cycles/render/scene.h8
-rw-r--r--intern/cycles/render/session.cpp86
-rw-r--r--intern/cycles/render/session.h16
-rw-r--r--intern/cycles/render/shader.cpp81
-rw-r--r--intern/cycles/render/shader.h16
-rw-r--r--intern/cycles/render/sky_model.cpp433
-rw-r--r--intern/cycles/render/sky_model.h296
-rw-r--r--intern/cycles/render/sky_model_data.h29
-rw-r--r--intern/cycles/render/svm.cpp12
-rw-r--r--intern/cycles/render/tables.cpp3
-rw-r--r--intern/cycles/render/tile.cpp3
-rw-r--r--intern/cycles/subd/subd_mesh.cpp6
-rw-r--r--intern/cycles/util/util_aligned_malloc.cpp2
-rw-r--r--intern/cycles/util/util_atomic.h36
-rw-r--r--intern/cycles/util/util_cache.h2
-rw-r--r--intern/cycles/util/util_foreach.h8
-rw-r--r--intern/cycles/util/util_function.h27
-rw-r--r--intern/cycles/util/util_guarded_allocator.h1
-rw-r--r--intern/cycles/util/util_half.h30
-rw-r--r--intern/cycles/util/util_hash.h2
-rw-r--r--intern/cycles/util/util_map.h27
-rw-r--r--intern/cycles/util/util_math.h13
-rw-r--r--intern/cycles/util/util_math_fast.h10
-rw-r--r--intern/cycles/util/util_optimization.h23
-rw-r--r--intern/cycles/util/util_progress.h12
-rw-r--r--intern/cycles/util/util_set.h12
-rw-r--r--intern/cycles/util/util_simd.h6
-rw-r--r--intern/cycles/util/util_string.cpp17
-rw-r--r--intern/cycles/util/util_string.h2
-rw-r--r--intern/cycles/util/util_system.cpp19
-rw-r--r--intern/cycles/util/util_task.cpp2
-rw-r--r--intern/cycles/util/util_task.h2
-rw-r--r--intern/cycles/util/util_thread.h21
-rw-r--r--intern/cycles/util/util_time.cpp2
-rw-r--r--intern/cycles/util/util_transform.cpp16
-rw-r--r--intern/cycles/util/util_transform.h34
-rw-r--r--intern/cycles/util/util_types.h18
-rw-r--r--intern/cycles/util/util_view.cpp3
-rw-r--r--intern/dualcon/CMakeLists.txt2
-rw-r--r--intern/dualcon/intern/Projections.cpp2
-rw-r--r--intern/dualcon/intern/dualcon_c_api.cpp2
-rw-r--r--intern/dualcon/intern/octree.cpp8
-rw-r--r--intern/ghost/CMakeLists.txt9
-rw-r--r--intern/ghost/GHOST_C-api.h10
-rw-r--r--intern/ghost/GHOST_ISystem.h2
-rw-r--r--intern/ghost/GHOST_IWindow.h4
-rw-r--r--intern/ghost/GHOST_Types.h8
-rw-r--r--intern/ghost/intern/GHOST_Context.h2
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.mm7
-rw-r--r--intern/ghost/intern/GHOST_ContextWGL.cpp14
-rw-r--r--intern/ghost/intern/GHOST_Debug.h2
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerX11.cpp5
-rw-r--r--intern/ghost/intern/GHOST_DropTargetX11.cpp3
-rw-r--r--intern/ghost/intern/GHOST_EventDragnDrop.h1
-rw-r--r--intern/ghost/intern/GHOST_EventPrinter.cpp3
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerX11.cpp2
-rw-r--r--intern/ghost/intern/GHOST_System.cpp4
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm9
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsCocoa.mm9
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsX11.cpp2
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp8
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp6
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.h12
-rw-r--r--intern/ghost/intern/GHOST_Window.cpp2
-rw-r--r--intern/ghost/intern/GHOST_Window.h4
-rw-r--r--intern/ghost/intern/GHOST_WindowManager.cpp2
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h2
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp62
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.h4
-rw-r--r--intern/ghost/test/CMakeLists.txt11
-rw-r--r--intern/ghost/test/gears/GHOST_C-Test.c34
-rw-r--r--intern/ghost/test/gears/GHOST_Test.cpp17
-rw-r--r--intern/ghost/test/multitest/MultiTest.c39
-rw-r--r--intern/guardedalloc/MEM_guardedalloc.h18
-rw-r--r--intern/guardedalloc/intern/mallocn_guarded_impl.c2
-rw-r--r--intern/iksolver/extern/IK_solver.h10
-rw-r--r--intern/itasc/CMakeLists.txt469
-rw-r--r--intern/locale/CMakeLists.txt6
-rw-r--r--intern/memutil/MEM_CacheLimiter.h13
-rw-r--r--intern/memutil/MEM_RefCountPtr.h17
-rw-r--r--intern/memutil/MEM_SmartPtr.h16
-rw-r--r--intern/opencolorio/fallback_impl.cc15
-rw-r--r--intern/opencolorio/ocio_capi.cc5
-rw-r--r--intern/opencolorio/ocio_capi.h2
-rw-r--r--intern/opencolorio/ocio_impl.cc10
-rw-r--r--intern/opencolorio/ocio_impl.h6
-rw-r--r--intern/smoke/extern/smoke_API.h3
-rw-r--r--intern/smoke/intern/WTURBULENCE.cpp100
-rw-r--r--intern/smoke/intern/WTURBULENCE.h7
-rw-r--r--intern/smoke/intern/smoke_API.cpp11
-rwxr-xr-xrelease/bin/blender-thumbnailer.py6
-rw-r--r--release/datafiles/brushicons/hairadd.pngbin0 -> 3341 bytes
-rw-r--r--release/datafiles/brushicons/haircomb.pngbin0 -> 3341 bytes
-rw-r--r--release/datafiles/brushicons/haircut.pngbin0 -> 3341 bytes
-rw-r--r--release/datafiles/brushicons/hairlength.pngbin0 -> 3341 bytes
-rw-r--r--release/datafiles/brushicons/hairpuff.pngbin0 -> 3341 bytes
-rw-r--r--release/datafiles/brushicons/hairsmooth.pngbin0 -> 3341 bytes
-rw-r--r--release/datafiles/brushicons/hairweight.pngbin0 -> 3341 bytes
-rw-r--r--release/datafiles/fonts/droidsans.ttf.gzbin2644887 -> 2466802 bytes
m---------release/datafiles/locale0
-rw-r--r--release/datafiles/splash.pngbin255011 -> 166788 bytes
-rw-r--r--release/datafiles/splash_2x.pngbin877592 -> 625100 bytes
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/freestyle/modules/freestyle/functions.py6
-rw-r--r--release/scripts/freestyle/modules/freestyle/predicates.py53
-rw-r--r--release/scripts/freestyle/modules/freestyle/shaders.py8
-rw-r--r--release/scripts/freestyle/modules/freestyle/utils.py110
-rw-r--r--release/scripts/freestyle/modules/parameter_editor.py15
-rw-r--r--release/scripts/modules/addon_utils.py95
-rw-r--r--release/scripts/modules/bl_i18n_utils/bl_extract_messages.py19
-rw-r--r--release/scripts/modules/bl_i18n_utils/settings.py4
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils.py17
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils_spell_check.py3
-rw-r--r--release/scripts/modules/bpy/path.py9
-rw-r--r--release/scripts/modules/bpy/utils/__init__.py (renamed from release/scripts/modules/bpy/utils.py)5
-rw-r--r--release/scripts/modules/bpy/utils/previews.py153
-rw-r--r--release/scripts/modules/bpy_extras/anim_utils.py303
-rw-r--r--release/scripts/modules/bpy_extras/io_utils.py39
-rw-r--r--release/scripts/modules/bpy_extras/object_utils.py13
-rw-r--r--release/scripts/modules/bpy_extras/view3d_utils.py18
-rw-r--r--release/scripts/modules/bpy_types.py40
-rw-r--r--release/scripts/modules/nodeitems_utils.py10
-rw-r--r--release/scripts/modules/rna_info.py9
-rw-r--r--release/scripts/modules/rna_prop_ui.py13
-rw-r--r--release/scripts/modules/rna_xml.py2
-rw-r--r--release/scripts/presets/interface_theme/back_to_black.xml28
-rw-r--r--release/scripts/presets/interface_theme/blender_24x.xml28
-rw-r--r--release/scripts/presets/interface_theme/elsyiun.xml28
-rw-r--r--release/scripts/presets/interface_theme/flatty_light.xml45
-rw-r--r--release/scripts/presets/interface_theme/graph.xml28
-rw-r--r--release/scripts/presets/interface_theme/hexagon.xml28
-rw-r--r--release/scripts/presets/interface_theme/rtheme.xml2
-rw-r--r--release/scripts/presets/interface_theme/science_lab.xml28
-rw-r--r--release/scripts/presets/interface_theme/softimage.xml28
-rw-r--r--release/scripts/presets/interface_theme/ubuntu_ambiance.xml28
-rw-r--r--release/scripts/presets/keyconfig/3dsmax.py3
-rw-r--r--release/scripts/presets/keyconfig/maya.py12
-rw-r--r--release/scripts/startup/bl_operators/__init__.py2
-rw-r--r--release/scripts/startup/bl_operators/add_mesh_torus.py18
-rw-r--r--release/scripts/startup/bl_operators/anim.py23
-rw-r--r--release/scripts/startup/bl_operators/clip.py12
-rw-r--r--release/scripts/startup/bl_operators/image.py3
-rw-r--r--release/scripts/startup/bl_operators/mask.py1
-rw-r--r--release/scripts/startup/bl_operators/mesh.py1
-rw-r--r--release/scripts/startup/bl_operators/object.py8
-rw-r--r--release/scripts/startup/bl_operators/object_align.py10
-rw-r--r--release/scripts/startup/bl_operators/object_quick_effects.py2
-rw-r--r--release/scripts/startup/bl_operators/presets.py159
-rw-r--r--release/scripts/startup/bl_operators/screen_play_rendered_anim.py11
-rw-r--r--release/scripts/startup/bl_operators/wm.py19
-rw-r--r--release/scripts/startup/bl_ui/__init__.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_constraint.py9
-rw-r--r--release/scripts/startup/bl_ui/properties_data_camera.py65
-rw-r--r--release/scripts/startup/bl_ui/properties_data_curve.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_lamp.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_data_mesh.py14
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py66
-rw-r--r--release/scripts/startup/bl_ui/properties_freestyle.py15
-rw-r--r--release/scripts/startup/bl_ui/properties_game.py43
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py6
-rw-r--r--release/scripts/startup/bl_ui/properties_mask_common.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_material.py19
-rw-r--r--release/scripts/startup/bl_ui/properties_object.py523
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py10
-rw-r--r--release/scripts/startup/bl_ui/properties_particle.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_common.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_smoke.py42
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py21
-rw-r--r--release/scripts/startup/bl_ui/properties_render_layer.py65
-rw-r--r--release/scripts/startup/bl_ui/properties_scene.py35
-rw-r--r--release/scripts/startup/bl_ui/properties_texture.py9
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py19
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py47
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py19
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py26
-rw-r--r--release/scripts/startup/bl_ui/space_image.py18
-rw-r--r--release/scripts/startup/bl_ui/space_info.py4
-rw-r--r--release/scripts/startup/bl_ui/space_logic.py11
-rw-r--r--release/scripts/startup/bl_ui/space_nla.py2
-rw-r--r--release/scripts/startup/bl_ui/space_node.py11
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py95
-rw-r--r--release/scripts/startup/bl_ui/space_time.py7
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py8
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py163
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py88
-rw-r--r--release/scripts/startup/nodeitems_builtins.py4
-rw-r--r--release/scripts/templates_py/addon_add_object.py5
-rw-r--r--release/scripts/templates_py/operator_modal_timer.py3
-rw-r--r--release/scripts/templates_py/ui_previews_custom_icon.py76
-rw-r--r--release/scripts/templates_py/ui_previews_dynamic_enum.py137
-rw-r--r--release/text/readme.html111
-rw-r--r--release/windows/installer/00.sconsblender.nsi7
-rw-r--r--source/blender/CMakeLists.txt4
-rw-r--r--source/blender/SConscript4
-rw-r--r--source/blender/avi/AVI_avi.h7
-rw-r--r--source/blender/avi/intern/avi_mjpeg.c43
-rw-r--r--source/blender/blenfont/BLF_api.h6
-rw-r--r--source/blender/blenfont/BLF_translation.h6
-rw-r--r--source/blender/blenfont/CMakeLists.txt10
-rw-r--r--source/blender/blenfont/SConscript5
-rw-r--r--source/blender/blenfont/intern/blf_font.c41
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c8
-rw-r--r--source/blender/blenfont/intern/blf_internal.h3
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h4
-rw-r--r--source/blender/blenfont/intern/blf_lang.c13
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c121
-rw-r--r--source/blender/blenfont/intern/blf_translation.c28
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h7
-rw-r--r--source/blender/blenkernel/BKE_action.h8
-rw-r--r--source/blender/blenkernel/BKE_addon.h2
-rw-r--r--source/blender/blenkernel/BKE_anim.h48
-rw-r--r--source/blender/blenkernel/BKE_animsys.h26
-rw-r--r--source/blender/blenkernel/BKE_appdir.h5
-rw-r--r--source/blender/blenkernel/BKE_armature.h54
-rw-r--r--source/blender/blenkernel/BKE_blender.h27
-rw-r--r--source/blender/blenkernel/BKE_bpath.h22
-rw-r--r--source/blender/blenkernel/BKE_brush.h35
-rw-r--r--source/blender/blenkernel/BKE_cache_library.h254
-rw-r--r--source/blender/blenkernel/BKE_camera.h39
-rw-r--r--source/blender/blenkernel/BKE_cloth.h4
-rw-r--r--source/blender/blenkernel/BKE_collision.h4
-rw-r--r--source/blender/blenkernel/BKE_colortools.h3
-rw-r--r--source/blender/blenkernel/BKE_constraint.h4
-rw-r--r--source/blender/blenkernel/BKE_context.h2
-rw-r--r--source/blender/blenkernel/BKE_curve.h13
-rw-r--r--source/blender/blenkernel/BKE_customdata.h4
-rw-r--r--source/blender/blenkernel/BKE_deform.h1
-rw-r--r--source/blender/blenkernel/BKE_depsgraph.h5
-rw-r--r--source/blender/blenkernel/BKE_displist.h5
-rw-r--r--source/blender/blenkernel/BKE_dynamicpaint.h6
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h4
-rw-r--r--source/blender/blenkernel/BKE_editmesh_bvh.h1
-rw-r--r--source/blender/blenkernel/BKE_editstrands.h104
-rw-r--r--source/blender/blenkernel/BKE_effect.h9
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h10
-rw-r--r--source/blender/blenkernel/BKE_fluidsim.h2
-rw-r--r--source/blender/blenkernel/BKE_font.h2
-rw-r--r--source/blender/blenkernel/BKE_freestyle.h3
-rw-r--r--source/blender/blenkernel/BKE_global.h5
-rw-r--r--source/blender/blenkernel/BKE_group.h2
-rw-r--r--source/blender/blenkernel/BKE_icons.h38
-rw-r--r--source/blender/blenkernel/BKE_image.h56
-rw-r--r--source/blender/blenkernel/BKE_key.h18
-rw-r--r--source/blender/blenkernel/BKE_lattice.h7
-rw-r--r--source/blender/blenkernel/BKE_library.h7
-rw-r--r--source/blender/blenkernel/BKE_linestyle.h4
-rw-r--r--source/blender/blenkernel/BKE_main.h1
-rw-r--r--source/blender/blenkernel/BKE_material.h3
-rw-r--r--source/blender/blenkernel/BKE_mball.h11
-rw-r--r--source/blender/blenkernel/BKE_mball_tessellate.h36
-rw-r--r--source/blender/blenkernel/BKE_mesh.h39
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h3
-rw-r--r--source/blender/blenkernel/BKE_mesh_remap.h1
-rw-r--r--source/blender/blenkernel/BKE_mesh_sample.h68
-rw-r--r--source/blender/blenkernel/BKE_modifier.h19
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h3
-rw-r--r--source/blender/blenkernel/BKE_multires.h7
-rw-r--r--source/blender/blenkernel/BKE_nla.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h15
-rw-r--r--source/blender/blenkernel/BKE_object.h66
-rw-r--r--source/blender/blenkernel/BKE_ocean.h26
-rw-r--r--source/blender/blenkernel/BKE_outliner_treehash.h (renamed from source/blender/blenkernel/BKE_treehash.h)19
-rw-r--r--source/blender/blenkernel/BKE_packedFile.h2
-rw-r--r--source/blender/blenkernel/BKE_paint.h12
-rw-r--r--source/blender/blenkernel/BKE_particle.h17
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h23
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h10
-rw-r--r--source/blender/blenkernel/BKE_rigidbody.h16
-rw-r--r--source/blender/blenkernel/BKE_sca.h1
-rw-r--r--source/blender/blenkernel/BKE_scene.h49
-rw-r--r--source/blender/blenkernel/BKE_screen.h7
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h21
-rw-r--r--source/blender/blenkernel/BKE_shrinkwrap.h1
-rw-r--r--source/blender/blenkernel/BKE_sound.h94
-rw-r--r--source/blender/blenkernel/BKE_strands.h358
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h4
-rw-r--r--source/blender/blenkernel/BKE_text.h3
-rw-r--r--source/blender/blenkernel/BKE_texture.h71
-rw-r--r--source/blender/blenkernel/BKE_tracking.h18
-rw-r--r--source/blender/blenkernel/BKE_writeavi.h18
-rw-r--r--source/blender/blenkernel/BKE_writeffmpeg.h14
-rw-r--r--source/blender/blenkernel/BKE_writeframeserver.h15
-rw-r--r--source/blender/blenkernel/CMakeLists.txt39
-rw-r--r--source/blender/blenkernel/SConscript5
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c79
-rw-r--r--source/blender/blenkernel/intern/action.c17
-rw-r--r--source/blender/blenkernel/intern/addon.c6
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c109
-rw-r--r--source/blender/blenkernel/intern/appdir.c172
-rw-r--r--source/blender/blenkernel/intern/armature.c542
-rw-r--r--source/blender/blenkernel/intern/armature_update.c697
-rw-r--r--source/blender/blenkernel/intern/blender.c42
-rw-r--r--source/blender/blenkernel/intern/bpath.c77
-rw-r--r--source/blender/blenkernel/intern/brush.c33
-rw-r--r--source/blender/blenkernel/intern/cache_library.c2256
-rw-r--r--source/blender/blenkernel/intern/camera.c290
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c27
-rw-r--r--source/blender/blenkernel/intern/cloth.c21
-rw-r--r--source/blender/blenkernel/intern/collision.c2
-rw-r--r--source/blender/blenkernel/intern/colortools.c12
-rw-r--r--source/blender/blenkernel/intern/constraint.c18
-rw-r--r--source/blender/blenkernel/intern/context.c2
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c8
-rw-r--r--source/blender/blenkernel/intern/curve.c111
-rw-r--r--source/blender/blenkernel/intern/customdata.c45
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c40
-rw-r--r--source/blender/blenkernel/intern/deform.c10
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c557
-rw-r--r--source/blender/blenkernel/intern/displist.c14
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c33
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c50
-rw-r--r--source/blender/blenkernel/intern/editmesh.c18
-rw-r--r--source/blender/blenkernel/intern/editstrands.c272
-rw-r--r--source/blender/blenkernel/intern/effect.c44
-rw-r--r--source/blender/blenkernel/intern/fcurve.c58
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c28
-rw-r--r--source/blender/blenkernel/intern/freestyle.c4
-rw-r--r--source/blender/blenkernel/intern/gpencil.c16
-rw-r--r--source/blender/blenkernel/intern/group.c7
-rw-r--r--source/blender/blenkernel/intern/icons.c351
-rw-r--r--source/blender/blenkernel/intern/idcode.c1
-rw-r--r--source/blender/blenkernel/intern/image.c1336
-rw-r--r--source/blender/blenkernel/intern/ipo.c26
-rw-r--r--source/blender/blenkernel/intern/key.c753
-rw-r--r--source/blender/blenkernel/intern/lamp.c4
-rw-r--r--source/blender/blenkernel/intern/lattice.c17
-rw-r--r--source/blender/blenkernel/intern/library.c65
-rw-r--r--source/blender/blenkernel/intern/linestyle.c13
-rw-r--r--source/blender/blenkernel/intern/mask_rasterize.c3
-rw-r--r--source/blender/blenkernel/intern/material.c40
-rw-r--r--source/blender/blenkernel/intern/mball.c1935
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c1325
-rw-r--r--source/blender/blenkernel/intern/mesh.c285
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c31
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c63
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c97
-rw-r--r--source/blender/blenkernel/intern/mesh_sample.c381
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c5
-rw-r--r--source/blender/blenkernel/intern/modifier.c59
-rw-r--r--source/blender/blenkernel/intern/modifiers_bmesh.c5
-rw-r--r--source/blender/blenkernel/intern/movieclip.c10
-rw-r--r--source/blender/blenkernel/intern/multires.c52
-rw-r--r--source/blender/blenkernel/intern/nla.c56
-rw-r--r--source/blender/blenkernel/intern/node.c26
-rw-r--r--source/blender/blenkernel/intern/object.c549
-rw-r--r--source/blender/blenkernel/intern/object_deform.c4
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c783
-rw-r--r--source/blender/blenkernel/intern/object_update.c355
-rw-r--r--source/blender/blenkernel/intern/ocean.c48
-rw-r--r--source/blender/blenkernel/intern/outliner_treehash.c (renamed from source/blender/blenkernel/intern/treehash.c)55
-rw-r--r--source/blender/blenkernel/intern/packedFile.c88
-rw-r--r--source/blender/blenkernel/intern/paint.c69
-rw-r--r--source/blender/blenkernel/intern/particle.c90
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c38
-rw-r--r--source/blender/blenkernel/intern/particle_system.c51
-rw-r--r--source/blender/blenkernel/intern/pbvh.c65
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c732
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h8
-rw-r--r--source/blender/blenkernel/intern/pointcache.c132
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c52
-rw-r--r--source/blender/blenkernel/intern/scene.c668
-rw-r--r--source/blender/blenkernel/intern/screen.c51
-rw-r--r--source/blender/blenkernel/intern/seqcache.c7
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c3
-rw-r--r--source/blender/blenkernel/intern/seqmodifier.c28
-rw-r--r--source/blender/blenkernel/intern/sequencer.c1083
-rw-r--r--source/blender/blenkernel/intern/smoke.c214
-rw-r--r--source/blender/blenkernel/intern/softbody.c62
-rw-r--r--source/blender/blenkernel/intern/sound.c277
-rw-r--r--source/blender/blenkernel/intern/speaker.c2
-rw-r--r--source/blender/blenkernel/intern/strands.c407
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c81
-rw-r--r--source/blender/blenkernel/intern/text.c172
-rw-r--r--source/blender/blenkernel/intern/texture.c130
-rw-r--r--source/blender/blenkernel/intern/tracking.c97
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c16
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c2
-rw-r--r--source/blender/blenkernel/intern/unit.c7
-rw-r--r--source/blender/blenkernel/intern/world.c4
-rw-r--r--source/blender/blenkernel/intern/writeavi.c107
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c420
-rw-r--r--source/blender/blenkernel/intern/writeframeserver.c132
-rw-r--r--source/blender/blenlib/BLI_array_utils.h8
-rw-r--r--source/blender/blenlib/BLI_blenlib.h1
-rw-r--r--source/blender/blenlib/BLI_callbacks.h1
-rw-r--r--source/blender/blenlib/BLI_compiler_compat.h12
-rw-r--r--source/blender/blenlib/BLI_compiler_typecheck.h299
-rw-r--r--source/blender/blenlib/BLI_edgehash.h1
-rw-r--r--source/blender/blenlib/BLI_fileops.h2
-rw-r--r--source/blender/blenlib/BLI_fileops_types.h18
-rw-r--r--source/blender/blenlib/BLI_ghash.h66
-rw-r--r--source/blender/blenlib/BLI_hash_mm2a.h2
-rw-r--r--source/blender/blenlib/BLI_linklist_stack.h10
-rw-r--r--source/blender/blenlib/BLI_math.h37
-rw-r--r--source/blender/blenlib/BLI_math_base.h4
-rw-r--r--source/blender/blenlib/BLI_math_bits.h51
-rw-r--r--source/blender/blenlib/BLI_math_color.h10
-rw-r--r--source/blender/blenlib/BLI_math_geom.h3
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h1
-rw-r--r--source/blender/blenlib/BLI_math_vector.h28
-rw-r--r--source/blender/blenlib/BLI_path_util.h8
-rw-r--r--source/blender/blenlib/BLI_quadric.h14
-rw-r--r--source/blender/blenlib/BLI_rect.h2
-rw-r--r--source/blender/blenlib/BLI_stack.h1
-rw-r--r--source/blender/blenlib/BLI_string.h2
-rw-r--r--source/blender/blenlib/BLI_task.h3
-rw-r--r--source/blender/blenlib/BLI_threads.h1
-rw-r--r--source/blender/blenlib/BLI_utildefines.h18
-rw-r--r--source/blender/blenlib/CMakeLists.txt20
-rw-r--r--source/blender/blenlib/intern/BLI_dynstr.c8
-rw-r--r--source/blender/blenlib/intern/BLI_filelist.c398
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c866
-rw-r--r--source/blender/blenlib/intern/BLI_heap.c2
-rw-r--r--source/blender/blenlib/intern/BLI_linklist.c2
-rw-r--r--source/blender/blenlib/intern/array_utils.c41
-rw-r--r--source/blender/blenlib/intern/astar.c2
-rw-r--r--source/blender/blenlib/intern/convexhull2d.c2
-rw-r--r--source/blender/blenlib/intern/edgehash.c66
-rw-r--r--source/blender/blenlib/intern/freetypefont.c3
-rw-r--r--source/blender/blenlib/intern/gsqueue.c8
-rw-r--r--source/blender/blenlib/intern/hash_md5.c3
-rw-r--r--source/blender/blenlib/intern/hash_mm2a.c44
-rw-r--r--source/blender/blenlib/intern/listbase.c2
-rw-r--r--source/blender/blenlib/intern/math_base.c41
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c19
-rw-r--r--source/blender/blenlib/intern/math_bits_inline.c59
-rw-r--r--source/blender/blenlib/intern/math_color_inline.c68
-rw-r--r--source/blender/blenlib/intern/math_geom.c102
-rw-r--r--source/blender/blenlib/intern/math_interp.c8
-rw-r--r--source/blender/blenlib/intern/math_matrix.c59
-rw-r--r--source/blender/blenlib/intern/math_rotation.c36
-rw-r--r--source/blender/blenlib/intern/math_vector.c78
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c47
-rw-r--r--source/blender/blenlib/intern/path_util.c268
-rw-r--r--source/blender/blenlib/intern/polyfill2d.c2
-rw-r--r--source/blender/blenlib/intern/polyfill2d_beautify.c10
-rw-r--r--source/blender/blenlib/intern/quadric.c65
-rw-r--r--source/blender/blenlib/intern/rand.c20
-rw-r--r--source/blender/blenlib/intern/rct.c43
-rw-r--r--source/blender/blenlib/intern/scanfill_utils.c10
-rw-r--r--source/blender/blenlib/intern/stack.c35
-rw-r--r--source/blender/blenlib/intern/storage.c314
-rw-r--r--source/blender/blenlib/intern/string.c43
-rw-r--r--source/blender/blenlib/intern/string_utf8.c10
-rw-r--r--source/blender/blenlib/intern/system.c10
-rw-r--r--source/blender/blenlib/intern/task.c24
-rw-r--r--source/blender/blenlib/intern/threads.c13
-rw-r--r--source/blender/blenlib/intern/timecode.c29
-rw-r--r--source/blender/blenloader/BLO_readfile.h5
-rw-r--r--source/blender/blenloader/BLO_undofile.h6
-rw-r--r--source/blender/blenloader/SConscript7
-rw-r--r--source/blender/blenloader/intern/readblenentry.c24
-rw-r--r--source/blender/blenloader/intern/readfile.c493
-rw-r--r--source/blender/blenloader/intern/readfile.h7
-rw-r--r--source/blender/blenloader/intern/undofile.c8
-rw-r--r--source/blender/blenloader/intern/versioning_250.c14
-rw-r--r--source/blender/blenloader/intern/versioning_260.c4
-rw-r--r--source/blender/blenloader/intern/versioning_270.c306
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c11
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c29
-rw-r--r--source/blender/blenloader/intern/writefile.c190
-rw-r--r--source/blender/bmesh/CMakeLists.txt4
-rw-r--r--source/blender/bmesh/bmesh.h2
-rw-r--r--source/blender/bmesh/bmesh_class.h38
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c288
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.h35
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c756
-rw-r--r--source/blender/bmesh/intern/bmesh_core.h64
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.c22
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.h22
-rw-r--r--source/blender/bmesh/intern/bmesh_inline.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c70
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.h6
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.c26
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.h19
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators_inline.h6
-rw-r--r--source/blender/bmesh/intern/bmesh_log.c81
-rw-r--r--source/blender/bmesh/intern/bmesh_log.h5
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c51
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.h26
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c56
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h9
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.c53
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.h9
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_validate.c11
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c51
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.h58
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c7
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api.h113
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api_inline.h49
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.c124
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.h18
-rw-r--r--source/blender/bmesh/intern/bmesh_operators_private.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c20
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.h10
-rw-r--r--source/blender/bmesh/intern/bmesh_private.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c464
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.h63
-rw-r--r--source/blender/bmesh/intern/bmesh_queries_inline.h10
-rw-r--r--source/blender/bmesh/intern/bmesh_strands.c145
-rw-r--r--source/blender/bmesh/intern/bmesh_strands.h215
-rw-r--r--source/blender/bmesh/intern/bmesh_strands_conv.c1314
-rw-r--r--source/blender/bmesh/intern/bmesh_strands_conv.h67
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.c115
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.h6
-rw-r--r--source/blender/bmesh/intern/bmesh_structure_inline.h5
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.c9
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.h18
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_impl.c308
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_private.h14
-rw-r--r--source/blender/bmesh/operators/bmo_bridge.c14
-rw-r--r--source/blender/bmesh/operators/bmo_connect_concave.c4
-rw-r--r--source/blender/bmesh/operators/bmo_connect_pair.c27
-rw-r--r--source/blender/bmesh/operators/bmo_dissolve.c2
-rw-r--r--source/blender/bmesh/operators/bmo_dupe.c31
-rw-r--r--source/blender/bmesh/operators/bmo_extrude.c70
-rw-r--r--source/blender/bmesh/operators/bmo_fill_attribute.c10
-rw-r--r--source/blender/bmesh/operators/bmo_fill_grid.c26
-rw-r--r--source/blender/bmesh/operators/bmo_hull.c47
-rw-r--r--source/blender/bmesh/operators/bmo_inset.c2
-rw-r--r--source/blender/bmesh/operators/bmo_join_triangles.c413
-rw-r--r--source/blender/bmesh/operators/bmo_normals.c2
-rw-r--r--source/blender/bmesh/operators/bmo_removedoubles.c12
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide.c128
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide_edgering.c47
-rw-r--r--source/blender/bmesh/operators/bmo_utils.c16
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.c24
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c582
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.h9
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate.h25
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c241
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_dissolve.c77
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.c18
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.h5
-rw-r--r--source/blender/bmesh/tools/bmesh_edgesplit.c112
-rw-r--r--source/blender/bmesh/tools/bmesh_edgesplit.h5
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c14
-rw-r--r--source/blender/bmesh/tools/bmesh_path.c6
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.c50
-rw-r--r--source/blender/bmesh/tools/bmesh_triangulate.c1
-rw-r--r--source/blender/bmesh/tools/bmesh_triangulate.h5
-rw-r--r--source/blender/bmesh/tools/bmesh_wireframe.c7
-rw-r--r--source/blender/collada/AnimationExporter.cpp6
-rw-r--r--source/blender/collada/AnimationExporter.h4
-rw-r--r--source/blender/collada/ArmatureImporter.cpp8
-rw-r--r--source/blender/collada/DocumentImporter.cpp4
-rw-r--r--source/blender/collada/DocumentImporter.h1
-rw-r--r--source/blender/collada/GeometryExporter.cpp53
-rw-r--r--source/blender/collada/GeometryExporter.h19
-rw-r--r--source/blender/collada/ImageExporter.cpp2
-rw-r--r--source/blender/collada/SceneExporter.cpp4
-rw-r--r--source/blender/collada/collada_utils.cpp7
-rw-r--r--source/blender/compositor/CMakeLists.txt4
-rw-r--r--source/blender/compositor/COM_compositor.h5
-rw-r--r--source/blender/compositor/intern/COM_CompositorContext.h17
-rw-r--r--source/blender/compositor/intern/COM_Converter.cpp8
-rw-r--r--source/blender/compositor/intern/COM_Debug.cpp6
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.cpp43
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.h5
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.cpp10
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.h6
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.h2
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.h22
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.cpp7
-rw-r--r--source/blender/compositor/intern/COM_OpenCLDevice.cpp4
-rw-r--r--source/blender/compositor/intern/COM_SingleThreadedOperation.cpp2
-rw-r--r--source/blender/compositor/intern/COM_SocketReader.h18
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.cpp5
-rw-r--r--source/blender/compositor/intern/COM_compositor.cpp8
-rw-r--r--source/blender/compositor/nodes/COM_AlphaOverNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_BokehImageNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_BrightnessNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ChannelMatteNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ChromaMatteNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ColorBalanceNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ColorCurveNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ColorMatteNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ColorNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ColorRampNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ColorSpillNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ColorToBWNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_CombineColorNode.cpp8
-rw-r--r--source/blender/compositor/nodes/COM_CompositorNode.cpp1
-rw-r--r--source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_CornerPinNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_CropNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_DespeckleNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_DistanceMatteNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_FilterNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_FlipNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_GammaNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_GlareNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.cpp107
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.h2
-rw-r--r--source/blender/compositor/nodes/COM_InpaintNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_InvertNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_LensDistortionNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_MapRangeNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_MapUVNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_MapValueNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_MathNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_MixNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_NormalNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_NormalizeNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_OutputFileNode.cpp46
-rw-r--r--source/blender/compositor/nodes/COM_PixelateNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_RenderLayersNode.cpp3
-rw-r--r--source/blender/compositor/nodes/COM_RotateNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_SeparateColorNode.cpp8
-rw-r--r--source/blender/compositor/nodes/COM_SetAlphaNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_SocketProxyNode.cpp4
-rw-r--r--source/blender/compositor/nodes/COM_SplitViewerNode.cpp4
-rw-r--r--source/blender/compositor/nodes/COM_SunBeamsNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_SwitchNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_SwitchViewNode.cpp42
-rw-r--r--source/blender/compositor/nodes/COM_SwitchViewNode.h37
-rw-r--r--source/blender/compositor/nodes/COM_TonemapNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_TransformNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ValueNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_VectorCurveNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ViewLevelsNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_ViewerNode.cpp5
-rw-r--r--source/blender/compositor/operations/COM_AntiAliasOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.cpp5
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_BokehBlurOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_BokehImageOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_CalculateMeanOperation.cpp12
-rw-r--r--source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp10
-rw-r--r--source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.cpp17
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_ConvertOperation.cpp5
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_CropOperation.cpp33
-rw-r--r--source/blender/compositor/operations/COM_DespeckleOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_DilateErodeOperation.cpp10
-rw-r--r--source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_DisplaceOperation.cpp12
-rw-r--r--source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_FlipOperation.cpp14
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_GlareBaseOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_GlareGhostOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_GlareThresholdOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.cpp19
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.h7
-rw-r--r--source/blender/compositor/operations/COM_InpaintOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_KeyingScreenOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_MapUVOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_MaskOperation.cpp3
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_MovieClipOperation.cpp10
-rw-r--r--source/blender/compositor/operations/COM_MovieDistortionOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_MultilayerImageOperation.cpp27
-rw-r--r--source/blender/compositor/operations/COM_MultilayerImageOperation.h11
-rw-r--r--source/blender/compositor/operations/COM_NormalizeOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp317
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h74
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cpp122
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.h19
-rw-r--r--source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_PreviewOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_PreviewOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ReadBufferOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.cpp14
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.h9
-rw-r--r--source/blender/compositor/operations/COM_ScaleOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_SetColorOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_SetSamplerOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_SetValueOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_SetVectorOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_SplitOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_SunBeamsOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_TonemapOperation.cpp12
-rw-r--r--source/blender/compositor/operations/COM_TrackPositionOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_TranslateOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp11
-rw-r--r--source/blender/compositor/operations/COM_VectorBlurOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.cpp17
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_WriteBufferOperation.cpp4
-rw-r--r--source/blender/depsgraph/CMakeLists.txt118
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h215
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h121
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_debug.h111
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h195
-rw-r--r--source/blender/depsgraph/SConscript74
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc473
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h224
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc370
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.h408
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build_nodes.cc1201
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build_relations.cc1841
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc1193
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.h87
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc394
-rw-r--r--source/blender/depsgraph/intern/depsgraph_intern.h168
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc217
-rw-r--r--source/blender/depsgraph/intern/depsgraph_queue.cc177
-rw-r--r--source/blender/depsgraph/intern/depsgraph_queue.h91
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc541
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type_defines.cc102
-rw-r--r--source/blender/depsgraph/intern/depsgraph_types.h173
-rw-r--r--source/blender/depsgraph/intern/depsnode.cc316
-rw-r--r--source/blender/depsgraph/intern/depsnode.h248
-rw-r--r--source/blender/depsgraph/intern/depsnode_component.cc318
-rw-r--r--source/blender/depsgraph/intern/depsnode_component.h201
-rw-r--r--source/blender/depsgraph/intern/depsnode_opcodes.h145
-rw-r--r--source/blender/depsgraph/intern/depsnode_operation.cc104
-rw-r--r--source/blender/depsgraph/intern/depsnode_operation.h90
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_cycle.cc140
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_cycle.h37
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_function.h112
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_hash.h72
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_map.h67
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_pchanmap.cc136
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_pchanmap.h59
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_set.h66
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_transitive.cc139
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_transitive.h38
-rw-r--r--source/blender/editors/CMakeLists.txt1
-rw-r--r--source/blender/editors/SConscript1
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c364
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c262
-rw-r--r--source/blender/editors/animation/anim_deps.c4
-rw-r--r--source/blender/editors/animation/anim_draw.c214
-rw-r--r--source/blender/editors/animation/anim_filter.c126
-rw-r--r--source/blender/editors/animation/anim_markers.c48
-rw-r--r--source/blender/editors/animation/anim_ops.c124
-rw-r--r--source/blender/editors/animation/drivers.c7
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c4
-rw-r--r--source/blender/editors/animation/keyframes_draw.c2
-rw-r--r--source/blender/editors/animation/keyframes_general.c133
-rw-r--r--source/blender/editors/animation/keyframing.c82
-rw-r--r--source/blender/editors/armature/BIF_retarget.h1
-rw-r--r--source/blender/editors/armature/armature_add.c344
-rw-r--r--source/blender/editors/armature/armature_edit.c100
-rw-r--r--source/blender/editors/armature/armature_intern.h1
-rw-r--r--source/blender/editors/armature/armature_naming.c4
-rw-r--r--source/blender/editors/armature/armature_ops.c4
-rw-r--r--source/blender/editors/armature/armature_relations.c16
-rw-r--r--source/blender/editors/armature/armature_select.c173
-rw-r--r--source/blender/editors/armature/armature_utils.c22
-rw-r--r--source/blender/editors/armature/editarmature_retarget.c4
-rw-r--r--source/blender/editors/armature/meshlaplacian.c8
-rw-r--r--source/blender/editors/armature/meshlaplacian.h2
-rw-r--r--source/blender/editors/armature/pose_edit.c9
-rw-r--r--source/blender/editors/armature/pose_group.c12
-rw-r--r--source/blender/editors/armature/pose_select.c106
-rw-r--r--source/blender/editors/armature/pose_slide.c152
-rw-r--r--source/blender/editors/armature/pose_transform.c2
-rw-r--r--source/blender/editors/curve/CMakeLists.txt1
-rw-r--r--source/blender/editors/curve/curve_intern.h3
-rw-r--r--source/blender/editors/curve/curve_ops.c1
-rw-r--r--source/blender/editors/curve/editcurve.c51
-rw-r--r--source/blender/editors/curve/editcurve_add.c20
-rw-r--r--source/blender/editors/curve/editfont.c57
-rw-r--r--source/blender/editors/curve/lorem.c658
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt7
-rw-r--r--source/blender/editors/datafiles/SConscript7
-rw-r--r--source/blender/editors/gpencil/CMakeLists.txt2
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c94
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c1484
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c447
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c1853
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h9
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c18
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c143
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c35
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c186
-rw-r--r--source/blender/editors/hair/CMakeLists.txt56
-rw-r--r--source/blender/editors/hair/SConscript54
-rw-r--r--source/blender/editors/hair/hair_cursor.c109
-rw-r--r--source/blender/editors/hair/hair_edit.c459
-rw-r--r--source/blender/editors/hair/hair_intern.h124
-rw-r--r--source/blender/editors/hair/hair_mirror.c210
-rw-r--r--source/blender/editors/hair/hair_object_cachelib.c104
-rw-r--r--source/blender/editors/hair/hair_object_particles.c101
-rw-r--r--source/blender/editors/hair/hair_ops.c143
-rw-r--r--source/blender/editors/hair/hair_select.c502
-rw-r--r--source/blender/editors/hair/hair_stroke.c498
-rw-r--r--source/blender/editors/hair/hair_undo.c190
-rw-r--r--source/blender/editors/include/BIF_glutil.h14
-rw-r--r--source/blender/editors/include/ED_anim_api.h28
-rw-r--r--source/blender/editors/include/ED_armature.h20
-rw-r--r--source/blender/editors/include/ED_buttons.h2
-rw-r--r--source/blender/editors/include/ED_curve.h5
-rw-r--r--source/blender/editors/include/ED_datafiles.h21
-rw-r--r--source/blender/editors/include/ED_gpencil.h4
-rw-r--r--source/blender/editors/include/ED_image.h4
-rw-r--r--source/blender/editors/include/ED_keyframes_draw.h1
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h2
-rw-r--r--source/blender/editors/include/ED_keyframing.h2
-rw-r--r--source/blender/editors/include/ED_lattice.h1
-rw-r--r--source/blender/editors/include/ED_mask.h1
-rw-r--r--source/blender/editors/include/ED_mball.h1
-rw-r--r--source/blender/editors/include/ED_mesh.h40
-rw-r--r--source/blender/editors/include/ED_node.h3
-rw-r--r--source/blender/editors/include/ED_object.h25
-rw-r--r--source/blender/editors/include/ED_outliner.h36
-rw-r--r--source/blender/editors/include/ED_paint.h7
-rw-r--r--source/blender/editors/include/ED_particle.h7
-rw-r--r--source/blender/editors/include/ED_physics.h26
-rw-r--r--source/blender/editors/include/ED_render.h18
-rw-r--r--source/blender/editors/include/ED_screen.h12
-rw-r--r--source/blender/editors/include/ED_sculpt.h1
-rw-r--r--source/blender/editors/include/ED_util.h13
-rw-r--r--source/blender/editors/include/ED_uvedit.h2
-rw-r--r--source/blender/editors/include/ED_view3d.h81
-rw-r--r--source/blender/editors/include/UI_icons.h7
-rw-r--r--source/blender/editors/include/UI_interface.h48
-rw-r--r--source/blender/editors/include/UI_interface_icons.h10
-rw-r--r--source/blender/editors/include/UI_resources.h9
-rw-r--r--source/blender/editors/include/UI_view2d.h1
-rw-r--r--source/blender/editors/interface/interface.c278
-rw-r--r--source/blender/editors/interface/interface_anim.c32
-rw-r--r--source/blender/editors/interface/interface_draw.c9
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c38
-rw-r--r--source/blender/editors/interface/interface_handlers.c1040
-rw-r--r--source/blender/editors/interface/interface_icons.c192
-rw-r--r--source/blender/editors/interface/interface_intern.h67
-rw-r--r--source/blender/editors/interface/interface_layout.c69
-rw-r--r--source/blender/editors/interface/interface_ops.c146
-rw-r--r--source/blender/editors/interface/interface_panel.c270
-rw-r--r--source/blender/editors/interface/interface_regions.c103
-rw-r--r--source/blender/editors/interface/interface_style.c8
-rw-r--r--source/blender/editors/interface/interface_templates.c321
-rw-r--r--source/blender/editors/interface/interface_utils.c68
-rw-r--r--source/blender/editors/interface/interface_widgets.c392
-rw-r--r--source/blender/editors/interface/resources.c38
-rw-r--r--source/blender/editors/interface/view2d.c215
-rw-r--r--source/blender/editors/interface/view2d_ops.c101
-rw-r--r--source/blender/editors/io/CMakeLists.txt5
-rw-r--r--source/blender/editors/io/SConscript5
-rw-r--r--source/blender/editors/io/io_cache_library.c961
-rw-r--r--source/blender/editors/io/io_cache_library.h56
-rw-r--r--source/blender/editors/io/io_cache_shapekey.c417
-rw-r--r--source/blender/editors/io/io_ops.c19
-rw-r--r--source/blender/editors/mask/mask_add.c14
-rw-r--r--source/blender/editors/mask/mask_draw.c4
-rw-r--r--source/blender/editors/mask/mask_intern.h1
-rw-r--r--source/blender/editors/mesh/editface.c2
-rw-r--r--source/blender/editors/mesh/editmesh_add.c5
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c2
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c2
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c5
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c2
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c68
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c2
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c6
-rw-r--r--source/blender/editors/mesh/editmesh_path.c2
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c258
-rw-r--r--source/blender/editors/mesh/editmesh_select.c1185
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c169
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c181
-rw-r--r--source/blender/editors/mesh/mesh_data.c76
-rw-r--r--source/blender/editors/mesh/mesh_intern.h10
-rw-r--r--source/blender/editors/mesh/mesh_navmesh.c3
-rw-r--r--source/blender/editors/mesh/mesh_ops.c5
-rw-r--r--source/blender/editors/mesh/meshtools.c8
-rw-r--r--source/blender/editors/metaball/mball_edit.c2
-rw-r--r--source/blender/editors/object/object_add.c57
-rw-r--r--source/blender/editors/object/object_bake_api.c46
-rw-r--r--source/blender/editors/object/object_constraint.c527
-rw-r--r--source/blender/editors/object/object_data_transfer.c9
-rw-r--r--source/blender/editors/object/object_edit.c96
-rw-r--r--source/blender/editors/object/object_hook.c5
-rw-r--r--source/blender/editors/object/object_intern.h11
-rw-r--r--source/blender/editors/object/object_lattice.c2
-rw-r--r--source/blender/editors/object/object_modifier.c110
-rw-r--r--source/blender/editors/object/object_ops.c6
-rw-r--r--source/blender/editors/object/object_random.c4
-rw-r--r--source/blender/editors/object/object_relations.c26
-rw-r--r--source/blender/editors/object/object_shapekey.c83
-rw-r--r--source/blender/editors/object/object_transform.c6
-rw-r--r--source/blender/editors/object/object_vgroup.c2
-rw-r--r--source/blender/editors/object/object_warp.c4
-rw-r--r--source/blender/editors/physics/particle_edit.c125
-rw-r--r--source/blender/editors/physics/physics_intern.h2
-rw-r--r--source/blender/editors/physics/physics_ops.c2
-rw-r--r--source/blender/editors/physics/rigidbody_object.c1
-rw-r--r--source/blender/editors/render/render_intern.h8
-rw-r--r--source/blender/editors/render/render_internal.c47
-rw-r--r--source/blender/editors/render/render_opengl.c380
-rw-r--r--source/blender/editors/render/render_ops.c4
-rw-r--r--source/blender/editors/render/render_preview.c191
-rw-r--r--source/blender/editors/render/render_shading.c151
-rw-r--r--source/blender/editors/render/render_update.c36
-rw-r--r--source/blender/editors/render/render_view.c10
-rw-r--r--source/blender/editors/screen/area.c405
-rw-r--r--source/blender/editors/screen/glutil.c74
-rw-r--r--source/blender/editors/screen/screen_context.c32
-rw-r--r--source/blender/editors/screen/screen_edit.c96
-rw-r--r--source/blender/editors/screen/screen_intern.h2
-rw-r--r--source/blender/editors/screen/screen_ops.c166
-rw-r--r--source/blender/editors/screen/screendump.c29
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c20
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve.c44
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c12
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c52
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c792
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h8
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c55
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c43
-rw-r--r--source/blender/editors/sculpt_paint/paint_undo.c17
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c17
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c15
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_proj.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c1247
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c8
-rw-r--r--source/blender/editors/sound/sound_intern.h1
-rw-r--r--source/blender/editors/sound/sound_ops.c14
-rw-r--r--source/blender/editors/space_action/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_action/action_data.c908
-rw-r--r--source/blender/editors/space_action/action_draw.c7
-rw-r--r--source/blender/editors/space_action/action_edit.c467
-rw-r--r--source/blender/editors/space_action/action_intern.h9
-rw-r--r--source/blender/editors/space_action/action_ops.c19
-rw-r--r--source/blender/editors/space_action/action_select.c4
-rw-r--r--source/blender/editors/space_api/spacetypes.c2
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c31
-rw-r--r--source/blender/editors/space_buttons/buttons_intern.h1
-rw-r--r--source/blender/editors/space_clip/clip_draw.c40
-rw-r--r--source/blender/editors/space_clip/clip_editor.c20
-rw-r--r--source/blender/editors/space_clip/clip_graph_ops.c22
-rw-r--r--source/blender/editors/space_clip/clip_ops.c6
-rw-r--r--source/blender/editors/space_clip/clip_utils.c46
-rw-r--r--source/blender/editors/space_clip/space_clip.c2
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c26
-rw-r--r--source/blender/editors/space_clip/tracking_select.c3
-rw-r--r--source/blender/editors/space_console/console_intern.h2
-rw-r--r--source/blender/editors/space_console/console_ops.c88
-rw-r--r--source/blender/editors/space_console/space_console.c2
-rw-r--r--source/blender/editors/space_file/file_draw.c157
-rw-r--r--source/blender/editors/space_file/file_intern.h2
-rw-r--r--source/blender/editors/space_file/file_ops.c63
-rw-r--r--source/blender/editors/space_file/filelist.c194
-rw-r--r--source/blender/editors/space_file/filelist.h6
-rw-r--r--source/blender/editors/space_file/filesel.c107
-rw-r--r--source/blender/editors/space_file/fsmenu.c2
-rw-r--r--source/blender/editors/space_file/space_file.c5
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c49
-rw-r--r--source/blender/editors/space_graph/graph_draw.c38
-rw-r--r--source/blender/editors/space_graph/graph_edit.c252
-rw-r--r--source/blender/editors/space_graph/graph_intern.h6
-rw-r--r--source/blender/editors/space_graph/graph_ops.c38
-rw-r--r--source/blender/editors/space_graph/graph_select.c32
-rw-r--r--source/blender/editors/space_graph/graph_utils.c9
-rw-r--r--source/blender/editors/space_graph/space_graph.c43
-rw-r--r--source/blender/editors/space_image/image_buttons.c350
-rw-r--r--source/blender/editors/space_image/image_draw.c71
-rw-r--r--source/blender/editors/space_image/image_edit.c8
-rw-r--r--source/blender/editors/space_image/image_intern.h4
-rw-r--r--source/blender/editors/space_image/image_ops.c489
-rw-r--r--source/blender/editors/space_image/space_image.c8
-rw-r--r--source/blender/editors/space_info/info_ops.c4
-rw-r--r--source/blender/editors/space_info/info_stats.c33
-rw-r--r--source/blender/editors/space_logic/logic_intern.h4
-rw-r--r--source/blender/editors/space_logic/logic_window.c2
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c6
-rw-r--r--source/blender/editors/space_nla/nla_channels.c52
-rw-r--r--source/blender/editors/space_nla/nla_draw.c13
-rw-r--r--source/blender/editors/space_nla/nla_edit.c50
-rw-r--r--source/blender/editors/space_nla/nla_intern.h3
-rw-r--r--source/blender/editors/space_nla/nla_ops.c12
-rw-r--r--source/blender/editors/space_node/drawnode.c89
-rw-r--r--source/blender/editors/space_node/node_draw.c15
-rw-r--r--source/blender/editors/space_node/node_edit.c106
-rw-r--r--source/blender/editors/space_node/node_group.c4
-rw-r--r--source/blender/editors/space_node/node_intern.h5
-rw-r--r--source/blender/editors/space_node/node_ops.c4
-rw-r--r--source/blender/editors/space_node/node_templates.c19
-rw-r--r--source/blender/editors/space_node/node_view.c9
-rw-r--r--source/blender/editors/space_node/space_node.c6
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c8
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c37
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h7
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c10
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c30
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c32
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c221
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c234
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c61
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h12
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c6
-rw-r--r--source/blender/editors/space_sequencer/sequencer_preview.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_scopes.c32
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c187
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c16
-rw-r--r--source/blender/editors/space_text/text_intern.h3
-rw-r--r--source/blender/editors/space_text/text_ops.c2
-rw-r--r--source/blender/editors/space_time/time_intern.h1
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_view3d/SConscript1
-rw-r--r--source/blender/editors/space_view3d/drawanimviz.c1
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c18
-rw-r--r--source/blender/editors/space_view3d/drawobject.c799
-rw-r--r--source/blender/editors/space_view3d/drawsimdebug.c7
-rw-r--r--source/blender/editors/space_view3d/drawstrands.c520
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c111
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c30
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c3
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c465
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c402
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h16
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c22
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c31
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c245
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c67
-rw-r--r--source/blender/editors/transform/CMakeLists.txt4
-rw-r--r--source/blender/editors/transform/SConscript3
-rw-r--r--source/blender/editors/transform/transform.c695
-rw-r--r--source/blender/editors/transform/transform.h20
-rw-r--r--source/blender/editors/transform/transform_constraints.c15
-rw-r--r--source/blender/editors/transform/transform_conversions.c952
-rw-r--r--source/blender/editors/transform/transform_generics.c35
-rw-r--r--source/blender/editors/transform/transform_manipulator.c17
-rw-r--r--source/blender/editors/transform/transform_ops.c50
-rw-r--r--source/blender/editors/transform/transform_orientations.c2
-rw-r--r--source/blender/editors/transform/transform_snap.c36
-rw-r--r--source/blender/editors/util/CMakeLists.txt2
-rw-r--r--source/blender/editors/util/ed_util.c26
-rw-r--r--source/blender/editors/util/editmode_undo.c32
-rw-r--r--source/blender/editors/util/numinput.c8
-rw-r--r--source/blender/editors/util/undo.c29
-rw-r--r--source/blender/editors/util/util_intern.h12
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h5
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c153
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c2
-rw-r--r--source/blender/freestyle/CMakeLists.txt1
-rw-r--r--source/blender/freestyle/FRS_freestyle.h5
-rw-r--r--source/blender/freestyle/intern/application/AppView.cpp2
-rw-r--r--source/blender/freestyle/intern/application/AppView.h4
-rw-r--r--source/blender/freestyle/intern/application/Controller.cpp12
-rw-r--r--source/blender/freestyle/intern/application/Controller.h1
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp4
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp10
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h30
-rw-r--r--source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp66
-rw-r--r--source/blender/freestyle/intern/geometry/GeomUtils.cpp2
-rw-r--r--source/blender/freestyle/intern/geometry/Grid.h6
-rw-r--r--source/blender/freestyle/intern/image/Image.h2
-rw-r--r--source/blender/freestyle/intern/image/ImagePyramid.cpp2
-rw-r--r--source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp18
-rw-r--r--source/blender/freestyle/intern/python/BPy_Freestyle.cpp8
-rw-r--r--source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp49
-rw-r--r--source/blender/freestyle/intern/python/BPy_IntegrationType.cpp2
-rw-r--r--source/blender/freestyle/intern/python/BPy_Operators.cpp40
-rw-r--r--source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp2
-rw-r--r--source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp5
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp4
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp8
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp8
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.h1
-rw-r--r--source/blender/freestyle/intern/stroke/Predicates1D.h4
-rw-r--r--source/blender/freestyle/intern/stroke/Stroke.cpp4
-rw-r--r--source/blender/freestyle/intern/system/PythonInterpreter.h22
-rw-r--r--source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp14
-rw-r--r--source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.h8
-rw-r--r--source/blender/freestyle/intern/view_map/AutoPtrHelper.h60
-rw-r--r--source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp12
-rw-r--r--source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.h8
-rw-r--r--source/blender/freestyle/intern/view_map/BoxGrid.cpp8
-rw-r--r--source/blender/freestyle/intern/view_map/BoxGrid.h4
-rw-r--r--source/blender/freestyle/intern/view_map/GridDensityProvider.h9
-rw-r--r--source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp32
-rw-r--r--source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.h8
-rw-r--r--source/blender/freestyle/intern/view_map/Interface1D.cpp4
-rw-r--r--source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp12
-rw-r--r--source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.h8
-rw-r--r--source/blender/freestyle/intern/view_map/Silhouette.h4
-rw-r--r--source/blender/freestyle/intern/view_map/SphericalGrid.cpp8
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMap.cpp4
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp18
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapBuilder.h2
-rw-r--r--source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp12
-rw-r--r--source/blender/gpu/CMakeLists.txt11
-rw-r--r--source/blender/gpu/GPU_buffers.h10
-rw-r--r--source/blender/gpu/GPU_compositing.h13
-rw-r--r--source/blender/gpu/GPU_debug.h5
-rw-r--r--source/blender/gpu/GPU_draw.h14
-rw-r--r--source/blender/gpu/GPU_extensions.h106
-rw-r--r--source/blender/gpu/GPU_material.h120
-rw-r--r--source/blender/gpu/GPU_select.h4
-rw-r--r--source/blender/gpu/GPU_simple_shader.h8
-rw-r--r--source/blender/gpu/SConscript5
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c192
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c218
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h67
-rw-r--r--source/blender/gpu/intern/gpu_compositing.c821
-rw-r--r--source/blender/gpu/intern/gpu_debug.c7
-rw-r--r--source/blender/gpu/intern/gpu_draw.c569
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c578
-rw-r--r--source/blender/gpu/intern/gpu_material.c509
-rw-r--r--source/blender/gpu/intern/gpu_private.h2
-rw-r--r--source/blender/gpu/intern/gpu_simple_shader.c3
-rw-r--r--source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl32
-rw-r--r--source/blender/gpu/shaders/gpu_program_smoke_frag.glsl27
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl166
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl50
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl58
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_lib.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl40
-rw-r--r--source/blender/ikplugin/BIK_api.h1
-rw-r--r--source/blender/ikplugin/CMakeLists.txt4
-rw-r--r--source/blender/ikplugin/intern/ikplugin_api.h1
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp3
-rw-r--r--source/blender/imbuf/CMakeLists.txt2
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h7
-rw-r--r--source/blender/imbuf/IMB_imbuf.h65
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h6
-rw-r--r--source/blender/imbuf/IMB_thumbs.h18
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h1
-rw-r--r--source/blender/imbuf/intern/IMB_filetype.h8
-rw-r--r--source/blender/imbuf/intern/IMB_metadata.h10
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c6
-rw-r--r--source/blender/imbuf/intern/anim_movie.c13
-rw-r--r--source/blender/imbuf/intern/bmp.c44
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.h6
-rw-r--r--source/blender/imbuf/intern/colormanagement.c104
-rw-r--r--source/blender/imbuf/intern/dds/BlockDXT.h24
-rw-r--r--source/blender/imbuf/intern/dds/ColorBlock.h3
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.cpp6
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.h12
-rw-r--r--source/blender/imbuf/intern/dds/Stream.h3
-rw-r--r--source/blender/imbuf/intern/dds/dds_api.cpp2
-rw-r--r--source/blender/imbuf/intern/divers.c86
-rw-r--r--source/blender/imbuf/intern/filetype.c12
-rw-r--r--source/blender/imbuf/intern/filter.c2
-rw-r--r--source/blender/imbuf/intern/imageprocess.c63
-rw-r--r--source/blender/imbuf/intern/indexer.c30
-rw-r--r--source/blender/imbuf/intern/metadata.c7
-rw-r--r--source/blender/imbuf/intern/moviecache.c4
-rw-r--r--source/blender/imbuf/intern/oiio/CMakeLists.txt1
-rw-r--r--source/blender/imbuf/intern/oiio/openimageio_api.cpp2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp1112
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_multi.h43
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_stub.cpp56
-rw-r--r--source/blender/imbuf/intern/png.c19
-rw-r--r--source/blender/imbuf/intern/readimage.c6
-rw-r--r--source/blender/imbuf/intern/rectop.c18
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c1292
-rw-r--r--source/blender/imbuf/intern/targa.c2
-rw-r--r--source/blender/imbuf/intern/thumbs.c244
-rw-r--r--source/blender/imbuf/intern/thumbs_blend.c4
-rw-r--r--source/blender/imbuf/intern/thumbs_font.c100
-rw-r--r--source/blender/imbuf/intern/tiff.c4
-rw-r--r--source/blender/imbuf/intern/util.c14
-rw-r--r--source/blender/imbuf/intern/writeimage.c34
-rw-r--r--source/blender/makesdna/DNA_ID.h23
-rw-r--r--source/blender/makesdna/DNA_action_types.h7
-rw-r--r--source/blender/makesdna/DNA_anim_types.h6
-rw-r--r--source/blender/makesdna/DNA_brush_types.h60
-rw-r--r--source/blender/makesdna/DNA_cache_library_types.h294
-rw-r--r--source/blender/makesdna/DNA_camera_types.h27
-rw-r--r--source/blender/makesdna/DNA_color_types.h1
-rw-r--r--source/blender/makesdna/DNA_curve_types.h2
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h8
-rw-r--r--source/blender/makesdna/DNA_documentation.h18
-rw-r--r--source/blender/makesdna/DNA_dynamicpaint_types.h1
-rw-r--r--source/blender/makesdna/DNA_gpu_types.h2
-rw-r--r--source/blender/makesdna/DNA_image_types.h53
-rw-r--r--source/blender/makesdna/DNA_key_types.h16
-rw-r--r--source/blender/makesdna/DNA_lamp_types.h1
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h3
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h9
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h47
-rw-r--r--source/blender/makesdna/DNA_node_types.h38
-rw-r--r--source/blender/makesdna/DNA_object_force.h2
-rw-r--r--source/blender/makesdna/DNA_object_types.h61
-rw-r--r--source/blender/makesdna/DNA_packedFile_types.h3
-rw-r--r--source/blender/makesdna/DNA_particle_types.h5
-rw-r--r--source/blender/makesdna/DNA_scene_types.h160
-rw-r--r--source/blender/makesdna/DNA_screen_types.h8
-rw-r--r--source/blender/makesdna/DNA_sensor_types.h2
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h43
-rw-r--r--source/blender/makesdna/DNA_smoke_types.h7
-rw-r--r--source/blender/makesdna/DNA_sound_types.h1
-rw-r--r--source/blender/makesdna/DNA_space_types.h57
-rw-r--r--source/blender/makesdna/DNA_strands_types.h99
-rw-r--r--source/blender/makesdna/DNA_texture_types.h4
-rw-r--r--source/blender/makesdna/DNA_tracking_types.h2
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h15
-rw-r--r--source/blender/makesdna/DNA_view2d_types.h2
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h24
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h19
-rw-r--r--source/blender/makesdna/intern/CMakeLists.txt3
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c2
-rw-r--r--source/blender/makesdna/intern/makesdna.c9
-rw-r--r--source/blender/makesrna/RNA_access.h9
-rw-r--r--source/blender/makesrna/RNA_enum_types.h14
-rw-r--r--source/blender/makesrna/RNA_types.h2
-rw-r--r--source/blender/makesrna/SConscript1
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt9
-rw-r--r--source/blender/makesrna/intern/SConscript1
-rw-r--r--source/blender/makesrna/intern/makesrna.c45
-rw-r--r--source/blender/makesrna/intern/rna_ID.c251
-rw-r--r--source/blender/makesrna/intern/rna_access.c38
-rw-r--r--source/blender/makesrna/intern/rna_action.c15
-rw-r--r--source/blender/makesrna/intern/rna_animation.c1
-rw-r--r--source/blender/makesrna/intern/rna_armature.c8
-rw-r--r--source/blender/makesrna/intern/rna_brush.c42
-rw-r--r--source/blender/makesrna/intern/rna_cache_library.c1049
-rw-r--r--source/blender/makesrna/intern/rna_camera.c84
-rw-r--r--source/blender/makesrna/intern/rna_color.c14
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c11
-rw-r--r--source/blender/makesrna/intern/rna_context.c1
-rw-r--r--source/blender/makesrna/intern/rna_controller.c2
-rw-r--r--source/blender/makesrna/intern/rna_curve.c7
-rw-r--r--source/blender/makesrna/intern/rna_define.c2
-rw-r--r--source/blender/makesrna/intern/rna_depsgraph.c112
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c2
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c10
-rw-r--r--source/blender/makesrna/intern/rna_image.c114
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c60
-rw-r--r--source/blender/makesrna/intern/rna_internal.h10
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_key.c20
-rw-r--r--source/blender/makesrna/intern/rna_lamp.c16
-rw-r--r--source/blender/makesrna/intern/rna_main.c14
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c239
-rw-r--r--source/blender/makesrna/intern/rna_material.c4
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c2
-rw-r--r--source/blender/makesrna/intern/rna_mesh_api.c51
-rw-r--r--source/blender/makesrna/intern/rna_mesh_sample.c73
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c143
-rw-r--r--source/blender/makesrna/intern/rna_movieclip.c2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c301
-rw-r--r--source/blender/makesrna/intern/rna_object.c219
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c73
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c2
-rw-r--r--source/blender/makesrna/intern/rna_palette.c181
-rw-r--r--source/blender/makesrna/intern/rna_particle.c14
-rw-r--r--source/blender/makesrna/intern/rna_pose.c4
-rw-r--r--source/blender/makesrna/intern/rna_render.c140
-rw-r--r--source/blender/makesrna/intern/rna_scene.c657
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c16
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c105
-rw-r--r--source/blender/makesrna/intern/rna_sensor.c14
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c115
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c18
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c21
-rw-r--r--source/blender/makesrna/intern/rna_sound.c6
-rw-r--r--source/blender/makesrna/intern/rna_space.c282
-rw-r--r--source/blender/makesrna/intern/rna_space_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_strands.c312
-rw-r--r--source/blender/makesrna/intern/rna_texture.c7
-rw-r--r--source/blender/makesrna/intern/rna_texture_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c37
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c61
-rw-r--r--source/blender/makesrna/intern/rna_wm.c112
-rw-r--r--source/blender/makesrna/intern/rna_world.c13
-rw-r--r--source/blender/modifiers/CMakeLists.txt3
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h1
-rw-r--r--source/blender/modifiers/SConscript2
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c14
-rw-r--r--source/blender/modifiers/intern/MOD_array.c39
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c1
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c17
-rw-r--r--source/blender/modifiers/intern/MOD_boolean_util.h2
-rw-r--r--source/blender/modifiers/intern/MOD_build.c43
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c14
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c28
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c1
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c769
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c22
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c28
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c20
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c17
-rw-r--r--source/blender/modifiers/intern/MOD_dynamicpaint.c23
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c1
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c3
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim.c34
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c21
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c1
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciansmooth.c1
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c14
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c19
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache.c1
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_util.h2
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c15
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c18
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c1
-rw-r--r--source/blender/modifiers/intern/MOD_none.c1
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c33
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c23
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c25
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c1
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c1
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c26
-rw-r--r--source/blender/modifiers/intern/MOD_shapekey.c1
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c19
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c14
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c22
-rw-r--r--source/blender/modifiers/intern/MOD_smoke.c177
-rw-r--r--source/blender/modifiers/intern/MOD_smooth.c1
-rw-r--r--source/blender/modifiers/intern/MOD_softbody.c1
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c9
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c3
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c1
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c1
-rw-r--r--source/blender/modifiers/intern/MOD_util.c3
-rw-r--r--source/blender/modifiers/intern/MOD_util.h6
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c21
-rw-r--r--source/blender/modifiers/intern/MOD_uvwarp.c26
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c21
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c17
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c22
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c24
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c27
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c1
-rw-r--r--source/blender/nodes/CMakeLists.txt2
-rw-r--r--source/blender/nodes/NOD_composite.h1
-rw-r--r--source/blender/nodes/NOD_shader.h1
-rw-r--r--source/blender/nodes/NOD_socket.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h6
-rw-r--r--source/blender/nodes/composite/node_composite_tree.c7
-rw-r--r--source/blender/nodes/composite/node_composite_util.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.c13
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapValue.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_outputFile.c4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_switchview.c153
-rw-r--r--source/blender/nodes/intern/node_common.c21
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bump.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mapping.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_object_info.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_checker.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_gradient.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_magic.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c75
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_sky.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_valToRgb.c3
-rw-r--r--source/blender/nodes/texture/node_texture_tree.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_proc.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_valToRgb.c3
-rw-r--r--source/blender/physics/BPH_mass_spring.h11
-rw-r--r--source/blender/physics/BPH_strands.h44
-rw-r--r--source/blender/physics/CMakeLists.txt3
-rw-r--r--source/blender/physics/SConscript1
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp648
-rw-r--r--source/blender/physics/intern/eigen_utils.h34
-rw-r--r--source/blender/physics/intern/hair_volume.cpp2
-rw-r--r--source/blender/physics/intern/implicit.h13
-rw-r--r--source/blender/physics/intern/implicit_blender.c38
-rw-r--r--source/blender/physics/intern/implicit_eigen.cpp2
-rw-r--r--source/blender/physics/intern/strands.cpp472
-rw-r--r--source/blender/pointcache/CMakeLists.txt66
-rw-r--r--source/blender/pointcache/PTC_api.cpp417
-rw-r--r--source/blender/pointcache/PTC_api.h132
-rw-r--r--source/blender/pointcache/SConscript58
-rw-r--r--source/blender/pointcache/alembic/CMakeLists.txt75
-rw-r--r--source/blender/pointcache/alembic/SConscript62
-rw-r--r--source/blender/pointcache/alembic/abc_cloth.cpp237
-rw-r--r--source/blender/pointcache/alembic/abc_cloth.h68
-rw-r--r--source/blender/pointcache/alembic/abc_customdata.cpp804
-rw-r--r--source/blender/pointcache/alembic/abc_customdata.h175
-rw-r--r--source/blender/pointcache/alembic/abc_frame_mapper.cpp52
-rw-r--r--source/blender/pointcache/alembic/abc_frame_mapper.h57
-rw-r--r--source/blender/pointcache/alembic/abc_group.cpp770
-rw-r--r--source/blender/pointcache/alembic/abc_group.h226
-rw-r--r--source/blender/pointcache/alembic/abc_info.cpp516
-rw-r--r--source/blender/pointcache/alembic/abc_interpolate.cpp32
-rw-r--r--source/blender/pointcache/alembic/abc_interpolate.h236
-rw-r--r--source/blender/pointcache/alembic/abc_mesh.cpp630
-rw-r--r--source/blender/pointcache/alembic/abc_mesh.h153
-rw-r--r--source/blender/pointcache/alembic/abc_object.cpp161
-rw-r--r--source/blender/pointcache/alembic/abc_object.h84
-rw-r--r--source/blender/pointcache/alembic/abc_particles.cpp1284
-rw-r--r--source/blender/pointcache/alembic/abc_particles.h222
-rw-r--r--source/blender/pointcache/alembic/abc_reader.cpp194
-rw-r--r--source/blender/pointcache/alembic/abc_reader.h108
-rw-r--r--source/blender/pointcache/alembic/abc_schema.h107
-rw-r--r--source/blender/pointcache/alembic/abc_simdebug.cpp185
-rw-r--r--source/blender/pointcache/alembic/abc_simdebug.h82
-rw-r--r--source/blender/pointcache/alembic/abc_split.cpp239
-rw-r--r--source/blender/pointcache/alembic/abc_writer.cpp132
-rw-r--r--source/blender/pointcache/alembic/abc_writer.h130
-rw-r--r--source/blender/pointcache/alembic/alembic.cpp147
-rw-r--r--source/blender/pointcache/alembic/alembic.h44
-rw-r--r--source/blender/pointcache/intern/ptc_types.cpp44
-rw-r--r--source/blender/pointcache/intern/ptc_types.h237
-rw-r--r--source/blender/pointcache/intern/reader.cpp57
-rw-r--r--source/blender/pointcache/intern/reader.h69
-rw-r--r--source/blender/pointcache/intern/writer.cpp56
-rw-r--r--source/blender/pointcache/intern/writer.h59
-rw-r--r--source/blender/pointcache/util/util_error_handler.cpp102
-rw-r--r--source/blender/pointcache/util/util_error_handler.h201
-rw-r--r--source/blender/pointcache/util/util_function.h48
-rw-r--r--source/blender/pointcache/util/util_task.cpp87
-rw-r--r--source/blender/pointcache/util/util_task.h51
-rw-r--r--source/blender/pointcache/util/util_thread.h74
-rw-r--r--source/blender/pointcache/util/util_types.h53
-rw-r--r--source/blender/python/bmesh/bmesh_py_api.c2
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops_call.c23
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c31
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.h9
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.c12
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_meshdata.c8
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_select.c4
-rw-r--r--source/blender/python/bmesh/bmesh_py_utils.c16
-rw-r--r--source/blender/python/generic/py_capi_utils.c28
-rw-r--r--source/blender/python/generic/py_capi_utils.h1
-rw-r--r--source/blender/python/intern/CMakeLists.txt3
-rw-r--r--source/blender/python/intern/bpy.c2
-rw-r--r--source/blender/python/intern/bpy_app.c30
-rw-r--r--source/blender/python/intern/bpy_app_translations.c12
-rw-r--r--source/blender/python/intern/bpy_app_translations.h1
-rw-r--r--source/blender/python/intern/bpy_interface.c9
-rw-r--r--source/blender/python/intern/bpy_operator.c4
-rw-r--r--source/blender/python/intern/bpy_props.c36
-rw-r--r--source/blender/python/intern/bpy_rna.c26
-rw-r--r--source/blender/python/intern/bpy_util.c60
-rw-r--r--source/blender/python/intern/bpy_util.h3
-rw-r--r--source/blender/python/intern/bpy_utils_previews.c188
-rw-r--r--source/blender/python/intern/bpy_utils_previews.h32
-rw-r--r--source/blender/python/intern/bpy_utils_units.c10
-rw-r--r--source/blender/python/intern/gpu.c31
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c4
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c14
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c2
-rw-r--r--source/blender/quicktime/apple/qtkit_export.m87
-rw-r--r--source/blender/quicktime/quicktime_export.h13
-rw-r--r--source/blender/render/CMakeLists.txt1
-rw-r--r--source/blender/render/SConscript1
-rw-r--r--source/blender/render/extern/include/RE_bake.h10
-rw-r--r--source/blender/render/extern/include/RE_engine.h11
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h69
-rw-r--r--source/blender/render/extern/include/RE_render_ext.h8
-rw-r--r--source/blender/render/intern/include/initrender.h1
-rw-r--r--source/blender/render/intern/include/occlusion.h3
-rw-r--r--source/blender/render/intern/include/pixelshading.h1
-rw-r--r--source/blender/render/intern/include/pointdensity.h4
-rw-r--r--source/blender/render/intern/include/render_result.h22
-rw-r--r--source/blender/render/intern/include/render_types.h9
-rw-r--r--source/blender/render/intern/include/rendercore.h3
-rw-r--r--source/blender/render/intern/include/shadbuf.h1
-rw-r--r--source/blender/render/intern/include/shading.h1
-rw-r--r--source/blender/render/intern/include/sss.h1
-rw-r--r--source/blender/render/intern/include/strand.h3
-rw-r--r--source/blender/render/intern/include/texture.h5
-rw-r--r--source/blender/render/intern/include/zbuf.h1
-rw-r--r--source/blender/render/intern/raytrace/rayobject_instance.cpp2
-rw-r--r--source/blender/render/intern/source/bake.c19
-rw-r--r--source/blender/render/intern/source/bake_api.c56
-rw-r--r--source/blender/render/intern/source/convertblender.c42
-rw-r--r--source/blender/render/intern/source/envmap.c17
-rw-r--r--source/blender/render/intern/source/external_engine.c69
-rw-r--r--source/blender/render/intern/source/initrender.c20
-rw-r--r--source/blender/render/intern/source/multires_bake.c10
-rw-r--r--source/blender/render/intern/source/pipeline.c1296
-rw-r--r--source/blender/render/intern/source/pointdensity.c479
-rw-r--r--source/blender/render/intern/source/rayshade.c39
-rw-r--r--source/blender/render/intern/source/render_result.c796
-rw-r--r--source/blender/render/intern/source/render_texture.c61
-rw-r--r--source/blender/render/intern/source/rendercore.c111
-rw-r--r--source/blender/render/intern/source/shadeinput.c11
-rw-r--r--source/blender/render/intern/source/shadeoutput.c89
-rw-r--r--source/blender/render/intern/source/texture_ocean.c2
-rw-r--r--source/blender/render/intern/source/volumetric.c12
-rw-r--r--source/blender/render/intern/source/zbuf.c62
-rw-r--r--source/blender/windowmanager/CMakeLists.txt8
-rw-r--r--source/blender/windowmanager/SConscript1
-rw-r--r--source/blender/windowmanager/WM_api.h41
-rw-r--r--source/blender/windowmanager/WM_keymap.h3
-rw-r--r--source/blender/windowmanager/WM_types.h31
-rw-r--r--source/blender/windowmanager/intern/wm.c4
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c23
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c284
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c276
-rw-r--r--source/blender/windowmanager/intern/wm_files.c28
-rw-r--r--source/blender/windowmanager/intern/wm_generic_widgets.c9
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c48
-rw-r--r--source/blender/windowmanager/intern/wm_jobs.c19
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c42
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c277
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c347
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c584
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c11
-rw-r--r--source/blender/windowmanager/intern/wm_widgets.c2
-rw-r--r--source/blender/windowmanager/intern/wm_window.c76
-rw-r--r--source/blender/windowmanager/wm.h8
-rw-r--r--source/blender/windowmanager/wm_draw.h21
-rw-r--r--source/blender/windowmanager/wm_event_system.h12
-rw-r--r--source/blender/windowmanager/wm_window.h7
-rw-r--r--source/blenderplayer/CMakeLists.txt3
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c36
-rw-r--r--source/creator/CMakeLists.txt125
-rw-r--r--source/creator/creator.c101
-rw-r--r--source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp2
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp5
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderCanvas.h2
-rw-r--r--source/gameengine/CMakeLists.txt2
-rw-r--r--source/gameengine/Converter/BL_ArmatureConstraint.cpp2
-rw-r--r--source/gameengine/Converter/BL_ArmatureObject.cpp2
-rw-r--r--source/gameengine/Converter/BL_BlenderDataConversion.cpp163
-rw-r--r--source/gameengine/Converter/BlenderWorldInfo.cpp200
-rw-r--r--source/gameengine/Converter/BlenderWorldInfo.h82
-rw-r--r--source/gameengine/Converter/CMakeLists.txt4
-rw-r--r--source/gameengine/Converter/KX_BlenderSceneConverter.cpp651
-rw-r--r--source/gameengine/Converter/KX_ConvertSensors.cpp974
-rw-r--r--source/gameengine/Expressions/CMakeLists.txt2
-rw-r--r--source/gameengine/Expressions/KX_PythonCallBack.cpp119
-rw-r--r--source/gameengine/Expressions/KX_PythonCallBack.h40
-rw-r--r--source/gameengine/Expressions/PyObjectPlus.cpp15
-rw-r--r--source/gameengine/Expressions/PyObjectPlus.h13
-rw-r--r--source/gameengine/GameLogic/SCA_IObject.h1
-rw-r--r--source/gameengine/GameLogic/SCA_ISensor.cpp34
-rw-r--r--source/gameengine/GameLogic/SCA_ISensor.h8
-rw-r--r--source/gameengine/GameLogic/SCA_PropertySensor.cpp9
-rw-r--r--source/gameengine/GameLogic/SCA_RandomSensor.cpp2
-rw-r--r--source/gameengine/GamePlayer/common/GPC_Canvas.h2
-rw-r--r--source/gameengine/GamePlayer/ghost/CMakeLists.txt1
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Application.cpp6
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp12
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Canvas.h2
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_ghost.cpp11
-rw-r--r--source/gameengine/GamePlayer/ghost/SConscript1
-rw-r--r--source/gameengine/Ketsji/BL_Action.cpp9
-rw-r--r--source/gameengine/Ketsji/BL_Texture.cpp24
-rw-r--r--source/gameengine/Ketsji/KX_BlenderMaterial.cpp53
-rw-r--r--source/gameengine/Ketsji/KX_BlenderMaterial.h9
-rw-r--r--source/gameengine/Ketsji/KX_Camera.cpp7
-rw-r--r--source/gameengine/Ketsji/KX_Camera.h2
-rw-r--r--source/gameengine/Ketsji/KX_FontObject.cpp1
-rw-r--r--source/gameengine/Ketsji/KX_FontObject.h1
-rw-r--r--source/gameengine/Ketsji/KX_GameActuator.cpp5
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.cpp307
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.h41
-rw-r--r--source/gameengine/Ketsji/KX_IpoConvert.cpp88
-rw-r--r--source/gameengine/Ketsji/KX_IpoConvert.h3
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.cpp71
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.h2
-rw-r--r--source/gameengine/Ketsji/KX_Light.cpp29
-rw-r--r--source/gameengine/Ketsji/KX_Light.h4
-rw-r--r--source/gameengine/Ketsji/KX_MaterialIpoController.cpp15
-rw-r--r--source/gameengine/Ketsji/KX_MouseActuator.cpp5
-rw-r--r--source/gameengine/Ketsji/KX_ObjectActuator.cpp32
-rw-r--r--source/gameengine/Ketsji/KX_ObjectActuator.h3
-rw-r--r--source/gameengine/Ketsji/KX_PyConstraintBinding.cpp90
-rw-r--r--source/gameengine/Ketsji/KX_PythonInit.cpp132
-rw-r--r--source/gameengine/Ketsji/KX_PythonInitTypes.cpp3
-rw-r--r--source/gameengine/Ketsji/KX_Scene.cpp233
-rw-r--r--source/gameengine/Ketsji/KX_Scene.h17
-rw-r--r--source/gameengine/Ketsji/KX_SteeringActuator.cpp9
-rw-r--r--source/gameengine/Ketsji/KX_VehicleWrapper.cpp18
-rw-r--r--source/gameengine/Ketsji/KX_WorldInfo.cpp456
-rw-r--r--source/gameengine/Ketsji/KX_WorldInfo.h84
-rw-r--r--source/gameengine/Ketsji/KX_WorldIpoController.cpp31
-rw-r--r--source/gameengine/Ketsji/KX_WorldIpoController.h28
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsController.cpp726
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsController.h59
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp230
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h24
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsController.h5
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h4
-rw-r--r--source/gameengine/Rasterizer/RAS_ICanvas.h2
-rw-r--r--source/gameengine/Rasterizer/RAS_IRasterizer.h12
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp6
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h9
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp120
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h21
-rw-r--r--source/gameengine/VideoTexture/ImageRender.cpp27
-rw-r--r--source/gameengine/VideoTexture/ImageRender.h2
-rw-r--r--source/gameengine/VideoTexture/Texture.cpp14
-rw-r--r--tests/gtests/blenlib/BLI_ghash_performance_test.cc415
-rw-r--r--tests/gtests/blenlib/BLI_ghash_test.cc158
-rw-r--r--tests/gtests/blenlib/BLI_ressource_strings.h602
-rw-r--r--tests/gtests/blenlib/BLI_stack_test.cc54
-rw-r--r--tests/gtests/blenlib/CMakeLists.txt5
-rw-r--r--tests/python/CMakeLists.txt6
-rw-r--r--tests/python/bl_load_addons.py25
-rw-r--r--tests/python/bl_rna_defaults.py117
-rw-r--r--tests/python/bl_rna_manual_reference.py (renamed from tests/python/bl_rna_wiki_reference.py)51
-rw-r--r--tests/python/bl_rst_completeness.py2
-rw-r--r--tests/python/bl_run_operators.py10
-rw-r--r--tests/python/pep8.py13
-rw-r--r--tests/python/rst_to_doctree_mini.py21
1901 files changed, 113017 insertions, 31537 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6bd589d650a..b631cce6a09 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -197,11 +197,10 @@ option(WITH_PYTHON "Enable Embedded Python API (only disable for develop
option(WITH_PYTHON_SECURITY "Disables execution of scripts within blend files by default" ON)
mark_as_advanced(WITH_PYTHON) # dont want people disabling this unless they really know what they are doing.
mark_as_advanced(WITH_PYTHON_SECURITY) # some distributions see this as a security issue, rather than have them patch it, make a build option.
-set(WITH_PYTHON_SECURITY ON CACHE BOOL "ON" FORCE) # temp force on.
option(WITH_PYTHON_SAFETY "Enable internal API error checking to track invalid data to prevent crash on access (at the expense of some effeciency, only enable for development)." OFF)
mark_as_advanced(WITH_PYTHON_SAFETY)
-option(WITH_PYTHON_MODULE "Enable building as a python module which runs without a user interface, like running regular blender in background mode (experimental, only enable for development)" OFF)
+option(WITH_PYTHON_MODULE "Enable building as a python module which runs without a user interface, like running regular blender in background mode (experimental, only enable for development), installs to PYTHON_SITE_PACKAGES (or CMAKE_INSTALL_PREFIX if WITH_INSTALL_PORTABLE is enabled)." OFF)
if(APPLE)
option(WITH_PYTHON_FRAMEWORK "Enable building using the Python available in the framework (OSX only)" OFF)
endif()
@@ -261,6 +260,10 @@ endif()
# (unix defaults to System OpenJPEG On)
option(WITH_SYSTEM_OPENJPEG "Use the operating systems OpenJPEG library" OFF)
+if(UNIX AND NOT APPLE)
+ option(WITH_SYSTEM_EIGEN3 "Use the systems Eigen3 library" OFF)
+endif()
+
# Modifiers
option(WITH_MOD_FLUID "Enable Elbeem Modifier (Fluid Simulation)" ON)
@@ -271,6 +274,10 @@ option(WITH_MOD_REMESH "Enable Remesh Modifier" ON)
# mark_as_advanced(WITH_MOD_CLOTH_ELTOPO)
option(WITH_MOD_OCEANSIM "Enable Ocean Modifier" OFF)
+# Alembic
+option(WITH_ALEMBIC "Enable Alembic Support" OFF)
+option(WITH_HDF5 "Enable HDF5 Support for Alembic" OFF)
+
# Image format support
option(WITH_OPENIMAGEIO "Enable OpenImageIO Support (http://www.openimageio.org)" ON)
option(WITH_IMAGE_OPENEXR "Enable OpenEXR Support (http://www.openexr.com)" ${_init_IMAGE_OPENEXR})
@@ -309,6 +316,9 @@ endif()
# Compression
option(WITH_LZO "Enable fast LZO compression (used for pointcache)" ON)
option(WITH_LZMA "Enable best LZMA compression, (used for pointcache)" ON)
+if(UNIX AND NOT APPLE)
+ option(WITH_SYSTEM_LZO "Use the system LZO library" OFF)
+endif()
# Camera/motion tracking
option(WITH_LIBMV "Enable libmv structure from motion library" ON)
@@ -352,7 +362,7 @@ option(WITH_CYCLES_STANDALONE "Build cycles standalone application" OFF)
option(WITH_CYCLES_STANDALONE_GUI "Build cycles standalone with GUI" OFF)
option(WITH_CYCLES_OSL "Build Cycles with OSL support" ${_init_CYCLES_OSL})
option(WITH_CYCLES_CUDA_BINARIES "Build cycles CUDA binaries" OFF)
-set(CYCLES_CUDA_BINARIES_ARCH sm_20 sm_21 sm_30 sm_35 sm_50 CACHE STRING "CUDA architectures to build binaries for")
+set(CYCLES_CUDA_BINARIES_ARCH sm_20 sm_21 sm_30 sm_35 sm_50 sm_52 CACHE STRING "CUDA architectures to build binaries for")
mark_as_advanced(CYCLES_CUDA_BINARIES_ARCH)
unset(PLATFORM_DEFAULT)
option(WITH_CYCLES_LOGGING "Build cycles with logging support" ON)
@@ -388,6 +398,7 @@ option(WITH_BOOST "Enable features depending on boost" ON)
# Unit testsing
option(WITH_GTESTS "Enable GTest unit testing" OFF)
+option(WITH_TESTS_PERFORMANCE "Enable performance tests" OFF)
# Documentation
@@ -437,6 +448,13 @@ if(MSVC)
set(CPACK_INSTALL_PREFIX ${CMAKE_GENERIC_PROGRAM_FILES}/${})
endif()
+# Experimental support of C++11
+option(WITH_CPP11 "Build with C++11 standard enabled, for development use only!" OFF)
+mark_as_advanced(WITH_CPP11)
+
+# Dependency graph
+option(WITH_LEGACY_DEPSGRAPH "Build Blender with legacy dependency graph" ON)
+
# avoid using again
option_defaults_clear()
@@ -626,17 +644,23 @@ if(NOT WITH_BOOST)
set_and_warn(WITH_CYCLES OFF)
set_and_warn(WITH_AUDASPACE OFF)
+ set_and_warn(WITH_ALEMBIC OFF)
set_and_warn(WITH_INTERNATIONAL OFF)
set_and_warn(WITH_OPENAL OFF) # depends on AUDASPACE
set_and_warn(WITH_GAMEENGINE OFF) # depends on AUDASPACE
-elseif(WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_AUDASPACE OR WITH_INTERNATIONAL)
+elseif(WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_AUDASPACE OR WITH_ALEMBIC OR WITH_INTERNATIONAL)
# Keep enabled
else()
# Enabled but we don't need it
set(WITH_BOOST OFF)
endif()
+# disable hdf5 if Alembic is disabled
+if(NOT WITH_ALEMBIC)
+ set(WITH_HDF5 OFF)
+endif()
+
# auto enable openimageio for cycles
if(WITH_CYCLES)
set(WITH_OPENIMAGEIO ON)
@@ -663,6 +687,7 @@ if(WITH_GHOST_SDL OR WITH_HEADLESS)
set(WITH_X11_XINPUT OFF)
set(WITH_X11_XF86VMODE OFF)
set(WITH_GHOST_XDND OFF)
+ set(WITH_INPUT_IME OFF)
endif()
if(WITH_CPU_SSE)
@@ -797,6 +822,21 @@ if(UNIX AND NOT APPLE)
find_package_wrapper(ZLIB REQUIRED)
find_package_wrapper(Freetype REQUIRED)
+ if(WITH_LZO AND WITH_SYSTEM_LZO)
+ find_package_wrapper(LZO)
+ if(NOT LZO_FOUND)
+ message(FATAL_ERROR "Failed finding system LZO version!")
+ endif()
+ endif()
+
+ if(WITH_SYSTEM_EIGEN3)
+ find_package_wrapper(Eigen3)
+ if(NOT EIGEN3_FOUND)
+ message(FATAL_ERROR "Failed finding system Eigen3 version!")
+ endif()
+ endif()
+ # else values are set below for all platforms
+
if(WITH_PYTHON)
# No way to set py34. remove for now.
# find_package(PythonLibs)
@@ -1031,75 +1071,31 @@ if(UNIX AND NOT APPLE)
endif()
endif()
- # XXX Maybe most of this section should go into an llvm module?
if(WITH_LLVM)
+ find_package_wrapper(LLVM)
- if(LLVM_ROOT_DIR)
- if(NOT DEFINED LLVM_VERSION)
- find_program(LLVM_CONFIG llvm-config-${LLVM_VERSION} HINTS ${LLVM_ROOT_DIR}/bin NO_CMAKE_PATH)
- endif()
- if(NOT LLVM_CONFIG)
- find_program(LLVM_CONFIG llvm-config HINTS ${LLVM_ROOT_DIR}/bin NO_CMAKE_PATH)
- endif()
- else()
- if(NOT DEFINED LLVM_VERSION)
- find_program(LLVM_CONFIG llvm-config-${LLVM_VERSION})
- endif()
- if(NOT LLVM_CONFIG)
- find_program(LLVM_CONFIG llvm-config)
- endif()
- endif()
-
- if(NOT DEFINED LLVM_VERSION)
- execute_process(COMMAND ${LLVM_CONFIG} --version
- OUTPUT_VARIABLE LLVM_VERSION
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- set(LLVM_VERSION ${LLVM_VERSION} CACHE STRING "Version of LLVM to use")
- endif()
- if(NOT DEFINED LLVM_ROOT_DIR)
- execute_process(COMMAND ${LLVM_CONFIG} --prefix
- OUTPUT_VARIABLE LLVM_ROOT_DIR
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- set(LLVM_ROOT_DIR ${LLVM_ROOT_DIR} CACHE PATH "Path to the LLVM installation")
- endif()
- if(NOT DEFINED LLVM_LIBPATH)
- execute_process(COMMAND ${LLVM_CONFIG} --libdir
- OUTPUT_VARIABLE LLVM_LIBPATH
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- set(LLVM_LIBPATH ${LLVM_LIBPATH} CACHE PATH "Path to the LLVM library path")
- mark_as_advanced(LLVM_LIBPATH)
- endif()
-
- if(LLVM_STATIC)
- find_library(LLVM_LIBRARY
- NAMES LLVMAnalysis # first of a whole bunch of libs to get
- PATHS ${LLVM_LIBPATH})
- else()
- find_library(LLVM_LIBRARY
- NAMES LLVM-${LLVM_VERSION}
- PATHS ${LLVM_LIBPATH})
+ if(NOT LLVM_FOUND)
+ set(WITH_LLVM OFF)
+ message(STATUS "LLVM not found")
endif()
+ endif()
+ if(WITH_LLVM OR WITH_SDL_DYNLOAD)
+ # Fix for conflict with Mesa llvmpipe
+ set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -Wl,--version-script='${CMAKE_SOURCE_DIR}/source/creator/blender.map'")
+ endif()
- if(LLVM_LIBRARY AND LLVM_ROOT_DIR AND LLVM_LIBPATH)
- if(LLVM_STATIC)
- # if static LLVM libraries were requested, use llvm-config to generate
- # the list of what libraries we need, and substitute that in the right
- # way for LLVM_LIBRARY.
- execute_process(COMMAND ${LLVM_CONFIG} --libfiles
- OUTPUT_VARIABLE LLVM_LIBRARY
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- string(REPLACE " " ";" LLVM_LIBRARY "${LLVM_LIBRARY}")
- endif()
- else()
- message(FATAL_ERROR "LLVM not found.")
+ if(WITH_ALEMBIC)
+ find_package_wrapper(Alembic)
+ set(ALEMBIC_LIBRARIES ${ALEMBIC_LIBRARIES} ${BOOST_LIBRARIES})
+ if(NOT ALEMBIC_HDF5_FOUND AND WITH_HDF5)
+ message(STATUS "Alembic is compiled without HDF5 support, disabling HDF5 options")
+ set(WITH_HDF5 OFF)
endif()
-
endif()
- if(WITH_LLVM OR WITH_SDL_DYNLOAD)
- # Fix for conflict with Mesa llvmpipe
- set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/source/creator/blender.map")
+ if(WITH_HDF5)
+ find_package_wrapper(HDF5)
endif()
# OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed
@@ -1128,6 +1124,25 @@ if(UNIX AND NOT APPLE)
# GNU Compiler
if(CMAKE_COMPILER_IS_GNUCC)
set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
+
+ if(NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "5.0")
+ # GCC5 uses gnu11, until we update, force c89
+ # though some c11 features can still be used.
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu89")
+ endif()
+
+ # use ld.gold linker if available, could make optional
+ execute_process(
+ COMMAND ${CMAKE_C_COMPILER} -fuse-ld=gold -Wl,--version
+ ERROR_QUIET OUTPUT_VARIABLE LD_VERSION)
+ if ("${LD_VERSION}" MATCHES "GNU gold")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=gold")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=gold")
+ else ()
+ message(INFO "GNU gold linker isn't available, using the default system linker.")
+ endif ()
+ unset(LD_VERSION)
+
# CLang is the same as GCC for now.
elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
@@ -1852,14 +1867,14 @@ elseif(APPLE)
if(NOT WITH_PYTHON_MODULE AND NOT WITH_PYTHON_FRAMEWORK)
# normally cached but not since we include them with blender
set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}m")
- # set(PYTHON_BINARY "${LIBDIR}/python/bin/python${PYTHON_VERSION}") # not used yet
+ # set(PYTHON_EXECUTABLE "${LIBDIR}/python/bin/python${PYTHON_VERSION}") # not used yet
set(PYTHON_LIBRARY python${PYTHON_VERSION}m)
set(PYTHON_LIBPATH "${LIBDIR}/python/lib/python${PYTHON_VERSION}")
# set(PYTHON_LINKFLAGS "-u _PyMac_Error") # won't build with this enabled
else()
# module must be compiled against Python framework
set(PYTHON_INCLUDE_DIR "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/include/python${PYTHON_VERSION}m")
- set(PYTHON_BINARY "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/bin/python${PYTHON_VERSION}")
+ set(PYTHON_EXECUTABLE "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/bin/python${PYTHON_VERSION}")
#set(PYTHON_LIBRARY python${PYTHON_VERSION})
set(PYTHON_LIBPATH "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/lib/python${PYTHON_VERSION}/config-${PYTHON_VERSION}m")
#set(PYTHON_LINKFLAGS "-u _PyMac_Error -framework Python") # won't build with this enabled
@@ -2169,6 +2184,12 @@ if(WITH_CYCLES)
endif()
endif()
+if(WITH_ALEMBIC)
+ if(NOT WITH_BOOST)
+ message(FATAL_ERROR "Alembic requires WITH_BOOST, the library may not have been found. Configure BOOST or disable WITH_ALEMBIC")
+ endif()
+endif()
+
if(WITH_INTERNATIONAL)
if(NOT WITH_BOOST)
message(FATAL_ERROR "Internationalization requires WITH_BOOST, the library may not have been found. Configure BOOST or disable WITH_INTERNATIONAL")
@@ -2232,6 +2253,9 @@ if(WITH_IMAGE_REDCODE)
set(REDCODE_INC ${REDCODE})
endif()
+if(NOT WITH_SYSTEM_EIGEN3)
+ set(EIGEN3_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extern/Eigen3)
+endif()
#-----------------------------------------------------------------------------
# Configure OpenGL.
@@ -2493,6 +2517,7 @@ if(CMAKE_COMPILER_IS_GNUCC)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_MISSING_INCLUDE_DIRS -Wmissing-include-dirs)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_NO_DIV_BY_ZERO -Wno-div-by-zero)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_TYPE_LIMITS -Wtype-limits)
+ ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_FORMAT_SIGN -Wformat-signedness)
# gcc 4.2 gives annoying warnings on every file with this
if(NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "4.3")
@@ -2520,6 +2545,16 @@ if(CMAKE_COMPILER_IS_GNUCC)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_MISSING_INCLUDE_DIRS -Wmissing-include-dirs)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_DIV_BY_ZERO -Wno-div-by-zero)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_TYPE_LIMITS -Wtype-limits)
+ ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_ERROR_RETURN_TYPE -Werror=return-type)
+ ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_ERROR_DECLARATION_AFTER_STATEMENT -Werror=declaration-after-statement)
+ ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_ERROR_IMPLICIT_FUNCTION_DECLARATION -Werror=implicit-function-declaration)
+ ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_CHAR_SUBSCRIPTS -Wno-char-subscripts)
+ ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_UNKNOWN_PRAGMAS -Wno-unknown-pragmas)
+ ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_POINTER_ARITH -Wpointer-arith)
+ ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_UNUSED_PARAMETER -Wunused-parameter)
+ ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_WRITE_STRINGS -Wwrite-strings)
+ ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_UNDEF -Wundef)
+ ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_FORMAT_SIGN -Wformat-signedness)
# gcc 4.2 gives annoying warnings on every file with this
if(NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "4.3")
@@ -2653,6 +2688,16 @@ if(WITH_PYTHON)
endif()
endif()
+if(WITH_CPP11)
+ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+ elseif(MSVC12)
+ # Nothing special is needed, C++11 features are available by default.
+ else()
+ message(FATAL_ERROR "Compiler ${CMAKE_C_COMPILER_ID} is not supported for C++11 build yet")
+ endif()
+endif()
+
# Include warnings first, so its possible to disable them with user defined flags
# eg: -Wno-uninitialized
set(CMAKE_C_FLAGS "${C_WARNINGS} ${CMAKE_C_FLAGS} ${PLATFORM_CFLAGS}")
diff --git a/GNUmakefile b/GNUmakefile
index 775d0ae532b..fc1de5e4954 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -65,7 +65,7 @@ ifneq "$(findstring cycles, $(MAKECMDGOALS))" ""
BUILD_CMAKE_ARGS:=$(BUILD_CMAKE_ARGS) -C"$(BLENDER_DIR)/build_files/cmake/config/cycles_standalone.cmake"
endif
ifneq "$(findstring headless, $(MAKECMDGOALS))" ""
- BUILD_DIR:=$(BUILD_DIR)_bpy
+ BUILD_DIR:=$(BUILD_DIR)_headless
BUILD_CMAKE_ARGS:=$(BUILD_CMAKE_ARGS) -C"$(BLENDER_DIR)/build_files/cmake/config/blender_headless.cmake"
endif
ifneq "$(findstring bpy, $(MAKECMDGOALS))" ""
@@ -171,7 +171,7 @@ help: FORCE
@echo ""
@echo "Package Targets"
@echo " * package_debian - build a debian package"
- @echo " * package_pacman - build an arch linux pacmanpackage"
+ @echo " * package_pacman - build an arch linux pacman package"
@echo " * package_archive - build an archive package"
@echo ""
@echo "Testing Targets (not associated with building blender)"
@@ -218,7 +218,7 @@ package_debian: FORCE
cd build_files/package_spec ; DEB_BUILD_OPTIONS="parallel=$(NPROCS)" sh ./build_debian.sh
package_pacman: FORCE
- cd build_files/package_spec/pacman ; MAKEFLAGS="-j$(NPROCS)" makepkg --asroot
+ cd build_files/package_spec/pacman ; MAKEFLAGS="-j$(NPROCS)" makepkg
package_archive: FORCE
make -C "$(BUILD_DIR)" -s package_archive
diff --git a/SConstruct b/SConstruct
index 29e22cb32a7..08a03205c35 100644
--- a/SConstruct
+++ b/SConstruct
@@ -470,6 +470,14 @@ if env['OURPLATFORM']=='darwin':
################### End Automatic configuration for OSX ##################
#############################################################################
+if env['OURPLATFORM'] == 'linux' and not env['C_COMPILER_ID']:
+ command = ["%s"%env['CC'], "--version"]
+ line = btools.get_command_output(command)
+ if line.startswith('gcc'):
+ env['C_COMPILER_ID'] = 'gcc'
+ elif 'clang' in line[0]:
+ env['C_COMPILER_ID'] = 'clang'
+
if env['WITH_BF_OPENMP'] == 1:
if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
env['CCFLAGS'].append('/openmp')
@@ -480,6 +488,13 @@ if env['WITH_BF_OPENMP'] == 1:
else:
env.Append(CCFLAGS=['-fopenmp'])
+if env['WITH_BF_CPP11']:
+ if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
+ # Nothing special is needed, C++11 features are available by default.
+ pass
+ else:
+ env['CXXFLAGS'].append('-std=c++11')
+
#check for additional debug libnames
if env.has_key('BF_DEBUG_LIBS'):
@@ -751,6 +766,9 @@ if B.targets != ['cudakernels']:
data_to_c_simple("release/datafiles/preview_cycles.blend")
# --- glsl ---
+ data_to_c_simple("source/blender/gpu/shaders/gpu_program_smoke_frag.glsl")
+ data_to_c_simple("source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl")
+
data_to_c_simple("source/blender/gpu/shaders/gpu_shader_simple_frag.glsl")
data_to_c_simple("source/blender/gpu/shaders/gpu_shader_simple_vert.glsl")
data_to_c_simple("source/blender/gpu/shaders/gpu_shader_material.glsl")
@@ -764,6 +782,9 @@ if B.targets != ['cudakernels']:
data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl")
data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl")
data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl")
+ data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl")
+ data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl")
+ data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl")
data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_lib.glsl")
data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl")
data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_vert.glsl")
@@ -796,6 +817,13 @@ if B.targets != ['cudakernels']:
data_to_c_simple("release/datafiles/brushicons/fill.png")
data_to_c_simple("release/datafiles/brushicons/flatten.png")
data_to_c_simple("release/datafiles/brushicons/grab.png")
+ data_to_c_simple("release/datafiles/brushicons/hairadd.png")
+ data_to_c_simple("release/datafiles/brushicons/haircomb.png")
+ data_to_c_simple("release/datafiles/brushicons/haircut.png")
+ data_to_c_simple("release/datafiles/brushicons/hairlength.png")
+ data_to_c_simple("release/datafiles/brushicons/hairpuff.png")
+ data_to_c_simple("release/datafiles/brushicons/hairsmooth.png")
+ data_to_c_simple("release/datafiles/brushicons/hairweight.png")
data_to_c_simple("release/datafiles/brushicons/inflate.png")
data_to_c_simple("release/datafiles/brushicons/layer.png")
data_to_c_simple("release/datafiles/brushicons/lighten.png")
@@ -861,19 +889,21 @@ B.init_lib_dict()
##### END SETUP ##########
-if B.targets != ['cudakernels']:
- # Put all auto configuration run-time tests here
+## Auto-configuration run-time tests
+
+from FindSharedPtr import FindSharedPtr
+from FindUnorderedMap import FindUnorderedMap
- from FindSharedPtr import FindSharedPtr
- from FindUnorderedMap import FindUnorderedMap
+conf = Configure(env)
+old_linkflags = conf.env['LINKFLAGS']
+conf.env.Append(LINKFLAGS=env['PLATFORM_LINKFLAGS'])
- conf = Configure(env)
- old_linkflags = conf.env['LINKFLAGS']
- conf.env.Append(LINKFLAGS=env['PLATFORM_LINKFLAGS'])
- FindSharedPtr(conf)
- FindUnorderedMap(conf)
- conf.env['LINKFLAGS'] = old_linkflags
- env = conf.Finish()
+# Put all tests here
+FindSharedPtr(conf)
+FindUnorderedMap(conf)
+
+conf.env['LINKFLAGS'] = old_linkflags
+env = conf.Finish()
# End of auto configuration
@@ -1005,14 +1035,16 @@ if env['OURPLATFORM']!='darwin':
dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'kernel')
source=os.listdir('intern/cycles/kernel')
if '__pycache__' in source: source.remove('__pycache__')
- source.remove('kernel.cpp')
source.remove('CMakeLists.txt')
+ source.remove('SConscript')
source.remove('svm')
source.remove('closure')
source.remove('geom')
source.remove('shaders')
source.remove('osl')
+ source.remove('split')
source=['intern/cycles/kernel/'+s for s in source]
+ source.append('intern/cycles/util/util_atomic.h')
source.append('intern/cycles/util/util_color.h')
source.append('intern/cycles/util/util_half.h')
source.append('intern/cycles/util/util_math.h')
@@ -1038,6 +1070,12 @@ if env['OURPLATFORM']!='darwin':
if '__pycache__' in source: source.remove('__pycache__')
source=['intern/cycles/kernel/geom/'+s for s in source]
scriptinstall.append(env.Install(dir=dir,source=source))
+ # split
+ dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'kernel', 'split')
+ source=os.listdir('intern/cycles/kernel/split')
+ if '__pycache__' in source: source.remove('__pycache__')
+ source=['intern/cycles/kernel/split/'+s for s in source]
+ scriptinstall.append(env.Install(dir=dir,source=source))
# licenses
dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'license')
@@ -1167,9 +1205,37 @@ if env['OURPLATFORM']=='linuxcross':
textlist = []
texttargetlist = []
for tp, tn, tf in os.walk('release/text'):
+ tf.remove("readme.html")
for f in tf:
textlist.append(tp+os.sep+f)
+def readme_version_patch():
+ readme_src = "release/text/readme.html"
+ readme_dst = os.path.abspath(os.path.normpath(os.path.join(env['BF_BUILDDIR'], "readme.html")))
+
+ if not os.path.exists(readme_dst) or (os.path.getmtime(readme_dst) < os.path.getmtime(readme_src)):
+ f = open(readme_src, "r")
+ data = f.read()
+ f.close()
+
+ data = data.replace("BLENDER_VERSION", VERSION)
+ f = open(readme_dst, "w")
+ f.write(data)
+ f.close()
+
+ textlist.append(readme_dst)
+
+readme_version_patch()
+del readme_version_patch
+
+
+'''Command(
+ "release/text/readme.html"
+
+ )
+Command("file.out", "file.in", Copy(env['BF_INSTALLDIR'], "release/text/readme.html"))
+'''
+
# Font licenses
textlist.append('release/datafiles/LICENSE-bfont.ttf.txt')
if env['WITH_BF_INTERNATIONAL']:
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index 1c78858ac59..3934d7c2108 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -28,8 +28,8 @@ getopt \
--long source:,install:,tmp:,info:,threads:,help,no-sudo,with-all,with-opencollada,\
ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,\
force-all,force-python,force-numpy,force-boost,force-ocio,force-oiio,force-llvm,force-osl,force-opencollada,\
-force-ffmpeg,\
-skip-python,skip-numpy,skip-boost,skip-ocio,skip-openexr,skip-oiio,skip-llvm,skip-osl,skip-ffmpeg,skip-opencollada,\
+force-ffmpeg,force-alembic,\
+skip-python,skip-numpy,skip-boost,skip-ocio,skip-openexr,skip-oiio,skip-llvm,skip-osl,skip-ffmpeg,skip-opencollada,skip-alembic,\
required-numpy: \
-- "$@" \
)
@@ -95,6 +95,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--with-opencollada
Build and install the OpenCOLLADA libraries.
+ --with-alembic
+ Build and install the Alembic library.
+
--ver-ocio=<ver>
Force version of OCIO library.
@@ -144,6 +147,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--force-ffmpeg
Force the rebuild of FFMpeg.
+ --force-alembic
+ Force the rebuild of Alembic.
+
Note about the --force-foo options:
* They obviously only have an effect if those libraries are built by this script
(i.e. if there is no available and satisfactory package)!
@@ -180,6 +186,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--skip-ffmpeg
Unconditionally skip FFMpeg installation/building.
+ --skip-alembic
+ Unconditionally skip Alembic installation/building.
+
--required-numpy
Use this in case your distro features a valid python package, but no matching Numpy one.
It will force compilation of both python and numpy\""
@@ -264,6 +273,11 @@ MP3LAME_DEV=""
OPENJPEG_USE=false
OPENJPEG_DEV=""
+ALEMBIC_VERSION="1.5.5"
+ALEMBIC_VERSION_MIN="1.5.5"
+ALEMBIC_FORCE_REBUILD=false
+ALEMBIC_SKIP=false
+
# Switch to english language, else some things (like check_package_DEB()) won't work!
LANG_BACK=$LANG
LANG=""
@@ -423,6 +437,9 @@ while true; do
--force-ffmpeg)
FFMPEG_FORCE_REBUILD=true; shift; continue
;;
+ --force-alembic)
+ ALEMBIC_FORCE_REBUILD=true; shift; continue
+ ;;
--skip-python)
PYTHON_SKIP=true; shift; continue
;;
@@ -453,6 +470,9 @@ while true; do
--skip-ffmpeg)
FFMPEG_SKIP=true; shift; continue
;;
+ --skip-alembic)
+ ALEMBIC_SKIP=true; shift; continue
+ ;;
--required-numpy)
NUMPY_REQUIRED=true; shift; continue
;;
@@ -510,9 +530,12 @@ OSL_SOURCE_REPO_UID="22ee5ea298fd215430dfbd160b5aefd507f06db0"
OSL_SOURCE_REPO_BRANCH="blender-fixes"
OPENCOLLADA_SOURCE=( "https://github.com/KhronosGroup/OpenCOLLADA.git" )
-OPENCOLLADA_REPO_UID="18da7f4109a8eafaa290a33f5550501cc4c8bae8"
+OPENCOLLADA_REPO_UID="3335ac164e68b2512a40914b14c74db260e6ff7d"
FFMPEG_SOURCE=( "http://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2" )
+ALEMBIC_SOURCE=( "https://code.google.com/p/alembic/" )
+ALEMBIC_REPO_UID=( "1_05_05" )
+
##### Generic Helpers #####
@@ -839,6 +862,7 @@ compile_Boost() {
# Rebuild dependecies as well!
OIIO_FORCE_REBUILD=true
OSL_FORCE_REBUILD=true
+ ALEMBIC_FORCE_REBUILD=true
prepare_opt
@@ -1374,7 +1398,7 @@ EOF
cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$_inst"
cmake_d="$cmake_d -D LLVM_ENABLE_FFI=ON"
cmake_d="$cmake_d -D LLVM_TARGETS_TO_BUILD=X86"
- cmake_d="$cmake_d -D -DLLVM_ENABLE_TERMINFO=OFF"
+ cmake_d="$cmake_d -D LLVM_ENABLE_TERMINFO=OFF"
if [ -d $_FFI_INCLUDE_DIR ]; then
cmake_d="$cmake_d -D FFI_INCLUDE_DIR=$_FFI_INCLUDE_DIR"
@@ -1537,7 +1561,7 @@ clean_OpenCOLLADA() {
compile_OpenCOLLADA() {
# To be changed each time we make edits that would modify the compiled results!
- opencollada_magic=8
+ opencollada_magic=9
_init_opencollada
# Clean install if needed!
@@ -1706,6 +1730,165 @@ compile_FFmpeg() {
fi
}
+#### Build ALEMBIC ####
+_init_alembic() {
+ _src=$SRC/Alembic-$ALEMBIC_VERSION
+ _hg=false
+ _inst=$INST/alembic-$ALEMBIC_VERSION
+ _inst_shortcut=$INST/alembic
+}
+
+clean_alembic() {
+ _init_alembic
+ _clean
+}
+
+compile_alembic() {
+ # To be changed each time we make edits that would modify the compiled result!
+ alembic_magic=1
+ _init_alembic
+
+ # Clean install if needed!
+ magic_compile_check alembic-$ALEMBIC_VERSION $alembic_magic
+ if [ $? -eq 1 -o $ALEMBIC_FORCE_REBUILD == true ]; then
+ clean_alembic
+ fi
+
+ if [ ! -d $_inst ]; then
+ INFO "Building Alembic-$ALEMBIC_VERSION"
+
+ prepare_opt
+
+ if [ ! -d $_src ]; then
+ mkdir -p $SRC
+ hg clone -u $ALEMBIC_REPO_UID $ALEMBIC_SOURCE $_src
+ fi
+
+ cd $_src
+
+ # XXX Ugly patching hack!
+ # Alembice cmake files are erratic, to say the least
+ # have to manually disable a bunch of crap here
+ cat << EOF | patch -p1
+--- a/CMakeLists.txt Mon Jul 28 10:09:21 2014 -0700
++++ b/CMakeLists.txt Thu Oct 16 15:03:27 2014 +0200
+@@ -57,9 +57,9 @@
+ ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH} )
+ SET( VERSION ${PROJECT_VERSION} )
+
+-SET( ALEMBIC_NO_TESTS FALSE )
+-SET( ALEMBIC_NO_BOOTSTRAP FALSE )
+-SET( ALEMBIC_NO_OPENGL FALSE )
++SET( ALEMBIC_NO_TESTS TRUE )
++SET( ALEMBIC_NO_BOOTSTRAP TRUE )
++SET( ALEMBIC_NO_OPENGL TRUE )
+
+ MESSAGE(STATUS "CMAKE SYSTEM NAME = ${CMAKE_SYSTEM_NAME}" )
+
+@@ -306,15 +306,15 @@
+ ENDIF()
+
+ # Include PyAlembic stuff
+-IF(DEFINED USE_PYALEMBIC AND NOT USE_PYALEMBIC)
+- MESSAGE(STATUS "Skipping Alembic Python bindings")
+-ELSE()
+- MESSAGE(STATUS "About to include Python cmake files")
+- ADD_SUBDIRECTORY( python )
+-ENDIF()
++#IF(DEFINED USE_PYALEMBIC AND NOT USE_PYALEMBIC)
++# MESSAGE(STATUS "Skipping Alembic Python bindings")
++#ELSE()
++# MESSAGE(STATUS "About to include Python cmake files")
++# ADD_SUBDIRECTORY( python )
++#ENDIF()
+
+ # Example code not supported
+-ADD_SUBDIRECTORY( examples )
++#ADD_SUBDIRECTORY( examples )
+
+ # Uncomment to build python docs Makefile (requires Sphinx)
+ # Run `make docs` from build root
+
+EOF
+
+ cat << EOF | patch -p1
+--- a/lib/Alembic/Util/CMakeLists.txt Mon Jul 28 10:09:21 2014 -0700
++++ b/lib/Alembic/Util/CMakeLists.txt Thu Oct 16 15:03:27 2014 +0200
+@@ -65,7 +65,7 @@
+ DESTINATION include/Alembic/Util
+ PERMISSIONS OWNER_READ GROUP_READ WORLD_READ )
+
+-IF( NOT ALEMBIC_NO_TESTS )
+- ADD_SUBDIRECTORY( Tests )
+-ENDIF()
++#IF( NOT ALEMBIC_NO_TESTS )
++# ADD_SUBDIRECTORY( Tests )
++#ENDIF()
+
+EOF
+
+ cat << EOF | patch -p1
+--- a/python/CMakeLists.txt Mon Jul 28 10:09:21 2014 -0700
++++ b/python/CMakeLists.txt Thu Oct 16 14:20:25 2014 +0200
+@@ -35,4 +35,4 @@
+
+ ADD_SUBDIRECTORY( PyAlembic )
+ ADD_SUBDIRECTORY( PyAbcOpenGL )
+-ADD_SUBDIRECTORY( examples )
++#ADD_SUBDIRECTORY( examples )
+
+EOF
+
+ # Always refresh the whole build!
+ # XXX 'build' directory is included in Alembic sources, don't touch that
+ if [ -d blender_build ]; then
+ rm -rf blender_build
+ fi
+ mkdir blender_build
+ cd blender_build
+
+ # XXX Alembic cmake doesn't take these as options
+ # XXX Alembic creates a subfolder itself ... rather than fix their
+ # stupid build files, just expect this here by using $INST as prefix
+ export ALEMBIC_INSTALL_PREFIX=$INST
+
+ cmake_d="-D CMAKE_BUILD_TYPE=Release"
+ cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$INST"
+ cmake_d="$cmake_d -D BUILD_SHARED_LIBS=ON"
+ cmake_d="$cmake_d -D BUILD_STATIC_LIBS=ON"
+ cmake_d="$cmake_d -D USE_PYTHON=OFF"
+ cmake_d="$cmake_d -D USE_PYALEMBIC=OFF"
+ cmake_d="$cmakd_d -D ALEMBIC_PYTHON_INCLUDE_DIR=/use/include/python2.7" # XXX BAD
+ cmake_d="$cmakd_d -D ALEMBIC_PYTHON_LIBRARY=/use/lib/python2.7" # XXX BAD
+ cmake_d="$cmake_d -D USE_PYILMBASE=OFF"
+ cmake_d="$cmake_d -D ILMBASE_ROOT=$INST/openexr"
+ cmake_d="$cmake_d -D ALEMBIC_ILMBASE_HALF_LIB=$INST/openexr/lib/libHalf.la"
+ cmake_d="$cmake_d -D ALEMBIC_ILMBASE_IEX_LIB=$INST/openexr/lib/libIex-2_1.la"
+ cmake_d="$cmake_d -D ALEMBIC_ILMBASE_ILMTHREAD_LIB=$INST/openexr/lib/libIlmThread-2_1.la"
+ cmake_d="$cmake_d -D ALEMBIC_ILMBASE_IMATH_LIB=$INST/openexr/lib/libImath-2_1.la"
+
+ cmake $cmake_d ../
+
+ make -j$THREADS && make install
+ make clean
+
+ if [ -d $_inst ]; then
+ _create_inst_shortcut
+ else
+ ERROR "Alembic-$ALEMBIC_VERSION failed to compile, exiting"
+ exit 1
+ fi
+
+ magic_compile_set alembic-$ALEMBIC_VERSION $alembic_magic
+
+ cd $CWD
+ INFO "Done compiling Alembic-$ALEMBIC_VERSION!"
+ else
+ INFO "Own Alembic-$ALEMBIC_VERSION is up to date, nothing to do!"
+ INFO "If you want to force rebuild of this lib, use the --force-alembic option."
+ fi
+}
+
#### Install on DEB-like ####
get_package_version_DEB() {
@@ -1812,7 +1995,7 @@ install_DEB() {
OGG_DEV="libogg-dev"
THEORA_DEV="libtheora-dev"
- _packages="gawk cmake cmake-curses-gui scons build-essential libjpeg-dev libpng-dev \
+ _packages="gawk cmake cmake-curses-gui scons mercurial build-essential libjpeg-dev libpng-dev \
libfreetype6-dev libx11-dev libxi-dev wget libsqlite3-dev libbz2-dev \
libncurses5-dev libssl-dev liblzma-dev libreadline-dev $OPENJPEG_DEV \
libopenal-dev libglew-dev libglewmx-dev yasm $THEORA_DEV $VORBIS_DEV $OGG_DEV \
@@ -1992,7 +2175,8 @@ install_DEB() {
if [ $? -eq 0 ]; then
install_packages_DEB libboost-locale$boost_version-dev libboost-filesystem$boost_version-dev \
libboost-regex$boost_version-dev libboost-system$boost_version-dev \
- libboost-thread$boost_version-dev libboost-wave$boost_version-dev
+ libboost-thread$boost_version-dev libboost-python$boost_version-dev \
+ libboost-program-options$boost_version-dev libboost-wave$boost_version-dev
clean_Boost
else
compile_Boost
@@ -2125,6 +2309,14 @@ install_DEB() {
# fi
compile_FFmpeg
fi
+
+ if $ALEMBIC_SKIP; then
+ WARNING "Skipping Alembic installation, as requested..."
+ else
+ install_packages_DEB libhdf5-dev
+ install_packages_DEB libpython2.7-dev # XXX nasty hack, should be done better ...
+ compile_alembic
+ fi
}
@@ -2287,7 +2479,7 @@ install_RPM() {
OGG_DEV="libogg-devel"
THEORA_DEV="libtheora-devel"
- _packages="gcc gcc-c++ make scons libtiff-devel freetype-devel libjpeg-devel\
+ _packages="gcc gcc-c++ make scons libtiff-devel libjpeg-devel\
libpng-devel libX11-devel libXi-devel wget ncurses-devel \
readline-devel $OPENJPEG_DEV openal-soft-devel \
glew-devel yasm $THEORA_DEV $VORBIS_DEV $OGG_DEV patch \
@@ -2301,7 +2493,7 @@ install_RPM() {
if [ $RPM = "FEDORA" -o $RPM = "RHEL" ]; then
OPENEXR_DEV="openexr-devel"
- _packages="$_packages libsqlite3x-devel fftw-devel SDL-devel"
+ _packages="$_packages freetype-devel libsqlite3x-devel fftw-devel SDL-devel"
if $WITH_ALL; then
_packages="$_packages jack-audio-connection-kit-devel"
@@ -2339,7 +2531,7 @@ install_RPM() {
elif [ $RPM = "SUSE" ]; then
OPENEXR_DEV="libopenexr-devel"
- _packages="$_packages cmake sqlite3-devel fftw3-devel libSDL-devel"
+ _packages="$_packages cmake freetype2-devel sqlite3-devel fftw3-devel libSDL-devel"
PRINT ""
install_packages_RPM $_packages
@@ -3030,6 +3222,12 @@ print_info() {
fi
fi
+ if [ -d $INST/alembic ]; then
+ _1="-D ALEMBIC_ROOT_DIR=$INST/alembic"
+ PRINT " $_1"
+ _buildargs="$_buildargs $_1"
+ fi
+
PRINT ""
PRINT "Or even simpler, just run (in your blender-source dir):"
PRINT " make -j$THREADS BUILD_CMAKE_ARGS=\"$_buildargs\""
@@ -3099,6 +3297,13 @@ print_info() {
PRINT "BF_FFMPEG_LIB = 'avformat avcodec swscale avutil avdevice `print_info_ffmpeglink`'"
fi
+ if [ "$ALEMBIC_SKIP" = false ]; then
+ PRINT "WITH_BF_ALEMBIC = True"
+ if [ -d $INST/alembic ]; then
+ PRINT "BF_ALEMBIC = '$INST/alembic'"
+ fi
+ fi
+
if [ "$WITH_ALL" = false ]; then
PRINT "WITH_BF_3DMOUSE = False"
# No libspacenav in official arch repos...
diff --git a/build_files/buildbot/config/user-config-glibc211-i686.py b/build_files/buildbot/config/user-config-glibc211-i686.py
index 06c43be32f2..d9c3fe59bc3 100644
--- a/build_files/buildbot/config/user-config-glibc211-i686.py
+++ b/build_files/buildbot/config/user-config-glibc211-i686.py
@@ -166,6 +166,19 @@ BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
# Ocean Simulation
WITH_BF_OCEANSIM = True
+# Alembic
+WITH_BF_HDF5 = False
+WITH_BF_ALEMBIC = True
+WITH_BF_STATICALEMBIC = True
+BF_ALEMBIC = '/opt/lib/alembic'
+BF_ALEMBIC_INC = '${BF_ALEMBIC}/include'
+BF_ALEMBIC_LIBPATH = '${BF_ALEMBIC}/lib/static'
+BF_ALEMBIC_LIB_STATIC = '${BF_ALEMBIC_LIBPATH}/libAlembicAbcGeom.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbc.a ' + \
+ '${BF_ALEMBIC_LIBPATH}/libAlembicAbcCollection.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreFactory.a ' + \
+ '${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcMaterial.a ' + \
+ '${BF_ALEMBIC_LIBPATH}/libAlembicOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreAbstract.a ' + \
+ '${BF_ALEMBIC_LIBPATH}/libAlembicUtil.a'
+
# Compilation and optimization
BF_DEBUG = False
REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++
diff --git a/build_files/buildbot/config/user-config-glibc211-x86_64.py b/build_files/buildbot/config/user-config-glibc211-x86_64.py
index 29f6143f50e..cc19472961d 100644
--- a/build_files/buildbot/config/user-config-glibc211-x86_64.py
+++ b/build_files/buildbot/config/user-config-glibc211-x86_64.py
@@ -166,6 +166,19 @@ BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
# Ocean Simulation
WITH_BF_OCEANSIM = True
+# Alembic
+WITH_BF_HDF5 = False
+WITH_BF_ALEMBIC = True
+WITH_BF_STATICALEMBIC = True
+BF_ALEMBIC = '/opt/lib/alembic'
+BF_ALEMBIC_INC = '${BF_ALEMBIC}/include'
+BF_ALEMBIC_LIBPATH = '${BF_ALEMBIC}/lib/static'
+BF_ALEMBIC_LIB_STATIC = '${BF_ALEMBIC_LIBPATH}/libAlembicAbcGeom.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbc.a ' + \
+ '${BF_ALEMBIC_LIBPATH}/libAlembicAbcCollection.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreFactory.a ' + \
+ '${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcMaterial.a ' + \
+ '${BF_ALEMBIC_LIBPATH}/libAlembicOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreAbstract.a ' + \
+ '${BF_ALEMBIC_LIBPATH}/libAlembicUtil.a'
+
# Compilation and optimization
BF_DEBUG = False
REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++
diff --git a/build_files/buildbot/config/user-config-mac-i386.py b/build_files/buildbot/config/user-config-mac-i386.py
index ab93628c78d..c1beefcf83d 100644
--- a/build_files/buildbot/config/user-config-mac-i386.py
+++ b/build_files/buildbot/config/user-config-mac-i386.py
@@ -5,3 +5,5 @@ WITH_BF_CYCLES_CUDA_BINARIES = True
WITH_BF_CYCLES_OSL = False # OSL never worked on OSX 32bit !
+WITH_BF_COLLADA = False # we drop 32bit, newest collada is only x86_64 !
+
diff --git a/build_files/buildbot/config/user-config-mac-x86_64.py b/build_files/buildbot/config/user-config-mac-x86_64.py
index ac923f48abe..6a13c80f6ce 100644
--- a/build_files/buildbot/config/user-config-mac-x86_64.py
+++ b/build_files/buildbot/config/user-config-mac-x86_64.py
@@ -1,5 +1,6 @@
+CC = "../lib/darwin-9.x.universal/clang-omp-3.5/bin/clang"
+CXX = "../lib/darwin-9.x.universal/clang-omp-3.5/bin/clang++"
MACOSX_ARCHITECTURE = 'x86_64' # valid archs: ppc, i386, ppc64, x86_64
WITH_BF_CYCLES_CUDA_BINARIES = True
-
diff --git a/build_files/buildbot/config/user-config-player-glibc211-i686.py b/build_files/buildbot/config/user-config-player-glibc211-i686.py
index b3c26ebb310..88889e272b8 100644
--- a/build_files/buildbot/config/user-config-player-glibc211-i686.py
+++ b/build_files/buildbot/config/user-config-player-glibc211-i686.py
@@ -120,6 +120,19 @@ WITH_BF_FFTW3 = True
WITH_BF_STATICFFTW3 = True
WITH_BF_OCEANSIM = True
+# Alembic
+WITH_BF_HDF5 = False
+WITH_BF_ALEMBIC = True
+WITH_BF_STATICALEMBIC = True
+BF_ALEMBIC = '/opt/lib/alembic'
+BF_ALEMBIC_INC = '${BF_ALEMBIC}/include'
+BF_ALEMBIC_LIBPATH = '${BF_ALEMBIC}/lib/static'
+BF_ALEMBIC_LIB_STATIC = '${BF_ALEMBIC_LIBPATH}/libAlembicAbcGeom.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbc.a ' + \
+ '${BF_ALEMBIC_LIBPATH}/libAlembicAbcCollection.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreFactory.a ' + \
+ '${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcMaterial.a ' + \
+ '${BF_ALEMBIC_LIBPATH}/libAlembicOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreAbstract.a ' + \
+ '${BF_ALEMBIC_LIBPATH}/libAlembicUtil.a'
+
# Compilation and optimization
BF_DEBUG = False
REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++
diff --git a/build_files/buildbot/config/user-config-player-glibc211-x86_64.py b/build_files/buildbot/config/user-config-player-glibc211-x86_64.py
index 173e15b08ca..dad2ad1b9d6 100644
--- a/build_files/buildbot/config/user-config-player-glibc211-x86_64.py
+++ b/build_files/buildbot/config/user-config-player-glibc211-x86_64.py
@@ -120,6 +120,19 @@ WITH_BF_FFTW3 = True
WITH_BF_STATICFFTW3 = True
WITH_BF_OCEANSIM = True
+# Alembic
+WITH_BF_HDF5 = False
+WITH_BF_ALEMBIC = True
+WITH_BF_STATICALEMBIC = True
+BF_ALEMBIC = '/opt/lib/alembic'
+BF_ALEMBIC_INC = '${BF_ALEMBIC}/include'
+BF_ALEMBIC_LIBPATH = '${BF_ALEMBIC}/lib/static'
+BF_ALEMBIC_LIB_STATIC = '${BF_ALEMBIC_LIBPATH}/libAlembicAbcGeom.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbc.a ' + \
+ '${BF_ALEMBIC_LIBPATH}/libAlembicAbcCollection.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreFactory.a ' + \
+ '${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcMaterial.a ' + \
+ '${BF_ALEMBIC_LIBPATH}/libAlembicOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreAbstract.a ' + \
+ '${BF_ALEMBIC_LIBPATH}/libAlembicUtil.a'
+
# Compilation and optimization
BF_DEBUG = False
REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++
diff --git a/build_files/buildbot/master_unpack.py b/build_files/buildbot/master_unpack.py
index 46131c5e1de..ec44705931c 100644
--- a/build_files/buildbot/master_unpack.py
+++ b/build_files/buildbot/master_unpack.py
@@ -124,10 +124,12 @@ else:
directory = 'public_html/download'
try:
+ filename = os.path.join(directory, packagename)
zf = z.open(package)
- f = file(os.path.join(directory, packagename), "wb")
+ f = file(filename, "wb")
shutil.copyfileobj(zf, f)
+ os.chmod(filename, 0644)
zf.close()
z.close()
diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py
index cbe345e764c..7b3f848a198 100644
--- a/build_files/buildbot/slave_compile.py
+++ b/build_files/buildbot/slave_compile.py
@@ -116,6 +116,8 @@ else:
if config.find('player') != -1:
scons_options.append('BF_BUILDDIR=%s_player' % (build_dir))
+ elif config.find('cuda') != -1:
+ scons_options.append('BF_BUILDDIR=%s_cuda' % (build_dir))
else:
scons_options.append('BF_BUILDDIR=%s' % (build_dir))
@@ -140,7 +142,7 @@ else:
retcode = subprocess.call(cur_scons_cmd + scons_options)
if retcode != 0:
- print('Error building rules wuth config ' + config)
+ print('Error building rules with config ' + config)
sys.exit(retcode)
sys.exit(0)
diff --git a/build_files/cmake/Modules/FindAlembic.cmake b/build_files/cmake/Modules/FindAlembic.cmake
new file mode 100644
index 00000000000..1fd964026d2
--- /dev/null
+++ b/build_files/cmake/Modules/FindAlembic.cmake
@@ -0,0 +1,103 @@
+# - Find Alembic library
+# Find the native Alembic includes and library
+# This module defines
+# ALEMBIC_INCLUDE_DIRS, where to find Alembic headers.
+# ALEMBIC_LIBRARIES, libraries to link against to use Alembic.
+# ALEMBIC_ROOT_DIR, The base directory to search for Alembic.
+# This can also be an environment variable.
+# ALEMBIC_FOUND, If false, do not try to use Alembic.
+# ALEMBIC_HDF5_FOUND, indicates whether Alembic supports HDF5
+
+#=============================================================================
+# Copyright 2013 Blender Foundation.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+# If ALEMBIC_ROOT_DIR was defined in the environment, use it.
+IF(NOT ALEMBIC_ROOT_DIR AND NOT $ENV{ALEMBIC_ROOT_DIR} STREQUAL "")
+ SET(ALEMBIC_ROOT_DIR $ENV{ALEMBIC_ROOT_DIR})
+ENDIF()
+
+SET(_alembic_SEARCH_DIRS
+ ${ALEMBIC_ROOT_DIR}
+ /usr/local
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt/lib/alembic
+)
+
+SET(_alembic_FIND_COMPONENTS
+ AlembicAbc
+ AlembicAbcCoreAbstract
+ AlembicAbcGeom
+ AlembicAbcCoreOgawa
+ AlembicOgawa
+ AlembicUtil
+)
+
+FIND_PATH(ALEMBIC_INCLUDE_DIR
+ NAMES
+ Alembic/Abc/All.h
+ HINTS
+ ${_alembic_SEARCH_DIRS}
+ PATH_SUFFIXES
+ include
+)
+
+SET(_alembic_LIBRARIES)
+FOREACH(COMPONENT ${_alembic_FIND_COMPONENTS})
+ STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
+
+ FIND_LIBRARY(ALEMBIC_${UPPERCOMPONENT}_LIBRARY
+ NAMES
+ ${COMPONENT}
+ HINTS
+ ${_alembic_SEARCH_DIRS}
+ PATH_SUFFIXES
+ lib
+ lib/static
+ )
+ MARK_AS_ADVANCED(ALEMBIC_${UPPERCOMPONENT}_LIBRARY)
+ LIST(APPEND _alembic_LIBRARIES "${ALEMBIC_${UPPERCOMPONENT}_LIBRARY}")
+ENDFOREACH()
+
+# Sepcial handling of optional libraries
+FIND_LIBRARY(ALEMBIC_ALEMBICABCCOREHDF5_LIBRARY
+ NAMES
+ AlembicAbcCoreHDF5
+ HINTS
+ ${_alembic_SEARCH_DIRS}
+ PATH_SUFFIXES
+ lib
+ lib/static
+ )
+MARK_AS_ADVANCED(ALEMBIC_ALEMBICABCCOREHDF5_LIBRARY)
+IF(ALEMBIC_ALEMBICABCCOREHDF5_LIBRARY)
+ LIST(APPEND _alembic_LIBRARIES "${ALEMBIC_ALEMBICABCCOREHDF5_LIBRARY}")
+ SET(ALEMBIC_HDF5_FOUND TRUE)
+ELSE()
+ SET(ALEMBIC_HDF5_FOUND FALSE)
+ENDIF()
+
+# handle the QUIETLY and REQUIRED arguments and set ALEMBIC_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Alembic DEFAULT_MSG
+ _alembic_LIBRARIES ALEMBIC_INCLUDE_DIR)
+
+IF(ALEMBIC_FOUND)
+ SET(ALEMBIC_LIBRARIES ${_alembic_LIBRARIES})
+ SET(ALEMBIC_INCLUDE_DIRS ${ALEMBIC_INCLUDE_DIR})
+ENDIF(ALEMBIC_FOUND)
+
+MARK_AS_ADVANCED(
+ ALEMBIC_INCLUDE_DIR
+ ALEMBIC_LIBRARIES
+)
diff --git a/build_files/cmake/Modules/FindEigen3.cmake b/build_files/cmake/Modules/FindEigen3.cmake
new file mode 100644
index 00000000000..400e8eb047d
--- /dev/null
+++ b/build_files/cmake/Modules/FindEigen3.cmake
@@ -0,0 +1,56 @@
+# - Find Eigen3 library
+# Find the native Eigen3 includes and library
+# This module defines
+# EIGEN3_INCLUDE_DIRS, where to find spnav.h, Set when
+# EIGEN3_INCLUDE_DIR is found.
+# EIGEN3_ROOT_DIR, The base directory to search for Eigen3.
+# This can also be an environment variable.
+# EIGEN3_FOUND, If false, do not try to use Eigen3.
+#
+#=============================================================================
+# Copyright 2015 Blender Foundation.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+# If EIGEN3_ROOT_DIR was defined in the environment, use it.
+IF(NOT EIGEN3_ROOT_DIR AND NOT $ENV{EIGEN3_ROOT_DIR} STREQUAL "")
+ SET(EIGEN3_ROOT_DIR $ENV{EIGEN3_ROOT_DIR})
+ENDIF()
+
+SET(_eigen3_SEARCH_DIRS
+ ${EIGEN3_ROOT_DIR}
+ /usr/local
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+)
+
+FIND_PATH(EIGEN3_INCLUDE_DIR
+ NAMES
+ # header has no '.h' suffix
+ Eigen/Eigen
+ HINTS
+ ${_eigen3_SEARCH_DIRS}
+ PATH_SUFFIXES
+ include/eigen3
+)
+
+# handle the QUIETLY and REQUIRED arguments and set EIGEN3_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Eigen3 DEFAULT_MSG
+ EIGEN3_INCLUDE_DIR)
+
+IF(EIGEN3_FOUND)
+ SET(EIGEN3_INCLUDE_DIRS ${EIGEN3_INCLUDE_DIR})
+ENDIF(EIGEN3_FOUND)
+
+MARK_AS_ADVANCED(
+ EIGEN3_INCLUDE_DIR
+)
diff --git a/build_files/cmake/Modules/FindHDF5.cmake b/build_files/cmake/Modules/FindHDF5.cmake
new file mode 100644
index 00000000000..d395519e1fe
--- /dev/null
+++ b/build_files/cmake/Modules/FindHDF5.cmake
@@ -0,0 +1,75 @@
+# - Find HDF5 library
+# Find the native hdf5 includes and library
+# This module defines
+# HDF5_INCLUDE_DIRS, where to find hdf5 headers.
+# HDF5_LIBRARIES, libraries to link against to use hdf5.
+# HDF5_ROOT_DIR, The base directory to search for hdf5.
+# This can also be an environment variable.
+# HDF5_FOUND, If false, do not try to use hdf5.
+
+#=============================================================================
+# Copyright 2013 Blender Foundation.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+# If HDF5_ROOT_DIR was defined in the environment, use it.
+IF(NOT HDF5_ROOT_DIR AND NOT $ENV{HDF5_ROOT_DIR} STREQUAL "")
+ SET(HDF5_ROOT_DIR $ENV{HDF5_ROOT_DIR})
+ENDIF()
+
+SET(_hdf5_SEARCH_DIRS
+ ${HDF5_ROOT_DIR}
+ /usr/local
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt/lib/hdf5
+)
+
+SET(_hdf5_FIND_COMPONENTS
+ hdf5
+ hdf5_hl
+)
+
+FIND_PATH(_hdf5_INCLUDE_DIRS
+ NAMES
+ hdf5.h
+ HINTS
+ ${_hdf5_SEARCH_DIRS}
+)
+
+SET(_hdf5_LIBRARIES)
+FOREACH(COMPONENT ${_hdf5_FIND_COMPONENTS})
+ STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
+
+ FIND_LIBRARY(HDF5_${UPPERCOMPONENT}_LIBRARY
+ NAMES
+ ${COMPONENT}
+ HINTS
+ ${_hdf5_SEARCH_DIRS}
+ )
+ MARK_AS_ADVANCED(HDF5_${UPPERCOMPONENT}_LIBRARY)
+ LIST(APPEND _hdf5_LIBRARIES "${HDF5_${UPPERCOMPONENT}_LIBRARY}")
+ENDFOREACH()
+
+# handle the QUIETLY and REQUIRED arguments and set HDF5_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(hdf5 DEFAULT_MSG
+ _hdf5_LIBRARIES _hdf5_INCLUDE_DIRS)
+
+IF(HDF5_FOUND)
+ SET(HDF5_LIBRARIES ${_hdf5_LIBRARIES})
+ SET(HDF5_INCLUDE_DIRS ${_hdf5_INCLUDE_DIRS})
+ENDIF(HDF5_FOUND)
+
+MARK_AS_ADVANCED(
+ HDF5_INCLUDE_DIRS
+ HDF5_LIBRARIES
+)
diff --git a/build_files/cmake/Modules/FindLLVM.cmake b/build_files/cmake/Modules/FindLLVM.cmake
new file mode 100644
index 00000000000..43791c8df8c
--- /dev/null
+++ b/build_files/cmake/Modules/FindLLVM.cmake
@@ -0,0 +1,94 @@
+# - Find LLVM library
+# Find the native LLVM includes and library
+# This module defines
+# LLVM_INCLUDE_DIRS, where to find LLVM.h, Set when LLVM_INCLUDE_DIR is found.
+# LLVM_LIBRARIES, libraries to link against to use LLVM.
+# LLVM_ROOT_DIR, The base directory to search for LLVM.
+# This can also be an environment variable.
+# LLVM_FOUND, If false, do not try to use LLVM.
+#
+# also defined, but not for general use are
+# LLVM_LIBRARY, where to find the LLVM library.
+
+#=============================================================================
+# Copyright 2015 Blender Foundation.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+if(LLVM_ROOT_DIR)
+ if(DEFINED LLVM_VERSION)
+ find_program(LLVM_CONFIG llvm-config-${LLVM_VERSION} HINTS ${LLVM_ROOT_DIR}/bin NO_CMAKE_PATH)
+ endif()
+ if(NOT LLVM_CONFIG)
+ find_program(LLVM_CONFIG llvm-config HINTS ${LLVM_ROOT_DIR}/bin NO_CMAKE_PATH)
+ endif()
+else()
+ if(DEFINED LLVM_VERSION)
+ message(running llvm-config-${LLVM_VERSION})
+ find_program(LLVM_CONFIG llvm-config-${LLVM_VERSION})
+ endif()
+ if(NOT LLVM_CONFIG)
+ find_program(LLVM_CONFIG llvm-config)
+ endif()
+endif()
+
+if(NOT DEFINED LLVM_VERSION)
+ execute_process(COMMAND ${LLVM_CONFIG} --version
+ OUTPUT_VARIABLE LLVM_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ set(LLVM_VERSION ${LLVM_VERSION} CACHE STRING "Version of LLVM to use")
+endif()
+if(NOT LLVM_ROOT_DIR)
+ execute_process(COMMAND ${LLVM_CONFIG} --prefix
+ OUTPUT_VARIABLE LLVM_ROOT_DIR
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ set(LLVM_ROOT_DIR ${LLVM_ROOT_DIR} CACHE PATH "Path to the LLVM installation")
+endif()
+if(NOT LLVM_LIBPATH)
+ execute_process(COMMAND ${LLVM_CONFIG} --libdir
+ OUTPUT_VARIABLE LLVM_LIBPATH
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ set(LLVM_LIBPATH ${LLVM_LIBPATH} CACHE PATH "Path to the LLVM library path")
+ mark_as_advanced(LLVM_LIBPATH)
+endif()
+
+if(LLVM_STATIC)
+ find_library(LLVM_LIBRARY
+ NAMES LLVMAnalysis # first of a whole bunch of libs to get
+ PATHS ${LLVM_LIBPATH})
+else()
+ find_library(LLVM_LIBRARY
+ NAMES LLVM-${LLVM_VERSION}
+ PATHS ${LLVM_LIBPATH})
+endif()
+
+
+if(LLVM_LIBRARY AND LLVM_ROOT_DIR AND LLVM_LIBPATH)
+ if(LLVM_STATIC)
+ # if static LLVM libraries were requested, use llvm-config to generate
+ # the list of what libraries we need, and substitute that in the right
+ # way for LLVM_LIBRARY.
+ execute_process(COMMAND ${LLVM_CONFIG} --libfiles
+ OUTPUT_VARIABLE LLVM_LIBRARY
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ string(REPLACE " " ";" LLVM_LIBRARY "${LLVM_LIBRARY}")
+ endif()
+endif()
+
+
+# handle the QUIETLY and REQUIRED arguments and set SDL2_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LLVM DEFAULT_MSG
+ LLVM_LIBRARY)
+
+MARK_AS_ADVANCED(
+ LLVM_LIBRARY
+)
+
diff --git a/build_files/cmake/Modules/FindLZO.cmake b/build_files/cmake/Modules/FindLZO.cmake
new file mode 100644
index 00000000000..a21aa0a03bb
--- /dev/null
+++ b/build_files/cmake/Modules/FindLZO.cmake
@@ -0,0 +1,68 @@
+# - Find LZO library
+# Find the native LZO includes and library
+# This module defines
+# LZO_INCLUDE_DIRS, where to find lzo1x.h, Set when
+# LZO_INCLUDE_DIR is found.
+# LZO_LIBRARIES, libraries to link against to use LZO.
+# LZO_ROOT_DIR, The base directory to search for LZO.
+# This can also be an environment variable.
+# LZO_FOUND, If false, do not try to use LZO.
+#
+# also defined, but not for general use are
+# LZO_LIBRARY, where to find the LZO library.
+
+#=============================================================================
+# Copyright 2015 Blender Foundation.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+# If LZO_ROOT_DIR was defined in the environment, use it.
+IF(NOT LZO_ROOT_DIR AND NOT $ENV{LZO_ROOT_DIR} STREQUAL "")
+ SET(LZO_ROOT_DIR $ENV{LZO_ROOT_DIR})
+ENDIF()
+
+SET(_lzo_SEARCH_DIRS
+ ${LZO_ROOT_DIR}
+ /usr/local
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+)
+
+FIND_PATH(LZO_INCLUDE_DIR lzo/lzo1x.h
+ HINTS
+ ${_lzo_SEARCH_DIRS}
+ PATH_SUFFIXES
+ include
+)
+
+FIND_LIBRARY(LZO_LIBRARY
+ NAMES
+ lzo2
+ HINTS
+ ${_lzo_SEARCH_DIRS}
+ PATH_SUFFIXES
+ lib64 lib
+ )
+
+# handle the QUIETLY and REQUIRED arguments and set LZO_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LZO DEFAULT_MSG
+ LZO_LIBRARY LZO_INCLUDE_DIR)
+
+IF(LZO_FOUND)
+ SET(LZO_LIBRARIES ${LZO_LIBRARY})
+ SET(LZO_INCLUDE_DIRS ${LZO_INCLUDE_DIR})
+ENDIF(LZO_FOUND)
+
+MARK_AS_ADVANCED(
+ LZO_INCLUDE_DIR
+ LZO_LIBRARY
+)
diff --git a/build_files/cmake/Modules/FindPCRE.cmake b/build_files/cmake/Modules/FindPCRE.cmake
index 9d73e9200d9..ff4b7261555 100644
--- a/build_files/cmake/Modules/FindPCRE.cmake
+++ b/build_files/cmake/Modules/FindPCRE.cmake
@@ -40,7 +40,6 @@ FIND_PATH(PCRE_INCLUDE_DIR pcre.h
${_pcre_SEARCH_DIRS}
PATH_SUFFIXES
include
- include
)
FIND_LIBRARY(PCRE_LIBRARY
diff --git a/build_files/cmake/Modules/FindPythonLibsUnix.cmake b/build_files/cmake/Modules/FindPythonLibsUnix.cmake
index 1fb27e7898c..e4236fb4c24 100644
--- a/build_files/cmake/Modules/FindPythonLibsUnix.cmake
+++ b/build_files/cmake/Modules/FindPythonLibsUnix.cmake
@@ -14,6 +14,7 @@
# PYTHON_INCLUDE_CONFIG_DIRS
# PYTHON_LIBRARIES
# PYTHON_LIBPATH, Used for installation
+# PYTHON_SITE_PACKAGES, Used for installation (as a Python module)
# PYTHON_LINKFLAGS
# PYTHON_ROOT_DIR, The base directory to search for Python.
# This can also be an environment variable.
@@ -65,6 +66,14 @@ IF(DEFINED PYTHON_LIBPATH)
SET(_IS_LIB_PATH_DEF ON)
ENDIF()
+STRING(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
+
+SET(_python_SEARCH_DIRS
+ ${PYTHON_ROOT_DIR}
+ "$ENV{HOME}/py${_PYTHON_VERSION_NO_DOTS}"
+ "/opt/py${_PYTHON_VERSION_NO_DOTS}"
+ "/opt/lib/python-${PYTHON_VERSION}"
+)
# only search for the dirs if we havn't already
IF((NOT _IS_INC_DEF) OR (NOT _IS_INC_CONF_DEF) OR (NOT _IS_LIB_DEF) OR (NOT _IS_LIB_PATH_DEF))
@@ -74,14 +83,7 @@ IF((NOT _IS_INC_DEF) OR (NOT _IS_INC_CONF_DEF) OR (NOT _IS_LIB_DEF) OR (NOT _IS_
"dm;dmu;du;d" # debug
)
- STRING(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
- SET(_python_SEARCH_DIRS
- ${PYTHON_ROOT_DIR}
- "$ENV{HOME}/py${_PYTHON_VERSION_NO_DOTS}"
- "/opt/py${_PYTHON_VERSION_NO_DOTS}"
- "/opt/lib/python-${PYTHON_VERSION}"
- )
FOREACH(_CURRENT_ABI_FLAGS ${_python_ABI_FLAGS})
#IF(CMAKE_BUILD_TYPE STREQUAL Debug)
@@ -146,6 +148,7 @@ IF((NOT _IS_INC_DEF) OR (NOT _IS_INC_CONF_DEF) OR (NOT _IS_LIB_DEF) OR (NOT _IS_
ENDIF()
IF(PYTHON_LIBRARY AND PYTHON_LIBPATH AND PYTHON_INCLUDE_DIR AND PYTHON_INCLUDE_CONFIG_DIR)
+ SET(_PYTHON_ABI_FLAGS "${_CURRENT_ABI_FLAGS}")
break()
ELSE()
# ensure we dont find values from 2 different ABI versions
@@ -168,7 +171,6 @@ IF((NOT _IS_INC_DEF) OR (NOT _IS_INC_CONF_DEF) OR (NOT _IS_LIB_DEF) OR (NOT _IS_
UNSET(_CURRENT_PATH)
UNSET(_python_ABI_FLAGS)
- UNSET(_python_SEARCH_DIRS)
ENDIF()
UNSET(_IS_INC_DEF)
@@ -187,17 +189,41 @@ IF(PYTHONLIBSUNIX_FOUND)
SET(PYTHON_INCLUDE_DIRS ${PYTHON_INCLUDE_DIR} ${PYTHON_INCLUDE_CONFIG_DIR})
SET(PYTHON_LIBRARIES ${PYTHON_LIBRARY})
+ FIND_FILE(PYTHON_SITE_PACKAGES
+ NAMES
+ # debian specific
+ dist-packages
+ site-packages
+ HINTS
+ ${PYTHON_LIBPATH}/python${PYTHON_VERSION}
+ )
+
# we need this for installation
# XXX No more valid with debian-like py3.4 packages...
# GET_FILENAME_COMPONENT(PYTHON_LIBPATH ${PYTHON_LIBRARY} PATH)
- # not used
- # SET(PYTHON_BINARY ${PYTHON_EXECUTABLE} CACHE STRING "")
+ # not required for build, just used when bundling Python.
+ FIND_PROGRAM(
+ PYTHON_EXECUTABLE
+ NAMES
+ "python${PYTHON_VERSION}${_PYTHON_ABI_FLAGS}"
+ "python${PYTHON_VERSION}"
+ "python"
+ HINTS
+ ${_python_SEARCH_DIRS}
+ PATH_SUFFIXES bin
+ )
ENDIF()
+UNSET(_PYTHON_VERSION_NO_DOTS)
+UNSET(_PYTHON_ABI_FLAGS)
+UNSET(_python_SEARCH_DIRS)
+
MARK_AS_ADVANCED(
PYTHON_INCLUDE_DIR
PYTHON_INCLUDE_CONFIG_DIR
PYTHON_LIBRARY
PYTHON_LIBPATH
+ PYTHON_SITE_PACKAGES
+ PYTHON_EXECUTABLE
)
diff --git a/build_files/cmake/buildinfo.cmake b/build_files/cmake/buildinfo.cmake
index 8ef29b06213..74c1f8f1f8e 100644
--- a/build_files/cmake/buildinfo.cmake
+++ b/build_files/cmake/buildinfo.cmake
@@ -60,7 +60,8 @@ if(EXISTS ${SOURCE_DIR}/.git)
execute_process(COMMAND git log HEAD..@{u}
WORKING_DIRECTORY ${SOURCE_DIR}
OUTPUT_VARIABLE _git_below_check
- OUTPUT_STRIP_TRAILING_WHITESPACE)
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET)
if(NOT _git_below_check STREQUAL "")
# If there're commits between HEAD and upstream this means
# that we're reset-ed to older revision. Use it's hash then.
diff --git a/build_files/cmake/cmake_consistency_check.py b/build_files/cmake/cmake_consistency_check.py
index 0883bdbf2d7..d0bbdda1870 100755
--- a/build_files/cmake/cmake_consistency_check.py
+++ b/build_files/cmake/cmake_consistency_check.py
@@ -28,13 +28,17 @@ if not sys.version.startswith("3"):
sys.version.partition(" ")[0])
sys.exit(1)
-from cmake_consistency_check_config import IGNORE, UTF8_CHECK, SOURCE_DIR
+from cmake_consistency_check_config import (
+ IGNORE,
+ UTF8_CHECK,
+ SOURCE_DIR,
+ BUILD_DIR,
+ )
+
import os
from os.path import join, dirname, normpath, splitext
-print("Scanning:", SOURCE_DIR)
-
global_h = set()
global_c = set()
global_refs = {}
@@ -134,6 +138,7 @@ def cmake_get_src(f):
if found:
cmake_base = dirname(f)
+ cmake_base_bin = os.path.join(BUILD_DIR, os.path.relpath(cmake_base, SOURCE_DIR))
while it is not None:
i += 1
@@ -154,6 +159,8 @@ def cmake_get_src(f):
# replace dirs
l = l.replace("${CMAKE_CURRENT_SOURCE_DIR}", cmake_base)
+ l = l.replace("${CMAKE_CURRENT_BINARY_DIR}", cmake_base_bin)
+ l = l.strip('"')
if not l:
pass
@@ -193,13 +200,16 @@ def cmake_get_src(f):
raise Exception("unknown file type - not c or h %s -> %s" % (f, new_file))
elif context_name == "INC":
- if os.path.isdir(new_file):
+ if new_file.startswith(BUILD_DIR):
+ # assume generated path
+ pass
+ elif os.path.isdir(new_file):
new_path_rel = os.path.relpath(new_file, cmake_base)
if new_path_rel != l:
print("overly relative path:\n %s:%d\n %s\n %s" % (f, i, l, new_path_rel))
- ## Save time. just replace the line
+ # # Save time. just replace the line
# replace_line(f, i - 1, new_path_rel)
else:
@@ -230,10 +240,6 @@ def cmake_get_src(f):
filen.close()
-for cmake in source_list(SOURCE_DIR, is_cmake):
- cmake_get_src(cmake)
-
-
def is_ignore(f):
for ig in IGNORE:
if ig in f:
@@ -241,73 +247,83 @@ def is_ignore(f):
return False
-# First do stupid check, do these files exist?
-print("\nChecking for missing references:")
-is_err = False
-errs = []
-for f in (global_h | global_c):
- if f.endswith("dna.c"):
- continue
-
- if not os.path.exists(f):
- refs = global_refs[f]
- if refs:
- for cf, i in refs:
- errs.append((cf, i))
- else:
- raise Exception("CMake referenecs missing, internal error, aborting!")
- is_err = True
-
-errs.sort()
-errs.reverse()
-for cf, i in errs:
- print("%s:%d" % (cf, i))
- # Write a 'sed' script, useful if we get a lot of these
- # print("sed '%dd' '%s' > '%s.tmp' ; mv '%s.tmp' '%s'" % (i, cf, cf, cf, cf))
-
-
-if is_err:
- raise Exception("CMake referenecs missing files, aborting!")
-del is_err
-del errs
-
-# now check on files not accounted for.
-print("\nC/C++ Files CMake doesnt know about...")
-for cf in sorted(source_list(SOURCE_DIR, is_c)):
- if not is_ignore(cf):
- if cf not in global_c:
- print("missing_c: ", cf)
-
- # check if automake builds a corrasponding .o file.
- '''
- if cf in global_c:
- out1 = os.path.splitext(cf)[0] + ".o"
- out2 = os.path.splitext(cf)[0] + ".Po"
- out2_dir, out2_file = out2 = os.path.split(out2)
- out2 = os.path.join(out2_dir, ".deps", out2_file)
- if not os.path.exists(out1) and not os.path.exists(out2):
- print("bad_c: ", cf)
- '''
-
-print("\nC/C++ Headers CMake doesnt know about...")
-for hf in sorted(source_list(SOURCE_DIR, is_c_header)):
- if not is_ignore(hf):
- if hf not in global_h:
- print("missing_h: ", hf)
-
-if UTF8_CHECK:
- # test encoding
- import traceback
- for files in (global_c, global_h):
- for f in sorted(files):
- if os.path.exists(f):
- # ignore outside of our source tree
- if "extern" not in f:
- i = 1
- try:
- for l in open(f, "r", encoding="utf8"):
- i += 1
- except UnicodeDecodeError:
- print("Non utf8: %s:%d" % (f, i))
- if i > 1:
- traceback.print_exc()
+def main():
+
+ print("Scanning:", SOURCE_DIR)
+
+ for cmake in source_list(SOURCE_DIR, is_cmake):
+ cmake_get_src(cmake)
+
+ # First do stupid check, do these files exist?
+ print("\nChecking for missing references:")
+ is_err = False
+ errs = []
+ for f in (global_h | global_c):
+ if f.startswith(BUILD_DIR):
+ continue
+
+ if not os.path.exists(f):
+ refs = global_refs[f]
+ if refs:
+ for cf, i in refs:
+ errs.append((cf, i))
+ else:
+ raise Exception("CMake referenecs missing, internal error, aborting!")
+ is_err = True
+
+ errs.sort()
+ errs.reverse()
+ for cf, i in errs:
+ print("%s:%d" % (cf, i))
+ # Write a 'sed' script, useful if we get a lot of these
+ # print("sed '%dd' '%s' > '%s.tmp' ; mv '%s.tmp' '%s'" % (i, cf, cf, cf, cf))
+
+
+ if is_err:
+ raise Exception("CMake referenecs missing files, aborting!")
+ del is_err
+ del errs
+
+ # now check on files not accounted for.
+ print("\nC/C++ Files CMake doesnt know about...")
+ for cf in sorted(source_list(SOURCE_DIR, is_c)):
+ if not is_ignore(cf):
+ if cf not in global_c:
+ print("missing_c: ", cf)
+
+ # check if automake builds a corrasponding .o file.
+ '''
+ if cf in global_c:
+ out1 = os.path.splitext(cf)[0] + ".o"
+ out2 = os.path.splitext(cf)[0] + ".Po"
+ out2_dir, out2_file = out2 = os.path.split(out2)
+ out2 = os.path.join(out2_dir, ".deps", out2_file)
+ if not os.path.exists(out1) and not os.path.exists(out2):
+ print("bad_c: ", cf)
+ '''
+
+ print("\nC/C++ Headers CMake doesnt know about...")
+ for hf in sorted(source_list(SOURCE_DIR, is_c_header)):
+ if not is_ignore(hf):
+ if hf not in global_h:
+ print("missing_h: ", hf)
+
+ if UTF8_CHECK:
+ # test encoding
+ import traceback
+ for files in (global_c, global_h):
+ for f in sorted(files):
+ if os.path.exists(f):
+ # ignore outside of our source tree
+ if "extern" not in f:
+ i = 1
+ try:
+ for l in open(f, "r", encoding="utf8"):
+ i += 1
+ except UnicodeDecodeError:
+ print("Non utf8: %s:%d" % (f, i))
+ if i > 1:
+ traceback.print_exc()
+
+if __name__ == "__main__":
+ main()
diff --git a/build_files/cmake/cmake_consistency_check_config.py b/build_files/cmake/cmake_consistency_check_config.py
index 729eecce233..1f75b9884bc 100644
--- a/build_files/cmake/cmake_consistency_check_config.py
+++ b/build_files/cmake/cmake_consistency_check_config.py
@@ -74,3 +74,6 @@ IGNORE = (
UTF8_CHECK = True
SOURCE_DIR = os.path.normpath(os.path.abspath(os.path.normpath(os.path.join(os.path.dirname(__file__), "..", ".."))))
+
+# doesn't have to exist, just use as reference
+BUILD_DIR = os.path.normpath(os.path.abspath(os.path.normpath(os.path.join(SOURCE_DIR, "..", "build"))))
diff --git a/build_files/cmake/cmake_netbeans_project.py b/build_files/cmake/cmake_netbeans_project.py
index 81b1a460f67..25d07373569 100755
--- a/build_files/cmake/cmake_netbeans_project.py
+++ b/build_files/cmake/cmake_netbeans_project.py
@@ -29,18 +29,19 @@ Example linux usage
Windows not supported so far
"""
-from project_info import (SIMPLE_PROJECTFILE,
- SOURCE_DIR,
- CMAKE_DIR,
- PROJECT_DIR,
- source_list,
- is_project_file,
- is_c_header,
- # is_py,
- cmake_advanced_info,
- cmake_compiler_defines,
- project_name_get,
- )
+from project_info import (
+ SIMPLE_PROJECTFILE,
+ SOURCE_DIR,
+ CMAKE_DIR,
+ PROJECT_DIR,
+ source_list,
+ is_project_file,
+ is_c_header,
+ # is_py,
+ cmake_advanced_info,
+ cmake_compiler_defines,
+ project_name_get,
+ )
import os
diff --git a/build_files/cmake/cmake_qtcreator_project.py b/build_files/cmake/cmake_qtcreator_project.py
index 1676d634cf2..67302c89a68 100755
--- a/build_files/cmake/cmake_qtcreator_project.py
+++ b/build_files/cmake/cmake_qtcreator_project.py
@@ -22,26 +22,27 @@
# <pep8 compliant>
-"""
+r"""
+Example Linux usage:
+ python ~/blender-git/blender/build_files/cmake/cmake_qtcreator_project.py ~/blender-git/cmake
+
Example Win32 usage:
c:\Python32\python.exe c:\blender_dev\blender\build_files\cmake\cmake_qtcreator_project.py c:\blender_dev\cmake_build
-
-example linux usage
- python ~/blender-git/blender/build_files/cmake/cmake_qtcreator_project.py ~/blender-git/cmake
"""
-from project_info import (SIMPLE_PROJECTFILE,
- SOURCE_DIR,
- # CMAKE_DIR,
- PROJECT_DIR,
- source_list,
- is_project_file,
- is_c_header,
- is_py,
- cmake_advanced_info,
- cmake_compiler_defines,
- project_name_get,
- )
+from project_info import (
+ SIMPLE_PROJECTFILE,
+ SOURCE_DIR,
+ # CMAKE_DIR,
+ PROJECT_DIR,
+ source_list,
+ is_project_file,
+ is_c_header,
+ is_py,
+ cmake_advanced_info,
+ cmake_compiler_defines,
+ project_name_get,
+ )
import os
import sys
@@ -63,18 +64,19 @@ def create_qtc_project_main():
if SIMPLE_PROJECTFILE:
# --- qtcreator specific, simple format
PROJECT_NAME = "Blender"
- with open(os.path.join(PROJECT_DIR, "%s.files" % PROJECT_NAME), 'w') as f:
+ FILE_NAME = PROJECT_NAME.lower()
+ with open(os.path.join(PROJECT_DIR, "%s.files" % FILE_NAME), 'w') as f:
f.write("\n".join(files_rel))
- with open(os.path.join(PROJECT_DIR, "%s.includes" % PROJECT_NAME), 'w') as f:
+ with open(os.path.join(PROJECT_DIR, "%s.includes" % FILE_NAME), 'w') as f:
f.write("\n".join(sorted(list(set(os.path.dirname(f)
for f in files_rel if is_c_header(f))))))
- qtc_prj = os.path.join(PROJECT_DIR, "%s.creator" % PROJECT_NAME)
+ qtc_prj = os.path.join(PROJECT_DIR, "%s.creator" % FILE_NAME)
with open(qtc_prj, 'w') as f:
f.write("[General]\n")
- qtc_cfg = os.path.join(PROJECT_DIR, "%s.config" % PROJECT_NAME)
+ qtc_cfg = os.path.join(PROJECT_DIR, "%s.config" % FILE_NAME)
if not os.path.exists(qtc_cfg):
with open(qtc_cfg, 'w') as f:
f.write("// ADD PREDEFINED MACROS HERE!\n")
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index 33c764402a2..87a7e8bb472 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -321,6 +321,9 @@ macro(setup_liblinks
endif()
endif()
+ if(WITH_LZO AND WITH_SYSTEM_LZO)
+ target_link_libraries(${target} ${LZO_LIBRARIES})
+ endif()
if(WITH_SYSTEM_GLEW)
target_link_libraries(${target} ${BLENDER_GLEW_LIBRARIES})
endif()
@@ -418,6 +421,12 @@ macro(setup_liblinks
if(WITH_LLVM)
target_link_libraries(${target} ${LLVM_LIBRARY})
endif()
+ if(WITH_ALEMBIC)
+ target_link_libraries(${target} ${ALEMBIC_LIBRARIES})
+ endif()
+ if(WITH_HDF5)
+ target_link_libraries(${target} ${HDF5_LIBRARIES})
+ endif()
if(WIN32 AND NOT UNIX)
target_link_libraries(${target} ${PTHREADS_LIBRARIES})
endif()
@@ -495,6 +504,7 @@ macro(SETUP_BLENDER_SORTED_LIBS)
bf_editor_object
bf_editor_armature
bf_editor_physics
+ bf_editor_hair
bf_editor_render
bf_editor_screen
bf_editor_sculpt_paint
@@ -513,14 +523,15 @@ macro(SETUP_BLENDER_SORTED_LIBS)
bf_ikplugin
bf_modifiers
bf_bmesh
+ bf_gpu
bf_blenkernel
bf_physics
bf_nodes
bf_rna
- bf_gpu
bf_blenloader
bf_imbuf
bf_blenlib
+ bf_depsgraph
bf_intern_ghost
bf_intern_string
bf_avi
@@ -539,7 +550,6 @@ macro(SETUP_BLENDER_SORTED_LIBS)
ge_phys_dummy
ge_phys_bullet
bf_intern_smoke
- extern_minilzo
extern_lzma
extern_colamd
ge_logic_ketsji
@@ -558,6 +568,8 @@ macro(SETUP_BLENDER_SORTED_LIBS)
ge_videotex
bf_dna
bf_blenfont
+ bf_pointcache_alembic
+ bf_pointcache
bf_intern_audaspace
bf_intern_mikktspace
bf_intern_dualcon
@@ -593,6 +605,10 @@ macro(SETUP_BLENDER_SORTED_LIBS)
list(APPEND BLENDER_SORTED_LIBS extern_eltopo)
endif()
+ if(NOT WITH_SYSTEM_LZO)
+ list(APPEND BLENDER_SORTED_LIBS extern_minilzo)
+ endif()
+
if(NOT WITH_SYSTEM_GLEW)
list(APPEND BLENDER_SORTED_LIBS ${BLENDER_GLEW_LIBRARIES})
endif()
@@ -955,6 +971,20 @@ macro(remove_strict_flags)
endmacro()
+macro(remove_extra_strict_flags)
+ if(CMAKE_COMPILER_IS_GNUCC)
+ remove_cc_flag("-Wunused-parameter")
+ endif()
+
+ if(CMAKE_C_COMPILER_ID MATCHES "Clang")
+ remove_cc_flag("-Wunused-parameter")
+ endif()
+
+ if(MSVC)
+ # TODO
+ endif()
+endmacro()
+
# note, we can only append flags on a single file so we need to negate the options.
# at the moment we cant shut up ffmpeg deprecations, so use this, but will
# probably add more removals here.
diff --git a/build_files/cmake/packaging.cmake b/build_files/cmake/packaging.cmake
index 95bbb2b59a8..0cb13e0fc66 100644
--- a/build_files/cmake/packaging.cmake
+++ b/build_files/cmake/packaging.cmake
@@ -27,7 +27,8 @@ if(EXISTS ${CMAKE_SOURCE_DIR}/.git/)
execute_process(COMMAND git rev-parse --short @{u}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE MY_WC_HASH
- OUTPUT_STRIP_TRAILING_WHITESPACE)
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET)
endif()
endif()
set(BUILD_REV ${MY_WC_HASH})
@@ -111,3 +112,9 @@ elseif(UNIX)
"tar.bz2")
endif()
+unset(MAJOR_VERSION)
+unset(MINOR_VERSION)
+unset(PATCH_VERSION)
+
+unset(BUILD_REV)
+
diff --git a/build_files/package_spec/pacman/PKGBUILD b/build_files/package_spec/pacman/PKGBUILD
index cc5198a88e3..961e35578b9 100644
--- a/build_files/package_spec/pacman/PKGBUILD
+++ b/build_files/package_spec/pacman/PKGBUILD
@@ -12,9 +12,9 @@ blender_version_char=$(sed -ne 's/.*BLENDER_VERSION_CHAR.*\([a-z]\)$/\1/p' $blen
# map the version a -> 1
# not to be confused with blender's internal subversions
if [ "$blender_version_char" ]; then
- blender_version_full=${blender_version}.$(expr index abcdefghijklmnopqrstuvwxyz $blender_version_char)
+ blender_version_full=${blender_version}.$(expr index abcdefghijklmnopqrstuvwxyz $blender_version_char)
else
- blender_version_full=${blender_version}
+ blender_version_full=${blender_version}
fi
blender_ver_string=$blender_version+git$blender_version_full
@@ -60,7 +60,7 @@ package() {
cd $srcdir/build
make DESTDIR="$pkgdir" install
python -m compileall \
- $pkgdir/usr/share/blender/$blender_version/scripts/startup \
- $pkgdir/usr/share/blender/$blender_version/scripts/modules \
- $pkgdir/usr/share/blender/$blender_version/scripts/addons
+ $pkgdir/usr/share/blender/$blender_version/scripts/startup \
+ $pkgdir/usr/share/blender/$blender_version/scripts/modules \
+ $pkgdir/usr/share/blender/$blender_version/scripts/addons
}
diff --git a/build_files/scons/config/linux-config.py b/build_files/scons/config/linux-config.py
index 455dd23cdb3..4a573475489 100644
--- a/build_files/scons/config/linux-config.py
+++ b/build_files/scons/config/linux-config.py
@@ -52,9 +52,9 @@ BF_OPENEXR = '/usr'
# BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR ${BF_OPENEXR}/include'
BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR'
-BF_OPENEXR_LIB = 'Half IlmImf Iex Imath '
+BF_OPENEXR_LIB = 'Half IlmImf-2_1 Iex-2_1 Imath-2_1 '
BF_OPENEXR_LIB_STATIC = '${BF_OPENEXR}/lib/libHalf.a ${BF_OPENEXR}/lib/libIlmImf.a ${BF_OPENEXR}/lib/libIex.a ${BF_OPENEXR}/lib/libImath.a ${BF_OPENEXR}/lib/libIlmThread.a'
-# BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib'
+BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib'
WITH_BF_DDS = True
@@ -226,11 +226,25 @@ BF_3DMOUSE_LIB_STATIC = '${BF_3DMOUSE_LIBPATH}/libspnav.a'
#Freestyle
WITH_BF_FREESTYLE = True
+# HDF5
+WITH_BF_HDF5 = True
+BF_HDF5 = '/usr'
+BF_HDF5_LIB = 'hdf5 hdf5_hl'
+BF_HDF5_LIBPATH='${BF_HDF5}/lib'
+
+# Alembic
+WITH_BF_ALEMBIC = True
+BF_ALEMBIC = '/opt/lib/alembic'
+BF_ALEMBIC_LIB = 'AlembicAbcGeom AlembicAbc AlembicAbcCollection AlembicAbcCoreFactory AlembicAbcCoreHDF5 AlembicAbcCoreAbstract AlembicAbcCoreOgawa AlembicAbcMaterial AlembicOgawa AlembicUtil'
+BF_ALEMBIC_INC = '${BF_ALEMBIC}/include'
+BF_ALEMBIC_LIBPATH='${BF_ALEMBIC}/lib/static'
+
##
CC = 'gcc'
CXX = 'g++'
-CCFLAGS = ['-pipe','-fPIC','-funsigned-char','-fno-strict-aliasing','-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64','-D_LARGEFILE64_SOURCE']
+CCFLAGS = ['-pipe','-fPIC','-funsigned-char','-fno-strict-aliasing', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64','-D_LARGEFILE64_SOURCE']
+CFLAGS = ['-std=gnu89']
CXXFLAGS = []
CPPFLAGS = []
diff --git a/build_files/scons/tools/Blender.py b/build_files/scons/tools/Blender.py
index 060904e7cd7..eeaa0d27379 100644
--- a/build_files/scons/tools/Blender.py
+++ b/build_files/scons/tools/Blender.py
@@ -204,10 +204,20 @@ def setup_staticlibs(lenv):
libincs += Split(lenv['BF_OIIO_LIBPATH'])
if lenv['WITH_BF_STATICOIIO']:
statlibs += Split(lenv['BF_OIIO_LIB_STATIC'])
+
+ if lenv['WITH_BF_HDF5']:
+ libincs += Split(lenv['BF_HDF5_LIBPATH'])
+
+ if lenv['WITH_BF_ALEMBIC']:
+ libincs += Split(lenv['BF_ALEMBIC_LIBPATH'])
+ if lenv['WITH_BF_STATICALEMBIC']:
+ statlibs += Split(lenv['BF_ALEMBIC_LIB_STATIC'])
+
if lenv['WITH_BF_OPENEXR']:
libincs += Split(lenv['BF_OPENEXR_LIBPATH'])
if lenv['WITH_BF_STATICOPENEXR']:
statlibs += Split(lenv['BF_OPENEXR_LIB_STATIC'])
+
if lenv['WITH_BF_ZLIB'] and lenv['WITH_BF_STATICZLIB']:
statlibs += Split(lenv['BF_ZLIB_LIB_STATIC'])
@@ -283,8 +293,16 @@ def setup_syslibs(lenv):
if not lenv['WITH_BF_STATICOCIO']:
syslibs += Split(lenv['BF_OCIO_LIB'])
+ if lenv['WITH_BF_HDF5']:
+ syslibs += Split(lenv['BF_HDF5_LIB'])
+
+ if lenv['WITH_BF_ALEMBIC']:
+ if not lenv['WITH_BF_STATICALEMBIC']:
+ syslibs += Split(lenv['BF_ALEMBIC_LIB'])
+
if lenv['WITH_BF_OPENEXR'] and not lenv['WITH_BF_STATICOPENEXR']:
syslibs += Split(lenv['BF_OPENEXR_LIB'])
+
if lenv['WITH_BF_ZLIB'] and not lenv['WITH_BF_STATICZLIB']:
syslibs += Split(lenv['BF_ZLIB_LIB'])
if lenv['WITH_BF_TIFF'] and not lenv['WITH_BF_STATICTIFF']:
@@ -372,7 +390,23 @@ def propose_priorities():
def creator(env):
sources = ['creator.c']# + Blender.buildinfo(env, "dynamic") + Blender.resources
- incs = ['#/intern/guardedalloc', '#/source/blender/blenlib', '#/source/blender/blenkernel', '#/source/blender/editors/include', '#/source/blender/blenloader', '#/source/blender/imbuf', '#/source/blender/renderconverter', '#/source/blender/render/extern/include', '#/source/blender/windowmanager', '#/source/blender/makesdna', '#/source/blender/makesrna', '#/source/gameengine/BlenderRoutines', '#/extern/glew/include', '#/source/blender/gpu', env['BF_OPENGL_INC']]
+ incs = ['#/intern/guardedalloc',
+ '#/source/blender/blenlib',
+ '#/source/blender/blenkernel',
+ '#/source/blender/depsgraph',
+ '#/source/blender/editors/include',
+ '#/source/blender/blenloader',
+ '#/source/blender/imbuf',
+ '#/source/blender/renderconverter',
+ '#/source/blender/render/extern/include',
+ '#/source/blender/windowmanager',
+ '#/source/blender/makesdna',
+ '#/source/blender/makesrna',
+ '#/source/blender/pointcache',
+ '#/source/gameengine/BlenderRoutines',
+ '#/extern/glew/include',
+ '#/source/blender/gpu',
+ env['BF_OPENGL_INC']]
defs = []
@@ -441,7 +475,7 @@ def buildinfo(lenv, build_type):
no_upstream = False
try :
- build_hash = btools.get_command_output(['git', 'rev-parse', '--short', '@{u}']).strip()
+ build_hash = btools.get_command_output(['git', 'rev-parse', '--short', '@{u}'], stderr=subprocess.STDOUT).strip()
except subprocess.CalledProcessError:
# assume branch has no upstream configured
build_hash = btools.get_command_output(['git', 'rev-parse', '--short', 'HEAD']).strip()
@@ -630,7 +664,7 @@ def WinPyBundle(target=None, source=None, env=None):
py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '.tar.gz'
py_target = env.subst(env['BF_INSTALLDIR']).lstrip("#")
- py_target = os.path.join(py_target, VERSION, 'python', 'lib')
+ py_target = os.path.join(py_target, VERSION, 'python')
def printexception(func,path,ex):
if os.path.exists(path): #do not report if path does not exist. eg on a fresh build.
print str(func) + ' failed on ' + str(path)
@@ -670,6 +704,8 @@ def WinPyBundle(target=None, source=None, env=None):
py_dir += '/release/site-packages'
# grr, we have to do one by one because the dir exists
for f in os.listdir(py_dir):
+ if f == '.svn':
+ continue
fn_src = os.path.join(py_dir, f)
fn_dst = os.path.join(py_target, f)
@@ -816,6 +852,8 @@ def AppIt(target=None, source=None, env=None):
instname = env['LCGDIR'][1:] # made libiomp5 part of blender libs
cmd = 'ditto --arch %s %s/openmp/lib/libiomp5.dylib %s/%s.app/Contents/Resources/lib/'%(osxarch, instname, installdir, binary) # copy libiomp5
commands.getoutput(cmd)
+ cmd = 'cp %s/openmp/LICENSE.txt %s/LICENSE-libiomp5.txt'%(instname, installdir) # copy libiomp5 license
+ commands.getoutput(cmd)
# extract copy system python, be sure to update other build systems
# when making changes to the files that are copied.
@@ -839,6 +877,7 @@ def UnixPyBundle(target=None, source=None, env=None):
py_src = env.subst( env['BF_PYTHON_LIBPATH'] + '/python'+env['BF_PYTHON_VERSION'] )
py_target = env.subst( dir + '/python/' + target_lib + '/python'+env['BF_PYTHON_VERSION'] )
+ py_target_bin = env.subst(dir + '/python/bin')
# This is a bit weak, but dont install if its been installed before, makes rebuilds quite slow.
if os.path.exists(py_target):
@@ -858,6 +897,11 @@ def UnixPyBundle(target=None, source=None, env=None):
except:
pass
+ # install the executable
+ run("rm -rf '%s'" % py_target_bin)
+ os.makedirs(py_target_bin)
+ run("cp '%s' '%s'" % (env.subst(env['BF_PYTHON_BINARY']), py_target_bin))
+
run("cp -R '%s' '%s'" % (py_src, os.path.dirname(py_target)))
run("rm -rf '%s/distutils'" % py_target)
run("rm -rf '%s/lib2to3'" % py_target)
diff --git a/build_files/scons/tools/btools.py b/build_files/scons/tools/btools.py
index eb5036f9996..13f931f9d28 100644
--- a/build_files/scons/tools/btools.py
+++ b/build_files/scons/tools/btools.py
@@ -182,7 +182,8 @@ def validate_arguments(args, bc):
'WITH_BF_BOOST', 'WITH_BF_STATICBOOST', 'BF_BOOST', 'BF_BOOST_INC', 'BF_BOOST_LIB', 'BF_BOOST_LIB_INTERNATIONAL', 'BF_BOOST_LIB_STATIC', 'BF_BOOST_LIBPATH',
'WITH_BF_LIBMV', 'WITH_BF_LIBMV_SCHUR_SPECIALIZATIONS',
'WITH_BF_CYCLES_OSL', 'WITH_BF_STATICOSL', 'BF_OSL', 'BF_OSL_INC', 'BF_OSL_LIB', 'BF_OSL_LIBPATH', 'BF_OSL_LIB_STATIC', 'BF_OSL_COMPILER',
- 'WITH_BF_LLVM', 'WITH_BF_STATICLLVM', 'BF_LLVM', 'BF_LLVM_LIB', 'BF_LLVM_LIBPATH', 'BF_LLVM_LIB_STATIC', 'BF_PROGRAM_LINKFLAGS'
+ 'WITH_BF_LLVM', 'WITH_BF_STATICLLVM', 'BF_LLVM', 'BF_LLVM_LIB', 'BF_LLVM_LIBPATH', 'BF_LLVM_LIB_STATIC', 'BF_PROGRAM_LINKFLAGS',
+ 'WITH_BF_ALEMBIC', 'BF_ALEMBIC', 'BF_ALEMBIC_INC', 'BF_ALEMBIC_LIB', 'BF_ALEMBIC_LIBPATH',
]
# Have options here that scons expects to be lists
@@ -198,7 +199,8 @@ def validate_arguments(args, bc):
'C_WARN', 'CC_WARN', 'CXX_WARN',
'LLIBS', 'PLATFORM_LINKFLAGS', 'MACOSX_ARCHITECTURE', 'MACOSX_SDK', 'XCODE_CUR_VER', 'C_COMPILER_ID',
'BF_CYCLES_CUDA_BINARIES_ARCH', 'BF_PROGRAM_LINKFLAGS', 'MACOSX_DEPLOYMENT_TARGET',
- 'WITH_BF_CYCLES_DEBUG', 'WITH_BF_CYCLES_LOGGING'
+ 'WITH_BF_CYCLES_DEBUG', 'WITH_BF_CYCLES_LOGGING',
+ 'WITH_BF_CPP11', 'WITH_BF_LEGACY_DEPSGRAPH',
]
@@ -580,6 +582,19 @@ def read_opts(env, cfg, args):
(BoolVariable('WITH_BF_LIBMV_SCHUR_SPECIALIZATIONS', 'Enable fixed-size schur specializations', True)),
(BoolVariable('WITH_BF_COMPOSITOR', 'Enable the tile based nodal compositor', True)),
+
+ (BoolVariable('WITH_BF_HDF5', 'Use HDF5 if true', False)),
+ ('BF_HDF5', 'HDF5 base path', ''),
+ ('BF_HDF5_LIB', 'HDF5 library', ''),
+ ('BF_HDF5_LIBPATH', 'HDF5 library path', ''),
+
+ (BoolVariable('WITH_BF_ALEMBIC', 'Use Alembic if true', False)),
+ (BoolVariable('WITH_BF_STATICALEMBIC', 'Staticly link to Alembic', False)),
+ ('BF_ALEMBIC', 'Alembic base path', ''),
+ ('BF_ALEMBIC_INC', 'Alembic include path', ''),
+ ('BF_ALEMBIC_LIB', 'Alembic library', ''),
+ ('BF_ALEMBIC_LIB_STATIC', 'Alembic static libraries', ''),
+ ('BF_ALEMBIC_LIBPATH', 'Alembic library path', ''),
) # end of opts.AddOptions()
localopts.AddVariables(
@@ -653,7 +668,11 @@ def read_opts(env, cfg, args):
('BF_LLVM_LIBPATH', 'LLVM library path', ''),
('BF_LLVM_LIB_STATIC', 'LLVM static library', ''),
- ('BF_PROGRAM_LINKFLAGS', 'Link flags applied only to final binaries (blender and blenderplayer, not makesrna/makesdna)', '')
+ ('BF_PROGRAM_LINKFLAGS', 'Link flags applied only to final binaries (blender and blenderplayer, not makesrna/makesdna)', ''),
+
+ (BoolVariable('WITH_BF_CPP11', '"Build with C++11 standard enabled, for development use only!', False)),
+
+ (BoolVariable('WITH_BF_LEGACY_DEPSGRAPH', 'Build Blender with legacy dependency graph', True)),
) # end of opts.AddOptions()
return localopts
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile
index 3865729fe56..153c7983ee5 100644
--- a/doc/doxygen/Doxyfile
+++ b/doc/doxygen/Doxyfile
@@ -1,106 +1,122 @@
-# Doxyfile 1.8.4
+# Doxyfile 1.8.9.1
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
#
-# All text after a double hash (##) is considered a comment and is placed
-# in front of the TAG it is preceding .
-# All text after a hash (#) is considered a comment and will be ignored.
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
# The format is:
-# TAG = value [value, ...]
-# For lists items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ").
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all
-# text before the first occurrence of this tag. Doxygen uses libiconv (or the
-# iconv built into libc) for the transcoding. See
-# http://www.gnu.org/software/libiconv for the list of possible encodings.
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
DOXYFILE_ENCODING = UTF-8
-# The PROJECT_NAME tag is a single word (or sequence of words) that should
-# identify the project. Note that if you do not use Doxywizard you need
-# to put quotes around the project name if it contains spaces.
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
PROJECT_NAME = Blender
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
PROJECT_NUMBER = "V2.7x"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer
-# a quick idea about the purpose of the project. Keep the description short.
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF =
-# With the PROJECT_LOGO tag one can specify an logo or icon that is
-# included in the documentation. The maximum height of the logo should not
-# exceed 55 pixels and the maximum width should not exceed 200 pixels.
-# Doxygen will copy the logo to the output directory.
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
PROJECT_LOGO = ../../release/freedesktop/icons/48x48/apps/blender.png
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
OUTPUT_DIRECTORY =
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
-# otherwise cause performance problems for the file system.
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
CREATE_SUBDIRS = YES
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
-# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
-# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
-# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian,
-# Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic,
-# Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
OUTPUT_LANGUAGE = English
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
BRIEF_MEMBER_DESC = YES
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
# brief descriptions will be completely suppressed.
+# The default value is: YES.
REPEAT_BRIEF = YES
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is
-# used as the annotated text. Otherwise, the brief description is used as-is.
-# If left blank, the following values are used ("$name" is automatically
-# replaced with the name of the entity): "The $name class" "The $name widget"
-# "The $name file" "is" "provides" "specifies" "contains"
-# "represents" "a" "an" "the"
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
@@ -115,8 +131,9 @@ ABBREVIATE_BRIEF = "The $name class" \
the
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
+# doxygen will generate a detailed section even if there is only a brief
# description.
+# The default value is: NO.
ALWAYS_DETAILED_SEC = NO
@@ -124,231 +141,269 @@ ALWAYS_DETAILED_SEC = NO
# inherited members of a class in the documentation of that class as if those
# members were ordinary class members. Constructors, destructors and assignment
# operators of the base classes will not be shown.
+# The default value is: NO.
INLINE_INHERITED_MEMB = NO
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
FULL_PATH_NAMES = NO
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip. Note that you specify absolute paths here, but also
-# relative paths, which will be relative from the directory where doxygen is
-# started.
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
STRIP_FROM_PATH =
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
-# the path mentioned in the documentation of a class, which tells
-# the reader which header file to include in order to use a class.
-# If left blank only the name of the header file containing the class
-# definition is used. Otherwise one should specify the include paths that
-# are normally passed to the compiler using the -I flag.
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
STRIP_FROM_INC_PATH =
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful if your file system
-# doesn't support long names like on DOS, Mac, or CD-ROM.
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
SHORT_NAMES = NO
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like regular Qt-style comments
-# (thus requiring an explicit @brief command for a brief description.)
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
JAVADOC_AUTOBRIEF = NO
-# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
-# interpret the first line (until the first dot) of a Qt-style
-# comment as the brief description. If set to NO, the comments
-# will behave just like regular Qt-style comments (thus requiring
-# an explicit \brief command for a brief description.)
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
QT_AUTOBRIEF = NO
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
MULTILINE_CPP_IS_BRIEF = NO
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# re-implements.
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
INHERIT_DOCS = YES
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
-# a new page for each member. If set to NO, the documentation of a member will
-# be part of the file/class/namespace that contains it.
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
SEPARATE_MEMBER_PAGES = NO
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
TAB_SIZE = 4
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
ALIASES =
# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding
-# "class=itcl::class" will allow you to use the command class in the
-# itcl::class meaning.
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
TCL_SUBST =
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
-# sources only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
-# of all members will be omitted, etc.
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
OPTIMIZE_OUTPUT_FOR_C = NO
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
-# sources only. Doxygen will then generate output that is more tailored for
-# Java. For instance, namespaces will be presented as packages, qualified
-# scopes will look different, etc.
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
OPTIMIZE_OUTPUT_JAVA = NO
# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources only. Doxygen will then generate output that is more tailored for
-# Fortran.
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
OPTIMIZE_FOR_FORTRAN = NO
# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for
-# VHDL.
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
OPTIMIZE_OUTPUT_VHDL = NO
# Doxygen selects the parser to use depending on the extension of the files it
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
-# using this tag. The format is ext=language, where ext is a file extension,
-# and language is one of the parsers supported by doxygen: IDL, Java,
-# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C,
-# C++. For instance to make doxygen treat .inc files as Fortran files (default
-# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note
-# that for custom extensions you also need to set FILE_PATTERNS otherwise the
-# files are not read by doxygen.
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
EXTENSION_MAPPING =
-# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
-# comments according to the Markdown format, which allows for more readable
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
# documentation. See http://daringfireball.net/projects/markdown/ for details.
-# The output of markdown processing is further processed by doxygen, so you
-# can mix doxygen, HTML, and XML commands with Markdown formatting.
-# Disable only in case of backward compatibilities issues.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
MARKDOWN_SUPPORT = YES
# When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can
-# be prevented in individual cases by by putting a % sign in front of the word
-# or globally by setting AUTOLINK_SUPPORT to NO.
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
AUTOLINK_SUPPORT = YES
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should
-# set this tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
-# func(std::string) {}). This also makes the inheritance and collaboration
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
BUILTIN_STL_SUPPORT = NO
# If you use Microsoft's C++/CLI language, you should set this option to YES to
# enable parsing support.
+# The default value is: NO.
CPP_CLI_SUPPORT = NO
-# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
-# Doxygen will parse them like normal C++ but will assume all classes use public
-# instead of private inheritance when no explicit protection keyword is present.
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
SIP_SUPPORT = NO
# For Microsoft's IDL there are propget and propput attributes to indicate
-# getter and setter methods for a property. Setting this option to YES (the
-# default) will make doxygen replace the get and set methods by a property in
-# the documentation. This will only work if the methods are indeed getting or
-# setting a simple type. If this is not the case, or you want to show the
-# methods anyway, you should set this option to NO.
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
IDL_PROPERTY_SUPPORT = YES
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
+# tag is set to YES then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
+# The default value is: NO.
DISTRIBUTE_GROUP_DOC = YES
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
SUBGROUPING = YES
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
-# unions are shown inside the group in which they are included (e.g. using
-# @ingroup) instead of on a separate page (for HTML and Man pages) or
-# section (for LaTeX and RTF).
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
INLINE_GROUPED_CLASSES = NO
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
-# unions with only public data fields or simple typedef fields will be shown
-# inline in the documentation of the scope in which they are defined (i.e. file,
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
# namespace, or group documentation), provided this scope is documented. If set
-# to NO (the default), structs, classes, and unions are shown on a separate
-# page (for HTML and Man pages) or section (for LaTeX and RTF).
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
INLINE_SIMPLE_STRUCTS = NO
-# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
-# is documented as struct, union, or enum with the name of the typedef. So
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically
-# be useful for C code in case the coding convention dictates that all compound
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
TYPEDEF_HIDES_STRUCT = NO
# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
-# cache is used to resolve symbols given their name and scope. Since this can
-# be an expensive process and often the same symbol appear multiple times in
-# the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too
-# small doxygen will become slower. If the cache is too large, memory is wasted.
-# The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid
-# range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536
-# symbols.
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
LOOKUP_CACHE_SIZE = 0
@@ -356,349 +411,401 @@ LOOKUP_CACHE_SIZE = 0
# Build related configuration options
#---------------------------------------------------------------------------
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
EXTRACT_ALL = YES
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
EXTRACT_PRIVATE = NO
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
# scope will be included in the documentation.
+# The default value is: NO.
EXTRACT_PACKAGE = NO
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
EXTRACT_STATIC = YES
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
-# If set to NO only classes defined in header files are included.
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
EXTRACT_LOCAL_CLASSES = YES
-# This flag is only useful for Objective-C code. When set to YES local
-# methods, which are defined in the implementation section but not in
-# the interface are included in the documentation.
-# If set to NO (the default) only methods in the interface are included.
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
EXTRACT_LOCAL_METHODS = NO
# If this flag is set to YES, the members of anonymous namespaces will be
# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base
-# name of the file that contains the anonymous namespace. By default
-# anonymous namespaces are hidden.
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
EXTRACT_ANON_NSPACES = NO
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
HIDE_UNDOC_MEMBERS = NO
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
HIDE_UNDOC_CLASSES = NO
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
-# documentation.
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
HIDE_FRIEND_COMPOUNDS = NO
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
-# function's detailed documentation block.
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
HIDE_IN_BODY_DOCS = NO
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
INTERNAL_DOCS = YES
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
CASE_SENSE_NAMES = YES
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
HIDE_SCOPE_NAMES = NO
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
SHOW_INCLUDE_FILES = YES
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
-# will list include files with double quotes in the documentation
-# rather than with sharp brackets.
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
FORCE_LOCAL_INCLUDES = NO
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
INLINE_INFO = YES
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
SORT_MEMBER_DOCS = YES
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
-# brief documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
-# declaration order.
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
SORT_BRIEF_DOCS = NO
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
-# will sort the (brief and detailed) documentation of class members so that
-# constructors and destructors are listed first. If set to NO (the default)
-# the constructors will appear in the respective orders defined by
-# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
-# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
-# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
SORT_MEMBERS_CTORS_1ST = NO
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
-# hierarchy of group names into alphabetical order. If set to NO (the default)
-# the group names will appear in their defined order.
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
SORT_GROUP_NAMES = NO
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
-# sorted by fully-qualified names, including namespaces. If set to
-# NO (the default), the class list will be sorted only by class name,
-# not including the namespace part.
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the
-# alphabetical list.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
SORT_BY_SCOPE_NAME = NO
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
-# do proper type resolution of all parameters of a function it will reject a
-# match between the prototype and the implementation of a member function even
-# if there is only one candidate or it is obvious which candidate to choose
-# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
-# will still accept a match between prototype and implementation in such cases.
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
STRICT_PROTO_MATCHING = NO
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation.
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
GENERATE_TODOLIST = YES
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-# commands in the documentation.
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
GENERATE_TESTLIST = YES
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
-# commands in the documentation.
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
GENERATE_BUGLIST = YES
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
-# \deprecated commands in the documentation.
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
GENERATE_DEPRECATEDLIST= YES
-# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if section-label ... \endif
-# and \cond section-label ... \endcond blocks.
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
ENABLED_SECTIONS =
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or macro consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and macros in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
MAX_INITIALIZER_LINES = 30
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
SHOW_USED_FILES = YES
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
-# This will remove the Files entry from the Quick Index and from the
-# Folder Tree View (if specified). The default is YES.
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
SHOW_FILES = YES
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
-# Namespaces page.
-# This will remove the Namespaces entry from the Quick Index
-# and from the Folder Tree View (if specified). The default is YES.
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
SHOW_NAMESPACES = YES
# The FILE_VERSION_FILTER tag can be used to specify a program or script that
# doxygen should invoke to get the current version for each file (typically from
# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command <command> <input-file>, where <command> is the value of
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
-# provided by doxygen. Whatever the program writes to standard output
-# is used as the file version. See the manual for examples.
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
FILE_VERSION_FILTER =
# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
# by doxygen. The layout file controls the global structure of the generated
# output files in an output format independent way. To create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option.
-# You can optionally specify a file name after the option, if omitted
-# DoxygenLayout.xml will be used as the name of the layout file.
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
LAYOUT_FILE =
-# The CITE_BIB_FILES tag can be used to specify one or more bib files
-# containing the references data. This must be a list of .bib files. The
-# .bib extension is automatically appended if omitted. Using this command
-# requires the bibtex tool to be installed. See also
-# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
-# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
-# feature you need bibtex and perl available in the search path. Do not use
-# file names with spaces, bibtex cannot handle them.
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
CITE_BIB_FILES =
#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
+# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
WARNINGS = YES
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
WARN_IF_UNDOCUMENTED = YES
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
WARN_IF_DOC_ERROR = YES
-# The WARN_NO_PARAMDOC option can be enabled to get warnings for
-# functions that are documented, but have no documentation for their parameters
-# or return value. If set to NO (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
-# documentation.
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
WARN_NO_PARAMDOC = NO
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text. Optionally the format may contain
-# $version, which will be replaced by the version of the file (if it could
-# be obtained via FILE_VERSION_FILTER)
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
WARN_FORMAT = "$file:$line: $text"
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
WARN_LOGFILE =
#---------------------------------------------------------------------------
-# configuration options related to the input files
+# Configuration options related to the input files
#---------------------------------------------------------------------------
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
-INPUT = doxygen.main \
- doxygen.source \
- doxygen.intern \
- doxygen.extern \
+INPUT = doxygen.main.h \
+ doxygen.source.h \
+ doxygen.intern.h \
+ doxygen.extern.h \
../../source \
../../intern \
../../extern/bullet2
# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
-# also the default input encoding. Doxygen uses libiconv (or the iconv built
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
-# the list of possible encodings.
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
-# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
-# *.f90 *.f *.for *.vhd *.vhdl
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
FILE_PATTERNS =
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
# Note that relative paths are relative to the directory from which doxygen is
# run.
@@ -708,14 +815,16 @@ EXCLUDE = ../../build_files, \
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
# from the input.
+# The default value is: NO.
EXCLUDE_SYMLINKS = NO
# If the value of the INPUT tag contains directories, you can use the
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories. Note that the wildcards are matched
-# against the file with absolute path, so to exclude all test directories
-# for example use the pattern */test/*
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
EXCLUDE_PATTERNS = .svn \
.git \
@@ -726,42 +835,49 @@ EXCLUDE_PATTERNS = .svn \
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
EXCLUDE_SYMBOLS =
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
EXAMPLE_PATH =
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
EXAMPLE_PATTERNS =
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
EXAMPLE_RECURSIVE = NO
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
IMAGE_PATH =
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output.
-# If FILTER_PATTERNS is specified, this tag will be ignored.
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
# Note that the filter must not add or remove lines; it is applied before the
# code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly.
@@ -769,172 +885,224 @@ IMAGE_PATH =
INPUT_FILTER =
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis.
-# Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match.
-# The filters are a list of the form:
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty or if
-# non of the patterns match the file name, INPUT_FILTER is applied.
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
FILTER_PATTERNS =
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
FILTER_SOURCE_FILES = NO
# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
-# and it is also possible to disable source filtering for a specific pattern
-# using *.ext= (so without naming a filter). This option only has effect when
-# FILTER_SOURCE_FILES is enabled.
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
FILTER_SOURCE_PATTERNS =
-# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
# is part of the input, its contents will be placed on the main page
# (index.html). This can be useful if you have a project on for instance GitHub
-# and want reuse the introduction page also for the doxygen output.
+# and want to reuse the introduction page also for the doxygen output.
-USE_MDFILE_AS_MAINPAGE =
+# USE_MDFILE_AS_MAINPAGE =
#---------------------------------------------------------------------------
-# configuration options related to source browsing
+# Configuration options related to source browsing
#---------------------------------------------------------------------------
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
-# VERBATIM_HEADERS is set to NO.
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
SOURCE_BROWSER = YES
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
INLINE_SOURCES = NO
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C, C++ and Fortran comments will always remain visible.
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
STRIP_CODE_COMMENTS = YES
-# If the REFERENCED_BY_RELATION tag is set to YES
-# then for each documented function all documented
-# functions referencing it will be listed.
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
REFERENCED_BY_RELATION = YES
-# If the REFERENCES_RELATION tag is set to YES
-# then for each documented function all documented entities
-# called/used by that function will be listed.
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
REFERENCES_RELATION = YES
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
-# link to the source code.
-# Otherwise they will link to the documentation.
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
REFERENCES_LINK_SOURCE = YES
-# If the USE_HTAGS tag is set to YES then the references to source code
-# will point to the HTML generated by the htags(1) tool instead of doxygen
-# built-in source browser. The htags tool is part of GNU's global source
-# tagging system (see http://www.gnu.org/software/global/global.html). You
-# will need version 4.8.6 or higher.
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
USE_HTAGS = NO
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
+# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
ALPHABETICAL_INDEX = YES
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
COLS_IN_ALPHA_INDEX = 5
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
IGNORE_PREFIX =
#---------------------------------------------------------------------------
-# configuration options related to the HTML output
+# Configuration options related to the HTML output
#---------------------------------------------------------------------------
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
GENERATE_HTML = YES
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = html
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FILE_EXTENSION = .html
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header. Note that when using a custom header you are responsible
-# for the proper inclusion of any scripts and style sheets that doxygen
-# needs, which is dependent on the configuration options used.
-# It is advised to generate a default header using "doxygen -w html
-# header.html footer.html stylesheet.css YourConfigFile" and then modify
-# that header. Note that the header is subject to change so you typically
-# have to redo this when upgrading to a newer version of doxygen or when
-# changing the value of configuration settings such as GENERATE_TREEVIEW!
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_HEADER =
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FOOTER = footer.html
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If left blank doxygen will
-# generate a default style sheet. Note that it is recommended to use
-# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this
-# tag will in the future become obsolete.
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_STYLESHEET =
-# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional
-# user-defined cascading style sheet that is included after the standard
-# style sheets created by doxygen. Using this option one can overrule
-# certain style aspects. This is preferred over using HTML_STYLESHEET
-# since it does not replace the standard style sheet and is therefor more
-# robust against future updates. Doxygen will copy the style sheet file to
-# the output directory.
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET =
@@ -942,632 +1110,835 @@ HTML_EXTRA_STYLESHEET =
# other source files which should be copied to the HTML output directory. Note
# that these files will be copied to the base HTML output directory. Use the
# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that
-# the files will be copied as-is; there are no commands or markers available.
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_FILES =
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
-# Doxygen will adjust the colors in the style sheet and background images
-# according to this color. Hue is specified as an angle on a colorwheel,
-# see http://en.wikipedia.org/wiki/Hue for more information.
-# For instance the value 0 represents red, 60 is yellow, 120 is green,
-# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
-# The allowed range is 0 to 359.
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_HUE = 220
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
-# the colors in the HTML output. For a value of 0 the output will use
-# grayscales only. A value of 255 will produce the most vivid colors.
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_SAT = 100
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
-# the luminance component of the colors in the HTML output. Values below
-# 100 gradually make the output lighter, whereas values above 100 make
-# the output darker. The value divided by 100 is the actual gamma applied,
-# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
-# and 100 does not change the gamma.
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_GAMMA = 79
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting
-# this to NO can help when comparing the output of multiple runs.
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = YES
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_DYNAMIC_SECTIONS = NO
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
-# entries shown in the various tree structured indices initially; the user
-# can expand and collapse entries dynamically later on. Doxygen will expand
-# the tree to such a level that at most the specified number of entries are
-# visible (unless a fully collapsed tree already exceeds this amount).
-# So setting the number of entries 1 will produce a full collapsed tree by
-# default. 0 is a special value representing an infinite number of entries
-# and will result in a full expanded tree by default.
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_INDEX_NUM_ENTRIES = 100
-# If the GENERATE_DOCSET tag is set to YES, additional index files
-# will be generated that can be used as input for Apple's Xcode 3
-# integrated development environment, introduced with OSX 10.5 (Leopard).
-# To create a documentation set, doxygen will generate a Makefile in the
-# HTML output directory. Running make will produce the docset in that
-# directory and running "make install" will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
-# it at startup.
-# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_DOCSET = NO
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
-# feed. A documentation feed provides an umbrella under which multiple
-# documentation sets from a single provider (such as a company or product suite)
-# can be grouped.
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_FEEDNAME = "Doxygen generated docs"
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
-# should uniquely identify the documentation set bundle. This should be a
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
-# will append .docset to the name.
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_BUNDLE_ID = org.doxygen.Project
-# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely
-# identify the documentation publisher. This should be a reverse domain-name
-# style string, e.g. com.mycompany.MyDocSet.documentation.
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
-# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_PUBLISHER_NAME = Publisher
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
-# of the generated HTML documentation.
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_HTMLHELP = YES
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_FILE = blender.chm
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
HHC_LOCATION = "C:/Program Files (x86)/HTML Help Workshop/hhc.exe"
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
GENERATE_CHI = NO
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file
-# content.
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_INDEX_ENCODING =
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
BINARY_TOC = NO
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
-# to the contents of the HTML help documentation and to the tree view.
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
TOC_EXPAND = NO
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
-# that can be used as input for Qt's qhelpgenerator to generate a
-# Qt Compressed Help (.qch) of the generated HTML documentation.
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_QHP = NO
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
-# be used to specify the file name of the resulting .qch file.
-# The path specified is relative to the HTML output folder.
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
QCH_FILE =
-# The QHP_NAMESPACE tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#namespace
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_NAMESPACE = org.doxygen.Project
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_VIRTUAL_FOLDER = doc
-# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
-# add. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#custom-filters
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_NAME =
-# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
-# Qt Help Project / Custom Filters</a>.
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's
-# filter section matches.
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
-# Qt Help Project / Filter Attributes</a>.
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS =
-# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
-# be used to specify the location of Qt's qhelpgenerator.
-# If non-empty doxygen will try to run qhelpgenerator on the generated
-# .qhp file.
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHG_LOCATION =
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
-# will be generated, which together with the HTML files, form an Eclipse help
-# plugin. To install this plugin and make it available under the help contents
-# menu in Eclipse, the contents of the directory containing the HTML and XML
-# files needs to be copied into the plugins directory of eclipse. The name of
-# the directory within the plugins directory should be the same as
-# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
-# the help appears.
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_ECLIPSEHELP = NO
-# A unique identifier for the eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have
-# this name.
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
ECLIPSE_DOC_ID = org.doxygen.Project
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
-# at top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it. Since the tabs have the same information as the
-# navigation tree you can set this option to NO if you already set
-# GENERATE_TREEVIEW to YES.
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
DISABLE_INDEX = NO
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information.
-# If the tag value is set to YES, a side panel will be generated
-# containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
-# Windows users are probably better off using the HTML help feature.
-# Since the tree basically has the same information as the tab index you
-# could consider to set DISABLE_INDEX to NO when enabling this option.
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = NO
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
-# (range [0,1..20]) that doxygen will group on one line in the generated HTML
-# documentation. Note that a value of 0 will completely suppress the enum
-# values from appearing in the overview section.
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
ENUM_VALUES_PER_LINE = 4
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
TREEVIEW_WIDTH = 246
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
-# links to external symbols imported via tag files in a separate window.
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
EXT_LINKS_IN_WINDOW = NO
-# Use this tag to change the font size of Latex formulas included
-# as images in the HTML documentation. The default is 10. Note that
-# when you change the font size after a successful doxygen run you need
-# to manually remove any form_*.png images from the HTML output directory
-# to force them to be regenerated.
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are
-# not supported properly for IE 6.0, but are supported on all modern browsers.
-# Note that when changing this option you need to delete any form_*.png files
-# in the HTML output before the changes have effect.
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
FORMULA_TRANSPARENT = YES
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
-# (see http://www.mathjax.org) which uses client side Javascript for the
-# rendering instead of using prerendered bitmaps. Use this if you do not
-# have LaTeX installed or if you want to formulas look prettier in the HTML
-# output. When enabled you may also need to install MathJax separately and
-# configure the path to it using the MATHJAX_RELPATH option.
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
USE_MATHJAX = NO
# When MathJax is enabled you can set the default output format to be used for
-# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and
-# SVG. The default value is HTML-CSS, which is slower, but has the best
-# compatibility.
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_FORMAT = HTML-CSS
-# When MathJax is enabled you need to specify the location relative to the
-# HTML output directory using the MATHJAX_RELPATH option. The destination
-# directory should contain the MathJax.js script. For instance, if the mathjax
-# directory is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to
-# the MathJax Content Delivery Network so you can quickly see the result without
-# installing MathJax.
-# However, it is strongly recommended to install a local
-# copy of MathJax from http://www.mathjax.org before deployment.
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = http://www.mathjax.org/mathjax
-# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
-# names that should be enabled during MathJax rendering.
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_EXTENSIONS =
-# The MATHJAX_CODEFILE tag can be used to specify a file with javascript
-# pieces of code that will be used on startup of the MathJax code.
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_CODEFILE =
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box
-# for the HTML output. The underlying search engine uses javascript
-# and DHTML and should work on any modern browser. Note that when using
-# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
-# (GENERATE_DOCSET) there is already a search function so this one should
-# typically be disabled. For large projects the javascript based search engine
-# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
SEARCHENGINE = NO
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a web server instead of a web client using Javascript.
-# There are two flavours of web server based search depending on the
-# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
-# searching and an index file used by the script. When EXTERNAL_SEARCH is
-# enabled the indexing and searching needs to be provided by external tools.
-# See the manual for details.
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
SERVER_BASED_SEARCH = NO
-# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
# script for searching. Instead the search results are written to an XML file
# which needs to be processed by an external indexer. Doxygen will invoke an
-# external search engine pointed to by the SEARCHENGINE_URL option to obtain
-# the search results. Doxygen ships with an example indexer (doxyindexer) and
-# search engine (doxysearch.cgi) which are based on the open source search
-# engine library Xapian. See the manual for configuration details.
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
EXTERNAL_SEARCH = NO
# The SEARCHENGINE_URL should point to a search engine hosted by a web server
-# which will returned the search results when EXTERNAL_SEARCH is enabled.
-# Doxygen ships with an example search engine (doxysearch) which is based on
-# the open source search engine library Xapian. See the manual for configuration
-# details.
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
SEARCHENGINE_URL =
# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
# search data is written to a file for indexing by an external tool. With the
# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
SEARCHDATA_FILE = searchdata.xml
-# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
EXTERNAL_SEARCH_ID =
# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
# projects other than the one defined by this configuration file, but that are
# all added to the same external search index. Each project needs to have a
-# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id
-# of to a relative location where the documentation can be found.
-# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ...
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
EXTRA_SEARCH_MAPPINGS =
#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
+# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
GENERATE_LATEX = NO
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
-# Note that when enabling USE_PDFLATEX this option is only used for
-# generating bitmaps for formulas in the HTML output, but not in the
-# Makefile that is written to the output directory.
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_CMD_NAME = latex
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
-# default command name.
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
MAKEINDEX_CMD_NAME = makeindex
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
COMPACT_LATEX = NO
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, letter, legal and
-# executive. If left blank a4 will be used.
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
PAPER_TYPE = a4wide
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
EXTRA_PACKAGES =
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HEADER =
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
-# the generated latex document. The footer should contain everything after
-# the last chapter. If it is left blank doxygen will generate a
-# standard footer. Notice: only use this tag if you know what you are doing!
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_FOOTER =
-# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images
-# or other source files which should be copied to the LaTeX output directory.
-# Note that the files will be copied as-is; there are no commands or markers
-# available.
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_EXTRA_FILES =
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
PDF_HYPERLINKS = NO
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
USE_PDFLATEX = NO
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_BATCHMODE = NO
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HIDE_INDICES = NO
-# If LATEX_SOURCE_CODE is set to YES then doxygen will include
-# source code with syntax highlighting in the LaTeX output.
-# Note that which sources are shown also depends on other settings
-# such as SOURCE_BROWSER.
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_SOURCE_CODE = NO
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
-# http://en.wikipedia.org/wiki/BibTeX for more info.
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_BIB_STYLE = plain
#---------------------------------------------------------------------------
-# configuration options related to the RTF output
+# Configuration options related to the RTF output
#---------------------------------------------------------------------------
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
-# other RTF readers or editors.
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
GENERATE_RTF = NO
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_OUTPUT = rtf
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
COMPACT_RTF = NO
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_HYPERLINKS = NO
-# Load style sheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assignments. You only have to provide
-# replacements, missing definitions are set to their default value.
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_STYLESHEET_FILE =
-# Set optional variables used in the generation of an rtf document.
-# Syntax is similar to doxygen's config file.
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_EXTENSIONS_FILE =
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
#---------------------------------------------------------------------------
-# configuration options related to the man page output
+# Configuration options related to the man page output
#---------------------------------------------------------------------------
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
GENERATE_MAN = NO
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
MAN_OUTPUT = man
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
MAN_EXTENSION = .3
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
MAN_LINKS = NO
#---------------------------------------------------------------------------
-# configuration options related to the XML output
+# Configuration options related to the XML output
#---------------------------------------------------------------------------
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation.
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
GENERATE_XML = NO
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `xml' will be used as the default path.
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
XML_OUTPUT = xml
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_SCHEMA =
-
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_DTD =
-
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
-# dump the program listings (including syntax highlighting
-# and cross-referencing information) to the XML output. Note that
-# enabling this will significantly increase the size of the XML output.
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
-# configuration options related to the DOCBOOK output
+# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
-# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
# that can be used to generate PDF.
+# The default value is: NO.
GENERATE_DOCBOOK = NO
-# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put.
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
-# front of it. If left blank docbook will be used as the default path.
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
DOCBOOK_OUTPUT = docbook
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
#---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
+# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
-# configuration options related to the Perl module output
+# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
-# moment.
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
GENERATE_PERLMOD = NO
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
-# to generate PDF and DVI output from the Perl module output.
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
PERLMOD_LATEX = NO
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader.
-# This is useful
-# if you want to understand what is going on.
-# On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
-# and Perl will parse it just the same.
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
PERLMOD_PRETTY = YES
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
-# Makefile don't overwrite each other's variables.
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
PERLMOD_MAKEVAR_PREFIX =
@@ -1575,113 +1946,130 @@ PERLMOD_MAKEVAR_PREFIX =
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
ENABLE_PREPROCESSING = YES
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
MACRO_EXPANSION = NO
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_DEFINED tags.
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
EXPAND_ONLY_PREDEF = NO
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# pointed to by INCLUDE_PATH will be searched when a #include is found.
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
INCLUDE_PATH = ../../source/blender/nodes \
../../source/blender/editors/include
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
INCLUDE_FILE_PATTERNS =
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed. To prevent a macro definition from being
-# undefined via #undef or recursively expanded use the := operator
-# instead of the = operator.
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
PREDEFINED = BUILD_DATE
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition that
-# overrules the definition found in the source code.
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
EXPAND_AS_DEFINED =
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all references to function-like macros
-# that are alone on a line, have an all uppercase name, and do not end with a
-# semicolon, because these will confuse the parser if not removed.
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
-# Configuration::additions related to external references
+# Configuration options related to external references
#---------------------------------------------------------------------------
-# The TAGFILES option can be used to specify one or more tagfiles. For each
-# tag file the location of the external documentation should be added. The
-# format of a tag file without this location is as follows:
-#
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
# TAGFILES = file1 file2 ...
# Adding location for the tag files is done as follows:
-#
# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths
-# or URLs. Note that each tag file must have a unique name (where the name does
-# NOT include the path). If a tag file is not located in the directory in which
-# doxygen is run, you must also specify the path to the tagfile here.
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
TAGFILES =
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
GENERATE_TAGFILE =
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
ALLEXTERNALS = NO
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
-# be listed.
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
EXTERNAL_GROUPS = YES
-# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed
-# in the related pages index. If set to NO, only the current project's
-# pages will be listed.
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
EXTERNAL_PAGES = YES
# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
PERL_PATH = /usr/bin/perl
@@ -1689,222 +2077,306 @@ PERL_PATH = /usr/bin/perl
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option also works with HAVE_DOT disabled, but it is recommended to
-# install and use dot, since it yields more powerful graphs.
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
CLASS_DIAGRAMS = NO
# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see
-# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
# the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path.
MSCGEN_PATH =
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
-HIDE_UNDOC_RELATIONS = YES
+DIA_PATH =
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
-HAVE_DOT = YES
+HIDE_UNDOC_RELATIONS = YES
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
-# allowed to run in parallel. When set to 0 (the default) doxygen will
-# base this on the number of processors available in the system. You can set it
-# explicitly to a value larger than 0 to get control over the balance
-# between CPU load and processing speed.
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_NUM_THREADS = 0
-# By default doxygen will use the Helvetica font for all dot files that
-# doxygen generates. When you want a differently looking font you can specify
-# the font name using DOT_FONTNAME. You need to make sure dot is able to find
-# the font, which can be done by putting it in a standard location or by setting
-# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
-# directory containing the font.
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTNAME = Helvetica
-# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
-# The default size is 10pt.
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTSIZE = 10
-# By default doxygen will tell dot to use the Helvetica font.
-# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
-# set the path where dot can find it.
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTPATH =
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# CLASS_DIAGRAMS tag to NO.
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
CLASS_GRAPH = YES
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
COLLABORATION_GRAPH = NO
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for groups, showing the direct groups dependencies
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
GROUP_GRAPHS = YES
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
# collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
UML_LOOK = YES
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside
-# the class node. If there are many fields or methods and many nodes the
-# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
-# threshold limits the number of items for each type to make the size more
-# manageable. Set this to 0 for no limit. Note that the threshold may be
-# exceeded by 50% before the limit is enforced.
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
UML_LIMIT_NUM_FIELDS = 10
-# If set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
TEMPLATE_RELATIONS = YES
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
INCLUDE_GRAPH = NO
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
INCLUDED_BY_GRAPH = NO
-# If the CALL_GRAPH and HAVE_DOT options are set to YES then
-# doxygen will generate a call dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable call graphs
-# for selected functions only using the \callgraph command.
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
CALL_GRAPH = NO
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
-# doxygen will generate a caller dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable caller
-# graphs for selected functions only using the \callergraph command.
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
CALLER_GRAPH = NO
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will generate a graphical hierarchy of all classes instead of a textual one.
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
GRAPHICAL_HIERARCHY = YES
-# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
DIRECTORY_GRAPH = YES
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are svg, png, jpg, or gif.
-# If left blank png will be used. If you choose svg you need to set
-# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
-# visible in IE 9+ (other browsers do not have this requirement).
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_IMAGE_FORMAT = png
# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
# enable generation of interactive SVG images that allow zooming and panning.
-# Note that this requires a modern browser other than Internet Explorer.
-# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
-# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
-# visible. Older versions of IE do not have SVG support.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
INTERACTIVE_SVG = NO
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_PATH =
# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
-# \dotfile command).
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
DOTFILE_DIRS =
# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the
-# \mscfile command).
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
MSCFILE_DIRS =
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
-# nodes that will be shown in the graph. If the number of nodes in a graph
-# becomes larger than this value, doxygen will truncate the graph, which is
-# visualized by representing a node as a red box. Note that doxygen if the
-# number of direct children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
-# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_GRAPH_MAX_NODES = 50
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes
-# that lay further from the root node will be omitted. Note that setting this
-# option to 1 or 2 may greatly reduce the computation time needed for large
-# code bases. Also note that the size of a graph can be further restricted by
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
MAX_DOT_GRAPH_DEPTH = 0
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not
-# seem to support this out of the box. Warning: Depending on the platform used,
-# enabling this option may lead to badly anti-aliased labels on the edges of
-# a graph (i.e. they become hard to read).
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_TRANSPARENT = NO
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10)
-# support this, this feature is disabled by default.
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_MULTI_TARGETS = YES
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
GENERATE_LEGEND = YES
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_CLEANUP = YES
diff --git a/doc/doxygen/doxygen.extern b/doc/doxygen/doxygen.extern.h
index 6c6872ff53f..6c6872ff53f 100644
--- a/doc/doxygen/doxygen.extern
+++ b/doc/doxygen/doxygen.extern.h
diff --git a/doc/doxygen/doxygen.intern b/doc/doxygen/doxygen.intern.h
index ae8f6ca88e4..2c8ecae0ead 100644
--- a/doc/doxygen/doxygen.intern
+++ b/doc/doxygen/doxygen.intern.h
@@ -10,26 +10,14 @@
* \ingroup intern
*/
-/** \defgroup boolop boolop
- * \ingroup intern
- */
-
/** \defgroup ctr container
* \ingroup intern
*/
-/** \defgroup decimation decimation
- * \ingroup intern
- */
-
/** \defgroup elbeem elbeem
* \ingroup intern
*/
-/** \defgroup bsp bsp
- * \ingroup intern
- */
-
/** \defgroup iksolver iksolver
* \ingroup intern
*/
diff --git a/doc/doxygen/doxygen.main b/doc/doxygen/doxygen.main.h
index 7f63764d7c6..7f63764d7c6 100644
--- a/doc/doxygen/doxygen.main
+++ b/doc/doxygen/doxygen.main.h
diff --git a/doc/doxygen/doxygen.source b/doc/doxygen/doxygen.source.h
index f27a5a87807..42516b9af6b 100644
--- a/doc/doxygen/doxygen.source
+++ b/doc/doxygen/doxygen.source.h
@@ -93,36 +93,44 @@
/* ================================ */
-/** \defgroup blender blender */
+/** \defgroup blender Blender */
-/** \defgroup blf blenfont
+/** \defgroup blf BlenFont
* \ingroup blender
*/
-/** \defgroup bke blenkernel
+/** \defgroup bke BlenKernel
* \ingroup blender
*/
-/** \defgroup bli blenlib
+/** \defgroup bli BlenLib
* \ingroup blender
*/
-/** \defgroup nodes nodes
+/** \defgroup depsgraph Dependency Graph
* \ingroup blender
*/
-/** \defgroup cmpnodes cmpnodes
+/** \defgroup bph Physics
+ * \ingroup blender
+ */
+
+/** \defgroup nodes Nodes
+ * \ingroup blender
+ */
+
+/** \defgroup cmpnodes Nodes (Compositor)
* \ingroup nodes
*/
-/** \defgroup shdnodes shdnodes
+/** \defgroup shdnodes Nodes (Shader)
* \ingroup nodes
*/
-/** \defgroup texnodes texnodes
+/** \defgroup texnodes Nodes (Texture)
* \ingroup nodes
*/
-/** \defgroup modifiers modifiers
+/** \defgroup modifiers Object Modifiers
* \ingroup blender
*/
@@ -132,29 +140,29 @@
* \ingroup blender
*/
-/** \defgroup ikplugin ikplugin
+/** \defgroup ikplugin IK Plugin
* \ingroup blender
*/
-/** \defgroup DNA sDNA
+/** \defgroup DNA Struct DNA (File Format)
* \ingroup blender data
*/
-/** \defgroup RNA RNA
+/** \defgroup RNA RNA (Data API)
* \ingroup blender data
*/
-/** \defgroup blenloader .blend read and write functions
+/** \defgroup blenloader Blend file IO
* \ingroup blender data
* \todo check if \ref blo and \ref blenloader groups can be
* merged in docs.
*/
-/** \defgroup quicktime quicktime
+/** \defgroup quicktime QuickTime
* \ingroup blender
/** \defgroup gui GUI */
-/** \defgroup wm windowmanager
+/** \defgroup wm Window Manager
* \ingroup blender gui
*/
@@ -324,7 +332,7 @@
* \ingroup externformats
*/
-/** \defgroup imbuf IMage Buffer
+/** \defgroup imbuf Image Buffer (ImBuf)
* \ingroup blender
*/
diff --git a/doc/python_api/examples/bge.constraints.py b/doc/python_api/examples/bge.constraints.py
index e76fc3dd13b..c617ac0622b 100644
--- a/doc/python_api/examples/bge.constraints.py
+++ b/doc/python_api/examples/bge.constraints.py
@@ -20,15 +20,15 @@ constraint_type = 2
physics_id_1 = object_1.getPhysicsId()
physics_id_2 = object_2.getPhysicsId()
-# Use bottom right edge of Object1 for hinge position
+# use bottom right edge of Object1 for hinge position
edge_position_x = 1.0
edge_position_y = 0.0
edge_position_z = -1.0
-# use Object1 y axis for angle to point hinge
+# rotate the pivot z axis about 90 degrees
edge_angle_x = 0.0
-edge_angle_y = 1.0
-edge_angle_z = 0.0
+edge_angle_y = 0.0
+edge_angle_z = 90.0
# create an edge constraint
constraints.createConstraint(physics_id_1, physics_id_2,
diff --git a/doc/python_api/examples/bpy.ops.2.py b/doc/python_api/examples/bpy.ops.2.py
index cf6df946873..dd88c73d5e9 100644
--- a/doc/python_api/examples/bpy.ops.2.py
+++ b/doc/python_api/examples/bpy.ops.2.py
@@ -1,16 +1,19 @@
"""
+.. _operator-execution_context:
+
Execution Context
-----------------
When calling an operator you may want to pass the execution context.
-This determines the context thats given to the operator to run in, and weather
-invoke() is called or execute().
+This determines the context that is given for the operator to run in, and whether
+invoke() is called or only execute().
-'EXEC_DEFAULT' is used by default but you may want the operator to take user
-interaction with 'INVOKE_DEFAULT'.
+'EXEC_DEFAULT' is used by default, running only the execute() method, but you may
+want the operator to take user interaction with 'INVOKE_DEFAULT' which will also
+call invoke() if existing.
-The execution context is as a non keyword, string argument in:
+The execution context is one of:
('INVOKE_DEFAULT', 'INVOKE_REGION_WIN', 'INVOKE_REGION_CHANNELS',
'INVOKE_REGION_PREVIEW', 'INVOKE_AREA', 'INVOKE_SCREEN', 'EXEC_DEFAULT',
'EXEC_REGION_WIN', 'EXEC_REGION_CHANNELS', 'EXEC_REGION_PREVIEW', 'EXEC_AREA',
diff --git a/doc/python_api/examples/bpy.props.2.py b/doc/python_api/examples/bpy.props.2.py
index 22fef5dc13a..ec9c838f5f2 100644
--- a/doc/python_api/examples/bpy.props.2.py
+++ b/doc/python_api/examples/bpy.props.2.py
@@ -3,7 +3,7 @@ PropertyGroup Example
+++++++++++++++++++++
PropertyGroups can be used for collecting custom settings into one value
-to avoid many indervidual settings mixed in together.
+to avoid many individual settings mixed in together.
"""
import bpy
diff --git a/doc/python_api/examples/bpy.props.py b/doc/python_api/examples/bpy.props.py
index f6bc55d6824..c199bd9b83a 100644
--- a/doc/python_api/examples/bpy.props.py
+++ b/doc/python_api/examples/bpy.props.py
@@ -6,7 +6,7 @@ Custom properties can be added to any subclass of an :class:`ID`,
:class:`Bone` and :class:`PoseBone`.
These properties can be animated, accessed by the user interface and python
-like blenders existing properties.
+like Blender's existing properties.
"""
import bpy
diff --git a/doc/python_api/examples/bpy.types.Menu.2.py b/doc/python_api/examples/bpy.types.Menu.2.py
index c87b10cb6e7..26409f12f45 100644
--- a/doc/python_api/examples/bpy.types.Menu.2.py
+++ b/doc/python_api/examples/bpy.types.Menu.2.py
@@ -1,12 +1,11 @@
"""
Extending Menus
+++++++++++++++
-When creating menus for addons you can't reference menus in blenders default
+When creating menus for addons you can't reference menus in Blender's default
scripts.
+Instead, the addon can add menu items to existing menus.
-Instead the addon can add menu items to existing menus.
-
-The function menu_draw acts like Menu.draw
+The function menu_draw acts like :class:`Menu.draw`.
"""
import bpy
diff --git a/doc/python_api/examples/bpy.types.Menu.py b/doc/python_api/examples/bpy.types.Menu.py
index 4ca18a67b78..e10e44f108e 100644
--- a/doc/python_api/examples/bpy.types.Menu.py
+++ b/doc/python_api/examples/bpy.types.Menu.py
@@ -1,21 +1,20 @@
"""
Basic Menu Example
++++++++++++++++++
-This script is a simple menu, menus differ from panels in that they must
+Here is an example of a simple menu. Menus differ from panels in that they must
reference from a header, panel or another menu.
-Notice the 'CATEGORY_MT_name' :class:`Menu.bl_idname`, this is a naming
+Notice the 'CATEGORY_MT_name' in :class:`Menu.bl_idname`, this is a naming
convention for menus.
.. note::
-
Menu subclasses must be registered before referencing them from blender.
.. note::
- Menu's have their :class:`Layout.operator_context` initialized as
- 'EXEC_REGION_WIN' rather then 'INVOKE_DEFAULT', so if the operator context
- needs to initialize inputs from the :class:`Operator.invoke` function
- then this needs to be explicitly set.
+ Menus have their :class:`Layout.operator_context` initialized as
+ 'EXEC_REGION_WIN' rather than 'INVOKE_DEFAULT' (see :ref:`Execution Context <operator-execution_context>`).
+ If the operator context needs to initialize inputs from the
+ :class:`Operator.invoke` function, then this needs to be explicitly set.
"""
import bpy
diff --git a/doc/python_api/rst/bge.constraints.rst b/doc/python_api/rst/bge.constraints.rst
index 018be96fd14..14ebc61dbf5 100644
--- a/doc/python_api/rst/bge.constraints.rst
+++ b/doc/python_api/rst/bge.constraints.rst
@@ -11,51 +11,54 @@ Physics Constraints (bge.constraints)
.. literalinclude:: ../examples/bge.constraints.py
:lines: 6-
-.. function:: createConstraint(physicsid, physicsid2, constrainttype, [pivotX, pivotY, pivotZ, [axisX, axisY, axisZ, [flag]]]])
+.. function:: createConstraint(physicsid_1, physicsid_2, constraint_type, pivot_X, pivot_y, pivot_z, axis_x, axis_y, axis_z, flag)
Creates a constraint.
- :arg physicsid: the physics id of the first object in constraint
- :type physicsid: int
+ Constraints types:
+ - :class:`POINTTOPOINT_CONSTRAINT`
+ - :class:`LINEHINGE_CONSTRAINT`
+ - :class:`ANGULAR_CONSTRAINT`
+ - :class:`CONETWIST_CONSTRAINT`
+ - :class:`VEHICLE_CONSTRAINT`
+ - :class:`GENERIC_6DOF_CONSTRAINT`
- :arg physicsid2: the physics id of the second object in constraint
- :type physicsid2: int
+ :arg physicsid_1: the physics id of the first object in constraint.
+ :type physicsid_1: int
- :arg constrainttype: the type of the constraint. The constraint types are:
-
- - :class:`POINTTOPOINT_CONSTRAINT`
- - :class:`LINEHINGE_CONSTRAINT`
- - :class:`ANGULAR_CONSTRAINT`
- - :class:`CONETWIST_CONSTRAINT`
- - :class:`VEHICLE_CONSTRAINT`
- - :class:`GENERIC_6DOF_CONSTRAINT`
+ :arg physicsid_2: the physics id of the second object in constraint.
+ :type physicsid_2: int
+ :arg constrainttype: the type of the constraint.
:type constrainttype: int
- :arg pivotX: pivot X position
- :type pivotX: float
+ :arg pivot_X: pivot X position (optional).
+ :type pivot_X: float
- :arg pivotY: pivot Y position
- :type pivotY: float
+ :arg pivot_Y: pivot Y position (optional).
+ :type pivot_Y: float
- :arg pivotZ: pivot Z position
- :type pivotZ: float
+ :arg pivot_Z: pivot Z position (optional).
+ :type pivot_Z: float
- :arg axisX: X axis
- :type axisX: float
+ :arg axis_X: X axis angle in degrees (optional).
+ :type axis_X: float
- :arg axisY: Y axis
- :type axisY: float
+ :arg axis_Y: Y axis angle in degrees (optional).
+ :type axis_Y: float
- :arg axisZ: Z axis
- :type axisZ: float
+ :arg axis_Z: Z axis angle in degrees (optional).
+ :type axis_Z: float
- :arg flag: 128 to disable collision between linked bodies
+ :arg flag: 128 to disable collision between linked bodies (optional).
:type flag: int
+ :return: a constraint wrapper.
+ :rtype: :class:`bge.types.KX_ConstraintWrapper`
+
.. attribute:: error
- Simbolic constant string that indicates error.
+ Symbolic constant string that indicates error.
.. function:: exportBulletFile(filename)
diff --git a/doc/python_api/rst/bge.render.rst b/doc/python_api/rst/bge.render.rst
index 77d5bd71761..1748ae14fc8 100644
--- a/doc/python_api/rst/bge.render.rst
+++ b/doc/python_api/rst/bge.render.rst
@@ -66,7 +66,7 @@ Constants
.. data:: KX_BLENDER_GLSL_MATERIAL
Materials approximating blender materials with GLSL.
-
+
.. DATA:: VSYNC_OFF
Disables vsync
@@ -87,6 +87,7 @@ Constants
Right eye being used during stereoscopic rendering.
+
*********
Functions
*********
@@ -94,47 +95,55 @@ Functions
.. function:: getWindowWidth()
Gets the width of the window (in pixels)
-
+
:rtype: integer
.. function:: getWindowHeight()
Gets the height of the window (in pixels)
-
+
:rtype: integer
.. function:: setWindowSize(width, height)
Set the width and height of the window (in pixels). This also works for fullscreen applications.
-
+
:type width: integer
:type height: integer
.. function:: setFullScreen(enable)
Set whether or not the window should be fullscreen.
-
+
:type enable: bool
.. function:: getFullScreen()
Returns whether or not the window is fullscreen.
-
+
:rtype: bool
-.. function:: makeScreenshot(filename)
+.. function:: getDisplayDimensions()
- Writes a screenshot to the given filename.
-
- If filename starts with // the image will be saved relative to the current directory.
- If the filename contains # it will be replaced with the frame number.
-
- The standalone player saves .png files. It does not support color space conversion
- or gamma correction.
-
- When run from Blender, makeScreenshot supports all Blender image file formats like PNG, TGA, Jpeg and OpenEXR.
- Gamma, Colorspace conversion and Jpeg compression are taken from the Render settings panels.
+ Get the actual display dimensions, in pixels, of the physical display (e.g., the monitor).
+ :type dimension: list [width,heigh]
+
+.. function:: makeScreenshot(filename)
+
+ Writes an image file with the current displayed frame.
+
+ The image is written to *'filename'*. The path may be absolute (eg. "/home/foo/image") or relative when started with
+ "//" (eg. "//image"). Note that absolute paths are not portable between platforms.
+ If the filename contains a "#", it will be replaced by an incremental index so that screenshots can be taken multiple
+ times without overwriting the previous ones (eg. "image-#").
+
+ Settings for the image are taken from the render settings (file format and respective settings, gamma and colospace
+ conversion, etc). The image resolution matches the framebuffer, meaning, the window size and aspect ratio.
+ When running from the standalone player, instead of the embedded player, only PNG files are supported. Additional
+ color conversions are also not supported.
+
+ :arg filename: path and name of the file to write
:type filename: string
@@ -146,65 +155,29 @@ Functions
.. function:: showMouse(visible)
Enables or disables the operating system mouse cursor.
-
+
:type visible: boolean
.. function:: setMousePosition(x, y)
Sets the mouse cursor position.
-
+
:type x: integer
:type y: integer
.. function:: setBackgroundColor(rgba)
- Sets the window background color.
-
- :type rgba: list [r, g, b, a]
-
-
-.. function:: setMistColor(rgb)
-
- Sets the mist color.
-
- :type rgb: list [r, g, b]
-
-
-.. function:: setAmbientColor(rgb)
-
- Sets the color of ambient light.
-
- :type rgb: list [r, g, b]
-
-
-.. function:: setMistStart(start)
+ Sets the window background color. (Deprecated: use KX_WorldInfo.background_color)
- Sets the mist start value. Objects further away than start will have mist applied to them.
-
- :type start: float
-
-
-.. function:: setMistEnd(end)
-
- Sets the mist end value. Objects further away from this will be colored solid with
- the color set by setMistColor().
-
- :type end: float
-
-
-.. function:: disableMist()
+ :type rgba: list [r, g, b, a]
- Disables mist.
-
- .. note:: Set any of the mist properties to enable mist.
-
.. function:: setEyeSeparation(eyesep)
Sets the eye separation for stereo mode. Usually Focal Length/30 provides a confortable value.
-
+
:arg eyesep: The distance between the left and right eye.
:type eyesep: float
@@ -212,21 +185,21 @@ Functions
.. function:: getEyeSeparation()
Gets the current eye separation for stereo mode.
-
+
:rtype: float
-
+
.. function:: setFocalLength(focallength)
Sets the focal length for stereo mode. It uses the current camera focal length as initial value.
-
- :arg focallength: The focal length.
+
+ :arg focallength: The focal length.
:type focallength: float
.. function:: getFocalLength()
Gets the current focal length for stereo mode.
-
+
:rtype: float
.. function:: getStereoEye()
@@ -241,7 +214,7 @@ Functions
.. function:: setMaterialMode(mode)
Set the material mode to use for OpenGL rendering.
-
+
:type mode: KX_TEXFACE_MATERIAL, KX_BLENDER_MULTITEX_MATERIAL, KX_BLENDER_GLSL_MATERIAL
.. note:: Changes will only affect newly created scenes.
@@ -250,14 +223,14 @@ Functions
.. function:: getMaterialMode(mode)
Get the material mode to use for OpenGL rendering.
-
+
:rtype: KX_TEXFACE_MATERIAL, KX_BLENDER_MULTITEX_MATERIAL, KX_BLENDER_GLSL_MATERIAL
.. function:: setGLSLMaterialSetting(setting, enable)
Enables or disables a GLSL material setting.
-
+
:type setting: string (lights, shaders, shadows, ramps, nodes, extra_textures)
:type enable: boolean
@@ -265,43 +238,43 @@ Functions
.. function:: getGLSLMaterialSetting(setting, enable)
Get the state of a GLSL material setting.
-
+
:type setting: string (lights, shaders, shadows, ramps, nodes, extra_textures)
:rtype: boolean
.. function:: setAnisotropicFiltering(level)
Set the anisotropic filtering level for textures.
-
+
:arg level: The new anisotropic filtering level to use
:type level: integer (must be one of 1, 2, 4, 8, 16)
-
+
.. note:: Changing this value can cause all textures to be recreated, which can be slow.
-
+
.. function:: getAnisotropicFiltering()
Get the anisotropic filtering level used for textures.
-
+
:rtype: integer (one of 1, 2, 4, 8, 16)
.. function:: setMipmapping(value)
Change how to use mipmapping.
-
+
:type value: RAS_MIPMAP_NONE, RAS_MIPMAP_NEAREST, RAS_MIPMAP_LINEAR
-
+
.. note:: Changing this value can cause all textures to be recreated, which can be slow.
.. function:: getMipmapping()
Get the current mipmapping setting.
-
+
:rtype: RAS_MIPMAP_NONE, RAS_MIPMAP_NEAREST, RAS_MIPMAP_LINEAR
-
+
.. function:: drawLine(fromVec,toVec,color)
Draw a line in the 3D scene.
-
+
:arg fromVec: the origin of the line
:type fromVec: list [x, y, z]
:arg toVec: the end of the line
@@ -313,7 +286,7 @@ Functions
.. function:: enableMotionBlur(factor)
Enable the motion blur effect.
-
+
:arg factor: the ammount of motion blur to display.
:type factor: float [0.0 - 1.0]
diff --git a/doc/python_api/rst/bge_types/bge.types.KX_ConstraintWrapper.rst b/doc/python_api/rst/bge_types/bge.types.KX_ConstraintWrapper.rst
index 53bef120f7a..59bd836d90e 100644
--- a/doc/python_api/rst/bge_types/bge.types.KX_ConstraintWrapper.rst
+++ b/doc/python_api/rst/bge_types/bge.types.KX_ConstraintWrapper.rst
@@ -23,15 +23,14 @@ base class --- :class:`PyObjectPlus`
:arg axis:
:type axis: integer
- .. note::
- For each axis:
- * Lowerlimit == Upperlimit -> axis is locked
- * Lowerlimit > Upperlimit -> axis is free
- * Lowerlimit < Upperlimit -> axis it limited in that range
+ .. note::
+ * Lowerlimit == Upperlimit -> axis is locked
+ * Lowerlimit > Upperlimit -> axis is free
+ * Lowerlimit < Upperlimit -> axis it limited in that range
- PHY_LINEHINGE_CONSTRAINT = 2 or PHY_ANGULAR_CONSTRAINT = 3:
- axis = 3 is a constraint limit, with low/high limit value
+ For PHY_LINEHINGE_CONSTRAINT = 2 or PHY_ANGULAR_CONSTRAINT = 3:
+ axis = 3 is a constraint limit, with low/high limit value
* 3: X axis angle
:arg value0 (min): Set the minimum limit of the axis
@@ -39,7 +38,8 @@ base class --- :class:`PyObjectPlus`
:arg value1 (max): Set the maximum limit of the axis
:type value1: float
- PHY_CONE_TWIST_CONSTRAINT = 3:
+ For PHY_CONE_TWIST_CONSTRAINT = 4:
+
axis = 3..5 are constraint limits, high limit values
* 3: X axis angle
* 4: Y axis angle
@@ -50,7 +50,8 @@ base class --- :class:`PyObjectPlus`
:arg value1 (max): Set the maximum limit of the axis
:type value1: float
- PHY_GENERIC_6DOF_CONSTRAINT = 12:
+ For PHY_GENERIC_6DOF_CONSTRAINT = 12:
+
axis = 0..2 are constraint limits, with low/high limit value
* 0: X axis position
* 1: Y axis position
@@ -132,10 +133,10 @@ base class --- :class:`PyObjectPlus`
Returns the contraint type (read only)
:type: integer
+ - 1 = :class:`~bge.constraints.POINTTOPOINT_CONSTRAINT`
+ - 2 = :class:`~bge.constraints.LINEHINGE_CONSTRAINT`
+ - 3 = :class:`~bge.constraints.ANGULAR_CONSTRAINT`
+ - 4 = :class:`~bge.constraints.CONETWIST_CONSTRAINT`
+ - 11 = :class:`~bge.constraints.VEHICLE_CONSTRAINT`
+ - 12 = :class:`~bge.constraints.GENERIC_6DOF_CONSTRAINT`
- * 1 = POINTTOPOINT_CONSTRAINT
- * 2 = LINEHINGE_CONSTRAINT
- * 3 = ANGULAR_CONSTRAINT (aka LINEHINGE_CONSTRAINT)
- * 4 = CONETWIST_CONSTRAINT
- * 11 = VEHICLE_CONSTRAINT
- * 12 = GENERIC_6DOF_CONSTRAINT
diff --git a/doc/python_api/rst/bge_types/bge.types.KX_FontObject.rst b/doc/python_api/rst/bge_types/bge.types.KX_FontObject.rst
index 1961f5e3e92..ca35ff49a08 100644
--- a/doc/python_api/rst/bge_types/bge.types.KX_FontObject.rst
+++ b/doc/python_api/rst/bge_types/bge.types.KX_FontObject.rst
@@ -7,6 +7,26 @@ base class --- :class:`KX_GameObject`
.. class:: KX_FontObject(KX_GameObject)
- TODO.
+ A Font object.
+ .. code-block:: python
+
+ # Display a message about the exit key using a Font object.
+ import bge
+
+ co = bge.logic.getCurrentController()
+ font = co.owner
+
+ exit_key = bge.events.EventToString(bge.logic.getExitKey())
+
+ if exit_key.endswith("KEY"):
+ exit_key = exit_key[:-3]
+
+ font.text = "Press key '%s' to quit the game." % exit_key
+
+ .. attribute:: text
+
+ The text displayed by this Font object.
+
+ :type: string
diff --git a/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst b/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst
index ebde93f872f..672df3728a9 100644
--- a/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst
+++ b/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst
@@ -78,6 +78,14 @@ base class --- :class:`SCA_IObject`
The object must have a physics controller for the mass to be applied, otherwise the mass value will be returned as 0.0.
+ .. attribute:: isSuspendDynamics
+
+ The object's dynamic state (read-only).
+
+ :type: boolean
+
+ .. seealso:: :py:meth:`suspendDynamics` and :py:meth:`restoreDynamics` allow you to change the state.
+
.. attribute:: linearDamping
The object's linear damping, also known as translational damping. Can be set simultaneously with angular damping using the :py:meth:`setDamping` method.
@@ -155,6 +163,18 @@ base class --- :class:`SCA_IObject`
:type: :class:`KX_GameObject` or None
+ .. attribute:: collisionGroup
+
+ The object's collision group.
+
+ :type: bitfield
+
+ .. attribute:: collisionMask
+
+ The object's collision mask.
+
+ :type: bitfield
+
.. attribute:: collisionCallbacks
A list of functions to be called when a collision occurs.
@@ -432,6 +452,12 @@ base class --- :class:`SCA_IObject`
If true, the object's and children's debug properties will be displayed on screen.
:type: boolean
+
+ .. attribute:: currentLodLevel
+
+ The index of the level of detail (LOD) currently used by this object (read-only).
+
+ :type: int
.. method:: endObject()
@@ -647,13 +673,19 @@ base class --- :class:`SCA_IObject`
:arg angular_damping: Angular ("rotational") damping factor.
:type angular_damping: float ∈ [0, 1]
- .. method:: suspendDynamics()
+ .. method:: suspendDynamics([ghost])
Suspends physics for this object.
+ :arg ghost: When set to `True`, collisions with the object will be ignored, similar to the "ghost" checkbox in
+ Blender. When `False` (the default), the object becomes static but still collide with other objects.
+ :type ghost: bool
+
+ .. seealso:: :py:attr:`isSuspendDynamics` allows you to inspect whether the object is in a suspended state.
+
.. method:: restoreDynamics()
- Resumes physics for this object.
+ Resumes physics for this object. Also reinstates collisions; the object will no longer be a ghost.
.. note::
diff --git a/doc/python_api/rst/bge_types/bge.types.KX_Scene.rst b/doc/python_api/rst/bge_types/bge.types.KX_Scene.rst
index fc5ba357add..5bd8e3a77de 100644
--- a/doc/python_api/rst/bge_types/bge.types.KX_Scene.rst
+++ b/doc/python_api/rst/bge_types/bge.types.KX_Scene.rst
@@ -83,6 +83,12 @@ base class --- :class:`PyObjectPlus`
This can be set directly from python to avoid using the :class:`KX_SceneActuator`.
+ .. attribute:: world
+
+ The current active world, (read-only).
+
+ :type: :class:`KX_WorldInfo`
+
.. attribute:: suspended
True if the scene is suspended, (read-only).
@@ -119,21 +125,27 @@ base class --- :class:`PyObjectPlus`
:type: list
+ .. attribute:: pre_draw_setup
+
+ A list of callables to be run before the drawing setup (i.e., before the model view and projection matrices are computed).
+
+ :type: list
+
.. attribute:: gravity
The scene gravity using the world x, y and z axis.
:type: Vector((gx, gy, gz))
- .. method:: addObject(object, other, time=0)
+ .. method:: addObject(object, reference, time=0)
Adds an object to the scene like the Add Object Actuator would.
- :arg object: The object to add
+ :arg object: The (name of the) object to add.
:type object: :class:`KX_GameObject` or string
- :arg other: The object's center to use when adding the object
- :type other: :class:`KX_GameObject` or string
- :arg time: The lifetime of the added object, in frames. A time of 0 means the object will last forever.
+ :arg reference: The (name of the) object which position, orientation, and scale to copy (optional), if the object to add is a light and there is not reference the light's layer will be the same that the active layer in the blender scene.
+ :type reference: :class:`KX_GameObject` or string
+ :arg time: The lifetime of the added object, in frames. A time of 0 means the object will last forever (optional).
:type time: integer
:return: The newly added object.
:rtype: :class:`KX_GameObject`
diff --git a/doc/python_api/rst/bge_types/bge.types.KX_WorldInfo.rst b/doc/python_api/rst/bge_types/bge.types.KX_WorldInfo.rst
new file mode 100644
index 00000000000..d0855c88d32
--- /dev/null
+++ b/doc/python_api/rst/bge_types/bge.types.KX_WorldInfo.rst
@@ -0,0 +1,79 @@
+KX_WordlInfo(PyObjectPlus)
+=============================
+
+.. module:: bge.types
+
+base class --- :class:`PyObjectPlus`
+
+.. class:: KX_WorldInfo(PyObjectPlus)
+
+ A wolrd object.
+
+ .. code-block:: python
+
+ # Set the mist color to red.
+ import bge
+
+ sce = bge.logic.getCurrentScene()
+
+ sce.world.mistColor = [1.0, 0.0, 0.0]
+
+ .. data:: KX_MIST_QUADRATIC
+
+ Type of quadratic attenuation used to fade mist.
+
+ .. data:: KX_MIST_LINEAR
+
+ Type of linear attenuation used to fade mist.
+
+ .. data:: KX_MIST_INV_QUADRATIC
+
+ Type of inverse quadratic attenuation used to fade mist.
+
+ .. attribute:: mistEnable
+
+ Return the state of the mist.
+
+ :type: bool
+
+ .. attribute:: mistStart
+
+ The mist start point.
+
+ :type: float
+
+ .. attribute:: mistDistance
+
+ The mist distance fom the start point to reach 100% mist.
+
+ :type: float
+
+ .. attribute:: mistIntensity
+
+ The mist intensity.
+
+ :type: float
+
+ .. attribute:: mistType
+
+ The type of mist - must be KX_MIST_QUADRATIC, KX_MIST_LINEAR or KX_MIST_INV_QUADRATIC
+
+ .. attribute:: mistColor
+
+ The color of the mist. Black = [0.0, 0.0, 0.0], White = [1.0, 1.0, 1.0].
+ Mist and background color sould always set to the same color.
+
+ :type: :class:`mathutils.Vector`
+
+ .. attribute:: backgroundColor
+
+ The color of the background. Black = [0.0, 0.0, 0.0], White = [1.0, 1.0, 1.0].
+ Mist and background color sould always set to the same color.
+
+ :type: :class:`mathutils.Vector`
+
+ .. attribute:: ambientColor
+
+ The color of the ambient light. Black = [0.0, 0.0, 0.0], White = [1.0, 1.0, 1.0].
+
+ :type: :class:`mathutils.Vector`
diff --git a/doc/python_api/rst/bge_types/bge.types.SCA_ISensor.rst b/doc/python_api/rst/bge_types/bge.types.SCA_ISensor.rst
index 9efd2e2d63a..af444fb9e65 100644
--- a/doc/python_api/rst/bge_types/bge.types.SCA_ISensor.rst
+++ b/doc/python_api/rst/bge_types/bge.types.SCA_ISensor.rst
@@ -23,8 +23,14 @@ base class --- :class:`SCA_ILogicBrick`
.. attribute:: frequency
- The frequency for pulse mode sensors.
-
+ The frequency for pulse mode sensors. (Deprecated: use SCA_ISensor.skippedTicks)
+
+ :type: integer
+
+ .. attribute:: skippedTicks
+
+ Number of logic ticks skipped between 2 active pulses
+
:type: integer
.. attribute:: level
diff --git a/doc/python_api/rst/info_gotcha.rst b/doc/python_api/rst/info_gotcha.rst
index 35f9c1bda9f..aad23112b42 100644
--- a/doc/python_api/rst/info_gotcha.rst
+++ b/doc/python_api/rst/info_gotcha.rst
@@ -86,9 +86,15 @@ Consider the calculations that might go into working out the object's final tran
To avoid expensive recalculations every time a property is modified, Blender defers making the actual calculations until they are needed.
However, while the script runs you may want to access the updated values.
+In this case you need to call :class:`bpy.types.Scene.update` after modifying values, for example:
+
+.. code-block:: python
+
+ bpy.context.object.location = 1, 2, 3
+ bpy.context.scene.update()
-This can be done by calling :class:`bpy.types.Scene.update` after modifying values which recalculates all data that is tagged to be updated.
+Now all dependent data (child objects, modifiers, drivers... etc) has been recalculated and is available to the script.
Can I redraw during the script?
-------------------------------
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index 344e6769524..e5ce4c76142 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -138,19 +138,9 @@ def handle_args():
parser.add_argument("-T", "--sphinx-theme",
dest="sphinx_theme",
type=str,
- default='default',
- help=
- # see SPHINX_THEMES below
- "Sphinx theme (default='default')\n"
- "Available themes\n"
- "----------------\n"
- "(Blender Foundation) blender-org\n" # naiad
- "(Sphinx) agogo, basic, epub, haiku, nature, "
- "scrolls, sphinxdoc, traditional\n",
-# choices=['naiad', 'blender-org'] + # bf
-# ['agogo', 'basic', 'epub',
-# 'haiku', 'nature', 'scrolls',
-# 'sphinxdoc', 'traditional'], # sphinx
+ default="classic",
+ help="Sphinx theme (default='classic'), "
+ "see: http://sphinx-doc.org/theming.html",
required=False)
parser.add_argument("-N", "--sphinx-named-output",
@@ -267,6 +257,7 @@ else:
"bpy.props",
"bpy.types", # supports filtering
"bpy.utils",
+ "bpy.utils.previews",
"bpy_extras",
"gpu",
"mathutils",
@@ -419,23 +410,7 @@ BLENDER_ZIP_FILENAME = "%s.zip" % REFERENCE_NAME
# -------------------------------SPHINX-----------------------------------------
-SPHINX_THEMES = {'bf': ['blender-org'], # , 'naiad',
- 'sphinx': ['agogo',
- 'basic',
- 'default',
- 'epub',
- 'haiku',
- 'nature',
- 'scrolls',
- 'sphinxdoc',
- 'traditional']}
-
-available_themes = SPHINX_THEMES['bf'] + SPHINX_THEMES['sphinx']
-if ARGS.sphinx_theme not in available_themes:
- print("Please choose a theme among: %s" % ', '.join(available_themes))
- sys.exit()
-
-if ARGS.sphinx_theme in SPHINX_THEMES['bf']:
+if ARGS.sphinx_theme == "blender-org":
SPHINX_THEME_DIR = os.path.join(ARGS.output_dir, ARGS.sphinx_theme)
SPHINX_THEME_SVN_DIR = os.path.join(SCRIPT_DIR, ARGS.sphinx_theme)
@@ -480,9 +455,11 @@ ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
MethodDescriptorType = type(dict.get)
GetSetDescriptorType = type(int.real)
StaticMethodType = type(staticmethod(lambda: None))
-from types import (MemberDescriptorType,
- MethodType,
- )
+from types import (
+ MemberDescriptorType,
+ MethodType,
+ FunctionType,
+ )
_BPY_STRUCT_FAKE = "bpy_struct"
_BPY_PROP_COLLECTION_FAKE = "bpy_prop_collection"
@@ -659,19 +636,26 @@ def pyfunc2sphinx(ident, fw, module_name, type_name, identifier, py_func, is_cla
func_type = "function"
# ther rest are class methods
- elif arg_str.startswith("(self, "):
- arg_str = "(" + arg_str[7:]
+ elif arg_str.startswith("(self, ") or arg_str == "(self)":
+ arg_str = "()" if (arg_str == "(self)") else ("(" + arg_str[7:])
func_type = "method"
elif arg_str.startswith("(cls, "):
- arg_str = "(" + arg_str[6:]
+ arg_str = "()" if (arg_str == "(cls)") else ("(" + arg_str[6:])
func_type = "classmethod"
else:
func_type = "staticmethod"
- fw(ident + ".. %s:: %s%s\n\n" % (func_type, identifier, arg_str))
- if py_func.__doc__:
- write_indented_lines(ident + " ", fw, py_func.__doc__)
+ doc = py_func.__doc__
+ if (not doc) or (not doc.startswith(".. %s:: " % func_type)):
+ fw(ident + ".. %s:: %s%s\n\n" % (func_type, identifier, arg_str))
+ ident_temp = ident + " "
+ else:
+ ident_temp = ident
+
+ if doc:
+ write_indented_lines(ident_temp, fw, doc)
fw("\n")
+ del doc, ident_temp
if is_class:
write_example_ref(ident + " ", fw, module_name + "." + type_name + "." + identifier)
@@ -887,7 +871,7 @@ def pymodule2sphinx(basepath, module_name, module, title):
module_dir_value_type.sort(key=lambda triple: str(triple[2]))
for attribute, value, value_type in module_dir_value_type:
- if value_type == types.FunctionType:
+ if value_type == FunctionType:
pyfunc2sphinx("", fw, module_name, None, attribute, value, is_class=False)
elif value_type in {types.BuiltinMethodType, types.BuiltinFunctionType}: # both the same at the moment but to be future proof
# note: can't get args from these, so dump the string as is
@@ -942,19 +926,24 @@ def pymodule2sphinx(basepath, module_name, module, title):
fw(value.__doc__)
else:
fw(".. class:: %s\n\n" % type_name)
- write_indented_lines(" ", fw, value.__doc__, False)
+ write_indented_lines(" ", fw, value.__doc__, True)
else:
fw(".. class:: %s\n\n" % type_name)
fw("\n")
write_example_ref(" ", fw, module_name + "." + type_name)
- descr_items = [(key, descr) for key, descr in sorted(value.__dict__.items()) if not key.startswith("__")]
+ descr_items = [(key, descr) for key, descr in sorted(value.__dict__.items()) if not key.startswith("_")]
for key, descr in descr_items:
if type(descr) == ClassMethodDescriptorType:
py_descr2sphinx(" ", fw, descr, module_name, type_name, key)
+ # needed for pure python classes
+ for key, descr in descr_items:
+ if type(descr) == FunctionType:
+ pyfunc2sphinx(" ", fw, module_name, type_name, key, descr, is_class=True)
+
for key, descr in descr_items:
if type(descr) == MethodDescriptorType:
py_descr2sphinx(" ", fw, descr, module_name, type_name, key)
@@ -1265,6 +1254,7 @@ def pyrna2sphinx(basepath):
fw("\n\n")
subclass_ids = [s.identifier for s in structs.values() if s.base is struct if not rna_info.rna_id_ignore(s.identifier)]
+ subclass_ids.sort()
if subclass_ids:
fw("subclasses --- \n" + ", ".join((":class:`%s`" % s) for s in subclass_ids) + "\n\n")
@@ -1572,7 +1562,7 @@ def write_sphinx_conf_py(basepath):
if ARGS.sphinx_theme != 'default':
fw("html_theme = '%s'\n" % ARGS.sphinx_theme)
- if ARGS.sphinx_theme in SPHINX_THEMES['bf']:
+ if ARGS.sphinx_theme == "blender-org":
fw("html_theme_path = ['../']\n")
# copied with the theme, exclude else we get an error [#28873]
fw("html_favicon = 'favicon.ico'\n") # in <theme>/static/
@@ -1633,6 +1623,7 @@ def write_rst_contents(basepath):
# py modules
"bpy.utils",
+ "bpy.utils.previews",
"bpy.path",
"bpy.app",
"bpy.app.handlers",
@@ -1987,7 +1978,7 @@ def main():
copy_function=shutil.copy)
# eventually, copy the theme dir
- if ARGS.sphinx_theme in SPHINX_THEMES['bf']:
+ if ARGS.sphinx_theme == "blender-org":
if os.path.exists(SPHINX_THEME_DIR):
shutil.rmtree(SPHINX_THEME_DIR, True)
shutil.copytree(SPHINX_THEME_SVN_DIR,
diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt
index 0ea8aa102e3..3dc790f2932 100644
--- a/extern/CMakeLists.txt
+++ b/extern/CMakeLists.txt
@@ -26,11 +26,14 @@
# Otherwise we get warnings here that we cant fix in external projects
remove_strict_flags()
-add_subdirectory(colamd)
add_subdirectory(rangetree)
add_subdirectory(wcwidth)
add_subdirectory(libmv)
+if(WITH_OPENNL)
+ add_subdirectory(colamd)
+endif()
+
if(WITH_BULLET)
if(NOT WITH_SYSTEM_BULLET)
add_subdirectory(bullet2)
@@ -66,7 +69,7 @@ if(WITH_IMAGE_REDCODE)
add_subdirectory(libredcode)
endif()
-if(WITH_LZO)
+if(WITH_LZO AND NOT WITH_SYSTEM_LZO)
add_subdirectory(lzo)
endif()
diff --git a/extern/bullet2/src/Bullet-C-Api.h b/extern/bullet2/src/Bullet-C-Api.h
index 2eabf3840e1..5d00f7e3ac3 100644
--- a/extern/bullet2/src/Bullet-C-Api.h
+++ b/extern/bullet2/src/Bullet-C-Api.h
@@ -171,6 +171,7 @@ extern "C" {
/* Convex Hull */
PL_DECLARE_HANDLE(plConvexHull);
plConvexHull plConvexHullCompute(float (*coords)[3], int count);
+ void plConvexHullDelete(plConvexHull hull);
int plConvexHullNumVertices(plConvexHull hull);
int plConvexHullNumFaces(plConvexHull hull);
void plConvexHullGetVertex(plConvexHull hull, int n, float coords[3], int *original_index);
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h
index b3fffdecd98..0ac5563d06e 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h
@@ -15,7 +15,7 @@ subject to the following restrictions:
/**
- * @mainpage Bullet Documentation
+ * @page Bullet Documentation
*
* @section intro_sec Introduction
* Bullet is a Collision Detection and Rigid Body Dynamics Library. The Library is Open Source and free for commercial use, under the ZLib license ( http://opensource.org/licenses/zlib-license.php ).
diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp b/extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp
index 21f0aa93220..e1f69afe101 100644
--- a/extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp
+++ b/extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp
@@ -413,6 +413,12 @@ plConvexHull plConvexHullCompute(float (*coords)[3], int count)
return reinterpret_cast<plConvexHull>(computer);
}
+void plConvexHullDelete(plConvexHull hull)
+{
+ btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull));
+ delete computer;
+}
+
int plConvexHullNumVertices(plConvexHull hull)
{
btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull));
diff --git a/extern/clew/include/clew.h b/extern/clew/include/clew.h
index 328fd52857a..1b72f813c9f 100644
--- a/extern/clew/include/clew.h
+++ b/extern/clew/include/clew.h
@@ -2751,6 +2751,30 @@ CLEW_FUN_EXPORT PFNCLGETGLCONTEXTINFOKHR __clewGetGLContextInfoKH
#endif
#define clGetGLContextInfoKHR CLEW_GET_FUN(__clewGetGLContextInfoKHR )
+/* cl_ext */
+
+/******************************************
+ * cl_nv_device_attribute_query extension *
+ ******************************************/
+/* cl_nv_device_attribute_query extension - no extension #define since it has no functions */
+#define CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV 0x4000
+#define CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV 0x4001
+#define CL_DEVICE_REGISTERS_PER_BLOCK_NV 0x4002
+#define CL_DEVICE_WARP_SIZE_NV 0x4003
+#define CL_DEVICE_GPU_OVERLAP_NV 0x4004
+#define CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV 0x4005
+#define CL_DEVICE_INTEGRATED_MEMORY_NV 0x4006
+
+/*********************************
+ * cl_amd_device_attribute_query *
+ *********************************/
+#define CL_DEVICE_PROFILING_TIMER_OFFSET_AMD 0x4036
+
+/*********************************
+ * cl_arm_printf extension
+ *********************************/
+#define CL_PRINTF_CALLBACK_ARM 0x40B0
+#define CL_PRINTF_BUFFERSIZE_ARM 0x40B1
#define CLEW_SUCCESS 0 //!< Success error code
#define CLEW_ERROR_OPEN_FAILED -1 //!< Error code for failing to open the dynamic library
diff --git a/extern/libmv/CMakeLists.txt b/extern/libmv/CMakeLists.txt
index 80e64046534..089743567f0 100644
--- a/extern/libmv/CMakeLists.txt
+++ b/extern/libmv/CMakeLists.txt
@@ -48,7 +48,7 @@ if(WITH_LIBMV OR WITH_GTESTS OR (WITH_CYCLES AND WITH_CYCLES_LOGGING))
)
list(APPEND INC_SYS
- ../Eigen3
+ ${EIGEN3_INCLUDE_DIRS}
${PNG_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIRS}
)
diff --git a/extern/libmv/bundle.sh b/extern/libmv/bundle.sh
index 66023fa693c..ac4190041bd 100755
--- a/extern/libmv/bundle.sh
+++ b/extern/libmv/bundle.sh
@@ -141,7 +141,7 @@ if(WITH_LIBMV OR WITH_GTESTS OR (WITH_CYCLES AND WITH_CYCLES_LOGGING))
)
list(APPEND INC_SYS
- ../Eigen3
+ \${EIGEN3_INCLUDE_DIRS}
\${PNG_INCLUDE_DIRS}
\${ZLIB_INCLUDE_DIRS}
)
diff --git a/extern/libmv/intern/stub.cc b/extern/libmv/intern/stub.cc
index f02509de90a..5d667baa880 100644
--- a/extern/libmv/intern/stub.cc
+++ b/extern/libmv/intern/stub.cc
@@ -179,20 +179,20 @@ void libmv_reconstructionDestroy(
/* ************ Feature detector ************ */
-libmv_Features *libmv_detectFeaturesByte(const unsigned char */*image_buffer*/,
+libmv_Features *libmv_detectFeaturesByte(const unsigned char * /*image_buffer*/,
int /*width*/,
int /*height*/,
int /*channels*/,
- libmv_DetectOptions */*options*/) {
+ libmv_DetectOptions * /*options*/) {
return NULL;
}
struct libmv_Features *libmv_detectFeaturesFloat(
- const float */*image_buffer*/,
+ const float * /*image_buffer*/,
int /*width*/,
int /*height*/,
int /*channels*/,
- libmv_DetectOptions */*options*/) {
+ libmv_DetectOptions * /*options*/) {
return NULL;
}
@@ -247,7 +247,7 @@ void libmv_cameraIntrinsicsSetThreads(
}
void libmv_cameraIntrinsicsExtractOptions(
- const libmv_CameraIntrinsics */*libmv_intrinsics*/,
+ const libmv_CameraIntrinsics * /*libmv_intrinsics*/,
libmv_CameraIntrinsicsOptions *camera_intrinsics_options) {
memset(camera_intrinsics_options, 0, sizeof(libmv_CameraIntrinsicsOptions));
camera_intrinsics_options->focal_length = 1.0;
@@ -355,7 +355,7 @@ void libmv_autoTrackSetOptions(libmv_AutoTrack* /*libmv_autotrack*/,
int libmv_autoTrackMarker(libmv_AutoTrack* /*libmv_autotrack*/,
const libmv_TrackRegionOptions* /*libmv_options*/,
- libmv_Marker */*libmv_tracker_marker*/,
+ libmv_Marker * /*libmv_tracker_marker*/,
libmv_TrackRegionResult* /*libmv_result*/)
{
return 0;
@@ -390,7 +390,7 @@ void libmv_FrameAccessorDestroy(libmv_FrameAccessor* /*frame_accessor*/)
}
int64_t libmv_frameAccessorgetTransformKey(
- const libmv_FrameTransform */*transform*/)
+ const libmv_FrameTransform * /*transform*/)
{
return 0;
}
diff --git a/extern/libmv/libmv/autotrack/autotrack.cc b/extern/libmv/libmv/autotrack/autotrack.cc
index 96a0ef64a50..4c7bdf1fde8 100644
--- a/extern/libmv/libmv/autotrack/autotrack.cc
+++ b/extern/libmv/libmv/autotrack/autotrack.cc
@@ -154,6 +154,7 @@ bool AutoTrack::TrackMarker(Marker* tracked_marker,
frame_accessor_,
&tracked_image);
if (!tracked_key) {
+ frame_accessor_->ReleaseImage(reference_key);
LG << "Couldn't get frame for tracked marker: " << tracked_marker;
return false;
}
diff --git a/extern/libmv/libmv/multiview/homography.cc b/extern/libmv/libmv/multiview/homography.cc
index a7679c33bbf..346acb3afd9 100644
--- a/extern/libmv/libmv/multiview/homography.cc
+++ b/extern/libmv/libmv/multiview/homography.cc
@@ -179,8 +179,12 @@ void GetNormalizedPoints(const Mat &original_points,
class HomographySymmetricGeometricCostFunctor {
public:
HomographySymmetricGeometricCostFunctor(const Vec2 &x,
- const Vec2 &y)
- : x_(x), y_(y) { }
+ const Vec2 &y) {
+ xx_ = x(0);
+ xy_ = x(1);
+ yx_ = y(0);
+ yy_ = y(1);
+ }
template<typename T>
bool operator()(const T *homography_parameters, T *residuals) const {
@@ -189,8 +193,8 @@ class HomographySymmetricGeometricCostFunctor {
Mat3 H(homography_parameters);
- Vec3 x(T(x_(0)), T(x_(1)), T(1.0));
- Vec3 y(T(y_(0)), T(y_(1)), T(1.0));
+ Vec3 x(T(xx_), T(xy_), T(1.0));
+ Vec3 y(T(yx_), T(yy_), T(1.0));
Vec3 H_x = H * x;
Vec3 Hinv_y = H.inverse() * y;
@@ -199,18 +203,19 @@ class HomographySymmetricGeometricCostFunctor {
Hinv_y /= Hinv_y(2);
// This is a forward error.
- residuals[0] = H_x(0) - T(y_(0));
- residuals[1] = H_x(1) - T(y_(1));
+ residuals[0] = H_x(0) - T(yx_);
+ residuals[1] = H_x(1) - T(yy_);
// This is a backward error.
- residuals[2] = Hinv_y(0) - T(x_(0));
- residuals[3] = Hinv_y(1) - T(x_(1));
+ residuals[2] = Hinv_y(0) - T(xx_);
+ residuals[3] = Hinv_y(1) - T(xy_);
return true;
}
- const Vec2 &x_;
- const Vec2 &y_;
+ // TODO(sergey): Think of better naming.
+ double xx_, xy_;
+ double yx_, yy_;
};
// Termination checking callback used for homography estimation.
diff --git a/extern/libmv/third_party/ceres/CMakeLists.txt b/extern/libmv/third_party/ceres/CMakeLists.txt
index 0ca888f6393..694982ec606 100644
--- a/extern/libmv/third_party/ceres/CMakeLists.txt
+++ b/extern/libmv/third_party/ceres/CMakeLists.txt
@@ -36,7 +36,7 @@ set(INC
)
set(INC_SYS
- ../../../Eigen3
+ ${EIGEN3_INCLUDE_DIRS}
)
set(SRC
diff --git a/extern/libmv/third_party/ceres/bundle.sh b/extern/libmv/third_party/ceres/bundle.sh
index 659f29e98ea..0becc87dd4f 100755
--- a/extern/libmv/third_party/ceres/bundle.sh
+++ b/extern/libmv/third_party/ceres/bundle.sh
@@ -129,7 +129,7 @@ set(INC
)
set(INC_SYS
- ../../../Eigen3
+ ${EIGEN3_INCLUDE_DIRS}
)
set(SRC
diff --git a/extern/rangetree/range_tree_c_api.h b/extern/rangetree/range_tree_c_api.h
index f0a2af4a29a..6abfb6bd55e 100644
--- a/extern/rangetree/range_tree_c_api.h
+++ b/extern/rangetree/range_tree_c_api.h
@@ -14,8 +14,8 @@
02110-1301, USA.
*/
-#ifndef RANGE_TREE_C_API_H
-#define RANGE_TREE_C_API_H
+#ifndef __RANGE_TREE_C_API_H__
+#define __RANGE_TREE_C_API_H__
#ifdef __cplusplus
extern "C" {
@@ -59,4 +59,4 @@ unsigned int range_tree_uint_allocation_lower_bound(const RangeTreeUInt *rt);
}
#endif
-#endif /* __DUALCON_H__ */
+#endif /* __RANGE_TREE_C_API_H__ */
diff --git a/intern/atomic/atomic_ops.h b/intern/atomic/atomic_ops.h
index 06a5c8d834e..15a77e48078 100644
--- a/intern/atomic/atomic_ops.h
+++ b/intern/atomic/atomic_ops.h
@@ -77,6 +77,27 @@
# define LG_SIZEOF_INT 2
#endif
+/************************/
+/* Function prototypes. */
+
+#if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3)
+ATOMIC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x);
+ATOMIC_INLINE uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x);
+ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _new);
+#endif
+
+ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x);
+ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x);
+ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _new);
+
+ATOMIC_INLINE size_t atomic_add_z(size_t *p, size_t x);
+ATOMIC_INLINE size_t atomic_sub_z(size_t *p, size_t x);
+ATOMIC_INLINE size_t atomic_cas_z(size_t *v, size_t old, size_t _new);
+
+ATOMIC_INLINE unsigned atomic_add_u(unsigned *p, unsigned x);
+ATOMIC_INLINE unsigned atomic_sub_u(unsigned *p, unsigned x);
+ATOMIC_INLINE unsigned atomic_cas_u(unsigned *v, unsigned old, unsigned _new);
+
/******************************************************************************/
/* 64-bit operations. */
#if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3)
diff --git a/intern/audaspace/CMakeLists.txt b/intern/audaspace/CMakeLists.txt
index 21a42553935..5b810493663 100644
--- a/intern/audaspace/CMakeLists.txt
+++ b/intern/audaspace/CMakeLists.txt
@@ -19,6 +19,8 @@
#
# ***** END LGPL LICENSE BLOCK *****
+remove_extra_strict_flags()
+
set(INC
.
FX
diff --git a/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp b/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp
index 434928c5a2b..c0c77b6f917 100644
--- a/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp
+++ b/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp
@@ -97,7 +97,7 @@ bool AUD_OpenALDevice::AUD_OpenALHandle::pause(bool keep)
return false;}
AUD_OpenALDevice::AUD_OpenALHandle::AUD_OpenALHandle(AUD_OpenALDevice* device, ALenum format, boost::shared_ptr<AUD_IReader> reader, bool keep) :
- m_isBuffered(false), m_reader(reader), m_keep(keep), m_format(format), m_current(0), m_bytepos(0),
+ m_isBuffered(false), m_reader(reader), m_keep(keep), m_format(format), m_current(0),
m_eos(false), m_loopcount(0), m_stop(NULL), m_stop_data(NULL), m_status(AUD_STATUS_PLAYING),
m_device(device)
{
@@ -208,8 +208,6 @@ bool AUD_OpenALDevice::AUD_OpenALHandle::stop()
if(!m_isBuffered)
alDeleteBuffers(CYCLE_BUFFERS, m_buffers);
- m_bytepos = 0;
-
for(AUD_HandleIterator it = m_device->m_playingSounds.begin(); it != m_device->m_playingSounds.end(); it++)
{
if(it->get() == this)
@@ -271,61 +269,55 @@ bool AUD_OpenALDevice::AUD_OpenALHandle::seek(float position)
alSourcef(m_source, AL_SEC_OFFSET, position);
else
{
- int offset = (int)(position * m_reader->getSpecs().rate);
- m_reader->seek(offset);
+ m_reader->seek((int)(position * m_reader->getSpecs().rate));
m_eos = false;
ALint info;
alGetSourcei(m_source, AL_SOURCE_STATE, &info);
- if(info != AL_PLAYING)
- {
- if(info == AL_PAUSED)
- alSourceStop(m_source);
+ // we need to stop playing sounds as well to clear the buffers
+ // this might cause clicks, but fixes a bug regarding position determination
+ if(info == AL_PAUSED || info == AL_PLAYING)
+ alSourceStop(m_source);
- alSourcei(m_source, AL_BUFFER, 0);
- m_current = 0;
+ alSourcei(m_source, AL_BUFFER, 0);
+ m_current = 0;
- ALenum err;
- if((err = alGetError()) == AL_NO_ERROR)
+ ALenum err;
+ if((err = alGetError()) == AL_NO_ERROR)
+ {
+ int length;
+ AUD_DeviceSpecs specs = m_device->m_specs;
+ specs.specs = m_reader->getSpecs();
+ m_device->m_buffer.assureSize(m_device->m_buffersize * AUD_DEVICE_SAMPLE_SIZE(specs));
+
+ for(int i = 0; i < CYCLE_BUFFERS; i++)
{
- int length;
- AUD_DeviceSpecs specs = m_device->m_specs;
- specs.specs = m_reader->getSpecs();
- m_device->m_buffer.assureSize(m_device->m_buffersize * AUD_DEVICE_SAMPLE_SIZE(specs));
+ length = m_device->m_buffersize;
+ m_reader->read(length, m_eos, m_device->m_buffer.getBuffer());
- for(int i = 0; i < CYCLE_BUFFERS; i++)
+ if(length == 0)
{
- length = m_device->m_buffersize;
- m_reader->read(length, m_eos, m_device->m_buffer.getBuffer());
-
- if(length == 0)
- {
- // AUD_XXX: TODO: don't fill all buffers and enqueue them later
- length = 1;
- memset(m_device->m_buffer.getBuffer(), 0, length * AUD_DEVICE_SAMPLE_SIZE(specs));
- }
-
- alBufferData(m_buffers[i], m_format, m_device->m_buffer.getBuffer(),
- length * AUD_DEVICE_SAMPLE_SIZE(specs), specs.rate);
-
- if(alGetError() != AL_NO_ERROR)
- break;
+ // AUD_XXX: TODO: don't fill all buffers and enqueue them later
+ length = 1;
+ memset(m_device->m_buffer.getBuffer(), 0, length * AUD_DEVICE_SAMPLE_SIZE(specs));
}
- if(m_loopcount != 0)
- m_eos = false;
+ alBufferData(m_buffers[i], m_format, m_device->m_buffer.getBuffer(),
+ length * AUD_DEVICE_SAMPLE_SIZE(specs), specs.rate);
- alSourceQueueBuffers(m_source, CYCLE_BUFFERS, m_buffers);
- m_bytepos = offset;
+ if(alGetError() != AL_NO_ERROR)
+ break;
}
- alSourceRewind(m_source);
- }
- else {
- m_bytepos = offset;
+ if(m_loopcount != 0)
+ m_eos = false;
+
+ alSourceQueueBuffers(m_source, CYCLE_BUFFERS, m_buffers);
}
+
+ alSourceRewind(m_source);
}
if(m_status == AUD_STATUS_STOPPED)
@@ -350,8 +342,14 @@ float AUD_OpenALDevice::AUD_OpenALHandle::getPosition()
if(!m_isBuffered)
{
+ int queued;
+
+ // this usually always returns CYCLE_BUFFERS
+ alGetSourcei(m_source, AL_BUFFERS_QUEUED, &queued);
+
AUD_Specs specs = m_reader->getSpecs();
- position += (m_bytepos) / specs.rate;
+ position += (m_reader->getPosition() - m_device->m_buffersize *
+ queued) / (float)specs.rate;
}
return position;
@@ -956,7 +954,6 @@ void AUD_OpenALDevice::updateStreams()
// unqueue buffer (warning: this might fail for slow early returning sources (none exist so far) if the buffer was not queued due to recent changes - has to be tested)
alSourceUnqueueBuffers(sound->m_source, 1, &sound->m_buffers[sound->m_current]);
- sound->m_bytepos += length;
ALenum err;
if((err = alGetError()) != AL_NO_ERROR)
{
diff --git a/intern/audaspace/OpenAL/AUD_OpenALDevice.h b/intern/audaspace/OpenAL/AUD_OpenALDevice.h
index 142d482b7b0..f0e47824967 100644
--- a/intern/audaspace/OpenAL/AUD_OpenALDevice.h
+++ b/intern/audaspace/OpenAL/AUD_OpenALDevice.h
@@ -75,8 +75,6 @@ private:
/// The first buffer to be read next.
int m_current;
- /// Amount of buffers already passed to OpenAL for processing. Used for proper timing
- unsigned int m_bytepos;
/// Whether the stream doesn't return any more data.
bool m_eos;
diff --git a/intern/audaspace/intern/AUD_AnimateableProperty.cpp b/intern/audaspace/intern/AUD_AnimateableProperty.cpp
index 9f399a0b99f..e0bc18ea520 100644
--- a/intern/audaspace/intern/AUD_AnimateableProperty.cpp
+++ b/intern/audaspace/intern/AUD_AnimateableProperty.cpp
@@ -119,13 +119,11 @@ void AUD_AnimateableProperty::write(const float* data, int position, int count)
{
m_unknown.push_back(Unknown(pos, position - 1));
+ // if the buffer was not animated before, we copy the previous static value
if(pos == 0)
- {
- for(int i = 0; i < position; i++)
- memcpy(buf + i * m_count, data, m_count * sizeof(float));
- }
- else
- updateUnknownCache(pos, position - 1);
+ pos = 1;
+
+ updateUnknownCache(pos, position - 1);
}
// otherwise it's not at the end, let's check if some unknown part got filled
else
diff --git a/intern/audaspace/intern/AUD_C-API.cpp b/intern/audaspace/intern/AUD_C-API.cpp
index 45d72ccb50e..78b9279a54a 100644
--- a/intern/audaspace/intern/AUD_C-API.cpp
+++ b/intern/audaspace/intern/AUD_C-API.cpp
@@ -222,7 +222,7 @@ static PyMethodDef meth_getcdevice[] = {
};
extern "C" {
-extern void *sound_get_factory(void *sound);
+extern void *BKE_sound_get_factory(void *sound);
}
static PyObject *AUD_getSoundFromPointer(PyObject *self, PyObject *args)
@@ -231,7 +231,7 @@ static PyObject *AUD_getSoundFromPointer(PyObject *self, PyObject *args)
if (PyArg_Parse(args, "l:_sound_from_pointer", &lptr)) {
if (lptr) {
- boost::shared_ptr<AUD_IFactory>* factory = (boost::shared_ptr<AUD_IFactory>*) sound_get_factory((void *) lptr);
+ boost::shared_ptr<AUD_IFactory>* factory = (boost::shared_ptr<AUD_IFactory>*) BKE_sound_get_factory((void *) lptr);
if (factory) {
Factory *obj = (Factory *)Factory_empty();
diff --git a/intern/audaspace/intern/AUD_Sequencer.cpp b/intern/audaspace/intern/AUD_Sequencer.cpp
index ddcf97e2ea1..a5b70232068 100644
--- a/intern/audaspace/intern/AUD_Sequencer.cpp
+++ b/intern/audaspace/intern/AUD_Sequencer.cpp
@@ -44,7 +44,8 @@ AUD_Sequencer::AUD_Sequencer(AUD_Specs specs, float fps, bool muted) :
m_distance_model(AUD_DISTANCE_MODEL_INVERSE_CLAMPED),
m_volume(1, 1.0f),
m_location(3),
- m_orientation(4)
+ m_orientation(4),
+ m_recursive(false)
{
AUD_Quaternion q;
m_orientation.write(q.get());
diff --git a/intern/audaspace/intern/AUD_Sequencer.h b/intern/audaspace/intern/AUD_Sequencer.h
index 1066eeae8e3..ef68efbbafc 100644
--- a/intern/audaspace/intern/AUD_Sequencer.h
+++ b/intern/audaspace/intern/AUD_Sequencer.h
@@ -201,6 +201,8 @@ public:
* \param entry The entry to remove.
*/
void remove(boost::shared_ptr<AUD_SequencerEntry> entry);
+
+ bool m_recursive;
};
#endif //__AUD_SEQUENCER_H__
diff --git a/intern/audaspace/intern/AUD_SequencerReader.cpp b/intern/audaspace/intern/AUD_SequencerReader.cpp
index aef93cd3896..b893b132fa3 100644
--- a/intern/audaspace/intern/AUD_SequencerReader.cpp
+++ b/intern/audaspace/intern/AUD_SequencerReader.cpp
@@ -78,6 +78,9 @@ AUD_Specs AUD_SequencerReader::getSpecs() const
void AUD_SequencerReader::read(int& length, bool& eos, sample_t* buffer)
{
+ if (m_sequence->m_recursive)
+ return;
+
AUD_MutexLock lock(*m_sequence);
if(m_sequence->m_status != m_status)
@@ -192,7 +195,9 @@ void AUD_SequencerReader::read(int& length, bool& eos, sample_t* buffer)
v2 -= v;
m_device.setListenerVelocity(v2 * m_sequence->m_fps);
+ m_sequence->m_recursive = true;
m_device.read(reinterpret_cast<data_t*>(buffer + specs.channels * pos), len);
+ m_sequence->m_recursive = false;
pos += len;
time += float(len) / float(specs.rate);
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt
index 2ba6af48d0d..ed6961f49e0 100644
--- a/intern/cycles/CMakeLists.txt
+++ b/intern/cycles/CMakeLists.txt
@@ -64,7 +64,7 @@ elseif(CMAKE_COMPILER_IS_GNUCC)
set(CYCLES_AVX_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mavx -mfpmath=sse")
endif()
if(CXX_HAS_AVX2)
- set(CYCLES_AVX2_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mavx -mavx2 -mfma -mlzcnt -mbmi -mbmi2 -mfpmath=sse")
+ set(CYCLES_AVX2_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mavx -mavx2 -mfma -mlzcnt -mbmi -mbmi2 -mf16c -mfpmath=sse")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
@@ -80,7 +80,7 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CYCLES_AVX_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mavx")
endif()
if(CXX_HAS_AVX2)
- set(CYCLES_AVX2_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mavx -mavx2 -mfma -mlzcnt -mbmi -mbmi2")
+ set(CYCLES_AVX2_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mavx -mavx2 -mfma -mlzcnt -mbmi -mbmi2 -mf16c")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math")
endif()
@@ -152,6 +152,27 @@ add_definitions(
-DWITH_MULTI
)
+TEST_UNORDERED_MAP_SUPPORT()
+if(HAVE_STD_UNORDERED_MAP_HEADER)
+ if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
+ add_definitions(-DCYCLES_STD_UNORDERED_MAP)
+ else()
+ if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ add_definitions(-DCYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ else()
+ add_definitions(-DCYCLES_NO_UNORDERED_MAP)
+ message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
+ endif()
+ endif()
+else()
+ if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ add_definitions(-DCYCLES_TR1_UNORDERED_MAP)
+ else()
+ add_definitions(-DCYCLES_NO_UNORDERED_MAP)
+ message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
+ endif()
+endif()
+
# Logging capabilities using GLog library.
if(WITH_CYCLES_LOGGING)
add_definitions(-DWITH_CYCLES_LOGGING)
diff --git a/intern/cycles/SConscript b/intern/cycles/SConscript
index 9cbdb93ce85..99df8c299fc 100644
--- a/intern/cycles/SConscript
+++ b/intern/cycles/SConscript
@@ -34,12 +34,8 @@ cycles.Depends('../../source/blender/makesrna/intern/RNA_blender_cpp.h', 'makesr
sources = cycles.Glob('bvh/*.cpp') + cycles.Glob('device/*.cpp') + cycles.Glob('kernel/*.cpp') + cycles.Glob('render/*.cpp') + cycles.Glob('subd/*.cpp') + cycles.Glob('util/*.cpp') + cycles.Glob('blender/*.cpp')
+sources.append(path.join('kernel', 'kernels', 'cpu', 'kernel.cpp'))
sources.remove(path.join('util', 'util_view.cpp'))
-sources.remove(path.join('kernel', 'kernel_sse2.cpp'))
-sources.remove(path.join('kernel', 'kernel_sse3.cpp'))
-sources.remove(path.join('kernel', 'kernel_sse41.cpp'))
-sources.remove(path.join('kernel', 'kernel_avx.cpp'))
-sources.remove(path.join('kernel', 'kernel_avx2.cpp'))
incs = []
defs = []
@@ -47,6 +43,18 @@ cxxflags = Split(env['CXXFLAGS'])
defs += env['BF_GL_DEFINITIONS']
+if env['WITH_UNORDERED_MAP_SUPPORT']:
+ if env['UNORDERED_MAP_HEADER'] == 'unordered_map':
+ if env['UNORDERED_MAP_NAMESPACE'] == 'std':
+ defs.append('CYCLES_STD_UNORDERED_MAP')
+ elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
+ defs.append('CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE')
+ elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
+ defs.append('CYCLES_TR1_UNORDERED_MAP')
+else:
+ print("-- Replacing unordered_map/set with map/set (warning: slower!)")
+ defs.append('CYCLES_NO_UNORDERED_MAP')
+
defs.append('CCL_NAMESPACE_BEGIN=namespace ccl {')
defs.append('CCL_NAMESPACE_END=}')
@@ -128,13 +136,13 @@ else:
if (env['C_COMPILER_ID'] == 'gcc' and env['CCVERSION'] >= '4.6') or (env['C_COMPILER_ID'] == 'clang' and env['CCVERSION'] >= '3.1'):
kernel_flags['avx'] = kernel_flags['sse41'] + ' -mavx'
- kernel_flags['avx2'] = kernel_flags['avx'] + ' -mavx2 -mfma -mlzcnt -mbmi -mbmi2'
+ kernel_flags['avx2'] = kernel_flags['avx'] + ' -mavx2 -mfma -mlzcnt -mbmi -mbmi2 -mf16c'
for kernel_type in kernel_flags.keys():
defs.append('WITH_KERNEL_' + kernel_type.upper())
for kernel_type in kernel_flags.keys():
- kernel_source = path.join('kernel', 'kernel_' + kernel_type + '.cpp')
+ kernel_source = path.join('kernel', 'kernels', 'cpu', 'kernel_' + kernel_type + '.cpp')
kernel_cxxflags = Split(env['CXXFLAGS'])
kernel_cxxflags.append(kernel_flags[kernel_type].split())
kernel_defs = defs[:]
diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt
index b000266cac2..b9a2abf1c9a 100644
--- a/intern/cycles/app/CMakeLists.txt
+++ b/intern/cycles/app/CMakeLists.txt
@@ -96,6 +96,12 @@ macro(cycles_target_link_libraries target)
${CMAKE_DL_LIBS}
${PLATFORM_LINKLIBS}
)
+ if(WITH_ALEMBIC)
+ target_link_libraries(
+ ${target}
+ ${ALEMBIC_LIBRARIES}
+ )
+ endif()
endmacro()
# Application build targets
@@ -106,6 +112,23 @@ if(WITH_CYCLES_STANDALONE)
cycles_xml.cpp
cycles_xml.h
)
+
+ if(WITH_ALEMBIC)
+ list(APPEND SRC
+ cycles_alembic.cpp
+ cycles_alembic.h
+ )
+ add_definitions(-DWITH_ALEMBIC)
+ include_directories(
+ SYSTEM
+ ${ALEMBIC_INCLUDE_DIRS}
+ )
+ endif()
+
+ if(WITH_HDF5)
+ add_definitions(-DWITH_HDF5)
+ endif()
+
add_executable(cycles ${SRC})
cycles_target_link_libraries(cycles)
diff --git a/intern/cycles/app/cycles_alembic.cpp b/intern/cycles/app/cycles_alembic.cpp
new file mode 100644
index 00000000000..3a1e6a6bcaa
--- /dev/null
+++ b/intern/cycles/app/cycles_alembic.cpp
@@ -0,0 +1,426 @@
+/*
+ * Copyright 2015 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 <stdio.h>
+
+#include <sstream>
+#include <algorithm>
+#include <iterator>
+
+#include <Alembic/AbcCoreOgawa/ReadWrite.h>
+#ifdef WITH_HDF5
+#include <Alembic/AbcCoreHDF5/ReadWrite.h>
+#endif
+#include <Alembic/Abc/IArchive.h>
+#include <Alembic/Abc/IObject.h>
+#include <Alembic/Abc/ISampleSelector.h>
+#include <Alembic/Abc/ICompoundProperty.h>
+#include <Alembic/Abc/IScalarProperty.h>
+#include <Alembic/Abc/IArrayProperty.h>
+#include <Alembic/Abc/ArchiveInfo.h>
+#include <Alembic/AbcGeom/IPolyMesh.h>
+
+#include "camera.h"
+#include "film.h"
+#include "graph.h"
+#include "integrator.h"
+#include "light.h"
+#include "mesh.h"
+#include "nodes.h"
+#include "object.h"
+#include "shader.h"
+#include "scene.h"
+
+#include "subd_mesh.h"
+#include "subd_patch.h"
+#include "subd_split.h"
+
+#include "util_debug.h"
+#include "util_foreach.h"
+#include "util_path.h"
+#include "util_transform.h"
+#include "util_xml.h"
+
+#include "cycles_alembic.h"
+
+CCL_NAMESPACE_BEGIN
+
+using namespace Alembic;
+using namespace Abc;
+using namespace AbcGeom;
+
+#define ABC_SAFE_CALL_BEGIN \
+ try {
+
+#define ABC_SAFE_CALL_END \
+ } \
+ catch (Alembic::Util::Exception e) { \
+ printf("%s", e.what()); \
+ }
+
+
+/* File */
+
+static const std::string g_sep(";");
+
+static void visitProperties(std::stringstream &ss, ICompoundProperty, std::string &);
+
+template <class PROP>
+static void visitSimpleArrayProperty(std::stringstream &ss, PROP iProp, const std::string &iIndent)
+{
+ std::string ptype = "ArrayProperty ";
+ size_t asize = 0;
+
+ AbcA::ArraySamplePtr samp;
+ index_t maxSamples = iProp.getNumSamples();
+ for (index_t i = 0 ; i < maxSamples; ++i) {
+ iProp.get(samp, ISampleSelector( i ));
+ asize = samp->size();
+ };
+
+ std::string mdstring = "interpretation=";
+ mdstring += iProp.getMetaData().get("interpretation");
+
+ std::stringstream dtype;
+ dtype << "datatype=";
+ dtype << iProp.getDataType();
+
+ std::stringstream asizestr;
+ asizestr << ";arraysize=";
+ asizestr << asize;
+
+ mdstring += g_sep;
+
+ mdstring += dtype.str();
+
+ mdstring += asizestr.str();
+
+ ss << iIndent << " " << ptype << "name=" << iProp.getName()
+ << g_sep << mdstring << g_sep << "numsamps="
+ << iProp.getNumSamples() << std::endl;
+}
+
+template <class PROP>
+static void visitSimpleScalarProperty(std::stringstream &ss, PROP iProp, const std::string &iIndent)
+{
+ std::string ptype = "ScalarProperty ";
+ size_t asize = 0;
+
+ const AbcA::DataType &dt = iProp.getDataType();
+ const Alembic::Util ::uint8_t extent = dt.getExtent();
+ Alembic::Util::Dimensions dims(extent);
+ AbcA::ArraySamplePtr samp = AbcA::AllocateArraySample( dt, dims );
+ index_t maxSamples = iProp.getNumSamples();
+ for (index_t i = 0 ; i < maxSamples; ++i) {
+ iProp.get(const_cast<void*>(samp->getData()), ISampleSelector( i ));
+ asize = samp->size();
+ };
+
+ std::string mdstring = "interpretation=";
+ mdstring += iProp.getMetaData().get("interpretation");
+
+ std::stringstream dtype;
+ dtype << "datatype=";
+ dtype << dt;
+
+ std::stringstream asizestr;
+ asizestr << ";arraysize=";
+ asizestr << asize;
+
+ mdstring += g_sep;
+
+ mdstring += dtype.str();
+
+ mdstring += asizestr.str();
+
+ ss << iIndent << " " << ptype << "name=" << iProp.getName()
+ << g_sep << mdstring << g_sep << "numsamps="
+ << iProp.getNumSamples() << std::endl;
+}
+
+static void visitCompoundProperty(std::stringstream &ss, ICompoundProperty iProp, std::string &ioIndent)
+{
+ std::string oldIndent = ioIndent;
+ ioIndent += " ";
+
+ std::string interp = "schema=";
+ interp += iProp.getMetaData().get("schema");
+
+ ss << ioIndent << "CompoundProperty " << "name=" << iProp.getName()
+ << g_sep << interp << std::endl;
+
+ visitProperties(ss, iProp, ioIndent);
+
+ ioIndent = oldIndent;
+}
+
+static void visitProperties(std::stringstream &ss, ICompoundProperty iParent, std::string &ioIndent )
+{
+ std::string oldIndent = ioIndent;
+ for (size_t i = 0 ; i < iParent.getNumProperties() ; i++) {
+ PropertyHeader header = iParent.getPropertyHeader(i);
+
+ if (header.isCompound()) {
+ visitCompoundProperty(ss, ICompoundProperty(iParent, header.getName()), ioIndent);
+ }
+ else if (header.isScalar()) {
+ visitSimpleScalarProperty(ss, IScalarProperty(iParent, header.getName()), ioIndent);
+ }
+ else {
+ assert(header.isArray());
+ visitSimpleArrayProperty(ss, IArrayProperty(iParent, header.getName()), ioIndent);
+ }
+ }
+
+ ioIndent = oldIndent;
+}
+
+static void visitObject(std::stringstream &ss, IObject iObj, std::string iIndent, AbcArchiveInfoLevel info_level)
+{
+ // Object has a name, a full name, some meta data,
+ // and then it has a compound property full of properties.
+ std::string path = iObj.getFullName();
+
+ if (iObj.isInstanceRoot()) {
+ if (path != "/") {
+ ss << "Object " << "name=" << path
+ << " [Instance " << iObj.instanceSourcePath() << "]"
+ << std::endl;
+ }
+ }
+ else if (iObj.isInstanceDescendant()) {
+ /* skip non-root instances to avoid repetition */
+ return;
+ }
+ else {
+ if (path != "/") {
+ ss << "Object " << "name=" << path << std::endl;
+ }
+
+ if (info_level >= ABC_INFO_PROPERTIES) {
+ // Get the properties.
+ ICompoundProperty props = iObj.getProperties();
+ visitProperties(ss, props, iIndent);
+ }
+
+ // now the child objects
+ for (size_t i = 0 ; i < iObj.getNumChildren() ; i++) {
+ visitObject(ss, IObject(iObj, iObj.getChildHeader(i).getName()), iIndent, info_level);
+ }
+ }
+}
+
+static std::string abc_archive_info(IArchive &archive, AbcArchiveInfoLevel info_level)
+{
+ std::stringstream ss;
+
+ ss << "Alembic Archive Info for "
+ << Alembic::AbcCoreAbstract::GetLibraryVersion()
+ << std::endl;;
+
+ std::string appName;
+ std::string libraryVersionString;
+ Alembic::Util::uint32_t libraryVersion;
+ std::string whenWritten;
+ std::string userDescription;
+ GetArchiveInfo(archive,
+ appName,
+ libraryVersionString,
+ libraryVersion,
+ whenWritten,
+ userDescription);
+
+ if (appName != "") {
+ ss << " file written by: " << appName << std::endl;
+ ss << " using Alembic : " << libraryVersionString << std::endl;
+ ss << " written on : " << whenWritten << std::endl;
+ ss << " user description : " << userDescription << std::endl;
+ ss << std::endl;
+ }
+ else {
+// ss << argv[1] << std::endl;
+ ss << " (file doesn't have any ArchiveInfo)"
+ << std::endl;
+ ss << std::endl;
+ }
+
+ if (info_level >= ABC_INFO_OBJECTS)
+ visitObject(ss, archive.getTop(), "", info_level);
+
+ return ss.str();
+}
+
+/* ========================================================================= */
+
+struct AbcReadState {
+ Scene *scene; /* scene pointer */
+ float time;
+ Transform tfm; /* current transform state */
+ bool smooth; /* smooth normal state */
+ int shader; /* current shader */
+ string base; /* base path to current file*/
+ float dicing_rate; /* current dicing rate */
+ Mesh::DisplacementMethod displacement_method;
+};
+
+static ISampleSelector get_sample_selector(const AbcReadState &state)
+{
+ return ISampleSelector(state.time, ISampleSelector::kFloorIndex);
+}
+
+static Mesh *add_mesh(Scene *scene, const Transform& tfm)
+{
+ /* create mesh */
+ Mesh *mesh = new Mesh();
+ scene->meshes.push_back(mesh);
+
+ /* create object*/
+ Object *object = new Object();
+ object->mesh = mesh;
+ object->tfm = tfm;
+ scene->objects.push_back(object);
+
+ return mesh;
+}
+
+static void read_mesh(const AbcReadState &state, IPolyMesh object)
+{
+ /* add mesh */
+ Mesh *mesh = add_mesh(state.scene, state.tfm);
+ mesh->used_shaders.push_back(state.shader);
+
+ /* read state */
+ int shader = state.shader;
+ bool smooth = state.smooth;
+
+ mesh->displacement_method = state.displacement_method;
+
+ ISampleSelector ss = get_sample_selector(state);
+ IPolyMeshSchema schema = object.getSchema();
+
+ IPolyMeshSchema::Sample sample;
+ schema.get(sample, ss);
+
+ int totverts = sample.getPositions()->size();
+ int totfaces = sample.getFaceCounts()->size();
+ const V3f *P = sample.getPositions()->get();
+ const int32_t *verts = sample.getFaceIndices()->get();
+ const int32_t *nverts = sample.getFaceCounts()->get();
+
+ /* create vertices */
+ mesh->verts.reserve(totverts);
+ for(int i = 0; i < totverts; i++) {
+ mesh->verts.push_back(make_float3(P[i].x, P[i].y, P[i].z));
+ }
+
+ /* create triangles */
+ int index_offset = 0;
+
+ for(int i = 0; i < totfaces; i++) {
+ int n = nverts[i];
+ /* XXX TODO only supports tris and quads atm,
+ * need a proper tessellation algorithm in cycles.
+ */
+ if (n > 4) {
+ printf("%d-sided face found, only triangles and quads are supported currently", n);
+ n = 4;
+ }
+
+ for(int j = 0; j < n-2; j++) {
+ int v0 = verts[index_offset];
+ int v1 = verts[index_offset + j + 1];
+ int v2 = verts[index_offset + j + 2];
+
+ assert(v0 < (int)totverts);
+ assert(v1 < (int)totverts);
+ assert(v2 < (int)totverts);
+
+ mesh->add_triangle(v0, v1, v2, shader, smooth);
+ }
+
+ index_offset += n;
+ }
+
+ /* temporary for test compatibility */
+ mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
+}
+
+static void read_object(const AbcReadState &state, IObject object)
+{
+ for (int i = 0; i < object.getNumChildren(); ++i) {
+ IObject child = object.getChild(i);
+ const MetaData &metadata = child.getMetaData();
+
+ if (IPolyMeshSchema::matches(metadata)) {
+ read_mesh(state, IPolyMesh(child, kWrapExisting));
+ }
+ else {
+ read_object(state, child);
+ }
+ }
+}
+
+static void read_archive(Scene *scene, IArchive archive, const char *filepath)
+{
+ AbcReadState state;
+
+ state.scene = scene;
+ state.time = 0.0f; // TODO
+ state.tfm = transform_identity();
+ state.shader = scene->default_surface;
+ state.smooth = false;
+ state.dicing_rate = 0.1f;
+ state.base = path_dirname(filepath);
+
+ read_object(state, archive.getTop());
+
+ scene->params.bvh_type = SceneParams::BVH_STATIC;
+}
+
+void abc_read_ogawa_file(Scene *scene, const char *filepath, AbcArchiveInfoLevel info_level)
+{
+ IArchive archive;
+ ABC_SAFE_CALL_BEGIN
+ archive = IArchive(AbcCoreOgawa::ReadArchive(), filepath, ErrorHandler::kThrowPolicy);
+ ABC_SAFE_CALL_END
+
+ if (archive) {
+ if (info_level >= ABC_INFO_BASIC)
+ printf("%s", abc_archive_info(archive, info_level).c_str());
+
+ read_archive(scene, archive, filepath);
+ }
+}
+
+void abc_read_hdf5_file(Scene *scene, const char *filepath, AbcArchiveInfoLevel info_level)
+{
+#ifdef WITH_HDF5
+ IArchive archive;
+ ABC_SAFE_CALL_BEGIN
+ archive = IArchive(AbcCoreHDF5::ReadArchive(), filepath, ErrorHandler::kThrowPolicy);
+ ABC_SAFE_CALL_END
+
+ if (archive) {
+ if (info_level >= ABC_INFO_BASIC)
+ printf("%s", abc_archive_info(archive, info_level).c_str());
+
+ read_archive(scene, archive, filepath);
+ }
+#endif
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/app/cycles_alembic.h b/intern/cycles/app/cycles_alembic.h
new file mode 100644
index 00000000000..df17f8b8fbe
--- /dev/null
+++ b/intern/cycles/app/cycles_alembic.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 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 __CYCLES_ALEMBIC_H__
+#define __CYCLES_ALEMBIC_H__
+
+CCL_NAMESPACE_BEGIN
+
+class Scene;
+
+enum AbcArchiveInfoLevel {
+ ABC_INFO_NONE = 0,
+ ABC_INFO_BASIC,
+ ABC_INFO_OBJECTS,
+ ABC_INFO_PROPERTIES,
+};
+
+void abc_read_ogawa_file(Scene *scene, const char *filepath, AbcArchiveInfoLevel info_level = ABC_INFO_NONE);
+void abc_read_hdf5_file(Scene *scene, const char *filepath, AbcArchiveInfoLevel info_level = ABC_INFO_NONE);
+
+CCL_NAMESPACE_END
+
+#endif /* __CYCLES_XML_H__ */
diff --git a/intern/cycles/app/cycles_server.cpp b/intern/cycles/app/cycles_server.cpp
index 3d5b237eec1..4ef9cd070bb 100644
--- a/intern/cycles/app/cycles_server.cpp
+++ b/intern/cycles/app/cycles_server.cpp
@@ -24,6 +24,7 @@
#include "util_stats.h"
#include "util_string.h"
#include "util_task.h"
+#include "util_logging.h"
using namespace ccl;
@@ -66,7 +67,7 @@ int main(int argc, const char **argv)
exit(EXIT_FAILURE);
}
- if (debug) {
+ if(debug) {
util_logging_start();
util_logging_verbosity_set(verbosity);
}
diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp
index 42c339f56e5..3980ca547c2 100644
--- a/intern/cycles/app/cycles_standalone.cpp
+++ b/intern/cycles/app/cycles_standalone.cpp
@@ -21,6 +21,7 @@
#include "device.h"
#include "scene.h"
#include "session.h"
+#include "integrator.h"
#include "util_args.h"
#include "util_foreach.h"
@@ -37,13 +38,23 @@
#endif
#include "cycles_xml.h"
+#ifdef WITH_ALEMBIC
+#include "cycles_alembic.h"
+#endif
CCL_NAMESPACE_BEGIN
+enum FileType {
+ FILETYPE_XML = 0,
+ FILETYPE_ABC_HDF5,
+ FILETYPE_ABC_OGAWA,
+};
+
struct Options {
Session *session;
Scene *scene;
string filepath;
+ FileType filetype;
int width, height;
SceneParams scene_params;
SessionParams session_params;
@@ -120,11 +131,25 @@ static void scene_init()
{
options.scene = new Scene(options.scene_params, options.session_params.device);
- /* Read XML */
- xml_read_file(options.scene, options.filepath.c_str());
+ /* Read file */
+ switch (options.filetype) {
+ case FILETYPE_XML:
+ xml_read_file(options.scene, options.filepath.c_str());
+ break;
+#ifdef WITH_ALEMBIC
+ case FILETYPE_ABC_OGAWA:
+ abc_read_ogawa_file(options.scene, options.filepath.c_str());
+ break;
+ case FILETYPE_ABC_HDF5:
+ abc_read_hdf5_file(options.scene, options.filepath.c_str());
+ break;
+#endif
+ default:
+ return;
+ }
/* Camera width/height override? */
- if (!(options.width == 0 || options.height == 0)) {
+ if(!(options.width == 0 || options.height == 0)) {
options.scene->camera->width = options.width;
options.scene->camera->height = options.height;
}
@@ -272,6 +297,7 @@ static void keyboard(unsigned char key)
else if(key == 'i')
options.interactive = !(options.interactive);
+ /* Navigation */
else if(options.interactive && (key == 'w' || key == 'a' || key == 's' || key == 'd')) {
Transform matrix = options.session->scene->camera->matrix;
float3 translate;
@@ -294,6 +320,25 @@ static void keyboard(unsigned char key)
options.session->reset(session_buffer_params(), options.session_params.samples);
}
+
+ /* Set Max Bounces */
+ else if(options.interactive && (key == '0' || key == '1' || key == '2' || key == '3')) {
+ int bounce;
+ switch(key) {
+ case '0': bounce = 0; break;
+ case '1': bounce = 1; break;
+ case '2': bounce = 2; break;
+ case '3': bounce = 3; break;
+ default: bounce = 0; break;
+ }
+
+ options.session->scene->integrator->max_bounce = bounce;
+
+ /* Update and Reset */
+ options.session->scene->integrator->need_update = true;
+
+ options.session->reset(session_buffer_params(), options.session_params.samples);
+ }
}
#endif
@@ -335,6 +380,16 @@ static void options_parse(int argc, const char **argv)
/* shading system */
string ssname = "svm";
+ /* input file type */
+ string filetypes = "auto, xml";
+#ifdef WITH_ALEMBIC
+ filetypes += ", alembic_ogawa";
+#ifdef WITH_HDF5
+ filetypes += ", alembic_hdf5";
+#endif
+#endif
+ string filetype = "auto";
+
/* parse options */
ArgParse ap;
bool help = false, debug = false;
@@ -350,6 +405,7 @@ static void options_parse(int argc, const char **argv)
"--quiet", &options.quiet, "In background mode, don't print progress messages",
"--samples %d", &options.session_params.samples, "Number of samples to render",
"--output %s", &options.session_params.output_path, "File path to write output image",
+ "--filetype %s", &filetype, ("File type: " + filetypes).c_str(),
"--threads %d", &options.session_params.threads, "CPU Rendering Threads",
"--width %d", &options.width, "Window width in pixel",
"--height %d", &options.height, "Window height in pixel",
@@ -367,7 +423,7 @@ static void options_parse(int argc, const char **argv)
exit(EXIT_FAILURE);
}
- if (debug) {
+ if(debug) {
util_logging_start();
util_logging_verbosity_set(verbosity);
}
@@ -377,7 +433,8 @@ static void options_parse(int argc, const char **argv)
printf("Devices:\n");
foreach(DeviceInfo& info, devices) {
- printf(" %s%s\n",
+ printf(" %-10s%s%s\n",
+ Device::string_from_type(info.type).c_str(),
info.description.c_str(),
(info.display_device)? " (display)": "");
}
@@ -394,6 +451,21 @@ static void options_parse(int argc, const char **argv)
else if(ssname == "svm")
options.scene_params.shadingsystem = SHADINGSYSTEM_SVM;
+ if(filetype == "auto") {
+ string extension = options.filepath.substr(options.filepath.find_last_of(".") + 1);
+
+ if (extension == "xml")
+ options.filetype = FILETYPE_XML;
+ else if (extension == "abc")
+ options.filetype = FILETYPE_ABC_OGAWA;
+ }
+ else if(filetype == "xml")
+ options.filetype = FILETYPE_XML;
+ else if(filetype == "alembic_ogawa")
+ options.filetype = FILETYPE_ABC_OGAWA;
+ else if(filetype == "alembic_hdf5")
+ options.filetype = FILETYPE_ABC_HDF5;
+
#ifndef WITH_CYCLES_STANDALONE_GUI
options.session_params.background = true;
#endif
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index 05e34387eb7..d53ab67621e 100644
--- a/intern/cycles/app/cycles_xml.cpp
+++ b/intern/cycles/app/cycles_xml.cpp
@@ -42,6 +42,9 @@
#include "util_xml.h"
#include "cycles_xml.h"
+#ifdef WITH_ALEMBIC
+#include "cycles_alembic.h"
+#endif
CCL_NAMESPACE_BEGIN
@@ -55,6 +58,16 @@ struct XMLReadState {
string base; /* base path to current file*/
float dicing_rate; /* current dicing rate */
Mesh::DisplacementMethod displacement_method;
+
+ XMLReadState()
+ : scene(NULL),
+ smooth(false),
+ shader(0),
+ dicing_rate(0.0f),
+ displacement_method(Mesh::DISPLACE_BUMP)
+ {
+ tfm = transform_identity();
+ }
};
/* Attribute Reading */
@@ -225,21 +238,21 @@ static ShaderSocketType xml_read_socket_type(pugi::xml_node node, const char *na
if(attr) {
string value = attr.value();
- if (string_iequals(value, "float"))
+ if(string_iequals(value, "float"))
return SHADER_SOCKET_FLOAT;
- else if (string_iequals(value, "int"))
+ else if(string_iequals(value, "int"))
return SHADER_SOCKET_INT;
- else if (string_iequals(value, "color"))
+ else if(string_iequals(value, "color"))
return SHADER_SOCKET_COLOR;
- else if (string_iequals(value, "vector"))
+ else if(string_iequals(value, "vector"))
return SHADER_SOCKET_VECTOR;
- else if (string_iequals(value, "point"))
+ else if(string_iequals(value, "point"))
return SHADER_SOCKET_POINT;
- else if (string_iequals(value, "normal"))
+ else if(string_iequals(value, "normal"))
return SHADER_SOCKET_NORMAL;
- else if (string_iequals(value, "closure color"))
+ else if(string_iequals(value, "closure color"))
return SHADER_SOCKET_CLOSURE;
- else if (string_iequals(value, "string"))
+ else if(string_iequals(value, "string"))
return SHADER_SOCKET_STRING;
else
fprintf(stderr, "Unknown shader socket type \"%s\" for attribute \"%s\".\n", value.c_str(), name);
@@ -381,6 +394,10 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
for(pugi::xml_node node = graph_node.first_child(); node; node = node.next_sibling()) {
ShaderNode *snode = NULL;
+ /* ToDo: Add missing nodes
+ * RGBCurvesNode, VectorCurvesNode, RGBRampNode and ConvertNode (RGB -> BW).
+ */
+
if(string_iequals(node.name(), "image_texture")) {
ImageTextureNode *img = new ImageTextureNode();
@@ -391,6 +408,8 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
xml_read_enum(&img->projection, ImageTextureNode::projection_enum, node, "projection");
xml_read_float(&img->projection_blend, node, "projection_blend");
+ /* ToDo: Interpolation */
+
snode = img;
}
else if(string_iequals(node.name(), "environment_texture")) {
@@ -419,25 +438,25 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
* Socket names must be stored in the extra lists instead. */
/* read input values */
for(pugi::xml_node param = node.first_child(); param; param = param.next_sibling()) {
- if (string_iequals(param.name(), "input")) {
+ if(string_iequals(param.name(), "input")) {
string name;
- if (!xml_read_string(&name, param, "name"))
+ if(!xml_read_string(&name, param, "name"))
continue;
ShaderSocketType type = xml_read_socket_type(param, "type");
- if (type == SHADER_SOCKET_UNDEFINED)
+ if(type == SHADER_SOCKET_UNDEFINED)
continue;
osl->input_names.push_back(ustring(name));
osl->add_input(osl->input_names.back().c_str(), type);
}
- else if (string_iequals(param.name(), "output")) {
+ else if(string_iequals(param.name(), "output")) {
string name;
- if (!xml_read_string(&name, param, "name"))
+ if(!xml_read_string(&name, param, "name"))
continue;
ShaderSocketType type = xml_read_socket_type(param, "type");
- if (type == SHADER_SOCKET_UNDEFINED)
+ if(type == SHADER_SOCKET_UNDEFINED)
continue;
osl->output_names.push_back(ustring(name));
@@ -493,10 +512,6 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
xml_read_int(&magic->depth, node, "depth");
snode = magic;
}
- else if(string_iequals(node.name(), "noise_texture")) {
- NoiseTextureNode *dist = new NoiseTextureNode();
- snode = dist;
- }
else if(string_iequals(node.name(), "wave_texture")) {
WaveTextureNode *wave = new WaveTextureNode();
xml_read_enum(&wave->type, WaveTextureNode::type_enum, node, "type");
@@ -507,6 +522,11 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
xml_read_float3(&normal->direction, node, "direction");
snode = normal;
}
+ else if(string_iequals(node.name(), "bump")) {
+ BumpNode *bump = new BumpNode();
+ xml_read_bool(&bump->invert, node, "invert");
+ snode = bump;
+ }
else if(string_iequals(node.name(), "mapping")) {
snode = new MappingNode();
}
@@ -561,6 +581,9 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
else if(string_iequals(node.name(), "background")) {
snode = new BackgroundNode();
}
+ else if(string_iequals(node.name(), "holdout")) {
+ snode = new HoldoutNode();
+ }
else if(string_iequals(node.name(), "absorption_volume")) {
snode = new AbsorptionVolumeNode();
}
@@ -569,7 +592,14 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
}
else if(string_iequals(node.name(), "subsurface_scattering")) {
SubsurfaceScatteringNode *sss = new SubsurfaceScatteringNode();
- //xml_read_enum(&sss->falloff, SubsurfaceScatteringNode::falloff_enum, node, "falloff");
+
+ string falloff;
+ xml_read_string(&falloff, node, "falloff");
+ if(falloff == "cubic")
+ sss->closure = CLOSURE_BSSRDF_CUBIC_ID;
+ else
+ sss->closure = CLOSURE_BSSRDF_GAUSSIAN_ID;
+
snode = sss;
}
else if(string_iequals(node.name(), "geometry")) {
@@ -613,6 +643,7 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
snode = new InvertNode();
}
else if(string_iequals(node.name(), "mix")) {
+ /* ToDo: Tag Mix case for optimization */
MixNode *mix = new MixNode();
xml_read_enum(&mix->type, MixNode::type_enum, node, "type");
xml_read_bool(&mix->use_clamp, node, "use_clamp");
@@ -637,10 +668,10 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
snode = new SeparateHSVNode();
}
else if(string_iequals(node.name(), "combine_xyz")) {
- snode = new CombineHSVNode();
+ snode = new CombineXYZNode();
}
else if(string_iequals(node.name(), "separate_xyz")) {
- snode = new SeparateHSVNode();
+ snode = new SeparateXYZNode();
}
else if(string_iequals(node.name(), "hsv")) {
snode = new HSVNode();
@@ -1028,13 +1059,28 @@ static void xml_read_light(const XMLReadState& state, pugi::xml_node node)
xml_read_float(&light->sizev, node, "sizev");
xml_read_float3(&light->axisu, node, "axisu");
xml_read_float3(&light->axisv, node, "axisv");
-
+
+ /* Portal? (Area light only) */
+ xml_read_bool(&light->is_portal, node, "is_portal");
+
/* Generic */
xml_read_float(&light->size, node, "size");
xml_read_float3(&light->dir, node, "dir");
xml_read_float3(&light->co, node, "P");
light->co = transform_point(&state.tfm, light->co);
+ /* Settings */
+ xml_read_bool(&light->cast_shadow, node, "cast_shadow");
+ xml_read_bool(&light->use_mis, node, "use_mis");
+ xml_read_int(&light->samples, node, "samples");
+ xml_read_int(&light->max_bounces, node, "max_bounces");
+
+ /* Ray Visibility */
+ xml_read_bool(&light->use_diffuse, node, "use_diffuse");
+ xml_read_bool(&light->use_glossy, node, "use_glossy");
+ xml_read_bool(&light->use_transmission, node, "use_transmission");
+ xml_read_bool(&light->use_scatter, node, "use_scatter");
+
state.scene->lights.push_back(light);
}
@@ -1109,6 +1155,25 @@ static void xml_read_state(XMLReadState& state, pugi::xml_node node)
state.displacement_method = Mesh::DISPLACE_BOTH;
}
+/* Alembic */
+static void xml_read_alembic(const XMLReadState& state, pugi::xml_node node)
+{
+#ifdef WITH_ALEMBIC
+ string filepath;
+
+ if(xml_read_string(&filepath, node, "file")) {
+ filepath = path_join(state.base, filepath);
+
+ if(xml_equal_string(node, "type", "hdf5"))
+ abc_read_hdf5_file(state.scene, filepath.c_str(), ABC_INFO_BASIC);
+ else if(xml_equal_string(node, "type", "ogawa"))
+ abc_read_ogawa_file(state.scene, filepath.c_str(), ABC_INFO_BASIC);
+ else
+ abc_read_ogawa_file(state.scene, filepath.c_str(), ABC_INFO_BASIC); /* default */
+ }
+#endif
+}
+
/* Scene */
static void xml_read_include(const XMLReadState& state, const string& src);
@@ -1158,6 +1223,9 @@ static void xml_read_scene(const XMLReadState& state, pugi::xml_node scene_node)
if(xml_read_string(&src, node, "src"))
xml_read_include(state, src);
}
+ else if(string_iequals(node.name(), "alembic")) {
+ xml_read_alembic(state, node);
+ }
else
fprintf(stderr, "Unknown node \"%s\".\n", node.name());
}
@@ -1178,7 +1246,8 @@ static void xml_read_include(const XMLReadState& state, const string& src)
XMLReadState substate = state;
substate.base = path_dirname(path);
- xml_read_scene(substate, doc);
+ pugi::xml_node cycles = doc.child("cycles");
+ xml_read_scene(substate, cycles);
}
else {
fprintf(stderr, "%s read error: %s\n", src.c_str(), parse_result.description());
diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt
index fff9ed20bba..c6a2b919486 100644
--- a/intern/cycles/blender/CMakeLists.txt
+++ b/intern/cycles/blender/CMakeLists.txt
@@ -31,10 +31,12 @@ set(SRC
blender_session.cpp
blender_shader.cpp
blender_sync.cpp
+ blender_texture.cpp
CCL_api.h
blender_sync.h
blender_session.h
+ blender_texture.h
blender_util.h
)
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py
index 5b0c6a84bb5..0783c1c4cba 100644
--- a/intern/cycles/blender/addon/__init__.py
+++ b/intern/cycles/blender/addon/__init__.py
@@ -30,8 +30,10 @@ bl_info = {
import bpy
-from . import engine
-from . import version_update
+from . import (
+ engine,
+ version_update,
+ )
class CyclesRender(bpy.types.RenderEngine):
@@ -65,8 +67,8 @@ class CyclesRender(bpy.types.RenderEngine):
def render(self, scene):
engine.render(self)
- def bake(self, scene, obj, pass_type, pixel_array, num_pixels, depth, result):
- engine.bake(self, obj, pass_type, pixel_array, num_pixels, depth, result)
+ def bake(self, scene, obj, pass_type, object_id, pixel_array, num_pixels, depth, result):
+ engine.bake(self, obj, pass_type, object_id, pixel_array, num_pixels, depth, result)
# viewport render
def view_update(self, context):
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index e50a8e45b52..4187e2381ac 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -59,11 +59,11 @@ def render(engine):
_cycles.render(engine.session)
-def bake(engine, obj, pass_type, pixel_array, num_pixels, depth, result):
+def bake(engine, obj, pass_type, object_id, pixel_array, num_pixels, depth, result):
import _cycles
session = getattr(engine, "session", None)
if session is not None:
- _cycles.bake(engine.session, obj.as_pointer(), pass_type, pixel_array.as_pointer(), num_pixels, depth, result.as_pointer())
+ _cycles.bake(engine.session, obj.as_pointer(), pass_type, object_id, pixel_array.as_pointer(), num_pixels, depth, result.as_pointer())
def reset(engine, data, scene):
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index a86f162ae5f..0daf6784798 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -66,6 +66,7 @@ enum_panorama_types = (
('FISHEYE_EQUIDISTANT', "Fisheye Equidistant", "Ideal for fulldomes, ignore the sensor dimensions"),
('FISHEYE_EQUISOLID', "Fisheye Equisolid",
"Similar to most fisheye modern lens, takes sensor dimensions into consideration"),
+ ('MIRRORBALL', "Mirror Ball", "Uses the mirror ball mapping"),
)
enum_curve_primitives = (
@@ -393,6 +394,12 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
default=0,
)
+ cls.use_animated_seed = BoolProperty(
+ name="Use Animated Seed",
+ description="Use different seed values (and hence noise patterns) at different frames",
+ default=False,
+ )
+
cls.sample_clamp_direct = FloatProperty(
name="Clamp Direct",
description="If non-zero, the maximum value for a direct sample, "
@@ -456,6 +463,12 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
description="Use BVH spatial splits: longer builder time, faster render",
default=False,
)
+ cls.debug_use_triangle_storage = BoolProperty(
+ name="Use Triangle Storage",
+ description="use special storage with aligned triangle coordinates for faster "
+ "intesection check in expense of higher memory usage",
+ default=True,
+ )
cls.use_cache = BoolProperty(
name="Cache BVH",
description="Cache last built BVH to disk for faster re-render if no geometry changed",
@@ -504,6 +517,19 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
),
)
+ cls.use_camera_cull = BoolProperty(
+ name="Use Camera Cull",
+ description="Allow objects to be culled based on the camera frustum",
+ default=False,
+ )
+
+ cls.camera_cull_margin = FloatProperty(
+ name="Camera Cull Margin",
+ description="Margin for the camera space culling",
+ default=0.1,
+ min=0.0, max=5.0
+ )
+
@classmethod
def unregister(cls):
del bpy.types.Scene.cycles
@@ -693,6 +719,12 @@ class CyclesLampSettings(bpy.types.PropertyGroup):
"reduces noise for area lamps and sharp glossy materials",
default=False,
)
+ cls.is_portal = BoolProperty(
+ name="Is Portal",
+ description="Use this area lamp to guide sampling of the background, "
+ "note that this will make the lamp invisible",
+ default=False,
+ )
@classmethod
def unregister(cls):
@@ -877,6 +909,12 @@ class CyclesObjectBlurSettings(bpy.types.PropertyGroup):
default=1,
)
+ cls.use_camera_cull = BoolProperty(
+ name="Use Camera Cull",
+ description="Allow this object and it's duplicators to be culled by camera space culling",
+ default=False,
+ )
+
@classmethod
def unregister(cls):
del bpy.types.Object.cycles
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 8e032bafd2e..fb6a3d76dec 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -18,7 +18,11 @@
import bpy
-from bpy.types import Panel, Menu, Operator
+from bpy.types import (
+ Panel,
+ Menu,
+ Operator,
+ )
class CYCLES_MT_sampling_presets(Menu):
@@ -56,7 +60,15 @@ def use_cpu(context):
return (device_type == 'NONE' or cscene.device == 'CPU')
-def draw_samples_info(layout, cscene):
+def use_branched_path(context):
+ cscene = context.scene.cycles
+ device_type = context.user_preferences.system.compute_device_type
+
+ return (cscene.progressive == 'BRANCHED_PATH' and device_type != 'OPENCL')
+
+
+def draw_samples_info(layout, context):
+ cscene = context.scene.cycles
integrator = cscene.progressive
# Calculate sample values
@@ -86,7 +98,7 @@ def draw_samples_info(layout, cscene):
# Draw interface
# Do not draw for progressive, when Square Samples are disabled
- if (integrator == 'BRANCHED_PATH') or (cscene.use_square_samples and integrator == 'PATH'):
+ if use_branched_path(context) or (cscene.use_square_samples and integrator == 'PATH'):
col = layout.column(align=True)
col.scale_y = 0.6
col.label("Total Samples:")
@@ -110,6 +122,7 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel):
scene = context.scene
cscene = scene.cycles
+ device_type = context.user_preferences.system.compute_device_type
row = layout.row(align=True)
row.menu("CYCLES_MT_sampling_presets", text=bpy.types.CYCLES_MT_sampling_presets.bl_label)
@@ -117,7 +130,9 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel):
row.operator("render.cycles_sampling_preset_add", text="", icon="ZOOMOUT").remove_active = True
row = layout.row()
- row.prop(cscene, "progressive", text="")
+ sub = row.row()
+ sub.active = device_type != 'OPENCL'
+ sub.prop(cscene, "progressive", text="")
row.prop(cscene, "use_square_samples")
split = layout.split()
@@ -125,11 +140,15 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel):
col = split.column()
sub = col.column(align=True)
sub.label("Settings:")
- sub.prop(cscene, "seed")
+
+ seed_sub = sub.row(align=True)
+ seed_sub.prop(cscene, "seed")
+ seed_sub.prop(cscene, "use_animated_seed", text="", icon="TIME")
+
sub.prop(cscene, "sample_clamp_direct")
sub.prop(cscene, "sample_clamp_indirect")
- if cscene.progressive == 'PATH':
+ if cscene.progressive == 'PATH' or use_branched_path(context) == False:
col = split.column()
sub = col.column(align=True)
sub.label(text="Samples:")
@@ -163,7 +182,7 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel):
layout.row().prop(cscene, "use_layer_samples")
break
- draw_samples_info(layout, cscene)
+ draw_samples_info(layout, context)
class CyclesRender_PT_volume_sampling(CyclesButtonsPanel, Panel):
@@ -303,6 +322,11 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
subsub.enabled = not rd.use_border
subsub.prop(rd, "use_save_buffers")
+ sub.prop(cscene, "use_camera_cull")
+ subsub = col.column()
+ subsub.active = cscene.use_camera_cull
+ subsub.prop(cscene, "camera_cull_margin")
+
col = split.column(align=True)
col.label(text="Viewport:")
@@ -320,6 +344,7 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
col.label(text="Acceleration structure:")
col.prop(cscene, "debug_use_spatial_splits")
+ col.prop(cscene, "debug_use_triangle_storage")
class CyclesRender_PT_layer_options(CyclesButtonsPanel, Panel):
@@ -413,6 +438,48 @@ class CyclesRender_PT_layer_passes(CyclesButtonsPanel, Panel):
col.prop(rl, "use_pass_environment")
+class CyclesRender_PT_views(CyclesButtonsPanel, Panel):
+ bl_label = "Views"
+ bl_context = "render_layer"
+
+ def draw_header(self, context):
+ rd = context.scene.render
+ self.layout.prop(rd, "use_multiview", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ scene = context.scene
+ rd = scene.render
+ rv = rd.views.active
+
+ layout.active = rd.use_multiview
+ basic_stereo = (rd.views_format == 'STEREO_3D')
+
+ row = layout.row()
+ row.prop(rd, "views_format", expand=True)
+
+ if basic_stereo:
+ row = layout.row()
+ row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "stereo_views", rd.views, "active_index", rows=2)
+
+ row = layout.row()
+ row.label(text="File Suffix:")
+ row.prop(rv, "file_suffix", text="")
+
+ else:
+ row = layout.row()
+ row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "views", rd.views, "active_index", rows=2)
+
+ col = row.column(align=True)
+ col.operator("scene.render_view_add", icon='ZOOMIN', text="")
+ col.operator("scene.render_view_remove", icon='ZOOMOUT', text="")
+
+ row = layout.row()
+ row.label(text="Camera Suffix:")
+ row.prop(rv, "camera_suffix", text="")
+
+
class Cycles_PT_post_processing(CyclesButtonsPanel, Panel):
bl_label = "Post Processing"
bl_options = {'DEFAULT_CLOSED'}
@@ -456,7 +523,16 @@ class CyclesCamera_PT_dof(CyclesButtonsPanel, Panel):
sub = col.row()
sub.active = cam.dof_object is None
sub.prop(cam, "dof_distance", text="Distance")
- col.prop(dof_options, "fstop")
+
+ hq_support = dof_options.is_hq_supported
+ sub = col.column(align=True)
+ sub.label("Viewport:")
+ subhq = sub.column()
+ subhq.active = hq_support
+ subhq.prop(dof_options, "use_high_quality")
+ sub.prop(dof_options, "fstop")
+ if dof_options.use_high_quality and hq_support:
+ sub.prop(dof_options, "blades")
col = split.column()
@@ -490,11 +566,16 @@ class Cycles_PT_context_material(CyclesButtonsPanel, Panel):
ob = context.object
slot = context.material_slot
space = context.space_data
+ is_sortable = len(ob.material_slots) > 1
if ob:
+ rows = 1
+ if (is_sortable):
+ rows = 4
+
row = layout.row()
- row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=1)
+ row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=rows)
col = row.column(align=True)
col.operator("object.material_slot_add", icon='ZOOMIN', text="")
@@ -502,6 +583,12 @@ class Cycles_PT_context_material(CyclesButtonsPanel, Panel):
col.menu("MATERIAL_MT_specials", icon='DOWNARROW_HLT', text="")
+ if is_sortable:
+ col.separator()
+
+ col.operator("object.material_slot_move", icon='TRIA_UP', text="").direction = 'UP'
+ col.operator("object.material_slot_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
+
if ob.mode == 'EDIT':
row = layout.row(align=True)
row.operator("object.material_slot_assign", text="Assign")
@@ -597,8 +684,8 @@ class CyclesObject_PT_motion_blur(CyclesButtonsPanel, Panel):
sub.prop(cob, "motion_steps", text="Steps")
-class CyclesObject_PT_ray_visibility(CyclesButtonsPanel, Panel):
- bl_label = "Ray Visibility"
+class CyclesObject_PT_cycles_settings(CyclesButtonsPanel, Panel):
+ bl_label = "Cycles Settings"
bl_context = "object"
bl_options = {'DEFAULT_CLOSED'}
@@ -613,8 +700,10 @@ class CyclesObject_PT_ray_visibility(CyclesButtonsPanel, Panel):
layout = self.layout
ob = context.object
+ cob = ob.cycles
visibility = ob.cycles_visibility
+ layout.label(text="Ray Visibility:")
flow = layout.column_flow()
flow.prop(visibility, "camera")
@@ -626,6 +715,9 @@ class CyclesObject_PT_ray_visibility(CyclesButtonsPanel, Panel):
if ob.type != 'LAMP':
flow.prop(visibility, "shadow")
+ layout.label(text="Performance:")
+ layout.prop(cob, "use_camera_cull")
+
class CYCLES_OT_use_shading_nodes(Operator):
"""Enable nodes on a material, world or lamp"""
@@ -652,9 +744,14 @@ def find_node(material, nodetype):
if material and material.node_tree:
ntree = material.node_tree
+ active_output_node = None
for node in ntree.nodes:
if getattr(node, "type", None) == nodetype:
- return node
+ if getattr(node, "is_active_output", True):
+ return node
+ if not active_output_node:
+ active_output_node = node
+ return active_output_node
return None
@@ -691,7 +788,10 @@ class CyclesLamp_PT_preview(CyclesButtonsPanel, Panel):
@classmethod
def poll(cls, context):
- return context.lamp and CyclesButtonsPanel.poll(context)
+ return context.lamp and \
+ not (context.lamp.type == 'AREA' and
+ context.lamp.cycles.is_portal) \
+ and CyclesButtonsPanel.poll(context)
def draw(self, context):
self.layout.template_preview(context.lamp)
@@ -729,13 +829,21 @@ class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel):
sub.prop(lamp, "size", text="Size X")
sub.prop(lamp, "size_y", text="Size Y")
- if cscene.progressive == 'BRANCHED_PATH':
- col.prop(clamp, "samples")
- col.prop(clamp, "max_bounces")
+ if not (lamp.type == 'AREA' and clamp.is_portal):
+ sub = col.column(align=True)
+ if use_branched_path(context):
+ sub.prop(clamp, "samples")
+ sub.prop(clamp, "max_bounces")
col = split.column()
- col.prop(clamp, "cast_shadow")
- col.prop(clamp, "use_multiple_importance_sampling", text="Multiple Importance")
+
+ sub = col.column(align=True)
+ sub.active = not (lamp.type == 'AREA' and clamp.is_portal)
+ sub.prop(clamp, "cast_shadow")
+ sub.prop(clamp, "use_multiple_importance_sampling", text="Multiple Importance")
+
+ if lamp.type == 'AREA':
+ col.prop(clamp, "is_portal", text="Portal")
if lamp.type == 'HEMI':
layout.label(text="Not supported, interpreted as sun lamp")
@@ -747,7 +855,9 @@ class CyclesLamp_PT_nodes(CyclesButtonsPanel, Panel):
@classmethod
def poll(cls, context):
- return context.lamp and CyclesButtonsPanel.poll(context)
+ return context.lamp and not (context.lamp.type == 'AREA' and
+ context.lamp.cycles.is_portal) and \
+ CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
@@ -930,7 +1040,7 @@ class CyclesWorld_PT_settings(CyclesButtonsPanel, Panel):
sub = col.column(align=True)
sub.active = cworld.sample_as_light
sub.prop(cworld, "sample_map_resolution")
- if cscene.progressive == 'BRANCHED_PATH':
+ if use_branched_path(context):
sub.prop(cworld, "samples")
col = split.column()
@@ -1032,7 +1142,7 @@ class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
sub = col.column()
sub.active = use_cpu(context)
sub.prop(cmat, "volume_sampling", text="")
- col.prop(cmat, "volume_interpolation", text="")
+ sub.prop(cmat, "volume_interpolation", text="")
col.prop(cmat, "homogeneous_volume", text="Homogeneous")
layout.separator()
@@ -1117,7 +1227,8 @@ class CyclesTexture_PT_mapping(CyclesButtonsPanel, Panel):
@classmethod
def poll(cls, context):
node = context.texture_node
- return node and CyclesButtonsPanel.poll(context)
+ # TODO(sergey): perform a faster/nicer check?
+ return node and hasattr(node, 'texture_mapping') and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
@@ -1341,13 +1452,21 @@ class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
- rd = context.scene.render
+ scene = context.scene
+ rd = scene.render
layout.active = rd.use_simplify
+ split = layout.split()
- row = layout.row()
- row.prop(rd, "simplify_subdivision", text="Subdivision")
- row.prop(rd, "simplify_child_particles", text="Child Particles")
+ col = split.column()
+ col.label(text="Viewport:")
+ col.prop(rd, "simplify_subdivision", text="Subdivision")
+ col.prop(rd, "simplify_child_particles", text="Child Particles")
+
+ col = split.column()
+ col.label(text="Render:")
+ col.prop(rd, "simplify_subdivision_render", text="Subdivision")
+ col.prop(rd, "simplify_child_particles_render", text="Child Particles")
def draw_device(self, context):
@@ -1420,6 +1539,7 @@ def get_panels():
"DATA_PT_vertex_colors",
"DATA_PT_camera",
"DATA_PT_camera_display",
+ "DATA_PT_camera_stereoscopy",
"DATA_PT_camera_safe_areas",
"DATA_PT_lens",
"DATA_PT_speaker",
diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py
index 741c2010774..2fbb01ba5b8 100644
--- a/intern/cycles/blender/addon/version_update.py
+++ b/intern/cycles/blender/addon/version_update.py
@@ -21,10 +21,8 @@ import bpy
from bpy.app.handlers import persistent
-def check_is_new_shading_material(material):
- if not material.node_tree:
- return False
- for node in material.node_tree.nodes:
+def check_is_new_shading_ntree(node_tree):
+ for node in node_tree.nodes:
# If material has any node with ONLY new shading system
# compatibility then it's considered a Cycles material
# and versioning code would need to perform on it.
@@ -44,6 +42,24 @@ def check_is_new_shading_material(material):
return False
+def check_is_new_shading_material(material):
+ if not material.node_tree:
+ return False
+ return check_is_new_shading_ntree(material.node_tree)
+
+
+def check_is_new_shading_world(world):
+ if not world.node_tree:
+ return False
+ return check_is_new_shading_ntree(world.node_tree)
+
+
+def check_is_new_shading_lamp(lamp):
+ if not lamp.node_tree:
+ return False
+ return check_is_new_shading_ntree(lamp.node_tree)
+
+
def foreach_notree_node(nodetree, callback, traversed):
if nodetree in traversed:
return
@@ -61,6 +77,16 @@ def foreach_cycles_node(callback):
foreach_notree_node(material.node_tree,
callback,
traversed)
+ for world in bpy.data.worlds:
+ if check_is_new_shading_world(world):
+ foreach_notree_node(world.node_tree,
+ callback,
+ traversed)
+ for lamp in bpy.data.lamps:
+ if check_is_new_shading_world(lamp):
+ foreach_notree_node(lamp.node_tree,
+ callback,
+ traversed)
def mapping_node_order_flip(node):
diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp
index dee9ee09fc6..3d23b5ecea8 100644
--- a/intern/cycles/blender/blender_camera.cpp
+++ b/intern/cycles/blender/blender_camera.cpp
@@ -72,7 +72,7 @@ struct BlenderCamera {
Transform matrix;
};
-static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings b_render, BL::Scene b_scene)
+static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings b_render)
{
memset(bcam, 0, sizeof(BlenderCamera));
@@ -95,7 +95,7 @@ static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings b_render
bcam->full_height = render_resolution_y(b_render);
}
-static float blender_camera_focal_distance(BL::Object b_ob, BL::Camera b_camera)
+static float blender_camera_focal_distance(BL::RenderEngine b_engine, BL::Object b_ob, BL::Camera b_camera)
{
BL::Object b_dof_object = b_camera.dof_object();
@@ -103,14 +103,16 @@ static float blender_camera_focal_distance(BL::Object b_ob, BL::Camera b_camera)
return b_camera.dof_distance();
/* for dof object, return distance along camera Z direction */
- Transform obmat = transform_clear_scale(get_transform(b_ob.matrix_world()));
+ BL::Array<float, 16> b_ob_matrix;
+ b_engine.camera_model_matrix(b_ob, b_ob_matrix);
+ Transform obmat = get_transform(b_ob_matrix);
Transform dofmat = get_transform(b_dof_object.matrix_world());
Transform mat = transform_inverse(obmat) * dofmat;
return fabsf(transform_get_column(&mat, 3).z);
}
-static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob, bool skip_panorama = false)
+static void blender_camera_from_object(BlenderCamera *bcam, BL::RenderEngine b_engine, BL::Object b_ob, bool skip_panorama = false)
{
BL::ID b_ob_data = b_ob.data();
@@ -146,6 +148,9 @@ static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob, boo
case 2:
bcam->panorama_type = PANORAMA_FISHEYE_EQUISOLID;
break;
+ case 3:
+ bcam->panorama_type = PANORAMA_MIRRORBALL;
+ break;
case 0:
default:
bcam->panorama_type = PANORAMA_EQUIRECTANGULAR;
@@ -181,10 +186,10 @@ static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob, boo
bcam->apertureblades = RNA_int_get(&ccamera, "aperture_blades");
bcam->aperturerotation = RNA_float_get(&ccamera, "aperture_rotation");
- bcam->focaldistance = blender_camera_focal_distance(b_ob, b_camera);
+ bcam->focaldistance = blender_camera_focal_distance(b_engine, b_ob, b_camera);
bcam->aperture_ratio = RNA_float_get(&ccamera, "aperture_ratio");
- bcam->shift.x = b_camera.shift_x();
+ bcam->shift.x = b_engine.camera_shift_x(b_ob);
bcam->shift.y = b_camera.shift_y();
bcam->sensor_width = b_camera.sensor_width();
@@ -303,7 +308,7 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int
&cam->viewplane, &aspectratio, &sensor_size);
/* panorama sensor */
- if (bcam->type == CAMERA_PANORAMA && bcam->panorama_type == PANORAMA_FISHEYE_EQUISOLID) {
+ if(bcam->type == CAMERA_PANORAMA && bcam->panorama_type == PANORAMA_FISHEYE_EQUISOLID) {
float fit_xratio = (float)bcam->full_width*bcam->pixelaspect.x;
float fit_yratio = (float)bcam->full_height*bcam->pixelaspect.y;
bool horizontal_fit;
@@ -380,7 +385,7 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int
void BlenderSync::sync_camera(BL::RenderSettings b_render, BL::Object b_override, int width, int height)
{
BlenderCamera bcam;
- blender_camera_init(&bcam, b_render, b_scene);
+ blender_camera_init(&bcam, b_render);
/* pixel aspect */
bcam.pixelaspect.x = b_render.pixel_aspect_x();
@@ -402,8 +407,10 @@ void BlenderSync::sync_camera(BL::RenderSettings b_render, BL::Object b_override
b_ob = b_override;
if(b_ob) {
- blender_camera_from_object(&bcam, b_ob);
- bcam.matrix = get_transform(b_ob.matrix_world());
+ BL::Array<float, 16> b_ob_matrix;
+ blender_camera_from_object(&bcam, b_engine, b_ob);
+ b_engine.camera_model_matrix(b_ob, b_ob_matrix);
+ bcam.matrix = get_transform(b_ob_matrix);
}
/* sync */
@@ -414,8 +421,9 @@ void BlenderSync::sync_camera(BL::RenderSettings b_render, BL::Object b_override
void BlenderSync::sync_camera_motion(BL::Object b_ob, float motion_time)
{
Camera *cam = scene->camera;
-
- Transform tfm = get_transform(b_ob.matrix_world());
+ BL::Array<float, 16> b_ob_matrix;
+ b_engine.camera_model_matrix(b_ob, b_ob_matrix);
+ Transform tfm = get_transform(b_ob_matrix);
tfm = blender_camera_matrix(tfm, cam->type);
if(tfm != cam->matrix) {
@@ -433,10 +441,10 @@ void BlenderSync::sync_camera_motion(BL::Object b_ob, float motion_time)
/* Sync 3D View Camera */
-static void blender_camera_view_subset(BL::RenderSettings b_render, BL::Scene b_scene, BL::Object b_ob, BL::SpaceView3D b_v3d,
+static void blender_camera_view_subset(BL::RenderEngine b_engine, BL::RenderSettings b_render, BL::Scene b_scene, BL::Object b_ob, BL::SpaceView3D b_v3d,
BL::RegionView3D b_rv3d, int width, int height, BoundBox2D *view_box, BoundBox2D *cam_box);
-static void blender_camera_from_view(BlenderCamera *bcam, BL::Scene b_scene, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height, bool skip_panorama = false)
+static void blender_camera_from_view(BlenderCamera *bcam, BL::RenderEngine b_engine, BL::Scene b_scene, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height, bool skip_panorama = false)
{
/* 3d view parameters */
bcam->nearclip = b_v3d.clip_start();
@@ -449,13 +457,13 @@ static void blender_camera_from_view(BlenderCamera *bcam, BL::Scene b_scene, BL:
BL::Object b_ob = (b_v3d.lock_camera_and_layers())? b_scene.camera(): b_v3d.camera();
if(b_ob) {
- blender_camera_from_object(bcam, b_ob, skip_panorama);
+ blender_camera_from_object(bcam, b_engine, b_ob, skip_panorama);
if(!skip_panorama && bcam->type == CAMERA_PANORAMA) {
/* in panorama camera view, we map viewplane to camera border */
BoundBox2D view_box, cam_box;
- blender_camera_view_subset(b_scene.render(), b_scene, b_ob, b_v3d, b_rv3d, width, height,
+ blender_camera_view_subset(b_engine, b_scene.render(), b_scene, b_ob, b_v3d, b_rv3d, width, height,
&view_box, &cam_box);
bcam->pano_viewplane = view_box.make_relative_to(cam_box);
@@ -493,7 +501,7 @@ static void blender_camera_from_view(BlenderCamera *bcam, BL::Scene b_scene, BL:
bcam->matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
}
-static void blender_camera_view_subset(BL::RenderSettings b_render, BL::Scene b_scene, BL::Object b_ob, BL::SpaceView3D b_v3d,
+static void blender_camera_view_subset(BL::RenderEngine b_engine, BL::RenderSettings b_render, BL::Scene b_scene, BL::Object b_ob, BL::SpaceView3D b_v3d,
BL::RegionView3D b_rv3d, int width, int height, BoundBox2D *view_box, BoundBox2D *cam_box)
{
BoundBox2D cam, view;
@@ -501,16 +509,16 @@ static void blender_camera_view_subset(BL::RenderSettings b_render, BL::Scene b_
/* get viewport viewplane */
BlenderCamera view_bcam;
- blender_camera_init(&view_bcam, b_render, b_scene);
- blender_camera_from_view(&view_bcam, b_scene, b_v3d, b_rv3d, width, height, true);
+ blender_camera_init(&view_bcam, b_render);
+ blender_camera_from_view(&view_bcam, b_engine, b_scene, b_v3d, b_rv3d, width, height, true);
blender_camera_viewplane(&view_bcam, width, height,
&view, &view_aspect, &sensor_size);
/* get camera viewplane */
BlenderCamera cam_bcam;
- blender_camera_init(&cam_bcam, b_render, b_scene);
- blender_camera_from_object(&cam_bcam, b_ob, true);
+ blender_camera_init(&cam_bcam, b_render);
+ blender_camera_from_object(&cam_bcam, b_engine, b_ob, true);
blender_camera_viewplane(&cam_bcam, cam_bcam.full_width, cam_bcam.full_height,
&cam, &cam_aspect, &sensor_size);
@@ -520,7 +528,8 @@ static void blender_camera_view_subset(BL::RenderSettings b_render, BL::Scene b_
*cam_box = cam * (1.0f/cam_aspect);
}
-static void blender_camera_border_subset(BL::RenderSettings b_render,
+static void blender_camera_border_subset(BL::RenderEngine b_engine,
+ BL::RenderSettings b_render,
BL::Scene b_scene,
BL::SpaceView3D b_v3d,
BL::RegionView3D b_rv3d,
@@ -531,7 +540,7 @@ static void blender_camera_border_subset(BL::RenderSettings b_render,
{
/* Determine camera viewport subset. */
BoundBox2D view_box, cam_box;
- blender_camera_view_subset(b_render, b_scene, b_ob, b_v3d, b_rv3d, width, height,
+ blender_camera_view_subset(b_engine, b_render, b_scene, b_ob, b_v3d, b_rv3d, width, height,
&view_box, &cam_box);
/* Determine viewport subset matching given border. */
@@ -539,7 +548,7 @@ static void blender_camera_border_subset(BL::RenderSettings b_render,
*result = cam_box.subset(border);
}
-static void blender_camera_border(BlenderCamera *bcam, BL::RenderSettings b_render, BL::Scene b_scene, BL::SpaceView3D b_v3d,
+static void blender_camera_border(BlenderCamera *bcam, BL::RenderEngine b_engine, BL::RenderSettings b_render, BL::Scene b_scene, BL::SpaceView3D b_v3d,
BL::RegionView3D b_rv3d, int width, int height)
{
bool is_camera_view;
@@ -568,7 +577,8 @@ static void blender_camera_border(BlenderCamera *bcam, BL::RenderSettings b_rend
/* Determine camera border inside the viewport. */
BoundBox2D full_border;
- blender_camera_border_subset(b_render,
+ blender_camera_border_subset(b_engine,
+ b_render,
b_scene,
b_v3d,
b_rv3d,
@@ -587,7 +597,8 @@ static void blender_camera_border(BlenderCamera *bcam, BL::RenderSettings b_rend
bcam->border.top = b_render.border_max_y();
/* Determine viewport subset matching camera border. */
- blender_camera_border_subset(b_render,
+ blender_camera_border_subset(b_engine,
+ b_render,
b_scene,
b_v3d,
b_rv3d,
@@ -601,14 +612,14 @@ static void blender_camera_border(BlenderCamera *bcam, BL::RenderSettings b_rend
void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height)
{
BlenderCamera bcam;
- blender_camera_init(&bcam, b_scene.render(), b_scene);
- blender_camera_from_view(&bcam, b_scene, b_v3d, b_rv3d, width, height);
- blender_camera_border(&bcam, b_scene.render(), b_scene, b_v3d, b_rv3d, width, height);
+ blender_camera_init(&bcam, b_scene.render());
+ blender_camera_from_view(&bcam, b_engine, b_scene, b_v3d, b_rv3d, width, height);
+ blender_camera_border(&bcam, b_engine, b_scene.render(), b_scene, b_v3d, b_rv3d, width, height);
blender_camera_sync(scene->camera, &bcam, width, height);
}
-BufferParams BlenderSync::get_buffer_params(BL::RenderSettings b_render, BL::Scene b_scene, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, Camera *cam, int width, int height)
+BufferParams BlenderSync::get_buffer_params(BL::RenderSettings b_render, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, Camera *cam, int width, int height)
{
BufferParams params;
bool use_border = false;
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp
index 72023d7e69b..4ed0b910f35 100644
--- a/intern/cycles/blender/blender_curves.cpp
+++ b/intern/cycles/blender/blender_curves.cpp
@@ -37,15 +37,14 @@ void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, floa
void interp_weights(float t, float data[4]);
float shaperadius(float shape, float root, float tip, float time);
void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData);
-bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num);
-bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num);
-bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background);
void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData);
void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
float3 RotCam, bool is_ortho);
void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resolution);
-void ExportCurveTriangleUV(Mesh *mesh, ParticleCurveData *CData, int vert_offset, int resol, float3 *uvdata);
-void ExportCurveTriangleVcol(Mesh *mesh, ParticleCurveData *CData, int vert_offset, int resol, uchar4 *cdata);
+void ExportCurveTriangleUV(ParticleCurveData *CData, int vert_offset, int resol, float3 *uvdata);
+void ExportCurveUV(Mesh *mesh, ParticleCurveData *CData, ustring name, bool active_render, int primitive, int vert_offset, int resol);
+void ExportCurveTriangleVcol(ParticleCurveData *CData, int vert_offset, int resol, uchar4 *cdata);
+void ExportCurveVcol(Mesh *mesh, ParticleCurveData *CData, ustring name, int primitive, int vert_offset, int resol);
ParticleCurveData::ParticleCurveData()
{
@@ -119,214 +118,338 @@ void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyl
curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t);
}
-bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background)
+static void ObtainCacheParticleData(Mesh *mesh, BL::Object b_ob, BL::ParticleSystem b_psys, const Transform &itfm,
+ ParticleCurveData *CData, bool background)
{
- int curvenum = 0;
- int keyno = 0;
+ BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+ int mi = clamp(b_part.material()-1, 0, mesh->used_shaders.size()-1);
+ int shader = mesh->used_shaders[mi];
+ int draw_step = background ? b_part.render_step() : b_part.draw_step();
+ int totparts = b_psys.particles.length();
+ int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
+ int totcurves = totchild;
+
+ if(b_part.child_type() == 0)
+ totcurves += totparts;
- if(!(mesh && b_mesh && b_ob && CData))
- return false;
+ if(totcurves == 0)
+ return;
- Transform tfm = get_transform(b_ob->matrix_world());
- Transform itfm = transform_quick_inverse(tfm);
+ int ren_step = (1 << draw_step) + 1;
+ if(b_part.kink() == BL::ParticleSettings::kink_SPIRAL)
+ ren_step += b_part.kink_extra_steps();
- BL::Object::modifiers_iterator b_mod;
- for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
- if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
- BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
- BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+ PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
+
+ int keyno = CData->curvekey_co.size();
+ int curvenum = CData->curve_keynum.size();
+
+ CData->psys_firstcurve.push_back(curvenum);
+ CData->psys_curvenum.push_back(totcurves);
+ CData->psys_shader.push_back(shader);
+
+ float radius = get_float(cpsys, "radius_scale") * 0.5f;
+
+ CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
+ CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
+ CData->psys_shape.push_back(get_float(cpsys, "shape"));
+ CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
+
+ int pa_no = 0;
+ if(!(b_part.child_type() == 0))
+ pa_no = totparts;
+
+ int num_add = (totparts+totchild - pa_no);
+ CData->curve_firstkey.reserve(CData->curve_firstkey.size() + num_add);
+ CData->curve_keynum.reserve(CData->curve_keynum.size() + num_add);
+ CData->curve_length.reserve(CData->curve_length.size() + num_add);
+ CData->curvekey_co.reserve(CData->curvekey_co.size() + num_add*ren_step);
+ CData->curvekey_time.reserve(CData->curvekey_time.size() + num_add*ren_step);
+
+ for(; pa_no < totparts+totchild; pa_no++) {
+ int keynum = 0;
+ CData->curve_firstkey.push_back(keyno);
+
+ float curve_length = 0.0f;
+ float3 pcKey;
+ for(int step_no = 0; step_no < ren_step; step_no++) {
+ float nco[3];
+ b_psys.co_hair(b_ob, pa_no, step_no, nco);
+ float3 cKey = make_float3(nco[0], nco[1], nco[2]);
+ cKey = transform_point(&itfm, cKey);
+ if(step_no > 0) {
+ float step_length = len(cKey - pcKey);
+ if(step_length == 0.0f)
+ continue;
+ curve_length += step_length;
+ }
+ CData->curvekey_co.push_back(cKey);
+ CData->curvekey_time.push_back(curve_length);
+ pcKey = cKey;
+ keynum++;
+ }
+ keyno += keynum;
- if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
- int mi = clamp(b_part.material()-1, 0, mesh->used_shaders.size()-1);
- int shader = mesh->used_shaders[mi];
- int draw_step = background ? b_part.render_step() : b_part.draw_step();
- int totparts = b_psys.particles.length();
- int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
- int totcurves = totchild;
-
- if(b_part.child_type() == 0)
- totcurves += totparts;
+ CData->curve_keynum.push_back(keynum);
+ CData->curve_length.push_back(curve_length);
+ curvenum++;
+ }
+}
- if(totcurves == 0)
- continue;
+static void ObtainCacheParticleUV(Mesh * /*mesh*/, BL::Object /*b_ob*/, BL::Mesh b_mesh, BL::ParticleSystem b_psys, BL::ParticleSystemModifier b_psmd,
+ ParticleCurveData *CData, bool background, int uv_num)
+{
+ BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+ int totparts = b_psys.particles.length();
+ int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
+ int totcurves = totchild;
+
+ if(b_part.child_type() == 0)
+ totcurves += totparts;
- int ren_step = (1 << draw_step) + 1;
- if (b_part.kink() == BL::ParticleSettings::kink_SPIRAL)
- ren_step += b_part.kink_extra_steps();
+ if(totcurves == 0)
+ return;
- PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
+ int pa_no = 0;
+ if(!(b_part.child_type() == 0))
+ pa_no = totparts;
- CData->psys_firstcurve.push_back(curvenum);
- CData->psys_curvenum.push_back(totcurves);
- CData->psys_shader.push_back(shader);
+ int num_add = (totparts+totchild - pa_no);
+ CData->curve_uv.reserve(CData->curve_uv.size() + num_add);
- float radius = get_float(cpsys, "radius_scale") * 0.5f;
-
- CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
- CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
- CData->psys_shape.push_back(get_float(cpsys, "shape"));
- CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
-
- int pa_no = 0;
- if(!(b_part.child_type() == 0))
- pa_no = totparts;
-
- int num_add = (totparts+totchild - pa_no);
- CData->curve_firstkey.reserve(CData->curve_firstkey.size() + num_add);
- CData->curve_keynum.reserve(CData->curve_keynum.size() + num_add);
- CData->curve_length.reserve(CData->curve_length.size() + num_add);
- CData->curvekey_co.reserve(CData->curvekey_co.size() + num_add*ren_step);
- CData->curvekey_time.reserve(CData->curvekey_time.size() + num_add*ren_step);
-
- for(; pa_no < totparts+totchild; pa_no++) {
- int keynum = 0;
- CData->curve_firstkey.push_back(keyno);
-
- float curve_length = 0.0f;
- float3 pcKey;
- for(int step_no = 0; step_no < ren_step; step_no++) {
- float nco[3];
- b_psys.co_hair(*b_ob, pa_no, step_no, nco);
- float3 cKey = make_float3(nco[0], nco[1], nco[2]);
- cKey = transform_point(&itfm, cKey);
- if(step_no > 0) {
- float step_length = len(cKey - pcKey);
- if(step_length == 0.0f)
- continue;
- curve_length += step_length;
- }
- CData->curvekey_co.push_back(cKey);
- CData->curvekey_time.push_back(curve_length);
- pcKey = cKey;
- keynum++;
- }
- keyno += keynum;
+ BL::ParticleSystem::particles_iterator b_pa;
+ b_psys.particles.begin(b_pa);
+ for(; pa_no < totparts+totchild; pa_no++) {
+ /* Add UVs */
+ BL::Mesh::tessface_uv_textures_iterator l;
+ b_mesh.tessface_uv_textures.begin(l);
- CData->curve_keynum.push_back(keynum);
- CData->curve_length.push_back(curve_length);
- curvenum++;
- }
- }
- }
- }
+ float3 uv = make_float3(0.0f, 0.0f, 0.0f);
+ if(b_mesh.tessface_uv_textures.length())
+ b_psys.uv_on_emitter(b_psmd, *b_pa, pa_no, uv_num, &uv.x);
+ CData->curve_uv.push_back(uv);
- return true;
+ if(pa_no < totparts && b_pa != b_psys.particles.end())
+ ++b_pa;
+ }
}
-bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num)
+static void ObtainCacheParticleVcol(Mesh * /*mesh*/, BL::Object /*b_ob*/, BL::Mesh b_mesh, BL::ParticleSystem b_psys, BL::ParticleSystemModifier b_psmd,
+ ParticleCurveData *CData, bool background, int vcol_num)
{
- if(!(mesh && b_mesh && b_ob && CData))
- return false;
+ BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+ int totparts = b_psys.particles.length();
+ int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
+ int totcurves = totchild;
+
+ if(b_part.child_type() == 0)
+ totcurves += totparts;
- CData->curve_uv.clear();
+ if(totcurves == 0)
+ return;
- BL::Object::modifiers_iterator b_mod;
- for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
- if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
- BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
- BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+ int pa_no = 0;
+ if(!(b_part.child_type() == 0))
+ pa_no = totparts;
- if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
- int totparts = b_psys.particles.length();
- int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
- int totcurves = totchild;
-
- if (b_part.child_type() == 0)
- totcurves += totparts;
+ int num_add = (totparts+totchild - pa_no);
+ CData->curve_vcol.reserve(CData->curve_vcol.size() + num_add);
- if (totcurves == 0)
- continue;
+ BL::ParticleSystem::particles_iterator b_pa;
+ b_psys.particles.begin(b_pa);
+ for(; pa_no < totparts+totchild; pa_no++) {
+ /* Add vertex colors */
+ BL::Mesh::tessface_vertex_colors_iterator l;
+ b_mesh.tessface_vertex_colors.begin(l);
- int pa_no = 0;
- if(!(b_part.child_type() == 0))
- pa_no = totparts;
+ float3 vcol = make_float3(0.0f, 0.0f, 0.0f);
+ if(b_mesh.tessface_vertex_colors.length())
+ b_psys.mcol_on_emitter(b_psmd, *b_pa, pa_no, vcol_num, &vcol.x);
+ CData->curve_vcol.push_back(vcol);
- int num_add = (totparts+totchild - pa_no);
- CData->curve_uv.reserve(CData->curve_uv.size() + num_add);
+ if(pa_no < totparts && b_pa != b_psys.particles.end())
+ ++b_pa;
+ }
+}
+
+/* A little bit of templated code here to avoid much duplication for parent/child strands:
+ * Most attributes are the same for both types, but some are handled slightly differently.
+ * These attributes are handled by templated utility functions that automatically get selected by type.
+ */
+template <typename StrandsT>
+struct StrandsTraits;
- BL::ParticleSystem::particles_iterator b_pa;
- b_psys.particles.begin(b_pa);
- for(; pa_no < totparts+totchild; pa_no++) {
- /* Add UVs */
- BL::Mesh::tessface_uv_textures_iterator l;
- b_mesh->tessface_uv_textures.begin(l);
+template<>
+struct StrandsTraits<BL::Strands>
+{
+ typedef BL::StrandsCurve curve_t;
+ typedef BL::StrandsVertex vertex_t;
+
+ static float3 get_location(BL::Strands b_strands, int index)
+ {
+ float *co = (b_strands.has_motion_state())? b_strands.motion_state[index].location() : b_strands.vertices[index].location();
+ return make_float3(co[0], co[1], co[2]);
+ }
+ static float3 get_uv(BL::Strands /*b_strands*/, int /*index*/, int /*uv_num*/)
+ {
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+ static float3 get_vcol(BL::Strands /*b_strands*/, int /*index*/, int /*vcol_num*/)
+ {
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+};
- float3 uv = make_float3(0.0f, 0.0f, 0.0f);
- if(b_mesh->tessface_uv_textures.length())
- b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
- CData->curve_uv.push_back(uv);
+template<>
+struct StrandsTraits<BL::StrandsChildren>
+{
+ typedef BL::StrandsChildCurve curve_t;
+ typedef BL::StrandsChildVertex vertex_t;
+
+ static float3 get_location(BL::StrandsChildren b_strands, int index)
+ {
+ float *co = b_strands.vertices[index].location();
+ return make_float3(co[0], co[1], co[2]);
+ }
+ static float3 get_uv(BL::StrandsChildren b_strands, int index, int uv_num)
+ {
+ if (uv_num < b_strands.num_curve_uv_layers()) {
+ size_t offset = uv_num * b_strands.curves.length();
+ float *uv = b_strands.curve_uvs[offset + index].uv();
+ return make_float3(uv[0], uv[1], 0.0f);
+ }
+ else
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+ static float3 get_vcol(BL::StrandsChildren b_strands, int index, int vcol_num)
+ {
+ if (vcol_num < b_strands.num_curve_vcol_layers()) {
+ size_t offset = vcol_num * b_strands.curves.length();
+ float *vcol = b_strands.curve_vcols[offset + index].vcol();
+ return make_float3(vcol[0], vcol[1], vcol[2]);
+ }
+ else
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+};
- if(pa_no < totparts && b_pa != b_psys.particles.end())
- ++b_pa;
- }
+template <typename StrandsT>
+static bool ObtainCacheStrandsData(Mesh *mesh, BL::Scene /*b_scene*/, BL::Object /*b_parent*/, BL::DupliObject /*b_dupli_ob*/, BL::ParticleSystem b_psys, StrandsT b_strands, const Transform &/*itfm*/,
+ ParticleCurveData *CData, bool /*background*/)
+{
+ typedef StrandsTraits<StrandsT> traits;
+ typedef typename traits::curve_t CurveT;
+
+ BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+ PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
+
+ int mi = clamp(b_part.material()-1, 0, mesh->used_shaders.size()-1);
+ int shader = mesh->used_shaders[mi];
+
+ int totcurves = b_strands.curves.length();
+ int totvert = b_strands.vertices.length();
+
+ int keyno = CData->curvekey_co.size();
+ int curvenum = CData->curve_keynum.size();
+
+ CData->psys_firstcurve.push_back(curvenum);
+ CData->psys_curvenum.push_back(totcurves);
+ CData->psys_shader.push_back(shader);
+
+ float radius = get_float(cpsys, "radius_scale") * 0.5f;
+
+ CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
+ CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
+ CData->psys_shape.push_back(get_float(cpsys, "shape"));
+ CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
+
+ CData->curve_firstkey.reserve(CData->curve_firstkey.size() + totcurves);
+ CData->curve_keynum.reserve(CData->curve_keynum.size() + totcurves);
+ CData->curve_length.reserve(CData->curve_length.size() + totcurves);
+ CData->curvekey_co.reserve(CData->curvekey_co.size() + totvert);
+ CData->curvekey_time.reserve(CData->curvekey_time.size() + totvert);
+
+ int icurve = 0;
+ int ivert = 0;
+ for(; icurve < totcurves; ++icurve) {
+ CurveT b_curve = b_strands.curves[icurve];
+ int numverts = b_curve.size();
+ int showverts = b_curve.render_size();
+ int usedverts = 0;
+ CData->curve_firstkey.push_back(keyno);
+
+ float curve_length = 0.0f;
+ float3 pcKey;
+ for(int cvert = 0; cvert < showverts; ++cvert) {
+ float3 cKey = traits::get_location(b_strands, ivert + cvert);
+
+ if(cvert > 0) {
+ float step_length = len(cKey - pcKey);
+ if(step_length == 0.0f)
+ continue;
+ curve_length += step_length;
}
+ CData->curvekey_co.push_back(cKey);
+ CData->curvekey_time.push_back(curve_length);
+ pcKey = cKey;
+ usedverts++;
}
- }
+ keyno += usedverts;
+ ivert += numverts;
+ CData->curve_keynum.push_back(usedverts);
+ CData->curve_length.push_back(curve_length);
+ curvenum++;
+ }
+
return true;
}
-bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num)
+template <typename StrandsT>
+static bool ObtainCacheStrandsUV(Mesh * /*mesh*/, BL::Scene /*b_scene*/, BL::Object /*b_parent*/, BL::DupliObject /*b_dupli_ob*/, BL::ParticleSystem /*b_psys*/, StrandsT b_strands,
+ ParticleCurveData *CData, bool /*background*/, int uv_num)
{
- if(!(mesh && b_mesh && b_ob && CData))
- return false;
-
- CData->curve_vcol.clear();
-
- BL::Object::modifiers_iterator b_mod;
- for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
- if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
- BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
- BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
-
- if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
- int totparts = b_psys.particles.length();
- int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
- int totcurves = totchild;
-
- if (b_part.child_type() == 0)
- totcurves += totparts;
-
- if (totcurves == 0)
- continue;
-
- int pa_no = 0;
- if(!(b_part.child_type() == 0))
- pa_no = totparts;
-
- int num_add = (totparts+totchild - pa_no);
- CData->curve_vcol.reserve(CData->curve_vcol.size() + num_add);
+ typedef StrandsTraits<StrandsT> traits;
+
+// BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
- BL::ParticleSystem::particles_iterator b_pa;
- b_psys.particles.begin(b_pa);
- for(; pa_no < totparts+totchild; pa_no++) {
- /* Add vertex colors */
- BL::Mesh::tessface_vertex_colors_iterator l;
- b_mesh->tessface_vertex_colors.begin(l);
+ int totcurves = b_strands.curves.length();
- float3 vcol = make_float3(0.0f, 0.0f, 0.0f);
- if(b_mesh->tessface_vertex_colors.length())
- b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
- CData->curve_vcol.push_back(vcol);
+ CData->curve_uv.reserve(CData->curve_uv.size() + totcurves);
- if(pa_no < totparts && b_pa != b_psys.particles.end())
- ++b_pa;
- }
- }
- }
+ int icurve = 0;
+ for(; icurve < totcurves; ++icurve) {
+ CData->curve_uv.push_back(traits::get_uv(b_strands, icurve, uv_num));
}
+
+ return true;
+}
+template <typename StrandsT>
+static bool ObtainCacheStrandsVcol(Mesh * /*mesh*/, BL::Scene /*b_scene*/, BL::Object /*b_parent*/, BL::DupliObject /*b_dupli_ob*/, BL::ParticleSystem /*b_psys*/, StrandsT b_strands,
+ ParticleCurveData *CData, bool /*background*/, int vcol_num)
+{
+ typedef StrandsTraits<StrandsT> traits;
+
+// BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+
+ int totcurves = b_strands.curves.length();
+
+ CData->curve_vcol.reserve(CData->curve_vcol.size() + totcurves);
+
+ int icurve = 0;
+ for(; icurve < totcurves; ++icurve) {
+ CData->curve_vcol.push_back(traits::get_vcol(b_strands, icurve, vcol_num));
+ }
+
return true;
}
-static void set_resolution(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, BL::Scene *scene, bool render)
+static void set_resolution(BL::Object *b_ob, BL::Scene *scene, bool render)
{
BL::Object::modifiers_iterator b_mod;
for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
- if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && ((b_mod->show_viewport()) || (b_mod->show_render()))) {
+ if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && ((b_mod->show_viewport()) || (b_mod->show_render()))) {
BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
b_psys.set_resolution(*scene, *b_ob, (render)? 2: 1);
@@ -513,7 +636,7 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resol
ybasis = normalize(cross(xbasis, v2));
- for (; subv <= 1; subv++) {
+ for(; subv <= 1; subv++) {
float3 ickey_loc = make_float3(0.0f,0.0f,0.0f);
float time = 0.0f;
@@ -581,7 +704,7 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
}
}
- if (num_curves > 0) {
+ if(num_curves > 0) {
VLOG(1) << "Exporting curve segments for mesh " << mesh->name;
}
@@ -621,7 +744,7 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
}
/* check allocation */
- if((mesh->curve_keys.size() != num_keys) || (mesh->curves.size() != num_curves)) {
+ if((mesh->curve_keys.size() != num_keys) || (mesh->curves.size() != num_curves)) {
VLOG(1) << "Allocation failed, clearing data";
mesh->curve_keys.clear();
mesh->curves.clear();
@@ -629,7 +752,7 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
}
}
-static void ExportCurveSegmentsMotion(Scene *scene, Mesh *mesh, ParticleCurveData *CData, int time_index)
+static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int time_index)
{
VLOG(1) << "Exporting curve motion segments for mesh " << mesh->name
<< ", time index " << time_index;
@@ -705,7 +828,7 @@ static void ExportCurveSegmentsMotion(Scene *scene, Mesh *mesh, ParticleCurveDat
}
}
-void ExportCurveTriangleUV(Mesh *mesh, ParticleCurveData *CData, int vert_offset, int resol, float3 *uvdata)
+void ExportCurveTriangleUV(ParticleCurveData *CData, int vert_offset, int resol, float3 *uvdata)
{
if(uvdata == NULL)
return;
@@ -750,7 +873,40 @@ void ExportCurveTriangleUV(Mesh *mesh, ParticleCurveData *CData, int vert_offset
}
}
-void ExportCurveTriangleVcol(Mesh *mesh, ParticleCurveData *CData, int vert_offset, int resol, uchar4 *cdata)
+void ExportCurveUV(Mesh *mesh, ParticleCurveData *CData, ustring name, bool active_render, int primitive, int vert_offset, int resol)
+{
+ AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
+ Attribute *attr_uv;
+
+ if(primitive == CURVE_TRIANGLES) {
+ if(active_render)
+ attr_uv = mesh->attributes.add(std, name);
+ else
+ attr_uv = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
+
+ float3 *uv = attr_uv->data_float3();
+
+ ExportCurveTriangleUV(CData, vert_offset, resol, uv);
+ }
+ else {
+ if(active_render)
+ attr_uv = mesh->curve_attributes.add(std, name);
+ else
+ attr_uv = mesh->curve_attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE);
+
+ float3 *uv = attr_uv->data_float3();
+
+ if(uv) {
+ size_t i = 0;
+
+ for(size_t curve = 0; curve < CData->curve_uv.size(); curve++)
+ if(!(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f))
+ uv[i++] = CData->curve_uv[curve];
+ }
+ }
+}
+
+void ExportCurveTriangleVcol(ParticleCurveData *CData, int vert_offset, int resol, uchar4 *cdata)
{
if(cdata == NULL)
return;
@@ -782,6 +938,31 @@ void ExportCurveTriangleVcol(Mesh *mesh, ParticleCurveData *CData, int vert_offs
}
}
+void ExportCurveVcol(Mesh *mesh, ParticleCurveData *CData, ustring name, int primitive, int vert_offset, int resol)
+{
+ if(primitive == CURVE_TRIANGLES) {
+ Attribute *attr_vcol = mesh->attributes.add(name, TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
+
+ uchar4 *cdata = attr_vcol->data_uchar4();
+
+ ExportCurveTriangleVcol(CData, vert_offset, resol, cdata);
+ }
+ else {
+ Attribute *attr_vcol = mesh->curve_attributes.add(name, TypeDesc::TypeColor, ATTR_ELEMENT_CURVE);
+
+ float3 *fdata = attr_vcol->data_float3();
+
+ if(fdata) {
+ size_t i = 0;
+
+ for(size_t curve = 0; curve < CData->curve_vcol.size(); curve++)
+ if(!(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f))
+ fdata[i++] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
+ }
+ }
+}
+
+
/* Hair Curve Sync */
void BlenderSync::sync_curve_settings()
@@ -856,8 +1037,61 @@ void BlenderSync::sync_curve_settings()
curve_system_manager->tag_update(scene);
}
-void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool motion, int time_index)
+struct CurvesPSysData {
+ CurvesPSysData(BL::ParticleSystemModifier b_psmd=PointerRNA_NULL, BL::ParticleSystem b_psys=PointerRNA_NULL,
+ BL::Strands b_strands=PointerRNA_NULL, BL::StrandsChildren b_strands_children=PointerRNA_NULL) :
+ b_psmd(b_psmd), b_psys(b_psys), b_strands(b_strands), b_strands_children(b_strands_children)
+ {}
+
+ BL::ParticleSystemModifier b_psmd;
+ BL::ParticleSystem b_psys;
+ BL::Strands b_strands;
+ BL::StrandsChildren b_strands_children;
+};
+
+static void curves_get_psys_data(std::vector<CurvesPSysData> &b_psys_list, BL::Scene b_scene, BL::Object b_ob, BL::Object b_parent, BL::DupliObject b_dupli_ob, bool preview)
+{
+ BL::Object::modifiers_iterator b_mod;
+ for(b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
+ if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (preview ? b_mod->show_viewport() : b_mod->show_render())) {
+ BL::ParticleSystemModifier b_psmd((const PointerRNA)b_mod->ptr);
+ BL::ParticleSystem b_psys((const PointerRNA)b_psmd.particle_system().ptr);
+ BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
+
+ if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
+ int settings = preview ? 1 : 2;
+
+ BL::StrandsChildren b_strands_children = PointerRNA_NULL;
+ BL::Strands b_strands = PointerRNA_NULL;
+
+ if (b_dupli_ob && b_parent) {
+ b_strands_children = b_dupli_ob.strands_children_new(b_scene, b_parent, b_psys, settings);
+ if (!b_strands_children)
+ b_strands = b_dupli_ob.strands_new(b_scene, b_parent, b_psys, settings);
+ }
+
+ b_psys_list.push_back(CurvesPSysData(b_psmd, b_psys, b_strands, b_strands_children));
+ }
+ }
+ }
+}
+
+static void curves_free_psys_data(std::vector<CurvesPSysData> &b_psys_list, BL::DupliObject b_dupli_ob)
+{
+ /* free temporary strands data */
+ for (int i = 0; i < b_psys_list.size(); ++i) {
+ CurvesPSysData &psys_data = b_psys_list[i];
+ if (psys_data.b_strands)
+ b_dupli_ob.strands_free(psys_data.b_strands);
+ if (psys_data.b_strands_children)
+ b_dupli_ob.strands_children_free(psys_data.b_strands_children);
+ }
+}
+
+void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_parent, bool motion, int time_index, BL::DupliObject b_dupli_ob)
{
+ BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
+
if(!motion) {
/* Clear stored curve data */
mesh->curve_keys.clear();
@@ -886,29 +1120,48 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool
ParticleCurveData CData;
if(!preview)
- set_resolution(mesh, &b_mesh, &b_ob, &b_scene, true);
+ set_resolution(&b_ob, &b_scene, true);
- ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, !preview);
+ Transform tfm = get_transform(b_ob.matrix_world());
+ Transform itfm = transform_quick_inverse(tfm);
+
+ /* obtain camera parameters */
+ float3 RotCam;
+ Camera *camera = scene->camera;
+ if(camera->type == CAMERA_ORTHOGRAPHIC) {
+ Transform &ctfm = camera->matrix;
+ RotCam = -make_float3(ctfm.x.z, ctfm.y.z, ctfm.z.z);
+ }
+ else {
+ Transform &ctfm = camera->matrix;
+ RotCam = transform_point(&itfm, make_float3(ctfm.x.w, ctfm.y.w, ctfm.z.w));
+ }
+ bool is_ortho_camera = camera->type == CAMERA_ORTHOGRAPHIC;
+
+ std::vector<CurvesPSysData> b_psys_list;
+ curves_get_psys_data(b_psys_list, b_scene, b_ob, b_parent, b_dupli_ob, preview);
+
+ for (int i = 0; i < b_psys_list.size(); ++i) {
+ CurvesPSysData &psys_data = b_psys_list[i];
+ if (psys_data.b_strands_children)
+ /* use child strands cache */
+ ObtainCacheStrandsData(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands_children,
+ itfm, &CData, !preview);
+ else if (psys_data.b_strands)
+ /* use parent strands cache */
+ ObtainCacheStrandsData(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands,
+ itfm, &CData, !preview);
+ else {
+ /* use object data */
+ ObtainCacheParticleData(mesh, b_ob, psys_data.b_psys,
+ itfm, &CData, !preview);
+ }
+ }
/* add hair geometry to mesh */
if(primitive == CURVE_TRIANGLES) {
if(triangle_method == CURVE_CAMERA_TRIANGLES) {
- /* obtain camera parameters */
- float3 RotCam;
- Camera *camera = scene->camera;
- Transform &ctfm = camera->matrix;
- if(camera->type == CAMERA_ORTHOGRAPHIC) {
- RotCam = -make_float3(ctfm.x.z, ctfm.y.z, ctfm.z.z);
- }
- else {
- Transform tfm = get_transform(b_ob.matrix_world());
- Transform itfm = transform_quick_inverse(tfm);
- RotCam = transform_point(&itfm, make_float3(ctfm.x.w,
- ctfm.y.w,
- ctfm.z.w));
- }
- bool is_ortho = camera->type == CAMERA_ORTHOGRAPHIC;
- ExportCurveTrianglePlanes(mesh, &CData, RotCam, is_ortho);
+ ExportCurveTrianglePlanes(mesh, &CData, RotCam, is_ortho_camera);
}
else {
ExportCurveTriangleGeometry(mesh, &CData, resolution);
@@ -917,7 +1170,7 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool
}
else {
if(motion)
- ExportCurveSegmentsMotion(scene, mesh, &CData, time_index);
+ ExportCurveSegmentsMotion(mesh, &CData, time_index);
else
ExportCurveSegments(scene, mesh, &CData);
}
@@ -955,33 +1208,31 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool
int vcol_num = 0;
for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l, vcol_num++) {
+ ustring name = ustring(l->name().c_str());
+
if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
continue;
- ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, !preview, vcol_num);
-
- if(primitive == CURVE_TRIANGLES) {
- Attribute *attr_vcol = mesh->attributes.add(
- ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
-
- uchar4 *cdata = attr_vcol->data_uchar4();
-
- ExportCurveTriangleVcol(mesh, &CData, tri_num * 3, used_res, cdata);
- }
- else {
- Attribute *attr_vcol = mesh->curve_attributes.add(
- ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE);
-
- float3 *fdata = attr_vcol->data_float3();
-
- if(fdata) {
- size_t i = 0;
-
- for(size_t curve = 0; curve < CData.curve_vcol.size(); curve++)
- if(!(CData.curve_keynum[curve] <= 1 || CData.curve_length[curve] == 0.0f))
- fdata[i++] = color_srgb_to_scene_linear(CData.curve_vcol[curve]);
+ CData.curve_vcol.clear();
+
+ for (int i = 0; i < b_psys_list.size(); ++i) {
+ CurvesPSysData &psys_data = b_psys_list[i];
+ if (psys_data.b_strands_children)
+ /* use child strands cache */
+ ObtainCacheStrandsVcol(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands_children,
+ &CData, !preview, vcol_num);
+ else if (psys_data.b_strands)
+ /* use parent strands cache */
+ ObtainCacheStrandsVcol(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands,
+ &CData, !preview, vcol_num);
+ else {
+ /* use object data */
+ ObtainCacheParticleVcol(mesh, b_ob, b_mesh, psys_data.b_psys, psys_data.b_psmd,
+ &CData, !preview, vcol_num);
}
}
+
+ ExportCurveVcol(mesh, &CData, name, primitive, tri_num * 3, used_res);
}
}
@@ -992,47 +1243,39 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool
for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l, uv_num++) {
bool active_render = l->active_render();
- AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
ustring name = ustring(l->name().c_str());
/* UV map */
- if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
- Attribute *attr_uv;
-
- ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, !preview, uv_num);
-
- if(primitive == CURVE_TRIANGLES) {
- if(active_render)
- attr_uv = mesh->attributes.add(std, name);
- else
- attr_uv = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
-
- float3 *uv = attr_uv->data_float3();
-
- ExportCurveTriangleUV(mesh, &CData, tri_num * 3, used_res, uv);
- }
+ if(!(mesh->need_attribute(scene, name) || (active_render && mesh->need_attribute(scene, ATTR_STD_UV))))
+ continue;
+
+ CData.curve_uv.clear();
+
+ for (int i = 0; i < b_psys_list.size(); ++i) {
+ CurvesPSysData &psys_data = b_psys_list[i];
+ if (psys_data.b_strands_children)
+ /* use child strands cache */
+ ObtainCacheStrandsUV(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands_children,
+ &CData, !preview, uv_num);
+ else if (psys_data.b_strands)
+ /* use parent strands cache */
+ ObtainCacheStrandsUV(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands,
+ &CData, !preview, uv_num);
else {
- if(active_render)
- attr_uv = mesh->curve_attributes.add(std, name);
- else
- attr_uv = mesh->curve_attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE);
-
- float3 *uv = attr_uv->data_float3();
-
- if(uv) {
- size_t i = 0;
-
- for(size_t curve = 0; curve < CData.curve_uv.size(); curve++)
- if(!(CData.curve_keynum[curve] <= 1 || CData.curve_length[curve] == 0.0f))
- uv[i++] = CData.curve_uv[curve];
- }
+ /* use object data */
+ ObtainCacheParticleUV(mesh, b_ob, b_mesh, psys_data.b_psys, psys_data.b_psmd,
+ &CData, !preview, uv_num);
}
}
+
+ ExportCurveUV(mesh, &CData, name, active_render, primitive, tri_num * 3, used_res);
}
}
+ curves_free_psys_data(b_psys_list, b_dupli_ob);
+
if(!preview)
- set_resolution(mesh, &b_mesh, &b_ob, &b_scene, false);
+ set_resolution(&b_ob, &b_scene, false);
mesh->compute_bounds();
}
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index e9a70db96c4..3fa80a89947 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -229,7 +229,13 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer *b_l
/* Create Volume Attribute */
-static void create_mesh_volume_attribute(BL::Object b_ob, Mesh *mesh, ImageManager *image_manager, AttributeStandard std, float frame)
+static void create_mesh_volume_attribute(BL::Object b_ob,
+ Mesh *mesh,
+ ImageManager *image_manager,
+ AttributeStandard std,
+ float frame,
+ AttributeStandard special_std = ATTR_STD_NONE,
+ bool from_alpha = false)
{
BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
@@ -240,17 +246,35 @@ static void create_mesh_volume_attribute(BL::Object b_ob, Mesh *mesh, ImageManag
VoxelAttribute *volume_data = attr->data_voxel();
bool is_float, is_linear;
bool animated = false;
+ AttributeStandard data_attr = (special_std == ATTR_STD_NONE) ? std : special_std;
volume_data->manager = image_manager;
- volume_data->slot = image_manager->add_image(Attribute::standard_name(std),
+ volume_data->slot = image_manager->add_image(Attribute::standard_name(data_attr),
b_ob.ptr.data, animated, frame, is_float, is_linear, INTERPOLATION_LINEAR, true);
+ volume_data->from_alpha = from_alpha;
}
static void create_mesh_volume_attributes(Scene *scene, BL::Object b_ob, Mesh *mesh, float frame)
{
/* for smoke volume rendering */
- if(mesh->need_attribute(scene, ATTR_STD_VOLUME_DENSITY))
- create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_DENSITY, frame);
+ if(mesh->need_attribute(scene, ATTR_STD_VOLUME_DENSITY)) {
+ /* Special case: we re-map density to A channel of Color texture
+ * if both attributes are requested.
+ */
+ AttributeStandard special_std = ATTR_STD_VOLUME_DENSITY;
+ bool from_alpha = false;
+ if(mesh->need_attribute(scene, ATTR_STD_VOLUME_COLOR)) {
+ special_std = ATTR_STD_VOLUME_COLOR;
+ from_alpha = true;
+ }
+ create_mesh_volume_attribute(b_ob,
+ mesh,
+ scene->image_manager,
+ ATTR_STD_VOLUME_DENSITY,
+ frame,
+ special_std,
+ from_alpha);
+ }
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_COLOR))
create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_COLOR, frame);
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_FLAME))
@@ -302,7 +326,7 @@ static void attr_create_uv_map(Scene *scene,
BL::Mesh b_mesh,
const vector<int>& nverts)
{
- if (b_mesh.tessface_uv_textures.length() != 0) {
+ if(b_mesh.tessface_uv_textures.length() != 0) {
BL::Mesh::tessface_uv_textures_iterator l;
for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) {
@@ -324,15 +348,15 @@ static void attr_create_uv_map(Scene *scene,
size_t i = 0;
for(l->data.begin(t); t != l->data.end(); ++t, ++i) {
- fdata[0] = get_float3(t->uv1());
- fdata[1] = get_float3(t->uv2());
- fdata[2] = get_float3(t->uv3());
+ fdata[0] = get_float3(t->uv1());
+ fdata[1] = get_float3(t->uv2());
+ fdata[2] = get_float3(t->uv3());
fdata += 3;
if(nverts[i] == 4) {
- fdata[0] = get_float3(t->uv1());
- fdata[1] = get_float3(t->uv3());
- fdata[2] = get_float3(t->uv4());
+ fdata[0] = get_float3(t->uv1());
+ fdata[1] = get_float3(t->uv3());
+ fdata[2] = get_float3(t->uv4());
fdata += 3;
}
}
@@ -634,8 +658,10 @@ static void create_subd_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, PointerR
/* Sync */
-Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris)
+Mesh *BlenderSync::sync_mesh(BL::Object b_parent, bool object_updated, bool hide_tris, BL::DupliObject b_dupli_ob)
{
+ BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
+
/* When viewport display is not needed during render we can force some
* caches to be releases from blender side in order to reduce peak memory
* footprint during synchronization process.
@@ -646,7 +672,6 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
/* test if we can instance or if the object is modified */
BL::ID b_ob_data = b_ob.data();
- BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data;
BL::Material material_override = render_layer.material_override;
/* find shader indices */
@@ -668,16 +693,39 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
}
/* test if we need to sync */
- bool use_mesh_geometry = render_layer.use_surfaces || render_layer.use_hair;
+ int requested_geometry_flags = Mesh::GEOMETRY_NONE;
+ if(render_layer.use_surfaces) {
+ requested_geometry_flags |= Mesh::GEOMETRY_TRIANGLES;
+ }
+ if(render_layer.use_hair) {
+ requested_geometry_flags |= Mesh::GEOMETRY_CURVES;
+ }
Mesh *mesh;
- if(!mesh_map.sync(&mesh, key)) {
+ bool need_update;
+ BL::CacheLibrary b_cachelib = b_parent.cache_library();
+ bool use_dupli_override = b_dupli_ob && b_cachelib &&
+ (b_cachelib.source_mode() == BL::CacheLibrary::source_mode_CACHE ||
+ b_cachelib.display_mode() == BL::CacheLibrary::display_mode_RESULT);
+ if (use_dupli_override) {
+ /* if a dupli override (cached data) is used, identify the mesh by object and parent together,
+ * so that individual per-dupli overrides are possible.
+ */
+ MeshKey key = MeshKey(b_parent, b_ob);
+ need_update = mesh_map.sync(&mesh, b_ob, b_parent, key);
+ }
+ else {
+ BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data;
+ need_update = mesh_map.sync(&mesh, key);
+ }
+
+ if(!need_update) {
/* if transform was applied to mesh, need full update */
if(object_updated && mesh->transform_applied);
/* test if shaders changed, these can be object level so mesh
* does not get tagged for recalc */
else if(mesh->used_shaders != used_shaders);
- else if(use_mesh_geometry != mesh->geometry_synced);
+ else if(requested_geometry_flags != mesh->geometry_flags);
else {
/* even if not tagged for recalc, we may need to sync anyway
* because the shader needs different mesh attributes */
@@ -711,7 +759,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
mesh->used_shaders = used_shaders;
mesh->name = ustring(b_ob_data.name().c_str());
- if(use_mesh_geometry) {
+ if(requested_geometry_flags != Mesh::GEOMETRY_NONE) {
/* mesh objects does have special handle in the dependency graph,
* they're ensured to have properly updated.
*
@@ -722,7 +770,9 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
b_ob.update_from_editmode();
bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);
- BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed);
+ BL::Mesh b_mesh = (use_dupli_override)?
+ dupli_to_mesh(b_data, b_scene, b_parent, b_dupli_ob, !preview, need_undeformed):
+ object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed);
if(b_mesh) {
if(render_layer.use_surfaces && !hide_tris) {
@@ -735,17 +785,17 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
}
if(render_layer.use_hair)
- sync_curves(mesh, b_mesh, b_ob, false);
+ sync_curves(mesh, b_mesh, b_parent, false, 0, b_dupli_ob);
if(can_free_caches) {
- b_ob.cache_release();
+ b_ob.cache_release(false);
}
/* free derived mesh */
b_data.meshes.remove(b_mesh);
}
- mesh->geometry_synced = true;
}
+ mesh->geometry_flags = requested_geometry_flags;
/* displacement method */
if(cmesh.data) {
@@ -781,8 +831,9 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
return mesh;
}
-void BlenderSync::sync_mesh_motion(BL::Object b_ob, Object *object, float motion_time)
+void BlenderSync::sync_mesh_motion(BL::Object b_parent, Object *object, float motion_time, BL::DupliObject b_dupli_ob)
{
+ BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
/* ensure we only sync instanced meshes once */
Mesh *mesh = object->mesh;
@@ -841,7 +892,9 @@ void BlenderSync::sync_mesh_motion(BL::Object b_ob, Object *object, float motion
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);
+ b_mesh = (b_dupli_ob && b_parent)?
+ dupli_to_mesh(b_data, b_scene, b_parent, b_dupli_ob, !preview, false):
+ object_to_mesh(b_data, b_ob, b_scene, true, !preview, false);
}
if(!b_mesh) {
@@ -931,7 +984,7 @@ void BlenderSync::sync_mesh_motion(BL::Object b_ob, Object *object, float motion
/* hair motion */
if(numkeys)
- sync_curves(mesh, b_mesh, b_ob, true, time_index);
+ sync_curves(mesh, b_mesh, b_parent, true, time_index, b_dupli_ob);
/* free derived mesh */
b_data.meshes.remove(b_mesh);
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index e827d46223b..b38fc93e47a 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -90,14 +90,17 @@ static uint object_ray_visibility(BL::Object b_ob)
/* Light */
-void BlenderSync::sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object b_ob, Transform& tfm)
+void BlenderSync::sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object b_ob, Transform& tfm, bool *use_portal)
{
/* test if we need to sync */
Light *light;
ObjectKey key(b_parent, persistent_id, b_ob);
- if(!light_map.sync(&light, b_ob, b_parent, key))
+ if(!light_map.sync(&light, b_ob, b_parent, key)) {
+ if(light->is_portal)
+ *use_portal = true;
return;
+ }
BL::Lamp b_lamp(b_ob.data());
@@ -171,6 +174,14 @@ void BlenderSync::sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSI
light->max_bounces = get_int(clamp, "max_bounces");
+ if(light->type == LIGHT_AREA)
+ light->is_portal = get_boolean(clamp, "is_portal");
+ else
+ light->is_portal = false;
+
+ if(light->is_portal)
+ *use_portal = true;
+
/* visibility */
uint visibility = object_ray_visibility(b_ob);
light->use_diffuse = (visibility & PATH_RAY_DIFFUSE) != 0;
@@ -182,7 +193,7 @@ void BlenderSync::sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSI
light->tag_update(scene);
}
-void BlenderSync::sync_background_light()
+void BlenderSync::sync_background_light(bool use_portal)
{
BL::World b_world = b_scene.world();
@@ -191,19 +202,20 @@ void BlenderSync::sync_background_light()
PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
bool sample_as_light = get_boolean(cworld, "sample_as_light");
- if(sample_as_light) {
+ if(sample_as_light || use_portal) {
/* test if we need to sync */
Light *light;
ObjectKey key(b_world, 0, b_world);
if(light_map.sync(&light, b_world, b_world, key) ||
- world_recalc ||
- b_world.ptr.data != world_map)
+ world_recalc ||
+ b_world.ptr.data != world_map)
{
light->type = LIGHT_BACKGROUND;
light->map_resolution = get_int(cworld, "sample_map_resolution");
light->shader = scene->default_background;
-
+ light->use_mis = sample_as_light;
+
int samples = get_int(cworld, "samples");
if(get_boolean(cscene, "use_square_samples"))
light->samples = samples * samples;
@@ -222,8 +234,53 @@ void BlenderSync::sync_background_light()
/* Object */
-Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob,
- Transform& tfm, uint layer_flag, float motion_time, bool hide_tris)
+static bool object_boundbox_clip(Scene *scene,
+ BL::Object b_ob,
+ Transform& tfm,
+ float margin)
+{
+ Camera *cam = scene->camera;
+ Transform& worldtondc = cam->worldtondc;
+ BL::Array<float, 24> boundbox = b_ob.bound_box();
+ float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
+ bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+ bool all_behind = true;
+ for(int i = 0; i < 8; ++i) {
+ float3 p = make_float3(boundbox[3 * i + 0],
+ boundbox[3 * i + 1],
+ boundbox[3 * i + 2]);
+ p = transform_point(&tfm, p);
+ p = transform_point(&worldtondc, p);
+ if(p.z >= -margin) {
+ all_behind = false;
+ }
+ p /= p.z;
+ bb_min = min(bb_min, p);
+ bb_max = max(bb_max, p);
+ }
+ if(!all_behind) {
+ if(bb_min.x >= 1.0f + margin ||
+ bb_min.y >= 1.0f + margin ||
+ bb_max.x <= -margin ||
+ bb_max.y <= -margin)
+ {
+ return true;
+ }
+ return false;
+ }
+ return true;
+}
+
+Object *BlenderSync::sync_object(BL::Object b_parent,
+ int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
+ BL::DupliObject b_dupli_ob,
+ Transform& tfm,
+ uint layer_flag,
+ float motion_time,
+ bool hide_tris,
+ bool use_camera_cull,
+ float camera_cull_margin,
+ bool *use_portal)
{
BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
bool motion = motion_time != 0.0f;
@@ -232,7 +289,7 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P
if(object_is_light(b_ob)) {
/* don't use lamps for excluded layers used as mask layer */
if(!motion && !((layer_flag & render_layer.holdout_layer) && (layer_flag & render_layer.exclude_layer)))
- sync_light(b_parent, persistent_id, b_ob, tfm);
+ sync_light(b_parent, persistent_id, b_ob, tfm, use_portal);
return NULL;
}
@@ -241,6 +298,11 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P
if(!object_is_mesh(b_ob))
return NULL;
+ /* Perform camera space culling. */
+ if(use_camera_cull && object_boundbox_clip(scene, b_ob, tfm, camera_cull_margin)) {
+ return NULL;
+ }
+
/* key to lookup object */
ObjectKey key(b_parent, persistent_id, b_ob);
Object *object;
@@ -265,7 +327,7 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P
/* mesh deformation */
if(object->mesh)
- sync_mesh_motion(b_ob, object, motion_time);
+ sync_mesh_motion(b_parent, object, motion_time, b_dupli_ob);
}
return object;
@@ -280,7 +342,10 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P
bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0;
/* mesh sync */
- object->mesh = sync_mesh(b_ob, object_updated, hide_tris);
+ if (b_dupli_ob)
+ object->mesh = sync_mesh(b_parent, object_updated, hide_tris, b_dupli_ob);
+ else
+ object->mesh = sync_mesh(b_ob, object_updated, hide_tris);
/* special case not tracked by object update flags */
@@ -356,7 +421,7 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P
object->random_id ^= hash_int(hash_string(b_parent.name().c_str()));
/* dupli texture coordinates */
- if (b_dupli_ob) {
+ if(b_dupli_ob) {
object->dupli_generated = 0.5f*get_float3(b_dupli_ob.orco()) - make_float3(0.5f, 0.5f, 0.5f);
object->dupli_uv = get_float2(b_dupli_ob.uv());
}
@@ -466,6 +531,15 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
mesh_motion_synced.clear();
}
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+ bool allow_camera_cull = scene->camera->type != CAMERA_PANORAMA &&
+ !b_scene.render().use_multiview() &&
+ get_boolean(cscene, "use_camera_cull");
+ float camera_cull_margin = 0.0f;
+ if(allow_camera_cull) {
+ camera_cull_margin = get_float(cscene, "camera_cull_margin");
+ }
+
/* object loop */
BL::Scene::object_bases_iterator b_base;
BL::Scene b_sce = b_scene;
@@ -476,6 +550,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
int dupli_settings = preview ? 1 : 2;
bool cancel = false;
+ bool use_portal = false;
for(; b_sce && !cancel; b_sce = b_sce.background_set()) {
for(b_sce.object_bases.begin(b_base); b_base != b_sce.object_bases.end() && !cancel; ++b_base) {
@@ -487,6 +562,12 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
if(!hide) {
progress.set_sync_status("Synchronizing object", b_ob.name());
+ PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
+ bool use_camera_cull = allow_camera_cull && get_boolean(cobject, "use_camera_cull");
+ if(use_camera_cull) {
+ /* Need to have proper projection matrix. */
+ scene->camera->update();
+ }
if(b_ob.is_duplicator() && !object_render_hide_duplis(b_ob)) {
/* dupli objects */
b_ob.dupli_list_create(b_scene, dupli_settings);
@@ -506,7 +587,16 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup->persistent_id();
/* sync object and mesh or light data */
- Object *object = sync_object(b_ob, persistent_id.data, *b_dup, tfm, ob_layer, motion_time, hide_tris);
+ Object *object = sync_object(b_ob,
+ persistent_id.data,
+ *b_dup,
+ tfm,
+ ob_layer,
+ motion_time,
+ hide_tris,
+ use_camera_cull,
+ camera_cull_margin,
+ &use_portal);
/* sync possible particle data, note particle_id
* starts counting at 1, first is dummy particle */
@@ -526,7 +616,16 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
if(!object_render_hide(b_ob, true, true, hide_tris)) {
/* object itself */
Transform tfm = get_transform(b_ob.matrix_world());
- sync_object(b_ob, NULL, PointerRNA_NULL, tfm, ob_layer, motion_time, hide_tris);
+ sync_object(b_ob,
+ NULL,
+ PointerRNA_NULL,
+ tfm,
+ ob_layer,
+ motion_time,
+ hide_tris,
+ use_camera_cull,
+ camera_cull_margin,
+ &use_portal);
}
}
@@ -537,7 +636,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
progress.set_sync_status("");
if(!cancel && !motion) {
- sync_background_light();
+ sync_background_light(use_portal);
/* handle removed data and modified pointers */
if(light_map.post_sync())
diff --git a/intern/cycles/blender/blender_particles.cpp b/intern/cycles/blender/blender_particles.cpp
index 2785cfa9634..6d799e6e10e 100644
--- a/intern/cycles/blender/blender_particles.cpp
+++ b/intern/cycles/blender/blender_particles.cpp
@@ -76,7 +76,7 @@ bool BlenderSync::sync_dupli_particle(BL::Object b_ob, BL::DupliObject b_dup, Ob
psys->particles.push_back(pa);
- if (object->particle_index != psys->particles.size() - 1)
+ if(object->particle_index != psys->particles.size() - 1)
scene->object_manager->tag_update(scene);
object->particle_system = psys;
object->particle_index = psys->particles.size() - 1;
diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp
index 292af14c63a..200003fbf70 100644
--- a/intern/cycles/blender/blender_python.cpp
+++ b/intern/cycles/blender/blender_python.cpp
@@ -25,6 +25,7 @@
#include "util_md5.h"
#include "util_opengl.h"
#include "util_path.h"
+#include "util_types.h"
#ifdef WITH_OSL
#include "osl.h"
@@ -70,7 +71,7 @@ static const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
return "";
}
-static PyObject *init_func(PyObject *self, PyObject *args)
+static PyObject *init_func(PyObject * /*self*/, PyObject *args)
{
PyObject *path, *user_path;
int headless;
@@ -90,7 +91,7 @@ static PyObject *init_func(PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
-static PyObject *create_func(PyObject *self, PyObject *args)
+static PyObject *create_func(PyObject * /*self*/, PyObject *args)
{
PyObject *pyengine, *pyuserpref, *pydata, *pyscene, *pyregion, *pyv3d, *pyrv3d;
int preview_osl;
@@ -162,14 +163,14 @@ static PyObject *create_func(PyObject *self, PyObject *args)
return PyLong_FromVoidPtr(session);
}
-static PyObject *free_func(PyObject *self, PyObject *value)
+static PyObject *free_func(PyObject * /*self*/, PyObject *value)
{
delete (BlenderSession*)PyLong_AsVoidPtr(value);
Py_RETURN_NONE;
}
-static PyObject *render_func(PyObject *self, PyObject *value)
+static PyObject *render_func(PyObject * /*self*/, PyObject *value)
{
BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(value);
@@ -183,14 +184,14 @@ static PyObject *render_func(PyObject *self, PyObject *value)
}
/* pixel_array and result passed as pointers */
-static PyObject *bake_func(PyObject *self, PyObject *args)
+static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
{
PyObject *pysession, *pyobject;
PyObject *pypixel_array, *pyresult;
const char *pass_type;
- int num_pixels, depth;
+ int num_pixels, depth, object_id;
- if(!PyArg_ParseTuple(args, "OOsOiiO", &pysession, &pyobject, &pass_type, &pypixel_array, &num_pixels, &depth, &pyresult))
+ if(!PyArg_ParseTuple(args, "OOsiOiiO", &pysession, &pyobject, &pass_type, &object_id, &pypixel_array, &num_pixels, &depth, &pyresult))
return NULL;
BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
@@ -207,14 +208,14 @@ static PyObject *bake_func(PyObject *self, PyObject *args)
python_thread_state_save(&session->python_thread_state);
- session->bake(b_object, pass_type, b_bake_pixel, (size_t)num_pixels, depth, (float *)b_result);
+ session->bake(b_object, pass_type, object_id, b_bake_pixel, (size_t)num_pixels, depth, (float *)b_result);
python_thread_state_restore(&session->python_thread_state);
Py_RETURN_NONE;
}
-static PyObject *draw_func(PyObject *self, PyObject *args)
+static PyObject *draw_func(PyObject * /*self*/, PyObject *args)
{
PyObject *pysession, *pyv3d, *pyrv3d;
@@ -234,7 +235,7 @@ static PyObject *draw_func(PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
-static PyObject *reset_func(PyObject *self, PyObject *args)
+static PyObject *reset_func(PyObject * /*self*/, PyObject *args)
{
PyObject *pysession, *pydata, *pyscene;
@@ -260,7 +261,7 @@ static PyObject *reset_func(PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
-static PyObject *sync_func(PyObject *self, PyObject *value)
+static PyObject *sync_func(PyObject * /*self*/, PyObject *value)
{
BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(value);
@@ -273,7 +274,7 @@ static PyObject *sync_func(PyObject *self, PyObject *value)
Py_RETURN_NONE;
}
-static PyObject *available_devices_func(PyObject *self, PyObject *args)
+static PyObject *available_devices_func(PyObject * /*self*/, PyObject * /*args*/)
{
vector<DeviceInfo>& devices = Device::available_devices();
PyObject *ret = PyTuple_New(devices.size());
@@ -288,7 +289,7 @@ static PyObject *available_devices_func(PyObject *self, PyObject *args)
#ifdef WITH_OSL
-static PyObject *osl_update_node_func(PyObject *self, PyObject *args)
+static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
{
PyObject *pynodegroup, *pynode;
const char *filepath = NULL;
@@ -390,7 +391,7 @@ static PyObject *osl_update_node_func(PyObject *self, PyObject *args)
/* find socket socket */
BL::NodeSocket b_sock(PointerRNA_NULL);
- if (param->isoutput) {
+ if(param->isoutput) {
b_sock = b_node.outputs[param->name.string()];
/* remove if type no longer matches */
if(b_sock && b_sock.bl_idname() != socket_type) {
@@ -444,7 +445,7 @@ static PyObject *osl_update_node_func(PyObject *self, PyObject *args)
removed = false;
- for (b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
+ for(b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
if(used_sockets.find(b_input->ptr.data) == used_sockets.end()) {
b_node.inputs.remove(*b_input);
removed = true;
@@ -452,7 +453,7 @@ static PyObject *osl_update_node_func(PyObject *self, PyObject *args)
}
}
- for (b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
+ for(b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
if(used_sockets.find(b_output->ptr.data) == used_sockets.end()) {
b_node.outputs.remove(*b_output);
removed = true;
@@ -464,7 +465,7 @@ static PyObject *osl_update_node_func(PyObject *self, PyObject *args)
Py_RETURN_TRUE;
}
-static PyObject *osl_compile_func(PyObject *self, PyObject *args)
+static PyObject *osl_compile_func(PyObject * /*self*/, PyObject *args)
{
const char *inputfile = NULL, *outputfile = NULL;
@@ -479,7 +480,7 @@ static PyObject *osl_compile_func(PyObject *self, PyObject *args)
}
#endif
-static PyObject *system_info_func(PyObject *self, PyObject *value)
+static PyObject *system_info_func(PyObject * /*self*/, PyObject * /*value*/)
{
string system_info = Device::device_capabilities();
return PyUnicode_FromString(system_info.c_str());
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index e61203d807a..e928a601dea 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -100,7 +100,8 @@ void BlenderSession::create_session()
start_resize_time = 0.0;
/* create scene */
- scene = new Scene(scene_params, session_params.device);
+ bool free_data_after_update = background && !scene_params.persistent_data;
+ scene = new Scene(scene_params, session_params.device, free_data_after_update);
/* setup callbacks for builtin image support */
scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3, _4, _5, _6, _7);
@@ -133,7 +134,7 @@ void BlenderSession::create_session()
}
/* set buffer parameters */
- BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_scene, b_v3d, b_rv3d, scene->camera, width, height);
+ BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
session->reset(buffer_params, session_params.samples);
b_engine.use_highlight_tiles(session_params.progressive_refine == false);
@@ -186,7 +187,7 @@ void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_)
sync->sync_integrator();
sync->sync_camera(b_render, b_engine.camera_override(), width, height);
- BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_scene, PointerRNA_NULL, PointerRNA_NULL, scene->camera, width, height);
+ BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, PointerRNA_NULL, PointerRNA_NULL, scene->camera, width, height);
session->reset(buffer_params, session_params.samples);
b_engine.use_highlight_tiles(session_params.progressive_refine == false);
@@ -331,9 +332,9 @@ static ShaderEvalType get_shader_type(const string& pass_type)
return SHADER_EVAL_BAKE;
}
-static BL::RenderResult begin_render_result(BL::RenderEngine b_engine, int x, int y, int w, int h, const char *layername)
+static BL::RenderResult begin_render_result(BL::RenderEngine b_engine, int x, int y, int w, int h, const char *layername, const char *viewname)
{
- return b_engine.begin_result(x, y, w, h, layername);
+ return b_engine.begin_result(x, y, w, h, layername, viewname);
}
static void end_render_result(BL::RenderEngine b_engine, BL::RenderResult b_rr, bool cancel, bool do_merge_results)
@@ -350,10 +351,10 @@ void BlenderSession::do_write_update_render_tile(RenderTile& rtile, bool do_upda
int h = params.height;
/* get render result */
- BL::RenderResult b_rr = begin_render_result(b_engine, x, y, w, h, b_rlay_name.c_str());
+ BL::RenderResult b_rr = begin_render_result(b_engine, x, y, w, h, b_rlay_name.c_str(), b_rview_name.c_str());
/* can happen if the intersected rectangle gives 0 width or height */
- if (b_rr.ptr.data == NULL) {
+ if(b_rr.ptr.data == NULL) {
return;
}
@@ -366,10 +367,10 @@ void BlenderSession::do_write_update_render_tile(RenderTile& rtile, bool do_upda
BL::RenderLayer b_rlay = *b_single_rlay;
- if (do_update_only) {
+ if(do_update_only) {
/* update only needed */
- if (rtile.sample != 0) {
+ if(rtile.sample != 0) {
/* sample would be zero at initial tile update, which is only needed
* to tag tile form blender side as IN PROGRESS for proper highlight
* no buffers should be sent to blender yet
@@ -397,7 +398,7 @@ void BlenderSession::update_render_tile(RenderTile& rtile)
* be updated in blender side
* would need to be investigated a bit further, but for now shall be fine
*/
- if (!b_engine.is_preview())
+ if(!b_engine.is_preview())
do_write_update_render_tile(rtile, true);
else
do_write_update_render_tile(rtile, false);
@@ -408,20 +409,22 @@ void BlenderSession::render()
/* set callback to write out render results */
session->write_render_tile_cb = function_bind(&BlenderSession::write_render_tile, this, _1);
session->update_render_tile_cb = function_bind(&BlenderSession::update_render_tile, this, _1);
+ session->clear_database_cb = function_bind(&BlenderSession::clear_blender_database, this);
/* get buffer parameters */
SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
- BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_scene, b_v3d, b_rv3d, scene->camera, width, height);
+ BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
/* render each layer */
BL::RenderSettings r = b_scene.render();
- BL::RenderSettings::layers_iterator b_iter;
+ BL::RenderSettings::layers_iterator b_layer_iter;
+ BL::RenderResult::views_iterator b_view_iter;
- for(r.layers.begin(b_iter); b_iter != r.layers.end(); ++b_iter) {
- b_rlay_name = b_iter->name();
+ for(r.layers.begin(b_layer_iter); b_layer_iter != r.layers.end(); ++b_layer_iter) {
+ b_rlay_name = b_layer_iter->name();
- /* temporary render result to find needed passes */
- BL::RenderResult b_rr = begin_render_result(b_engine, 0, 0, 1, 1, b_rlay_name.c_str());
+ /* temporary render result to find needed passes and views */
+ BL::RenderResult b_rr = begin_render_result(b_engine, 0, 0, 1, 1, b_rlay_name.c_str(), NULL);
BL::RenderResult::layers_iterator b_single_rlay;
b_rr.layers.begin(b_single_rlay);
@@ -456,39 +459,50 @@ void BlenderSession::render()
}
}
- /* free result without merging */
- end_render_result(b_engine, b_rr, true, false);
-
buffer_params.passes = passes;
- scene->film->pass_alpha_threshold = b_iter->pass_alpha_threshold();
+ scene->film->pass_alpha_threshold = b_layer_iter->pass_alpha_threshold();
scene->film->tag_passes_update(scene, passes);
scene->film->tag_update(scene);
scene->integrator->tag_update(scene);
- /* update scene */
- sync->sync_camera(b_render, b_engine.camera_override(), width, height);
- sync->sync_data(b_v3d, b_engine.camera_override(), &python_thread_state, b_rlay_name.c_str());
+ for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter) {
+ b_rview_name = b_view_iter->name();
- /* update number of samples per layer */
- int samples = sync->get_layer_samples();
- bool bound_samples = sync->get_layer_bound_samples();
+ /* set the current view */
+ b_engine.active_view_set(b_rview_name.c_str());
- if(samples != 0 && (!bound_samples || (samples < session_params.samples)))
- session->reset(buffer_params, samples);
- else
- session->reset(buffer_params, session_params.samples);
+ /* update scene */
+ sync->sync_camera(b_render, b_engine.camera_override(), width, height);
+ sync->sync_data(b_v3d, b_engine.camera_override(), &python_thread_state, b_rlay_name.c_str());
- /* render */
- session->start();
- session->wait();
+ /* update number of samples per layer */
+ int samples = sync->get_layer_samples();
+ bool bound_samples = sync->get_layer_bound_samples();
+
+ if(samples != 0 && (!bound_samples || (samples < session_params.samples)))
+ session->reset(buffer_params, samples);
+ else
+ session->reset(buffer_params, session_params.samples);
+
+ /* render */
+ session->start();
+ session->wait();
+
+ if(session->progress.get_cancel())
+ break;
+ }
+
+ /* free result without merging */
+ end_render_result(b_engine, b_rr, true, false);
if(session->progress.get_cancel())
break;
}
/* clear callback */
- session->write_render_tile_cb = NULL;
- session->update_render_tile_cb = NULL;
+ session->write_render_tile_cb = function_null;
+ session->update_render_tile_cb = function_null;
+ session->clear_database_cb = function_null;
/* free all memory used (host and device), so we wouldn't leave render
* engine with extra memory allocated
@@ -500,18 +514,22 @@ void BlenderSession::render()
sync = NULL;
}
-static void populate_bake_data(BakeData *data, BL::BakePixel pixel_array, const int num_pixels)
+static void populate_bake_data(BakeData *data, const int object_id, BL::BakePixel pixel_array, const int num_pixels)
{
BL::BakePixel bp = pixel_array;
int i;
for(i=0; i < num_pixels; i++) {
- data->set(i, bp.primitive_id(), bp.uv(), bp.du_dx(), bp.du_dy(), bp.dv_dx(), bp.dv_dy());
+ if(bp.object_id() == object_id) {
+ data->set(i, bp.primitive_id(), bp.uv(), bp.du_dx(), bp.du_dy(), bp.dv_dx(), bp.dv_dy());
+ } else {
+ data->set_null(i);
+ }
bp = bp.next();
}
}
-void BlenderSession::bake(BL::Object b_object, const string& pass_type, BL::BakePixel pixel_array, const size_t num_pixels, const int depth, float result[])
+void BlenderSession::bake(BL::Object b_object, const string& pass_type, const int object_id, BL::BakePixel pixel_array, const size_t num_pixels, const int /*depth*/, float result[])
{
ShaderEvalType shader_type = get_shader_type(pass_type);
size_t object_index = OBJECT_NONE;
@@ -543,7 +561,7 @@ void BlenderSession::bake(BL::Object b_object, const string& pass_type, BL::Bake
/* get buffer parameters */
SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
- BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_scene, b_v3d, b_rv3d, scene->camera, width, height);
+ BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
scene->bake_manager->set_shader_limit((size_t)b_engine.tile_x(), (size_t)b_engine.tile_y());
scene->bake_manager->set_baking(true);
@@ -567,7 +585,7 @@ void BlenderSession::bake(BL::Object b_object, const string& pass_type, BL::Bake
BakeData *bake_data = scene->bake_manager->init(object, tri_offset, num_pixels);
- populate_bake_data(bake_data, pixel_array, num_pixels);
+ populate_bake_data(bake_data, object_id, pixel_array, num_pixels);
/* set number of samples */
session->tile_manager.set_samples(session_params.samples);
@@ -601,7 +619,7 @@ void BlenderSession::do_write_update_render_result(BL::RenderResult b_rr, BL::Re
vector<float> pixels(params.width*params.height*4);
- if (!do_update_only) {
+ if(!do_update_only) {
/* copy each pass */
BL::RenderLayer::passes_iterator b_iter;
@@ -619,10 +637,12 @@ void BlenderSession::do_write_update_render_result(BL::RenderResult b_rr, BL::Re
b_pass.rect(&pixels[0]);
}
}
-
- /* copy combined pass */
- if(buffers->get_pass_rect(PASS_COMBINED, exposure, rtile.sample, 4, &pixels[0]))
- b_rlay.rect(&pixels[0]);
+ else {
+ /* copy combined pass */
+ BL::RenderPass b_combined_pass(b_rlay.passes.find_by_type(BL::RenderPass::type_COMBINED, b_rview_name.c_str()));
+ if(buffers->get_pass_rect(PASS_COMBINED, exposure, rtile.sample, 4, &pixels[0]))
+ b_combined_pass.rect(&pixels[0]);
+ }
/* tag result as updated */
b_engine.update_result(b_rr);
@@ -692,7 +712,7 @@ void BlenderSession::synchronize()
/* reset if needed */
if(scene->need_reset()) {
- BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_scene, b_v3d, b_rv3d, scene->camera, width, height);
+ BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
session->reset(buffer_params, session_params.samples);
/* reset time */
@@ -747,7 +767,7 @@ bool BlenderSession::draw(int w, int h)
/* reset if requested */
if(reset) {
SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
- BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_scene, b_v3d, b_rv3d, scene->camera, width, height);
+ BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
bool session_pause = BlenderSync::get_session_pause(b_scene, background);
if(session_pause == false) {
@@ -764,7 +784,7 @@ bool BlenderSession::draw(int w, int h)
update_status_progress();
/* draw */
- BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_scene, b_v3d, b_rv3d, scene->camera, width, height);
+ BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
DeviceDrawParams draw_params;
if(session->params.display_buffer_linear) {
@@ -841,6 +861,9 @@ void BlenderSession::update_status_progress()
scene += " | " + b_scene.name();
if(b_rlay_name != "")
scene += ", " + b_rlay_name;
+
+ if(b_rview_name != "")
+ scene += ", " + b_rview_name;
}
else {
BLI_timestr(total_time, time_str, sizeof(time_str));
@@ -869,7 +892,7 @@ void BlenderSession::update_status_progress()
last_progress = progress;
}
- if (session->progress.get_error()) {
+ if(session->progress.get_error()) {
string error = session->progress.get_error_message();
if(error != last_error) {
/* TODO(sergey): Currently C++ RNA API doesn't let us to
@@ -981,6 +1004,18 @@ void BlenderSession::builtin_image_info(const string &builtin_name, void *builti
is_float = true;
}
+ else {
+ /* TODO(sergey): Check we're indeed in shader node tree. */
+ PointerRNA ptr;
+ RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr);
+ BL::Node b_node(ptr);
+ if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
+ BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
+ channels = 4;
+ width = height = depth = b_point_density_node.resolution();
+ is_float = true;
+ }
+ }
}
bool BlenderSession::builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels)
@@ -1000,18 +1035,19 @@ bool BlenderSession::builtin_image_pixels(const string &builtin_name, void *buil
unsigned char *image_pixels;
image_pixels = image_get_pixels_for_frame(b_image, frame);
+ size_t num_pixels = ((size_t)width) * height;
if(image_pixels) {
- memcpy(pixels, image_pixels, width * height * channels * sizeof(unsigned char));
+ memcpy(pixels, image_pixels, num_pixels * channels * sizeof(unsigned char));
MEM_freeN(image_pixels);
}
else {
if(channels == 1) {
- memset(pixels, 0, width * height * sizeof(unsigned char));
+ memset(pixels, 0, num_pixels * sizeof(unsigned char));
}
else {
unsigned char *cp = pixels;
- for(int i = 0; i < width * height; i++, cp += channels) {
+ for(size_t i = 0; i < num_pixels; i++, cp += channels) {
cp[0] = 255;
cp[1] = 0;
cp[2] = 255;
@@ -1023,7 +1059,7 @@ bool BlenderSession::builtin_image_pixels(const string &builtin_name, void *buil
/* premultiply, byte images are always straight for blender */
unsigned char *cp = pixels;
- for(int i = 0; i < width * height; i++, cp += channels) {
+ for(size_t i = 0; i < num_pixels; i++, cp += channels) {
cp[0] = (cp[0] * cp[3]) >> 8;
cp[1] = (cp[1] * cp[3]) >> 8;
cp[2] = (cp[2] * cp[3]) >> 8;
@@ -1052,18 +1088,19 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void
float *image_pixels;
image_pixels = image_get_float_pixels_for_frame(b_image, frame);
+ size_t num_pixels = ((size_t)width) * height;
if(image_pixels) {
- memcpy(pixels, image_pixels, width * height * channels * sizeof(float));
+ memcpy(pixels, image_pixels, num_pixels * channels * sizeof(float));
MEM_freeN(image_pixels);
}
else {
if(channels == 1) {
- memset(pixels, 0, width * height * sizeof(float));
+ memset(pixels, 0, num_pixels * sizeof(float));
}
else {
float *fp = pixels;
- for(int i = 0; i < width * height; i++, fp += channels) {
+ for(int i = 0; i < num_pixels; i++, fp += channels) {
fp[0] = 1.0f;
fp[1] = 0.0f;
fp[2] = 1.0f;
@@ -1089,11 +1126,12 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void
int width = resolution.x * amplify;
int height = resolution.y * amplify;
int depth = resolution.z * amplify;
+ size_t num_pixels = ((size_t)width) * height * depth;
if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) {
SmokeDomainSettings_density_grid_get_length(&b_domain.ptr, &length);
- if(length == width*height*depth) {
+ if(length == num_pixels) {
SmokeDomainSettings_density_grid_get(&b_domain.ptr, pixels);
return true;
}
@@ -1103,7 +1141,7 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void
* as 1500..3000 K with the first part faded to zero density */
SmokeDomainSettings_flame_grid_get_length(&b_domain.ptr, &length);
- if(length == width*height*depth) {
+ if(length == num_pixels) {
SmokeDomainSettings_flame_grid_get(&b_domain.ptr, pixels);
return true;
}
@@ -1112,7 +1150,7 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void
/* the RGB is "premultiplied" by density for better interpolation results */
SmokeDomainSettings_color_grid_get_length(&b_domain.ptr, &length);
- if(length == width*height*depth*4) {
+ if(length == num_pixels*4) {
SmokeDomainSettings_color_grid_get(&b_domain.ptr, pixels);
return true;
}
@@ -1120,9 +1158,41 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void
fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n");
}
+ else {
+ /* TODO(sergey): Check we're indeed in shader node tree. */
+ PointerRNA ptr;
+ RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr);
+ BL::Node b_node(ptr);
+ if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
+ BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
+ int length;
+ b_point_density_node.calc_point_density(b_scene, &length, &pixels);
+ }
+ }
return false;
}
+void BlenderSession::clear_blender_database()
+{
+ const bool is_interface_locked = b_engine.render() &&
+ b_engine.render().use_lock_interface();
+ const bool can_free_database = BlenderSession::headless || is_interface_locked;
+ if(!can_free_database) {
+ /* Database might be used by the interface, can not free it at all. */
+ return;
+ }
+ for(BL::Scene b_sce = b_scene; b_sce; b_sce = b_sce.background_set()) {
+ BL::Scene::object_bases_iterator b_base;
+ for(b_sce.object_bases.begin(b_base);
+ b_base != b_sce.object_bases.end();
+ ++b_base)
+ {
+ BL::Object b_ob = b_base->object();
+ b_ob.cache_release(true);
+ }
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h
index c8070286006..5498548eb74 100644
--- a/intern/cycles/blender/blender_session.h
+++ b/intern/cycles/blender/blender_session.h
@@ -52,7 +52,7 @@ public:
/* offline render */
void render();
- void bake(BL::Object b_object, const string& pass_type, BL::BakePixel pixel_array, const size_t num_pixels, const int depth, float pixels[]);
+ void bake(BL::Object b_object, const string& pass_type, const int object_id, BL::BakePixel pixel_array, const size_t num_pixels, const int depth, float pixels[]);
void write_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile);
void write_render_tile(RenderTile& rtile);
@@ -90,6 +90,7 @@ public:
BL::SpaceView3D b_v3d;
BL::RegionView3D b_rv3d;
string b_rlay_name;
+ string b_rview_name;
string last_status;
string last_error;
@@ -108,6 +109,8 @@ protected:
void builtin_image_info(const string &builtin_name, void *builtin_data, bool &is_float, int &width, int &height, int &depth, int &channels);
bool builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels);
bool builtin_image_float_pixels(const string &builtin_name, void *builtin_data, float *pixels);
+
+ void clear_blender_database();
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index baf79a78987..6c54149164d 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -22,6 +22,7 @@
#include "scene.h"
#include "shader.h"
+#include "blender_texture.h"
#include "blender_sync.h"
#include "blender_util.h"
@@ -106,7 +107,7 @@ static ShaderSocketType convert_socket_type(BL::NodeSocket b_socket)
}
}
-static void set_default_value(ShaderInput *input, BL::Node b_node, BL::NodeSocket b_sock, BL::BlendData b_data, BL::ID b_id)
+static void set_default_value(ShaderInput *input, BL::NodeSocket b_sock, BL::BlendData b_data, BL::ID b_id)
{
/* copy values for non linked inputs */
switch(input->type) {
@@ -179,53 +180,59 @@ static bool is_output_node(BL::Node b_node)
|| b_node.is_a(&RNA_ShaderNodeOutputLamp));
}
-static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, ShaderGraph *graph, BL::ShaderNodeTree b_ntree, BL::ShaderNode b_node)
+static ShaderNode *add_node(Scene *scene,
+ BL::RenderEngine b_engine,
+ BL::BlendData b_data,
+ BL::Scene b_scene,
+ ShaderGraph *graph,
+ BL::ShaderNodeTree b_ntree,
+ BL::ShaderNode b_node)
{
ShaderNode *node = NULL;
/* existing blender nodes */
- if (b_node.is_a(&RNA_ShaderNodeRGBCurve)) {
+ if(b_node.is_a(&RNA_ShaderNodeRGBCurve)) {
BL::ShaderNodeRGBCurve b_curve_node(b_node);
RGBCurvesNode *curves = new RGBCurvesNode();
curvemapping_color_to_array(b_curve_node.mapping(), curves->curves, RAMP_TABLE_SIZE, true);
node = curves;
}
- if (b_node.is_a(&RNA_ShaderNodeVectorCurve)) {
+ if(b_node.is_a(&RNA_ShaderNodeVectorCurve)) {
BL::ShaderNodeVectorCurve b_curve_node(b_node);
VectorCurvesNode *curves = new VectorCurvesNode();
curvemapping_color_to_array(b_curve_node.mapping(), curves->curves, RAMP_TABLE_SIZE, false);
node = curves;
}
- else if (b_node.is_a(&RNA_ShaderNodeValToRGB)) {
+ else if(b_node.is_a(&RNA_ShaderNodeValToRGB)) {
RGBRampNode *ramp = new RGBRampNode();
BL::ShaderNodeValToRGB b_ramp_node(b_node);
colorramp_to_array(b_ramp_node.color_ramp(), ramp->ramp, RAMP_TABLE_SIZE);
ramp->interpolate = b_ramp_node.color_ramp().interpolation() != BL::ColorRamp::interpolation_CONSTANT;
node = ramp;
}
- else if (b_node.is_a(&RNA_ShaderNodeRGB)) {
+ else if(b_node.is_a(&RNA_ShaderNodeRGB)) {
ColorNode *color = new ColorNode();
color->value = get_node_output_rgba(b_node, "Color");
node = color;
}
- else if (b_node.is_a(&RNA_ShaderNodeValue)) {
+ else if(b_node.is_a(&RNA_ShaderNodeValue)) {
ValueNode *value = new ValueNode();
value->value = get_node_output_value(b_node, "Value");
node = value;
}
- else if (b_node.is_a(&RNA_ShaderNodeCameraData)) {
+ else if(b_node.is_a(&RNA_ShaderNodeCameraData)) {
node = new CameraNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeInvert)) {
+ else if(b_node.is_a(&RNA_ShaderNodeInvert)) {
node = new InvertNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeGamma)) {
+ else if(b_node.is_a(&RNA_ShaderNodeGamma)) {
node = new GammaNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeBrightContrast)) {
+ else if(b_node.is_a(&RNA_ShaderNodeBrightContrast)) {
node = new BrightContrastNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeMixRGB)) {
+ else if(b_node.is_a(&RNA_ShaderNodeMixRGB)) {
BL::ShaderNodeMixRGB b_mix_node(b_node);
MixNode *mix = new MixNode();
mix->type = MixNode::type_enum[b_mix_node.blend_type()];
@@ -236,44 +243,44 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
mix->use_clamp = b_mix_node.use_clamp();
node = mix;
}
- else if (b_node.is_a(&RNA_ShaderNodeSeparateRGB)) {
+ else if(b_node.is_a(&RNA_ShaderNodeSeparateRGB)) {
node = new SeparateRGBNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeCombineRGB)) {
+ else if(b_node.is_a(&RNA_ShaderNodeCombineRGB)) {
node = new CombineRGBNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeSeparateHSV)) {
+ else if(b_node.is_a(&RNA_ShaderNodeSeparateHSV)) {
node = new SeparateHSVNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeCombineHSV)) {
+ else if(b_node.is_a(&RNA_ShaderNodeCombineHSV)) {
node = new CombineHSVNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeSeparateXYZ)) {
+ else if(b_node.is_a(&RNA_ShaderNodeSeparateXYZ)) {
node = new SeparateXYZNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeCombineXYZ)) {
+ else if(b_node.is_a(&RNA_ShaderNodeCombineXYZ)) {
node = new CombineXYZNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeHueSaturation)) {
+ else if(b_node.is_a(&RNA_ShaderNodeHueSaturation)) {
node = new HSVNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeRGBToBW)) {
+ else if(b_node.is_a(&RNA_ShaderNodeRGBToBW)) {
node = new ConvertNode(SHADER_SOCKET_COLOR, SHADER_SOCKET_FLOAT);
}
- else if (b_node.is_a(&RNA_ShaderNodeMath)) {
+ else if(b_node.is_a(&RNA_ShaderNodeMath)) {
BL::ShaderNodeMath b_math_node(b_node);
MathNode *math = new MathNode();
math->type = MathNode::type_enum[b_math_node.operation()];
math->use_clamp = b_math_node.use_clamp();
node = math;
}
- else if (b_node.is_a(&RNA_ShaderNodeVectorMath)) {
+ else if(b_node.is_a(&RNA_ShaderNodeVectorMath)) {
BL::ShaderNodeVectorMath b_vector_math_node(b_node);
VectorMathNode *vmath = new VectorMathNode();
vmath->type = VectorMathNode::type_enum[b_vector_math_node.operation()];
node = vmath;
}
- else if (b_node.is_a(&RNA_ShaderNodeVectorTransform)) {
+ else if(b_node.is_a(&RNA_ShaderNodeVectorTransform)) {
BL::ShaderNodeVectorTransform b_vector_transform_node(b_node);
VectorTransformNode *vtransform = new VectorTransformNode();
vtransform->type = VectorTransformNode::type_enum[b_vector_transform_node.type()];
@@ -281,7 +288,7 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
vtransform->convert_to = VectorTransformNode::convert_space_enum[b_vector_transform_node.convert_to()];
node = vtransform;
}
- else if (b_node.is_a(&RNA_ShaderNodeNormal)) {
+ else if(b_node.is_a(&RNA_ShaderNodeNormal)) {
BL::Node::outputs_iterator out_it;
b_node.outputs.begin(out_it);
@@ -289,7 +296,7 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
norm->direction = get_node_output_vector(b_node, "Normal");
node = norm;
}
- else if (b_node.is_a(&RNA_ShaderNodeMapping)) {
+ else if(b_node.is_a(&RNA_ShaderNodeMapping)) {
BL::ShaderNodeMapping b_mapping_node(b_node);
MappingNode *mapping = new MappingNode();
@@ -297,31 +304,31 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
node = mapping;
}
- else if (b_node.is_a(&RNA_ShaderNodeFresnel)) {
+ else if(b_node.is_a(&RNA_ShaderNodeFresnel)) {
node = new FresnelNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeLayerWeight)) {
+ else if(b_node.is_a(&RNA_ShaderNodeLayerWeight)) {
node = new LayerWeightNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeAddShader)) {
+ else if(b_node.is_a(&RNA_ShaderNodeAddShader)) {
node = new AddClosureNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeMixShader)) {
+ else if(b_node.is_a(&RNA_ShaderNodeMixShader)) {
node = new MixClosureNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeAttribute)) {
+ else if(b_node.is_a(&RNA_ShaderNodeAttribute)) {
BL::ShaderNodeAttribute b_attr_node(b_node);
AttributeNode *attr = new AttributeNode();
attr->attribute = b_attr_node.attribute_name();
node = attr;
}
- else if (b_node.is_a(&RNA_ShaderNodeBackground)) {
+ else if(b_node.is_a(&RNA_ShaderNodeBackground)) {
node = new BackgroundNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeHoldout)) {
+ else if(b_node.is_a(&RNA_ShaderNodeHoldout)) {
node = new HoldoutNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeBsdfAnisotropic)) {
+ else if(b_node.is_a(&RNA_ShaderNodeBsdfAnisotropic)) {
BL::ShaderNodeBsdfAnisotropic b_aniso_node(b_node);
AnisotropicBsdfNode *aniso = new AnisotropicBsdfNode();
@@ -340,10 +347,10 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
node = aniso;
}
- else if (b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) {
+ else if(b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) {
node = new DiffuseBsdfNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeSubsurfaceScattering)) {
+ else if(b_node.is_a(&RNA_ShaderNodeSubsurfaceScattering)) {
BL::ShaderNodeSubsurfaceScattering b_subsurface_node(b_node);
SubsurfaceScatteringNode *subsurface = new SubsurfaceScatteringNode();
@@ -359,7 +366,7 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
node = subsurface;
}
- else if (b_node.is_a(&RNA_ShaderNodeBsdfGlossy)) {
+ else if(b_node.is_a(&RNA_ShaderNodeBsdfGlossy)) {
BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
GlossyBsdfNode *glossy = new GlossyBsdfNode();
@@ -379,7 +386,7 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
}
node = glossy;
}
- else if (b_node.is_a(&RNA_ShaderNodeBsdfGlass)) {
+ else if(b_node.is_a(&RNA_ShaderNodeBsdfGlass)) {
BL::ShaderNodeBsdfGlass b_glass_node(b_node);
GlassBsdfNode *glass = new GlassBsdfNode();
switch(b_glass_node.distribution()) {
@@ -395,7 +402,7 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
}
node = glass;
}
- else if (b_node.is_a(&RNA_ShaderNodeBsdfRefraction)) {
+ else if(b_node.is_a(&RNA_ShaderNodeBsdfRefraction)) {
BL::ShaderNodeBsdfRefraction b_refraction_node(b_node);
RefractionBsdfNode *refraction = new RefractionBsdfNode();
switch(b_refraction_node.distribution()) {
@@ -411,7 +418,7 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
}
node = refraction;
}
- else if (b_node.is_a(&RNA_ShaderNodeBsdfToon)) {
+ else if(b_node.is_a(&RNA_ShaderNodeBsdfToon)) {
BL::ShaderNodeBsdfToon b_toon_node(b_node);
ToonBsdfNode *toon = new ToonBsdfNode();
switch(b_toon_node.component()) {
@@ -424,7 +431,7 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
}
node = toon;
}
- else if (b_node.is_a(&RNA_ShaderNodeBsdfHair)) {
+ else if(b_node.is_a(&RNA_ShaderNodeBsdfHair)) {
BL::ShaderNodeBsdfHair b_hair_node(b_node);
HairBsdfNode *hair = new HairBsdfNode();
switch(b_hair_node.component()) {
@@ -437,64 +444,64 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
}
node = hair;
}
- else if (b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) {
+ else if(b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) {
node = new TranslucentBsdfNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeBsdfTransparent)) {
+ else if(b_node.is_a(&RNA_ShaderNodeBsdfTransparent)) {
node = new TransparentBsdfNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeBsdfVelvet)) {
+ else if(b_node.is_a(&RNA_ShaderNodeBsdfVelvet)) {
node = new VelvetBsdfNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeEmission)) {
+ else if(b_node.is_a(&RNA_ShaderNodeEmission)) {
node = new EmissionNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeAmbientOcclusion)) {
+ else if(b_node.is_a(&RNA_ShaderNodeAmbientOcclusion)) {
node = new AmbientOcclusionNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeVolumeScatter)) {
+ else if(b_node.is_a(&RNA_ShaderNodeVolumeScatter)) {
node = new ScatterVolumeNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeVolumeAbsorption)) {
+ else if(b_node.is_a(&RNA_ShaderNodeVolumeAbsorption)) {
node = new AbsorptionVolumeNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeNewGeometry)) {
+ else if(b_node.is_a(&RNA_ShaderNodeNewGeometry)) {
node = new GeometryNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeWireframe)) {
+ else if(b_node.is_a(&RNA_ShaderNodeWireframe)) {
BL::ShaderNodeWireframe b_wireframe_node(b_node);
WireframeNode *wire = new WireframeNode();
wire->use_pixel_size = b_wireframe_node.use_pixel_size();
node = wire;
}
- else if (b_node.is_a(&RNA_ShaderNodeWavelength)) {
+ else if(b_node.is_a(&RNA_ShaderNodeWavelength)) {
node = new WavelengthNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeBlackbody)) {
+ else if(b_node.is_a(&RNA_ShaderNodeBlackbody)) {
node = new BlackbodyNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeLightPath)) {
+ else if(b_node.is_a(&RNA_ShaderNodeLightPath)) {
node = new LightPathNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeLightFalloff)) {
+ else if(b_node.is_a(&RNA_ShaderNodeLightFalloff)) {
node = new LightFalloffNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeObjectInfo)) {
+ else if(b_node.is_a(&RNA_ShaderNodeObjectInfo)) {
node = new ObjectInfoNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeParticleInfo)) {
+ else if(b_node.is_a(&RNA_ShaderNodeParticleInfo)) {
node = new ParticleInfoNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeHairInfo)) {
+ else if(b_node.is_a(&RNA_ShaderNodeHairInfo)) {
node = new HairInfoNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeBump)) {
+ else if(b_node.is_a(&RNA_ShaderNodeBump)) {
BL::ShaderNodeBump b_bump_node(b_node);
BumpNode *bump = new BumpNode();
bump->invert = b_bump_node.invert();
node = bump;
}
- else if (b_node.is_a(&RNA_ShaderNodeScript)) {
+ else if(b_node.is_a(&RNA_ShaderNodeScript)) {
#ifdef WITH_OSL
if(scene->shader_manager->use_osl()) {
/* create script node */
@@ -510,16 +517,16 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
* Socket names must be stored in the extra lists instead. */
BL::Node::inputs_iterator b_input;
- for (b_script_node.inputs.begin(b_input); b_input != b_script_node.inputs.end(); ++b_input) {
+ for(b_script_node.inputs.begin(b_input); b_input != b_script_node.inputs.end(); ++b_input) {
script_node->input_names.push_back(ustring(b_input->name()));
ShaderInput *input = script_node->add_input(script_node->input_names.back().c_str(),
convert_socket_type(*b_input));
- set_default_value(input, b_node, *b_input, b_data, b_ntree);
+ set_default_value(input, *b_input, b_data, b_ntree);
}
BL::Node::outputs_iterator b_output;
- for (b_script_node.outputs.begin(b_output); b_output != b_script_node.outputs.end(); ++b_output) {
+ for(b_script_node.outputs.begin(b_output); b_output != b_script_node.outputs.end(); ++b_output) {
script_node->output_names.push_back(ustring(b_output->name()));
script_node->add_output(script_node->output_names.back().c_str(),
convert_socket_type(*b_output));
@@ -543,9 +550,12 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
node = script_node;
}
+#else
+ (void)b_data;
+ (void)b_ntree;
#endif
}
- else if (b_node.is_a(&RNA_ShaderNodeTexImage)) {
+ else if(b_node.is_a(&RNA_ShaderNodeTexImage)) {
BL::ShaderNodeTexImage b_image_node(b_node);
BL::Image b_image(b_image_node.image());
ImageTextureNode *image = new ImageTextureNode();
@@ -555,7 +565,8 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
*/
bool is_builtin = b_image.packed_file() ||
b_image.source() == BL::Image::source_GENERATED ||
- b_image.source() == BL::Image::source_MOVIE;
+ b_image.source() == BL::Image::source_MOVIE ||
+ b_engine.is_preview();
if(is_builtin) {
/* for builtin images we're using image datablock name to find an image to
@@ -578,7 +589,7 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
image->use_alpha = b_image.use_alpha();
/* TODO(sergey): Does not work properly when we change builtin type. */
- if (b_image.is_updated()) {
+ if(b_image.is_updated()) {
scene->image_manager->tag_reload_image(image->filename,
image->builtin_data,
(InterpolationType)b_image_node.interpolation());
@@ -591,14 +602,15 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
get_tex_mapping(&image->tex_mapping, b_image_node.texture_mapping());
node = image;
}
- else if (b_node.is_a(&RNA_ShaderNodeTexEnvironment)) {
+ else if(b_node.is_a(&RNA_ShaderNodeTexEnvironment)) {
BL::ShaderNodeTexEnvironment b_env_node(b_node);
BL::Image b_image(b_env_node.image());
EnvironmentTextureNode *env = new EnvironmentTextureNode();
if(b_image) {
bool is_builtin = b_image.packed_file() ||
b_image.source() == BL::Image::source_GENERATED ||
- b_image.source() == BL::Image::source_MOVIE;
+ b_image.source() == BL::Image::source_MOVIE ||
+ b_engine.is_preview();
if(is_builtin) {
int scene_frame = b_scene.frame_current();
@@ -615,7 +627,7 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
env->use_alpha = b_image.use_alpha();
/* TODO(sergey): Does not work properly when we change builtin type. */
- if (b_image.is_updated()) {
+ if(b_image.is_updated()) {
scene->image_manager->tag_reload_image(env->filename,
env->builtin_data,
INTERPOLATION_LINEAR);
@@ -626,41 +638,41 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
get_tex_mapping(&env->tex_mapping, b_env_node.texture_mapping());
node = env;
}
- else if (b_node.is_a(&RNA_ShaderNodeTexGradient)) {
+ else if(b_node.is_a(&RNA_ShaderNodeTexGradient)) {
BL::ShaderNodeTexGradient b_gradient_node(b_node);
GradientTextureNode *gradient = new GradientTextureNode();
gradient->type = GradientTextureNode::type_enum[(int)b_gradient_node.gradient_type()];
get_tex_mapping(&gradient->tex_mapping, b_gradient_node.texture_mapping());
node = gradient;
}
- else if (b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
+ else if(b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
VoronoiTextureNode *voronoi = new VoronoiTextureNode();
voronoi->coloring = VoronoiTextureNode::coloring_enum[(int)b_voronoi_node.coloring()];
get_tex_mapping(&voronoi->tex_mapping, b_voronoi_node.texture_mapping());
node = voronoi;
}
- else if (b_node.is_a(&RNA_ShaderNodeTexMagic)) {
+ else if(b_node.is_a(&RNA_ShaderNodeTexMagic)) {
BL::ShaderNodeTexMagic b_magic_node(b_node);
MagicTextureNode *magic = new MagicTextureNode();
magic->depth = b_magic_node.turbulence_depth();
get_tex_mapping(&magic->tex_mapping, b_magic_node.texture_mapping());
node = magic;
}
- else if (b_node.is_a(&RNA_ShaderNodeTexWave)) {
+ else if(b_node.is_a(&RNA_ShaderNodeTexWave)) {
BL::ShaderNodeTexWave b_wave_node(b_node);
WaveTextureNode *wave = new WaveTextureNode();
wave->type = WaveTextureNode::type_enum[(int)b_wave_node.wave_type()];
get_tex_mapping(&wave->tex_mapping, b_wave_node.texture_mapping());
node = wave;
}
- else if (b_node.is_a(&RNA_ShaderNodeTexChecker)) {
+ else if(b_node.is_a(&RNA_ShaderNodeTexChecker)) {
BL::ShaderNodeTexChecker b_checker_node(b_node);
CheckerTextureNode *checker = new CheckerTextureNode();
get_tex_mapping(&checker->tex_mapping, b_checker_node.texture_mapping());
node = checker;
}
- else if (b_node.is_a(&RNA_ShaderNodeTexBrick)) {
+ else if(b_node.is_a(&RNA_ShaderNodeTexBrick)) {
BL::ShaderNodeTexBrick b_brick_node(b_node);
BrickTextureNode *brick = new BrickTextureNode();
brick->offset = b_brick_node.offset();
@@ -670,20 +682,20 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
get_tex_mapping(&brick->tex_mapping, b_brick_node.texture_mapping());
node = brick;
}
- else if (b_node.is_a(&RNA_ShaderNodeTexNoise)) {
+ else if(b_node.is_a(&RNA_ShaderNodeTexNoise)) {
BL::ShaderNodeTexNoise b_noise_node(b_node);
NoiseTextureNode *noise = new NoiseTextureNode();
get_tex_mapping(&noise->tex_mapping, b_noise_node.texture_mapping());
node = noise;
}
- else if (b_node.is_a(&RNA_ShaderNodeTexMusgrave)) {
+ else if(b_node.is_a(&RNA_ShaderNodeTexMusgrave)) {
BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
MusgraveTextureNode *musgrave = new MusgraveTextureNode();
musgrave->type = MusgraveTextureNode::type_enum[(int)b_musgrave_node.musgrave_type()];
get_tex_mapping(&musgrave->tex_mapping, b_musgrave_node.texture_mapping());
node = musgrave;
}
- else if (b_node.is_a(&RNA_ShaderNodeTexCoord)) {
+ else if(b_node.is_a(&RNA_ShaderNodeTexCoord)) {
BL::ShaderNodeTexCoord b_tex_coord_node(b_node);
TextureCoordinateNode *tex_coord = new TextureCoordinateNode();
tex_coord->from_dupli = b_tex_coord_node.from_dupli();
@@ -693,7 +705,7 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
}
node = tex_coord;
}
- else if (b_node.is_a(&RNA_ShaderNodeTexSky)) {
+ else if(b_node.is_a(&RNA_ShaderNodeTexSky)) {
BL::ShaderNodeTexSky b_sky_node(b_node);
SkyTextureNode *sky = new SkyTextureNode();
sky->type = SkyTextureNode::type_enum[(int)b_sky_node.sky_type()];
@@ -703,14 +715,14 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
get_tex_mapping(&sky->tex_mapping, b_sky_node.texture_mapping());
node = sky;
}
- else if (b_node.is_a(&RNA_ShaderNodeNormalMap)) {
+ else if(b_node.is_a(&RNA_ShaderNodeNormalMap)) {
BL::ShaderNodeNormalMap b_normal_map_node(b_node);
NormalMapNode *nmap = new NormalMapNode();
nmap->space = NormalMapNode::space_enum[(int)b_normal_map_node.space()];
nmap->attribute = b_normal_map_node.uv_map();
node = nmap;
}
- else if (b_node.is_a(&RNA_ShaderNodeTangent)) {
+ else if(b_node.is_a(&RNA_ShaderNodeTangent)) {
BL::ShaderNodeTangent b_tangent_node(b_node);
TangentNode *tangent = new TangentNode();
tangent->direction_type = TangentNode::direction_type_enum[(int)b_tangent_node.direction_type()];
@@ -718,13 +730,41 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
tangent->attribute = b_tangent_node.uv_map();
node = tangent;
}
- else if (b_node.is_a(&RNA_ShaderNodeUVMap)) {
+ else if(b_node.is_a(&RNA_ShaderNodeUVMap)) {
BL::ShaderNodeUVMap b_uvmap_node(b_node);
UVMapNode *uvm = new UVMapNode();
uvm->attribute = b_uvmap_node.uv_map();
uvm->from_dupli = b_uvmap_node.from_dupli();
node = uvm;
}
+ else if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
+ BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
+ PointDensityTextureNode *point_density = new PointDensityTextureNode();
+ point_density->filename = b_point_density_node.name();
+ point_density->space =
+ PointDensityTextureNode::space_enum[(int)b_point_density_node.space()];
+ point_density->interpolation =
+ (InterpolationType)b_point_density_node.interpolation();
+ point_density->builtin_data = b_point_density_node.ptr.data;
+
+ /* Transformation form world space to texture space. */
+ BL::Object b_ob(b_point_density_node.object());
+ if(b_ob) {
+ float3 loc, size;
+ point_density_texture_space(b_point_density_node, loc, size);
+ point_density->tfm =
+ transform_translate(-loc) * transform_scale(size) *
+ transform_inverse(get_transform(b_ob.matrix_world()));
+ }
+
+ /* TODO(sergey): Use more proper update flag. */
+ if(true) {
+ scene->image_manager->tag_reload_image(point_density->filename,
+ point_density->builtin_data,
+ point_density->interpolation);
+ }
+ node = point_density;
+ }
if(node)
graph->add(node);
@@ -734,7 +774,7 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
static bool node_use_modified_socket_name(ShaderNode *node)
{
- if (node->special_type == SHADER_SPECIAL_TYPE_SCRIPT)
+ if(node->special_type == SHADER_SPECIAL_TYPE_SCRIPT)
return false;
return true;
@@ -744,14 +784,14 @@ static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::Node b_node, B
{
string name = b_socket.name();
- if (node_use_modified_socket_name(node)) {
+ if(node_use_modified_socket_name(node)) {
BL::Node::inputs_iterator b_input;
bool found = false;
int counter = 0, total = 0;
- for (b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
- if (b_input->name() == name) {
- if (!found)
+ for(b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
+ if(b_input->name() == name) {
+ if(!found)
counter++;
total++;
}
@@ -761,10 +801,10 @@ static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::Node b_node, B
}
/* rename if needed */
- if (name == "Shader")
+ if(name == "Shader")
name = "Closure";
- if (total > 1)
+ if(total > 1)
name = string_printf("%s%d", name.c_str(), counter);
}
@@ -775,14 +815,14 @@ static ShaderOutput *node_find_output_by_name(ShaderNode *node, BL::Node b_node,
{
string name = b_socket.name();
- if (node_use_modified_socket_name(node)) {
+ if(node_use_modified_socket_name(node)) {
BL::Node::outputs_iterator b_output;
bool found = false;
int counter = 0, total = 0;
- for (b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
- if (b_output->name() == name) {
- if (!found)
+ for(b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
+ if(b_output->name() == name) {
+ if(!found)
counter++;
total++;
}
@@ -792,18 +832,24 @@ static ShaderOutput *node_find_output_by_name(ShaderNode *node, BL::Node b_node,
}
/* rename if needed */
- if (name == "Shader")
+ if(name == "Shader")
name = "Closure";
- if (total > 1)
+ if(total > 1)
name = string_printf("%s%d", name.c_str(), counter);
}
return node->output(name.c_str());
}
-static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, ShaderGraph *graph, BL::ShaderNodeTree b_ntree,
- const ProxyMap &proxy_input_map, const ProxyMap &proxy_output_map)
+static void add_nodes(Scene *scene,
+ BL::RenderEngine b_engine,
+ BL::BlendData b_data,
+ BL::Scene b_scene,
+ ShaderGraph *graph,
+ BL::ShaderNodeTree b_ntree,
+ const ProxyMap &proxy_input_map,
+ const ProxyMap &proxy_output_map)
{
/* add nodes */
BL::ShaderNodeTree::nodes_iterator b_node;
@@ -818,7 +864,7 @@ static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, Sha
BL::ShaderNode output_node(PointerRNA_NULL);
for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
- if (is_output_node(*b_node)) {
+ if(is_output_node(*b_node)) {
BL::ShaderNodeOutputMaterial b_output_node(*b_node);
if(b_output_node.is_active_output()) {
@@ -834,10 +880,10 @@ static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, Sha
/* add nodes */
for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
- if (b_node->mute() || b_node->is_a(&RNA_NodeReroute)) {
+ if(b_node->mute() || b_node->is_a(&RNA_NodeReroute)) {
/* replace muted node with internal links */
BL::Node::internal_links_iterator b_link;
- for (b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end(); ++b_link) {
+ for(b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end(); ++b_link) {
ProxyNode *proxy = new ProxyNode(convert_socket_type(b_link->to_socket()));
input_map[b_link->from_socket().ptr.data] = proxy->inputs[0];
@@ -846,10 +892,10 @@ static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, Sha
graph->add(proxy);
}
}
- else if (b_node->is_a(&RNA_ShaderNodeGroup) || b_node->is_a(&RNA_NodeCustomGroup)) {
+ else if(b_node->is_a(&RNA_ShaderNodeGroup) || b_node->is_a(&RNA_NodeCustomGroup)) {
BL::ShaderNodeTree b_group_ntree(PointerRNA_NULL);
- if (b_node->is_a(&RNA_ShaderNodeGroup))
+ if(b_node->is_a(&RNA_ShaderNodeGroup))
b_group_ntree = BL::ShaderNodeTree(((BL::NodeGroup)(*b_node)).node_tree());
else
b_group_ntree = BL::ShaderNodeTree(((BL::NodeCustomGroup)(*b_node)).node_tree());
@@ -868,7 +914,7 @@ static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, Sha
input_map[b_input->ptr.data] = proxy->inputs[0];
- set_default_value(proxy->inputs[0], *b_node, *b_input, b_data, b_ntree);
+ set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree);
}
for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
ProxyNode *proxy = new ProxyNode(convert_socket_type(*b_output));
@@ -880,33 +926,41 @@ static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, Sha
output_map[b_output->ptr.data] = proxy->outputs[0];
}
- if (b_group_ntree)
- add_nodes(scene, b_data, b_scene, graph, b_group_ntree, group_proxy_input_map, group_proxy_output_map);
+ if(b_group_ntree) {
+ add_nodes(scene,
+ b_engine,
+ b_data,
+ b_scene,
+ graph,
+ b_group_ntree,
+ group_proxy_input_map,
+ group_proxy_output_map);
+ }
}
- else if (b_node->is_a(&RNA_NodeGroupInput)) {
+ else if(b_node->is_a(&RNA_NodeGroupInput)) {
/* map each socket to a proxy node */
for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
ProxyMap::const_iterator proxy_it = proxy_input_map.find(b_output->identifier());
- if (proxy_it != proxy_input_map.end()) {
+ if(proxy_it != proxy_input_map.end()) {
ProxyNode *proxy = proxy_it->second;
output_map[b_output->ptr.data] = proxy->outputs[0];
}
}
}
- else if (b_node->is_a(&RNA_NodeGroupOutput)) {
+ else if(b_node->is_a(&RNA_NodeGroupOutput)) {
BL::NodeGroupOutput b_output_node(*b_node);
/* only the active group output is used */
- if (b_output_node.is_active_output()) {
+ if(b_output_node.is_active_output()) {
/* map each socket to a proxy node */
for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
ProxyMap::const_iterator proxy_it = proxy_output_map.find(b_input->identifier());
- if (proxy_it != proxy_output_map.end()) {
+ if(proxy_it != proxy_output_map.end()) {
ProxyNode *proxy = proxy_it->second;
input_map[b_input->ptr.data] = proxy->inputs[0];
- set_default_value(proxy->inputs[0], *b_node, *b_input, b_data, b_ntree);
+ set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree);
}
}
}
@@ -914,30 +968,36 @@ static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, Sha
else {
ShaderNode *node = NULL;
- if (is_output_node(*b_node)) {
- if (b_node->ptr.data == output_node.ptr.data) {
+ if(is_output_node(*b_node)) {
+ if(b_node->ptr.data == output_node.ptr.data) {
node = graph->output();
}
}
else {
- node = add_node(scene, b_data, b_scene, graph, b_ntree, BL::ShaderNode(*b_node));
+ node = add_node(scene,
+ b_engine,
+ b_data,
+ b_scene,
+ graph,
+ b_ntree,
+ BL::ShaderNode(*b_node));
}
if(node) {
/* map node sockets for linking */
for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
ShaderInput *input = node_find_input_by_name(node, *b_node, *b_input);
- if (!input) {
+ if(!input) {
/* XXX should not happen, report error? */
continue;
}
input_map[b_input->ptr.data] = input;
- set_default_value(input, *b_node, *b_input, b_data, b_ntree);
+ set_default_value(input, *b_input, b_data, b_ntree);
}
for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
ShaderOutput *output = node_find_output_by_name(node, *b_node, *b_output);
- if (!output) {
+ if(!output) {
/* XXX should not happen, report error? */
continue;
}
@@ -951,6 +1011,10 @@ static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, Sha
BL::NodeTree::links_iterator b_link;
for(b_ntree.links.begin(b_link); b_link != b_ntree.links.end(); ++b_link) {
+ /* Ignore invalid links to avoid unwanted cycles created in graph. */
+ if(!b_link->is_valid()) {
+ continue;
+ }
/* get blender link data */
BL::NodeSocket b_from_sock = b_link->from_socket();
BL::NodeSocket b_to_sock = b_link->to_socket();
@@ -959,10 +1023,10 @@ static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, Sha
ShaderInput *input = 0;
PtrOutputMap::iterator output_it = output_map.find(b_from_sock.ptr.data);
- if (output_it != output_map.end())
+ if(output_it != output_map.end())
output = output_it->second;
PtrInputMap::iterator input_it = input_map.find(b_to_sock.ptr.data);
- if (input_it != input_map.end())
+ if(input_it != input_map.end())
input = input_it->second;
/* either node may be NULL when the node was not exported, typically
@@ -972,10 +1036,22 @@ static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, Sha
}
}
-static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, ShaderGraph *graph, BL::ShaderNodeTree b_ntree)
+static void add_nodes(Scene *scene,
+ BL::RenderEngine b_engine,
+ BL::BlendData b_data,
+ BL::Scene b_scene,
+ ShaderGraph *graph,
+ BL::ShaderNodeTree b_ntree)
{
static const ProxyMap empty_proxy_map;
- add_nodes(scene, b_data, b_scene, graph, b_ntree, empty_proxy_map, empty_proxy_map);
+ add_nodes(scene,
+ b_engine,
+ b_data,
+ b_scene,
+ graph,
+ b_ntree,
+ empty_proxy_map,
+ empty_proxy_map);
}
/* Sync Materials */
@@ -1001,7 +1077,7 @@ void BlenderSync::sync_materials(bool update_all)
if(b_mat->use_nodes() && b_mat->node_tree()) {
BL::ShaderNodeTree b_ntree(b_mat->node_tree());
- add_nodes(scene, b_data, b_scene, graph, b_ntree);
+ add_nodes(scene, b_engine, b_data, b_scene, graph, b_ntree);
}
else {
ShaderNode *closure, *out;
@@ -1044,7 +1120,7 @@ void BlenderSync::sync_world(bool update_all)
if(b_world && b_world.use_nodes() && b_world.node_tree()) {
BL::ShaderNodeTree b_ntree(b_world.node_tree());
- add_nodes(scene, b_data, b_scene, graph, b_ntree);
+ add_nodes(scene, b_engine, b_data, b_scene, graph, b_ntree);
/* volume */
PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
@@ -1130,7 +1206,7 @@ void BlenderSync::sync_lamps(bool update_all)
BL::ShaderNodeTree b_ntree(b_lamp->node_tree());
- add_nodes(scene, b_data, b_scene, graph, b_ntree);
+ add_nodes(scene, b_engine, b_data, b_scene, graph, b_ntree);
}
else {
ShaderNode *closure, *out;
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index 985a3cd3d5a..87e2932d6b1 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -36,6 +36,7 @@
#include "util_debug.h"
#include "util_foreach.h"
#include "util_opengl.h"
+#include "util_hash.h"
CCL_NAMESPACE_BEGIN
@@ -111,7 +112,7 @@ bool BlenderSync::sync_recalc()
if(b_ob->is_updated_data()) {
BL::Object::particle_systems_iterator b_psys;
- for (b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys)
+ for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys)
particle_system_map.set_recalc(*b_ob);
}
}
@@ -150,6 +151,7 @@ void BlenderSync::sync_data(BL::SpaceView3D b_v3d, BL::Object b_override, void *
sync_integrator();
sync_film();
sync_shaders();
+ sync_images();
sync_curve_settings();
mesh_synced.clear(); /* use for objects and motion sync */
@@ -194,6 +196,9 @@ void BlenderSync::sync_integrator()
integrator->filter_glossy = get_float(cscene, "blur_glossy");
integrator->seed = get_int(cscene, "seed");
+ if(get_boolean(cscene, "use_animated_seed"))
+ integrator->seed = hash_int_2d(b_scene.frame_current(), get_int(cscene, "seed"));
+
integrator->sampling_pattern = (SamplingPattern)RNA_enum_get(&cscene, "sampling_pattern");
integrator->layer_flag = render_layer.layer;
@@ -360,6 +365,39 @@ void BlenderSync::sync_render_layers(BL::SpaceView3D b_v3d, const char *layer)
}
}
+/* Images */
+void BlenderSync::sync_images()
+{
+ /* Sync is a convention for this API, but currently it frees unused buffers. */
+
+ const bool is_interface_locked = b_engine.render() &&
+ b_engine.render().use_lock_interface();
+ if(is_interface_locked == false && BlenderSession::headless == false) {
+ /* If interface is not locked, it's possible image is needed for
+ * the display.
+ */
+ return;
+ }
+ /* Free buffers used by images which are not needed for render. */
+ BL::BlendData::images_iterator b_image;
+ for(b_data.images.begin(b_image);
+ b_image != b_data.images.end();
+ ++b_image)
+ {
+ /* TODO(sergey): Consider making it an utility function to check
+ * whether image is considered builtin.
+ */
+ const bool is_builtin = b_image->packed_file() ||
+ b_image->source() == BL::Image::source_GENERATED ||
+ b_image->source() == BL::Image::source_MOVIE ||
+ b_engine.is_preview();
+ if(is_builtin == false) {
+ b_image->buffers_free();
+ }
+ /* TODO(sergey): Free builtin images not used by any shader. */
+ }
+}
+
/* Scene Parameters */
SceneParams BlenderSync::get_scene_params(BL::Scene b_scene, bool background, bool is_cpu)
@@ -397,6 +435,8 @@ SceneParams BlenderSync::get_scene_params(BL::Scene b_scene, bool background, bo
params.use_qbvh = false;
}
+ params.use_bvh_triangle_storage = RNA_boolean_get(&cscene, "debug_use_triangle_storage");
+
return params;
}
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
index 6a320ac8085..ef279a4fe63 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -68,7 +68,7 @@ public:
BL::Scene b_scene,
bool background);
static bool get_session_pause(BL::Scene b_scene, bool background);
- static BufferParams get_buffer_params(BL::RenderSettings b_render, BL::Scene b_scene, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, Camera *cam, int width, int height);
+ static BufferParams get_buffer_params(BL::RenderSettings b_render, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, Camera *cam, int width, int height);
private:
/* sync */
@@ -83,18 +83,30 @@ private:
void sync_curve_settings();
void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree);
- Mesh *sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris);
- void sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool motion, int time_index = 0);
- Object *sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob,
- Transform& tfm, uint layer_flag, float motion_time, bool hide_tris);
- void sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object b_ob, Transform& tfm);
- void sync_background_light();
- void sync_mesh_motion(BL::Object b_ob, Object *object, float motion_time);
+ Mesh *sync_mesh(BL::Object b_parent, bool object_updated, bool hide_tris, BL::DupliObject b_dupli_ob = PointerRNA_NULL);
+ void sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_parent, bool motion, int time_index = 0, BL::DupliObject b_dupli_ob = PointerRNA_NULL);
+ Object *sync_object(BL::Object b_parent,
+ int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
+ BL::DupliObject b_dupli_ob,
+ Transform& tfm,
+ uint layer_flag,
+ float motion_time,
+ bool hide_tris,
+ bool use_camera_cull,
+ float camera_cull_margin,
+ bool *use_portal);
+ void sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object b_ob, Transform& tfm, bool *use_portal);
+ void sync_background_light(bool use_portal);
+ void sync_mesh_motion(BL::Object b_parent, Object *object, float motion_time, BL::DupliObject b_dupli_ob = PointerRNA_NULL);
+
void sync_camera_motion(BL::Object b_ob, float motion_time);
/* particles */
bool sync_dupli_particle(BL::Object b_ob, BL::DupliObject b_dup, Object *object);
+ /* Images. */
+ void sync_images();
+
/* util */
void find_shader(BL::ID id, vector<uint>& used_shaders, int default_shader);
bool BKE_object_is_modified(BL::Object b_ob);
@@ -108,7 +120,7 @@ private:
id_map<void*, Shader> shader_map;
id_map<ObjectKey, Object> object_map;
- id_map<void*, Mesh> mesh_map;
+ id_map<MeshKey, Mesh> mesh_map;
id_map<ObjectKey, Light> light_map;
id_map<ParticleSystemKey, ParticleSystem> particle_system_map;
set<Mesh*> mesh_synced;
diff --git a/intern/cycles/blender/blender_texture.cpp b/intern/cycles/blender/blender_texture.cpp
new file mode 100644
index 00000000000..cb4dd1792d0
--- /dev/null
+++ b/intern/cycles/blender/blender_texture.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2011-2015 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 "blender_texture.h"
+
+CCL_NAMESPACE_BEGIN
+
+namespace {
+
+/* Point density helpers. */
+
+static void density_texture_space_invert(float3& loc,
+ float3& size)
+{
+ if(size.x != 0.0f) size.x = 0.5f/size.x;
+ if(size.y != 0.0f) size.y = 0.5f/size.y;
+ if(size.z != 0.0f) size.z = 0.5f/size.z;
+
+ loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
+}
+
+static void density_object_texture_space(BL::Object b_ob,
+ float radius,
+ float3& loc,
+ float3& size)
+{
+ if(b_ob.type() == BL::Object::type_MESH) {
+ BL::Mesh b_mesh(b_ob.data());
+ loc = get_float3(b_mesh.texspace_location());
+ size = get_float3(b_mesh.texspace_size());
+ }
+ else {
+ /* TODO(sergey): Not supported currently. */
+ }
+ /* Adjust texture space to include density points on the boundaries. */
+ size = size + make_float3(radius, radius, radius);
+ density_texture_space_invert(loc, size);
+}
+
+static void density_particle_system_texture_space(
+ BL::Object b_ob,
+ BL::ParticleSystem b_particle_system,
+ float radius,
+ float3& loc,
+ float3& size)
+{
+ if(b_particle_system.settings().type() == BL::ParticleSettings::type_HAIR) {
+ /* TODO(sergey): Not supported currently. */
+ return;
+ }
+ Transform tfm = get_transform(b_ob.matrix_world());
+ Transform itfm = transform_inverse(tfm);
+ float3 min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
+ max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+ float3 particle_size = make_float3(radius, radius, radius);
+ for(int i = 0; i < b_particle_system.particles.length(); ++i) {
+ BL::Particle particle = b_particle_system.particles[i];
+ float3 location = get_float3(particle.location());
+ location = transform_point(&itfm, location);
+ min = ccl::min(min, location - particle_size);
+ max = ccl::max(max, location + particle_size);
+ }
+ /* Calculate texture space from the particle bounds. */
+ loc = (min + max) * 0.5f;
+ size = (max - min) * 0.5f;
+ density_texture_space_invert(loc, size);
+}
+
+} /* namespace */
+
+void point_density_texture_space(BL::ShaderNodeTexPointDensity b_point_density_node,
+ float3& loc,
+ float3& size)
+{
+ /* Fallback values. */
+ loc = make_float3(0.0f, 0.0f, 0.0f);
+ size = make_float3(0.0f, 0.0f, 0.0f);
+ BL::Object b_ob(b_point_density_node.object());
+ if(!b_ob) {
+ return;
+ }
+ if(b_point_density_node.point_source() ==
+ BL::ShaderNodeTexPointDensity::point_source_PARTICLE_SYSTEM)
+ {
+ BL::ParticleSystem b_particle_system(
+ b_point_density_node.particle_system());
+ if(b_particle_system) {
+ density_particle_system_texture_space(b_ob,
+ b_particle_system,
+ b_point_density_node.radius(),
+ loc,
+ size);
+ }
+ }
+ else {
+ density_object_texture_space(b_ob,
+ b_point_density_node.radius(),
+ loc,
+ size);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/render/blackbody.h b/intern/cycles/blender/blender_texture.h
index 6b752a227fa..74fbca02a9e 100644
--- a/intern/cycles/render/blackbody.h
+++ b/intern/cycles/blender/blender_texture.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2013 Blender Foundation
+ * Copyright 2011-2015 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,15 +14,18 @@
* limitations under the License.
*/
-#ifndef __BLACKBODY_H__
-#define __BLACKBODY_H__
+#ifndef __BLENDER_TEXTURE_H__
+#define __BLENDER_TEXTURE_H__
-#include "util_vector.h"
+#include <stdlib.h>
+#include "blender_sync.h"
CCL_NAMESPACE_BEGIN
-vector<float> blackbody_table_build();
+void point_density_texture_space(BL::ShaderNodeTexPointDensity b_point_density_node,
+ float3& loc,
+ float3& size);
CCL_NAMESPACE_END
-#endif /* __BLACKBODY_H__ */
+#endif /* __BLENDER_TEXTURE_H__ */
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index 9f7181cc564..3199afedf3c 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -43,6 +43,18 @@ void python_thread_state_restore(void **python_thread_state);
static inline BL::Mesh object_to_mesh(BL::BlendData data, BL::Object object, BL::Scene scene, bool apply_modifiers, bool render, bool calc_undeformed)
{
BL::Mesh me = data.meshes.new_from_object(scene, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed);
+ if((bool)me) {
+ if(me.use_auto_smooth()) {
+ me.calc_normals_split();
+ }
+ me.calc_tessface(true);
+ }
+ return me;
+}
+
+static inline BL::Mesh dupli_to_mesh(BL::BlendData data, BL::Scene scene, BL::Object parent, BL::DupliObject dob, bool render, bool calc_undeformed)
+{
+ BL::Mesh me = data.meshes.new_from_dupli(scene, parent, dob, (render)? 2: 1, false, calc_undeformed);
if ((bool)me) {
if (me.use_auto_smooth()) {
me.calc_normals_split();
@@ -310,7 +322,7 @@ static inline string get_string(PointerRNA& ptr, const char *name)
char cstrbuf[1024];
char *cstr = RNA_string_get_alloc(&ptr, name, cstrbuf, sizeof(cstrbuf));
string str(cstr);
- if (cstr != cstrbuf)
+ if(cstr != cstrbuf)
MEM_freeN(cstr);
return str;
@@ -388,7 +400,7 @@ static inline BL::SmokeDomainSettings object_smoke_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_SmokeModifier)) {
+ if(b_mod->is_a(&RNA_SmokeModifier)) {
BL::SmokeModifier b_smd(*b_mod);
if(b_smd.smoke_type() == BL::SmokeModifier::smoke_type_DOMAIN)
@@ -568,6 +580,36 @@ struct ObjectKey {
}
};
+/* Mesh Key */
+
+struct MeshKey {
+ void *parent;
+ void *mesh;
+
+ MeshKey(void *mesh_)
+ : parent(NULL), mesh(mesh_)
+ {
+ }
+
+ MeshKey(void *parent_, void *mesh_)
+ : parent(parent_), mesh(mesh_)
+ {
+ }
+
+ bool operator<(const MeshKey& k) const
+ {
+ if(mesh < k.mesh) {
+ return true;
+ }
+ else if(mesh == k.mesh) {
+ return parent < k.parent;
+ return true;
+ }
+
+ return false;
+ }
+};
+
/* Particle System Key */
struct ParticleSystemKey {
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index 9fa602f0952..ff435b751ad 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -28,6 +28,7 @@
#include "util_cache.h"
#include "util_debug.h"
#include "util_foreach.h"
+#include "util_logging.h"
#include "util_map.h"
#include "util_progress.h"
#include "util_system.h"
@@ -106,25 +107,25 @@ bool BVH::cache_read(CacheData& key)
if(!(value.read(pack.root_index) &&
value.read(pack.SAH) &&
value.read(pack.nodes) &&
+ value.read(pack.leaf_nodes) &&
value.read(pack.object_node) &&
value.read(pack.tri_woop) &&
value.read(pack.prim_type) &&
value.read(pack.prim_visibility) &&
value.read(pack.prim_index) &&
- value.read(pack.prim_object) &&
- value.read(pack.is_leaf)))
+ value.read(pack.prim_object)))
{
/* Clear the pack if load failed. */
pack.root_index = 0;
pack.SAH = 0.0f;
pack.nodes.clear();
+ pack.leaf_nodes.clear();
pack.object_node.clear();
pack.tri_woop.clear();
pack.prim_type.clear();
pack.prim_visibility.clear();
pack.prim_index.clear();
pack.prim_object.clear();
- pack.is_leaf.clear();
return false;
}
return true;
@@ -141,13 +142,13 @@ void BVH::cache_write(CacheData& key)
value.add(pack.SAH);
value.add(pack.nodes);
+ value.add(pack.leaf_nodes);
value.add(pack.object_node);
value.add(pack.tri_woop);
value.add(pack.prim_type);
value.add(pack.prim_visibility);
value.add(pack.prim_index);
value.add(pack.prim_object);
- value.add(pack.is_leaf);
Cache::global.insert(key, value);
@@ -284,28 +285,34 @@ void BVH::pack_triangle(int idx, float4 woop[3])
void BVH::pack_primitives()
{
- int nsize = TRI_NODE_SIZE;
+ const int nsize = TRI_NODE_SIZE;
+ const bool use_triangle_storage = params.use_triangle_storage;
size_t tidx_size = pack.prim_index.size();
pack.tri_woop.clear();
- pack.tri_woop.resize(tidx_size * nsize);
+ if (use_triangle_storage) {
+ pack.tri_woop.resize(tidx_size * nsize);
+ }
+ else {
+ pack.tri_woop.resize(0);
+ }
pack.prim_visibility.clear();
pack.prim_visibility.resize(tidx_size);
for(unsigned int i = 0; i < tidx_size; i++) {
if(pack.prim_index[i] != -1) {
- float4 woop[3];
-
- if(pack.prim_type[i] & PRIMITIVE_TRIANGLE) {
- pack_triangle(i, woop);
- }
- else {
- /* Avoid use of uninitialized memory. */
- memset(&woop, 0, sizeof(woop));
+ if(use_triangle_storage) {
+ float4 woop[3];
+ if(pack.prim_type[i] & PRIMITIVE_TRIANGLE) {
+ pack_triangle(i, woop);
+ }
+ else {
+ /* Avoid use of uninitialized memory. */
+ memset(&woop, 0, sizeof(woop));
+ }
+ memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3);
}
- memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3);
-
int tob = pack.prim_object[i];
Object *ob = objects[tob];
pack.prim_visibility[i] = ob->visibility;
@@ -314,7 +321,9 @@ void BVH::pack_primitives()
pack.prim_visibility[i] |= PATH_RAY_CURVE;
}
else {
- memset(&pack.tri_woop[i * nsize], 0, sizeof(float4)*3);
+ if(use_triangle_storage) {
+ memset(&pack.tri_woop[i * nsize], 0, sizeof(float4)*3);
+ }
pack.prim_visibility[i] = 0;
}
}
@@ -322,13 +331,14 @@ void BVH::pack_primitives()
/* Pack Instances */
-void BVH::pack_instances(size_t nodes_size)
+void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
{
/* The BVH's for instances are built separately, but for traversal all
* BVH's are stored in global arrays. This function merges them into the
* top level BVH, adjusting indexes and offsets where appropriate. */
bool use_qbvh = params.use_qbvh;
size_t nsize = (use_qbvh)? BVH_QNODE_SIZE: BVH_NODE_SIZE;
+ size_t nsize_leaf = (use_qbvh)? BVH_QNODE_LEAF_SIZE: BVH_NODE_LEAF_SIZE;
/* adjust primitive index to point to the triangle in the global array, for
* meshes with transform applied and already in the top level BVH */
@@ -343,6 +353,7 @@ void BVH::pack_instances(size_t nodes_size)
/* track offsets of instanced BVH data in global array */
size_t prim_offset = pack.prim_index.size();
size_t nodes_offset = nodes_size;
+ size_t nodes_leaf_offset = leaf_nodes_size;
/* clear array that gives the node indexes for instanced objects */
pack.object_node.clear();
@@ -354,6 +365,7 @@ void BVH::pack_instances(size_t nodes_size)
size_t pack_prim_index_offset = prim_index_size;
size_t pack_tri_woop_offset = tri_woop_size;
size_t pack_nodes_offset = nodes_size;
+ size_t pack_leaf_nodes_offset = leaf_nodes_size;
size_t object_offset = 0;
map<Mesh*, int> mesh_map;
@@ -367,6 +379,7 @@ void BVH::pack_instances(size_t nodes_size)
prim_index_size += bvh->pack.prim_index.size();
tri_woop_size += bvh->pack.tri_woop.size();
nodes_size += bvh->pack.nodes.size();
+ leaf_nodes_size += bvh->pack.leaf_nodes.size();
mesh_map[mesh] = 1;
}
@@ -381,6 +394,7 @@ void BVH::pack_instances(size_t nodes_size)
pack.prim_visibility.resize(prim_index_size);
pack.tri_woop.resize(tri_woop_size);
pack.nodes.resize(nodes_size);
+ pack.leaf_nodes.resize(leaf_nodes_size);
pack.object_node.resize(objects.size());
int *pack_prim_index = (pack.prim_index.size())? &pack.prim_index[0]: NULL;
@@ -389,6 +403,7 @@ void BVH::pack_instances(size_t nodes_size)
uint *pack_prim_visibility = (pack.prim_visibility.size())? &pack.prim_visibility[0]: NULL;
float4 *pack_tri_woop = (pack.tri_woop.size())? &pack.tri_woop[0]: NULL;
int4 *pack_nodes = (pack.nodes.size())? &pack.nodes[0]: NULL;
+ int4 *pack_leaf_nodes = (pack.leaf_nodes.size())? &pack.leaf_nodes[0]: NULL;
/* merge */
foreach(Object *ob, objects) {
@@ -414,12 +429,13 @@ void BVH::pack_instances(size_t nodes_size)
BVH *bvh = mesh->bvh;
int noffset = nodes_offset/nsize;
+ int noffset_leaf = nodes_leaf_offset/nsize_leaf;
int mesh_tri_offset = mesh->tri_offset;
int mesh_curve_offset = mesh->curve_offset;
/* fill in node indexes for instances */
- if((bvh->pack.is_leaf.size() != 0) && bvh->pack.is_leaf[0])
- pack.object_node[object_offset++] = -noffset-1;
+ if(bvh->pack.root_index == -1)
+ pack.object_node[object_offset++] = -noffset_leaf-1;
else
pack.object_node[object_offset++] = noffset;
@@ -453,6 +469,18 @@ void BVH::pack_instances(size_t nodes_size)
}
/* merge nodes */
+ if(bvh->pack.leaf_nodes.size()) {
+ int4 *leaf_nodes_offset = &bvh->pack.leaf_nodes[0];
+ size_t leaf_nodes_offset_size = bvh->pack.leaf_nodes.size();
+ for(size_t i = 0, j = 0; i < leaf_nodes_offset_size; i+=nsize_leaf, j++) {
+ int4 data = leaf_nodes_offset[i];
+ data.x += prim_offset;
+ data.y += prim_offset;
+ pack_leaf_nodes[pack_leaf_nodes_offset] = data;
+ pack_leaf_nodes_offset += nsize_leaf;
+ }
+ }
+
if(bvh->pack.nodes.size()) {
/* For QBVH we're packing a child bbox into 6 float4,
* and for regular BVH they're packed into 3 float4.
@@ -460,7 +488,6 @@ void BVH::pack_instances(size_t nodes_size)
size_t nsize_bbox = (use_qbvh)? 6: 3;
int4 *bvh_nodes = &bvh->pack.nodes[0];
size_t bvh_nodes_size = bvh->pack.nodes.size();
- bool *bvh_is_leaf = (bvh->pack.is_leaf.size() != 0) ? &bvh->pack.is_leaf[0] : NULL;
for(size_t i = 0, j = 0; i < bvh_nodes_size; i+=nsize, j++) {
memcpy(pack_nodes + pack_nodes_offset, bvh_nodes + i, nsize_bbox*sizeof(int4));
@@ -468,18 +495,12 @@ void BVH::pack_instances(size_t nodes_size)
/* modify offsets into arrays */
int4 data = bvh_nodes[i + nsize_bbox];
- if(bvh_is_leaf && bvh_is_leaf[j]) {
- data.x += prim_offset;
- data.y += prim_offset;
- }
- else {
- data.x += (data.x < 0)? -noffset: noffset;
- data.y += (data.y < 0)? -noffset: noffset;
+ data.x += (data.x < 0)? -noffset_leaf: noffset;
+ data.y += (data.y < 0)? -noffset_leaf: noffset;
- if(use_qbvh) {
- data.z += (data.z < 0)? -noffset: noffset;
- data.w += (data.w < 0)? -noffset: noffset;
- }
+ if(use_qbvh) {
+ data.z += (data.z < 0)? -noffset_leaf: noffset;
+ data.w += (data.w < 0)? -noffset_leaf: noffset;
}
pack_nodes[pack_nodes_offset + nsize_bbox] = data;
@@ -496,6 +517,7 @@ void BVH::pack_instances(size_t nodes_size)
}
nodes_offset += bvh->pack.nodes.size();
+ nodes_leaf_offset += bvh->pack.leaf_nodes.size();
prim_offset += bvh->pack.prim_index.size();
}
}
@@ -509,20 +531,24 @@ RegularBVH::RegularBVH(const BVHParams& params_, const vector<Object*>& objects_
void RegularBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
{
+ float4 data[BVH_NODE_LEAF_SIZE];
+ memset(data, 0, sizeof(data));
if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1) {
/* object */
- pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, ~(leaf->m_lo), 0,
- leaf->m_visibility, leaf->m_visibility);
+ data[0].x = __int_as_float(~(leaf->m_lo));
+ data[0].y = __int_as_float(0);
}
else {
- int prim_type = leaf->num_triangles() ? pack.prim_type[leaf->m_lo] : 0;
- /* Triangle/curve primitive leaf. */
- pack_node(e.idx, leaf->m_bounds, leaf->m_bounds,
- leaf->m_lo, leaf->m_hi,
- leaf->m_visibility,
- prim_type);
+ /* triangle */
+ data[0].x = __int_as_float(leaf->m_lo);
+ data[0].y = __int_as_float(leaf->m_hi);
+ }
+ data[0].z = __uint_as_float(leaf->m_visibility);
+ if(leaf->num_triangles() != 0) {
+ data[0].w = __uint_as_float(pack.prim_type[leaf->m_lo]);
}
+ memcpy(&pack.leaf_nodes[e.idx * BVH_NODE_LEAF_SIZE], data, sizeof(float4)*BVH_NODE_LEAF_SIZE);
}
void RegularBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1)
@@ -545,31 +571,36 @@ void RegularBVH::pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int
void RegularBVH::pack_nodes(const BVHNode *root)
{
- size_t node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
+ size_t tot_node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
+ size_t leaf_node_size = root->getSubtreeSize(BVH_STAT_LEAF_COUNT);
+ size_t node_size = tot_node_size - leaf_node_size;
/* resize arrays */
pack.nodes.clear();
- pack.is_leaf.clear();
- pack.is_leaf.resize(node_size);
/* for top level BVH, first merge existing BVH's so we know the offsets */
- if(params.top_level)
- pack_instances(node_size*BVH_NODE_SIZE);
- else
+ if(params.top_level) {
+ pack_instances(node_size*BVH_NODE_SIZE,
+ leaf_node_size*BVH_NODE_LEAF_SIZE);
+ }
+ else {
pack.nodes.resize(node_size*BVH_NODE_SIZE);
+ pack.leaf_nodes.resize(leaf_node_size*BVH_NODE_LEAF_SIZE);
+ }
- int nextNodeIdx = 0;
+ int nextNodeIdx = 0, nextLeafNodeIdx = 0;
vector<BVHStackEntry> stack;
stack.reserve(BVHParams::MAX_DEPTH*2);
- stack.push_back(BVHStackEntry(root, nextNodeIdx++));
+ if(root->is_leaf())
+ stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++));
+ else
+ stack.push_back(BVHStackEntry(root, nextNodeIdx++));
while(stack.size()) {
BVHStackEntry e = stack.back();
stack.pop_back();
- pack.is_leaf[e.idx] = e.node->is_leaf();
-
if(e.node->is_leaf()) {
/* leaf node */
const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node);
@@ -577,15 +608,17 @@ void RegularBVH::pack_nodes(const BVHNode *root)
}
else {
/* innner node */
- stack.push_back(BVHStackEntry(e.node->get_child(0), nextNodeIdx++));
- stack.push_back(BVHStackEntry(e.node->get_child(1), nextNodeIdx++));
+ int idx0 = (e.node->get_child(0)->is_leaf())? (nextLeafNodeIdx++) : (nextNodeIdx++);
+ int idx1 = (e.node->get_child(1)->is_leaf())? (nextLeafNodeIdx++) : (nextNodeIdx++);
+ stack.push_back(BVHStackEntry(e.node->get_child(0), idx0));
+ stack.push_back(BVHStackEntry(e.node->get_child(1), idx1));
pack_inner(e, stack[stack.size()-2], stack[stack.size()-1]);
}
}
/* root index to start traversal at, to handle case of single leaf node */
- pack.root_index = (pack.is_leaf[0])? -1: 0;
+ pack.root_index = (root->is_leaf())? -1: 0;
}
void RegularBVH::refit_nodes()
@@ -594,17 +627,15 @@ void RegularBVH::refit_nodes()
BoundBox bbox = BoundBox::empty;
uint visibility = 0;
- refit_node(0, (pack.is_leaf[0])? true: false, bbox, visibility);
+ refit_node(0, (pack.root_index == -1)? true: false, bbox, visibility);
}
void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
{
- int4 *data = &pack.nodes[idx*BVH_NODE_SIZE];
-
- int c0 = data[3].x;
- int c1 = data[3].y;
-
if(leaf) {
+ int4 *data = &pack.leaf_nodes[idx*BVH_NODE_LEAF_SIZE];
+ int c0 = data[0].x;
+ int c1 = data[0].y;
/* refit leaf node */
for(int prim = c0; prim < c1; prim++) {
int pidx = pack.prim_index[prim];
@@ -638,7 +669,7 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
size_t steps = mesh->motion_steps - 1;
float4 *key_steps = attr->data_float4();
- for (size_t i = 0; i < steps; i++)
+ for(size_t i = 0; i < steps; i++)
curve.bounds_grow(k, key_steps + i*mesh_size, bbox);
}
}
@@ -660,7 +691,7 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
size_t steps = mesh->motion_steps - 1;
float3 *vert_steps = attr->data_float3();
- for (size_t i = 0; i < steps; i++)
+ for(size_t i = 0; i < steps; i++)
triangle.bounds_grow(vert_steps + i*mesh_size, bbox);
}
}
@@ -670,9 +701,20 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
visibility |= ob->visibility;
}
- pack_node(idx, bbox, bbox, c0, c1, visibility, data[3].w);
+ /* TODO(sergey): De-duplicate with pack_leaf(). */
+ float4 leaf_data[BVH_NODE_LEAF_SIZE];
+ leaf_data[0].x = __int_as_float(c0);
+ 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);
}
else {
+ int4 *data = &pack.nodes[idx*BVH_NODE_SIZE];
+ int c0 = data[3].x;
+ int c1 = data[3].y;
/* refit inner node, set bbox from children */
BoundBox bbox0 = BoundBox::empty, bbox1 = BoundBox::empty;
uint visibility0 = 0, visibility1 = 0;
@@ -698,26 +740,24 @@ QBVH::QBVH(const BVHParams& params_, const vector<Object*>& objects_)
void QBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
{
- float4 data[BVH_QNODE_SIZE];
-
+ float4 data[BVH_QNODE_LEAF_SIZE];
memset(data, 0, sizeof(data));
-
if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1) {
/* object */
- data[6].x = __int_as_float(~(leaf->m_lo));
- data[6].y = __int_as_float(0);
+ data[0].x = __int_as_float(~(leaf->m_lo));
+ data[0].y = __int_as_float(0);
}
else {
/* triangle */
- data[6].x = __int_as_float(leaf->m_lo);
- data[6].y = __int_as_float(leaf->m_hi);
+ data[0].x = __int_as_float(leaf->m_lo);
+ data[0].y = __int_as_float(leaf->m_hi);
}
- data[6].z = __uint_as_float(leaf->m_visibility);
+ data[0].z = __uint_as_float(leaf->m_visibility);
if(leaf->num_triangles() != 0) {
- data[6].w = __uint_as_float(pack.prim_type[leaf->m_lo]);
+ data[0].w = __uint_as_float(pack.prim_type[leaf->m_lo]);
}
- memcpy(&pack.nodes[e.idx * BVH_QNODE_SIZE], data, sizeof(float4)*BVH_QNODE_SIZE);
+ memcpy(&pack.leaf_nodes[e.idx * BVH_QNODE_LEAF_SIZE], data, sizeof(float4)*BVH_QNODE_LEAF_SIZE);
}
void QBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num)
@@ -761,31 +801,39 @@ void QBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num)
void QBVH::pack_nodes(const BVHNode *root)
{
- size_t node_size = root->getSubtreeSize(BVH_STAT_QNODE_COUNT);
+ size_t tot_node_size = root->getSubtreeSize(BVH_STAT_QNODE_COUNT);
+ size_t leaf_node_size = root->getSubtreeSize(BVH_STAT_LEAF_COUNT);
+ size_t node_size = tot_node_size - leaf_node_size;
/* resize arrays */
pack.nodes.clear();
- pack.is_leaf.clear();
- pack.is_leaf.resize(node_size);
+ pack.leaf_nodes.clear();
/* for top level BVH, first merge existing BVH's so we know the offsets */
- if(params.top_level)
- pack_instances(node_size*BVH_QNODE_SIZE);
- else
+ if(params.top_level) {
+ pack_instances(node_size*BVH_QNODE_SIZE,
+ leaf_node_size*BVH_QNODE_LEAF_SIZE);
+ }
+ else {
pack.nodes.resize(node_size*BVH_QNODE_SIZE);
+ pack.leaf_nodes.resize(leaf_node_size*BVH_QNODE_LEAF_SIZE);
+ }
- int nextNodeIdx = 0;
+ int nextNodeIdx = 0, nextLeafNodeIdx = 0;
vector<BVHStackEntry> stack;
stack.reserve(BVHParams::MAX_DEPTH*2);
- stack.push_back(BVHStackEntry(root, nextNodeIdx++));
+ if(root->is_leaf()) {
+ stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++));
+ }
+ else {
+ stack.push_back(BVHStackEntry(root, nextNodeIdx++));
+ }
while(stack.size()) {
BVHStackEntry e = stack.back();
stack.pop_back();
- pack.is_leaf[e.idx] = e.node->is_leaf();
-
if(e.node->is_leaf()) {
/* leaf node */
const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node);
@@ -818,8 +866,16 @@ void QBVH::pack_nodes(const BVHNode *root)
}
/* push entries on the stack */
- for(int i = 0; i < numnodes; i++)
- stack.push_back(BVHStackEntry(nodes[i], nextNodeIdx++));
+ for(int i = 0; i < numnodes; i++) {
+ int idx;
+ if(nodes[i]->is_leaf()) {
+ idx = nextLeafNodeIdx++;
+ }
+ else {
+ idx = nextNodeIdx++;
+ }
+ stack.push_back(BVHStackEntry(nodes[i], idx));
+ }
/* set node */
pack_inner(e, &stack[stack.size()-numnodes], numnodes);
@@ -827,7 +883,7 @@ void QBVH::pack_nodes(const BVHNode *root)
}
/* root index to start traversal at, to handle case of single leaf node */
- pack.root_index = (pack.is_leaf[0])? -1: 0;
+ pack.root_index = (root->is_leaf())? -1: 0;
}
void QBVH::refit_nodes()
@@ -836,14 +892,14 @@ void QBVH::refit_nodes()
BoundBox bbox = BoundBox::empty;
uint visibility = 0;
- refit_node(0, (pack.is_leaf[0])? true: false, bbox, visibility);
+ refit_node(0, (pack.root_index == -1)? true: false, bbox, visibility);
}
void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
{
- int4 *data = &pack.nodes[idx*BVH_QNODE_SIZE];
- int4 c = data[6];
if(leaf) {
+ int4 *data = &pack.leaf_nodes[idx*BVH_QNODE_LEAF_SIZE];
+ int4 c = data[0];
/* Refit leaf node. */
for(int prim = c.x; prim < c.y; prim++) {
int pidx = pack.prim_index[prim];
@@ -877,7 +933,7 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
size_t steps = mesh->motion_steps - 1;
float4 *key_steps = attr->data_float4();
- for (size_t i = 0; i < steps; i++)
+ for(size_t i = 0; i < steps; i++)
curve.bounds_grow(k, key_steps + i*mesh_size, bbox);
}
}
@@ -899,7 +955,7 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
size_t steps = mesh->motion_steps - 1;
float3 *vert_steps = attr->data_float3();
- for (size_t i = 0; i < steps; i++)
+ for(size_t i = 0; i < steps; i++)
triangle.bounds_grow(vert_steps + i*mesh_size, bbox);
}
}
@@ -919,17 +975,18 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
*
* Same applies to the inner nodes case below.
*/
- float4 leaf_data[BVH_QNODE_SIZE];
- memset(leaf_data, 0, sizeof(leaf_data));
- leaf_data[6].x = __int_as_float(c.x);
- leaf_data[6].y = __int_as_float(c.y);
- leaf_data[6].z = __uint_as_float(visibility);
- leaf_data[6].w = __uint_as_float(c.w);
- memcpy(&pack.nodes[idx * BVH_QNODE_SIZE],
+ float4 leaf_data[BVH_QNODE_LEAF_SIZE];
+ leaf_data[0].x = __int_as_float(c.x);
+ leaf_data[0].y = __int_as_float(c.y);
+ leaf_data[0].z = __uint_as_float(visibility);
+ leaf_data[0].w = __uint_as_float(c.w);
+ memcpy(&pack.leaf_nodes[idx * BVH_QNODE_LEAF_SIZE],
leaf_data,
- sizeof(float4)*BVH_QNODE_SIZE);
+ sizeof(float4)*BVH_QNODE_LEAF_SIZE);
}
else {
+ int4 *data = &pack.nodes[idx*BVH_QNODE_SIZE];
+ int4 c = data[6];
/* Refit inner node, set bbox from children. */
BoundBox child_bbox[4] = {BoundBox::empty,
BoundBox::empty,
diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h
index 40f039541eb..669d2ccdcd5 100644
--- a/intern/cycles/bvh/bvh.h
+++ b/intern/cycles/bvh/bvh.h
@@ -36,7 +36,9 @@ class Object;
class Progress;
#define BVH_NODE_SIZE 4
+#define BVH_NODE_LEAF_SIZE 1
#define BVH_QNODE_SIZE 7
+#define BVH_QNODE_LEAF_SIZE 1
#define BVH_ALIGN 4096
#define TRI_NODE_SIZE 3
@@ -47,7 +49,9 @@ class Progress;
struct PackedBVH {
/* BVH nodes storage, one node is 4x int4, and contains two bounding boxes,
* and child, triangle or object indexes depending on the node type */
- array<int4> nodes;
+ array<int4> nodes;
+ /* BVH leaf nodes storage. */
+ array<int4> leaf_nodes;
/* object index to BVH node index mapping for instances */
array<int> object_node;
/* precomputed triangle intersection data, one triangle is 4x float4 */
@@ -61,9 +65,6 @@ struct PackedBVH {
array<int> prim_index;
/* mapping from BVH primitive index, to the object id of that primitive. */
array<int> prim_object;
- /* quick array to lookup if a node is a leaf, not used for traversal, only
- * for instance BVH merging */
- array<bool> is_leaf;
/* index of the root node. */
int root_index;
@@ -108,7 +109,7 @@ protected:
void pack_triangle(int idx, float4 woop[3]);
/* merge instance BVH's */
- void pack_instances(size_t nodes_size);
+ void pack_instances(size_t nodes_size, size_t leaf_nodes_size);
/* for subclasses to implement */
virtual void pack_nodes(const BVHNode *root) = 0;
diff --git a/intern/cycles/bvh/bvh_binning.cpp b/intern/cycles/bvh/bvh_binning.cpp
index bd37ffbcf38..db96490a36f 100644
--- a/intern/cycles/bvh/bvh_binning.cpp
+++ b/intern/cycles/bvh/bvh_binning.cpp
@@ -29,10 +29,10 @@ CCL_NAMESPACE_BEGIN
/* SSE replacements */
-__forceinline void prefetch_L1 (const void* ptr) { }
-__forceinline void prefetch_L2 (const void* ptr) { }
-__forceinline void prefetch_L3 (const void* ptr) { }
-__forceinline void prefetch_NTA(const void* ptr) { }
+__forceinline void prefetch_L1 (const void* /*ptr*/) { }
+__forceinline void prefetch_L2 (const void* /*ptr*/) { }
+__forceinline void prefetch_L3 (const void* /*ptr*/) { }
+__forceinline void prefetch_NTA(const void* /*ptr*/) { }
template<size_t src> __forceinline float extract(const int4& b)
{ return b[src]; }
diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp
index 4ce8f787169..5baf94918b4 100644
--- a/intern/cycles/bvh/bvh_build.cpp
+++ b/intern/cycles/bvh/bvh_build.cpp
@@ -42,7 +42,7 @@ ccl_device_inline int bitscan(int value)
{
assert(value != 0);
int bit = 0;
- while (value >>= 1) {
+ while(value >>= 1) {
++bit;
}
return bit;
@@ -136,7 +136,7 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh,
size_t steps = mesh->motion_steps - 1;
float4 *key_steps = curve_attr_mP->data_float4();
- for (size_t i = 0; i < steps; i++)
+ for(size_t i = 0; i < steps; i++)
curve.bounds_grow(k, key_steps + i*mesh_size, bounds);
type = PRIMITIVE_MOTION_CURVE;
@@ -577,17 +577,22 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range)
return new InnerNode(range.bounds(), leaves[0], leaves[1]);
}
else if(num_leaves == 3) {
- BoundBox inner_bounds = merge(bounds[1], bounds[2]);
+ BoundBox inner_bounds = merge(leaves[1]->m_bounds, leaves[2]->m_bounds);
BVHNode *inner = new InnerNode(inner_bounds, leaves[1], leaves[2]);
return new InnerNode(range.bounds(), leaves[0], inner);
- } else /*if(num_leaves == 4)*/ {
+ } else {
/* Shpuld be doing more branches if more primitive types added. */
- assert(num_leaves == 4);
- BoundBox inner_bounds_a = merge(bounds[0], bounds[1]);
- BoundBox inner_bounds_b = merge(bounds[2], bounds[3]);
+ assert(num_leaves <= 5);
+ BoundBox inner_bounds_a = merge(leaves[0]->m_bounds, leaves[1]->m_bounds);
+ BoundBox inner_bounds_b = merge(leaves[2]->m_bounds, leaves[3]->m_bounds);
BVHNode *inner_a = new InnerNode(inner_bounds_a, leaves[0], leaves[1]);
BVHNode *inner_b = new InnerNode(inner_bounds_b, leaves[2], leaves[3]);
- return new InnerNode(range.bounds(), inner_a, inner_b);
+ BoundBox inner_bounds_c = merge(inner_a->m_bounds, inner_b->m_bounds);
+ BVHNode *inner_c = new InnerNode(inner_bounds_c, inner_a, inner_b);
+ if(num_leaves == 5) {
+ return new InnerNode(range.bounds(), inner_c, leaves[4]);
+ }
+ return inner_c;
}
}
diff --git a/intern/cycles/bvh/bvh_node.h b/intern/cycles/bvh/bvh_node.h
index 1656bb367a4..44f5518229b 100644
--- a/intern/cycles/bvh/bvh_node.h
+++ b/intern/cycles/bvh/bvh_node.h
@@ -24,8 +24,7 @@
CCL_NAMESPACE_BEGIN
-enum BVH_STAT
-{
+enum BVH_STAT {
BVH_STAT_NODE_COUNT,
BVH_STAT_INNER_COUNT,
BVH_STAT_LEAF_COUNT,
diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h
index 99bfd9449da..892fd906e77 100644
--- a/intern/cycles/bvh/bvh_params.h
+++ b/intern/cycles/bvh/bvh_params.h
@@ -49,6 +49,9 @@ public:
/* QBVH */
bool use_qbvh;
+ /* Use pre-aligned tringle storage for faster lookup. */
+ bool use_triangle_storage;
+
/* fixed parameters */
enum {
MAX_DEPTH = 64,
@@ -73,6 +76,7 @@ public:
top_level = false;
use_cache = false;
use_qbvh = false;
+ use_triangle_storage = true;
}
/* SAH costs */
@@ -113,7 +117,9 @@ public:
__forceinline int prim_type() const { return type; }
BVHReference& operator=(const BVHReference &arg) {
- memcpy(this, &arg, sizeof(BVHReference));
+ if(&arg != this) {
+ memcpy(this, &arg, sizeof(BVHReference));
+ }
return *this;
}
diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp
index 07c35c08c18..2290c4143ad 100644
--- a/intern/cycles/bvh/bvh_split.cpp
+++ b/intern/cycles/bvh/bvh_split.cpp
@@ -253,7 +253,7 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH
Object *ob = builder->objects[ref.prim_object()];
const Mesh *mesh = ob->mesh;
- if (ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) {
+ if(ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) {
const int *inds = mesh->triangles[ref.prim_index()].v;
const float3 *verts = &mesh->verts[0];
const float3* v1 = &verts[inds[2]];
diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake
index d7c59f42a5e..13196e2ba6b 100644
--- a/intern/cycles/cmake/external_libs.cmake
+++ b/intern/cycles/cmake/external_libs.cmake
@@ -30,7 +30,7 @@ if(NOT CYCLES_STANDALONE_REPOSITORY)
set(GLEW_INCLUDE_DIR "${GLEW_INCLUDE_PATH}")
endif()
-if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI)
+if(WITH_CYCLES_STANDALONE)
set(CYCLES_APP_GLEW_LIBRARY ${BLENDER_GLEW_LIBRARIES})
endif()
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp
index 3a33b8fb68b..5cad8e1b49c 100644
--- a/intern/cycles/device/device.cpp
+++ b/intern/cycles/device/device.cpp
@@ -33,6 +33,13 @@ CCL_NAMESPACE_BEGIN
/* Device */
+Device::~Device()
+{
+ if(!background && vertex_buffer != 0) {
+ glDeleteBuffers(1, &vertex_buffer);
+ }
+}
+
void Device::pixels_alloc(device_memory& mem)
{
mem_alloc(mem, MEM_READ_WRITE);
@@ -51,7 +58,7 @@ void Device::pixels_free(device_memory& mem)
mem_free(mem);
}
-void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int dy, int width, int height, bool transparent,
+void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int dx, int dy, int width, int height, bool transparent,
const DeviceDrawParams &draw_params)
{
pixels_copy_from(rgba, y, w, h);
@@ -67,6 +74,9 @@ void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int dy, int w
/* for multi devices, this assumes the inefficient method that we allocate
* all pixels on the device even though we only render to a subset */
GLhalf *data_pointer = (GLhalf*)rgba.data_pointer;
+ float vbuffer[16], *basep;
+ float *vp = NULL;
+
data_pointer += 4*y*w;
/* draw half float texture, GLSL shader for display transform assumed to be bound */
@@ -83,23 +93,63 @@ void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int dy, int w
draw_params.bind_display_space_shader_cb();
}
- glPushMatrix();
- glTranslatef(0.0f, (float)dy, 0.0f);
+ if(GLEW_VERSION_1_5) {
+ if(!vertex_buffer)
+ glGenBuffers(1, &vertex_buffer);
+
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
+ /* invalidate old contents - avoids stalling if buffer is still waiting in queue to be rendered */
+ glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW);
- glBegin(GL_QUADS);
-
- glTexCoord2f(0.0f, 0.0f);
- glVertex2f(0.0f, 0.0f);
- glTexCoord2f(1.0f, 0.0f);
- glVertex2f((float)width, 0.0f);
- glTexCoord2f(1.0f, 1.0f);
- glVertex2f((float)width, (float)height);
- glTexCoord2f(0.0f, 1.0f);
- glVertex2f(0.0f, (float)height);
+ vp = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
- glEnd();
+ basep = NULL;
+ }
+ else {
+ basep = vbuffer;
+ vp = vbuffer;
+ }
- glPopMatrix();
+ if(vp) {
+ /* texture coordinate - vertex pair */
+ vp[0] = 0.0f;
+ vp[1] = 0.0f;
+ vp[2] = dx;
+ vp[3] = dy;
+
+ vp[4] = 1.0f;
+ vp[5] = 0.0f;
+ vp[6] = (float)width + dx;
+ vp[7] = dy;
+
+ vp[8] = 1.0f;
+ vp[9] = 1.0f;
+ vp[10] = (float)width + dx;
+ vp[11] = (float)height + dy;
+
+ vp[12] = 0.0f;
+ vp[13] = 1.0f;
+ vp[14] = dx;
+ vp[15] = (float)height + dy;
+
+ if(vertex_buffer)
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+ }
+
+ glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), basep);
+ glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), ((char *)basep) + 2 * sizeof(float));
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ if(vertex_buffer) {
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
if(draw_params.unbind_display_space_shader_cb) {
draw_params.unbind_display_space_shader_cb();
@@ -113,7 +163,7 @@ void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int dy, int w
/* fallback for old graphics cards that don't support GLSL, half float,
* and non-power-of-two textures */
glPixelZoom((float)width/(float)w, (float)height/(float)h);
- glRasterPos2f(0, dy);
+ glRasterPos2f(dx, dy);
uint8_t *pixels = (uint8_t*)rgba.data_pointer;
@@ -277,13 +327,10 @@ string Device::device_capabilities()
#endif
#ifdef WITH_OPENCL
- /* TODO(sergey): Needs proper usable implementation. */
- /*
if(device_opencl_init()) {
capabilities += "\nOpenCL device capabilities:\n";
capabilities += device_opencl_capabilities();
}
- */
#endif
return capabilities;
diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index 7c17f7f4112..6b4a190bbf0 100644
--- a/intern/cycles/device/device.h
+++ b/intern/cycles/device/device.h
@@ -55,6 +55,7 @@ public:
bool advanced_shading;
bool pack_images;
bool extended_images; /* flag for GPU and Multi device */
+ bool use_split_kernel; /* Denotes if the device is going to run cycles using split-kernel */
vector<DeviceInfo> multi_devices;
DeviceInfo()
@@ -66,25 +67,76 @@ public:
advanced_shading = true;
pack_images = false;
extended_images = false;
+ use_split_kernel = false;
+ }
+};
+
+class DeviceRequestedFeatures {
+public:
+ /* Use experimental feature set. */
+ bool experimental;
+
+ /* Maximum number of closures in shader trees. */
+ int max_closure;
+
+ /* Selective nodes compilation. */
+
+ /* Identifier of a node group up to which all the nodes needs to be
+ * compiled in. Nodes from higher group indices will be ignores.
+ */
+ int max_nodes_group;
+
+ /* Features bitfield indicating which features from the requested group
+ * will be compiled in. Nodes which corresponds to features which are not
+ * in this bitfield will be ignored even if they're in the requested group.
+ */
+ int nodes_features;
+
+ /* BVH/sampling kernel features. */
+ bool use_hair;
+ bool use_object_motion;
+ bool use_camera_motion;
+
+ DeviceRequestedFeatures()
+ {
+ /* TODO(sergey): Find more meaningful defaults. */
+ experimental = false;
+ max_closure = 0;
+ max_nodes_group = 0;
+ nodes_features = 0;
+ use_hair = false;
+ use_object_motion = false;
+ use_camera_motion = false;
+ }
+
+ bool modified(const DeviceRequestedFeatures& requested_features)
+ {
+ return !(experimental == requested_features.experimental &&
+ max_closure == requested_features.max_closure &&
+ max_nodes_group == requested_features.max_nodes_group &&
+ nodes_features == requested_features.nodes_features);
}
};
/* Device */
struct DeviceDrawParams {
- boost::function<void(void)> bind_display_space_shader_cb;
- boost::function<void(void)> unbind_display_space_shader_cb;
+ function<void(void)> bind_display_space_shader_cb;
+ function<void(void)> unbind_display_space_shader_cb;
};
class Device {
protected:
- Device(DeviceInfo& info_, Stats &stats_, bool background) : background(background), info(info_), stats(stats_) {}
+ Device(DeviceInfo& info_, Stats &stats_, bool background) : background(background), vertex_buffer(0), info(info_), stats(stats_) {}
bool background;
string error_msg;
+ /* used for real time display */
+ unsigned int vertex_buffer;
+
public:
- virtual ~Device() {}
+ virtual ~Device();
/* info */
DeviceInfo info;
@@ -106,9 +158,15 @@ public:
virtual void const_copy_to(const char *name, void *host, size_t size) = 0;
/* texture memory */
- virtual void tex_alloc(const char *name, device_memory& mem,
- InterpolationType interpolation = INTERPOLATION_NONE, bool periodic = false) {};
- virtual void tex_free(device_memory& mem) {};
+ virtual void tex_alloc(const char * /*name*/,
+ device_memory& /*mem*/,
+ InterpolationType interpolation = INTERPOLATION_NONE,
+ bool periodic = false)
+ {
+ (void)interpolation; /* Ignored. */
+ (void)periodic; /* Ignored. */
+ };
+ virtual void tex_free(device_memory& /*mem*/) {};
/* pixel memory */
virtual void pixels_alloc(device_memory& mem);
@@ -119,7 +177,9 @@ public:
virtual void *osl_memory() { return NULL; }
/* load/compile kernels, must be called before adding tasks */
- virtual bool load_kernels(bool experimental) { return true; }
+ virtual bool load_kernels(
+ const DeviceRequestedFeatures& /*requested_features*/)
+ { return true; }
/* tasks */
virtual int get_split_task_count(DeviceTask& task) = 0;
@@ -129,7 +189,7 @@ public:
/* opengl drawing */
virtual void draw_pixels(device_memory& mem, int y, int w, int h,
- int dy, int width, int height, bool transparent,
+ int dx, int dy, int width, int height, bool transparent,
const DeviceDrawParams &draw_params);
#ifdef WITH_NETWORK
@@ -138,8 +198,8 @@ public:
#endif
/* multi device */
- virtual void map_tile(Device *sub_device, RenderTile& tile) {}
- virtual int device_number(Device *sub_device) { return 0; }
+ virtual void map_tile(Device * /*sub_device*/, RenderTile& /*tile*/) {}
+ virtual int device_number(Device * /*sub_device*/) { return 0; }
/* static */
static Device *create(DeviceInfo& info, Stats &stats, bool background = true);
diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp
index 9abcf9167d5..013f656e31c 100644
--- a/intern/cycles/device/device_cpu.cpp
+++ b/intern/cycles/device/device_cpu.cpp
@@ -19,6 +19,15 @@
/* So ImathMath is included before our kernel_cpu_compat. */
#ifdef WITH_OSL
+# if defined(_MSC_VER)
+/* Prevent OSL from polluting the context with weird macros from windows.h.
+ * TODO(sergey): Ideally it's only enough to have class/struct declarations in
+ * the header and skip header include here.
+ */
+# define NOGDI
+# define NOMINMAX
+# define WIN32_LEAN_AND_MEAN
+# endif
# include <OSL/oslexec.h>
#endif
@@ -38,6 +47,7 @@
#include "util_debug.h"
#include "util_foreach.h"
#include "util_function.h"
+#include "util_logging.h"
#include "util_opengl.h"
#include "util_progress.h"
#include "util_system.h"
@@ -75,19 +85,21 @@ public:
task_pool.stop();
}
- void mem_alloc(device_memory& mem, MemoryType type)
+ void mem_alloc(device_memory& mem, MemoryType /*type*/)
{
mem.device_pointer = mem.data_pointer;
mem.device_size = mem.memory_size();
stats.mem_alloc(mem.device_size);
}
- void mem_copy_to(device_memory& mem)
+ void mem_copy_to(device_memory& /*mem*/)
{
/* no-op */
}
- void mem_copy_from(device_memory& mem, int y, int w, int h, int elem)
+ void mem_copy_from(device_memory& /*mem*/,
+ int /*y*/, int /*w*/, int /*h*/,
+ int /*elem*/)
{
/* no-op */
}
@@ -111,8 +123,9 @@ public:
kernel_const_copy(&kernel_globals, name, host, size);
}
- void tex_alloc(const char *name, device_memory& mem, InterpolationType interpolation, bool periodic)
+ void tex_alloc(const char *name, device_memory& mem, InterpolationType interpolation, bool /*periodic*/)
{
+ VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
kernel_tex_copy(&kernel_globals, name, mem.data_pointer, mem.data_width, mem.data_height, mem.data_depth, interpolation);
mem.device_pointer = mem.data_pointer;
mem.device_size = mem.memory_size();
@@ -207,7 +220,7 @@ public:
int end_sample = tile.start_sample + tile.num_samples;
for(int sample = start_sample; sample < end_sample; sample++) {
- if (task.get_cancel() || task_pool.canceled()) {
+ if(task.get_cancel() || task_pool.canceled()) {
if(task.need_finish_queue == false)
break;
}
@@ -368,7 +381,7 @@ public:
int get_split_task_count(DeviceTask& task)
{
- if (task.type == DeviceTask::SHADER)
+ if(task.type == DeviceTask::SHADER)
return task.get_subtask_count(TaskScheduler::num_threads(), 256);
else
return task.get_subtask_count(TaskScheduler::num_threads());
diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp
index 79a1a2b7fe1..eb861d79a8c 100644
--- a/intern/cycles/device/device_cuda.cpp
+++ b/intern/cycles/device/device_cuda.cpp
@@ -185,7 +185,7 @@ public:
cuda_assert(cuCtxDestroy(cuContext));
}
- bool support_device(bool experimental)
+ bool support_device(bool /*experimental*/)
{
int major, minor;
cuDeviceComputeCapability(&major, &minor, cuDevId);
@@ -266,7 +266,7 @@ public:
printf("CUDA version %d.%d detected, build may succeed but only CUDA 6.5 is officially supported.\n", cuda_version/10, cuda_version%10);
/* compile */
- string kernel = path_join(kernel_path, "kernel.cu");
+ string kernel = path_join(kernel_path, path_join("kernels", path_join("cuda", "kernel.cu")));
string include = kernel_path;
const int machine = system_cpu_bits();
@@ -281,7 +281,7 @@ public:
nvcc, major, minor, machine, kernel.c_str(), cubin.c_str(), include.c_str(), cuda_version);
if(experimental)
- command += " -D__KERNEL_CUDA_EXPERIMENTAL__";
+ command += " -D__KERNEL_EXPERIMENTAL__";
if(getenv("CYCLES_CUDA_EXTRA_CFLAGS")) {
command += string(" ") + getenv("CYCLES_CUDA_EXTRA_CFLAGS");
@@ -309,18 +309,18 @@ public:
return cubin;
}
- bool load_kernels(bool experimental)
+ bool load_kernels(const DeviceRequestedFeatures& requested_features)
{
/* check if cuda init succeeded */
if(cuContext == 0)
return false;
/* check if GPU is supported */
- if(!support_device(experimental))
+ if(!support_device(requested_features.experimental))
return false;
/* get kernel */
- string cubin = compile_kernel(experimental);
+ string cubin = compile_kernel(requested_features.experimental);
if(cubin == "")
return false;
@@ -331,7 +331,7 @@ public:
string cubin_data;
CUresult result;
- if (path_read_text(cubin, cubin_data))
+ if(path_read_text(cubin, cubin_data))
result = cuModuleLoadData(&cuModule, cubin_data.c_str());
else
result = CUDA_ERROR_FILE_NOT_FOUND;
@@ -344,7 +344,7 @@ public:
return (result == CUDA_SUCCESS);
}
- void mem_alloc(device_memory& mem, MemoryType type)
+ void mem_alloc(device_memory& mem, MemoryType /*type*/)
{
cuda_push_context();
CUdeviceptr device_pointer;
@@ -419,6 +419,7 @@ public:
void tex_alloc(const char *name, device_memory& mem, InterpolationType interpolation, bool periodic)
{
/* todo: support 3D textures, only CPU for now */
+ VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
/* determine format */
CUarray_format_enum format;
@@ -483,7 +484,7 @@ public:
if(interpolation == INTERPOLATION_CLOSEST) {
cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_POINT));
}
- else if (interpolation == INTERPOLATION_LINEAR) {
+ else if(interpolation == INTERPOLATION_LINEAR) {
cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_LINEAR));
}
else {/* CUBIC and SMART are unsupported for CUDA */
@@ -879,11 +880,12 @@ public:
}
}
- void draw_pixels(device_memory& mem, int y, int w, int h, int dy, int width, int height, bool transparent,
+ void draw_pixels(device_memory& mem, int y, int w, int h, int dx, int dy, int width, int height, bool transparent,
const DeviceDrawParams &draw_params)
{
if(!background) {
PixelMem pmem = pixel_mem_map[mem.device_pointer];
+ float *vpointer;
cuda_push_context();
@@ -917,23 +919,52 @@ public:
draw_params.bind_display_space_shader_cb();
}
- glPushMatrix();
- glTranslatef(0.0f, (float)dy, 0.0f);
-
- glBegin(GL_QUADS);
-
- glTexCoord2f(0.0f, 0.0f);
- glVertex2f(0.0f, 0.0f);
- glTexCoord2f((float)w/(float)pmem.w, 0.0f);
- glVertex2f((float)width, 0.0f);
- glTexCoord2f((float)w/(float)pmem.w, (float)h/(float)pmem.h);
- glVertex2f((float)width, (float)height);
- glTexCoord2f(0.0f, (float)h/(float)pmem.h);
- glVertex2f(0.0f, (float)height);
+ if(!vertex_buffer)
+ glGenBuffers(1, &vertex_buffer);
+
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
+ /* invalidate old contents - avoids stalling if buffer is still waiting in queue to be rendered */
+ glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW);
+
+ vpointer = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+
+ if(vpointer) {
+ /* texture coordinate - vertex pair */
+ vpointer[0] = 0.0f;
+ vpointer[1] = 0.0f;
+ vpointer[2] = dx;
+ vpointer[3] = dy;
+
+ vpointer[4] = (float)w/(float)pmem.w;
+ vpointer[5] = 0.0f;
+ vpointer[6] = (float)width + dx;
+ vpointer[7] = dy;
+
+ vpointer[8] = (float)w/(float)pmem.w;
+ vpointer[9] = (float)h/(float)pmem.h;
+ vpointer[10] = (float)width + dx;
+ vpointer[11] = (float)height + dy;
+
+ vpointer[12] = 0.0f;
+ vpointer[13] = (float)h/(float)pmem.h;
+ vpointer[14] = dx;
+ vpointer[15] = (float)height + dy;
+
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+ }
+
+ glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), 0);
+ glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), (char *)NULL + 2 * sizeof(float));
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- glEnd();
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
- glPopMatrix();
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
if(draw_params.unbind_display_space_shader_cb) {
draw_params.unbind_display_space_shader_cb();
@@ -950,7 +981,7 @@ public:
return;
}
- Device::draw_pixels(mem, y, w, h, dy, width, height, transparent, draw_params);
+ Device::draw_pixels(mem, y, w, h, dx, dy, width, height, transparent, draw_params);
}
void thread_run(DeviceTask *task)
@@ -966,7 +997,7 @@ public:
int end_sample = tile.start_sample + tile.num_samples;
for(int sample = start_sample; sample < end_sample; sample++) {
- if (task->get_cancel()) {
+ if(task->get_cancel()) {
if(task->need_finish_queue == false)
break;
}
@@ -999,7 +1030,7 @@ public:
}
};
- int get_split_task_count(DeviceTask& task)
+ int get_split_task_count(DeviceTask& /*task*/)
{
return 1;
}
@@ -1035,12 +1066,12 @@ bool device_cuda_init(void)
static bool initialized = false;
static bool result = false;
- if (initialized)
+ if(initialized)
return result;
initialized = true;
int cuew_result = cuewInit();
- if (cuew_result == CUEW_SUCCESS) {
+ if(cuew_result == CUEW_SUCCESS) {
VLOG(1) << "CUEW initialization succeeded";
if(CUDADevice::have_precompiled_kernels()) {
VLOG(1) << "Found precompiled kernels";
@@ -1132,7 +1163,7 @@ string device_cuda_capabilities(void)
if(result != CUDA_ERROR_NO_DEVICE) {
return string("Error initializing CUDA: ") + cuewErrorString(result);
}
- return "No CUDA device found";
+ return "No CUDA device found\n";
}
int count;
diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp
index 9aac86daa1d..c61e550151f 100644
--- a/intern/cycles/device/device_multi.cpp
+++ b/intern/cycles/device/device_multi.cpp
@@ -25,6 +25,7 @@
#include "util_foreach.h"
#include "util_list.h"
+#include "util_logging.h"
#include "util_map.h"
#include "util_time.h"
@@ -88,10 +89,10 @@ public:
return error_msg;
}
- bool load_kernels(bool experimental)
+ bool load_kernels(const DeviceRequestedFeatures& requested_features)
{
foreach(SubDevice& sub, devices)
- if(!sub.device->load_kernels(experimental))
+ if(!sub.device->load_kernels(requested_features))
return false;
return true;
@@ -170,6 +171,8 @@ public:
void tex_alloc(const char *name, device_memory& mem, InterpolationType interpolation, bool periodic)
{
+ VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
+
foreach(SubDevice& sub, devices) {
mem.device_pointer = 0;
sub.device->tex_alloc(name, mem, interpolation, periodic);
@@ -233,7 +236,7 @@ public:
mem.device_pointer = tmp;
}
- void draw_pixels(device_memory& rgba, int y, int w, int h, int dy, int width, int height, bool transparent,
+ void draw_pixels(device_memory& rgba, int y, int w, int h, int dx, int dy, int width, int height, bool transparent,
const DeviceDrawParams &draw_params)
{
device_ptr tmp = rgba.device_pointer;
@@ -248,7 +251,7 @@ public:
/* adjust math for w/width */
rgba.device_pointer = sub.ptr_map[tmp];
- sub.device->draw_pixels(rgba, sy, w, sh, sdy, width, sheight, transparent, draw_params);
+ sub.device->draw_pixels(rgba, sy, w, sh, dx, sdy, width, sheight, transparent, draw_params);
i++;
}
diff --git a/intern/cycles/device/device_network.cpp b/intern/cycles/device/device_network.cpp
index 4733482bf4e..1d6066c94dc 100644
--- a/intern/cycles/device/device_network.cpp
+++ b/intern/cycles/device/device_network.cpp
@@ -19,6 +19,7 @@
#include "device_network.h"
#include "util_foreach.h"
+#include "util_logging.h"
#if defined(WITH_NETWORK)
@@ -164,6 +165,8 @@ public:
void tex_alloc(const char *name, device_memory& mem, InterpolationType interpolation, bool periodic)
{
+ VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
+
thread_scoped_lock lock(rpc_lock);
mem.device_pointer = ++mem_counter;
@@ -194,7 +197,7 @@ public:
}
}
- bool load_kernels(bool experimental)
+ bool load_kernels(const DeviceRequestedFeatures& requested_features)
{
if(error_func.have_error())
return false;
@@ -202,7 +205,10 @@ public:
thread_scoped_lock lock(rpc_lock);
RPCSend snd(socket, &error_func, "load_kernels");
- snd.add(experimental);
+ snd.add(requested_features.experimental);
+ snd.add(requested_features.max_closure);
+ snd.add(requested_features.max_nodes_group);
+ snd.add(requested_features.nodes_features);
snd.write();
bool result;
@@ -269,7 +275,7 @@ public:
lock.unlock();
TileList::iterator it = tile_list_find(the_tiles, tile);
- if (it != the_tiles.end()) {
+ if(it != the_tiles.end()) {
tile.buffers = it->buffers;
the_tiles.erase(it);
}
@@ -605,11 +611,14 @@ protected:
device->tex_free(mem);
}
else if(rcv.name == "load_kernels") {
- bool experimental;
- rcv.read(experimental);
+ DeviceRequestedFeatures requested_features;
+ rcv.read(requested_features.experimental);
+ rcv.read(requested_features.max_closure);
+ rcv.read(requested_features.max_nodes_group);
+ rcv.read(requested_features.nodes_features);
bool result;
- result = device->load_kernels(experimental);
+ result = device->load_kernels(requested_features);
RPCSend snd(socket, &error_func, "load_kernels");
snd.add(result);
snd.write();
diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp
index a5bf35a63c8..87c08b3e045 100644
--- a/intern/cycles/device/device_opencl.cpp
+++ b/intern/cycles/device/device_opencl.cpp
@@ -28,6 +28,7 @@
#include "buffers.h"
#include "util_foreach.h"
+#include "util_logging.h"
#include "util_map.h"
#include "util_math.h"
#include "util_md5.h"
@@ -39,6 +40,28 @@ CCL_NAMESPACE_BEGIN
#define CL_MEM_PTR(p) ((cl_mem)(uintptr_t)(p))
+/* Macro declarations used with split kernel */
+
+/* Macro to enable/disable work-stealing */
+#define __WORK_STEALING__
+
+#define SPLIT_KERNEL_LOCAL_SIZE_X 64
+#define SPLIT_KERNEL_LOCAL_SIZE_Y 1
+
+/* This value may be tuned according to the scene we are rendering.
+ *
+ * Modifying PATH_ITER_INC_FACTOR value proportional to number of expected
+ * ray-bounces will improve performance.
+ */
+#define PATH_ITER_INC_FACTOR 8
+
+/* When allocate global memory in chunks. We may not be able to
+ * allocate exactly "CL_DEVICE_MAX_MEM_ALLOC_SIZE" bytes in chunks;
+ * Since some bytes may be needed for aligning chunks of memory;
+ * This is the amount of memory that we dedicate for that purpose.
+ */
+#define DATA_ALLOCATION_MEM_FACTOR 5000000 //5MB
+
static cl_device_type opencl_device_type()
{
char *device = getenv("CYCLES_OPENCL_TEST");
@@ -72,44 +95,13 @@ static bool opencl_kernel_use_advanced_shading(const string& platform)
else if(platform == "Apple")
return false;
else if(platform == "AMD Accelerated Parallel Processing")
- return false;
+ return true;
else if(platform == "Intel(R) OpenCL")
return true;
return false;
}
-static string opencl_kernel_build_options(const string& platform, const string *debug_src = NULL)
-{
- string build_options = " -cl-fast-relaxed-math ";
-
- if(platform == "NVIDIA CUDA")
- build_options += "-D__KERNEL_OPENCL_NVIDIA__ -cl-nv-maxrregcount=32 -cl-nv-verbose ";
-
- else if(platform == "Apple")
- build_options += "-D__KERNEL_OPENCL_APPLE__ ";
-
- else if(platform == "AMD Accelerated Parallel Processing")
- build_options += "-D__KERNEL_OPENCL_AMD__ ";
-
- else if(platform == "Intel(R) OpenCL") {
- build_options += "-D__KERNEL_OPENCL_INTEL_CPU__";
-
- /* options for gdb source level kernel debugging. this segfaults on linux currently */
- if(opencl_kernel_use_debug() && debug_src)
- build_options += "-g -s \"" + *debug_src + "\"";
- }
-
- if(opencl_kernel_use_debug())
- build_options += "-D__KERNEL_OPENCL_DEBUG__ ";
-
-#ifdef WITH_CYCLES_DEBUG
- build_options += "-D__KERNEL_DEBUG__ ";
-#endif
-
- return build_options;
-}
-
/* thread safe cache for contexts and programs */
class OpenCLCache
{
@@ -117,14 +109,18 @@ class OpenCLCache
{
thread_mutex *mutex;
cl_context context;
- cl_program program;
+ /* cl_program for shader, bake, film_convert kernels (used in OpenCLDeviceBase) */
+ cl_program ocl_dev_base_program;
+ /* cl_program for megakernel (used in OpenCLDeviceMegaKernel) */
+ cl_program ocl_dev_megakernel_program;
- Slot() : mutex(NULL), context(NULL), program(NULL) {}
+ Slot() : mutex(NULL), context(NULL), ocl_dev_base_program(NULL), ocl_dev_megakernel_program(NULL) {}
Slot(const Slot &rhs)
: mutex(rhs.mutex)
, context(rhs.context)
- , program(rhs.program)
+ , ocl_dev_base_program(rhs.ocl_dev_base_program)
+ , ocl_dev_megakernel_program(rhs.ocl_dev_megakernel_program)
{
/* copy can only happen in map insert, assert that */
assert(mutex == NULL);
@@ -235,6 +231,12 @@ class OpenCLCache
}
public:
+
+ enum ProgramName {
+ OCL_DEV_BASE_PROGRAM,
+ OCL_DEV_MEGAKERNEL_PROGRAM,
+ };
+
/* see get_something comment */
static cl_context get_context(cl_platform_id platform, cl_device_id device,
thread_scoped_lock &slot_locker)
@@ -253,10 +255,21 @@ public:
}
/* see get_something comment */
- static cl_program get_program(cl_platform_id platform, cl_device_id device,
+ static cl_program get_program(cl_platform_id platform, cl_device_id device, ProgramName program_name,
thread_scoped_lock &slot_locker)
{
- cl_program program = get_something<cl_program>(platform, device, &Slot::program, slot_locker);
+ cl_program program = NULL;
+
+ if(program_name == OCL_DEV_BASE_PROGRAM) {
+ /* Get program related to OpenCLDeviceBase */
+ program = get_something<cl_program>(platform, device, &Slot::ocl_dev_base_program, slot_locker);
+ }
+ else if(program_name == OCL_DEV_MEGAKERNEL_PROGRAM) {
+ /* Get program related to megakernel */
+ program = get_something<cl_program>(platform, device, &Slot::ocl_dev_megakernel_program, slot_locker);
+ } else {
+ assert(!"Invalid program name");
+ }
if(!program)
return NULL;
@@ -283,10 +296,18 @@ public:
}
/* see store_something comment */
- static void store_program(cl_platform_id platform, cl_device_id device, cl_program program,
+ static void store_program(cl_platform_id platform, cl_device_id device, cl_program program, ProgramName program_name,
thread_scoped_lock &slot_locker)
{
- store_something<cl_program>(platform, device, program, &Slot::program, slot_locker);
+ if(program_name == OCL_DEV_BASE_PROGRAM) {
+ store_something<cl_program>(platform, device, program, &Slot::ocl_dev_base_program, slot_locker);
+ }
+ else if(program_name == OCL_DEV_MEGAKERNEL_PROGRAM) {
+ store_something<cl_program>(platform, device, program, &Slot::ocl_dev_megakernel_program, slot_locker);
+ } else {
+ assert(!"Invalid program name\n");
+ return;
+ }
/* increment reference count in OpenCL.
* The caller is going to release the object when done with it. */
@@ -303,8 +324,10 @@ public:
thread_scoped_lock cache_lock(self.cache_lock);
foreach(CacheMap::value_type &item, self.cache) {
- if(item.second.program != NULL)
- clReleaseProgram(item.second.program);
+ if(item.second.ocl_dev_base_program != NULL)
+ clReleaseProgram(item.second.ocl_dev_base_program);
+ if(item.second.ocl_dev_megakernel_program != NULL)
+ clReleaseProgram(item.second.ocl_dev_megakernel_program);
if(item.second.context != NULL)
clReleaseContext(item.second.context);
}
@@ -313,7 +336,7 @@ public:
}
};
-class OpenCLDevice : public Device
+class OpenCLDeviceBase : public Device
{
public:
DedicatedTaskPool task_pool;
@@ -322,7 +345,6 @@ public:
cl_platform_id cpPlatform;
cl_device_id cdDevice;
cl_program cpProgram;
- cl_kernel ckPathTraceKernel;
cl_kernel ckFilmConvertByteKernel;
cl_kernel ckFilmConvertHalfFloatKernel;
cl_kernel ckShaderKernel;
@@ -384,7 +406,7 @@ public:
}
}
- OpenCLDevice(DeviceInfo& info, Stats &stats, bool background_)
+ OpenCLDeviceBase(DeviceInfo& info, Stats &stats, bool background_)
: Device(info, stats, background_)
{
cpPlatform = NULL;
@@ -392,7 +414,6 @@ public:
cxContext = NULL;
cqCommandQueue = NULL;
cpProgram = NULL;
- ckPathTraceKernel = NULL;
ckFilmConvertByteKernel = NULL;
ckFilmConvertHalfFloatKernel = NULL;
ckShaderKernel = NULL;
@@ -423,7 +444,7 @@ public:
int num_base = 0;
int total_devices = 0;
- for (int platform = 0; platform < num_platforms; platform++) {
+ for(int platform = 0; platform < num_platforms; platform++) {
cl_uint num_devices;
if(opencl_error(clGetDeviceIDs(platforms[platform], opencl_device_type(), 0, NULL, &num_devices)))
@@ -500,12 +521,12 @@ public:
if(opencl_error(ciErr))
return;
- fprintf(stderr,"Device init succes\n");
+ fprintf(stderr, "Device init success\n");
device_initialized = true;
}
static void CL_CALLBACK context_notify_callback(const char *err_info,
- const void *private_info, size_t cb, void *user_data)
+ const void * /*private_info*/, size_t /*cb*/, void *user_data)
{
char name[256];
clGetDeviceInfo((cl_device_id)user_data, CL_DEVICE_NAME, sizeof(name), &name, NULL);
@@ -546,7 +567,11 @@ public:
return true;
}
- bool load_binary(const string& kernel_path, const string& clbin, const string *debug_src = NULL)
+ bool load_binary(const string& /*kernel_path*/,
+ const string& clbin,
+ string custom_kernel_build_options,
+ cl_program *program,
+ const string *debug_src = NULL)
{
/* read binary into memory */
vector<uint8_t> binary;
@@ -561,7 +586,7 @@ public:
size_t size = binary.size();
const uint8_t *bytes = &binary[0];
- cpProgram = clCreateProgramWithBinary(cxContext, 1, &cdDevice,
+ *program = clCreateProgramWithBinary(cxContext, 1, &cdDevice,
&size, &bytes, &status, &ciErr);
if(opencl_error(status) || opencl_error(ciErr)) {
@@ -569,16 +594,16 @@ public:
return false;
}
- if(!build_kernel(kernel_path, debug_src))
+ if(!build_kernel(program, custom_kernel_build_options, debug_src))
return false;
return true;
}
- bool save_binary(const string& clbin)
+ bool save_binary(cl_program *program, const string& clbin)
{
size_t size = 0;
- clGetProgramInfo(cpProgram, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &size, NULL);
+ clGetProgramInfo(*program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &size, NULL);
if(!size)
return false;
@@ -586,7 +611,7 @@ public:
vector<uint8_t> binary(size);
uint8_t *bytes = &binary[0];
- clGetProgramInfo(cpProgram, CL_PROGRAM_BINARIES, sizeof(uint8_t*), &bytes, NULL);
+ clGetProgramInfo(*program, CL_PROGRAM_BINARIES, sizeof(uint8_t*), &bytes, NULL);
if(!path_write_binary(clbin, binary)) {
opencl_error(string_printf("OpenCL failed to write cached binary %s.", clbin.c_str()));
@@ -596,24 +621,30 @@ public:
return true;
}
- bool build_kernel(const string& kernel_path, const string *debug_src = NULL)
+ bool build_kernel(cl_program *kernel_program,
+ string custom_kernel_build_options,
+ const string *debug_src = NULL)
{
- string build_options = opencl_kernel_build_options(platform_name, debug_src);
-
- ciErr = clBuildProgram(cpProgram, 0, NULL, build_options.c_str(), NULL, NULL);
+ string build_options;
+ build_options = kernel_build_options(debug_src) + custom_kernel_build_options;
+
+ ciErr = clBuildProgram(*kernel_program, 0, NULL, build_options.c_str(), NULL, NULL);
/* show warnings even if build is successful */
size_t ret_val_size = 0;
- clGetProgramBuildInfo(cpProgram, cdDevice, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
+ clGetProgramBuildInfo(*kernel_program, cdDevice, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
if(ret_val_size > 1) {
- vector<char> build_log(ret_val_size+1);
- clGetProgramBuildInfo(cpProgram, cdDevice, CL_PROGRAM_BUILD_LOG, ret_val_size, &build_log[0], NULL);
+ vector<char> build_log(ret_val_size + 1);
+ clGetProgramBuildInfo(*kernel_program, cdDevice, CL_PROGRAM_BUILD_LOG, ret_val_size, &build_log[0], NULL);
build_log[ret_val_size] = '\0';
- fprintf(stderr, "OpenCL kernel build output:\n");
- fprintf(stderr, "%s\n", &build_log[0]);
+ /* Skip meaningless empty output from the NVidia compiler. */
+ if(!(ret_val_size == 2 && build_log[0] == '\n')) {
+ fprintf(stderr, "OpenCL kernel build output:\n");
+ fprintf(stderr, "%s\n", &build_log[0]);
+ }
}
if(ciErr != CL_SUCCESS) {
@@ -624,12 +655,15 @@ public:
return true;
}
- bool compile_kernel(const string& kernel_path, const string& kernel_md5, const string *debug_src = NULL)
+ bool compile_kernel(const string& kernel_path,
+ string source,
+ string custom_kernel_build_options,
+ cl_program *kernel_program,
+ const string *debug_src = NULL)
{
/* 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 */
- string source = "#include \"kernel.cl\" // " + kernel_md5 + "\n";
source = path_source_replace_includes(source, kernel_path);
if(debug_src)
@@ -638,15 +672,19 @@ public:
size_t source_len = source.size();
const char *source_str = source.c_str();
- cpProgram = clCreateProgramWithSource(cxContext, 1, &source_str, &source_len, &ciErr);
+ *kernel_program = clCreateProgramWithSource(cxContext, 1, &source_str, &source_len, &ciErr);
if(opencl_error(ciErr))
return false;
double starttime = time_dt();
printf("Compiling OpenCL kernel ...\n");
+ /* TODO(sergey): Report which kernel is being compiled
+ * as well (megakernel or which of split kernels etc..).
+ */
+ printf("Build flags: %s\n", custom_kernel_build_options.c_str());
- if(!build_kernel(kernel_path, debug_src))
+ if(!build_kernel(kernel_program, custom_kernel_build_options, debug_src))
return false;
printf("Kernel compilation finished in %.2lfs.\n", time_dt() - starttime);
@@ -654,7 +692,7 @@ public:
return true;
}
- string device_md5_hash()
+ string device_md5_hash(string kernel_custom_build_options = "")
{
MD5Hash md5;
char version[256], driver[256], name[256], vendor[256];
@@ -669,13 +707,14 @@ public:
md5.append((uint8_t*)name, strlen(name));
md5.append((uint8_t*)driver, strlen(driver));
- string options = opencl_kernel_build_options(platform_name);
+ string options = kernel_build_options();
+ options += kernel_custom_build_options;
md5.append((uint8_t*)options.c_str(), options.size());
return md5.get_hex();
}
- bool load_kernels(bool experimental)
+ bool load_kernels(const DeviceRequestedFeatures& /*requested_features*/)
{
/* verify if device was initialized */
if(!device_initialized) {
@@ -685,7 +724,7 @@ public:
/* try to use cached kernel */
thread_scoped_lock cache_locker;
- cpProgram = OpenCLCache::get_program(cpPlatform, cdDevice, cache_locker);
+ cpProgram = OpenCLCache::get_program(cpPlatform, cdDevice, OpenCLCache::OCL_DEV_BASE_PROGRAM, cache_locker);
if(!cpProgram) {
/* verify we have right opencl version */
@@ -711,28 +750,27 @@ public:
}
/* if exists already, try use it */
- if(path_exists(clbin) && load_binary(kernel_path, clbin, debug_src)) {
+ if(path_exists(clbin) && load_binary(kernel_path, clbin, "", &cpProgram)) {
/* kernel loaded from binary */
}
else {
+
+ 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, kernel_md5, debug_src))
+ if(!compile_kernel(kernel_path, init_kernel_source, "", &cpProgram, debug_src))
return false;
/* save binary for reuse */
- if(!save_binary(clbin))
+ if(!save_binary(&cpProgram, clbin))
return false;
}
/* cache the program */
- OpenCLCache::store_program(cpPlatform, cdDevice, cpProgram, cache_locker);
+ OpenCLCache::store_program(cpPlatform, cdDevice, cpProgram, OpenCLCache::OCL_DEV_BASE_PROGRAM, cache_locker);
}
/* find kernels */
- ckPathTraceKernel = clCreateKernel(cpProgram, "kernel_ocl_path_trace", &ciErr);
- if(opencl_error(ciErr))
- return false;
-
ckFilmConvertByteKernel = clCreateKernel(cpProgram, "kernel_ocl_convert_to_byte", &ciErr);
if(opencl_error(ciErr))
return false;
@@ -752,7 +790,7 @@ public:
return true;
}
- ~OpenCLDevice()
+ ~OpenCLDeviceBase()
{
task_pool.stop();
@@ -765,12 +803,14 @@ public:
delete mt->second;
}
- if(ckPathTraceKernel)
- clReleaseKernel(ckPathTraceKernel);
if(ckFilmConvertByteKernel)
clReleaseKernel(ckFilmConvertByteKernel);
if(ckFilmConvertHalfFloatKernel)
clReleaseKernel(ckFilmConvertHalfFloatKernel);
+ if(ckShaderKernel)
+ clReleaseKernel(ckShaderKernel);
+ if(ckBakeKernel)
+ clReleaseKernel(ckBakeKernel);
if(cpProgram)
clReleaseProgram(cpProgram);
if(cqCommandQueue)
@@ -854,8 +894,12 @@ public:
mem_copy_to(*i->second);
}
- void tex_alloc(const char *name, device_memory& mem, InterpolationType interpolation, bool periodic)
+ void tex_alloc(const char *name,
+ device_memory& mem,
+ InterpolationType /*interpolation*/,
+ bool /*periodic*/)
{
+ VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
mem_alloc(mem, MEM_READ_ONLY);
mem_copy_to(mem);
assert(mem_map.find(name) == mem_map.end());
@@ -908,42 +952,6 @@ public:
opencl_assert(clFlush(cqCommandQueue));
}
- void path_trace(RenderTile& rtile, int sample)
- {
- /* cast arguments to cl types */
- cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
- cl_mem d_buffer = CL_MEM_PTR(rtile.buffer);
- cl_mem d_rng_state = CL_MEM_PTR(rtile.rng_state);
- cl_int d_x = rtile.x;
- cl_int d_y = rtile.y;
- cl_int d_w = rtile.w;
- cl_int d_h = rtile.h;
- cl_int d_sample = sample;
- cl_int d_offset = rtile.offset;
- cl_int d_stride = rtile.stride;
-
- /* sample arguments */
- cl_uint narg = 0;
-
- opencl_assert(clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_data), (void*)&d_data));
- opencl_assert(clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_buffer), (void*)&d_buffer));
- opencl_assert(clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_rng_state), (void*)&d_rng_state));
-
-#define KERNEL_TEX(type, ttype, name) \
- set_kernel_arg_mem(ckPathTraceKernel, &narg, #name);
-#include "kernel_textures.h"
-
- opencl_assert(clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_sample), (void*)&d_sample));
- opencl_assert(clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_x), (void*)&d_x));
- opencl_assert(clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_y), (void*)&d_y));
- opencl_assert(clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_w), (void*)&d_w));
- opencl_assert(clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_h), (void*)&d_h));
- opencl_assert(clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_offset), (void*)&d_offset));
- opencl_assert(clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_stride), (void*)&d_stride));
-
- enqueue_kernel(ckPathTraceKernel, d_w, d_h);
- }
-
void set_kernel_arg_mem(cl_kernel kernel, cl_uint *narg, const char *name)
{
cl_mem ptr;
@@ -974,29 +982,30 @@ public:
cl_int d_offset = task.offset;
cl_int d_stride = task.stride;
- /* sample arguments */
- cl_uint narg = 0;
-
cl_kernel ckFilmConvertKernel = (rgba_byte)? ckFilmConvertByteKernel: ckFilmConvertHalfFloatKernel;
- opencl_assert(clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_data), (void*)&d_data));
- opencl_assert(clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_rgba), (void*)&d_rgba));
- opencl_assert(clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_buffer), (void*)&d_buffer));
+ cl_uint start_arg_index =
+ kernel_set_args(ckFilmConvertKernel,
+ 0,
+ d_data,
+ d_rgba,
+ d_buffer);
#define KERNEL_TEX(type, ttype, name) \
- set_kernel_arg_mem(ckFilmConvertKernel, &narg, #name);
+ set_kernel_arg_mem(ckFilmConvertKernel, &start_arg_index, #name);
#include "kernel_textures.h"
-
- opencl_assert(clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_sample_scale), (void*)&d_sample_scale));
- opencl_assert(clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_x), (void*)&d_x));
- opencl_assert(clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_y), (void*)&d_y));
- opencl_assert(clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_w), (void*)&d_w));
- opencl_assert(clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_h), (void*)&d_h));
- opencl_assert(clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_offset), (void*)&d_offset));
- opencl_assert(clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_stride), (void*)&d_stride));
-
-
+#undef KERNEL_TEX
+
+ start_arg_index += kernel_set_args(ckFilmConvertKernel,
+ start_arg_index,
+ d_sample_scale,
+ d_x,
+ d_y,
+ d_w,
+ d_h,
+ d_offset,
+ d_stride);
enqueue_kernel(ckFilmConvertKernel, d_w, d_h);
}
@@ -1012,9 +1021,6 @@ public:
cl_int d_shader_w = task.shader_w;
cl_int d_offset = task.offset;
- /* sample arguments */
- cl_uint narg = 0;
-
cl_kernel kernel;
if(task.shader_eval_type >= SHADER_EVAL_BAKE)
@@ -1029,19 +1035,25 @@ public:
cl_int d_sample = sample;
- opencl_assert(clSetKernelArg(kernel, narg++, sizeof(d_data), (void*)&d_data));
- opencl_assert(clSetKernelArg(kernel, narg++, sizeof(d_input), (void*)&d_input));
- opencl_assert(clSetKernelArg(kernel, narg++, sizeof(d_output), (void*)&d_output));
+ cl_uint start_arg_index =
+ kernel_set_args(kernel,
+ 0,
+ d_data,
+ d_input,
+ d_output);
#define KERNEL_TEX(type, ttype, name) \
- set_kernel_arg_mem(kernel, &narg, #name);
+ set_kernel_arg_mem(kernel, &start_arg_index, #name);
#include "kernel_textures.h"
+#undef KERNEL_TEX
- opencl_assert(clSetKernelArg(kernel, narg++, sizeof(d_shader_eval_type), (void*)&d_shader_eval_type));
- opencl_assert(clSetKernelArg(kernel, narg++, sizeof(d_shader_x), (void*)&d_shader_x));
- opencl_assert(clSetKernelArg(kernel, narg++, sizeof(d_shader_w), (void*)&d_shader_w));
- opencl_assert(clSetKernelArg(kernel, narg++, sizeof(d_offset), (void*)&d_offset));
- opencl_assert(clSetKernelArg(kernel, narg++, sizeof(d_sample), (void*)&d_sample));
+ start_arg_index += kernel_set_args(kernel,
+ start_arg_index,
+ d_shader_eval_type,
+ d_shader_x,
+ d_shader_w,
+ d_offset,
+ d_sample);
enqueue_kernel(kernel, task.shader_w, 1);
@@ -1049,6 +1061,380 @@ public:
}
}
+ class OpenCLDeviceTask : public DeviceTask {
+ public:
+ OpenCLDeviceTask(OpenCLDeviceBase *device, DeviceTask& task)
+ : DeviceTask(task)
+ {
+ run = function_bind(&OpenCLDeviceBase::thread_run,
+ device,
+ this);
+ }
+ };
+
+ int get_split_task_count(DeviceTask& /*task*/)
+ {
+ return 1;
+ }
+
+ void task_add(DeviceTask& task)
+ {
+ task_pool.push(new OpenCLDeviceTask(this, task));
+ }
+
+ void task_wait()
+ {
+ task_pool.wait();
+ }
+
+ void task_cancel()
+ {
+ task_pool.cancel();
+ }
+
+ virtual void thread_run(DeviceTask * /*task*/) = 0;
+
+protected:
+
+ string kernel_build_options(const string *debug_src = NULL)
+ {
+ string build_options = " -cl-fast-relaxed-math ";
+
+ if(platform_name == "NVIDIA CUDA") {
+ build_options += "-D__KERNEL_OPENCL_NVIDIA__ "
+ "-cl-nv-maxrregcount=32 "
+ "-cl-nv-verbose ";
+
+ uint compute_capability_major, compute_capability_minor;
+ clGetDeviceInfo(cdDevice, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV,
+ sizeof(cl_uint), &compute_capability_major, NULL);
+ clGetDeviceInfo(cdDevice, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV,
+ sizeof(cl_uint), &compute_capability_minor, NULL);
+
+ build_options += string_printf("-D__COMPUTE_CAPABILITY__=%u ",
+ compute_capability_major * 100 +
+ compute_capability_minor * 10);
+ }
+
+ else if(platform_name == "Apple")
+ build_options += "-D__KERNEL_OPENCL_APPLE__ ";
+
+ else if(platform_name == "AMD Accelerated Parallel Processing")
+ build_options += "-D__KERNEL_OPENCL_AMD__ ";
+
+ else if(platform_name == "Intel(R) OpenCL") {
+ build_options += "-D__KERNEL_OPENCL_INTEL_CPU__ ";
+
+ /* Options for gdb source level kernel debugging.
+ * this segfaults on linux currently.
+ */
+ if(opencl_kernel_use_debug() && debug_src)
+ build_options += "-g -s \"" + *debug_src + "\" ";
+ }
+
+ if(opencl_kernel_use_debug())
+ build_options += "-D__KERNEL_OPENCL_DEBUG__ ";
+
+#ifdef WITH_CYCLES_DEBUG
+ build_options += "-D__KERNEL_DEBUG__ ";
+#endif
+
+ return build_options;
+ }
+
+ class ArgumentWrapper {
+ public:
+ ArgumentWrapper() : size(0), pointer(NULL) {}
+ template <typename T>
+ ArgumentWrapper(T& argument) : size(sizeof(argument)),
+ pointer(&argument) { }
+ size_t size;
+ void *pointer;
+ };
+
+ /* TODO(sergey): In the future we can use variadic templates, once
+ * C++0x is allowed. Should allow to clean this up a bit.
+ */
+ int kernel_set_args(cl_kernel kernel,
+ int start_argument_index,
+ const ArgumentWrapper& arg1 = ArgumentWrapper(),
+ const ArgumentWrapper& arg2 = ArgumentWrapper(),
+ const ArgumentWrapper& arg3 = ArgumentWrapper(),
+ const ArgumentWrapper& arg4 = ArgumentWrapper(),
+ const ArgumentWrapper& arg5 = ArgumentWrapper(),
+ const ArgumentWrapper& arg6 = ArgumentWrapper(),
+ const ArgumentWrapper& arg7 = ArgumentWrapper(),
+ const ArgumentWrapper& arg8 = ArgumentWrapper(),
+ const ArgumentWrapper& arg9 = ArgumentWrapper(),
+ const ArgumentWrapper& arg10 = ArgumentWrapper(),
+ const ArgumentWrapper& arg11 = ArgumentWrapper(),
+ const ArgumentWrapper& arg12 = ArgumentWrapper(),
+ const ArgumentWrapper& arg13 = ArgumentWrapper(),
+ const ArgumentWrapper& arg14 = ArgumentWrapper(),
+ const ArgumentWrapper& arg15 = ArgumentWrapper(),
+ const ArgumentWrapper& arg16 = ArgumentWrapper(),
+ const ArgumentWrapper& arg17 = ArgumentWrapper(),
+ const ArgumentWrapper& arg18 = ArgumentWrapper(),
+ const ArgumentWrapper& arg19 = ArgumentWrapper(),
+ const ArgumentWrapper& arg20 = ArgumentWrapper(),
+ const ArgumentWrapper& arg21 = ArgumentWrapper(),
+ const ArgumentWrapper& arg22 = ArgumentWrapper(),
+ const ArgumentWrapper& arg23 = ArgumentWrapper(),
+ const ArgumentWrapper& arg24 = ArgumentWrapper(),
+ const ArgumentWrapper& arg25 = ArgumentWrapper(),
+ const ArgumentWrapper& arg26 = ArgumentWrapper(),
+ const ArgumentWrapper& arg27 = ArgumentWrapper(),
+ const ArgumentWrapper& arg28 = ArgumentWrapper(),
+ const ArgumentWrapper& arg29 = ArgumentWrapper(),
+ const ArgumentWrapper& arg30 = ArgumentWrapper(),
+ const ArgumentWrapper& arg31 = ArgumentWrapper(),
+ const ArgumentWrapper& arg32 = ArgumentWrapper(),
+ const ArgumentWrapper& arg33 = ArgumentWrapper())
+ {
+ int current_arg_index = 0;
+#define FAKE_VARARG_HANDLE_ARG(arg) \
+ do { \
+ if(arg.pointer != NULL) { \
+ opencl_assert(clSetKernelArg( \
+ kernel, \
+ start_argument_index + current_arg_index, \
+ arg.size, arg.pointer)); \
+ ++current_arg_index; \
+ } \
+ else { \
+ return current_arg_index; \
+ } \
+ } while(false)
+ FAKE_VARARG_HANDLE_ARG(arg1);
+ FAKE_VARARG_HANDLE_ARG(arg2);
+ FAKE_VARARG_HANDLE_ARG(arg3);
+ FAKE_VARARG_HANDLE_ARG(arg4);
+ FAKE_VARARG_HANDLE_ARG(arg5);
+ FAKE_VARARG_HANDLE_ARG(arg6);
+ FAKE_VARARG_HANDLE_ARG(arg7);
+ FAKE_VARARG_HANDLE_ARG(arg8);
+ FAKE_VARARG_HANDLE_ARG(arg9);
+ FAKE_VARARG_HANDLE_ARG(arg10);
+ FAKE_VARARG_HANDLE_ARG(arg11);
+ FAKE_VARARG_HANDLE_ARG(arg12);
+ FAKE_VARARG_HANDLE_ARG(arg13);
+ FAKE_VARARG_HANDLE_ARG(arg14);
+ FAKE_VARARG_HANDLE_ARG(arg15);
+ FAKE_VARARG_HANDLE_ARG(arg16);
+ FAKE_VARARG_HANDLE_ARG(arg17);
+ FAKE_VARARG_HANDLE_ARG(arg18);
+ FAKE_VARARG_HANDLE_ARG(arg19);
+ FAKE_VARARG_HANDLE_ARG(arg20);
+ FAKE_VARARG_HANDLE_ARG(arg21);
+ FAKE_VARARG_HANDLE_ARG(arg22);
+ FAKE_VARARG_HANDLE_ARG(arg23);
+ FAKE_VARARG_HANDLE_ARG(arg24);
+ FAKE_VARARG_HANDLE_ARG(arg25);
+ FAKE_VARARG_HANDLE_ARG(arg26);
+ FAKE_VARARG_HANDLE_ARG(arg27);
+ FAKE_VARARG_HANDLE_ARG(arg28);
+ FAKE_VARARG_HANDLE_ARG(arg29);
+ FAKE_VARARG_HANDLE_ARG(arg30);
+ FAKE_VARARG_HANDLE_ARG(arg31);
+ FAKE_VARARG_HANDLE_ARG(arg32);
+ FAKE_VARARG_HANDLE_ARG(arg33);
+#undef FAKE_VARARG_HANDLE_ARG
+ return current_arg_index;
+ }
+
+ inline void release_kernel_safe(cl_kernel kernel)
+ {
+ if(kernel) {
+ clReleaseKernel(kernel);
+ }
+ }
+
+ inline void release_mem_object_safe(cl_mem mem)
+ {
+ if(mem != NULL) {
+ clReleaseMemObject(mem);
+ }
+ }
+
+ inline void release_program_safe(cl_program program)
+ {
+ if(program) {
+ clReleaseProgram(program);
+ }
+ }
+
+ string build_options_from_requested_features(
+ const DeviceRequestedFeatures& requested_features)
+ {
+ string build_options = "";
+ if(requested_features.experimental) {
+ build_options += " -D__KERNEL_EXPERIMENTAL__";
+ }
+ build_options += " -D__NODES_MAX_GROUP__=" +
+ string_printf("%d", requested_features.max_nodes_group);
+ build_options += " -D__NODES_FEATURES__=" +
+ string_printf("%d", requested_features.nodes_features);
+ build_options += string_printf(" -D__MAX_CLOSURE__=%d",
+ requested_features.max_closure);
+ if(!requested_features.use_hair) {
+ build_options += " -D__NO_HAIR__";
+ }
+ if(!requested_features.use_object_motion) {
+ build_options += " -D__NO_OBJECT_MOTION__";
+ }
+ if(!requested_features.use_camera_motion) {
+ build_options += " -D__NO_CAMERA_MOTION__";
+ }
+ return build_options;
+ }
+};
+
+class OpenCLDeviceMegaKernel : public OpenCLDeviceBase
+{
+public:
+ cl_kernel ckPathTraceKernel;
+ cl_program path_trace_program;
+
+ OpenCLDeviceMegaKernel(DeviceInfo& info, Stats &stats, bool background_)
+ : OpenCLDeviceBase(info, stats, background_)
+ {
+ ckPathTraceKernel = NULL;
+ path_trace_program = NULL;
+ }
+
+ bool load_kernels(const DeviceRequestedFeatures& requested_features)
+ {
+ /* Get Shader, bake and film convert kernels.
+ * It'll also do verification of OpenCL actually initialized.
+ */
+ if(!OpenCLDeviceBase::load_kernels(requested_features)) {
+ return false;
+ }
+
+ /* Try to use cached kernel. */
+ thread_scoped_lock cache_locker;
+ path_trace_program = OpenCLCache::get_program(cpPlatform,
+ cdDevice,
+ OpenCLCache::OCL_DEV_MEGAKERNEL_PROGRAM,
+ cache_locker);
+
+ if(!path_trace_program) {
+ /* Verify we have right opencl version. */
+ if(!opencl_version_check())
+ return false;
+
+ /* Calculate md5 hash to detect changes. */
+ string kernel_path = path_get("kernel");
+ string kernel_md5 = path_files_md5_hash(kernel_path);
+ string custom_kernel_build_options = "-D__COMPILE_ONLY_MEGAKERNEL__ ";
+ string device_md5 = device_md5_hash(custom_kernel_build_options);
+
+ /* Path to cached binary. */
+ string clbin = string_printf("cycles_kernel_%s_%s.clbin",
+ device_md5.c_str(),
+ kernel_md5.c_str());
+ clbin = path_user_get(path_join("cache", clbin));
+
+ /* Path to preprocessed source for debugging. */
+ string clsrc, *debug_src = NULL;
+ if(opencl_kernel_use_debug()) {
+ clsrc = string_printf("cycles_kernel_%s_%s.cl",
+ device_md5.c_str(),
+ kernel_md5.c_str());
+ clsrc = path_user_get(path_join("cache", clsrc));
+ debug_src = &clsrc;
+ }
+
+ /* If exists already, try use it. */
+ if(path_exists(clbin) && load_binary(kernel_path,
+ clbin,
+ custom_kernel_build_options,
+ &path_trace_program,
+ debug_src)) {
+ /* Kernel loaded from binary, nothing to do. */
+ }
+ else {
+ 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,
+ init_kernel_source,
+ custom_kernel_build_options,
+ &path_trace_program,
+ debug_src))
+ {
+ return false;
+ }
+ /* Save binary for reuse. */
+ if(!save_binary(&path_trace_program, clbin)) {
+ return false;
+ }
+ }
+ /* Cache the program. */
+ OpenCLCache::store_program(cpPlatform,
+ cdDevice,
+ path_trace_program,
+ OpenCLCache::OCL_DEV_MEGAKERNEL_PROGRAM,
+ cache_locker);
+ }
+
+ /* Find kernels. */
+ ckPathTraceKernel = clCreateKernel(path_trace_program,
+ "kernel_ocl_path_trace",
+ &ciErr);
+ if(opencl_error(ciErr))
+ return false;
+ return true;
+ }
+
+ ~OpenCLDeviceMegaKernel()
+ {
+ task_pool.stop();
+ release_kernel_safe(ckPathTraceKernel);
+ release_program_safe(path_trace_program);
+ }
+
+ void path_trace(RenderTile& rtile, int sample)
+ {
+ /* Cast arguments to cl types. */
+ cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
+ cl_mem d_buffer = CL_MEM_PTR(rtile.buffer);
+ cl_mem d_rng_state = CL_MEM_PTR(rtile.rng_state);
+ cl_int d_x = rtile.x;
+ cl_int d_y = rtile.y;
+ cl_int d_w = rtile.w;
+ cl_int d_h = rtile.h;
+ cl_int d_offset = rtile.offset;
+ cl_int d_stride = rtile.stride;
+
+ /* Sample arguments. */
+ cl_int d_sample = sample;
+
+ cl_uint start_arg_index =
+ kernel_set_args(ckPathTraceKernel,
+ 0,
+ d_data,
+ d_buffer,
+ d_rng_state);
+
+#define KERNEL_TEX(type, ttype, name) \
+ set_kernel_arg_mem(ckPathTraceKernel, &start_arg_index, #name);
+#include "kernel_textures.h"
+#undef KERNEL_TEX
+
+ start_arg_index += kernel_set_args(ckPathTraceKernel,
+ start_arg_index,
+ d_sample,
+ d_x,
+ d_y,
+ d_w,
+ d_h,
+ d_offset,
+ d_stride);
+
+ enqueue_kernel(ckPathTraceKernel, d_w, d_h);
+ }
+
void thread_run(DeviceTask *task)
{
if(task->type == DeviceTask::FILM_CONVERT) {
@@ -1059,8 +1445,7 @@ public:
}
else if(task->type == DeviceTask::PATH_TRACE) {
RenderTile tile;
-
- /* keep rendering tiles until done */
+ /* Keep rendering tiles until done. */
while(task->acquire_tile(this, tile)) {
int start_sample = tile.start_sample;
int end_sample = tile.start_sample + tile.num_samples;
@@ -1078,62 +1463,1902 @@ public:
task->update_progress(&tile);
}
+ /* Complete kernel execution before release tile */
+ /* This helps in multi-device render;
+ * The device that reaches the critical-section function
+ * release_tile waits (stalling other devices from entering
+ * release_tile) for all kernels to complete. If device1 (a
+ * slow-render device) reaches release_tile first then it would
+ * stall device2 (a fast-render device) from proceeding to render
+ * next tile.
+ */
+ clFinish(cqCommandQueue);
+
task->release_tile(tile);
}
}
}
+};
- class OpenCLDeviceTask : public DeviceTask {
- public:
- OpenCLDeviceTask(OpenCLDevice *device, DeviceTask& task)
- : DeviceTask(task)
+/* TODO(sergey): This is to keep tile split on OpenCL level working
+ * for now, since without this view-port render does not work as it
+ * should.
+ *
+ * Ideally it'll be done on the higher level, but we need to get ready
+ * for merge rather soon, so let's keep split logic private here in
+ * the file.
+ */
+class SplitRenderTile : public RenderTile {
+public:
+ SplitRenderTile()
+ : RenderTile(),
+ buffer_offset_x(0),
+ buffer_offset_y(0),
+ rng_state_offset_x(0),
+ rng_state_offset_y(0),
+ buffer_rng_state_stride(0) {}
+
+ explicit SplitRenderTile(RenderTile& tile)
+ : RenderTile(),
+ buffer_offset_x(0),
+ buffer_offset_y(0),
+ rng_state_offset_x(0),
+ rng_state_offset_y(0),
+ buffer_rng_state_stride(0)
+ {
+ x = tile.x;
+ y = tile.y;
+ w = tile.w;
+ h = tile.h;
+ start_sample = tile.start_sample;
+ num_samples = tile.num_samples;
+ sample = tile.sample;
+ resolution = tile.resolution;
+ offset = tile.offset;
+ stride = tile.stride;
+ buffer = tile.buffer;
+ rng_state = tile.rng_state;
+ buffers = tile.buffers;
+ }
+
+ /* Split kernel is device global memory constrained;
+ * hence split kernel cant render big tile size's in
+ * one go. If the user sets a big tile size (big tile size
+ * is a term relative to the available device global memory),
+ * we split the tile further and then call path_trace on
+ * each of those split tiles. The following variables declared,
+ * assist in achieving that purpose
+ */
+ int buffer_offset_x;
+ int buffer_offset_y;
+ int rng_state_offset_x;
+ int rng_state_offset_y;
+ int buffer_rng_state_stride;
+};
+
+/* OpenCLDeviceSplitKernel's declaration/definition. */
+class OpenCLDeviceSplitKernel : public OpenCLDeviceBase
+{
+public:
+ /* Kernel declaration. */
+ cl_kernel ckPathTraceKernel_data_init;
+ cl_kernel ckPathTraceKernel_scene_intersect;
+ cl_kernel ckPathTraceKernel_lamp_emission;
+ cl_kernel ckPathTraceKernel_queue_enqueue;
+ cl_kernel ckPathTraceKernel_background_buffer_update;
+ cl_kernel ckPathTraceKernel_shader_eval;
+ cl_kernel ckPathTraceKernel_holdout_emission_blurring_pathtermination_ao;
+ cl_kernel ckPathTraceKernel_direct_lighting;
+ cl_kernel ckPathTraceKernel_shadow_blocked;
+ cl_kernel ckPathTraceKernel_next_iteration_setup;
+ cl_kernel ckPathTraceKernel_sum_all_radiance;
+
+ /* cl_program declaration. */
+ cl_program data_init_program;
+ cl_program scene_intersect_program;
+ cl_program lamp_emission_program;
+ cl_program queue_enqueue_program;
+ cl_program background_buffer_update_program;
+ cl_program shader_eval_program;
+ cl_program holdout_emission_blurring_pathtermination_ao_program;
+ cl_program direct_lighting_program;
+ cl_program shadow_blocked_program;
+ cl_program next_iteration_setup_program;
+ cl_program sum_all_radiance_program;
+
+ /* Global memory variables [porting]; These memory is used for
+ * co-operation between different kernels; Data written by one
+ * kernel will be available to another kernel via this global
+ * memory.
+ */
+ cl_mem rng_coop;
+ cl_mem throughput_coop;
+ cl_mem L_transparent_coop;
+ cl_mem PathRadiance_coop;
+ cl_mem Ray_coop;
+ cl_mem PathState_coop;
+ cl_mem Intersection_coop;
+ cl_mem kgbuffer; /* KernelGlobals buffer. */
+
+ /* Global buffers for ShaderData. */
+ cl_mem sd; /* ShaderData used in the main path-iteration loop. */
+ cl_mem sd_DL_shadow; /* ShaderData used in Direct Lighting and
+ * shadow_blocked kernel.
+ */
+
+ /* Global buffers of each member of ShaderData. */
+ cl_mem P_sd;
+ cl_mem P_sd_DL_shadow;
+ cl_mem N_sd;
+ cl_mem N_sd_DL_shadow;
+ cl_mem Ng_sd;
+ cl_mem Ng_sd_DL_shadow;
+ cl_mem I_sd;
+ cl_mem I_sd_DL_shadow;
+ cl_mem shader_sd;
+ cl_mem shader_sd_DL_shadow;
+ cl_mem flag_sd;
+ cl_mem flag_sd_DL_shadow;
+ cl_mem prim_sd;
+ cl_mem prim_sd_DL_shadow;
+ cl_mem type_sd;
+ cl_mem type_sd_DL_shadow;
+ cl_mem u_sd;
+ cl_mem u_sd_DL_shadow;
+ cl_mem v_sd;
+ cl_mem v_sd_DL_shadow;
+ cl_mem object_sd;
+ cl_mem object_sd_DL_shadow;
+ cl_mem time_sd;
+ cl_mem time_sd_DL_shadow;
+ cl_mem ray_length_sd;
+ cl_mem ray_length_sd_DL_shadow;
+ cl_mem ray_depth_sd;
+ cl_mem ray_depth_sd_DL_shadow;
+ cl_mem transparent_depth_sd;
+ cl_mem transparent_depth_sd_DL_shadow;
+
+ /* Ray differentials. */
+ cl_mem dP_sd, dI_sd;
+ cl_mem dP_sd_DL_shadow, dI_sd_DL_shadow;
+ cl_mem du_sd, dv_sd;
+ cl_mem du_sd_DL_shadow, dv_sd_DL_shadow;
+
+ /* Dp/Du */
+ cl_mem dPdu_sd, dPdv_sd;
+ cl_mem dPdu_sd_DL_shadow, dPdv_sd_DL_shadow;
+
+ /* Object motion. */
+ cl_mem ob_tfm_sd, ob_itfm_sd;
+ cl_mem ob_tfm_sd_DL_shadow, ob_itfm_sd_DL_shadow;
+
+ cl_mem closure_sd;
+ cl_mem closure_sd_DL_shadow;
+ cl_mem num_closure_sd;
+ cl_mem num_closure_sd_DL_shadow;
+ cl_mem randb_closure_sd;
+ cl_mem randb_closure_sd_DL_shadow;
+ cl_mem ray_P_sd;
+ cl_mem ray_P_sd_DL_shadow;
+ cl_mem ray_dP_sd;
+ cl_mem ray_dP_sd_DL_shadow;
+
+ /* Global memory required for shadow blocked and accum_radiance. */
+ cl_mem BSDFEval_coop;
+ cl_mem ISLamp_coop;
+ cl_mem LightRay_coop;
+ cl_mem AOAlpha_coop;
+ cl_mem AOBSDF_coop;
+ cl_mem AOLightRay_coop;
+ cl_mem Intersection_coop_AO;
+ cl_mem Intersection_coop_DL;
+
+#ifdef WITH_CYCLES_DEBUG
+ /* DebugData memory */
+ cl_mem debugdata_coop;
+#endif
+
+ /* Global state array that tracks ray state. */
+ cl_mem ray_state;
+
+ /* Per sample buffers. */
+ cl_mem per_sample_output_buffers;
+
+ /* Denotes which sample each ray is being processed for. */
+ cl_mem work_array;
+
+ /* Queue */
+ cl_mem Queue_data; /* Array of size queuesize * num_queues * sizeof(int). */
+ cl_mem Queue_index; /* Array of size num_queues * sizeof(int);
+ * Tracks the size of each queue.
+ */
+
+ /* Flag to make sceneintersect and lampemission kernel use queues. */
+ cl_mem use_queues_flag;
+
+ /* Amount of memory in output buffer associated with one pixel/thread. */
+ size_t per_thread_output_buffer_size;
+
+ /* Total allocatable available device memory. */
+ size_t total_allocatable_memory;
+
+ /* host version of ray_state; Used in checking host path-iteration
+ * termination.
+ */
+ char *hostRayStateArray;
+
+ /* Number of path-iterations to be done in one shot. */
+ unsigned int PathIteration_times;
+
+#ifdef __WORK_STEALING__
+ /* Work pool with respect to each work group. */
+ cl_mem work_pool_wgs;
+
+ /* Denotes the maximum work groups possible w.r.t. current tile size. */
+ unsigned int max_work_groups;
+#endif
+
+ /* clos_max value for which the kernels have been loaded currently. */
+ int current_max_closure;
+
+ /* Marked True in constructor and marked false at the end of path_trace(). */
+ bool first_tile;
+
+ OpenCLDeviceSplitKernel(DeviceInfo& info, Stats &stats, bool background_)
+ : OpenCLDeviceBase(info, stats, background_)
+ {
+ background = background_;
+
+ /* Initialize kernels. */
+ ckPathTraceKernel_data_init = NULL;
+ ckPathTraceKernel_scene_intersect = NULL;
+ ckPathTraceKernel_lamp_emission = NULL;
+ ckPathTraceKernel_background_buffer_update = NULL;
+ ckPathTraceKernel_shader_eval = NULL;
+ ckPathTraceKernel_holdout_emission_blurring_pathtermination_ao = NULL;
+ ckPathTraceKernel_direct_lighting = NULL;
+ ckPathTraceKernel_shadow_blocked = NULL;
+ ckPathTraceKernel_next_iteration_setup = NULL;
+ ckPathTraceKernel_sum_all_radiance = NULL;
+ ckPathTraceKernel_queue_enqueue = NULL;
+
+ /* Initialize program. */
+ data_init_program = NULL;
+ scene_intersect_program = NULL;
+ lamp_emission_program = NULL;
+ queue_enqueue_program = NULL;
+ background_buffer_update_program = NULL;
+ shader_eval_program = NULL;
+ holdout_emission_blurring_pathtermination_ao_program = NULL;
+ direct_lighting_program = NULL;
+ shadow_blocked_program = NULL;
+ next_iteration_setup_program = NULL;
+ sum_all_radiance_program = NULL;
+
+ /* Initialize cl_mem variables. */
+ kgbuffer = NULL;
+ sd = NULL;
+ sd_DL_shadow = NULL;
+
+ P_sd = NULL;
+ P_sd_DL_shadow = NULL;
+ N_sd = NULL;
+ N_sd_DL_shadow = NULL;
+ Ng_sd = NULL;
+ Ng_sd_DL_shadow = NULL;
+ I_sd = NULL;
+ I_sd_DL_shadow = NULL;
+ shader_sd = NULL;
+ shader_sd_DL_shadow = NULL;
+ flag_sd = NULL;
+ flag_sd_DL_shadow = NULL;
+ prim_sd = NULL;
+ prim_sd_DL_shadow = NULL;
+ type_sd = NULL;
+ type_sd_DL_shadow = NULL;
+ u_sd = NULL;
+ u_sd_DL_shadow = NULL;
+ v_sd = NULL;
+ v_sd_DL_shadow = NULL;
+ object_sd = NULL;
+ object_sd_DL_shadow = NULL;
+ time_sd = NULL;
+ time_sd_DL_shadow = NULL;
+ ray_length_sd = NULL;
+ ray_length_sd_DL_shadow = NULL;
+ ray_depth_sd = NULL;
+ ray_depth_sd_DL_shadow = NULL;
+ transparent_depth_sd = NULL;
+ transparent_depth_sd_DL_shadow = NULL;
+
+ /* Ray differentials. */
+ dP_sd = NULL;
+ dI_sd = NULL;
+ dP_sd_DL_shadow = NULL;
+ dI_sd_DL_shadow = NULL;
+ du_sd = NULL;
+ dv_sd = NULL;
+ du_sd_DL_shadow = NULL;
+ dv_sd_DL_shadow = NULL;
+
+ /* Dp/Du */
+ dPdu_sd = NULL;
+ dPdv_sd = NULL;
+ dPdu_sd_DL_shadow = NULL;
+ dPdv_sd_DL_shadow = NULL;
+
+ /* Object motion. */
+ ob_tfm_sd = NULL;
+ ob_itfm_sd = NULL;
+ ob_tfm_sd_DL_shadow = NULL;
+ ob_itfm_sd_DL_shadow = NULL;
+
+ closure_sd = NULL;
+ closure_sd_DL_shadow = NULL;
+ num_closure_sd = NULL;
+ num_closure_sd_DL_shadow = NULL;
+ randb_closure_sd = NULL;
+ randb_closure_sd_DL_shadow = NULL;
+ ray_P_sd = NULL;
+ ray_P_sd_DL_shadow = NULL;
+ ray_dP_sd = NULL;
+ ray_dP_sd_DL_shadow = NULL;
+
+ rng_coop = NULL;
+ throughput_coop = NULL;
+ L_transparent_coop = NULL;
+ PathRadiance_coop = NULL;
+ Ray_coop = NULL;
+ PathState_coop = NULL;
+ Intersection_coop = NULL;
+ ray_state = NULL;
+
+ AOAlpha_coop = NULL;
+ AOBSDF_coop = NULL;
+ AOLightRay_coop = NULL;
+ BSDFEval_coop = NULL;
+ ISLamp_coop = NULL;
+ LightRay_coop = NULL;
+ Intersection_coop_AO = NULL;
+ Intersection_coop_DL = NULL;
+
+#ifdef WITH_CYCLES_DEBUG
+ debugdata_coop = NULL;
+#endif
+
+ work_array = NULL;
+
+ /* Queue. */
+ Queue_data = NULL;
+ Queue_index = NULL;
+ use_queues_flag = NULL;
+
+ per_sample_output_buffers = NULL;
+
+ per_thread_output_buffer_size = 0;
+ hostRayStateArray = NULL;
+ PathIteration_times = PATH_ITER_INC_FACTOR;
+#ifdef __WORK_STEALING__
+ work_pool_wgs = NULL;
+ max_work_groups = 0;
+#endif
+ current_max_closure = -1;
+ first_tile = true;
+
+ /* Get device's maximum memory that can be allocated. */
+ ciErr = clGetDeviceInfo(cdDevice,
+ CL_DEVICE_MAX_MEM_ALLOC_SIZE,
+ sizeof(size_t),
+ &total_allocatable_memory,
+ NULL);
+ assert(ciErr == CL_SUCCESS);
+ if(platform_name == "AMD Accelerated Parallel Processing") {
+ /* This value is tweak-able; AMD platform does not seem to
+ * give maximum performance when all of CL_DEVICE_MAX_MEM_ALLOC_SIZE
+ * is considered for further computation.
+ */
+ total_allocatable_memory /= 2;
+ }
+ }
+
+ /* 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,
+ cl_program *program,
+ const string *debug_src = NULL)
+ {
+ if(!opencl_version_check())
+ return false;
+
+ 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)) {
+ /* Kernel loaded from binary. */
+ }
+ else {
+ /* If does not exist or loading binary failed, compile kernel. */
+ if(!compile_kernel(kernel_path,
+ kernel_init_source,
+ custom_kernel_build_options,
+ program,
+ debug_src))
+ {
+ return false;
+ }
+ /* Save binary for reuse. */
+ if(!save_binary(program, clbin)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /* Split kernel utility functions. */
+ size_t get_tex_size(const char *tex_name)
+ {
+ cl_mem ptr;
+ size_t ret_size = 0;
+ MemMap::iterator i = mem_map.find(tex_name);
+ if(i != mem_map.end()) {
+ ptr = CL_MEM_PTR(i->second);
+ ciErr = clGetMemObjectInfo(ptr,
+ CL_MEM_SIZE,
+ sizeof(ret_size),
+ &ret_size,
+ NULL);
+ assert(ciErr == CL_SUCCESS);
+ }
+ return ret_size;
+ }
+
+ size_t get_shader_closure_size(int max_closure)
+ {
+ return (sizeof(ShaderClosure) * max_closure);
+ }
+
+ size_t get_shader_data_size(size_t shader_closure_size)
+ {
+ /* ShaderData size without accounting for ShaderClosure array. */
+ size_t shader_data_size =
+ sizeof(ShaderData) - (sizeof(ShaderClosure) * MAX_CLOSURE);
+ return (shader_data_size + shader_closure_size);
+ }
+
+ /* Returns size of KernelGlobals structure associated with OpenCL. */
+ size_t get_KernelGlobals_size()
+ {
+ /* Copy dummy KernelGlobals related to OpenCL from kernel_globals.h to
+ * fetch its size.
+ */
+ typedef struct KernelGlobals {
+ ccl_constant KernelData *data;
+#define KERNEL_TEX(type, ttype, name) \
+ ccl_global type *name;
+#include "kernel_textures.h"
+#undef KERNEL_TEX
+ } KernelGlobals;
+
+ return sizeof(KernelGlobals);
+ }
+
+ /* Returns size of Structure of arrays implementation of. */
+ size_t get_shaderdata_soa_size()
+ {
+ size_t shader_soa_size = 0;
+
+#define SD_VAR(type, what) shader_soa_size += sizeof(void *);
+#define SD_CLOSURE_VAR(type, what, max_closure) shader_soa_size += sizeof(void *);
+ #include "kernel_shaderdata_vars.h"
+#undef SD_VAR
+#undef SD_CLOSURE_VAR
+
+ return shader_soa_size;
+ }
+
+ bool load_kernels(const DeviceRequestedFeatures& requested_features)
+ {
+ /* Get Shader, bake and film_convert kernels.
+ * It'll also do verification of OpenCL actually initialized.
+ */
+ if(!OpenCLDeviceBase::load_kernels(requested_features)) {
+ return false;
+ }
+
+ string kernel_path = path_get("kernel");
+ string kernel_md5 = path_files_md5_hash(kernel_path);
+ string device_md5;
+ string kernel_init_source;
+ string clbin;
+ string clsrc, *debug_src = NULL;
+
+ string build_options = "-D__SPLIT_KERNEL__";
+#ifdef __WORK_STEALING__
+ build_options += " -D__WORK_STEALING__";
+#endif
+ build_options += build_options_from_requested_features(requested_features);
+
+ /* Set compute device build option. */
+ cl_device_type device_type;
+ ciErr = clGetDeviceInfo(cdDevice,
+ CL_DEVICE_TYPE,
+ sizeof(cl_device_type),
+ &device_type,
+ NULL);
+ assert(ciErr == CL_SUCCESS);
+ if(device_type == CL_DEVICE_TYPE_GPU) {
+ build_options += " -D__COMPUTE_DEVICE_GPU__";
+ }
+
+#define GLUE(a, b) a ## b
+#define LOAD_KERNEL(name) \
+ do { \
+ kernel_init_source = "#include \"kernels/opencl/kernel_" #name ".cl\" // " + \
+ kernel_md5 + "\n"; \
+ device_md5 = device_md5_hash(build_options); \
+ clbin = string_printf("cycles_kernel_%s_%s_" #name ".clbin", \
+ device_md5.c_str(), kernel_md5.c_str()); \
+ if(opencl_kernel_use_debug()) { \
+ clsrc = string_printf("cycles_kernel_%s_%s_" #name ".cl", \
+ device_md5.c_str(), kernel_md5.c_str()); \
+ clsrc = path_user_get(path_join("cache", clsrc)); \
+ debug_src = &clsrc; \
+ } \
+ if(!load_split_kernel(kernel_path, kernel_init_source, clbin, \
+ build_options, \
+ &GLUE(name, _program), \
+ debug_src)) \
+ { \
+ fprintf(stderr, "Faled to compile %s\n", #name); \
+ return false; \
+ } \
+ } while(false)
+
+ LOAD_KERNEL(data_init);
+ LOAD_KERNEL(scene_intersect);
+ LOAD_KERNEL(lamp_emission);
+ LOAD_KERNEL(queue_enqueue);
+ LOAD_KERNEL(background_buffer_update);
+ LOAD_KERNEL(shader_eval);
+ LOAD_KERNEL(holdout_emission_blurring_pathtermination_ao);
+ LOAD_KERNEL(direct_lighting);
+ LOAD_KERNEL(shadow_blocked);
+ LOAD_KERNEL(next_iteration_setup);
+ LOAD_KERNEL(sum_all_radiance);
+
+#undef LOAD_KERNEL
+
+#define FIND_KERNEL(name) \
+ do { \
+ GLUE(ckPathTraceKernel_, name) = \
+ clCreateKernel(GLUE(name, _program), \
+ "kernel_ocl_path_trace_" #name, &ciErr); \
+ if(opencl_error(ciErr)) { \
+ fprintf(stderr,"Missing kernel kernel_ocl_path_trace_%s\n", #name); \
+ return false; \
+ } \
+ } while(false)
+
+ FIND_KERNEL(data_init);
+ FIND_KERNEL(scene_intersect);
+ FIND_KERNEL(lamp_emission);
+ FIND_KERNEL(queue_enqueue);
+ FIND_KERNEL(background_buffer_update);
+ FIND_KERNEL(shader_eval);
+ FIND_KERNEL(holdout_emission_blurring_pathtermination_ao);
+ FIND_KERNEL(direct_lighting);
+ FIND_KERNEL(shadow_blocked);
+ FIND_KERNEL(next_iteration_setup);
+ FIND_KERNEL(sum_all_radiance);
+#undef FIND_KERNEL
+#undef GLUE
+
+ current_max_closure = requested_features.max_closure;
+
+ return true;
+ }
+
+ ~OpenCLDeviceSplitKernel()
+ {
+ task_pool.stop();
+
+ /* Release kernels */
+ release_kernel_safe(ckPathTraceKernel_data_init);
+ release_kernel_safe(ckPathTraceKernel_scene_intersect);
+ release_kernel_safe(ckPathTraceKernel_lamp_emission);
+ release_kernel_safe(ckPathTraceKernel_queue_enqueue);
+ release_kernel_safe(ckPathTraceKernel_background_buffer_update);
+ release_kernel_safe(ckPathTraceKernel_shader_eval);
+ release_kernel_safe(ckPathTraceKernel_holdout_emission_blurring_pathtermination_ao);
+ release_kernel_safe(ckPathTraceKernel_direct_lighting);
+ release_kernel_safe(ckPathTraceKernel_shadow_blocked);
+ release_kernel_safe(ckPathTraceKernel_next_iteration_setup);
+ release_kernel_safe(ckPathTraceKernel_sum_all_radiance);
+
+ /* Release global memory */
+ release_mem_object_safe(P_sd);
+ release_mem_object_safe(P_sd_DL_shadow);
+ release_mem_object_safe(N_sd);
+ release_mem_object_safe(N_sd_DL_shadow);
+ release_mem_object_safe(Ng_sd);
+ release_mem_object_safe(Ng_sd_DL_shadow);
+ release_mem_object_safe(I_sd);
+ release_mem_object_safe(I_sd_DL_shadow);
+ release_mem_object_safe(shader_sd);
+ release_mem_object_safe(shader_sd_DL_shadow);
+ release_mem_object_safe(flag_sd);
+ release_mem_object_safe(flag_sd_DL_shadow);
+ release_mem_object_safe(prim_sd);
+ release_mem_object_safe(prim_sd_DL_shadow);
+ release_mem_object_safe(type_sd);
+ release_mem_object_safe(type_sd_DL_shadow);
+ release_mem_object_safe(u_sd);
+ release_mem_object_safe(u_sd_DL_shadow);
+ release_mem_object_safe(v_sd);
+ release_mem_object_safe(v_sd_DL_shadow);
+ release_mem_object_safe(object_sd);
+ release_mem_object_safe(object_sd_DL_shadow);
+ release_mem_object_safe(time_sd);
+ release_mem_object_safe(time_sd_DL_shadow);
+ release_mem_object_safe(ray_length_sd);
+ release_mem_object_safe(ray_length_sd_DL_shadow);
+ release_mem_object_safe(ray_depth_sd);
+ release_mem_object_safe(ray_depth_sd_DL_shadow);
+ release_mem_object_safe(transparent_depth_sd);
+ release_mem_object_safe(transparent_depth_sd_DL_shadow);
+
+ /* Ray differentials. */
+ release_mem_object_safe(dP_sd);
+ release_mem_object_safe(dP_sd_DL_shadow);
+ release_mem_object_safe(dI_sd);
+ release_mem_object_safe(dI_sd_DL_shadow);
+ release_mem_object_safe(du_sd);
+ release_mem_object_safe(du_sd_DL_shadow);
+ release_mem_object_safe(dv_sd);
+ release_mem_object_safe(dv_sd_DL_shadow);
+
+ /* Dp/Du */
+ release_mem_object_safe(dPdu_sd);
+ release_mem_object_safe(dPdu_sd_DL_shadow);
+ release_mem_object_safe(dPdv_sd);
+ release_mem_object_safe(dPdv_sd_DL_shadow);
+
+ /* Object motion. */
+ release_mem_object_safe(ob_tfm_sd);
+ release_mem_object_safe(ob_itfm_sd);
+
+ release_mem_object_safe(ob_tfm_sd_DL_shadow);
+ release_mem_object_safe(ob_itfm_sd_DL_shadow);
+
+ release_mem_object_safe(closure_sd);
+ release_mem_object_safe(closure_sd_DL_shadow);
+ release_mem_object_safe(num_closure_sd);
+ release_mem_object_safe(num_closure_sd_DL_shadow);
+ release_mem_object_safe(randb_closure_sd);
+ release_mem_object_safe(randb_closure_sd_DL_shadow);
+ release_mem_object_safe(ray_P_sd);
+ release_mem_object_safe(ray_P_sd_DL_shadow);
+ release_mem_object_safe(ray_dP_sd);
+ release_mem_object_safe(ray_dP_sd_DL_shadow);
+ release_mem_object_safe(rng_coop);
+ release_mem_object_safe(throughput_coop);
+ release_mem_object_safe(L_transparent_coop);
+ release_mem_object_safe(PathRadiance_coop);
+ release_mem_object_safe(Ray_coop);
+ release_mem_object_safe(PathState_coop);
+ release_mem_object_safe(Intersection_coop);
+ release_mem_object_safe(kgbuffer);
+ release_mem_object_safe(sd);
+ release_mem_object_safe(sd_DL_shadow);
+ release_mem_object_safe(ray_state);
+ release_mem_object_safe(AOAlpha_coop);
+ release_mem_object_safe(AOBSDF_coop);
+ release_mem_object_safe(AOLightRay_coop);
+ release_mem_object_safe(BSDFEval_coop);
+ release_mem_object_safe(ISLamp_coop);
+ release_mem_object_safe(LightRay_coop);
+ release_mem_object_safe(Intersection_coop_AO);
+ release_mem_object_safe(Intersection_coop_DL);
+#ifdef WITH_CYCLES_DEBUG
+ release_mem_object_safe(debugdata_coop);
+#endif
+ release_mem_object_safe(use_queues_flag);
+ release_mem_object_safe(Queue_data);
+ release_mem_object_safe(Queue_index);
+ release_mem_object_safe(work_array);
+#ifdef __WORK_STEALING__
+ release_mem_object_safe(work_pool_wgs);
+#endif
+ release_mem_object_safe(per_sample_output_buffers);
+
+ /* Release programs */
+ release_program_safe(data_init_program);
+ release_program_safe(scene_intersect_program);
+ release_program_safe(lamp_emission_program);
+ release_program_safe(queue_enqueue_program);
+ release_program_safe(background_buffer_update_program);
+ release_program_safe(shader_eval_program);
+ release_program_safe(holdout_emission_blurring_pathtermination_ao_program);
+ release_program_safe(direct_lighting_program);
+ release_program_safe(shadow_blocked_program);
+ release_program_safe(next_iteration_setup_program);
+ release_program_safe(sum_all_radiance_program);
+
+ if(hostRayStateArray != NULL) {
+ free(hostRayStateArray);
+ }
+ }
+
+ void path_trace(SplitRenderTile& rtile, int2 max_render_feasible_tile_size)
+ {
+ /* cast arguments to cl types */
+ cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
+ cl_mem d_buffer = CL_MEM_PTR(rtile.buffer);
+ cl_mem d_rng_state = CL_MEM_PTR(rtile.rng_state);
+ cl_int d_x = rtile.x;
+ cl_int d_y = rtile.y;
+ cl_int d_w = rtile.w;
+ cl_int d_h = rtile.h;
+ cl_int d_offset = rtile.offset;
+ cl_int d_stride = rtile.stride;
+
+ /* Make sure that set render feasible tile size is a multiple of local
+ * work size dimensions.
+ */
+ assert(max_render_feasible_tile_size.x % SPLIT_KERNEL_LOCAL_SIZE_X == 0);
+ assert(max_render_feasible_tile_size.y % SPLIT_KERNEL_LOCAL_SIZE_Y == 0);
+
+ size_t global_size[2];
+ size_t local_size[2] = {SPLIT_KERNEL_LOCAL_SIZE_X,
+ SPLIT_KERNEL_LOCAL_SIZE_Y};
+
+ /* Set the range of samples to be processed for every ray in
+ * path-regeneration logic.
+ */
+ cl_int start_sample = rtile.start_sample;
+ cl_int end_sample = rtile.start_sample + rtile.num_samples;
+ cl_int num_samples = rtile.num_samples;
+
+#ifdef __WORK_STEALING__
+ global_size[0] = (((d_w - 1) / local_size[0]) + 1) * local_size[0];
+ global_size[1] = (((d_h - 1) / local_size[1]) + 1) * local_size[1];
+ unsigned int num_parallel_samples = 1;
+#else
+ global_size[1] = (((d_h - 1) / local_size[1]) + 1) * local_size[1];
+ unsigned int num_threads = max_render_feasible_tile_size.x *
+ max_render_feasible_tile_size.y;
+ unsigned int num_tile_columns_possible = num_threads / global_size[1];
+ /* Estimate number of parallel samples that can be
+ * processed in parallel.
+ */
+ unsigned int num_parallel_samples = min(num_tile_columns_possible / d_w,
+ rtile.num_samples);
+ /* Wavefront size in AMD is 64.
+ * TODO(sergey): What about other platforms?
+ */
+ if(num_parallel_samples >= 64) {
+ /* TODO(sergey): Could use generic round-up here. */
+ num_parallel_samples = (num_parallel_samples / 64) * 64;
+ }
+ assert(num_parallel_samples != 0);
+
+ global_size[0] = d_w * num_parallel_samples;
+#endif /* __WORK_STEALING__ */
+
+ assert(global_size[0] * global_size[1] <=
+ max_render_feasible_tile_size.x * max_render_feasible_tile_size.y);
+
+ /* Allocate all required global memory once. */
+ if(first_tile) {
+ size_t num_global_elements = max_render_feasible_tile_size.x *
+ max_render_feasible_tile_size.y;
+ /* TODO(sergey): This will actually over-allocate if
+ * particular kernel does not support multiclosure.
+ */
+ size_t ShaderClosure_size = get_shader_closure_size(current_max_closure);
+
+#ifdef __WORK_STEALING__
+ /* Calculate max groups */
+ size_t max_global_size[2];
+ size_t tile_x = max_render_feasible_tile_size.x;
+ size_t tile_y = max_render_feasible_tile_size.y;
+ max_global_size[0] = (((tile_x - 1) / local_size[0]) + 1) * local_size[0];
+ max_global_size[1] = (((tile_y - 1) / local_size[1]) + 1) * local_size[1];
+ max_work_groups = (max_global_size[0] * max_global_size[1]) /
+ (local_size[0] * local_size[1]);
+ /* Allocate work_pool_wgs memory. */
+ work_pool_wgs = mem_alloc(max_work_groups * sizeof(unsigned int));
+#endif /* __WORK_STEALING__ */
+
+ /* Allocate queue_index memory only once. */
+ Queue_index = mem_alloc(NUM_QUEUES * sizeof(int));
+ use_queues_flag = mem_alloc(sizeof(char));
+ kgbuffer = mem_alloc(get_KernelGlobals_size());
+
+ /* Create global buffers for ShaderData. */
+ sd = mem_alloc(get_shaderdata_soa_size());
+ sd_DL_shadow = mem_alloc(get_shaderdata_soa_size());
+ P_sd = mem_alloc(num_global_elements * sizeof(float3));
+ P_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float3));
+ N_sd = mem_alloc(num_global_elements * sizeof(float3));
+ N_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float3));
+ Ng_sd = mem_alloc(num_global_elements * sizeof(float3));
+ Ng_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float3));
+ I_sd = mem_alloc(num_global_elements * sizeof(float3));
+ I_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float3));
+ shader_sd = mem_alloc(num_global_elements * sizeof(int));
+ shader_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(int));
+ flag_sd = mem_alloc(num_global_elements * sizeof(int));
+ flag_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(int));
+ prim_sd = mem_alloc(num_global_elements * sizeof(int));
+ prim_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(int));
+ type_sd = mem_alloc(num_global_elements * sizeof(int));
+ type_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(int));
+ u_sd = mem_alloc(num_global_elements * sizeof(float));
+ u_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float));
+ v_sd = mem_alloc(num_global_elements * sizeof(float));
+ v_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float));
+ object_sd = mem_alloc(num_global_elements * sizeof(int));
+ object_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(int));
+ time_sd = mem_alloc(num_global_elements * sizeof(float));
+ time_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float));
+ ray_length_sd = mem_alloc(num_global_elements * sizeof(float));
+ ray_length_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float));
+ ray_depth_sd = mem_alloc(num_global_elements * sizeof(int));
+ ray_depth_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(int));
+ transparent_depth_sd = mem_alloc(num_global_elements * sizeof(int));
+ transparent_depth_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(int));
+
+ /* Ray differentials. */
+ dP_sd = mem_alloc(num_global_elements * sizeof(differential3));
+ dP_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(differential3));
+ dI_sd = mem_alloc(num_global_elements * sizeof(differential3));
+ dI_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(differential3));
+ du_sd = mem_alloc(num_global_elements * sizeof(differential));
+ du_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(differential));
+ dv_sd = mem_alloc(num_global_elements * sizeof(differential));
+ dv_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(differential));
+
+ /* Dp/Du */
+ dPdu_sd = mem_alloc(num_global_elements * sizeof(float3));
+ dPdu_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float3));
+ dPdv_sd = mem_alloc(num_global_elements * sizeof(float3));
+ dPdv_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float3));
+
+ /* Object motion. */
+ ob_tfm_sd = mem_alloc(num_global_elements * sizeof(Transform));
+ ob_tfm_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(Transform));
+ ob_itfm_sd = mem_alloc(num_global_elements * sizeof(Transform));
+ ob_itfm_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(Transform));
+
+ closure_sd = mem_alloc(num_global_elements * ShaderClosure_size);
+ closure_sd_DL_shadow = mem_alloc(num_global_elements * 2 * ShaderClosure_size);
+ num_closure_sd = mem_alloc(num_global_elements * sizeof(int));
+ num_closure_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(int));
+ randb_closure_sd = mem_alloc(num_global_elements * sizeof(float));
+ randb_closure_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float));
+ ray_P_sd = mem_alloc(num_global_elements * sizeof(float3));
+ ray_P_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float3));
+ ray_dP_sd = mem_alloc(num_global_elements * sizeof(differential3));
+ ray_dP_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(differential3));
+
+ /* Creation of global memory buffers which are shared among
+ * the kernels.
+ */
+ rng_coop = mem_alloc(num_global_elements * sizeof(RNG));
+ throughput_coop = mem_alloc(num_global_elements * sizeof(float3));
+ L_transparent_coop = mem_alloc(num_global_elements * sizeof(float));
+ PathRadiance_coop = mem_alloc(num_global_elements * sizeof(PathRadiance));
+ Ray_coop = mem_alloc(num_global_elements * sizeof(Ray));
+ PathState_coop = mem_alloc(num_global_elements * sizeof(PathState));
+ Intersection_coop = mem_alloc(num_global_elements * sizeof(Intersection));
+ AOAlpha_coop = mem_alloc(num_global_elements * sizeof(float3));
+ AOBSDF_coop = mem_alloc(num_global_elements * sizeof(float3));
+ AOLightRay_coop = mem_alloc(num_global_elements * sizeof(Ray));
+ BSDFEval_coop = mem_alloc(num_global_elements * sizeof(BsdfEval));
+ ISLamp_coop = mem_alloc(num_global_elements * sizeof(int));
+ LightRay_coop = mem_alloc(num_global_elements * sizeof(Ray));
+ Intersection_coop_AO = mem_alloc(num_global_elements * sizeof(Intersection));
+ Intersection_coop_DL = mem_alloc(num_global_elements * sizeof(Intersection));
+
+#ifdef WITH_CYCLES_DEBUG
+ debugdata_coop = mem_alloc(num_global_elements * sizeof(DebugData));
+#endif
+
+ ray_state = mem_alloc(num_global_elements * sizeof(char));
+
+ hostRayStateArray = (char *)calloc(num_global_elements, sizeof(char));
+ assert(hostRayStateArray != NULL && "Can't create hostRayStateArray memory");
+
+ Queue_data = mem_alloc(num_global_elements * (NUM_QUEUES * sizeof(int)+sizeof(int)));
+ work_array = mem_alloc(num_global_elements * sizeof(unsigned int));
+ per_sample_output_buffers = mem_alloc(num_global_elements *
+ per_thread_output_buffer_size);
+ }
+
+ cl_int dQueue_size = global_size[0] * global_size[1];
+ cl_int total_num_rays = global_size[0] * global_size[1];
+
+ cl_uint start_arg_index =
+ kernel_set_args(ckPathTraceKernel_data_init,
+ 0,
+ kgbuffer,
+ sd,
+ sd_DL_shadow,
+ P_sd,
+ P_sd_DL_shadow,
+ N_sd,
+ N_sd_DL_shadow,
+ Ng_sd,
+ Ng_sd_DL_shadow,
+ I_sd,
+ I_sd_DL_shadow,
+ shader_sd,
+ shader_sd_DL_shadow,
+ flag_sd,
+ flag_sd_DL_shadow,
+ prim_sd,
+ prim_sd_DL_shadow,
+ type_sd,
+ type_sd_DL_shadow,
+ u_sd,
+ u_sd_DL_shadow,
+ v_sd,
+ v_sd_DL_shadow,
+ object_sd,
+ object_sd_DL_shadow,
+ time_sd,
+ time_sd_DL_shadow,
+ ray_length_sd,
+ ray_length_sd_DL_shadow,
+ ray_depth_sd,
+ ray_depth_sd_DL_shadow,
+ transparent_depth_sd,
+ transparent_depth_sd_DL_shadow);
+
+ /* Ray differentials. */
+ start_arg_index +=
+ kernel_set_args(ckPathTraceKernel_data_init,
+ start_arg_index,
+ dP_sd,
+ dP_sd_DL_shadow,
+ dI_sd,
+ dI_sd_DL_shadow,
+ du_sd,
+ du_sd_DL_shadow,
+ dv_sd,
+ dv_sd_DL_shadow);
+
+ /* Dp/Du */
+ start_arg_index +=
+ kernel_set_args(ckPathTraceKernel_data_init,
+ start_arg_index,
+ dPdu_sd,
+ dPdu_sd_DL_shadow,
+ dPdv_sd,
+ dPdv_sd_DL_shadow);
+
+ /* Object motion. */
+ start_arg_index +=
+ kernel_set_args(ckPathTraceKernel_data_init,
+ start_arg_index,
+ ob_tfm_sd,
+ ob_tfm_sd_DL_shadow,
+ ob_itfm_sd,
+ ob_itfm_sd_DL_shadow);
+
+ start_arg_index +=
+ kernel_set_args(ckPathTraceKernel_data_init,
+ start_arg_index,
+ closure_sd,
+ closure_sd_DL_shadow,
+ num_closure_sd,
+ num_closure_sd_DL_shadow,
+ randb_closure_sd,
+ randb_closure_sd_DL_shadow,
+ ray_P_sd,
+ ray_P_sd_DL_shadow,
+ ray_dP_sd,
+ ray_dP_sd_DL_shadow,
+ d_data,
+ per_sample_output_buffers,
+ d_rng_state,
+ rng_coop,
+ throughput_coop,
+ L_transparent_coop,
+ PathRadiance_coop,
+ Ray_coop,
+ PathState_coop,
+ ray_state);
+
+/* TODO(segrey): Avoid map lookup here. */
+#define KERNEL_TEX(type, ttype, name) \
+ set_kernel_arg_mem(ckPathTraceKernel_data_init, &start_arg_index, #name);
+#include "kernel_textures.h"
+#undef KERNEL_TEX
+
+ start_arg_index +=
+ kernel_set_args(ckPathTraceKernel_data_init,
+ start_arg_index,
+ start_sample,
+ d_x,
+ d_y,
+ d_w,
+ d_h,
+ d_offset,
+ d_stride,
+ rtile.rng_state_offset_x,
+ rtile.rng_state_offset_y,
+ rtile.buffer_rng_state_stride,
+ Queue_data,
+ Queue_index,
+ dQueue_size,
+ use_queues_flag,
+ work_array,
+#ifdef __WORK_STEALING__
+ work_pool_wgs,
+ num_samples,
+#endif
+#ifdef WITH_CYCLES_DEBUG
+ debugdata_coop,
+#endif
+ num_parallel_samples);
+
+ kernel_set_args(ckPathTraceKernel_scene_intersect,
+ 0,
+ kgbuffer,
+ d_data,
+ rng_coop,
+ Ray_coop,
+ PathState_coop,
+ Intersection_coop,
+ ray_state,
+ d_w,
+ d_h,
+ Queue_data,
+ Queue_index,
+ dQueue_size,
+ use_queues_flag,
+#ifdef WITH_CYCLES_DEBUG
+ debugdata_coop,
+#endif
+ num_parallel_samples);
+
+ kernel_set_args(ckPathTraceKernel_lamp_emission,
+ 0,
+ kgbuffer,
+ d_data,
+ sd,
+ throughput_coop,
+ PathRadiance_coop,
+ Ray_coop,
+ PathState_coop,
+ Intersection_coop,
+ ray_state,
+ d_w,
+ d_h,
+ Queue_data,
+ Queue_index,
+ dQueue_size,
+ use_queues_flag,
+ num_parallel_samples);
+
+ kernel_set_args(ckPathTraceKernel_queue_enqueue,
+ 0,
+ Queue_data,
+ Queue_index,
+ ray_state,
+ dQueue_size);
+
+ kernel_set_args(ckPathTraceKernel_background_buffer_update,
+ 0,
+ kgbuffer,
+ d_data,
+ sd,
+ per_sample_output_buffers,
+ d_rng_state,
+ rng_coop,
+ throughput_coop,
+ PathRadiance_coop,
+ Ray_coop,
+ PathState_coop,
+ L_transparent_coop,
+ ray_state,
+ d_w,
+ d_h,
+ d_x,
+ d_y,
+ d_stride,
+ rtile.rng_state_offset_x,
+ rtile.rng_state_offset_y,
+ rtile.buffer_rng_state_stride,
+ work_array,
+ Queue_data,
+ Queue_index,
+ dQueue_size,
+ end_sample,
+ start_sample,
+#ifdef __WORK_STEALING__
+ work_pool_wgs,
+ num_samples,
+#endif
+#ifdef WITH_CYCLES_DEBUG
+ debugdata_coop,
+#endif
+ num_parallel_samples);
+
+ kernel_set_args(ckPathTraceKernel_shader_eval,
+ 0,
+ kgbuffer,
+ d_data,
+ sd,
+ rng_coop,
+ Ray_coop,
+ PathState_coop,
+ Intersection_coop,
+ ray_state,
+ Queue_data,
+ Queue_index,
+ dQueue_size);
+
+ kernel_set_args(ckPathTraceKernel_holdout_emission_blurring_pathtermination_ao,
+ 0,
+ kgbuffer,
+ d_data,
+ sd,
+ per_sample_output_buffers,
+ rng_coop,
+ throughput_coop,
+ L_transparent_coop,
+ PathRadiance_coop,
+ PathState_coop,
+ Intersection_coop,
+ AOAlpha_coop,
+ AOBSDF_coop,
+ AOLightRay_coop,
+ d_w,
+ d_h,
+ d_x,
+ d_y,
+ d_stride,
+ ray_state,
+ work_array,
+ Queue_data,
+ Queue_index,
+ dQueue_size,
+#ifdef __WORK_STEALING__
+ start_sample,
+#endif
+ num_parallel_samples);
+
+ kernel_set_args(ckPathTraceKernel_direct_lighting,
+ 0,
+ kgbuffer,
+ d_data,
+ sd,
+ sd_DL_shadow,
+ rng_coop,
+ PathState_coop,
+ ISLamp_coop,
+ LightRay_coop,
+ BSDFEval_coop,
+ ray_state,
+ Queue_data,
+ Queue_index,
+ dQueue_size);
+
+ kernel_set_args(ckPathTraceKernel_shadow_blocked,
+ 0,
+ kgbuffer,
+ d_data,
+ sd_DL_shadow,
+ PathState_coop,
+ LightRay_coop,
+ AOLightRay_coop,
+ Intersection_coop_AO,
+ Intersection_coop_DL,
+ ray_state,
+ Queue_data,
+ Queue_index,
+ dQueue_size,
+ total_num_rays);
+
+ kernel_set_args(ckPathTraceKernel_next_iteration_setup,
+ 0,
+ kgbuffer,
+ d_data,
+ sd,
+ rng_coop,
+ throughput_coop,
+ PathRadiance_coop,
+ Ray_coop,
+ PathState_coop,
+ LightRay_coop,
+ ISLamp_coop,
+ BSDFEval_coop,
+ AOLightRay_coop,
+ AOBSDF_coop,
+ AOAlpha_coop,
+ ray_state,
+ Queue_data,
+ Queue_index,
+ dQueue_size,
+ use_queues_flag);
+
+ kernel_set_args(ckPathTraceKernel_sum_all_radiance,
+ 0,
+ d_data,
+ d_buffer,
+ per_sample_output_buffers,
+ num_parallel_samples,
+ d_w,
+ d_h,
+ d_stride,
+ rtile.buffer_offset_x,
+ rtile.buffer_offset_y,
+ rtile.buffer_rng_state_stride,
+ start_sample);
+
+ /* Macro for Enqueuing split kernels. */
+#define GLUE(a, b) a ## b
+#define ENQUEUE_SPLIT_KERNEL(kernelName, globalSize, localSize) \
+ opencl_assert(clEnqueueNDRangeKernel(cqCommandQueue, \
+ GLUE(ckPathTraceKernel_, \
+ kernelName), \
+ 2, \
+ NULL, \
+ globalSize, \
+ localSize, \
+ 0, \
+ NULL, \
+ NULL))
+
+ /* Enqueue ckPathTraceKernel_data_init kernel. */
+ ENQUEUE_SPLIT_KERNEL(data_init, global_size, local_size);
+ bool activeRaysAvailable = true;
+
+ /* Record number of time host intervention has been made */
+ unsigned int numHostIntervention = 0;
+ unsigned int numNextPathIterTimes = PathIteration_times;
+ while(activeRaysAvailable) {
+ /* Twice the global work size of other kernels for
+ * ckPathTraceKernel_shadow_blocked_direct_lighting. */
+ size_t global_size_shadow_blocked[2];
+ global_size_shadow_blocked[0] = global_size[0] * 2;
+ global_size_shadow_blocked[1] = global_size[1];
+
+ /* Do path-iteration in host [Enqueue Path-iteration kernels. */
+ for(int PathIter = 0; PathIter < PathIteration_times; PathIter++) {
+ ENQUEUE_SPLIT_KERNEL(scene_intersect, global_size, local_size);
+ ENQUEUE_SPLIT_KERNEL(lamp_emission, global_size, local_size);
+ ENQUEUE_SPLIT_KERNEL(queue_enqueue, global_size, local_size);
+ ENQUEUE_SPLIT_KERNEL(background_buffer_update, global_size, local_size);
+ ENQUEUE_SPLIT_KERNEL(shader_eval, global_size, local_size);
+ ENQUEUE_SPLIT_KERNEL(holdout_emission_blurring_pathtermination_ao, global_size, local_size);
+ ENQUEUE_SPLIT_KERNEL(direct_lighting, global_size, local_size);
+ ENQUEUE_SPLIT_KERNEL(shadow_blocked, global_size_shadow_blocked, local_size);
+ ENQUEUE_SPLIT_KERNEL(next_iteration_setup, global_size, local_size);
+ }
+
+ /* Read ray-state into Host memory to decide if we should exit
+ * path-iteration in host.
+ */
+ ciErr = clEnqueueReadBuffer(cqCommandQueue,
+ ray_state,
+ CL_TRUE,
+ 0,
+ global_size[0] * global_size[1] * sizeof(char),
+ hostRayStateArray,
+ 0,
+ NULL,
+ NULL);
+ assert(ciErr == CL_SUCCESS);
+
+ activeRaysAvailable = false;
+
+ for(int rayStateIter = 0;
+ rayStateIter < global_size[0] * global_size[1];
+ ++rayStateIter)
+ {
+ if(int8_t(hostRayStateArray[rayStateIter]) != RAY_INACTIVE) {
+ /* Not all rays are RAY_INACTIVE. */
+ activeRaysAvailable = true;
+ break;
+ }
+ }
+
+ if(activeRaysAvailable) {
+ numHostIntervention++;
+ PathIteration_times = PATH_ITER_INC_FACTOR;
+ /* Host intervention done before all rays become RAY_INACTIVE;
+ * Set do more initial iterations for the next tile.
+ */
+ numNextPathIterTimes += PATH_ITER_INC_FACTOR;
+ }
+ }
+
+ /* Execute SumALLRadiance kernel to accumulate radiance calculated in
+ * per_sample_output_buffers into RenderTile's output buffer.
+ */
+ size_t sum_all_radiance_local_size[2] = {16, 16};
+ size_t sum_all_radiance_global_size[2];
+ sum_all_radiance_global_size[0] =
+ (((d_w - 1) / sum_all_radiance_local_size[0]) + 1) *
+ sum_all_radiance_local_size[0];
+ sum_all_radiance_global_size[1] =
+ (((d_h - 1) / sum_all_radiance_local_size[1]) + 1) *
+ sum_all_radiance_local_size[1];
+ ENQUEUE_SPLIT_KERNEL(sum_all_radiance,
+ sum_all_radiance_global_size,
+ sum_all_radiance_local_size);
+
+#undef ENQUEUE_SPLIT_KERNEL
+#undef GLUE
+
+ if(numHostIntervention == 0) {
+ /* This means that we are executing kernel more than required
+ * Must avoid this for the next sample/tile.
+ */
+ PathIteration_times = ((numNextPathIterTimes - PATH_ITER_INC_FACTOR) <= 0) ?
+ PATH_ITER_INC_FACTOR : numNextPathIterTimes - PATH_ITER_INC_FACTOR;
+ }
+ else {
+ /* Number of path-iterations done for this tile is set as
+ * Initial path-iteration times for the next tile
+ */
+ PathIteration_times = numNextPathIterTimes;
+ }
+
+ first_tile = false;
+ }
+
+ /* Calculates the amount of memory that has to be always
+ * allocated in order for the split kernel to function.
+ * This memory is tile/scene-property invariant (meaning,
+ * the value returned by this function does not depend
+ * on the user set tile size or scene properties.
+ */
+ size_t get_invariable_mem_allocated()
+ {
+ size_t total_invariable_mem_allocated = 0;
+ size_t KernelGlobals_size = 0;
+ size_t ShaderData_SOA_size = 0;
+
+ KernelGlobals_size = get_KernelGlobals_size();
+ ShaderData_SOA_size = get_shaderdata_soa_size();
+
+ total_invariable_mem_allocated += KernelGlobals_size; /* KernelGlobals size */
+ total_invariable_mem_allocated += NUM_QUEUES * sizeof(unsigned int); /* Queue index size */
+ total_invariable_mem_allocated += sizeof(char); /* use_queues_flag size */
+ total_invariable_mem_allocated += ShaderData_SOA_size; /* sd size */
+ total_invariable_mem_allocated += ShaderData_SOA_size; /* sd_DL_shadow size */
+
+ return total_invariable_mem_allocated;
+ }
+
+ /* Calculate the memory that has-to-be/has-been allocated for
+ * the split kernel to function.
+ */
+ size_t get_tile_specific_mem_allocated(const int2 tile_size)
+ {
+ size_t tile_specific_mem_allocated = 0;
+
+ /* Get required tile info */
+ unsigned int user_set_tile_w = tile_size.x;
+ unsigned int user_set_tile_h = tile_size.y;
+
+#ifdef __WORK_STEALING__
+ /* Calculate memory to be allocated for work_pools in
+ * case of work_stealing.
+ */
+ size_t max_global_size[2];
+ size_t max_num_work_pools = 0;
+ max_global_size[0] =
+ (((user_set_tile_w - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_X;
+ max_global_size[1] =
+ (((user_set_tile_h - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_Y;
+ max_num_work_pools =
+ (max_global_size[0] * max_global_size[1]) /
+ (SPLIT_KERNEL_LOCAL_SIZE_X * SPLIT_KERNEL_LOCAL_SIZE_Y);
+ tile_specific_mem_allocated += max_num_work_pools * sizeof(unsigned int);
+#endif
+
+ tile_specific_mem_allocated +=
+ user_set_tile_w * user_set_tile_h * per_thread_output_buffer_size;
+ tile_specific_mem_allocated +=
+ user_set_tile_w * user_set_tile_h * sizeof(RNG);
+
+ return tile_specific_mem_allocated;
+ }
+
+ /* Calculates the texture memories and KernelData (d_data) memory
+ * that has been allocated.
+ */
+ size_t get_scene_specific_mem_allocated(cl_mem d_data)
+ {
+ size_t scene_specific_mem_allocated = 0;
+ /* Calculate texture memories. */
+#define KERNEL_TEX(type, ttype, name) \
+ scene_specific_mem_allocated += get_tex_size(#name);
+#include "kernel_textures.h"
+#undef KERNEL_TEX
+ size_t d_data_size;
+ ciErr = clGetMemObjectInfo(d_data,
+ CL_MEM_SIZE,
+ sizeof(d_data_size),
+ &d_data_size,
+ NULL);
+ assert(ciErr == CL_SUCCESS && "Can't get d_data mem object info");
+ scene_specific_mem_allocated += d_data_size;
+ return scene_specific_mem_allocated;
+ }
+
+ /* Calculate the memory required for one thread in split kernel. */
+ size_t get_per_thread_memory()
+ {
+ size_t shader_closure_size = 0;
+ size_t shaderdata_volume = 0;
+ shader_closure_size = get_shader_closure_size(current_max_closure);
+ /* TODO(sergey): This will actually over-allocate if
+ * particular kernel does not support multiclosure.
+ */
+ shaderdata_volume = get_shader_data_size(shader_closure_size);
+ size_t retval = sizeof(RNG)
+ + sizeof(float3) /* Throughput size */
+ + sizeof(float) /* L transparent size */
+ + sizeof(char) /* Ray state size */
+ + sizeof(unsigned int) /* Work element size */
+ + sizeof(int) /* ISLamp_size */
+ + sizeof(PathRadiance) + sizeof(Ray) + sizeof(PathState)
+ + sizeof(Intersection) /* Overall isect */
+ + sizeof(Intersection) /* Instersection_coop_AO */
+ + sizeof(Intersection) /* Intersection coop DL */
+ + shaderdata_volume /* Overall ShaderData */
+ + (shaderdata_volume * 2) /* ShaderData : DL and shadow */
+ + sizeof(Ray) + sizeof(BsdfEval)
+ + sizeof(float3) /* AOAlpha size */
+ + sizeof(float3) /* AOBSDF size */
+ + sizeof(Ray)
+ + (sizeof(int) * NUM_QUEUES)
+ + per_thread_output_buffer_size;
+ return retval;
+ }
+
+ /* Considers the total memory available in the device and
+ * and returns the maximum global work size possible.
+ */
+ size_t get_feasible_global_work_size(int2 tile_size, cl_mem d_data)
+ {
+ /* Calculate invariably allocated memory. */
+ size_t invariable_mem_allocated = get_invariable_mem_allocated();
+ /* Calculate tile specific allocated memory. */
+ size_t tile_specific_mem_allocated =
+ get_tile_specific_mem_allocated(tile_size);
+ /* Calculate scene specific allocated memory. */
+ size_t scene_specific_mem_allocated =
+ get_scene_specific_mem_allocated(d_data);
+ /* Calculate total memory available for the threads in global work size. */
+ size_t available_memory = total_allocatable_memory
+ - invariable_mem_allocated
+ - tile_specific_mem_allocated
+ - scene_specific_mem_allocated
+ - DATA_ALLOCATION_MEM_FACTOR;
+ size_t per_thread_memory_required = get_per_thread_memory();
+ return (available_memory / per_thread_memory_required);
+ }
+
+ /* Checks if the device has enough memory to render the whole tile;
+ * If not, we should split single tile into multiple tiles of small size
+ * and process them all.
+ */
+ bool need_to_split_tile(unsigned int d_w,
+ unsigned int d_h,
+ int2 max_render_feasible_tile_size)
+ {
+ size_t global_size_estimate[2];
+ /* TODO(sergey): Such round-ups are in quite few places, need to replace
+ * them with an utility macro.
+ */
+ global_size_estimate[0] =
+ (((d_w - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_X;
+ global_size_estimate[1] =
+ (((d_h - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_Y;
+ if((global_size_estimate[0] * global_size_estimate[1]) >
+ (max_render_feasible_tile_size.x * max_render_feasible_tile_size.y))
{
- run = function_bind(&OpenCLDevice::thread_run, device, this);
+ return true;
}
- };
+ else {
+ return false;
+ }
+ }
- int get_split_task_count(DeviceTask& task)
+ /* Considers the scene properties, global memory available in the device
+ * and returns a rectanglular tile dimension (approx the maximum)
+ * that should render on split kernel.
+ */
+ int2 get_max_render_feasible_tile_size(size_t feasible_global_work_size)
{
- return 1;
+ int2 max_render_feasible_tile_size;
+ int square_root_val = (int)sqrt(feasible_global_work_size);
+ max_render_feasible_tile_size.x = square_root_val;
+ max_render_feasible_tile_size.y = square_root_val;
+ /* Ciel round-off max_render_feasible_tile_size. */
+ int2 ceil_render_feasible_tile_size;
+ ceil_render_feasible_tile_size.x =
+ (((max_render_feasible_tile_size.x - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_X;
+ ceil_render_feasible_tile_size.y =
+ (((max_render_feasible_tile_size.y - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_Y;
+ if(ceil_render_feasible_tile_size.x * ceil_render_feasible_tile_size.y <=
+ feasible_global_work_size)
+ {
+ return ceil_render_feasible_tile_size;
+ }
+ /* Floor round-off max_render_feasible_tile_size. */
+ int2 floor_render_feasible_tile_size;
+ floor_render_feasible_tile_size.x =
+ (max_render_feasible_tile_size.x / SPLIT_KERNEL_LOCAL_SIZE_X) *
+ SPLIT_KERNEL_LOCAL_SIZE_X;
+ floor_render_feasible_tile_size.y =
+ (max_render_feasible_tile_size.y / SPLIT_KERNEL_LOCAL_SIZE_Y) *
+ SPLIT_KERNEL_LOCAL_SIZE_Y;
+ return floor_render_feasible_tile_size;
}
- void task_add(DeviceTask& task)
+ /* Try splitting the current tile into multiple smaller
+ * almost-square-tiles.
+ */
+ int2 get_split_tile_size(RenderTile rtile,
+ int2 max_render_feasible_tile_size)
{
- task_pool.push(new OpenCLDeviceTask(this, task));
+ int2 split_tile_size;
+ int num_global_threads = max_render_feasible_tile_size.x *
+ max_render_feasible_tile_size.y;
+ int d_w = rtile.w;
+ int d_h = rtile.h;
+ /* Ceil round off d_w and d_h */
+ d_w = (((d_w - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_X;
+ d_h = (((d_h - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_Y;
+ while(d_w * d_h > num_global_threads) {
+ /* Halve the longer dimension. */
+ if(d_w >= d_h) {
+ d_w = d_w / 2;
+ d_w = (((d_w - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_X;
+ }
+ else {
+ d_h = d_h / 2;
+ d_h = (((d_h - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_Y;
+ }
+ }
+ split_tile_size.x = d_w;
+ split_tile_size.y = d_h;
+ return split_tile_size;
}
- void task_wait()
+ /* Splits existing tile into multiple tiles of tile size split_tile_size. */
+ vector<SplitRenderTile> split_tiles(RenderTile rtile, int2 split_tile_size)
{
- task_pool.wait();
+ vector<SplitRenderTile> to_path_trace_rtile;
+ int d_w = rtile.w;
+ int d_h = rtile.h;
+ int num_tiles_x = (((d_w - 1) / split_tile_size.x) + 1);
+ int num_tiles_y = (((d_h - 1) / split_tile_size.y) + 1);
+ /* Buffer and rng_state offset calc. */
+ size_t offset_index = rtile.offset + (rtile.x + rtile.y * rtile.stride);
+ size_t offset_x = offset_index % rtile.stride;
+ size_t offset_y = offset_index / rtile.stride;
+ /* Resize to_path_trace_rtile. */
+ to_path_trace_rtile.resize(num_tiles_x * num_tiles_y);
+ for(int tile_iter_y = 0; tile_iter_y < num_tiles_y; tile_iter_y++) {
+ for(int tile_iter_x = 0; tile_iter_x < num_tiles_x; tile_iter_x++) {
+ int rtile_index = tile_iter_y * num_tiles_x + tile_iter_x;
+ to_path_trace_rtile[rtile_index].rng_state_offset_x = offset_x + tile_iter_x * split_tile_size.x;
+ to_path_trace_rtile[rtile_index].rng_state_offset_y = offset_y + tile_iter_y * split_tile_size.y;
+ to_path_trace_rtile[rtile_index].buffer_offset_x = offset_x + tile_iter_x * split_tile_size.x;
+ to_path_trace_rtile[rtile_index].buffer_offset_y = offset_y + tile_iter_y * split_tile_size.y;
+ to_path_trace_rtile[rtile_index].start_sample = rtile.start_sample;
+ to_path_trace_rtile[rtile_index].num_samples = rtile.num_samples;
+ to_path_trace_rtile[rtile_index].sample = rtile.sample;
+ to_path_trace_rtile[rtile_index].resolution = rtile.resolution;
+ to_path_trace_rtile[rtile_index].offset = rtile.offset;
+ to_path_trace_rtile[rtile_index].buffers = rtile.buffers;
+ to_path_trace_rtile[rtile_index].buffer = rtile.buffer;
+ to_path_trace_rtile[rtile_index].rng_state = rtile.rng_state;
+ to_path_trace_rtile[rtile_index].x = rtile.x + (tile_iter_x * split_tile_size.x);
+ to_path_trace_rtile[rtile_index].y = rtile.y + (tile_iter_y * split_tile_size.y);
+ to_path_trace_rtile[rtile_index].buffer_rng_state_stride = rtile.stride;
+ /* Fill width and height of the new render tile. */
+ to_path_trace_rtile[rtile_index].w = (tile_iter_x == (num_tiles_x - 1)) ?
+ (d_w - (tile_iter_x * split_tile_size.x)) /* Border tile */
+ : split_tile_size.x;
+ to_path_trace_rtile[rtile_index].h = (tile_iter_y == (num_tiles_y - 1)) ?
+ (d_h - (tile_iter_y * split_tile_size.y)) /* Border tile */
+ : split_tile_size.y;
+ to_path_trace_rtile[rtile_index].stride = to_path_trace_rtile[rtile_index].w;
+ }
+ }
+ return to_path_trace_rtile;
}
- void task_cancel()
+ void thread_run(DeviceTask *task)
{
- task_pool.cancel();
+ if(task->type == DeviceTask::FILM_CONVERT) {
+ film_convert(*task, task->buffer, task->rgba_byte, task->rgba_half);
+ }
+ else if(task->type == DeviceTask::SHADER) {
+ shader(*task);
+ }
+ else if(task->type == DeviceTask::PATH_TRACE) {
+ RenderTile tile;
+ bool initialize_data_and_check_render_feasibility = false;
+ bool need_to_split_tiles_further = false;
+ int2 max_render_feasible_tile_size;
+ size_t feasible_global_work_size;
+ const int2 tile_size = task->requested_tile_size;
+ /* Keep rendering tiles until done. */
+ while(task->acquire_tile(this, tile)) {
+ if(!initialize_data_and_check_render_feasibility) {
+ /* Initialize data. */
+ /* Calculate per_thread_output_buffer_size. */
+ size_t output_buffer_size = 0;
+ ciErr = clGetMemObjectInfo((cl_mem)tile.buffer,
+ CL_MEM_SIZE,
+ sizeof(output_buffer_size),
+ &output_buffer_size,
+ NULL);
+ assert(ciErr == CL_SUCCESS && "Can't get tile.buffer mem object info");
+ /* This value is different when running on AMD and NV. */
+ if(background) {
+ /* In offline render the number of buffer elements
+ * associated with tile.buffer is the current tile size.
+ */
+ per_thread_output_buffer_size =
+ output_buffer_size / (tile.w * tile.h);
+ }
+ else {
+ /* interactive rendering, unlike offline render, the number of buffer elements
+ * associated with tile.buffer is the entire viewport size.
+ */
+ per_thread_output_buffer_size =
+ output_buffer_size / (tile.buffers->params.width *
+ tile.buffers->params.height);
+ }
+ /* Check render feasibility. */
+ feasible_global_work_size = get_feasible_global_work_size(
+ tile_size,
+ CL_MEM_PTR(const_mem_map["__data"]->device_pointer));
+ max_render_feasible_tile_size =
+ get_max_render_feasible_tile_size(
+ feasible_global_work_size);
+ need_to_split_tiles_further =
+ need_to_split_tile(tile_size.x,
+ tile_size.y,
+ max_render_feasible_tile_size);
+ initialize_data_and_check_render_feasibility = true;
+ }
+ if(need_to_split_tiles_further) {
+ int2 split_tile_size =
+ get_split_tile_size(tile,
+ max_render_feasible_tile_size);
+ vector<SplitRenderTile> to_path_trace_render_tiles =
+ split_tiles(tile, split_tile_size);
+ /* Print message to console */
+ if(background && (to_path_trace_render_tiles.size() > 1)) {
+ fprintf(stderr, "Message : Tiles need to be split "
+ "further inside path trace (due to insufficient "
+ "device-global-memory for split kernel to "
+ "function) \n"
+ "The current tile of dimensions %dx%d is split "
+ "into tiles of dimension %dx%d for render \n",
+ tile.w, tile.h,
+ split_tile_size.x,
+ split_tile_size.y);
+ }
+ /* Process all split tiles. */
+ for(int tile_iter = 0;
+ tile_iter < to_path_trace_render_tiles.size();
+ ++tile_iter)
+ {
+ path_trace(to_path_trace_render_tiles[tile_iter],
+ max_render_feasible_tile_size);
+ }
+ }
+ else {
+ /* No splitting required; process the entire tile at once. */
+ /* Render feasible tile size is user-set-tile-size itself. */
+ max_render_feasible_tile_size.x =
+ (((tile_size.x - 1) / SPLIT_KERNEL_LOCAL_SIZE_X) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_X;
+ max_render_feasible_tile_size.y =
+ (((tile_size.y - 1) / SPLIT_KERNEL_LOCAL_SIZE_Y) + 1) *
+ SPLIT_KERNEL_LOCAL_SIZE_Y;
+ /* buffer_rng_state_stride is stride itself. */
+ SplitRenderTile split_tile(tile);
+ split_tile.buffer_rng_state_stride = tile.stride;
+ path_trace(split_tile, max_render_feasible_tile_size);
+ }
+ tile.sample = tile.start_sample + tile.num_samples;
+
+ /* Complete kernel execution before release tile. */
+ /* This helps in multi-device render;
+ * The device that reaches the critical-section function
+ * release_tile waits (stalling other devices from entering
+ * release_tile) for all kernels to complete. If device1 (a
+ * slow-render device) reaches release_tile first then it would
+ * stall device2 (a fast-render device) from proceeding to render
+ * next tile.
+ */
+ clFinish(cqCommandQueue);
+
+ task->release_tile(tile);
+ }
+ }
+ }
+
+protected:
+ cl_mem mem_alloc(size_t bufsize, cl_mem_flags mem_flag = CL_MEM_READ_WRITE)
+ {
+ cl_mem ptr;
+ ptr = clCreateBuffer(cxContext, mem_flag, bufsize, NULL, &ciErr);
+ if(opencl_error(ciErr)) {
+ assert(0);
+ }
+ return ptr;
}
};
+/* Returns true in case of successful detection of platform and device type,
+ * else returns false.
+ */
+static bool get_platform_and_devicetype(const DeviceInfo info,
+ string &platform_name,
+ cl_device_type &device_type)
+{
+ cl_platform_id platform_id;
+ cl_device_id device_id;
+ cl_uint num_platforms;
+ cl_int ciErr;
+
+ /* TODO(sergey): Use some generic error print helper function/ */
+ ciErr = clGetPlatformIDs(0, NULL, &num_platforms);
+ if(ciErr != CL_SUCCESS) {
+ fprintf(stderr, "Can't getPlatformIds. file - %s, line - %d\n", __FILE__, __LINE__);
+ return false;
+ }
+
+ if(num_platforms == 0) {
+ fprintf(stderr, "No OpenCL platforms found. file - %s, line - %d\n", __FILE__, __LINE__);
+ return false;
+ }
+
+ vector<cl_platform_id> platforms(num_platforms, NULL);
+
+ ciErr = clGetPlatformIDs(num_platforms, &platforms[0], NULL);
+ if(ciErr != CL_SUCCESS) {
+ fprintf(stderr, "Can't getPlatformIds. file - %s, line - %d\n", __FILE__, __LINE__);
+ return false;
+ }
+
+ int num_base = 0;
+ int total_devices = 0;
+
+ for(int platform = 0; platform < num_platforms; platform++) {
+ cl_uint num_devices;
+
+ ciErr = clGetDeviceIDs(platforms[platform], opencl_device_type(), 0, NULL, &num_devices);
+ if(ciErr != CL_SUCCESS) {
+ fprintf(stderr, "Can't getDeviceIDs. file - %s, line - %d\n", __FILE__, __LINE__);
+ return false;
+ }
+
+ total_devices += num_devices;
+
+ if(info.num - num_base >= num_devices) {
+ /* num doesn't refer to a device in this platform */
+ num_base += num_devices;
+ continue;
+ }
+
+ /* device is in this platform */
+ platform_id = platforms[platform];
+
+ /* get devices */
+ vector<cl_device_id> device_ids(num_devices, NULL);
+
+ ciErr = clGetDeviceIDs(platform_id, opencl_device_type(), num_devices, &device_ids[0], NULL);
+ if(ciErr != CL_SUCCESS) {
+ fprintf(stderr, "Can't getDeviceIDs. file - %s, line - %d\n", __FILE__, __LINE__);
+ return false;
+ }
+
+ device_id = device_ids[info.num - num_base];
+
+ char name[256];
+ ciErr = clGetPlatformInfo(platform_id, CL_PLATFORM_NAME, sizeof(name), &name, NULL);
+ if(ciErr != CL_SUCCESS) {
+ fprintf(stderr, "Can't getPlatformIDs. file - %s, line - %d \n", __FILE__, __LINE__);
+ return false;
+ }
+ platform_name = name;
+
+ ciErr = clGetDeviceInfo(device_id, CL_DEVICE_TYPE, sizeof(cl_device_type), &device_type, NULL);
+ if(ciErr != CL_SUCCESS) {
+ fprintf(stderr, "Can't getDeviceInfo. file - %s, line - %d \n", __FILE__, __LINE__);
+ return false;
+ }
+
+ break;
+ }
+
+ if(total_devices == 0) {
+ fprintf(stderr, "No devices found. file - %s, line - %d \n", __FILE__, __LINE__);
+ return false;
+ }
+
+ return true;
+}
+
Device *device_opencl_create(DeviceInfo& info, Stats &stats, bool background)
{
- return new OpenCLDevice(info, stats, background);
+ string platform_name;
+ cl_device_type device_type;
+ if(get_platform_and_devicetype(info, platform_name, device_type)) {
+ const bool force_split_kernel =
+ getenv("CYCLES_OPENCL_SPLIT_KERNEL_TEST") != NULL;
+ /* TODO(sergey): Replace string lookups with more enum-like API,
+ * similar to device/vendor checks blender's gpu.
+ */
+ if(force_split_kernel ||
+ (platform_name == "AMD Accelerated Parallel Processing" &&
+ device_type == CL_DEVICE_TYPE_GPU))
+ {
+ /* If the device is an AMD GPU, take split kernel path. */
+ VLOG(1) << "Using split kernel";
+ info.use_split_kernel = true;
+ return new OpenCLDeviceSplitKernel(info, stats, background);
+ } else {
+ /* For any other device, take megakernel path. */
+ VLOG(1) << "Using mega kernel";
+ return new OpenCLDeviceMegaKernel(info, stats, background);
+ }
+ } else {
+ /* If we can't retrieve platform and device type information for some
+ * reason, we default to megakernel path.
+ */
+ VLOG(1) << "Failed to retrieve platform or device, using mega kernel";
+ return new OpenCLDeviceMegaKernel(info, stats, background);
+ }
}
-bool device_opencl_init(void) {
+bool device_opencl_init(void)
+{
static bool initialized = false;
static bool result = false;
- if (initialized)
+ if(initialized)
return result;
initialized = true;
- // OpenCL disabled for now, only works with this environment variable set
- if(!getenv("CYCLES_OPENCL_TEST")) {
- result = false;
- }
- else {
- result = clewInit() == CLEW_SUCCESS;
- }
+ result = clewInit() == CLEW_SUCCESS;
return result;
}
@@ -1157,7 +3382,11 @@ void device_opencl_info(vector<DeviceInfo>& devices)
/* devices are numbered consecutively across platforms */
int num_base = 0;
- for (int platform = 0; platform < num_platforms; platform++, num_base += num_devices) {
+ const bool force_all_platforms =
+ (getenv("CYCLES_OPENCL_TEST") != NULL) ||
+ (getenv("CYCLES_OPENCL_SPLIT_KERNEL_TEST")) != NULL;
+
+ for(int platform = 0; platform < num_platforms; platform++, num_base += num_devices) {
num_devices = 0;
if(clGetDeviceIDs(platform_ids[platform], opencl_device_type(), 0, NULL, &num_devices) != CL_SUCCESS || num_devices == 0)
continue;
@@ -1176,13 +3405,24 @@ void device_opencl_info(vector<DeviceInfo>& devices)
cl_device_id device_id = device_ids[num];
char name[1024] = "\0";
+ cl_device_type device_type;
+ clGetDeviceInfo(device_id, CL_DEVICE_TYPE, sizeof(cl_device_type), &device_type, NULL);
+
+ /* TODO(sergey): Make it an utility function to check whitelisted devices. */
+ if(!(force_all_platforms ||
+ (platform_name == "AMD Accelerated Parallel Processing" &&
+ device_type == CL_DEVICE_TYPE_GPU)))
+ {
+ continue;
+ }
+
if(clGetDeviceInfo(device_id, CL_DEVICE_NAME, sizeof(name), &name, NULL) != CL_SUCCESS)
continue;
DeviceInfo info;
info.type = DEVICE_OPENCL;
- info.description = string(name);
+ info.description = string_remove_trademark(string(name));
info.num = num_base + num;
info.id = string_printf("OPENCL_%d", info.num);
/* we don't know if it's used for display, but assume it is */
@@ -1197,8 +3437,77 @@ void device_opencl_info(vector<DeviceInfo>& devices)
string device_opencl_capabilities(void)
{
- /* TODO(sergey): Not implemented yet. */
- return "";
+ string result = "";
+ string error_msg = ""; /* Only used by opencl_assert(), but in the future
+ * it could also be nicely reported to the console.
+ */
+ cl_uint num_platforms = 0;
+ opencl_assert(clGetPlatformIDs(0, NULL, &num_platforms));
+ if(num_platforms == 0) {
+ return "No OpenCL platforms found\n";
+ }
+ result += string_printf("Number of platforms: %d\n", num_platforms);
+
+ vector<cl_platform_id> platform_ids;
+ platform_ids.resize(num_platforms);
+ opencl_assert(clGetPlatformIDs(num_platforms, &platform_ids[0], NULL));
+
+#define APPEND_STRING_INFO(func, id, name, what) \
+ do { \
+ char data[1024] = "\0"; \
+ opencl_assert(func(id, what, sizeof(data), &data, NULL)); \
+ result += string_printf("%s: %s\n", name, data); \
+ } while(false)
+#define APPEND_PLATFORM_STRING_INFO(id, name, what) \
+ APPEND_STRING_INFO(clGetPlatformInfo, id, "\tPlatform " name, what)
+#define APPEND_DEVICE_STRING_INFO(id, name, what) \
+ APPEND_STRING_INFO(clGetDeviceInfo, id, "\t\t\tDevice " name, what)
+
+ vector<cl_device_id> device_ids;
+ for (cl_uint platform = 0; platform < num_platforms; ++platform) {
+ cl_platform_id platform_id = platform_ids[platform];
+
+ result += string_printf("Platform #%d\n", platform);
+
+ APPEND_PLATFORM_STRING_INFO(platform_id, "Name", CL_PLATFORM_NAME);
+ APPEND_PLATFORM_STRING_INFO(platform_id, "Vendor", CL_PLATFORM_VENDOR);
+ APPEND_PLATFORM_STRING_INFO(platform_id, "Version", CL_PLATFORM_VERSION);
+ APPEND_PLATFORM_STRING_INFO(platform_id, "Profile", CL_PLATFORM_PROFILE);
+ APPEND_PLATFORM_STRING_INFO(platform_id, "Extensions", CL_PLATFORM_EXTENSIONS);
+
+ cl_uint num_devices = 0;
+ opencl_assert(clGetDeviceIDs(platform_ids[platform],
+ CL_DEVICE_TYPE_ALL,
+ 0,
+ NULL,
+ &num_devices));
+ result += string_printf("\tNumber of devices: %d\n", num_devices);
+
+ device_ids.resize(num_devices);
+ opencl_assert(clGetDeviceIDs(platform_ids[platform],
+ CL_DEVICE_TYPE_ALL,
+ num_devices,
+ &device_ids[0],
+ NULL));
+ for (cl_uint device = 0; device < num_devices; ++device) {
+ cl_device_id device_id = device_ids[device];
+
+ result += string_printf("\t\tDevice: #%d\n", device);
+
+ APPEND_DEVICE_STRING_INFO(device_id, "Name", CL_DEVICE_NAME);
+ APPEND_DEVICE_STRING_INFO(device_id, "Vendor", CL_DEVICE_VENDOR);
+ APPEND_DEVICE_STRING_INFO(device_id, "OpenCL C Version", CL_DEVICE_OPENCL_C_VERSION);
+ APPEND_DEVICE_STRING_INFO(device_id, "Profile", CL_DEVICE_PROFILE);
+ APPEND_DEVICE_STRING_INFO(device_id, "Version", CL_DEVICE_VERSION);
+ APPEND_DEVICE_STRING_INFO(device_id, "Extensions", CL_DEVICE_EXTENSIONS);
+ }
+ }
+
+#undef APPEND_STRING_INFO
+#undef APPEND_PLATFORM_STRING_INFO
+#undef APPEND_DEVICE_STRING_INFO
+
+ return result;
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/device/device_task.cpp b/intern/cycles/device/device_task.cpp
index 2fe2f334176..d527540f300 100644
--- a/intern/cycles/device/device_task.cpp
+++ b/intern/cycles/device/device_task.cpp
@@ -111,7 +111,7 @@ void DeviceTask::update_progress(RenderTile *rtile)
if(update_tile_sample) {
double current_time = time_dt();
- if (current_time - last_update_time >= 1.0) {
+ if(current_time - last_update_time >= 1.0) {
update_tile_sample(*rtile);
last_update_time = current_time;
diff --git a/intern/cycles/device/device_task.h b/intern/cycles/device/device_task.h
index 84945bcf9a5..834ea60988a 100644
--- a/intern/cycles/device/device_task.h
+++ b/intern/cycles/device/device_task.h
@@ -57,14 +57,15 @@ public:
void update_progress(RenderTile *rtile);
- boost::function<bool(Device *device, RenderTile&)> acquire_tile;
- boost::function<void(void)> update_progress_sample;
- boost::function<void(RenderTile&)> update_tile_sample;
- boost::function<void(RenderTile&)> release_tile;
- boost::function<bool(void)> get_cancel;
+ function<bool(Device *device, RenderTile&)> acquire_tile;
+ function<void(void)> update_progress_sample;
+ function<void(RenderTile&)> update_tile_sample;
+ function<void(RenderTile&)> release_tile;
+ function<bool(void)> get_cancel;
bool need_finish_queue;
bool integrator_branched;
+ int2 requested_tile_size;
protected:
double last_update_time;
};
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index a25eb3f5b50..91f25a56b68 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -1,3 +1,4 @@
+remove_extra_strict_flags()
set(INC
.
@@ -11,9 +12,20 @@ set(INC_SYS
)
set(SRC
- kernel.cpp
- kernel.cl
- kernel.cu
+ kernels/cpu/kernel.cpp
+ kernels/opencl/kernel.cl
+ kernels/opencl/kernel_data_init.cl
+ kernels/opencl/kernel_queue_enqueue.cl
+ kernels/opencl/kernel_scene_intersect.cl
+ kernels/opencl/kernel_lamp_emission.cl
+ kernels/opencl/kernel_background_buffer_update.cl
+ kernels/opencl/kernel_shader_eval.cl
+ kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl
+ kernels/opencl/kernel_direct_lighting.cl
+ kernels/opencl/kernel_shadow_blocked.cl
+ kernels/opencl/kernel_next_iteration_setup.cl
+ kernels/opencl/kernel_sum_all_radiance.cl
+ kernels/cuda/kernel.cu
)
set(SRC_HEADERS
@@ -35,17 +47,21 @@ set(SRC_HEADERS
kernel_montecarlo.h
kernel_passes.h
kernel_path.h
+ kernel_path_common.h
kernel_path_state.h
kernel_path_surface.h
kernel_path_volume.h
kernel_projection.h
+ kernel_queues.h
kernel_random.h
kernel_shader.h
+ kernel_shaderdata_vars.h
kernel_shadow.h
kernel_subsurface.h
kernel_textures.h
kernel_types.h
kernel_volume.h
+ kernel_work_stealing.h
)
set(SRC_CLOSURE_HEADERS
@@ -67,6 +83,7 @@ set(SRC_CLOSURE_HEADERS
closure/emissive.h
closure/volume.h
)
+
set(SRC_SVM_HEADERS
svm/svm.h
svm/svm_attribute.h
@@ -107,6 +124,7 @@ set(SRC_SVM_HEADERS
svm/svm_value.h
svm/svm_vector_transform.h
svm/svm_voronoi.h
+ svm/svm_voxel.h
svm/svm_wave.h
)
@@ -118,6 +136,7 @@ set(SRC_GEOM_HEADERS
geom/geom_bvh_subsurface.h
geom/geom_bvh_traversal.h
geom/geom_bvh_volume.h
+ geom/geom_bvh_volume_all.h
geom/geom_curve.h
geom/geom_motion_curve.h
geom/geom_motion_triangle.h
@@ -128,12 +147,14 @@ set(SRC_GEOM_HEADERS
geom/geom_qbvh_subsurface.h
geom/geom_qbvh_traversal.h
geom/geom_qbvh_volume.h
+ geom/geom_qbvh_volume_all.h
geom/geom_triangle.h
geom/geom_triangle_intersect.h
geom/geom_volume.h
)
set(SRC_UTIL_HEADERS
+ ../util/util_atomic.h
../util/util_color.h
../util/util_half.h
../util/util_math.h
@@ -141,6 +162,21 @@ set(SRC_UTIL_HEADERS
../util/util_transform.h
../util/util_types.h
)
+
+set(SRC_SPLIT_HEADERS
+ split/kernel_background_buffer_update.h
+ split/kernel_data_init.h
+ split/kernel_direct_lighting.h
+ split/kernel_holdout_emission_blurring_pathtermination_ao.h
+ split/kernel_lamp_emission.h
+ split/kernel_next_iteration_setup.h
+ split/kernel_scene_intersect.h
+ split/kernel_shader_eval.h
+ split/kernel_shadow_blocked.h
+ split/kernel_split_common.h
+ split/kernel_sum_all_radiance.h
+)
+
# CUDA module
if(WITH_CYCLES_CUDA_BINARIES)
@@ -166,12 +202,12 @@ if(WITH_CYCLES_CUDA_BINARIES)
endif()
# build for each arch
- set(cuda_sources kernel.cu ${SRC_HEADERS} ${SRC_SVM_HEADERS} ${SRC_GEOM_HEADERS} ${SRC_CLOSURE_HEADERS} ${SRC_UTIL_HEADERS})
+ set(cuda_sources kernels/cuda/kernel.cu ${SRC_HEADERS} ${SRC_SVM_HEADERS} ${SRC_GEOM_HEADERS} ${SRC_CLOSURE_HEADERS} ${SRC_UTIL_HEADERS})
set(cuda_cubins)
macro(CYCLES_CUDA_KERNEL_ADD arch experimental)
if(${experimental})
- set(cuda_extra_flags "-D__KERNEL_CUDA_EXPERIMENTAL__")
+ set(cuda_extra_flags "-D__KERNEL_EXPERIMENTAL__")
set(cuda_cubin kernel_experimental_${arch}.cubin)
else()
set(cuda_extra_flags "")
@@ -192,7 +228,7 @@ if(WITH_CYCLES_CUDA_BINARIES)
COMMAND ${CUDA_NVCC_EXECUTABLE}
-arch=${arch}
-m${CUDA_BITS}
- --cubin ${CMAKE_CURRENT_SOURCE_DIR}/kernel.cu
+ --cubin ${CMAKE_CURRENT_SOURCE_DIR}/kernels/cuda/kernel.cu
-o ${CMAKE_CURRENT_BINARY_DIR}/${cuda_cubin}
--ptxas-options="-v"
${cuda_arch_flags}
@@ -240,28 +276,28 @@ include_directories(SYSTEM ${INC_SYS})
if(CXX_HAS_SSE)
list(APPEND SRC
- kernel_sse2.cpp
- kernel_sse3.cpp
- kernel_sse41.cpp
+ kernels/cpu/kernel_sse2.cpp
+ kernels/cpu/kernel_sse3.cpp
+ kernels/cpu/kernel_sse41.cpp
)
- set_source_files_properties(kernel_sse2.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_SSE2_KERNEL_FLAGS}")
- set_source_files_properties(kernel_sse3.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_SSE3_KERNEL_FLAGS}")
- set_source_files_properties(kernel_sse41.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_SSE41_KERNEL_FLAGS}")
+ set_source_files_properties(kernels/cpu/kernel_sse2.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_SSE2_KERNEL_FLAGS}")
+ set_source_files_properties(kernels/cpu/kernel_sse3.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_SSE3_KERNEL_FLAGS}")
+ set_source_files_properties(kernels/cpu/kernel_sse41.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_SSE41_KERNEL_FLAGS}")
endif()
if(CXX_HAS_AVX)
list(APPEND SRC
- kernel_avx.cpp
+ kernels/cpu/kernel_avx.cpp
)
- set_source_files_properties(kernel_avx.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_AVX_KERNEL_FLAGS}")
+ set_source_files_properties(kernels/cpu/kernel_avx.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_AVX_KERNEL_FLAGS}")
endif()
if(CXX_HAS_AVX2)
list(APPEND SRC
- kernel_avx2.cpp
+ kernels/cpu/kernel_avx2.cpp
)
- set_source_files_properties(kernel_avx2.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_AVX2_KERNEL_FLAGS}")
+ set_source_files_properties(kernels/cpu/kernel_avx2.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_AVX2_KERNEL_FLAGS}")
endif()
add_library(cycles_kernel ${SRC} ${SRC_HEADERS} ${SRC_CLOSURE_HEADERS} ${SRC_SVM_HEADERS} ${SRC_GEOM_HEADERS})
@@ -280,11 +316,23 @@ endif()
#add_custom_target(cycles_kernel_preprocess ALL DEPENDS ${KERNEL_PREPROCESSED})
#delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${KERNEL_PREPROCESSED}" ${CYCLES_INSTALL_PATH}/kernel)
-delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernel.cl" ${CYCLES_INSTALL_PATH}/kernel)
-delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernel.cu" ${CYCLES_INSTALL_PATH}/kernel)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_data_init.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_queue_enqueue.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_scene_intersect.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_lamp_emission.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_background_buffer_update.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_shader_eval.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_direct_lighting.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_shadow_blocked.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_next_iteration_setup.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_sum_all_radiance.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/cuda/kernel.cu" ${CYCLES_INSTALL_PATH}/kernel/kernels/cuda)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_CLOSURE_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/closure)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_SVM_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/svm)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_GEOM_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/geom)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_UTIL_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel)
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_SPLIT_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/split)
diff --git a/intern/cycles/kernel/SConscript b/intern/cycles/kernel/SConscript
index c0d969e24ae..e8d51013924 100644
--- a/intern/cycles/kernel/SConscript
+++ b/intern/cycles/kernel/SConscript
@@ -57,8 +57,9 @@ if env['WITH_BF_CYCLES_CUDA_BINARIES']:
build_dir = os.path.join(root_build_dir, 'intern/cycles/kernel')
# source directories and files
+ kernel_file_rel = os.path.join("kernels", "cuda", "kernel.cu")
source_dir = Dir('.').srcnode().path
- kernel_file = os.path.join(source_dir, "kernel.cu")
+ kernel_file = os.path.join(source_dir, kernel_file_rel)
util_dir = os.path.join(source_dir, "../util")
svm_dir = os.path.join(source_dir, "../svm")
geom_dir = os.path.join(source_dir, "../geom")
@@ -83,11 +84,11 @@ if env['WITH_BF_CYCLES_CUDA_BINARIES']:
nvcc_flags += " -D__KERNEL_DEBUG__"
# dependencies
- dependencies = ['kernel.cu'] + kernel.Glob('*.h') + kernel.Glob('../util/*.h') + kernel.Glob('svm/*.h') + kernel.Glob('geom/*.h') + kernel.Glob('closure/*.h')
+ dependencies = [kernel_file_rel] + kernel.Glob('*.h') + kernel.Glob('../util/*.h') + kernel.Glob('svm/*.h') + kernel.Glob('geom/*.h') + kernel.Glob('closure/*.h')
last_cubin_file = None
configs = (("kernel_%s.cubin", ''),
- ("kernel_experimental_%s.cubin", ' -D__KERNEL_CUDA_EXPERIMENTAL__'))
+ ("kernel_experimental_%s.cubin", ' -D__KERNEL_EXPERIMENTAL__'))
# add command for each cuda architecture
for arch in cuda_archs:
@@ -105,7 +106,7 @@ if env['WITH_BF_CYCLES_CUDA_BINARIES']:
else:
command = "\"%s\" -arch=%s %s \"%s\" -o \"%s\"" % (nvcc, arch, current_flags, kernel_file, cubin_file)
- kernel.Command(cubin_file, 'kernel.cu', command)
+ kernel.Command(cubin_file, kernel_file_rel, command)
kernel.Depends(cubin_file, dependencies)
kernel_binaries.append(cubin_file)
diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h
index 2b9e2a4e44d..558aa0dc6a9 100644
--- a/intern/cycles/kernel/closure/bsdf.h
+++ b/intern/cycles/kernel/closure/bsdf.h
@@ -47,79 +47,79 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader
switch(sc->type) {
case CLOSURE_BSDF_DIFFUSE_ID:
case CLOSURE_BSDF_BSSRDF_ID:
- label = bsdf_diffuse_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+ label = bsdf_diffuse_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
#ifdef __SVM__
case CLOSURE_BSDF_OREN_NAYAR_ID:
- label = bsdf_oren_nayar_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+ label = bsdf_oren_nayar_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
/*case CLOSURE_BSDF_PHONG_RAMP_ID:
- label = bsdf_phong_ramp_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+ label = bsdf_phong_ramp_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_DIFFUSE_RAMP_ID:
- label = bsdf_diffuse_ramp_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+ label = bsdf_diffuse_ramp_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;*/
case CLOSURE_BSDF_TRANSLUCENT_ID:
- label = bsdf_translucent_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+ label = bsdf_translucent_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_REFLECTION_ID:
- label = bsdf_reflection_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+ label = bsdf_reflection_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_REFRACTION_ID:
- label = bsdf_refraction_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+ label = bsdf_refraction_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_TRANSPARENT_ID:
- label = bsdf_transparent_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+ label = bsdf_transparent_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
- label = bsdf_microfacet_ggx_sample(kg, sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+ label = bsdf_microfacet_ggx_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
- label = bsdf_microfacet_beckmann_sample(kg, sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+ label = bsdf_microfacet_beckmann_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID:
- label = bsdf_ashikhmin_shirley_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+ label = bsdf_ashikhmin_shirley_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID:
- label = bsdf_ashikhmin_velvet_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+ label = bsdf_ashikhmin_velvet_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_DIFFUSE_TOON_ID:
- label = bsdf_diffuse_toon_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+ label = bsdf_diffuse_toon_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_GLOSSY_TOON_ID:
- label = bsdf_glossy_toon_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+ label = bsdf_glossy_toon_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_HAIR_REFLECTION_ID:
- label = bsdf_hair_reflection_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+ label = bsdf_hair_reflection_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_HAIR_TRANSMISSION_ID:
- label = bsdf_hair_transmission_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
+ label = bsdf_hair_transmission_sample(sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
#endif
#ifdef __VOLUME__
case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID:
- label = volume_henyey_greenstein_sample(sc, sd->I, sd->dI.dx, sd->dI.dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
+ label = volume_henyey_greenstein_sample(sc, ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
#endif
default:
@@ -139,67 +139,67 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade
return OSLShader::bsdf_eval(sd, sc, omega_in, *pdf);
#endif
- if(dot(sd->Ng, omega_in) >= 0.0f) {
+ if(dot(ccl_fetch(sd, Ng), omega_in) >= 0.0f) {
switch(sc->type) {
case CLOSURE_BSDF_DIFFUSE_ID:
case CLOSURE_BSDF_BSSRDF_ID:
- eval = bsdf_diffuse_eval_reflect(sc, sd->I, omega_in, pdf);
+ eval = bsdf_diffuse_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
#ifdef __SVM__
case CLOSURE_BSDF_OREN_NAYAR_ID:
- eval = bsdf_oren_nayar_eval_reflect(sc, sd->I, omega_in, pdf);
+ eval = bsdf_oren_nayar_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
/*case CLOSURE_BSDF_PHONG_RAMP_ID:
- eval = bsdf_phong_ramp_eval_reflect(sc, sd->I, omega_in, pdf);
+ eval = bsdf_phong_ramp_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_DIFFUSE_RAMP_ID:
- eval = bsdf_diffuse_ramp_eval_reflect(sc, sd->I, omega_in, pdf);
+ eval = bsdf_diffuse_ramp_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;*/
case CLOSURE_BSDF_TRANSLUCENT_ID:
- eval = bsdf_translucent_eval_reflect(sc, sd->I, omega_in, pdf);
+ eval = bsdf_translucent_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_REFLECTION_ID:
- eval = bsdf_reflection_eval_reflect(sc, sd->I, omega_in, pdf);
+ eval = bsdf_reflection_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_REFRACTION_ID:
- eval = bsdf_refraction_eval_reflect(sc, sd->I, omega_in, pdf);
+ eval = bsdf_refraction_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_TRANSPARENT_ID:
- eval = bsdf_transparent_eval_reflect(sc, sd->I, omega_in, pdf);
+ eval = bsdf_transparent_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
- eval = bsdf_microfacet_ggx_eval_reflect(sc, sd->I, omega_in, pdf);
+ eval = bsdf_microfacet_ggx_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
- eval = bsdf_microfacet_beckmann_eval_reflect(sc, sd->I, omega_in, pdf);
+ eval = bsdf_microfacet_beckmann_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID:
- eval = bsdf_ashikhmin_shirley_eval_reflect(sc, sd->I, omega_in, pdf);
+ eval = bsdf_ashikhmin_shirley_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID:
- eval = bsdf_ashikhmin_velvet_eval_reflect(sc, sd->I, omega_in, pdf);
+ eval = bsdf_ashikhmin_velvet_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_DIFFUSE_TOON_ID:
- eval = bsdf_diffuse_toon_eval_reflect(sc, sd->I, omega_in, pdf);
+ eval = bsdf_diffuse_toon_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_GLOSSY_TOON_ID:
- eval = bsdf_glossy_toon_eval_reflect(sc, sd->I, omega_in, pdf);
+ eval = bsdf_glossy_toon_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_HAIR_REFLECTION_ID:
- eval = bsdf_hair_reflection_eval_reflect(sc, sd->I, omega_in, pdf);
+ eval = bsdf_hair_reflection_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_HAIR_TRANSMISSION_ID:
- eval = bsdf_hair_transmission_eval_reflect(sc, sd->I, omega_in, pdf);
+ eval = bsdf_hair_transmission_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
#endif
#ifdef __VOLUME__
case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID:
- eval = volume_henyey_greenstein_eval_phase(sc, sd->I, omega_in, pdf);
+ eval = volume_henyey_greenstein_eval_phase(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
#endif
default:
@@ -211,57 +211,57 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade
switch(sc->type) {
case CLOSURE_BSDF_DIFFUSE_ID:
case CLOSURE_BSDF_BSSRDF_ID:
- eval = bsdf_diffuse_eval_transmit(sc, sd->I, omega_in, pdf);
+ eval = bsdf_diffuse_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
#ifdef __SVM__
case CLOSURE_BSDF_OREN_NAYAR_ID:
- eval = bsdf_oren_nayar_eval_transmit(sc, sd->I, omega_in, pdf);
+ eval = bsdf_oren_nayar_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_TRANSLUCENT_ID:
- eval = bsdf_translucent_eval_transmit(sc, sd->I, omega_in, pdf);
+ eval = bsdf_translucent_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_REFLECTION_ID:
- eval = bsdf_reflection_eval_transmit(sc, sd->I, omega_in, pdf);
+ eval = bsdf_reflection_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_REFRACTION_ID:
- eval = bsdf_refraction_eval_transmit(sc, sd->I, omega_in, pdf);
+ eval = bsdf_refraction_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_TRANSPARENT_ID:
- eval = bsdf_transparent_eval_transmit(sc, sd->I, omega_in, pdf);
+ eval = bsdf_transparent_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
- eval = bsdf_microfacet_ggx_eval_transmit(sc, sd->I, omega_in, pdf);
+ eval = bsdf_microfacet_ggx_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
- eval = bsdf_microfacet_beckmann_eval_transmit(sc, sd->I, omega_in, pdf);
+ eval = bsdf_microfacet_beckmann_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID:
- eval = bsdf_ashikhmin_shirley_eval_transmit(sc, sd->I, omega_in, pdf);
+ eval = bsdf_ashikhmin_shirley_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID:
- eval = bsdf_ashikhmin_velvet_eval_transmit(sc, sd->I, omega_in, pdf);
+ eval = bsdf_ashikhmin_velvet_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_DIFFUSE_TOON_ID:
- eval = bsdf_diffuse_toon_eval_transmit(sc, sd->I, omega_in, pdf);
+ eval = bsdf_diffuse_toon_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_GLOSSY_TOON_ID:
- eval = bsdf_glossy_toon_eval_transmit(sc, sd->I, omega_in, pdf);
+ eval = bsdf_glossy_toon_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_HAIR_REFLECTION_ID:
- eval = bsdf_hair_reflection_eval_transmit(sc, sd->I, omega_in, pdf);
+ eval = bsdf_hair_reflection_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
case CLOSURE_BSDF_HAIR_TRANSMISSION_ID:
- eval = bsdf_hair_transmission_eval_transmit(sc, sd->I, omega_in, pdf);
+ eval = bsdf_hair_transmission_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
#endif
#ifdef __VOLUME__
case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID:
- eval = volume_henyey_greenstein_eval_phase(sc, sd->I, omega_in, pdf);
+ eval = volume_henyey_greenstein_eval_phase(sc, ccl_fetch(sd, I), omega_in, pdf);
break;
#endif
default:
diff --git a/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h b/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h
index acc477246d2..8d7d533d6f8 100644
--- a/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h
+++ b/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h
@@ -69,6 +69,9 @@ ccl_device float3 bsdf_ashikhmin_shirley_eval_reflect(const ShaderClosure *sc, c
float out = 0.0f;
+ if(fmaxf(sc->data0, sc->data1) <= 1e-4f)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
if(NdotI > 0.0f && NdotO > 0.0f) {
NdotI = fmaxf(NdotI, 1e-6f);
NdotO = fmaxf(NdotO, 1e-6f);
@@ -190,8 +193,15 @@ ccl_device int bsdf_ashikhmin_shirley_sample(const ShaderClosure *sc, float3 Ng,
/* reflect I on H to get omega_in */
*omega_in = -I + (2.0f * HdotI) * H;
- /* leave the rest to eval_reflect */
- *eval = bsdf_ashikhmin_shirley_eval_reflect(sc, I, *omega_in, pdf);
+ if(fmaxf(sc->data0, sc->data1) <= 1e-4f) {
+ /* Some high number for MIS. */
+ *pdf = 1e6f;
+ *eval = make_float3(1e6f, 1e6f, 1e6f);
+ }
+ else {
+ /* leave the rest to eval_reflect */
+ *eval = bsdf_ashikhmin_shirley_eval_reflect(sc, I, *omega_in, pdf);
+ }
#ifdef __RAY_DIFFERENTIALS__
/* just do the reflection thing for now */
diff --git a/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h b/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h
index 580f50d5dd6..f1a26650078 100644
--- a/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h
+++ b/intern/cycles/kernel/closure/bsdf_ashikhmin_velvet.h
@@ -59,7 +59,7 @@ ccl_device float3 bsdf_ashikhmin_velvet_eval_reflect(const ShaderClosure *sc, co
float cosHO = fabsf(dot(I, H));
if(!(fabsf(cosNH) < 1.0f-1e-5f && cosHO > 1e-5f))
- return make_float3(0, 0, 0);
+ return make_float3(0.0f, 0.0f, 0.0f);
float cosNHdivHO = cosNH / cosHO;
cosNHdivHO = fmaxf(cosNHdivHO, 1e-5f);
@@ -80,7 +80,7 @@ ccl_device float3 bsdf_ashikhmin_velvet_eval_reflect(const ShaderClosure *sc, co
return make_float3(out, out, out);
}
- return make_float3(0, 0, 0);
+ return make_float3(0.0f, 0.0f, 0.0f);
}
ccl_device float3 bsdf_ashikhmin_velvet_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
@@ -114,7 +114,7 @@ ccl_device int bsdf_ashikhmin_velvet_sample(const ShaderClosure *sc, float3 Ng,
float sinNH2 = 1 - cosNH * cosNH;
float sinNH4 = sinNH2 * sinNH2;
- float cotangent2 = (cosNH * cosNH) / sinNH2;
+ float cotangent2 = (cosNH * cosNH) / sinNH2;
float D = expf(-cotangent2 * m_invsigma2) * m_invsigma2 * M_1_PI_F / sinNH4;
float G = min(1.0f, min(fac1, fac2)); // TODO: derive G from D analytically
diff --git a/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h b/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h
index cdaf84f1750..e0287e7655a 100644
--- a/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h
+++ b/intern/cycles/kernel/closure/bsdf_diffuse_ramp.h
@@ -52,6 +52,8 @@ ccl_device float3 bsdf_diffuse_ramp_get_color(const ShaderClosure *sc, const flo
ccl_device int bsdf_diffuse_ramp_setup(ShaderClosure *sc)
{
sc->type = CLOSURE_BSDF_DIFFUSE_RAMP_ID;
+ sc->data0 = 0.0f;
+ sc->data1 = 0.0f;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h
index 71086f2e764..6a50bbed3b3 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet.h
@@ -35,79 +35,7 @@
CCL_NAMESPACE_BEGIN
-/* Approximate erf and erfinv implementations.
- * Implementation comes straight from Wikipedia:
- *
- * http://en.wikipedia.org/wiki/Error_function
- *
- * Some constants are baked into the code.
- */
-
-ccl_device_inline float approx_erff_do(float x)
-{
- /* Such a clamp doesn't give much distortion to the output value
- * and gives quite a few of the speedup.
- */
- if(x > 3.0f) {
- return 1.0f;
- }
- float t = 1.0f / (1.0f + 0.47047f*x);
- return (1.0f -
- t*(0.3480242f + t*(-0.0958798f + t*0.7478556f)) * expf(-x*x));
-}
-
-ccl_device_inline float approx_erff(float x)
-{
- if(x >= 0.0f) {
- return approx_erff_do(x);
- }
- else {
- return -approx_erff_do(-x);
- }
-}
-
-ccl_device_inline float approx_erfinvf_do(float x)
-{
- if(x <= 0.7f) {
- const float x2 = x * x;
- const float a1 = 0.886226899f;
- const float a2 = -1.645349621f;
- const float a3 = 0.914624893f;
- const float a4 = -0.140543331f;
- const float b1 = -2.118377725f;
- const float b2 = 1.442710462f;
- const float b3 = -0.329097515f;
- const float b4 = 0.012229801f;
- return x * (((a4 * x2 + a3) * x2 + a2) * x2 + a1) /
- ((((b4 * x2 + b3) * x2 + b2) * x2 + b1) * x2 + 1.0f);
- }
- else {
- const float c1 = -1.970840454f;
- const float c2 = -1.624906493f;
- const float c3 = 3.429567803f;
- const float c4 = 1.641345311f;
- const float d1 = 3.543889200f;
- const float d2 = 1.637067800f;
- const float z = sqrtf(-logf((1.0f - x) * 0.5f));
- return (((c4 * z + c3) * z + c2) * z + c1) /
- ((d2 * z + d1) * z + 1.0f);
- }
-}
-
-ccl_device_inline float approx_erfinvf(float x)
-{
- if(x >= 0.0f) {
- return approx_erfinvf_do(x);
- }
- else {
- return -approx_erfinvf_do(-x);
- }
-}
-
-/* Beckmann and GGX microfacet importance sampling from:
- *
- * Importance Sampling Microfacet-Based BSDFs using the Distribution of Visible Normals.
- * E. Heitz and E. d'Eon, EGSR 2014 */
+/* Beckmann and GGX microfacet importance sampling. */
ccl_device_inline void microfacet_beckmann_sample_slopes(
KernelGlobals *kg,
@@ -128,64 +56,71 @@ ccl_device_inline void microfacet_beckmann_sample_slopes(
/* precomputations */
const float tan_theta_i = sin_theta_i/cos_theta_i;
const float inv_a = tan_theta_i;
- const float a = 1.0f/inv_a;
- const float erf_a = approx_erff(a);
- const float exp_a2 = expf(-a*a);
+ const float cot_theta_i = 1.0f/tan_theta_i;
+ const float erf_a = fast_erff(cot_theta_i);
+ const float exp_a2 = expf(-cot_theta_i*cot_theta_i);
const float SQRT_PI_INV = 0.56418958354f;
const float Lambda = 0.5f*(erf_a - 1.0f) + (0.5f*SQRT_PI_INV)*(exp_a2*inv_a);
const float G1 = 1.0f/(1.0f + Lambda); /* masking */
*G1i = G1;
-#if 0
- const float C = 1.0f - G1 * erf_a;
-
- /* sample slope X */
- if(randu < C) {
- /* rescale randu */
- randu = randu / C;
- const float w_1 = 0.5f * SQRT_PI_INV * sin_theta_i * exp_a2;
- const float w_2 = cos_theta_i * (0.5f - 0.5f*erf_a);
- const float p = w_1 / (w_1 + w_2);
+#if defined(__KERNEL_GPU__)
+ /* Based on paper from Wenzel Jakob
+ * An Improved Visible Normal Sampling Routine for the Beckmann Distribution
+ *
+ * http://www.mitsuba-renderer.org/~wenzel/files/visnormal.pdf
+ *
+ * Reformulation from OpenShadingLanguage which avoids using inverse
+ * trigonometric functions.
+ */
- if(randu < p) {
- randu = randu / p;
- *slope_x = -sqrtf(-logf(randu*exp_a2));
- }
- else {
- randu = (randu - p) / (1.0f - p);
- *slope_x = approx_erfinvf(randu - 1.0f - randu*erf_a);
- }
+ /* Sample slope X.
+ *
+ * Compute a coarse approximation using the approximation:
+ * exp(-ierf(x)^2) ~= 1 - x * x
+ * solve y = 1 + b + K * (1 - b * b)
+ */
+ float K = tan_theta_i * SQRT_PI_INV;
+ float y_approx = randu * (1.0f + erf_a + K * (1 - erf_a * erf_a));
+ float y_exact = randu * (1.0f + erf_a + K * exp_a2);
+ float b = K > 0 ? (0.5f - sqrtf(K * (K - y_approx + 1.0f) + 0.25f)) / K : y_approx - 1.0f;
+
+ /* Perform newton step to refine toward the true root. */
+ float inv_erf = fast_ierff(b);
+ float value = 1.0f + b + K * expf(-inv_erf * inv_erf) - y_exact;
+ /* Check if we are close enough already,
+ * this also avoids NaNs as we get close to the root.
+ */
+ if(fabsf(value) > 1e-6f) {
+ b -= value / (1.0f - inv_erf * tan_theta_i); /* newton step 1. */
+ inv_erf = fast_ierff(b);
+ value = 1.0f + b + K * expf(-inv_erf * inv_erf) - y_exact;
+ b -= value / (1.0f - inv_erf * tan_theta_i); /* newton step 2. */
+ /* Compute the slope from the refined value. */
+ *slope_x = fast_ierff(b);
}
else {
- /* rescale randu */
- randu = (randu - C) / (1.0f - C);
- *slope_x = approx_erfinvf((-1.0f + 2.0f*randu)*erf_a);
-
- const float p = (-(*slope_x)*sin_theta_i + cos_theta_i) / (2.0f*cos_theta_i);
-
- if(randv > p) {
- *slope_x = -(*slope_x);
- randv = (randv - p) / (1.0f - p);
- }
- else
- randv = randv / p;
+ /* We are close enough already. */
+ *slope_x = inv_erf;
}
-
- /* sample slope Y */
- *slope_y = approx_erfinvf(2.0f*randv - 1.0f);
+ *slope_y = fast_ierff(2.0f*randv - 1.0f);
#else
- /* use precomputed table, because it better preserves stratification
- * of the random number pattern */
+ /* Use precomputed table on CPU, it gives better perfomance. */
int beckmann_table_offset = kernel_data.tables.beckmann_offset;
*slope_x = lookup_table_read_2D(kg, randu, cos_theta_i,
beckmann_table_offset, BECKMANN_TABLE_SIZE, BECKMANN_TABLE_SIZE);
- *slope_y = approx_erfinvf(2.0f*randv - 1.0f);
+ *slope_y = fast_ierff(2.0f*randv - 1.0f);
#endif
-
}
+/* GGX microfacet importance sampling from:
+ *
+ * Importance Sampling Microfacet-Based BSDFs using the Distribution of Visible Normals.
+ * E. Heitz and E. d'Eon, EGSR 2014
+ */
+
ccl_device_inline void microfacet_ggx_sample_slopes(
const float cos_theta_i, const float sin_theta_i,
float randu, float randv, float *slope_x, float *slope_y,
@@ -300,7 +235,7 @@ ccl_device_inline float3 microfacet_sample_stretched(
ccl_device int bsdf_microfacet_ggx_setup(ShaderClosure *sc)
{
- sc->data0 = clamp(sc->data0, 0.0f, 1.0f); /* alpha_x */
+ sc->data0 = saturate(sc->data0); /* alpha_x */
sc->data1 = sc->data0; /* alpha_y */
sc->type = CLOSURE_BSDF_MICROFACET_GGX_ID;
@@ -310,8 +245,8 @@ ccl_device int bsdf_microfacet_ggx_setup(ShaderClosure *sc)
ccl_device int bsdf_microfacet_ggx_aniso_setup(ShaderClosure *sc)
{
- sc->data0 = clamp(sc->data0, 0.0f, 1.0f); /* alpha_x */
- sc->data1 = clamp(sc->data1, 0.0f, 1.0f); /* alpha_y */
+ sc->data0 = saturate(sc->data0); /* alpha_x */
+ sc->data1 = saturate(sc->data1); /* alpha_y */
sc->type = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
@@ -320,7 +255,7 @@ ccl_device int bsdf_microfacet_ggx_aniso_setup(ShaderClosure *sc)
ccl_device int bsdf_microfacet_ggx_refraction_setup(ShaderClosure *sc)
{
- sc->data0 = clamp(sc->data0, 0.0f, 1.0f); /* alpha_x */
+ sc->data0 = saturate(sc->data0); /* alpha_x */
sc->data1 = sc->data0; /* alpha_y */
sc->type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
@@ -342,7 +277,7 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons
float3 N = sc->N;
if(m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f)
- return make_float3(0, 0, 0);
+ return make_float3(0.0f, 0.0f, 0.0f);
float cosNO = dot(N, I);
float cosNI = dot(N, omega_in);
@@ -421,7 +356,7 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons
return make_float3(out, out, out);
}
- return make_float3(0, 0, 0);
+ return make_float3(0.0f, 0.0f, 0.0f);
}
ccl_device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
@@ -433,13 +368,13 @@ ccl_device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderClosure *sc, con
float3 N = sc->N;
if(!m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f)
- return make_float3(0, 0, 0);
+ return make_float3(0.0f, 0.0f, 0.0f);
float cosNO = dot(N, I);
float cosNI = dot(N, omega_in);
if(cosNO <= 0 || cosNI >= 0)
- return make_float3(0, 0, 0); /* vectors on same side -- not possible */
+ return make_float3(0.0f, 0.0f, 0.0f); /* vectors on same side -- not possible */
/* compute half-vector of the refraction (eq. 16) */
float3 ht = -(m_eta * omega_in + I);
@@ -653,7 +588,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure
ccl_device int bsdf_microfacet_beckmann_setup(ShaderClosure *sc)
{
- sc->data0 = clamp(sc->data0, 0.0f, 1.0f); /* alpha_x */
+ sc->data0 = saturate(sc->data0); /* alpha_x */
sc->data1 = sc->data0; /* alpha_y */
sc->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
@@ -662,8 +597,8 @@ ccl_device int bsdf_microfacet_beckmann_setup(ShaderClosure *sc)
ccl_device int bsdf_microfacet_beckmann_aniso_setup(ShaderClosure *sc)
{
- sc->data0 = clamp(sc->data0, 0.0f, 1.0f); /* alpha_x */
- sc->data1 = clamp(sc->data1, 0.0f, 1.0f); /* alpha_y */
+ sc->data0 = saturate(sc->data0); /* alpha_x */
+ sc->data1 = saturate(sc->data1); /* alpha_y */
sc->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
@@ -671,7 +606,7 @@ ccl_device int bsdf_microfacet_beckmann_aniso_setup(ShaderClosure *sc)
ccl_device int bsdf_microfacet_beckmann_refraction_setup(ShaderClosure *sc)
{
- sc->data0 = clamp(sc->data0, 0.0f, 1.0f); /* alpha_x */
+ sc->data0 = saturate(sc->data0); /* alpha_x */
sc->data1 = sc->data0; /* alpha_y */
sc->type = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
@@ -692,7 +627,7 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc,
float3 N = sc->N;
if(m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f)
- return make_float3(0, 0, 0);
+ return make_float3(0.0f, 0.0f, 0.0f);
float cosNO = dot(N, I);
float cosNI = dot(N, omega_in);
@@ -774,7 +709,7 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc,
return make_float3(out, out, out);
}
- return make_float3(0, 0, 0);
+ return make_float3(0.0f, 0.0f, 0.0f);
}
ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
@@ -786,13 +721,13 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc
float3 N = sc->N;
if(!m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f)
- return make_float3(0, 0, 0);
+ return make_float3(0.0f, 0.0f, 0.0f);
float cosNO = dot(N, I);
float cosNI = dot(N, omega_in);
if(cosNO <= 0 || cosNI >= 0)
- return make_float3(0, 0, 0);
+ return make_float3(0.0f, 0.0f, 0.0f);
/* compute half-vector of the refraction (eq. 16) */
float3 ht = -(m_eta * omega_in + I);
diff --git a/intern/cycles/kernel/closure/bsdf_oren_nayar.h b/intern/cycles/kernel/closure/bsdf_oren_nayar.h
index c476d4ca4e2..61b7cb11b02 100644
--- a/intern/cycles/kernel/closure/bsdf_oren_nayar.h
+++ b/intern/cycles/kernel/closure/bsdf_oren_nayar.h
@@ -37,7 +37,7 @@ ccl_device int bsdf_oren_nayar_setup(ShaderClosure *sc)
sc->type = CLOSURE_BSDF_OREN_NAYAR_ID;
- sigma = clamp(sigma, 0.0f, 1.0f);
+ sigma = saturate(sigma);
float div = 1.0f / (M_PI_F + ((3.0f * M_PI_F - 4.0f) / 6.0f) * sigma);
diff --git a/intern/cycles/kernel/closure/bsdf_phong_ramp.h b/intern/cycles/kernel/closure/bsdf_phong_ramp.h
index f9f263719e9..1ab15eee954 100644
--- a/intern/cycles/kernel/closure/bsdf_phong_ramp.h
+++ b/intern/cycles/kernel/closure/bsdf_phong_ramp.h
@@ -51,9 +51,9 @@ ccl_device float3 bsdf_phong_ramp_get_color(const ShaderClosure *sc, const float
ccl_device int bsdf_phong_ramp_setup(ShaderClosure *sc)
{
- sc->data0 = max(sc->data0, 0.0f);
-
sc->type = CLOSURE_BSDF_PHONG_RAMP_ID;
+ sc->data0 = max(sc->data0, 0.0f);
+ sc->data1 = 0.0f;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
diff --git a/intern/cycles/kernel/closure/bsdf_toon.h b/intern/cycles/kernel/closure/bsdf_toon.h
index df03942638f..e5b6ab93a64 100644
--- a/intern/cycles/kernel/closure/bsdf_toon.h
+++ b/intern/cycles/kernel/closure/bsdf_toon.h
@@ -40,8 +40,8 @@ CCL_NAMESPACE_BEGIN
ccl_device int bsdf_diffuse_toon_setup(ShaderClosure *sc)
{
sc->type = CLOSURE_BSDF_DIFFUSE_TOON_ID;
- sc->data0 = clamp(sc->data0, 0.0f, 1.0f);
- sc->data1 = clamp(sc->data1, 0.0f, 1.0f);
+ sc->data0 = saturate(sc->data0);
+ sc->data1 = saturate(sc->data1);
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
@@ -120,8 +120,8 @@ ccl_device int bsdf_diffuse_toon_sample(const ShaderClosure *sc, float3 Ng, floa
ccl_device int bsdf_glossy_toon_setup(ShaderClosure *sc)
{
sc->type = CLOSURE_BSDF_GLOSSY_TOON_ID;
- sc->data0 = clamp(sc->data0, 0.0f, 1.0f);
- sc->data1 = clamp(sc->data1, 0.0f, 1.0f);
+ sc->data0 = saturate(sc->data0);
+ sc->data1 = saturate(sc->data1);
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
diff --git a/intern/cycles/kernel/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h
index b6de2da8c71..f817dcd5f2d 100644
--- a/intern/cycles/kernel/closure/bssrdf.h
+++ b/intern/cycles/kernel/closure/bssrdf.h
@@ -30,8 +30,8 @@ ccl_device int bssrdf_setup(ShaderClosure *sc, ClosureType type)
return flag;
}
else {
- sc->data1 = clamp(sc->data1, 0.0f, 1.0f); /* texture blur */
- sc->T.x = clamp(sc->T.x, 0.0f, 1.0f); /* sharpness */
+ sc->data1 = saturate(sc->data1); /* texture blur */
+ sc->T.x = saturate(sc->T.x); /* sharpness */
sc->type = type;
return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF;
@@ -157,7 +157,7 @@ ccl_device float bssrdf_cubic_quintic_root_find(float xi)
float x = 0.25f;
int i;
- for (i = 0; i < max_iteration_count; i++) {
+ for(i = 0; i < max_iteration_count; i++) {
float x2 = x*x;
float x3 = x2*x;
float nx = (1.0f - x);
@@ -168,7 +168,7 @@ ccl_device float bssrdf_cubic_quintic_root_find(float xi)
if(fabsf(f) < tolerance || f_ == 0.0f)
break;
- x = clamp(x - f/f_, 0.0f, 1.0f);
+ x = saturate(x - f/f_);
}
return x;
diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h
index bf0d86e6206..5ab900d47aa 100644
--- a/intern/cycles/kernel/geom/geom.h
+++ b/intern/cycles/kernel/geom/geom.h
@@ -22,7 +22,9 @@
#define BVH_STACK_SIZE 192
#define BVH_QSTACK_SIZE 384
#define BVH_NODE_SIZE 4
+#define BVH_NODE_LEAF_SIZE 1
#define BVH_QNODE_SIZE 7
+#define BVH_QNODE_LEAF_SIZE 1
#define TRI_NODE_SIZE 3
/* silly workaround for float extended precision that happens when compiling
diff --git a/intern/cycles/kernel/geom/geom_attribute.h b/intern/cycles/kernel/geom/geom_attribute.h
index 9ac16e86085..c7364e9edac 100644
--- a/intern/cycles/kernel/geom/geom_attribute.h
+++ b/intern/cycles/kernel/geom/geom_attribute.h
@@ -29,13 +29,13 @@ CCL_NAMESPACE_BEGIN
ccl_device_inline int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem)
{
- if(sd->object == PRIM_NONE)
+ if(ccl_fetch(sd, object) == PRIM_NONE)
return (int)ATTR_STD_NOT_FOUND;
/* for SVM, find attribute by unique id */
- uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride;
+ uint attr_offset = ccl_fetch(sd, object)*kernel_data.bvh.attributes_map_stride;
#ifdef __HAIR__
- attr_offset = (sd->type & PRIMITIVE_ALL_CURVE)? attr_offset + ATTR_PRIM_CURVE: attr_offset;
+ attr_offset = (ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE)? attr_offset + ATTR_PRIM_CURVE: attr_offset;
#endif
uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
@@ -49,7 +49,7 @@ ccl_device_inline int find_attribute(KernelGlobals *kg, const ShaderData *sd, ui
*elem = (AttributeElement)attr_map.y;
- if(sd->prim == PRIM_NONE && (AttributeElement)attr_map.y != ATTR_ELEMENT_MESH)
+ if(ccl_fetch(sd, prim) == PRIM_NONE && (AttributeElement)attr_map.y != ATTR_ELEMENT_MESH)
return ATTR_STD_NOT_FOUND;
/* return result */
diff --git a/intern/cycles/kernel/geom/geom_bvh.h b/intern/cycles/kernel/geom/geom_bvh.h
index c0eefcd9c7f..3d0d406dd0b 100644
--- a/intern/cycles/kernel/geom/geom_bvh.h
+++ b/intern/cycles/kernel/geom/geom_bvh.h
@@ -115,7 +115,39 @@ CCL_NAMESPACE_BEGIN
#include "geom_bvh_subsurface.h"
#endif
-/* Record all BVH intersection for shadows */
+/* Volume BVH traversal */
+
+#if defined(__VOLUME__)
+#define BVH_FUNCTION_NAME bvh_intersect_volume
+#define BVH_FUNCTION_FEATURES 0
+#include "geom_bvh_volume.h"
+#endif
+
+#if defined(__VOLUME__) && defined(__INSTANCING__)
+#define BVH_FUNCTION_NAME bvh_intersect_volume_instancing
+#define BVH_FUNCTION_FEATURES BVH_INSTANCING
+#include "geom_bvh_volume.h"
+#endif
+
+#if defined(__VOLUME__) && defined(__HAIR__)
+#define BVH_FUNCTION_NAME bvh_intersect_volume_hair
+#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH
+#include "geom_bvh_volume.h"
+#endif
+
+#if defined(__VOLUME__) && defined(__OBJECT_MOTION__)
+#define BVH_FUNCTION_NAME bvh_intersect_volume_motion
+#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
+#include "geom_bvh_volume.h"
+#endif
+
+#if defined(__VOLUME__) && defined(__HAIR__) && defined(__OBJECT_MOTION__)
+#define BVH_FUNCTION_NAME bvh_intersect_volume_hair_motion
+#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH|BVH_MOTION
+#include "geom_bvh_volume.h"
+#endif
+
+/* Record all intersections - Shadow BVH traversal */
#if defined(__SHADOW_RECORD_ALL__)
#define BVH_FUNCTION_NAME bvh_intersect_shadow_all
@@ -147,36 +179,36 @@ CCL_NAMESPACE_BEGIN
#include "geom_bvh_shadow.h"
#endif
-/* Camera inside Volume BVH intersection */
+/* Record all intersections - Volume BVH traversal */
-#if defined(__VOLUME__)
-#define BVH_FUNCTION_NAME bvh_intersect_volume
+#if defined(__VOLUME_RECORD_ALL__)
+#define BVH_FUNCTION_NAME bvh_intersect_volume_all
#define BVH_FUNCTION_FEATURES 0
-#include "geom_bvh_volume.h"
+#include "geom_bvh_volume_all.h"
#endif
-#if defined(__VOLUME__) && defined(__INSTANCING__)
-#define BVH_FUNCTION_NAME bvh_intersect_volume_instancing
+#if defined(__VOLUME_RECORD_ALL__) && defined(__INSTANCING__)
+#define BVH_FUNCTION_NAME bvh_intersect_volume_all_instancing
#define BVH_FUNCTION_FEATURES BVH_INSTANCING
-#include "geom_bvh_volume.h"
+#include "geom_bvh_volume_all.h"
#endif
-#if defined(__VOLUME__) && defined(__HAIR__)
-#define BVH_FUNCTION_NAME bvh_intersect_volume_hair
+#if defined(__VOLUME_RECORD_ALL__) && defined(__HAIR__)
+#define BVH_FUNCTION_NAME bvh_intersect_volume_all_hair
#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH
-#include "geom_bvh_volume.h"
+#include "geom_bvh_volume_all.h"
#endif
-#if defined(__VOLUME__) && defined(__OBJECT_MOTION__)
-#define BVH_FUNCTION_NAME bvh_intersect_volume_motion
+#if defined(__VOLUME_RECORD_ALL__) && defined(__OBJECT_MOTION__)
+#define BVH_FUNCTION_NAME bvh_intersect_volume_all_motion
#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
-#include "geom_bvh_volume.h"
+#include "geom_bvh_volume_all.h"
#endif
-#if defined(__VOLUME__) && defined(__HAIR__) && defined(__OBJECT_MOTION__)
-#define BVH_FUNCTION_NAME bvh_intersect_volume_hair_motion
+#if defined(__VOLUME_RECORD_ALL__) && defined(__HAIR__) && defined(__OBJECT_MOTION__)
+#define BVH_FUNCTION_NAME bvh_intersect_volume_all_hair_motion
#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH|BVH_MOTION
-#include "geom_bvh_volume.h"
+#include "geom_bvh_volume_all.h"
#endif
#undef BVH_FEATURE
@@ -330,6 +362,37 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals *kg,
}
#endif
+#ifdef __VOLUME_RECORD_ALL__
+ccl_device_intersect uint scene_intersect_volume_all(KernelGlobals *kg,
+ const Ray *ray,
+ Intersection *isect,
+ const uint max_hits)
+{
+#ifdef __OBJECT_MOTION__
+ if(kernel_data.bvh.have_motion) {
+#ifdef __HAIR__
+ if(kernel_data.bvh.have_curves)
+ return bvh_intersect_volume_all_hair_motion(kg, ray, isect, max_hits);
+#endif /* __HAIR__ */
+
+ return bvh_intersect_volume_all_motion(kg, ray, isect, max_hits);
+ }
+#endif /* __OBJECT_MOTION__ */
+
+#ifdef __HAIR__
+ if(kernel_data.bvh.have_curves)
+ return bvh_intersect_volume_all_hair(kg, ray, isect, max_hits);
+#endif /* __HAIR__ */
+
+#ifdef __INSTANCING__
+ if(kernel_data.bvh.have_instancing)
+ return bvh_intersect_volume_all_instancing(kg, ray, isect, max_hits);
+#endif /* __INSTANCING__ */
+
+ return bvh_intersect_volume_all(kg, ray, isect, max_hits);
+}
+#endif
+
/* Ray offset to avoid self intersection.
*
@@ -384,5 +447,21 @@ ccl_device_inline float3 ray_offset(float3 P, float3 Ng)
#endif
}
+#if defined(__SHADOW_RECORD_ALL__) || defined (__VOLUME_RECORD_ALL__)
+/* ToDo: Move to another file? */
+ccl_device int intersections_compare(const void *a, const void *b)
+{
+ const Intersection *isect_a = (const Intersection*)a;
+ const Intersection *isect_b = (const Intersection*)b;
+
+ if(isect_a->t < isect_b->t)
+ return -1;
+ else if(isect_a->t > isect_b->t)
+ return 1;
+ else
+ return 0;
+}
+#endif
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_bvh_shadow.h b/intern/cycles/kernel/geom/geom_bvh_shadow.h
index 193f49074a3..e4cba99dc96 100644
--- a/intern/cycles/kernel/geom/geom_bvh_shadow.h
+++ b/intern/cycles/kernel/geom/geom_bvh_shadow.h
@@ -200,7 +200,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
/* if node is leaf, fetch triangle list */
if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+3);
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
int primAddr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
@@ -226,7 +226,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
switch(p_type) {
case PRIMITIVE_TRIANGLE: {
- hit = triangle_intersect(kg, &isect_precalc, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr);
+ hit = triangle_intersect(kg, &isect_precalc, isect_array, P, PATH_RAY_SHADOW, object, primAddr);
break;
}
#if BVH_FEATURE(BVH_MOTION)
@@ -264,7 +264,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
if(kernel_tex_fetch(__prim_type, isect_array->prim) & PRIMITIVE_ALL_TRIANGLE)
#endif
{
- shader = kernel_tex_fetch(__tri_shader, prim);
+ shader = kernel_tex_fetch(__tri_shader, prim);
}
#ifdef __HAIR__
else {
diff --git a/intern/cycles/kernel/geom/geom_bvh_subsurface.h b/intern/cycles/kernel/geom/geom_bvh_subsurface.h
index 290297ef5c5..a73139f9c88 100644
--- a/intern/cycles/kernel/geom/geom_bvh_subsurface.h
+++ b/intern/cycles/kernel/geom/geom_bvh_subsurface.h
@@ -187,7 +187,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
/* if node is leaf, fetch triangle list */
if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+3);
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
int primAddr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
@@ -210,7 +210,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
if(tri_object != subsurface_object)
continue;
- triangle_intersect_subsurface(kg, &isect_precalc, isect_array, P, dir, object, primAddr, isect_t, &num_hits, lcg_state, max_hits);
+ triangle_intersect_subsurface(kg, &isect_precalc, isect_array, P, object, primAddr, isect_t, &num_hits, lcg_state, max_hits);
}
break;
}
diff --git a/intern/cycles/kernel/geom/geom_bvh_traversal.h b/intern/cycles/kernel/geom/geom_bvh_traversal.h
index 0298e687de2..87f8ccd01b1 100644
--- a/intern/cycles/kernel/geom/geom_bvh_traversal.h
+++ b/intern/cycles/kernel/geom/geom_bvh_traversal.h
@@ -248,7 +248,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
/* if node is leaf, fetch triangle list */
if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+3);
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
int primAddr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
@@ -269,7 +269,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
isect->num_traversal_steps++;
#endif
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- if(triangle_intersect(kg, &isect_precalc, isect, P, dir, visibility, object, primAddr)) {
+ if(triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr)) {
/* shadow ray early termination */
#if defined(__KERNEL_SSE2__)
if(visibility == PATH_RAY_SHADOW_OPAQUE)
diff --git a/intern/cycles/kernel/geom/geom_bvh_volume.h b/intern/cycles/kernel/geom/geom_bvh_volume.h
index 0862812a170..41c784869f2 100644
--- a/intern/cycles/kernel/geom/geom_bvh_volume.h
+++ b/intern/cycles/kernel/geom/geom_bvh_volume.h
@@ -188,7 +188,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
/* if node is leaf, fetch triangle list */
if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+3);
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
int primAddr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
@@ -213,7 +213,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
- triangle_intersect(kg, &isect_precalc, isect, P, dir, visibility, object, primAddr);
+ triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr);
}
break;
}
diff --git a/intern/cycles/kernel/geom/geom_bvh_volume_all.h b/intern/cycles/kernel/geom/geom_bvh_volume_all.h
new file mode 100644
index 00000000000..b6db36f4b17
--- /dev/null
+++ b/intern/cycles/kernel/geom/geom_bvh_volume_all.h
@@ -0,0 +1,454 @@
+/*
+ * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
+ * and code copyright 2009-2012 Intel Corporation
+ *
+ * Modifications Copyright 2011-2014, 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.
+ */
+
+#ifdef __QBVH__
+#include "geom_qbvh_volume_all.h"
+#endif
+
+/* This is a template BVH traversal function for volumes, where
+ * various features can be enabled/disabled. This way we can compile optimized
+ * versions for each case without new features slowing things down.
+ *
+ * BVH_INSTANCING: object instancing
+ * BVH_HAIR: hair curve rendering
+ * BVH_MOTION: motion blur rendering
+ *
+ */
+
+ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
+ const Ray *ray,
+ Intersection *isect_array,
+ const uint max_hits)
+{
+ /* todo:
+ * - test if pushing distance on the stack helps (for non shadow rays)
+ * - separate version for shadow rays
+ * - likely and unlikely for if() statements
+ * - test restrict attribute for pointers
+ */
+
+ /* traversal stack in CUDA thread-local memory */
+ int traversalStack[BVH_STACK_SIZE];
+ traversalStack[0] = ENTRYPOINT_SENTINEL;
+
+ /* traversal variables in registers */
+ int stackPtr = 0;
+ int nodeAddr = kernel_data.bvh.root;
+
+ /* ray parameters in registers */
+ const float tmax = ray->t;
+ float3 P = ray->P;
+ float3 dir = bvh_clamp_direction(ray->D);
+ float3 idir = bvh_inverse_direction(dir);
+ int object = OBJECT_NONE;
+ float isect_t = tmax;
+
+ const uint visibility = PATH_RAY_ALL_VISIBILITY;
+
+#if BVH_FEATURE(BVH_MOTION)
+ Transform ob_tfm;
+#endif
+
+#if BVH_FEATURE(BVH_INSTANCING)
+ int num_hits_in_instance = 0;
+#endif
+
+ uint num_hits = 0;
+ isect_array->t = tmax;
+
+#if defined(__KERNEL_SSE2__)
+ const shuffle_swap_t shuf_identity = shuffle_swap_identity();
+ const shuffle_swap_t shuf_swap = shuffle_swap_swap();
+
+ const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
+ ssef Psplat[3], idirsplat[3];
+ shuffle_swap_t shufflexyz[3];
+
+ Psplat[0] = ssef(P.x);
+ Psplat[1] = ssef(P.y);
+ Psplat[2] = ssef(P.z);
+
+ ssef tsplat(0.0f, 0.0f, -isect_t, -isect_t);
+
+ gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
+#endif
+
+ IsectPrecalc isect_precalc;
+ triangle_intersect_precalc(dir, &isect_precalc);
+
+ /* traversal loop */
+ do {
+ do {
+ /* traverse internal nodes */
+ while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
+ bool traverseChild0, traverseChild1;
+ int nodeAddrChild1;
+
+#if !defined(__KERNEL_SSE2__)
+ /* Intersect two child bounding boxes, non-SSE version */
+ float t = isect_array->t;
+
+ /* fetch node data */
+ float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0);
+ float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1);
+ float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2);
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3);
+
+ /* intersect ray against child nodes */
+ NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x;
+ NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x;
+ NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y;
+ NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y;
+ NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z;
+ NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z;
+ NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f);
+ NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
+
+ NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x;
+ NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x;
+ NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y;
+ NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y;
+ NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z;
+ NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z;
+ NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
+ NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
+
+ /* decide which nodes to traverse next */
+ traverseChild0 = (c0max >= c0min);
+ traverseChild1 = (c1max >= c1min);
+
+#else // __KERNEL_SSE2__
+ /* Intersect two child bounding boxes, SSE3 version adapted from Embree */
+
+ /* fetch node data */
+ const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE;
+ const float4 cnodes = ((float4*)bvh_nodes)[3];
+
+ /* intersect ray against child nodes */
+ const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0];
+ const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1];
+ const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2];
+
+ /* calculate { c0min, c1min, -c0max, -c1max} */
+ ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
+ const ssef tminmax = minmax ^ pn;
+
+ const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
+
+ /* decide which nodes to traverse next */
+ traverseChild0 = (movemask(lrhit) & 1);
+ traverseChild1 = (movemask(lrhit) & 2);
+#endif // __KERNEL_SSE2__
+
+ nodeAddr = __float_as_int(cnodes.x);
+ nodeAddrChild1 = __float_as_int(cnodes.y);
+
+ if(traverseChild0 && traverseChild1) {
+ /* both children were intersected, push the farther one */
+#if !defined(__KERNEL_SSE2__)
+ bool closestChild1 = (c1min < c0min);
+#else
+ bool closestChild1 = tminmax[1] < tminmax[0];
+#endif
+
+ if(closestChild1) {
+ int tmp = nodeAddr;
+ nodeAddr = nodeAddrChild1;
+ nodeAddrChild1 = tmp;
+ }
+
+ ++stackPtr;
+ kernel_assert(stackPtr < BVH_STACK_SIZE);
+ traversalStack[stackPtr] = nodeAddrChild1;
+ }
+ else {
+ /* one child was intersected */
+ if(traverseChild1) {
+ nodeAddr = nodeAddrChild1;
+ }
+ else if(!traverseChild0) {
+ /* neither child was intersected */
+ nodeAddr = traversalStack[stackPtr];
+ --stackPtr;
+ }
+ }
+ }
+
+ /* if node is leaf, fetch triangle list */
+ if(nodeAddr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
+ int primAddr = __float_as_int(leaf.x);
+
+#if BVH_FEATURE(BVH_INSTANCING)
+ if(primAddr >= 0) {
+#endif
+ const int primAddr2 = __float_as_int(leaf.y);
+ const uint type = __float_as_int(leaf.w);
+ bool hit;
+
+ /* pop */
+ nodeAddr = traversalStack[stackPtr];
+ --stackPtr;
+
+ /* primitive intersection */
+ switch(type & PRIMITIVE_ALL) {
+ case PRIMITIVE_TRIANGLE: {
+ /* intersect ray against primitive */
+ for(; primAddr < primAddr2; primAddr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ /* only primitives from volume object */
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ int object_flag = kernel_tex_fetch(__object_flag, tri_object);
+ if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
+ continue;
+ }
+ hit = triangle_intersect(kg, &isect_precalc, isect_array, P, visibility, object, primAddr);
+ if(hit) {
+ /* Move on to next entry in intersections array. */
+ isect_array++;
+ num_hits++;
+#if BVH_FEATURE(BVH_INSTANCING)
+ num_hits_in_instance++;
+#endif
+ isect_array->t = isect_t;
+ if(num_hits == max_hits) {
+#if BVH_FEATURE(BVH_INSTANCING)
+#if BVH_FEATURE(BVH_MOTION)
+ float t_fac = len(transform_direction(&ob_tfm, 1.0f/idir));
+#else
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+ float t_fac = len(transform_direction(&tfm, 1.0f/idir));
+#endif
+ for(int i = 0; i < num_hits_in_instance; i++) {
+ (isect_array-i-1)->t *= t_fac;
+ }
+#endif /* BVH_FEATURE(BVH_INSTANCING) */
+ return num_hits;
+ }
+ }
+ }
+ break;
+ }
+#if BVH_FEATURE(BVH_MOTION)
+ case PRIMITIVE_MOTION_TRIANGLE: {
+ /* intersect ray against primitive */
+ for(; primAddr < primAddr2; primAddr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ /* only primitives from volume object */
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ int object_flag = kernel_tex_fetch(__object_flag, tri_object);
+ if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
+ continue;
+ }
+ hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, visibility, object, primAddr);
+ if(hit) {
+ /* Move on to next entry in intersections array. */
+ isect_array++;
+ num_hits++;
+#if BVH_FEATURE(BVH_INSTANCING)
+ num_hits_in_instance++;
+#endif
+ isect_array->t = isect_t;
+ if(num_hits == max_hits) {
+#if BVH_FEATURE(BVH_INSTANCING)
+# if BVH_FEATURE(BVH_MOTION)
+ float t_fac = len(transform_direction(&ob_tfm, 1.0f/idir));
+# else
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+ float t_fac = len(transform_direction(&tfm, 1.0f/idir));
+#endif
+ for(int i = 0; i < num_hits_in_instance; i++) {
+ (isect_array-i-1)->t *= t_fac;
+ }
+#endif /* BVH_FEATURE(BVH_INSTANCING) */
+ return num_hits;
+ }
+ }
+ }
+ break;
+ }
+#endif
+#if BVH_FEATURE(BVH_HAIR)
+ case PRIMITIVE_CURVE:
+ case PRIMITIVE_MOTION_CURVE: {
+ /* intersect ray against primitive */
+ for(; primAddr < primAddr2; primAddr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ /* only primitives from volume object */
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ int object_flag = kernel_tex_fetch(__object_flag, tri_object);
+ if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
+ continue;
+ }
+ if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
+ hit = bvh_cardinal_curve_intersect(kg, isect_array, P, dir, visibility, object, primAddr, ray->time, type, NULL, 0, 0);
+ else
+ hit = bvh_curve_intersect(kg, isect_array, P, dir, visibility, object, primAddr, ray->time, type, NULL, 0, 0);
+ if(hit) {
+ /* Move on to next entry in intersections array. */
+ isect_array++;
+ num_hits++;
+#if BVH_FEATURE(BVH_INSTANCING)
+ num_hits_in_instance++;
+#endif
+ isect_array->t = isect_t;
+ if(num_hits == max_hits) {
+#if BVH_FEATURE(BVH_INSTANCING)
+# if BVH_FEATURE(BVH_MOTION)
+ float t_fac = len(transform_direction(&ob_tfm, 1.0f/idir));
+# else
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+ float t_fac = len(transform_direction(&tfm, 1.0f/idir));
+#endif
+ for(int i = 0; i < num_hits_in_instance; i++) {
+ (isect_array-i-1)->t *= t_fac;
+ }
+#endif /* BVH_FEATURE(BVH_INSTANCING) */
+ return num_hits;
+ }
+ }
+ }
+ break;
+ }
+#endif
+ default: {
+ break;
+ }
+ }
+ }
+#if BVH_FEATURE(BVH_INSTANCING)
+ else {
+ /* instance push */
+ object = kernel_tex_fetch(__prim_object, -primAddr-1);
+ int object_flag = kernel_tex_fetch(__object_flag, object);
+
+ if(object_flag & SD_OBJECT_HAS_VOLUME) {
+
+#if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_tfm);
+#else
+ bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect_t);
+#endif
+
+ triangle_intersect_precalc(dir, &isect_precalc);
+ num_hits_in_instance = 0;
+ isect_array->t = isect_t;
+
+#if defined(__KERNEL_SSE2__)
+ Psplat[0] = ssef(P.x);
+ Psplat[1] = ssef(P.y);
+ Psplat[2] = ssef(P.z);
+
+ tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
+
+ gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
+#endif
+
+ ++stackPtr;
+ kernel_assert(stackPtr < BVH_STACK_SIZE);
+ traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
+
+ nodeAddr = kernel_tex_fetch(__object_node, object);
+ }
+ else {
+ /* pop */
+ object = OBJECT_NONE;
+ nodeAddr = traversalStack[stackPtr];
+ --stackPtr;
+ }
+ }
+ }
+#endif /* FEATURE(BVH_INSTANCING) */
+ } while(nodeAddr != ENTRYPOINT_SENTINEL);
+
+#if BVH_FEATURE(BVH_INSTANCING)
+ if(stackPtr >= 0) {
+ kernel_assert(object != OBJECT_NONE);
+
+ if(num_hits_in_instance) {
+ float t_fac;
+#if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac, &ob_tfm);
+#else
+ bvh_instance_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac);
+#endif
+ triangle_intersect_precalc(dir, &isect_precalc);
+ /* Scale isect->t to adjust for instancing. */
+ for(int i = 0; i < num_hits_in_instance; i++) {
+ (isect_array-i-1)->t *= t_fac;
+ }
+ }
+ else {
+ float ignore_t = FLT_MAX;
+#if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &ignore_t, &ob_tfm);
+#else
+ bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &ignore_t);
+#endif
+ triangle_intersect_precalc(dir, &isect_precalc);
+ }
+
+ isect_t = tmax;
+ isect_array->t = isect_t;
+
+#if defined(__KERNEL_SSE2__)
+ Psplat[0] = ssef(P.x);
+ Psplat[1] = ssef(P.y);
+ Psplat[2] = ssef(P.z);
+
+ tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
+
+ gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
+#endif
+
+ object = OBJECT_NONE;
+ nodeAddr = traversalStack[stackPtr];
+ --stackPtr;
+ }
+#endif /* FEATURE(BVH_MOTION) */
+ } while(nodeAddr != ENTRYPOINT_SENTINEL);
+
+ return num_hits;
+}
+
+ccl_device_inline uint BVH_FUNCTION_NAME(KernelGlobals *kg,
+ const Ray *ray,
+ Intersection *isect_array,
+ const uint max_hits)
+{
+#ifdef __QBVH__
+ if(kernel_data.bvh.use_qbvh) {
+ return BVH_FUNCTION_FULL_NAME(QBVH)(kg,
+ ray,
+ isect_array,
+ max_hits);
+ }
+ else
+#endif
+ {
+ kernel_assert(kernel_data.bvh.use_qbvh == false);
+ return BVH_FUNCTION_FULL_NAME(BVH)(kg,
+ ray,
+ isect_array,
+ max_hits);
+ }
+}
+
+#undef BVH_FUNCTION_NAME
+#undef BVH_FUNCTION_FEATURES
diff --git a/intern/cycles/kernel/geom/geom_curve.h b/intern/cycles/kernel/geom/geom_curve.h
index ac6c6ec4929..9653ad8f1bb 100644
--- a/intern/cycles/kernel/geom/geom_curve.h
+++ b/intern/cycles/kernel/geom/geom_curve.h
@@ -32,22 +32,22 @@ ccl_device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd,
if(dy) *dy = 0.0f;
#endif
- return kernel_tex_fetch(__attributes_float, offset + sd->prim);
+ return kernel_tex_fetch(__attributes_float, offset + ccl_fetch(sd, prim));
}
else if(elem == ATTR_ELEMENT_CURVE_KEY || elem == ATTR_ELEMENT_CURVE_KEY_MOTION) {
- float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
- int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(sd->type);
+ float4 curvedata = kernel_tex_fetch(__curves, ccl_fetch(sd, prim));
+ int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(ccl_fetch(sd, type));
int k1 = k0 + 1;
float f0 = kernel_tex_fetch(__attributes_float, offset + k0);
float f1 = kernel_tex_fetch(__attributes_float, offset + k1);
#ifdef __RAY_DIFFERENTIALS__
- if(dx) *dx = sd->du.dx*(f1 - f0);
+ if(dx) *dx = ccl_fetch(sd, du).dx*(f1 - f0);
if(dy) *dy = 0.0f;
#endif
- return (1.0f - sd->u)*f0 + sd->u*f1;
+ return (1.0f - ccl_fetch(sd, u))*f0 + ccl_fetch(sd, u)*f1;
}
else {
#ifdef __RAY_DIFFERENTIALS__
@@ -71,22 +71,22 @@ ccl_device float3 curve_attribute_float3(KernelGlobals *kg, const ShaderData *sd
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
#endif
- return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + sd->prim));
+ return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + ccl_fetch(sd, prim)));
}
else if(elem == ATTR_ELEMENT_CURVE_KEY || elem == ATTR_ELEMENT_CURVE_KEY_MOTION) {
- float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
- int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(sd->type);
+ float4 curvedata = kernel_tex_fetch(__curves, ccl_fetch(sd, prim));
+ int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(ccl_fetch(sd, type));
int k1 = k0 + 1;
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + k0));
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + k1));
#ifdef __RAY_DIFFERENTIALS__
- if(dx) *dx = sd->du.dx*(f1 - f0);
+ if(dx) *dx = ccl_fetch(sd, du).dx*(f1 - f0);
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
#endif
- return (1.0f - sd->u)*f0 + sd->u*f1;
+ return (1.0f - ccl_fetch(sd, u))*f0 + ccl_fetch(sd, u)*f1;
}
else {
#ifdef __RAY_DIFFERENTIALS__
@@ -104,22 +104,22 @@ ccl_device float curve_thickness(KernelGlobals *kg, ShaderData *sd)
{
float r = 0.0f;
- if(sd->type & PRIMITIVE_ALL_CURVE) {
- float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
- int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(sd->type);
+ if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) {
+ float4 curvedata = kernel_tex_fetch(__curves, ccl_fetch(sd, prim));
+ int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(ccl_fetch(sd, type));
int k1 = k0 + 1;
float4 P_curve[2];
- if(sd->type & PRIMITIVE_CURVE) {
+ if(ccl_fetch(sd, type) & PRIMITIVE_CURVE) {
P_curve[0]= kernel_tex_fetch(__curve_keys, k0);
P_curve[1]= kernel_tex_fetch(__curve_keys, k1);
}
else {
- motion_curve_keys(kg, sd->object, sd->prim, sd->time, k0, k1, P_curve);
+ motion_curve_keys(kg, ccl_fetch(sd, object), ccl_fetch(sd, prim), ccl_fetch(sd, time), k0, k1, P_curve);
}
- r = (P_curve[1].w - P_curve[0].w) * sd->u + P_curve[0].w;
+ r = (P_curve[1].w - P_curve[0].w) * ccl_fetch(sd, u) + P_curve[0].w;
}
return r*2.0f;
@@ -130,8 +130,8 @@ ccl_device float curve_thickness(KernelGlobals *kg, ShaderData *sd)
ccl_device float3 curve_motion_center_location(KernelGlobals *kg, ShaderData *sd)
{
- float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
- int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(sd->type);
+ float4 curvedata = kernel_tex_fetch(__curves, ccl_fetch(sd, prim));
+ int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(ccl_fetch(sd, type));
int k1 = k0 + 1;
float4 P_curve[2];
@@ -139,7 +139,7 @@ ccl_device float3 curve_motion_center_location(KernelGlobals *kg, ShaderData *sd
P_curve[0]= kernel_tex_fetch(__curve_keys, k0);
P_curve[1]= kernel_tex_fetch(__curve_keys, k1);
- return float4_to_float3(P_curve[1]) * sd->u + float4_to_float3(P_curve[0]) * (1.0f - sd->u);
+ return float4_to_float3(P_curve[1]) * ccl_fetch(sd, u) + float4_to_float3(P_curve[0]) * (1.0f - ccl_fetch(sd, u));
}
/* Curve tangent normal */
@@ -148,14 +148,14 @@ ccl_device float3 curve_tangent_normal(KernelGlobals *kg, ShaderData *sd)
{
float3 tgN = make_float3(0.0f,0.0f,0.0f);
- if(sd->type & PRIMITIVE_ALL_CURVE) {
+ if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) {
- tgN = -(-sd->I - sd->dPdu * (dot(sd->dPdu,-sd->I) / len_squared(sd->dPdu)));
+ tgN = -(-ccl_fetch(sd, I) - ccl_fetch(sd, dPdu) * (dot(ccl_fetch(sd, dPdu),-ccl_fetch(sd, I)) / len_squared(ccl_fetch(sd, dPdu))));
tgN = normalize(tgN);
/* need to find suitable scaled gd for corrected normal */
#if 0
- tgN = normalize(tgN - gd * sd->dPdu);
+ tgN = normalize(tgN - gd * ccl_fetch(sd, dPdu));
#endif
}
@@ -442,12 +442,12 @@ ccl_device_inline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersect
float r_ext = mw_extension + r_curr;
float coverage = 1.0f;
- if (bminz - r_curr > isect->t || bmaxz + r_curr < epsilon || bminx > r_ext|| bmaxx < -r_ext|| bminy > r_ext|| bmaxy < -r_ext) {
+ if(bminz - r_curr > isect->t || bmaxz + r_curr < epsilon || bminx > r_ext|| bmaxx < -r_ext|| bminy > r_ext|| bmaxy < -r_ext) {
/* the bounding box does not overlap the square centered at O */
tree += level;
level = tree & -tree;
}
- else if (level == 1) {
+ else if(level == 1) {
/* the maximum recursion depth is reached.
* check if dP0.(Q-P0)>=0 and dPn.(Pn-Q)>=0.
@@ -459,13 +459,13 @@ ccl_device_inline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersect
if(flags & CURVE_KN_RIBBONS) {
float3 tg = (p_en - p_st);
float w = tg.x * tg.x + tg.y * tg.y;
- if (w == 0) {
+ if(w == 0) {
tree++;
level = tree & -tree;
continue;
}
w = -(p_st.x * tg.x + p_st.y * tg.y) / w;
- w = clamp((float)w, 0.0f, 1.0f);
+ w = saturate(w);
/* compute u on the curve segment */
u = i_st * (1 - w) + i_en * w;
@@ -474,17 +474,17 @@ ccl_device_inline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersect
float3 p_curr = ((curve_coef[3] * u + curve_coef[2]) * u + curve_coef[1]) * u + curve_coef[0];
float3 dp_st = (3 * curve_coef[3] * i_st + 2 * curve_coef[2]) * i_st + curve_coef[1];
- if (dot(tg, dp_st)< 0)
+ if(dot(tg, dp_st)< 0)
dp_st *= -1;
- if (dot(dp_st, -p_st) + p_curr.z * dp_st.z < 0) {
+ if(dot(dp_st, -p_st) + p_curr.z * dp_st.z < 0) {
tree++;
level = tree & -tree;
continue;
}
float3 dp_en = (3 * curve_coef[3] * i_en + 2 * curve_coef[2]) * i_en + curve_coef[1];
- if (dot(tg, dp_en) < 0)
+ if(dot(tg, dp_en) < 0)
dp_en *= -1;
- if (dot(dp_en, p_en) - p_curr.z * dp_en.z < 0) {
+ if(dot(dp_en, p_en) - p_curr.z * dp_en.z < 0) {
tree++;
level = tree & -tree;
continue;
@@ -500,13 +500,13 @@ ccl_device_inline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersect
float d0 = d - r_curr;
float d1 = d + r_curr;
float inv_mw_extension = 1.0f/mw_extension;
- if (d0 >= 0)
+ if(d0 >= 0)
coverage = (min(d1 * inv_mw_extension, 1.0f) - min(d0 * inv_mw_extension, 1.0f)) * 0.5f;
else // inside
coverage = (min(d1 * inv_mw_extension, 1.0f) + min(-d0 * inv_mw_extension, 1.0f)) * 0.5f;
}
- if (p_curr.x * p_curr.x + p_curr.y * p_curr.y >= r_ext * r_ext || p_curr.z <= epsilon || isect->t < p_curr.z) {
+ if(p_curr.x * p_curr.x + p_curr.y * p_curr.y >= r_ext * r_ext || p_curr.z <= epsilon || isect->t < p_curr.z) {
tree++;
level = tree & -tree;
continue;
@@ -548,7 +548,7 @@ ccl_device_inline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersect
float tb = 2*(tdif.z - tg.z*(tdifz + gd*(tdifz*gd + or1)));
float tc = dot(tdif,tdif) - tdifz * tdifz * (1 + gd*gd) - or1*or1 - 2*or1*tdifz*gd;
float td = tb*tb - 4*cyla*tc;
- if (td < 0.0f) {
+ if(td < 0.0f) {
tree++;
level = tree & -tree;
continue;
@@ -559,10 +559,10 @@ ccl_device_inline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersect
t = tcentre + correction;
float3 dp_st = (3 * curve_coef[3] * i_st + 2 * curve_coef[2]) * i_st + curve_coef[1];
- if (dot(tg, dp_st)< 0)
+ if(dot(tg, dp_st)< 0)
dp_st *= -1;
float3 dp_en = (3 * curve_coef[3] * i_en + 2 * curve_coef[2]) * i_en + curve_coef[1];
- if (dot(tg, dp_en) < 0)
+ if(dot(tg, dp_en) < 0)
dp_en *= -1;
if(flags & CURVE_KN_BACKFACING && (dot(dp_st, -p_st) + t * dp_st.z < 0 || dot(dp_en, p_en) - t * dp_en.z < 0 || isect->t < t || t <= 0.0f)) {
@@ -570,14 +570,14 @@ ccl_device_inline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersect
t = tcentre + correction;
}
- if (dot(dp_st, -p_st) + t * dp_st.z < 0 || dot(dp_en, p_en) - t * dp_en.z < 0 || isect->t < t || t <= 0.0f) {
+ if(dot(dp_st, -p_st) + t * dp_st.z < 0 || dot(dp_en, p_en) - t * dp_en.z < 0 || isect->t < t || t <= 0.0f) {
tree++;
level = tree & -tree;
continue;
}
float w = (zcentre + (tg.z * correction)) * invl;
- w = clamp((float)w, 0.0f, 1.0f);
+ w = saturate(w);
/* compute u on the curve segment */
u = i_st * (1 - w) + i_en * w;
@@ -777,7 +777,7 @@ ccl_device_inline bool bvh_curve_intersect(KernelGlobals *kg, Intersection *isec
float tc = dot3(tdif, tdif) - tdifz*tdifz - tdifma*tdifma;
float td = tb*tb - 4*a*tc;
- if (td < 0.0f)
+ if(td < 0.0f)
return false;
float rootd = 0.0f;
@@ -818,7 +818,7 @@ ccl_device_inline bool bvh_curve_intersect(KernelGlobals *kg, Intersection *isec
if(t > 0.0f && t < isect->t && z >= 0 && z <= l) {
- if (flags & CURVE_KN_ENCLOSEFILTER) {
+ if(flags & CURVE_KN_ENCLOSEFILTER) {
float enc_ratio = 1.01f;
if((difz > -r1 * enc_ratio) && (dot3(dif_second, tg) < r2 * enc_ratio)) {
float a2 = 1.0f - (dirz*dirz*(1 + gd*gd*enc_ratio*enc_ratio));
@@ -890,7 +890,7 @@ ccl_device_inline float3 bvh_curve_refine(KernelGlobals *kg, ShaderData *sd, con
if(isect->object != OBJECT_NONE) {
#ifdef __OBJECT_MOTION__
- Transform tfm = sd->ob_itfm;
+ Transform tfm = ccl_fetch(sd, ob_itfm);
#else
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
#endif
@@ -903,7 +903,7 @@ ccl_device_inline float3 bvh_curve_refine(KernelGlobals *kg, ShaderData *sd, con
int prim = kernel_tex_fetch(__prim_index, isect->prim);
float4 v00 = kernel_tex_fetch(__curves, prim);
- int k0 = __float_as_int(v00.x) + PRIMITIVE_UNPACK_SEGMENT(sd->type);
+ int k0 = __float_as_int(v00.x) + PRIMITIVE_UNPACK_SEGMENT(ccl_fetch(sd, type));
int k1 = k0 + 1;
float3 tg;
@@ -914,14 +914,14 @@ ccl_device_inline float3 bvh_curve_refine(KernelGlobals *kg, ShaderData *sd, con
float4 P_curve[4];
- if(sd->type & PRIMITIVE_CURVE) {
+ if(ccl_fetch(sd, type) & PRIMITIVE_CURVE) {
P_curve[0] = kernel_tex_fetch(__curve_keys, ka);
P_curve[1] = kernel_tex_fetch(__curve_keys, k0);
P_curve[2] = kernel_tex_fetch(__curve_keys, k1);
P_curve[3] = kernel_tex_fetch(__curve_keys, kb);
}
else {
- motion_cardinal_curve_keys(kg, sd->object, sd->prim, sd->time, ka, k0, k1, kb, P_curve);
+ motion_cardinal_curve_keys(kg, ccl_fetch(sd, object), ccl_fetch(sd, prim), ccl_fetch(sd, time), ka, k0, k1, kb, P_curve);
}
float3 p[4];
@@ -933,43 +933,43 @@ ccl_device_inline float3 bvh_curve_refine(KernelGlobals *kg, ShaderData *sd, con
P = P + D*t;
#ifdef __UV__
- sd->u = isect->u;
- sd->v = 0.0f;
+ ccl_fetch(sd, u) = isect->u;
+ ccl_fetch(sd, v) = 0.0f;
#endif
tg = normalize(curvetangent(isect->u, p[0], p[1], p[2], p[3]));
if(kernel_data.curve.curveflags & CURVE_KN_RIBBONS) {
- sd->Ng = normalize(-(D - tg * (dot(tg, D))));
+ ccl_fetch(sd, Ng) = normalize(-(D - tg * (dot(tg, D))));
}
else {
/* direction from inside to surface of curve */
float3 p_curr = curvepoint(isect->u, p[0], p[1], p[2], p[3]);
- sd->Ng = normalize(P - p_curr);
+ ccl_fetch(sd, Ng) = normalize(P - p_curr);
/* adjustment for changing radius */
float gd = isect->v;
if(gd != 0.0f) {
- sd->Ng = sd->Ng - gd * tg;
- sd->Ng = normalize(sd->Ng);
+ ccl_fetch(sd, Ng) = ccl_fetch(sd, Ng) - gd * tg;
+ ccl_fetch(sd, Ng) = normalize(ccl_fetch(sd, Ng));
}
}
/* todo: sometimes the normal is still so that this is detected as
* backfacing even if cull backfaces is enabled */
- sd->N = sd->Ng;
+ ccl_fetch(sd, N) = ccl_fetch(sd, Ng);
}
else {
float4 P_curve[2];
- if(sd->type & PRIMITIVE_CURVE) {
+ if(ccl_fetch(sd, type) & PRIMITIVE_CURVE) {
P_curve[0]= kernel_tex_fetch(__curve_keys, k0);
P_curve[1]= kernel_tex_fetch(__curve_keys, k1);
}
else {
- motion_curve_keys(kg, sd->object, sd->prim, sd->time, k0, k1, P_curve);
+ motion_curve_keys(kg, ccl_fetch(sd, object), ccl_fetch(sd, prim), ccl_fetch(sd, time), k0, k1, P_curve);
}
float l = 1.0f;
@@ -980,39 +980,39 @@ ccl_device_inline float3 bvh_curve_refine(KernelGlobals *kg, ShaderData *sd, con
float3 dif = P - float4_to_float3(P_curve[0]);
#ifdef __UV__
- sd->u = dot(dif,tg)/l;
- sd->v = 0.0f;
+ ccl_fetch(sd, u) = dot(dif,tg)/l;
+ ccl_fetch(sd, v) = 0.0f;
#endif
- if (flag & CURVE_KN_TRUETANGENTGNORMAL) {
- sd->Ng = -(D - tg * dot(tg, D));
- sd->Ng = normalize(sd->Ng);
+ if(flag & CURVE_KN_TRUETANGENTGNORMAL) {
+ ccl_fetch(sd, Ng) = -(D - tg * dot(tg, D));
+ ccl_fetch(sd, Ng) = normalize(ccl_fetch(sd, Ng));
}
else {
float gd = isect->v;
/* direction from inside to surface of curve */
- sd->Ng = (dif - tg * sd->u * l) / (P_curve[0].w + sd->u * l * gd);
+ ccl_fetch(sd, Ng) = (dif - tg * ccl_fetch(sd, u) * l) / (P_curve[0].w + ccl_fetch(sd, u) * l * gd);
/* adjustment for changing radius */
- if (gd != 0.0f) {
- sd->Ng = sd->Ng - gd * tg;
- sd->Ng = normalize(sd->Ng);
+ if(gd != 0.0f) {
+ ccl_fetch(sd, Ng) = ccl_fetch(sd, Ng) - gd * tg;
+ ccl_fetch(sd, Ng) = normalize(ccl_fetch(sd, Ng));
}
}
- sd->N = sd->Ng;
+ ccl_fetch(sd, N) = ccl_fetch(sd, Ng);
}
#ifdef __DPDU__
/* dPdu/dPdv */
- sd->dPdu = tg;
- sd->dPdv = cross(tg, sd->Ng);
+ ccl_fetch(sd, dPdu) = tg;
+ ccl_fetch(sd, dPdv) = cross(tg, ccl_fetch(sd, Ng));
#endif
if(isect->object != OBJECT_NONE) {
#ifdef __OBJECT_MOTION__
- Transform tfm = sd->ob_tfm;
+ Transform tfm = ccl_fetch(sd, ob_tfm);
#else
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
#endif
diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h
index d3297e05c67..86f93f242a1 100644
--- a/intern/cycles/kernel/geom/geom_motion_triangle.h
+++ b/intern/cycles/kernel/geom/geom_motion_triangle.h
@@ -134,7 +134,7 @@ ccl_device_inline float3 motion_triangle_refine(KernelGlobals *kg, ShaderData *s
return P;
}
#ifdef __OBJECT_MOTION__
- Transform tfm = sd->ob_itfm;
+ Transform tfm = ccl_fetch(sd, ob_itfm);
#else
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
#endif
@@ -161,7 +161,7 @@ ccl_device_inline float3 motion_triangle_refine(KernelGlobals *kg, ShaderData *s
if(isect->object != OBJECT_NONE) {
#ifdef __OBJECT_MOTION__
- Transform tfm = sd->ob_tfm;
+ Transform tfm = ccl_fetch(sd, ob_tfm);
#else
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
#endif
@@ -187,7 +187,7 @@ ccl_device_inline float3 motion_triangle_refine_subsurface(KernelGlobals *kg, Sh
#ifdef __INTERSECTION_REFINE__
if(isect->object != OBJECT_NONE) {
#ifdef __OBJECT_MOTION__
- Transform tfm = sd->ob_itfm;
+ Transform tfm = ccl_fetch(sd, ob_itfm);
#else
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
#endif
@@ -213,7 +213,7 @@ ccl_device_inline float3 motion_triangle_refine_subsurface(KernelGlobals *kg, Sh
if(isect->object != OBJECT_NONE) {
#ifdef __OBJECT_MOTION__
- Transform tfm = sd->ob_tfm;
+ Transform tfm = ccl_fetch(sd, ob_tfm);
#else
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
#endif
@@ -236,25 +236,25 @@ ccl_device_inline float3 motion_triangle_refine_subsurface(KernelGlobals *kg, Sh
ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, bool subsurface)
{
/* get shader */
- sd->shader = kernel_tex_fetch(__tri_shader, sd->prim);
+ ccl_fetch(sd, shader) = kernel_tex_fetch(__tri_shader, ccl_fetch(sd, prim));
/* get motion info */
int numsteps, numverts;
- object_motion_info(kg, sd->object, &numsteps, &numverts, NULL);
+ object_motion_info(kg, ccl_fetch(sd, object), &numsteps, &numverts, NULL);
/* figure out which steps we need to fetch and their interpolation factor */
int maxstep = numsteps*2;
- int step = min((int)(sd->time*maxstep), maxstep-1);
- float t = sd->time*maxstep - step;
+ int step = min((int)(ccl_fetch(sd, time)*maxstep), maxstep-1);
+ float t = ccl_fetch(sd, time)*maxstep - step;
/* find attribute */
AttributeElement elem;
- int offset = find_attribute_motion(kg, sd->object, ATTR_STD_MOTION_VERTEX_POSITION, &elem);
+ int offset = find_attribute_motion(kg, ccl_fetch(sd, object), ATTR_STD_MOTION_VERTEX_POSITION, &elem);
kernel_assert(offset != ATTR_STD_NOT_FOUND);
/* fetch vertex coordinates */
float3 verts[3], next_verts[3];
- float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, sd->prim));
+ float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)));
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_verts);
@@ -268,33 +268,33 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, ShaderD
#ifdef __SUBSURFACE__
if(!subsurface)
#endif
- sd->P = motion_triangle_refine(kg, sd, isect, ray, verts);
+ ccl_fetch(sd, P) = motion_triangle_refine(kg, sd, isect, ray, verts);
#ifdef __SUBSURFACE__
else
- sd->P = motion_triangle_refine_subsurface(kg, sd, isect, ray, verts);
+ ccl_fetch(sd, P) = motion_triangle_refine_subsurface(kg, sd, isect, ray, verts);
#endif
/* compute face normal */
float3 Ng;
- if(sd->flag & SD_NEGATIVE_SCALE_APPLIED)
+ if(ccl_fetch(sd, flag) & SD_NEGATIVE_SCALE_APPLIED)
Ng = normalize(cross(verts[2] - verts[0], verts[1] - verts[0]));
else
Ng = normalize(cross(verts[1] - verts[0], verts[2] - verts[0]));
- sd->Ng = Ng;
- sd->N = Ng;
+ ccl_fetch(sd, Ng) = Ng;
+ ccl_fetch(sd, N) = Ng;
/* compute derivatives of P w.r.t. uv */
#ifdef __DPDU__
- sd->dPdu = (verts[0] - verts[2]);
- sd->dPdv = (verts[1] - verts[2]);
+ ccl_fetch(sd, dPdu) = (verts[0] - verts[2]);
+ ccl_fetch(sd, dPdv) = (verts[1] - verts[2]);
#endif
/* compute smooth normal */
- if(sd->shader & SHADER_SMOOTH_NORMAL) {
+ if(ccl_fetch(sd, shader) & SHADER_SMOOTH_NORMAL) {
/* find attribute */
AttributeElement elem;
- int offset = find_attribute_motion(kg, sd->object, ATTR_STD_MOTION_VERTEX_NORMAL, &elem);
+ int offset = find_attribute_motion(kg, ccl_fetch(sd, object), ATTR_STD_MOTION_VERTEX_NORMAL, &elem);
kernel_assert(offset != ATTR_STD_NOT_FOUND);
/* fetch vertex coordinates */
@@ -308,10 +308,10 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, ShaderD
normals[2] = (1.0f - t)*normals[2] + t*next_normals[2];
/* interpolate between vertices */
- float u = sd->u;
- float v = sd->v;
+ float u = ccl_fetch(sd, u);
+ float v = ccl_fetch(sd, v);
float w = 1.0f - u - v;
- sd->N = (u*normals[0] + v*normals[1] + w*normals[2]);
+ ccl_fetch(sd, N) = (u*normals[0] + v*normals[1] + w*normals[2]);
}
}
diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h
index 79a56683454..9d0a008fff1 100644
--- a/intern/cycles/kernel/geom/geom_object.h
+++ b/intern/cycles/kernel/geom/geom_object.h
@@ -123,9 +123,9 @@ ccl_device_inline Transform object_fetch_transform_motion_test(KernelGlobals *kg
ccl_device_inline void object_position_transform(KernelGlobals *kg, const ShaderData *sd, float3 *P)
{
#ifdef __OBJECT_MOTION__
- *P = transform_point(&sd->ob_tfm, *P);
+ *P = transform_point_auto(&ccl_fetch(sd, ob_tfm), *P);
#else
- Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
+ Transform tfm = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_TRANSFORM);
*P = transform_point(&tfm, *P);
#endif
}
@@ -135,9 +135,9 @@ ccl_device_inline void object_position_transform(KernelGlobals *kg, const Shader
ccl_device_inline void object_inverse_position_transform(KernelGlobals *kg, const ShaderData *sd, float3 *P)
{
#ifdef __OBJECT_MOTION__
- *P = transform_point(&sd->ob_itfm, *P);
+ *P = transform_point_auto(&ccl_fetch(sd, ob_itfm), *P);
#else
- Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
+ Transform tfm = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_INVERSE_TRANSFORM);
*P = transform_point(&tfm, *P);
#endif
}
@@ -147,9 +147,9 @@ ccl_device_inline void object_inverse_position_transform(KernelGlobals *kg, cons
ccl_device_inline void object_inverse_normal_transform(KernelGlobals *kg, const ShaderData *sd, float3 *N)
{
#ifdef __OBJECT_MOTION__
- *N = normalize(transform_direction_transposed(&sd->ob_tfm, *N));
+ *N = normalize(transform_direction_transposed_auto(&ccl_fetch(sd, ob_tfm), *N));
#else
- Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
+ Transform tfm = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_TRANSFORM);
*N = normalize(transform_direction_transposed(&tfm, *N));
#endif
}
@@ -159,9 +159,9 @@ ccl_device_inline void object_inverse_normal_transform(KernelGlobals *kg, const
ccl_device_inline void object_normal_transform(KernelGlobals *kg, const ShaderData *sd, float3 *N)
{
#ifdef __OBJECT_MOTION__
- *N = normalize(transform_direction_transposed(&sd->ob_itfm, *N));
+ *N = normalize(transform_direction_transposed_auto(&ccl_fetch(sd, ob_itfm), *N));
#else
- Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
+ Transform tfm = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_INVERSE_TRANSFORM);
*N = normalize(transform_direction_transposed(&tfm, *N));
#endif
}
@@ -171,9 +171,9 @@ ccl_device_inline void object_normal_transform(KernelGlobals *kg, const ShaderDa
ccl_device_inline void object_dir_transform(KernelGlobals *kg, const ShaderData *sd, float3 *D)
{
#ifdef __OBJECT_MOTION__
- *D = transform_direction(&sd->ob_tfm, *D);
+ *D = transform_direction_auto(&ccl_fetch(sd, ob_tfm), *D);
#else
- Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
+ Transform tfm = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_TRANSFORM);
*D = transform_direction(&tfm, *D);
#endif
}
@@ -183,9 +183,9 @@ ccl_device_inline void object_dir_transform(KernelGlobals *kg, const ShaderData
ccl_device_inline void object_inverse_dir_transform(KernelGlobals *kg, const ShaderData *sd, float3 *D)
{
#ifdef __OBJECT_MOTION__
- *D = transform_direction(&sd->ob_itfm, *D);
+ *D = transform_direction_auto(&ccl_fetch(sd, ob_itfm), *D);
#else
- Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
+ Transform tfm = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_INVERSE_TRANSFORM);
*D = transform_direction(&tfm, *D);
#endif
}
@@ -194,13 +194,13 @@ ccl_device_inline void object_inverse_dir_transform(KernelGlobals *kg, const Sha
ccl_device_inline float3 object_location(KernelGlobals *kg, const ShaderData *sd)
{
- if(sd->object == OBJECT_NONE)
+ if(ccl_fetch(sd, object) == OBJECT_NONE)
return make_float3(0.0f, 0.0f, 0.0f);
#ifdef __OBJECT_MOTION__
- return make_float3(sd->ob_tfm.x.w, sd->ob_tfm.y.w, sd->ob_tfm.z.w);
+ return make_float3(ccl_fetch(sd, ob_tfm).x.w, ccl_fetch(sd, ob_tfm).y.w, ccl_fetch(sd, ob_tfm).z.w);
#else
- Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
+ Transform tfm = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_TRANSFORM);
return make_float3(tfm.x.w, tfm.y.w, tfm.z.w);
#endif
}
@@ -243,7 +243,7 @@ ccl_device_inline float object_random_number(KernelGlobals *kg, int object)
ccl_device_inline int object_particle_id(KernelGlobals *kg, int object)
{
if(object == OBJECT_NONE)
- return 0.0f;
+ return 0;
int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
float4 f = kernel_tex_fetch(__objects, offset);
@@ -296,7 +296,7 @@ ccl_device_inline void object_motion_info(KernelGlobals *kg, int object, int *nu
ccl_device int shader_pass_id(KernelGlobals *kg, const ShaderData *sd)
{
- return kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2 + 1);
+ return kernel_tex_fetch(__shader_flag, (ccl_fetch(sd, shader) & SHADER_MASK)*2 + 1);
}
/* Particle data from which object was instanced */
@@ -377,7 +377,7 @@ ccl_device_inline float3 bvh_inverse_direction(float3 dir)
/* Transform ray into object space to enter static object in BVH */
-ccl_device_inline void bvh_instance_push(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, float *t)
+ccl_device_inline void bvh_instance_push(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, ccl_addr_space float *t)
{
Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
@@ -425,7 +425,7 @@ ccl_device_inline void qbvh_instance_push(KernelGlobals *kg,
/* Transorm ray to exit static object in BVH */
-ccl_device_inline void bvh_instance_pop(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, float *t)
+ccl_device_inline void bvh_instance_pop(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, ccl_addr_space float *t)
{
if(*t != FLT_MAX) {
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
@@ -453,7 +453,7 @@ ccl_device_inline void bvh_instance_pop_factor(KernelGlobals *kg, int object, co
#ifdef __OBJECT_MOTION__
/* Transform ray into object space to enter motion blurred object in BVH */
-ccl_device_inline void bvh_instance_motion_push(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, float *t, Transform *tfm)
+ccl_device_inline void bvh_instance_motion_push(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, ccl_addr_space float *t, Transform *tfm)
{
Transform itfm;
*tfm = object_fetch_transform_motion_test(kg, object, ray->time, &itfm);
@@ -497,7 +497,7 @@ ccl_device_inline void qbvh_instance_motion_push(KernelGlobals *kg, int object,
/* Transorm ray to exit motion blurred object in BVH */
-ccl_device_inline void bvh_instance_motion_pop(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, float *t, Transform *tfm)
+ccl_device_inline void bvh_instance_motion_pop(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, ccl_addr_space float *t, Transform *tfm)
{
if(*t != FLT_MAX)
*t *= len(transform_direction(tfm, 1.0f/(*idir)));
@@ -520,5 +520,38 @@ ccl_device_inline void bvh_instance_motion_pop_factor(KernelGlobals *kg, int obj
#endif
+/* TODO(sergey): This is only for until we've got OpenCL 2.0
+ * on all devices we consider supported. It'll be replaced with
+ * generic address space.
+ */
+
+#ifdef __KERNEL_OPENCL__
+ccl_device_inline void object_dir_transform_addrspace(KernelGlobals *kg,
+ const ShaderData *sd,
+ ccl_addr_space float3 *D)
+{
+ float3 private_D = *D;
+ object_dir_transform(kg, sd, &private_D);
+ *D = private_D;
+}
+
+ccl_device_inline void object_normal_transform_addrspace(KernelGlobals *kg,
+ const ShaderData *sd,
+ ccl_addr_space float3 *N)
+{
+ float3 private_N = *N;
+ object_normal_transform(kg, sd, &private_N);
+ *N = private_N;
+}
+#endif
+
+#ifndef __KERNEL_OPENCL__
+# define object_dir_transform_auto object_dir_transform
+# define object_normal_transform_auto object_normal_transform
+#else
+# define object_dir_transform_auto object_dir_transform_addrspace
+# define object_normal_transform_auto object_normal_transform_addrspace
+#endif
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_primitive.h b/intern/cycles/kernel/geom/geom_primitive.h
index b52ec7ef1b2..30f12d32355 100644
--- a/intern/cycles/kernel/geom/geom_primitive.h
+++ b/intern/cycles/kernel/geom/geom_primitive.h
@@ -25,16 +25,16 @@ CCL_NAMESPACE_BEGIN
ccl_device float primitive_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
{
- if(sd->type & PRIMITIVE_ALL_TRIANGLE) {
+ if(ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE) {
return triangle_attribute_float(kg, sd, elem, offset, dx, dy);
}
#ifdef __HAIR__
- else if(sd->type & PRIMITIVE_ALL_CURVE) {
+ else if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) {
return curve_attribute_float(kg, sd, elem, offset, dx, dy);
}
#endif
#ifdef __VOLUME__
- else if(sd->object != OBJECT_NONE && elem == ATTR_ELEMENT_VOXEL) {
+ else if(ccl_fetch(sd, object) != OBJECT_NONE && elem == ATTR_ELEMENT_VOXEL) {
return volume_attribute_float(kg, sd, elem, offset, dx, dy);
}
#endif
@@ -47,16 +47,16 @@ ccl_device float primitive_attribute_float(KernelGlobals *kg, const ShaderData *
ccl_device float3 primitive_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
{
- if(sd->type & PRIMITIVE_ALL_TRIANGLE) {
+ if(ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE) {
return triangle_attribute_float3(kg, sd, elem, offset, dx, dy);
}
#ifdef __HAIR__
- else if(sd->type & PRIMITIVE_ALL_CURVE) {
+ else if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) {
return curve_attribute_float3(kg, sd, elem, offset, dx, dy);
}
#endif
#ifdef __VOLUME__
- else if(sd->object != OBJECT_NONE && elem == ATTR_ELEMENT_VOXEL) {
+ else if(ccl_fetch(sd, object) != OBJECT_NONE && elem == ATTR_ELEMENT_VOXEL) {
return volume_attribute_float3(kg, sd, elem, offset, dx, dy);
}
#endif
@@ -108,9 +108,9 @@ ccl_device bool primitive_ptex(KernelGlobals *kg, ShaderData *sd, float2 *uv, in
ccl_device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd)
{
#ifdef __HAIR__
- if(sd->type & PRIMITIVE_ALL_CURVE)
+ if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE)
#ifdef __DPDU__
- return normalize(sd->dPdu);
+ return normalize(ccl_fetch(sd, dPdu));
#else
return make_float3(0.0f, 0.0f, 0.0f);
#endif
@@ -124,12 +124,12 @@ ccl_device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd)
float3 data = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f);
object_normal_transform(kg, sd, &data);
- return cross(sd->N, normalize(cross(data, sd->N)));
+ return cross(ccl_fetch(sd, N), normalize(cross(data, ccl_fetch(sd, N))));
}
else {
/* otherwise use surface derivatives */
#ifdef __DPDU__
- return normalize(sd->dPdu);
+ return normalize(ccl_fetch(sd, dPdu));
#else
return make_float3(0.0f, 0.0f, 0.0f);
#endif
@@ -144,16 +144,16 @@ ccl_device float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *sd)
float3 center;
#ifdef __HAIR__
- bool is_curve_primitive = sd->type & PRIMITIVE_ALL_CURVE;
+ bool is_curve_primitive = ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE;
if(is_curve_primitive) {
center = curve_motion_center_location(kg, sd);
- if(!(sd->flag & SD_TRANSFORM_APPLIED))
+ if(!(ccl_fetch(sd, flag) & SD_TRANSFORM_APPLIED))
object_position_transform(kg, sd, &center);
}
else
#endif
- center = sd->P;
+ center = ccl_fetch(sd, P);
float3 motion_pre = center, motion_post = center;
@@ -164,16 +164,16 @@ ccl_device float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *sd)
if(offset != ATTR_STD_NOT_FOUND) {
/* get motion info */
int numverts, numkeys;
- object_motion_info(kg, sd->object, NULL, &numverts, &numkeys);
+ object_motion_info(kg, ccl_fetch(sd, object), NULL, &numverts, &numkeys);
/* lookup attributes */
- int offset_next = (sd->type & PRIMITIVE_ALL_TRIANGLE)? offset + numverts: offset + numkeys;
+ int offset_next = (ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE)? offset + numverts: offset + numkeys;
motion_pre = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL);
motion_post = primitive_attribute_float3(kg, sd, elem, offset_next, NULL, NULL);
#ifdef __HAIR__
- if(is_curve_primitive && (sd->flag & SD_OBJECT_HAS_VERTEX_MOTION) == 0) {
+ if(is_curve_primitive && (ccl_fetch(sd, flag) & SD_OBJECT_HAS_VERTEX_MOTION) == 0) {
object_position_transform(kg, sd, &motion_pre);
object_position_transform(kg, sd, &motion_post);
}
@@ -184,17 +184,17 @@ ccl_device float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *sd)
* transformation was set match the world/object space of motion_pre/post */
Transform tfm;
- tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE);
+ tfm = object_fetch_vector_transform(kg, ccl_fetch(sd, object), OBJECT_VECTOR_MOTION_PRE);
motion_pre = transform_point(&tfm, motion_pre);
- tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST);
+ tfm = object_fetch_vector_transform(kg, ccl_fetch(sd, object), OBJECT_VECTOR_MOTION_POST);
motion_post = transform_point(&tfm, motion_post);
float3 motion_center;
/* camera motion, for perspective/orthographic motion.pre/post will be a
* world-to-raster matrix, for panorama it's world-to-camera */
- if (kernel_data.cam.type != CAMERA_PANORAMA) {
+ if(kernel_data.cam.type != CAMERA_PANORAMA) {
tfm = kernel_data.cam.worldtoraster;
motion_center = transform_perspective(&tfm, center);
diff --git a/intern/cycles/kernel/geom/geom_qbvh_shadow.h b/intern/cycles/kernel/geom/geom_qbvh_shadow.h
index 4233ff15c86..f79b2ed9f34 100644
--- a/intern/cycles/kernel/geom/geom_qbvh_shadow.h
+++ b/intern/cycles/kernel/geom/geom_qbvh_shadow.h
@@ -155,11 +155,11 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
++stackPtr;
kernel_assert(stackPtr < BVH_QSTACK_SIZE);
traversalStack[stackPtr].addr = c1;
- traversalStack[stackPtr].dist = c1;
+ traversalStack[stackPtr].dist = d1;
++stackPtr;
kernel_assert(stackPtr < BVH_QSTACK_SIZE);
traversalStack[stackPtr].addr = c0;
- traversalStack[stackPtr].dist = c0;
+ traversalStack[stackPtr].dist = d0;
/* Three children are hit, push all onto stack and sort 3
* stack items, continue with closest child.
@@ -206,7 +206,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* If node is leaf, fetch triangle list. */
if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_QNODE_SIZE+6);
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
#ifdef __VISIBILITY_FLAG__
if((__float_as_uint(leaf.z) & PATH_RAY_SHADOW) == 0) {
/* Pop. */
@@ -241,7 +241,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
switch(p_type) {
case PRIMITIVE_TRIANGLE: {
- hit = triangle_intersect(kg, &isect_precalc, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr);
+ hit = triangle_intersect(kg, &isect_precalc, isect_array, P, PATH_RAY_SHADOW, object, primAddr);
break;
}
#if BVH_FEATURE(BVH_MOTION)
@@ -279,7 +279,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
if(kernel_tex_fetch(__prim_type, isect_array->prim) & PRIMITIVE_ALL_TRIANGLE)
#endif
{
- shader = kernel_tex_fetch(__tri_shader, prim);
+ shader = kernel_tex_fetch(__tri_shader, prim);
}
#ifdef __HAIR__
else {
diff --git a/intern/cycles/kernel/geom/geom_qbvh_subsurface.h b/intern/cycles/kernel/geom/geom_qbvh_subsurface.h
index 62598115fa3..d85e1a4691e 100644
--- a/intern/cycles/kernel/geom/geom_qbvh_subsurface.h
+++ b/intern/cycles/kernel/geom/geom_qbvh_subsurface.h
@@ -202,7 +202,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* If node is leaf, fetch triangle list. */
if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_QNODE_SIZE+6);
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
int primAddr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
@@ -226,7 +226,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
if(tri_object != subsurface_object) {
continue;
}
- triangle_intersect_subsurface(kg, &isect_precalc, isect_array, P, dir, object, primAddr, isect_t, &num_hits, lcg_state, max_hits);
+ triangle_intersect_subsurface(kg, &isect_precalc, isect_array, P, object, primAddr, isect_t, &num_hits, lcg_state, max_hits);
}
break;
}
diff --git a/intern/cycles/kernel/geom/geom_qbvh_traversal.h b/intern/cycles/kernel/geom/geom_qbvh_traversal.h
index 99d2fb20837..cc20ebd8154 100644
--- a/intern/cycles/kernel/geom/geom_qbvh_traversal.h
+++ b/intern/cycles/kernel/geom/geom_qbvh_traversal.h
@@ -260,7 +260,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* If node is leaf, fetch triangle list. */
if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_QNODE_SIZE+6);
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
#ifdef __VISIBILITY_FLAG__
if(UNLIKELY((nodeDist > isect->t) || ((__float_as_uint(leaf.z) & visibility) == 0)))
@@ -296,7 +296,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
isect->num_traversal_steps++;
#endif
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- if(triangle_intersect(kg, &isect_precalc, isect, P, dir, visibility, object, primAddr)) {
+ if(triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr)) {
tfar = ssef(isect->t);
/* Shadow ray early termination. */
if(visibility == PATH_RAY_SHADOW_OPAQUE)
diff --git a/intern/cycles/kernel/geom/geom_qbvh_volume.h b/intern/cycles/kernel/geom/geom_qbvh_volume.h
index 2c396e99fc4..e3a5dcffee5 100644
--- a/intern/cycles/kernel/geom/geom_qbvh_volume.h
+++ b/intern/cycles/kernel/geom/geom_qbvh_volume.h
@@ -208,7 +208,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* If node is leaf, fetch triangle list. */
if(nodeAddr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_QNODE_SIZE+6);
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
int primAddr = __float_as_int(leaf.x);
#if BVH_FEATURE(BVH_INSTANCING)
@@ -234,7 +234,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
continue;
}
/* Intersect ray against primitive. */
- triangle_intersect(kg, &isect_precalc, isect, P, dir, visibility, object, primAddr);
+ triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr);
}
break;
}
diff --git a/intern/cycles/kernel/geom/geom_qbvh_volume_all.h b/intern/cycles/kernel/geom/geom_qbvh_volume_all.h
new file mode 100644
index 00000000000..d5131919944
--- /dev/null
+++ b/intern/cycles/kernel/geom/geom_qbvh_volume_all.h
@@ -0,0 +1,446 @@
+/*
+ * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
+ * and code copyright 2009-2012 Intel Corporation
+ *
+ * Modifications Copyright 2011-2014, 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.
+ */
+
+/* This is a template BVH traversal function for volumes, where
+ * various features can be enabled/disabled. This way we can compile optimized
+ * versions for each case without new features slowing things down.
+ *
+ * BVH_INSTANCING: object instancing
+ * BVH_HAIR: hair curve rendering
+ * BVH_MOTION: motion blur rendering
+ *
+ */
+
+ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
+ const Ray *ray,
+ Intersection *isect_array,
+ const uint max_hits)
+{
+ /* TODO(sergey):
+ * - Test if pushing distance on the stack helps.
+ * - Likely and unlikely for if() statements.
+ * - Test restrict attribute for pointers.
+ */
+
+ /* Traversal stack in CUDA thread-local memory. */
+ QBVHStackItem traversalStack[BVH_QSTACK_SIZE];
+ traversalStack[0].addr = ENTRYPOINT_SENTINEL;
+
+ /* Traversal variables in registers. */
+ int stackPtr = 0;
+ int nodeAddr = kernel_data.bvh.root;
+
+ /* Ray parameters in registers. */
+ const float tmax = ray->t;
+ float3 P = ray->P;
+ float3 dir = bvh_clamp_direction(ray->D);
+ float3 idir = bvh_inverse_direction(dir);
+ int object = OBJECT_NONE;
+ float isect_t = tmax;
+
+ const uint visibility = PATH_RAY_ALL_VISIBILITY;
+
+#if BVH_FEATURE(BVH_MOTION)
+ Transform ob_tfm;
+#endif
+
+#ifndef __KERNEL_SSE41__
+ if(!isfinite(P.x)) {
+ return false;
+ }
+#endif
+
+#if BVH_FEATURE(BVH_INSTANCING)
+ int num_hits_in_instance = 0;
+#endif
+
+ uint num_hits = 0;
+ isect_array->t = tmax;
+
+ ssef tnear(0.0f), tfar(isect_t);
+ sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z));
+
+#ifdef __KERNEL_AVX2__
+ float3 P_idir = P*idir;
+ sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
+#else
+ sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+#endif
+
+ /* Offsets to select the side that becomes the lower or upper bound. */
+ int near_x, near_y, near_z;
+ int far_x, far_y, far_z;
+
+ if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
+ if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
+ if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
+
+ IsectPrecalc isect_precalc;
+ triangle_intersect_precalc(dir, &isect_precalc);
+
+ /* Traversal loop. */
+ do {
+ do {
+ /* Traverse internal nodes. */
+ while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
+ ssef dist;
+ int traverseChild = qbvh_node_intersect(kg,
+ tnear,
+ tfar,
+#ifdef __KERNEL_AVX2__
+ P_idir4,
+#else
+ org,
+#endif
+ idir4,
+ near_x, near_y, near_z,
+ far_x, far_y, far_z,
+ nodeAddr,
+ &dist);
+
+ if(traverseChild != 0) {
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6);
+
+ /* One child is hit, continue with that child. */
+ int r = __bscf(traverseChild);
+ if(traverseChild == 0) {
+ nodeAddr = __float_as_int(cnodes[r]);
+ continue;
+ }
+
+ /* Two children are hit, push far child, and continue with
+ * closer child.
+ */
+ int c0 = __float_as_int(cnodes[r]);
+ float d0 = ((float*)&dist)[r];
+ r = __bscf(traverseChild);
+ int c1 = __float_as_int(cnodes[r]);
+ float d1 = ((float*)&dist)[r];
+ if(traverseChild == 0) {
+ if(d1 < d0) {
+ nodeAddr = c1;
+ ++stackPtr;
+ kernel_assert(stackPtr < BVH_QSTACK_SIZE);
+ traversalStack[stackPtr].addr = c0;
+ traversalStack[stackPtr].dist = d0;
+ continue;
+ }
+ else {
+ nodeAddr = c0;
+ ++stackPtr;
+ kernel_assert(stackPtr < BVH_QSTACK_SIZE);
+ traversalStack[stackPtr].addr = c1;
+ traversalStack[stackPtr].dist = d1;
+ continue;
+ }
+ }
+
+ /* Here starts the slow path for 3 or 4 hit children. We push
+ * all nodes onto the stack to sort them there.
+ */
+ ++stackPtr;
+ kernel_assert(stackPtr < BVH_QSTACK_SIZE);
+ traversalStack[stackPtr].addr = c1;
+ traversalStack[stackPtr].dist = d1;
+ ++stackPtr;
+ kernel_assert(stackPtr < BVH_QSTACK_SIZE);
+ traversalStack[stackPtr].addr = c0;
+ traversalStack[stackPtr].dist = d0;
+
+ /* Three children are hit, push all onto stack and sort 3
+ * stack items, continue with closest child.
+ */
+ r = __bscf(traverseChild);
+ int c2 = __float_as_int(cnodes[r]);
+ float d2 = ((float*)&dist)[r];
+ if(traverseChild == 0) {
+ ++stackPtr;
+ kernel_assert(stackPtr < BVH_QSTACK_SIZE);
+ traversalStack[stackPtr].addr = c2;
+ traversalStack[stackPtr].dist = d2;
+ qbvh_stack_sort(&traversalStack[stackPtr],
+ &traversalStack[stackPtr - 1],
+ &traversalStack[stackPtr - 2]);
+ nodeAddr = traversalStack[stackPtr].addr;
+ --stackPtr;
+ continue;
+ }
+
+ /* Four children are hit, push all onto stack and sort 4
+ * stack items, continue with closest child.
+ */
+ r = __bscf(traverseChild);
+ int c3 = __float_as_int(cnodes[r]);
+ float d3 = ((float*)&dist)[r];
+ ++stackPtr;
+ kernel_assert(stackPtr < BVH_QSTACK_SIZE);
+ traversalStack[stackPtr].addr = c3;
+ traversalStack[stackPtr].dist = d3;
+ ++stackPtr;
+ kernel_assert(stackPtr < BVH_QSTACK_SIZE);
+ traversalStack[stackPtr].addr = c2;
+ traversalStack[stackPtr].dist = d2;
+ qbvh_stack_sort(&traversalStack[stackPtr],
+ &traversalStack[stackPtr - 1],
+ &traversalStack[stackPtr - 2],
+ &traversalStack[stackPtr - 3]);
+ }
+
+ nodeAddr = traversalStack[stackPtr].addr;
+ --stackPtr;
+ }
+
+ /* If node is leaf, fetch triangle list. */
+ if(nodeAddr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
+ int primAddr = __float_as_int(leaf.x);
+
+#if BVH_FEATURE(BVH_INSTANCING)
+ if(primAddr >= 0) {
+#endif
+ int primAddr2 = __float_as_int(leaf.y);
+ const uint type = __float_as_int(leaf.w);
+ const uint p_type = type & PRIMITIVE_ALL;
+ bool hit;
+
+ /* Pop. */
+ nodeAddr = traversalStack[stackPtr].addr;
+ --stackPtr;
+
+ /* Primitive intersection. */
+ switch(p_type) {
+ case PRIMITIVE_TRIANGLE: {
+ for(; primAddr < primAddr2; primAddr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ /* Only primitives from volume object. */
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ int object_flag = kernel_tex_fetch(__object_flag, tri_object);
+ if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
+ continue;
+ }
+ /* Intersect ray against primitive. */
+ hit = triangle_intersect(kg, &isect_precalc, isect_array, P, visibility, object, primAddr);
+ if(hit) {
+ /* Move on to next entry in intersections array. */
+ isect_array++;
+ num_hits++;
+#if BVH_FEATURE(BVH_INSTANCING)
+ num_hits_in_instance++;
+#endif
+ isect_array->t = isect_t;
+ if(num_hits == max_hits) {
+#if BVH_FEATURE(BVH_INSTANCING)
+#if BVH_FEATURE(BVH_MOTION)
+ float t_fac = len(transform_direction(&ob_tfm, 1.0f/idir));
+#else
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+ float t_fac = len(transform_direction(&tfm, 1.0f/idir));
+#endif
+ for(int i = 0; i < num_hits_in_instance; i++) {
+ (isect_array-i-1)->t *= t_fac;
+ }
+#endif /* BVH_FEATURE(BVH_INSTANCING) */
+ return num_hits;
+ }
+ }
+ }
+ break;
+ }
+#if BVH_FEATURE(BVH_MOTION)
+ case PRIMITIVE_MOTION_TRIANGLE: {
+ for(; primAddr < primAddr2; primAddr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ /* Only primitives from volume object. */
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ int object_flag = kernel_tex_fetch(__object_flag, tri_object);
+ if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
+ continue;
+ }
+ /* Intersect ray against primitive. */
+ hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, visibility, object, primAddr);
+ if(hit) {
+ /* Move on to next entry in intersections array. */
+ isect_array++;
+ num_hits++;
+#if BVH_FEATURE(BVH_INSTANCING)
+ num_hits_in_instance++;
+#endif
+ isect_array->t = isect_t;
+ if(num_hits == max_hits) {
+#if BVH_FEATURE(BVH_INSTANCING)
+# if BVH_FEATURE(BVH_MOTION)
+ float t_fac = len(transform_direction(&ob_tfm, 1.0f/idir));
+# else
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+ float t_fac = len(transform_direction(&tfm, 1.0f/idir));
+#endif
+ for(int i = 0; i < num_hits_in_instance; i++) {
+ (isect_array-i-1)->t *= t_fac;
+ }
+#endif /* BVH_FEATURE(BVH_INSTANCING) */
+ return num_hits;
+ }
+ }
+ }
+ break;
+ }
+#endif
+#if BVH_FEATURE(BVH_HAIR)
+ case PRIMITIVE_CURVE:
+ case PRIMITIVE_MOTION_CURVE: {
+ for(; primAddr < primAddr2; primAddr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ /* Only primitives from volume object. */
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ int object_flag = kernel_tex_fetch(__object_flag, tri_object);
+ if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
+ continue;
+ }
+ /* Intersect ray against primitive. */
+ if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
+ hit = bvh_cardinal_curve_intersect(kg, isect_array, P, dir, visibility, object, primAddr, ray->time, type, NULL, 0, 0);
+ else
+ hit = bvh_curve_intersect(kg, isect_array, P, dir, visibility, object, primAddr, ray->time, type, NULL, 0, 0);
+ if(hit) {
+ /* Move on to next entry in intersections array. */
+ isect_array++;
+ num_hits++;
+#if BVH_FEATURE(BVH_INSTANCING)
+ num_hits_in_instance++;
+#endif
+ isect_array->t = isect_t;
+ if(num_hits == max_hits) {
+#if BVH_FEATURE(BVH_INSTANCING)
+# if BVH_FEATURE(BVH_MOTION)
+ float t_fac = len(transform_direction(&ob_tfm, 1.0f/idir));
+# else
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+ float t_fac = len(transform_direction(&tfm, 1.0f/idir));
+#endif
+ for(int i = 0; i < num_hits_in_instance; i++) {
+ (isect_array-i-1)->t *= t_fac;
+ }
+#endif /* BVH_FEATURE(BVH_INSTANCING) */
+ return num_hits;
+ }
+ }
+ }
+ break;
+ }
+#endif
+ }
+ }
+#if BVH_FEATURE(BVH_INSTANCING)
+ else {
+ /* Instance push. */
+ object = kernel_tex_fetch(__prim_object, -primAddr-1);
+ int object_flag = kernel_tex_fetch(__object_flag, object);
+
+ if(object_flag & SD_OBJECT_HAS_VOLUME) {
+
+#if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_tfm);
+#else
+ bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect_t);
+#endif
+
+ if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
+ if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
+ if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
+ tfar = ssef(isect_t);
+ idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
+#ifdef __KERNEL_AVX2__
+ P_idir = P*idir;
+ P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
+#else
+ org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+#endif
+ triangle_intersect_precalc(dir, &isect_precalc);
+ num_hits_in_instance = 0;
+ isect_array->t = isect_t;
+
+ ++stackPtr;
+ kernel_assert(stackPtr < BVH_QSTACK_SIZE);
+ traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL;
+
+ nodeAddr = kernel_tex_fetch(__object_node, object);
+ }
+ else {
+ /* Pop. */
+ object = OBJECT_NONE;
+ nodeAddr = traversalStack[stackPtr].addr;
+ --stackPtr;
+ }
+ }
+ }
+#endif /* FEATURE(BVH_INSTANCING) */
+ } while(nodeAddr != ENTRYPOINT_SENTINEL);
+
+#if BVH_FEATURE(BVH_INSTANCING)
+ if(stackPtr >= 0) {
+ kernel_assert(object != OBJECT_NONE);
+
+ /* Instance pop. */
+ if(num_hits_in_instance) {
+ float t_fac;
+#if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac, &ob_tfm);
+#else
+ bvh_instance_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac);
+#endif
+ triangle_intersect_precalc(dir, &isect_precalc);
+ /* Scale isect->t to adjust for instancing. */
+ for(int i = 0; i < num_hits_in_instance; i++) {
+ (isect_array-i-1)->t *= t_fac;
+ }
+ }
+ else {
+ float ignore_t = FLT_MAX;
+#if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &ignore_t, &ob_tfm);
+#else
+ bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &ignore_t);
+#endif
+ triangle_intersect_precalc(dir, &isect_precalc);
+ }
+
+ if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
+ if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
+ if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
+ tfar = ssef(isect_t);
+ idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
+#ifdef __KERNEL_AVX2__
+ P_idir = P*idir;
+ P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
+#else
+ org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
+#endif
+ triangle_intersect_precalc(dir, &isect_precalc);
+ isect_t = tmax;
+ isect_array->t = isect_t;
+
+ object = OBJECT_NONE;
+ nodeAddr = traversalStack[stackPtr].addr;
+ --stackPtr;
+ }
+#endif /* FEATURE(BVH_INSTANCING) */
+ } while(nodeAddr != ENTRYPOINT_SENTINEL);
+
+ return num_hits;
+}
diff --git a/intern/cycles/kernel/geom/geom_triangle.h b/intern/cycles/kernel/geom/geom_triangle.h
index dd3928682e3..995dfac5b09 100644
--- a/intern/cycles/kernel/geom/geom_triangle.h
+++ b/intern/cycles/kernel/geom/geom_triangle.h
@@ -27,14 +27,14 @@ CCL_NAMESPACE_BEGIN
ccl_device_inline float3 triangle_normal(KernelGlobals *kg, ShaderData *sd)
{
/* load triangle vertices */
- float4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
+ float4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
float3 v0 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
float3 v1 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
float3 v2 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
/* return normal */
- if(sd->flag & SD_NEGATIVE_SCALE_APPLIED)
+ if(ccl_fetch(sd, flag) & SD_NEGATIVE_SCALE_APPLIED)
return normalize(cross(v2 - v0, v1 - v0));
else
return normalize(cross(v1 - v0, v2 - v0));
@@ -94,7 +94,7 @@ ccl_device_inline float3 triangle_smooth_normal(KernelGlobals *kg, int prim, flo
/* Ray differentials on triangle */
-ccl_device_inline void triangle_dPdudv(KernelGlobals *kg, int prim, float3 *dPdu, float3 *dPdv)
+ccl_device_inline void triangle_dPdudv(KernelGlobals *kg, int prim, ccl_addr_space float3 *dPdu, ccl_addr_space float3 *dPdv)
{
/* fetch triangle vertex coordinates */
float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
@@ -116,34 +116,34 @@ ccl_device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *s
if(dx) *dx = 0.0f;
if(dy) *dy = 0.0f;
- return kernel_tex_fetch(__attributes_float, offset + sd->prim);
+ return kernel_tex_fetch(__attributes_float, offset + ccl_fetch(sd, prim));
}
else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) {
- float4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
+ float4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
float f0 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.x));
float f1 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.y));
float f2 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.z));
#ifdef __RAY_DIFFERENTIALS__
- if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
- if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
+ if(dx) *dx = ccl_fetch(sd, du).dx*f0 + ccl_fetch(sd, dv).dx*f1 - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*f2;
+ if(dy) *dy = ccl_fetch(sd, du).dy*f0 + ccl_fetch(sd, dv).dy*f1 - (ccl_fetch(sd, du).dy + ccl_fetch(sd, dv).dy)*f2;
#endif
- return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
+ return ccl_fetch(sd, u)*f0 + ccl_fetch(sd, v)*f1 + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*f2;
}
else if(elem == ATTR_ELEMENT_CORNER) {
- int tri = offset + sd->prim*3;
+ int tri = offset + ccl_fetch(sd, prim)*3;
float f0 = kernel_tex_fetch(__attributes_float, tri + 0);
float f1 = kernel_tex_fetch(__attributes_float, tri + 1);
float f2 = kernel_tex_fetch(__attributes_float, tri + 2);
#ifdef __RAY_DIFFERENTIALS__
- if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
- if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
+ if(dx) *dx = ccl_fetch(sd, du).dx*f0 + ccl_fetch(sd, dv).dx*f1 - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*f2;
+ if(dy) *dy = ccl_fetch(sd, du).dy*f0 + ccl_fetch(sd, dv).dy*f1 - (ccl_fetch(sd, du).dy + ccl_fetch(sd, dv).dy)*f2;
#endif
- return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
+ return ccl_fetch(sd, u)*f0 + ccl_fetch(sd, v)*f1 + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*f2;
}
else {
if(dx) *dx = 0.0f;
@@ -159,24 +159,24 @@ ccl_device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
- return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + sd->prim));
+ return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + ccl_fetch(sd, prim)));
}
else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) {
- float4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
+ float4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x)));
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y)));
float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z)));
#ifdef __RAY_DIFFERENTIALS__
- if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
- if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
+ if(dx) *dx = ccl_fetch(sd, du).dx*f0 + ccl_fetch(sd, dv).dx*f1 - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*f2;
+ if(dy) *dy = ccl_fetch(sd, du).dy*f0 + ccl_fetch(sd, dv).dy*f1 - (ccl_fetch(sd, du).dy + ccl_fetch(sd, dv).dy)*f2;
#endif
- return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
+ return ccl_fetch(sd, u)*f0 + ccl_fetch(sd, v)*f1 + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*f2;
}
else if(elem == ATTR_ELEMENT_CORNER || elem == ATTR_ELEMENT_CORNER_BYTE) {
- int tri = offset + sd->prim*3;
+ int tri = offset + ccl_fetch(sd, prim)*3;
float3 f0, f1, f2;
if(elem == ATTR_ELEMENT_CORNER) {
@@ -191,11 +191,11 @@ ccl_device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData
}
#ifdef __RAY_DIFFERENTIALS__
- if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
- if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
+ if(dx) *dx = ccl_fetch(sd, du).dx*f0 + ccl_fetch(sd, dv).dx*f1 - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*f2;
+ if(dy) *dy = ccl_fetch(sd, du).dy*f0 + ccl_fetch(sd, dv).dy*f1 - (ccl_fetch(sd, du).dy + ccl_fetch(sd, dv).dy)*f2;
#endif
- return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
+ return ccl_fetch(sd, u)*f0 + ccl_fetch(sd, v)*f1 + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*f2;
}
else {
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h
index 06917dc16d8..d6e4abc8267 100644
--- a/intern/cycles/kernel/geom/geom_triangle_intersect.h
+++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-/* Triangle/Ray intersections .
+/* Triangle/Ray intersections.
*
* For BVH ray intersection we use a precomputed triangle storage to accelerate
* intersection at the cost of more memory usage.
@@ -50,7 +50,7 @@ typedef struct IsectPrecalc {
} IsectPrecalc;
/* Workaround for CUDA toolkit 6.5.16. */
-#if defined(__KERNEL_CPU__) || !defined(__KERNEL_CUDA_EXPERIMENTAL__) || __CUDA_ARCH__ < 500
+#if defined(__KERNEL_CPU__) || !defined(__KERNEL_EXPERIMENTAL__) || __CUDA_ARCH__ < 500
# if (defined(i386) || defined(_M_IX86))
ccl_device_noinline
# else
@@ -60,7 +60,7 @@ ccl_device_inline
ccl_device_noinline
#endif
void triangle_intersect_precalc(float3 dir,
- IsectPrecalc *isect_precalc)
+ IsectPrecalc *isect_precalc)
{
/* Calculate dimension where the ray direction is maximal. */
int kz = util_max_axis(make_float3(fabsf(dir.x),
@@ -77,10 +77,10 @@ void triangle_intersect_precalc(float3 dir,
}
/* Calculate the shear constants. */
- float inf_dir_z = 1.0f / IDX(dir, kz);
- isect_precalc->Sx = IDX(dir, kx) * inf_dir_z;
- isect_precalc->Sy = IDX(dir, ky) * inf_dir_z;
- isect_precalc->Sz = inf_dir_z;
+ float inv_dir_z = 1.0f / IDX(dir, kz);
+ isect_precalc->Sx = IDX(dir, kx) * inv_dir_z;
+ isect_precalc->Sy = IDX(dir, ky) * inv_dir_z;
+ isect_precalc->Sz = inv_dir_z;
/* Store the dimensions. */
isect_precalc->kx = kx;
@@ -98,7 +98,6 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
const IsectPrecalc *isect_precalc,
Intersection *isect,
float3 P,
- float3 dir,
uint visibility,
int object,
int triAddr)
@@ -111,14 +110,22 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
const float Sz = isect_precalc->Sz;
/* Calculate vertices relative to ray origin. */
- float3 tri[3];
- tri[0] = float4_to_float3(kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0));
- tri[1] = float4_to_float3(kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1));
- tri[2] = float4_to_float3(kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2));
-
- const float3 A = tri[0] - P;
- const float3 B = tri[1] - P;
- const float3 C = tri[2] - P;
+ float4 tri_a, tri_b, tri_c;
+ if (kernel_data.bvh.use_tri_storage) {
+ tri_a = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0);
+ tri_b = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1);
+ tri_c = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
+ }
+ else {
+ const int prim = kernel_tex_fetch(__prim_index, triAddr);
+ const float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ tri_a = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x));
+ tri_b = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y));
+ tri_c = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z));
+ }
+ const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z);
+ const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z);
+ const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z);
const float A_kx = IDX(A, kx), A_ky = IDX(A, ky), A_kz = IDX(A, kz);
const float B_kx = IDX(B, kx), B_ky = IDX(B, ky), B_kz = IDX(B, kz);
@@ -154,15 +161,10 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
* the hit distance.
*/
const float T = (U * A_kz + V * B_kz + W * C_kz) * Sz;
-
- /* Perform "near clipping". */
- const float abs_T = xor_signmast(T, sign_mask);
- if(abs_T < 0.0f) {
- return false;
- }
- /* Perform "far clipping". */
- const float abs_det = xor_signmast(det, sign_mask);
- if(abs_T > isect->t * abs_det) {
+ const float sign_T = xor_signmast(T, sign_mask);
+ if((sign_T < 0.0f) ||
+ (sign_T > isect->t * xor_signmast(det, sign_mask)))
+ {
return false;
}
@@ -174,37 +176,12 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
{
/* Normalize U, V, W, and T. */
const float inv_det = 1.0f / det;
- const float t = T * inv_det;
-
-#ifdef __INTERSECTION_REFINE__
- /* TODO(sergey): When intersection refine is enabled ray is being
- * pushed by quite small epsilon from the surface, which causes
- * numerical issues of watertight Woop intersection check with
- * huge triangles.
- *
- * Here we're working this around by checking distance in Pleucker
- * coordinates if intersection is suspiciously close to the point
- * in order to eliminate self-shadowing.
- *
- * Ideally we need to solve this in Woop intersection code but
- * it's quite tricky.
- */
- if(UNLIKELY(abs_det > 100000.0f && t < 1e-3f)) {
- const float3 Ng = cross(A - B, C - A);
- const float pleucker_den = dot(Ng, dir);
- const float pleucker_T = dot(A, Ng);
- if(UNLIKELY(pleucker_T * pleucker_den < 0.0f)) {
- return false;
- }
- }
-#endif
-
isect->prim = triAddr;
isect->object = object;
isect->type = PRIMITIVE_TRIANGLE;
isect->u = U * inv_det;
isect->v = V * inv_det;
- isect->t = t;
+ isect->t = T * inv_det;
return true;
}
return false;
@@ -221,7 +198,6 @@ ccl_device_inline void triangle_intersect_subsurface(
const IsectPrecalc *isect_precalc,
Intersection *isect_array,
float3 P,
- float3 dir,
int object,
int triAddr,
float tmax,
@@ -237,14 +213,22 @@ ccl_device_inline void triangle_intersect_subsurface(
const float Sz = isect_precalc->Sz;
/* Calculate vertices relative to ray origin. */
- float3 tri[3];
- tri[0] = float4_to_float3(kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0));
- tri[1] = float4_to_float3(kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1));
- tri[2] = float4_to_float3(kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2));
-
- const float3 A = tri[0] - P;
- const float3 B = tri[1] - P;
- const float3 C = tri[2] - P;
+ float4 tri_a, tri_b, tri_c;
+ if (kernel_data.bvh.use_tri_storage) {
+ tri_a = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0);
+ tri_b = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1);
+ tri_c = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
+ }
+ else {
+ const int prim = kernel_tex_fetch(__prim_index, triAddr);
+ const float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ tri_a = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x));
+ tri_b = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y));
+ tri_c = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z));
+ }
+ const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z);
+ const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z);
+ const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z);
const float A_kx = IDX(A, kx), A_ky = IDX(A, ky), A_kz = IDX(A, kz);
const float B_kx = IDX(B, kx), B_ky = IDX(B, ky), B_kz = IDX(B, kz);
@@ -279,13 +263,10 @@ ccl_device_inline void triangle_intersect_subsurface(
/* Calculate scaled z−coordinates of vertices and use them to calculate
* the hit distance.
*/
- const float Az = Sz * A_kz;
- const float Bz = Sz * B_kz;
- const float Cz = Sz * C_kz;
- const float T = U * Az + V * Bz + W * Cz;
-
- if ((xor_signmast(T, sign_mask) < 0.0f) ||
- (xor_signmast(T, sign_mask) > tmax * xor_signmast(det, sign_mask)))
+ const float T = (U * A_kz + V * B_kz + W * C_kz) * Sz;
+ const float sign_T = xor_signmast(T, sign_mask);
+ if((sign_T < 0.0f) ||
+ (sign_T > tmax * xor_signmast(det, sign_mask)))
{
return;
}
@@ -345,7 +326,7 @@ ccl_device_inline float3 triangle_refine(KernelGlobals *kg,
return P;
}
#ifdef __OBJECT_MOTION__
- Transform tfm = sd->ob_itfm;
+ Transform tfm = ccl_fetch(sd, ob_itfm);
#else
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
#endif
@@ -357,14 +338,22 @@ ccl_device_inline float3 triangle_refine(KernelGlobals *kg,
P = P + D*t;
- float3 tri[3];
- tri[0] = float4_to_float3(kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0));
- tri[1] = float4_to_float3(kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+1));
- tri[2] = float4_to_float3(kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+2));
-
- float3 edge1 = tri[0] - tri[2];
- float3 edge2 = tri[1] - tri[2];
- float3 tvec = P - tri[2];
+ float4 tri_a, tri_b, tri_c;
+ if (kernel_data.bvh.use_tri_storage) {
+ tri_a = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0);
+ tri_b = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+1);
+ tri_c = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+2);
+ }
+ else {
+ const int prim = kernel_tex_fetch(__prim_index, isect->prim);
+ const float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ tri_a = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x));
+ tri_b = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y));
+ tri_c = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z));
+ }
+ float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z);
+ float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z);
+ 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);
@@ -373,7 +362,7 @@ ccl_device_inline float3 triangle_refine(KernelGlobals *kg,
if(isect->object != OBJECT_NONE) {
#ifdef __OBJECT_MOTION__
- Transform tfm = sd->ob_tfm;
+ Transform tfm = ccl_fetch(sd, ob_tfm);
#else
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
#endif
@@ -402,7 +391,7 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg,
#ifdef __INTERSECTION_REFINE__
if(isect->object != OBJECT_NONE) {
#ifdef __OBJECT_MOTION__
- Transform tfm = sd->ob_itfm;
+ Transform tfm = ccl_fetch(sd, ob_itfm);
#else
Transform tfm = object_fetch_transform(kg,
isect->object,
@@ -416,14 +405,22 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg,
P = P + D*t;
- float3 tri[3];
- tri[0] = float4_to_float3(kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0));
- tri[1] = float4_to_float3(kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+1));
- tri[2] = float4_to_float3(kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+2));
-
- float3 edge1 = tri[0] - tri[2];
- float3 edge2 = tri[1] - tri[2];
- float3 tvec = P - tri[2];
+ float4 tri_a, tri_b, tri_c;
+ if (kernel_data.bvh.use_tri_storage) {
+ tri_a = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0);
+ tri_b = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+1);
+ tri_c = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+2);
+ }
+ else {
+ const int prim = kernel_tex_fetch(__prim_index, isect->prim);
+ const float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ tri_a = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x));
+ tri_b = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y));
+ tri_c = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z));
+ }
+ float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z);
+ float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z);
+ 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);
@@ -432,7 +429,7 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg,
if(isect->object != OBJECT_NONE) {
#ifdef __OBJECT_MOTION__
- Transform tfm = sd->ob_tfm;
+ Transform tfm = ccl_fetch(sd, ob_tfm);
#else
Transform tfm = object_fetch_transform(kg,
isect->object,
diff --git a/intern/cycles/kernel/geom/geom_volume.h b/intern/cycles/kernel/geom/geom_volume.h
index c33509fbf4f..24430dd223b 100644
--- a/intern/cycles/kernel/geom/geom_volume.h
+++ b/intern/cycles/kernel/geom/geom_volume.h
@@ -53,17 +53,21 @@ ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd,
float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
#else
float4 r;
+ int slot = id >> 1;
if(sd->flag & SD_VOLUME_CUBIC)
- r = kernel_tex_image_interp_3d_ex(id, P.x, P.y, P.z, INTERPOLATION_CUBIC);
+ r = kernel_tex_image_interp_3d_ex(slot, P.x, P.y, P.z, INTERPOLATION_CUBIC);
else
- r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z);
+ r = kernel_tex_image_interp_3d(slot, P.x, P.y, P.z);
#endif
if(dx) *dx = 0.0f;
- if(dx) *dy = 0.0f;
+ if(dy) *dy = 0.0f;
/* todo: support float textures to lower memory usage for single floats */
- return average(float4_to_float3(r));
+ if(id & 1)
+ return r.w;
+ else
+ return average(float4_to_float3(r));
}
ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int id, float3 *dx, float3 *dy)
@@ -73,16 +77,20 @@ ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *s
float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
#else
float4 r;
+ int slot = id >> 1;
if(sd->flag & SD_VOLUME_CUBIC)
- r = kernel_tex_image_interp_3d_ex(id, P.x, P.y, P.z, INTERPOLATION_CUBIC);
+ r = kernel_tex_image_interp_3d_ex(slot, P.x, P.y, P.z, INTERPOLATION_CUBIC);
else
- r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z);
+ r = kernel_tex_image_interp_3d(slot, P.x, P.y, P.z);
#endif
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
- return float4_to_float3(r);
+ if(id & 1)
+ return make_float3(r.w, r.w, r.w);
+ else
+ return float4_to_float3(r);
}
#endif
diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h
index 369c615eade..257728b6244 100644
--- a/intern/cycles/kernel/kernel_accumulate.h
+++ b/intern/cycles/kernel/kernel_accumulate.h
@@ -176,7 +176,7 @@ ccl_device_inline void path_radiance_init(PathRadiance *L, int use_light_pass)
#endif
}
-ccl_device_inline void path_radiance_bsdf_bounce(PathRadiance *L, float3 *throughput,
+ccl_device_inline void path_radiance_bsdf_bounce(PathRadiance *L, ccl_addr_space float3 *throughput,
BsdfEval *bsdf_eval, float bsdf_pdf, int bounce, int bsdf_label)
{
float inverse_pdf = 1.0f/bsdf_pdf;
diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h
index 20d7a143c67..2fca83c615f 100644
--- a/intern/cycles/kernel/kernel_bake.h
+++ b/intern/cycles/kernel/kernel_bake.h
@@ -57,7 +57,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
/* sample subsurface scattering */
if((is_combined || is_sss_sample) && (sd->flag & SD_BSSRDF)) {
/* when mixing BSSRDF and BSDF closures we should skip BSDF lighting if scattering was successful */
- if (kernel_path_subsurface_scatter(kg, sd, &L_sample, &state, &rng, &ray, &throughput))
+ if(kernel_path_subsurface_scatter(kg, sd, &L_sample, &state, &rng, &ray, &throughput))
is_sss_sample = true;
}
#endif
@@ -208,7 +208,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
filter_x = filter_y = 0.5f;
}
else {
- path_rng_2D(kg, &rng, sample, num_samples, PRNG_FILTER_U, &filter_x, &filter_x);
+ path_rng_2D(kg, &rng, sample, num_samples, PRNG_FILTER_U, &filter_x, &filter_y);
}
/* subpixel u/v offset */
@@ -259,7 +259,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
/* data passes */
case SHADER_EVAL_NORMAL:
{
- if ((sd.flag & SD_HAS_BUMP)) {
+ if((sd.flag & SD_HAS_BUMP)) {
shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
}
diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h
index ded222e20ff..3ce5134181a 100644
--- a/intern/cycles/kernel/kernel_camera.h
+++ b/intern/cycles/kernel/kernel_camera.h
@@ -16,17 +16,6 @@
CCL_NAMESPACE_BEGIN
-/* Workaround for explicit conversion from constant to private memory
- * pointer when using OpenCL.
- *
- * TODO(sergey): Find a real solution for this.
- */
-#ifdef __KERNEL_OPENCL__
-# define __motion_as_decoupled_const_ptr(motion) ((motion))
-#else
-# define __motion_as_decoupled_const_ptr(motion) ((const DecompMotionTransform*)(motion))
-#endif
-
/* Perspective Camera */
ccl_device float2 camera_sample_aperture(KernelGlobals *kg, float u, float v)
@@ -50,7 +39,7 @@ ccl_device float2 camera_sample_aperture(KernelGlobals *kg, float u, float v)
return bokeh;
}
-ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, Ray *ray)
+ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, ccl_addr_space Ray *ray)
{
/* create ray form raster position */
Transform rastertocamera = kernel_data.cam.rastertocamera;
@@ -80,9 +69,16 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
#ifdef __CAMERA_MOTION__
if(kernel_data.cam.have_motion) {
+#ifdef __KERNEL_OPENCL__
+ const MotionTransform tfm = kernel_data.cam.motion;
transform_motion_interpolate(&cameratoworld,
- __motion_as_decoupled_const_ptr(&kernel_data.cam.motion),
+ ((const DecompMotionTransform*)&tfm),
ray->time);
+#else
+ transform_motion_interpolate(&cameratoworld,
+ ((const DecompMotionTransform*)&kernel_data.cam.motion),
+ ray->time);
+#endif
}
#endif
@@ -112,8 +108,7 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
}
/* Orthographic Camera */
-
-ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, Ray *ray)
+ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, ccl_addr_space Ray *ray)
{
/* create ray form raster position */
Transform rastertocamera = kernel_data.cam.rastertocamera;
@@ -144,9 +139,16 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl
#ifdef __CAMERA_MOTION__
if(kernel_data.cam.have_motion) {
+#ifdef __KERNEL_OPENCL__
+ const MotionTransform tfm = kernel_data.cam.motion;
transform_motion_interpolate(&cameratoworld,
- __motion_as_decoupled_const_ptr(&kernel_data.cam.motion),
+ (const DecompMotionTransform*)&tfm,
ray->time);
+#else
+ transform_motion_interpolate(&cameratoworld,
+ (const DecompMotionTransform*)&kernel_data.cam.motion,
+ ray->time);
+#endif
}
#endif
@@ -172,7 +174,7 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl
/* Panorama Camera */
-ccl_device void camera_sample_panorama(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, Ray *ray)
+ccl_device void camera_sample_panorama(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, ccl_addr_space Ray *ray)
{
Transform rastertocamera = kernel_data.cam.rastertocamera;
float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
@@ -220,10 +222,18 @@ ccl_device void camera_sample_panorama(KernelGlobals *kg, float raster_x, float
Transform cameratoworld = kernel_data.cam.cameratoworld;
#ifdef __CAMERA_MOTION__
- if(kernel_data.cam.have_motion)
+ if(kernel_data.cam.have_motion) {
+#ifdef __KERNEL_OPENCL__
+ const MotionTransform tfm = kernel_data.cam.motion;
transform_motion_interpolate(&cameratoworld,
- __motion_as_decoupled_const_ptr(&kernel_data.cam.motion),
+ (const DecompMotionTransform*)&tfm,
ray->time);
+#else
+ transform_motion_interpolate(&cameratoworld,
+ (const DecompMotionTransform*)&kernel_data.cam.motion,
+ ray->time);
+#endif
+ }
#endif
ray->P = transform_point(&cameratoworld, ray->P);
@@ -245,7 +255,7 @@ ccl_device void camera_sample_panorama(KernelGlobals *kg, float raster_x, float
/* Common */
ccl_device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, float filter_v,
- float lens_u, float lens_v, float time, Ray *ray)
+ float lens_u, float lens_v, float time, ccl_addr_space Ray *ray)
{
/* pixel filter */
int filter_table_offset = kernel_data.film.filter_table_offset;
@@ -308,7 +318,7 @@ ccl_device_inline float3 camera_world_to_ndc(KernelGlobals *kg, ShaderData *sd,
{
if(kernel_data.cam.type != CAMERA_PANORAMA) {
/* perspective / ortho */
- if(sd->object == PRIM_NONE && kernel_data.cam.type == CAMERA_PERSPECTIVE)
+ if(ccl_fetch(sd, object) == PRIM_NONE && kernel_data.cam.type == CAMERA_PERSPECTIVE)
P += camera_position(kg);
Transform tfm = kernel_data.cam.worldtondc;
@@ -318,7 +328,7 @@ ccl_device_inline float3 camera_world_to_ndc(KernelGlobals *kg, ShaderData *sd,
/* panorama */
Transform tfm = kernel_data.cam.worldtocamera;
- if(sd->object != OBJECT_NONE)
+ if(ccl_fetch(sd, object) != OBJECT_NONE)
P = normalize(transform_point(&tfm, P));
else
P = normalize(transform_direction(&tfm, P));
@@ -329,7 +339,4 @@ ccl_device_inline float3 camera_world_to_ndc(KernelGlobals *kg, ShaderData *sd,
}
}
-#undef __motion_as_decoupled_const_ptr
-
CCL_NAMESPACE_END
-
diff --git a/intern/cycles/kernel/kernel_compat_cpu.h b/intern/cycles/kernel/kernel_compat_cpu.h
index 200667a0911..7a5f70ff3da 100644
--- a/intern/cycles/kernel/kernel_compat_cpu.h
+++ b/intern/cycles/kernel/kernel_compat_cpu.h
@@ -26,12 +26,22 @@
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
+/* Selective nodes compilation. */
+#ifndef __NODES_MAX_GROUP__
+# define __NODES_MAX_GROUP__ NODE_GROUP_LEVEL_MAX
+#endif
+#ifndef __NODES_FEATURES__
+# define __NODES_FEATURES__ NODE_FEATURE_ALL
+#endif
+
#include "util_debug.h"
#include "util_math.h"
#include "util_simd.h"
#include "util_half.h"
#include "util_types.h"
+#define ccl_addr_space
+
/* On x86_64, versions of glibc < 2.16 have an issue where expf is
* much slower than the double version. This was fixed in glibc 2.16.
*/
diff --git a/intern/cycles/kernel/kernel_compat_cuda.h b/intern/cycles/kernel/kernel_compat_cuda.h
index 904736c190c..9fdd3abfec3 100644
--- a/intern/cycles/kernel/kernel_compat_cuda.h
+++ b/intern/cycles/kernel/kernel_compat_cuda.h
@@ -22,6 +22,14 @@
#define CCL_NAMESPACE_BEGIN
#define CCL_NAMESPACE_END
+/* Selective nodes compilation. */
+#ifndef __NODES_MAX_GROUP__
+# define __NODES_MAX_GROUP__ NODE_GROUP_LEVEL_MAX
+#endif
+#ifndef __NODES_FEATURES__
+# define __NODES_FEATURES__ NODE_FEATURE_ALL
+#endif
+
#include <cuda.h>
#include <float.h>
@@ -33,6 +41,7 @@
#define ccl_global
#define ccl_constant
#define ccl_may_alias
+#define ccl_addr_space
/* No assert supported for CUDA */
diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h
index d480ec0f270..e8b36d2605d 100644
--- a/intern/cycles/kernel/kernel_compat_opencl.h
+++ b/intern/cycles/kernel/kernel_compat_opencl.h
@@ -37,6 +37,22 @@
#define ccl_may_alias
#define ccl_constant __constant
#define ccl_global __global
+#define ccl_local __local
+#define ccl_private __private
+
+#ifdef __SPLIT_KERNEL__
+#define ccl_addr_space __global
+#else
+#define ccl_addr_space
+#endif
+
+/* Selective nodes compilation. */
+#ifndef __NODES_MAX_GROUP__
+# define __NODES_MAX_GROUP__ NODE_GROUP_LEVEL_MAX
+#endif
+#ifndef __NODES_FEATURES__
+# define __NODES_FEATURES__ NODE_FEATURE_ALL
+#endif
/* no assert in opencl */
#define kernel_assert(cond)
diff --git a/intern/cycles/kernel/kernel_debug.h b/intern/cycles/kernel/kernel_debug.h
index f532442ba41..94ede397848 100644
--- a/intern/cycles/kernel/kernel_debug.h
+++ b/intern/cycles/kernel/kernel_debug.h
@@ -23,7 +23,7 @@ ccl_device_inline void debug_data_init(DebugData *debug_data)
ccl_device_inline void kernel_write_debug_passes(KernelGlobals *kg,
ccl_global float *buffer,
- PathState *state,
+ ccl_addr_space PathState *state,
DebugData *debug_data,
int sample)
{
diff --git a/intern/cycles/kernel/kernel_differential.h b/intern/cycles/kernel/kernel_differential.h
index e5fbd5b450e..ae1e70f0167 100644
--- a/intern/cycles/kernel/kernel_differential.h
+++ b/intern/cycles/kernel/kernel_differential.h
@@ -18,7 +18,7 @@ CCL_NAMESPACE_BEGIN
/* See "Tracing Ray Differentials", Homan Igehy, 1999. */
-ccl_device void differential_transfer(differential3 *dP_, const differential3 dP, float3 D, const differential3 dD, float3 Ng, float t)
+ccl_device void differential_transfer(ccl_addr_space differential3 *dP_, const differential3 dP, float3 D, const differential3 dD, float3 Ng, float t)
{
/* ray differential transfer through homogeneous medium, to
* compute dPdx/dy at a shading point from the incoming ray */
@@ -31,7 +31,7 @@ ccl_device void differential_transfer(differential3 *dP_, const differential3 dP
dP_->dy = tmpy - dot(tmpy, Ng)*tmp;
}
-ccl_device void differential_incoming(differential3 *dI, const differential3 dD)
+ccl_device void differential_incoming(ccl_addr_space differential3 *dI, const differential3 dD)
{
/* compute dIdx/dy at a shading point, we just need to negate the
* differential of the ray direction */
@@ -40,7 +40,7 @@ ccl_device void differential_incoming(differential3 *dI, const differential3 dD)
dI->dy = -dD.dy;
}
-ccl_device void differential_dudv(differential *du, differential *dv, float3 dPdu, float3 dPdv, differential3 dP, float3 Ng)
+ccl_device void differential_dudv(ccl_addr_space differential *du, ccl_addr_space differential *dv, float3 dPdu, float3 dPdv, differential3 dP, float3 Ng)
{
/* now we have dPdx/dy from the ray differential transfer, and dPdu/dv
* from the primitive, we can compute dudx/dy and dvdx/dy. these are
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index 7523105607f..de9e8d77ec8 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -17,12 +17,20 @@
CCL_NAMESPACE_BEGIN
/* Direction Emission */
-
ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
- LightSample *ls, float3 I, differential3 dI, float t, float time, int bounce, int transparent_bounce)
+ LightSample *ls, float3 I, differential3 dI, float t, float time, int bounce, int transparent_bounce
+#ifdef __SPLIT_KERNEL__
+ ,ShaderData *sd_input
+#endif
+)
{
/* setup shading at emitter */
- ShaderData sd;
+#ifdef __SPLIT_KERNEL__
+ ShaderData *sd = sd_input;
+#else
+ ShaderData sd_object;
+ ShaderData *sd = &sd_object;
+#endif
float3 eval;
#ifdef __BACKGROUND_MIS__
@@ -37,23 +45,23 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
ray.dP = differential3_zero();
ray.dD = dI;
- shader_setup_from_background(kg, &sd, &ray, bounce+1, transparent_bounce);
- eval = shader_eval_background(kg, &sd, 0, SHADER_CONTEXT_EMISSION);
+ shader_setup_from_background(kg, sd, &ray, bounce+1, transparent_bounce);
+ eval = shader_eval_background(kg, sd, 0, SHADER_CONTEXT_EMISSION);
}
else
#endif
{
- shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, ls->u, ls->v, t, time, bounce+1, transparent_bounce);
+ shader_setup_from_sample(kg, sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, ls->u, ls->v, t, time, bounce+1, transparent_bounce);
- ls->Ng = sd.Ng;
+ ls->Ng = ccl_fetch(sd, Ng);
/* no path flag, we're evaluating this for all closures. that's weak but
* we'd have to do multiple evaluations otherwise */
- shader_eval_surface(kg, &sd, 0.0f, 0, SHADER_CONTEXT_EMISSION);
+ shader_eval_surface(kg, sd, 0.0f, 0, SHADER_CONTEXT_EMISSION);
/* evaluate emissive closure */
- if(sd.flag & SD_EMISSION)
- eval = shader_emissive_eval(kg, &sd);
+ if(ccl_fetch(sd, flag) & SD_EMISSION)
+ eval = shader_emissive_eval(kg, sd);
else
eval = make_float3(0.0f, 0.0f, 0.0f);
}
@@ -65,7 +73,11 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
ccl_device_noinline bool direct_emission(KernelGlobals *kg, ShaderData *sd,
LightSample *ls, Ray *ray, BsdfEval *eval, bool *is_lamp,
- int bounce, int transparent_bounce)
+ int bounce, int transparent_bounce
+#ifdef __SPLIT_KERNEL__
+ , ShaderData *sd_DL
+#endif
+ )
{
if(ls->pdf == 0.0f)
return false;
@@ -74,7 +86,14 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg, ShaderData *sd,
differential3 dD = differential3_zero();
/* evaluate closure */
- float3 light_eval = direct_emissive_eval(kg, ls, -ls->D, dD, ls->t, sd->time, bounce, transparent_bounce);
+
+ float3 light_eval = direct_emissive_eval(kg, ls, -ls->D, dD, ls->t, ccl_fetch(sd, time),
+ bounce,
+ transparent_bounce
+#ifdef __SPLIT_KERNEL__
+ ,sd_DL
+#endif
+ );
if(is_zero(light_eval))
return false;
@@ -83,7 +102,7 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg, ShaderData *sd,
float bsdf_pdf;
#ifdef __VOLUME__
- if(sd->prim != PRIM_NONE)
+ if(ccl_fetch(sd, prim) != PRIM_NONE)
shader_bsdf_eval(kg, sd, ls->D, eval, &bsdf_pdf);
else
shader_volume_phase_eval(kg, sd, ls->D, eval, &bsdf_pdf);
@@ -118,8 +137,8 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg, ShaderData *sd,
if(ls->shader & SHADER_CAST_SHADOW) {
/* setup ray */
- bool transmit = (dot(sd->Ng, ls->D) < 0.0f);
- ray->P = ray_offset(sd->P, (transmit)? -sd->Ng: sd->Ng);
+ bool transmit = (dot(ccl_fetch(sd, Ng), ls->D) < 0.0f);
+ ray->P = ray_offset(ccl_fetch(sd, P), (transmit)? -ccl_fetch(sd, Ng): ccl_fetch(sd, Ng));
if(ls->t == FLT_MAX) {
/* distant light */
@@ -132,7 +151,7 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg, ShaderData *sd,
ray->D = normalize_len(ray->D, &ray->t);
}
- ray->dP = sd->dP;
+ ray->dP = ccl_fetch(sd, dP);
ray->dD = differential3_zero();
}
else {
@@ -154,14 +173,14 @@ ccl_device_noinline float3 indirect_primitive_emission(KernelGlobals *kg, Shader
float3 L = shader_emissive_eval(kg, sd);
#ifdef __HAIR__
- if(!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS) && (sd->type & PRIMITIVE_ALL_TRIANGLE))
+ if(!(path_flag & PATH_RAY_MIS_SKIP) && (ccl_fetch(sd, flag) & SD_USE_MIS) && (ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE))
#else
- if(!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS))
+ if(!(path_flag & PATH_RAY_MIS_SKIP) && (ccl_fetch(sd, flag) & SD_USE_MIS))
#endif
{
/* multiple importance sampling, get triangle light pdf,
* and compute weight with respect to BSDF pdf */
- float pdf = triangle_light_pdf(kg, sd->Ng, sd->I, t);
+ float pdf = triangle_light_pdf(kg, ccl_fetch(sd, Ng), ccl_fetch(sd, I), t);
float mis_weight = power_heuristic(bsdf_pdf, pdf);
return L*mis_weight;
@@ -172,7 +191,11 @@ ccl_device_noinline float3 indirect_primitive_emission(KernelGlobals *kg, Shader
/* Indirect Lamp Emission */
-ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg, PathState *state, Ray *ray, float3 *emission)
+ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg, PathState *state, Ray *ray, float3 *emission
+#ifdef __SPLIT_KERNEL__
+ ,ShaderData *sd
+#endif
+ )
{
bool hit_lamp = false;
@@ -188,14 +211,21 @@ ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg, PathState *st
/* use visibility flag to skip lights */
if(ls.shader & SHADER_EXCLUDE_ANY) {
if(((ls.shader & SHADER_EXCLUDE_DIFFUSE) && (state->flag & PATH_RAY_DIFFUSE)) ||
- ((ls.shader & SHADER_EXCLUDE_GLOSSY) && (state->flag & PATH_RAY_REFLECT)) ||
+ ((ls.shader & SHADER_EXCLUDE_GLOSSY) &&
+ ((state->flag & (PATH_RAY_GLOSSY|PATH_RAY_REFLECT)) == (PATH_RAY_GLOSSY|PATH_RAY_REFLECT))) ||
((ls.shader & SHADER_EXCLUDE_TRANSMIT) && (state->flag & PATH_RAY_TRANSMIT)) ||
((ls.shader & SHADER_EXCLUDE_SCATTER) && (state->flag & PATH_RAY_VOLUME_SCATTER)))
continue;
}
#endif
- float3 L = direct_emissive_eval(kg, &ls, -ray->D, ray->dD, ls.t, ray->time, state->bounce, state->transparent_bounce);
+ float3 L = direct_emissive_eval(kg, &ls, -ray->D, ray->dD, ls.t, ray->time,
+ state->bounce,
+ state->transparent_bounce
+#ifdef __SPLIT_KERNEL__
+ ,sd
+#endif
+ );
#ifdef __VOLUME__
if(state->volume_stack[0].shader != SHADER_NONE) {
@@ -224,7 +254,11 @@ ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg, PathState *st
/* Indirect Background */
-ccl_device_noinline float3 indirect_background(KernelGlobals *kg, PathState *state, Ray *ray)
+ccl_device_noinline float3 indirect_background(KernelGlobals *kg, ccl_addr_space PathState *state, ccl_addr_space Ray *ray
+#ifdef __SPLIT_KERNEL__
+ ,ShaderData *sd_global
+#endif
+ )
{
#ifdef __BACKGROUND__
int shader = kernel_data.background.surface_shader;
@@ -232,18 +266,25 @@ ccl_device_noinline float3 indirect_background(KernelGlobals *kg, PathState *sta
/* use visibility flag to skip lights */
if(shader & SHADER_EXCLUDE_ANY) {
if(((shader & SHADER_EXCLUDE_DIFFUSE) && (state->flag & PATH_RAY_DIFFUSE)) ||
- ((shader & SHADER_EXCLUDE_GLOSSY) && (state->flag & PATH_RAY_REFLECT)) ||
+ ((shader & SHADER_EXCLUDE_GLOSSY) &&
+ ((state->flag & (PATH_RAY_GLOSSY|PATH_RAY_REFLECT)) == (PATH_RAY_GLOSSY|PATH_RAY_REFLECT))) ||
((shader & SHADER_EXCLUDE_TRANSMIT) && (state->flag & PATH_RAY_TRANSMIT)) ||
((shader & SHADER_EXCLUDE_CAMERA) && (state->flag & PATH_RAY_CAMERA)) ||
((shader & SHADER_EXCLUDE_SCATTER) && (state->flag & PATH_RAY_VOLUME_SCATTER)))
return make_float3(0.0f, 0.0f, 0.0f);
}
+#ifdef __SPLIT_KERNEL__
/* evaluate background closure */
+ Ray priv_ray = *ray;
+ shader_setup_from_background(kg, sd_global, &priv_ray, state->bounce+1, state->transparent_bounce);
+ float3 L = shader_eval_background(kg, sd_global, state->flag, SHADER_CONTEXT_EMISSION);
+#else
ShaderData sd;
shader_setup_from_background(kg, &sd, ray, state->bounce+1, state->transparent_bounce);
float3 L = shader_eval_background(kg, &sd, state->flag, SHADER_CONTEXT_EMISSION);
+#endif
#ifdef __BACKGROUND_MIS__
/* check if background light exists or if we should skip pdf */
@@ -252,7 +293,7 @@ ccl_device_noinline float3 indirect_background(KernelGlobals *kg, PathState *sta
if(!(state->flag & PATH_RAY_MIS_SKIP) && res) {
/* multiple importance sampling, get background light pdf for ray
* direction, and compute weight with respect to BSDF pdf */
- float pdf = background_light_pdf(kg, ray->D);
+ float pdf = background_light_pdf(kg, ray->P, ray->D);
float mis_weight = power_heuristic(state->ray_pdf, pdf);
return L*mis_weight;
diff --git a/intern/cycles/kernel/kernel_film.h b/intern/cycles/kernel/kernel_film.h
index 4668b40b86d..f9e9b413898 100644
--- a/intern/cycles/kernel/kernel_film.h
+++ b/intern/cycles/kernel/kernel_film.h
@@ -27,7 +27,7 @@ ccl_device float4 film_map(KernelGlobals *kg, float4 irradiance, float scale)
result.z = color_scene_linear_to_srgb(result.z*exposure);
/* clamp since alpha might be > 1.0 due to russian roulette */
- result.w = clamp(result.w, 0.0f, 1.0f);
+ result.w = saturate(result.w);
return result;
}
@@ -37,10 +37,10 @@ ccl_device uchar4 film_float_to_byte(float4 color)
uchar4 result;
/* simple float to byte conversion */
- result.x = (uchar)clamp(color.x*255.0f, 0.0f, 255.0f);
- result.y = (uchar)clamp(color.y*255.0f, 0.0f, 255.0f);
- result.z = (uchar)clamp(color.z*255.0f, 0.0f, 255.0f);
- result.w = (uchar)clamp(color.w*255.0f, 0.0f, 255.0f);
+ result.x = (uchar)(saturate(color.x)*255.0f);
+ result.y = (uchar)(saturate(color.y)*255.0f);
+ result.z = (uchar)(saturate(color.z)*255.0f);
+ result.w = (uchar)(saturate(color.w)*255.0f);
return result;
}
diff --git a/intern/cycles/kernel/kernel_globals.h b/intern/cycles/kernel/kernel_globals.h
index 0a9753baca2..17fa18909c4 100644
--- a/intern/cycles/kernel/kernel_globals.h
+++ b/intern/cycles/kernel/kernel_globals.h
@@ -80,7 +80,7 @@ typedef struct KernelGlobals {} KernelGlobals;
#ifdef __KERNEL_OPENCL__
-typedef struct KernelGlobals {
+typedef ccl_addr_space struct KernelGlobals {
ccl_constant KernelData *data;
#define KERNEL_TEX(type, ttype, name) \
@@ -94,7 +94,7 @@ typedef struct KernelGlobals {
ccl_device float lookup_table_read(KernelGlobals *kg, float x, int offset, int size)
{
- x = clamp(x, 0.0f, 1.0f)*(size-1);
+ x = saturate(x)*(size-1);
int index = min(float_to_int(x), size-1);
int nindex = min(index+1, size-1);
@@ -110,7 +110,7 @@ ccl_device float lookup_table_read(KernelGlobals *kg, float x, int offset, int s
ccl_device float lookup_table_read_2D(KernelGlobals *kg, float x, float y, int offset, int xsize, int ysize)
{
- y = clamp(y, 0.0f, 1.0f)*(ysize-1);
+ y = saturate(y)*(ysize-1);
int index = min(float_to_int(y), ysize-1);
int nindex = min(index+1, ysize-1);
diff --git a/intern/cycles/kernel/kernel_jitter.h b/intern/cycles/kernel/kernel_jitter.h
index 6aa29311ee6..9ba41635b9e 100644
--- a/intern/cycles/kernel/kernel_jitter.h
+++ b/intern/cycles/kernel/kernel_jitter.h
@@ -47,6 +47,8 @@ ccl_device_inline int cmj_fast_div_pow2(int a, int b)
# else
return a >> __builtin_ctz(b);
# endif
+#elif defined(__KERNEL_CUDA__)
+ return a >> (__ffs(b) - 1);
#else
return a/b;
#endif
@@ -63,6 +65,8 @@ ccl_device_inline uint cmj_w_mask(uint w)
# else
return ((1 << (32 - __builtin_clz(w))) - 1);
# endif
+#elif defined(__KERNEL_CUDA__)
+ return ((1 << (32 - __clz(w))) - 1);
#else
w |= w >> 1;
w |= w >> 2;
@@ -124,7 +128,7 @@ ccl_device_inline uint cmj_permute(uint i, uint l, uint p)
i *= 0xc860a3df;
i &= w;
i ^= i >> 5;
- } while (i >= l);
+ } while(i >= l);
return (i + p) % l;
}
@@ -167,7 +171,11 @@ ccl_device void cmj_sample_2D(int s, int N, int p, float *fx, float *fy)
{
kernel_assert(s < N);
+#if defined(__KERNEL_CUDA__)
+ int m = float_to_int(__fsqrt_ru(N));
+#else
int m = float_to_int(sqrtf(N));
+#endif
int n = (N + m - 1)/m;
float invN = 1.0f/N;
float invm = 1.0f/m;
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index 76fa754b5fa..1badbc3b9f7 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -33,6 +33,98 @@ typedef struct LightSample {
LightType type; /* type of light */
} LightSample;
+/* Area light sampling */
+
+/* Uses the following paper:
+ *
+ * Carlos Urena et al.
+ * An Area-Preserving Parametrization for Spherical Rectangles.
+ *
+ * https://www.solidangle.com/research/egsr2013_spherical_rectangle.pdf
+ *
+ * Note: light_p is modified when sample_coord is true.
+ */
+ccl_device float area_light_sample(float3 P,
+ float3 *light_p,
+ float3 axisu, float3 axisv,
+ float randu, float randv,
+ bool sample_coord)
+{
+ /* In our name system we're using P for the center,
+ * which is o in the paper.
+ */
+
+ float3 corner = *light_p - axisu * 0.5f - axisv * 0.5f;
+ float axisu_len, axisv_len;
+ /* Compute local reference system R. */
+ float3 x = normalize_len(axisu, &axisu_len);
+ float3 y = normalize_len(axisv, &axisv_len);
+ float3 z = cross(x, y);
+ /* Compute rectangle coords in local reference system. */
+ float3 dir = corner - P;
+ float z0 = dot(dir, z);
+ /* Flip 'z' to make it point against Q. */
+ if(z0 > 0.0f) {
+ z *= -1.0f;
+ z0 *= -1.0f;
+ }
+ float x0 = dot(dir, x);
+ float y0 = dot(dir, y);
+ float x1 = x0 + axisu_len;
+ float y1 = y0 + axisv_len;
+ /* Create vectors to four vertices. */
+ float3 v00 = make_float3(x0, y0, z0);
+ float3 v01 = make_float3(x0, y1, z0);
+ float3 v10 = make_float3(x1, y0, z0);
+ float3 v11 = make_float3(x1, y1, z0);
+ /* Compute normals to edges. */
+ float3 n0 = normalize(cross(v00, v10));
+ float3 n1 = normalize(cross(v10, v11));
+ float3 n2 = normalize(cross(v11, v01));
+ float3 n3 = normalize(cross(v01, v00));
+ /* Compute internal angles (gamma_i). */
+ float g0 = safe_acosf(-dot(n0, n1));
+ float g1 = safe_acosf(-dot(n1, n2));
+ float g2 = safe_acosf(-dot(n2, n3));
+ float g3 = safe_acosf(-dot(n3, n0));
+ /* Compute predefined constants. */
+ float b0 = n0.z;
+ float b1 = n2.z;
+ float b0sq = b0 * b0;
+ float k = M_2PI_F - g2 - g3;
+ /* Compute solid angle from internal angles. */
+ float S = g0 + g1 - k;
+
+ if(sample_coord) {
+ /* Compute cu. */
+ float au = randu * S + k;
+ float fu = (cosf(au) * b0 - b1) / sinf(au);
+ float cu = 1.0f / sqrtf(fu * fu + b0sq) * (fu > 0.0f ? 1.0f : -1.0f);
+ cu = clamp(cu, -1.0f, 1.0f);
+ /* Compute xu. */
+ float xu = -(cu * z0) / sqrtf(1.0f - cu * cu);
+ xu = clamp(xu, x0, x1);
+ /* Compute yv. */
+ float z0sq = z0 * z0;
+ float y0sq = y0 * y0;
+ float y1sq = y1 * y1;
+ float d = sqrtf(xu * xu + z0sq);
+ float h0 = y0 / sqrtf(d * d + y0sq);
+ float h1 = y1 / sqrtf(d * d + y1sq);
+ float hv = h0 + randv * (h1 - h0), hv2 = hv * hv;
+ float yv = (hv2 < 1.0f - 1e-6f) ? (hv * d) / sqrtf(1.0f - hv2) : y1;
+
+ /* Transform (xu, yv, z0) to world coords. */
+ *light_p = P + xu * x + yv * y + z0 * z;
+ }
+
+ /* return pdf */
+ if(S != 0.0f)
+ return 1.0f / S;
+ else
+ return 0.0f;
+}
+
/* Background Light */
#ifdef __BACKGROUND_MIS__
@@ -46,7 +138,7 @@ ccl_device_noinline
#else
ccl_device
#endif
-float3 background_light_sample(KernelGlobals *kg, float randu, float randv, float *pdf)
+float3 background_map_sample(KernelGlobals *kg, float randu, float randv, float *pdf)
{
/* for the following, the CDF values are actually a pair of floats, with the
* function value as X and the actual CDF as Y. The last entry's function
@@ -116,10 +208,8 @@ float3 background_light_sample(KernelGlobals *kg, float randu, float randv, floa
else
*pdf = (cdf_u.x * cdf_v.x)/(M_2PI_F * M_PI_F * sin_theta * denom);
- *pdf *= kernel_data.integrator.pdf_lights;
-
/* compute direction */
- return -equirectangular_to_direction(u, v);
+ return equirectangular_to_direction(u, v);
}
/* TODO(sergey): Same as above, after the release we should consider using
@@ -130,7 +220,7 @@ ccl_device_noinline
#else
ccl_device
#endif
-float background_light_pdf(KernelGlobals *kg, float3 direction)
+float background_map_pdf(KernelGlobals *kg, float3 direction)
{
float2 uv = direction_to_equirectangular(direction);
int res = kernel_data.integrator.pdf_background_res;
@@ -156,9 +246,223 @@ float background_light_pdf(KernelGlobals *kg, float3 direction)
float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * (res + 1) + index_u);
float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v);
- float pdf = (cdf_u.x * cdf_v.x)/(M_2PI_F * M_PI_F * sin_theta * denom);
+ return (cdf_u.x * cdf_v.x)/(M_2PI_F * M_PI_F * sin_theta * denom);
+}
+
+ccl_device_inline bool background_portal_data_fetch_and_check_side(KernelGlobals *kg,
+ float3 P,
+ int index,
+ float3 *lightpos,
+ float3 *dir)
+{
+ float4 data0 = kernel_tex_fetch(__light_data, (index + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 0);
+ float4 data3 = kernel_tex_fetch(__light_data, (index + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 3);
+
+ *lightpos = make_float3(data0.y, data0.z, data0.w);
+ *dir = make_float3(data3.y, data3.z, data3.w);
+
+ /* Check whether portal is on the right side. */
+ if(dot(*dir, P - *lightpos) > 1e-5f)
+ return true;
+
+ return false;
+}
+
+ccl_device float background_portal_pdf(KernelGlobals *kg,
+ float3 P,
+ float3 direction,
+ int ignore_portal,
+ bool *is_possible)
+{
+ float portal_pdf = 0.0f;
+
+ for(int p = 0; p < kernel_data.integrator.num_portals; p++) {
+ if(p == ignore_portal)
+ continue;
+
+ float3 lightpos, dir;
+ if(!background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir))
+ continue;
+
+ if(is_possible) {
+ /* There's a portal that could be sampled from this position. */
+ *is_possible = true;
+ }
+
+ float t = -(dot(P, dir) - dot(lightpos, dir)) / dot(direction, dir);
+ if(t <= 1e-5f) {
+ /* Either behind the portal or too close. */
+ continue;
+ }
- return pdf * kernel_data.integrator.pdf_lights;
+ float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1);
+ float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2);
+
+ float3 axisu = make_float3(data1.y, data1.z, data1.w);
+ float3 axisv = make_float3(data2.y, data2.z, data2.w);
+
+ float3 hit = P + t*direction;
+ float3 inplane = hit - lightpos;
+ /* Skip if the the ray doesn't pass through portal. */
+ if(fabsf(dot(inplane, axisu) / dot(axisu, axisu)) > 0.5f)
+ continue;
+ if(fabsf(dot(inplane, axisv) / dot(axisv, axisv)) > 0.5f)
+ continue;
+
+ portal_pdf += area_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false);
+ }
+
+ return kernel_data.integrator.num_portals? portal_pdf / kernel_data.integrator.num_portals: 0.0f;
+}
+
+ccl_device int background_num_possible_portals(KernelGlobals *kg, float3 P)
+{
+ int num_possible_portals = 0;
+ for(int p = 0; p < kernel_data.integrator.num_portals; p++) {
+ float3 lightpos, dir;
+ if(background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir))
+ num_possible_portals++;
+ }
+ return num_possible_portals;
+}
+
+ccl_device float3 background_portal_sample(KernelGlobals *kg,
+ float3 P,
+ float randu,
+ float randv,
+ int num_possible,
+ int *sampled_portal,
+ float *pdf)
+{
+ /* Pick a portal, then re-normalize randv. */
+ randv *= num_possible;
+ int portal = (int)randv;
+ randv -= portal;
+
+ /* TODO(sergey): Some smarter way of finding portal to sample
+ * is welcome.
+ */
+ for(int p = 0; p < kernel_data.integrator.num_portals; p++) {
+ /* Search for the sampled portal. */
+ float3 lightpos, dir;
+ if(!background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir))
+ continue;
+
+ if(portal == 0) {
+ /* p is the portal to be sampled. */
+ float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1);
+ float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2);
+ float3 axisu = make_float3(data1.y, data1.z, data1.w);
+ float3 axisv = make_float3(data2.y, data2.z, data2.w);
+
+ *pdf = area_light_sample(P, &lightpos,
+ axisu, axisv,
+ randu, randv,
+ true);
+
+ *pdf /= num_possible;
+ *sampled_portal = p;
+ return normalize(lightpos - P);
+ }
+
+ portal--;
+ }
+
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+ccl_device float3 background_light_sample(KernelGlobals *kg, float3 P, float randu, float randv, float *pdf)
+{
+ /* Probability of sampling portals instead of the map. */
+ float portal_sampling_pdf = kernel_data.integrator.portal_pdf;
+
+ /* Check if there are portals in the scene which we can sample. */
+ if(portal_sampling_pdf > 0.0f) {
+ int num_portals = background_num_possible_portals(kg, P);
+ if(num_portals > 0) {
+ if(portal_sampling_pdf == 1.0f || randu < portal_sampling_pdf) {
+ if(portal_sampling_pdf < 1.0f) {
+ randu /= portal_sampling_pdf;
+ }
+ int portal;
+ float3 D = background_portal_sample(kg, P, randu, randv, num_portals, &portal, pdf);
+ if(num_portals > 1) {
+ /* Ignore the chosen portal, its pdf is already included. */
+ *pdf += background_portal_pdf(kg, P, D, portal, NULL);
+ }
+ /* We could also have sampled the map, so combine with MIS. */
+ if(portal_sampling_pdf < 1.0f) {
+ float cdf_pdf = background_map_pdf(kg, D);
+ *pdf = (portal_sampling_pdf * (*pdf)
+ + (1.0f - portal_sampling_pdf) * cdf_pdf);
+ }
+ return D;
+ } else {
+ /* Sample map, but with nonzero portal_sampling_pdf for MIS. */
+ randu = (randu - portal_sampling_pdf) / (1.0f - portal_sampling_pdf);
+ }
+ } else {
+ /* We can't sample a portal.
+ * Check if we can sample the map instead.
+ */
+ if(portal_sampling_pdf == 1.0f) {
+ /* Use uniform as a fallback if we can't sample the map. */
+ *pdf = 1.0f / M_4PI_F;
+ return sample_uniform_sphere(randu, randv);
+ }
+ else {
+ portal_sampling_pdf = 0.0f;
+ }
+ }
+ }
+
+ float3 D = background_map_sample(kg, randu, randv, pdf);
+ /* Use MIS if portals could be sampled as well. */
+ if(portal_sampling_pdf > 0.0f) {
+ float portal_pdf = background_portal_pdf(kg, P, D, -1, NULL);
+ *pdf = (portal_sampling_pdf * portal_pdf
+ + (1.0f - portal_sampling_pdf) * (*pdf));
+ }
+ return D;
+}
+
+ccl_device float background_light_pdf(KernelGlobals *kg, float3 P, float3 direction)
+{
+ /* Probability of sampling portals instead of the map. */
+ float portal_sampling_pdf = kernel_data.integrator.portal_pdf;
+
+ if(portal_sampling_pdf > 0.0f) {
+ bool is_possible = false;
+ float portal_pdf = background_portal_pdf(kg, P, direction, -1, &is_possible);
+ if(portal_pdf == 0.0f) {
+ if(portal_sampling_pdf == 1.0f) {
+ /* If there are no possible portals at this point,
+ * the fallback sampling would have been used.
+ * Otherwise, the direction would not be sampled at all => pdf = 0
+ */
+ return is_possible? 0.0f: kernel_data.integrator.pdf_lights / M_4PI_F;
+ }
+ else {
+ /* We can only sample the map. */
+ return background_map_pdf(kg, direction) * kernel_data.integrator.pdf_lights;
+ }
+ } else {
+ if(portal_sampling_pdf == 1.0f) {
+ /* We can only sample portals. */
+ return portal_pdf * kernel_data.integrator.pdf_lights;
+ }
+ else {
+ /* We can sample both, so combine with MIS. */
+ return (background_map_pdf(kg, direction) * (1.0f - portal_sampling_pdf)
+ + portal_pdf * portal_sampling_pdf) * kernel_data.integrator.pdf_lights;
+ }
+ }
+ }
+
+ /* No portals in the scene, so must sample the map.
+ * At least one of them is always possible if we have a LIGHT_BACKGROUND.
+ */
+ return background_map_pdf(kg, direction) * kernel_data.integrator.pdf_lights;
}
#endif
@@ -184,96 +488,6 @@ ccl_device float3 sphere_light_sample(float3 P, float3 center, float radius, flo
return disk_light_sample(normalize(P - center), randu, randv)*radius;
}
-/* Uses the following paper:
- *
- * Carlos Urena et al.
- * An Area-Preserving Parametrization for Spherical Rectangles.
- *
- * https://www.solidangle.com/research/egsr2013_spherical_rectangle.pdf
- *
- * Note: light_p is modified when sample_coord is true.
- */
-ccl_device float area_light_sample(float3 P,
- float3 *light_p,
- float3 axisu, float3 axisv,
- float randu, float randv,
- bool sample_coord)
-{
- /* In our name system we're using P for the center,
- * which is o in the paper.
- */
-
- float3 corner = *light_p - axisu * 0.5f - axisv * 0.5f;
- float axisu_len, axisv_len;
- /* Compute local reference system R. */
- float3 x = normalize_len(axisu, &axisu_len);
- float3 y = normalize_len(axisv, &axisv_len);
- float3 z = cross(x, y);
- /* Compute rectangle coords in local reference system. */
- float3 dir = corner - P;
- float z0 = dot(dir, z);
- /* Flip 'z' to make it point against Q. */
- if(z0 > 0.0f) {
- z *= -1.0f;
- z0 *= -1.0f;
- }
- float x0 = dot(dir, x);
- float y0 = dot(dir, y);
- float x1 = x0 + axisu_len;
- float y1 = y0 + axisv_len;
- /* Create vectors to four vertices. */
- float3 v00 = make_float3(x0, y0, z0);
- float3 v01 = make_float3(x0, y1, z0);
- float3 v10 = make_float3(x1, y0, z0);
- float3 v11 = make_float3(x1, y1, z0);
- /* Compute normals to edges. */
- float3 n0 = normalize(cross(v00, v10));
- float3 n1 = normalize(cross(v10, v11));
- float3 n2 = normalize(cross(v11, v01));
- float3 n3 = normalize(cross(v01, v00));
- /* Compute internal angles (gamma_i). */
- float g0 = safe_acosf(-dot(n0, n1));
- float g1 = safe_acosf(-dot(n1, n2));
- float g2 = safe_acosf(-dot(n2, n3));
- float g3 = safe_acosf(-dot(n3, n0));
- /* Compute predefined constants. */
- float b0 = n0.z;
- float b1 = n2.z;
- float b0sq = b0 * b0;
- float k = M_2PI_F - g2 - g3;
- /* Compute solid angle from internal angles. */
- float S = g0 + g1 - k;
-
- if(sample_coord) {
- /* Compute cu. */
- float au = randu * S + k;
- float fu = (cosf(au) * b0 - b1) / sinf(au);
- float cu = 1.0f / sqrtf(fu * fu + b0sq) * (fu > 0.0f ? 1.0f : -1.0f);
- cu = clamp(cu, -1.0f, 1.0f);
- /* Compute xu. */
- float xu = -(cu * z0) / sqrtf(1.0f - cu * cu);
- xu = clamp(xu, x0, x1);
- /* Compute yv. */
- float z0sq = z0 * z0;
- float y0sq = y0 * y0;
- float y1sq = y1 * y1;
- float d = sqrtf(xu * xu + z0sq);
- float h0 = y0 / sqrtf(d * d + y0sq);
- float h1 = y1 / sqrtf(d * d + y1sq);
- float hv = h0 + randv * (h1 - h0), hv2 = hv * hv;
- float yv = (hv2 < 1.0f - 1e-6f) ? (hv * d) / sqrtf(1.0f - hv2) : y1;
-
- /* Transform (xu, yv, z0) to world coords. */
- *light_p = P + xu * x + yv * y + z0 * z;
- }
-
- /* return pdf */
- if(S != 0.0f)
- return 1.0f / S;
- else
- return 0.0f;
-}
-
ccl_device float spot_light_attenuation(float4 data1, float4 data2, LightSample *ls)
{
float3 dir = make_float3(data2.y, data2.z, data2.w);
@@ -344,13 +558,14 @@ ccl_device void lamp_light_sample(KernelGlobals *kg, int lamp,
#ifdef __BACKGROUND_MIS__
else if(type == LIGHT_BACKGROUND) {
/* infinite area light (e.g. light dome or env light) */
- float3 D = background_light_sample(kg, randu, randv, &ls->pdf);
+ float3 D = -background_light_sample(kg, P, randu, randv, &ls->pdf);
ls->P = D;
ls->Ng = D;
ls->D = -D;
ls->t = FLT_MAX;
ls->eval_fac = 1.0f;
+ ls->pdf *= kernel_data.integrator.pdf_lights;
}
#endif
else {
diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h
index 6bb39ee485d..20cf3fa931b 100644
--- a/intern/cycles/kernel/kernel_passes.h
+++ b/intern/cycles/kernel/kernel_passes.h
@@ -19,23 +19,49 @@ CCL_NAMESPACE_BEGIN
ccl_device_inline void kernel_write_pass_float(ccl_global float *buffer, int sample, float value)
{
ccl_global float *buf = buffer;
+#if defined(__SPLIT_KERNEL__) && defined(__WORK_STEALING__)
+ atomic_add_float(buf, value);
+#else
*buf = (sample == 0)? value: *buf + value;
+#endif // __SPLIT_KERNEL__ && __WORK_STEALING__
}
ccl_device_inline void kernel_write_pass_float3(ccl_global float *buffer, int sample, float3 value)
{
+#if defined(__SPLIT_KERNEL__) && defined(__WORK_STEALING__)
+ ccl_global float *buf_x = buffer + 0;
+ ccl_global float *buf_y = buffer + 1;
+ ccl_global float *buf_z = buffer + 2;
+
+ atomic_add_float(buf_x, value.x);
+ atomic_add_float(buf_y, value.y);
+ atomic_add_float(buf_z, value.z);
+#else
ccl_global float3 *buf = (ccl_global float3*)buffer;
*buf = (sample == 0)? value: *buf + value;
+#endif // __SPLIT_KERNEL__ && __WORK_STEALING__
}
ccl_device_inline void kernel_write_pass_float4(ccl_global float *buffer, int sample, float4 value)
{
+#if defined(__SPLIT_KERNEL__) && defined(__WORK_STEALING__)
+ ccl_global float *buf_x = buffer + 0;
+ ccl_global float *buf_y = buffer + 1;
+ ccl_global float *buf_z = buffer + 2;
+ ccl_global float *buf_w = buffer + 3;
+
+ atomic_add_float(buf_x, value.x);
+ atomic_add_float(buf_y, value.y);
+ atomic_add_float(buf_z, value.z);
+ atomic_add_float(buf_w, value.w);
+#else
ccl_global float4 *buf = (ccl_global float4*)buffer;
*buf = (sample == 0)? value: *buf + value;
+#endif // __SPLIT_KERNEL__ && __WORK_STEALING__
}
ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global float *buffer, PathRadiance *L,
- ShaderData *sd, int sample, PathState *state, float3 throughput)
+ ShaderData *sd, int sample, ccl_addr_space PathState *state, float3 throughput)
{
#ifdef __PASSES__
int path_flag = state->flag;
@@ -49,18 +75,18 @@ ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global fl
return;
if(!(path_flag & PATH_RAY_SINGLE_PASS_DONE)) {
- if(!(sd->flag & SD_TRANSPARENT) ||
+ if(!(ccl_fetch(sd, flag) & SD_TRANSPARENT) ||
kernel_data.film.pass_alpha_threshold == 0.0f ||
average(shader_bsdf_alpha(kg, sd)) >= kernel_data.film.pass_alpha_threshold)
{
if(sample == 0) {
if(flag & PASS_DEPTH) {
- float depth = camera_distance(kg, sd->P);
+ float depth = camera_distance(kg, ccl_fetch(sd, P));
kernel_write_pass_float(buffer + kernel_data.film.pass_depth, sample, depth);
}
if(flag & PASS_OBJECT_ID) {
- float id = object_pass_id(kg, sd->object);
+ float id = object_pass_id(kg, ccl_fetch(sd, object));
kernel_write_pass_float(buffer + kernel_data.film.pass_object_id, sample, id);
}
if(flag & PASS_MATERIAL_ID) {
@@ -70,7 +96,7 @@ ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global fl
}
if(flag & PASS_NORMAL) {
- float3 normal = sd->N;
+ float3 normal = ccl_fetch(sd, N);
kernel_write_pass_float3(buffer + kernel_data.film.pass_normal, sample, normal);
}
if(flag & PASS_UV) {
@@ -101,8 +127,8 @@ ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global fl
float mist_start = kernel_data.film.mist_start;
float mist_inv_depth = kernel_data.film.mist_inv_depth;
- float depth = camera_distance(kg, sd->P);
- float mist = clamp((depth - mist_start)*mist_inv_depth, 0.0f, 1.0f);
+ float depth = camera_distance(kg, ccl_fetch(sd, P));
+ float mist = saturate((depth - mist_start)*mist_inv_depth);
/* falloff */
float mist_falloff = kernel_data.film.mist_falloff;
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 151e762020b..e2dbf6e22f7 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -42,6 +42,7 @@
#include "kernel_path_state.h"
#include "kernel_shadow.h"
#include "kernel_emission.h"
+#include "kernel_path_common.h"
#include "kernel_path_surface.h"
#include "kernel_path_volume.h"
@@ -117,7 +118,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray,
/* direct light sampling */
kernel_branched_path_volume_connect_light(kg, rng, &volume_sd,
- throughput, &state, L, 1.0f, all, &volume_ray, &volume_segment);
+ throughput, &state, L, all, &volume_ray, &volume_segment);
/* indirect sample. if we use distance sampling and take just
* one sample for direct and indirect light, we could share
@@ -273,8 +274,6 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray,
float bssrdf_u, bssrdf_v;
path_state_rng_2D(kg, rng, &state, PRNG_BSDF_U, &bssrdf_u, &bssrdf_v);
subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, bssrdf_u, bssrdf_v, false);
-
- state.flag |= PATH_RAY_BSSRDF_ANCESTOR;
}
}
#endif
@@ -307,17 +306,17 @@ ccl_device void kernel_path_ao(KernelGlobals *kg, ShaderData *sd, PathRadiance *
sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
- if(dot(sd->Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
+ if(dot(ccl_fetch(sd, Ng), ao_D) > 0.0f && ao_pdf != 0.0f) {
Ray light_ray;
float3 ao_shadow;
- light_ray.P = ray_offset(sd->P, sd->Ng);
+ light_ray.P = ray_offset(ccl_fetch(sd, P), ccl_fetch(sd, Ng));
light_ray.D = ao_D;
light_ray.t = kernel_data.background.ao_distance;
#ifdef __OBJECT_MOTION__
- light_ray.time = sd->time;
+ light_ray.time = ccl_fetch(sd, time);
#endif
- light_ray.dP = sd->dP;
+ light_ray.dP = ccl_fetch(sd, dP);
light_ray.dD = differential3_zero();
if(!shadow_blocked(kg, state, &light_ray, &ao_shadow))
@@ -343,17 +342,17 @@ ccl_device void kernel_branched_path_ao(KernelGlobals *kg, ShaderData *sd, PathR
sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
- if(dot(sd->Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
+ if(dot(ccl_fetch(sd, Ng), ao_D) > 0.0f && ao_pdf != 0.0f) {
Ray light_ray;
float3 ao_shadow;
- light_ray.P = ray_offset(sd->P, sd->Ng);
+ light_ray.P = ray_offset(ccl_fetch(sd, P), ccl_fetch(sd, Ng));
light_ray.D = ao_D;
light_ray.t = kernel_data.background.ao_distance;
#ifdef __OBJECT_MOTION__
- light_ray.time = sd->time;
+ light_ray.time = ccl_fetch(sd, time);
#endif
- light_ray.dP = sd->dP;
+ light_ray.dP = ccl_fetch(sd, dP);
light_ray.dD = differential3_zero();
if(!shadow_blocked(kg, state, &light_ray, &ao_shadow))
@@ -364,31 +363,6 @@ ccl_device void kernel_branched_path_ao(KernelGlobals *kg, ShaderData *sd, PathR
#ifdef __SUBSURFACE__
-#ifdef __VOLUME__
-ccl_device void kernel_path_subsurface_update_volume_stack(KernelGlobals *kg,
- Ray *ray,
- VolumeStack *stack)
-{
- kernel_assert(kernel_data.integrator.use_volumes);
-
- Ray volume_ray = *ray;
- Intersection isect;
- int step = 0;
- while(step < VOLUME_STACK_SIZE &&
- scene_intersect_volume(kg, &volume_ray, &isect))
- {
- ShaderData sd;
- shader_setup_from_ray(kg, &sd, &isect, &volume_ray, 0, 0);
- kernel_volume_stack_enter_exit(kg, &sd, stack);
-
- /* Move ray forward. */
- volume_ray.P = ray_offset(sd.P, -sd.Ng);
- volume_ray.t -= sd.ray_length;
- ++step;
- }
-}
-#endif
-
ccl_device bool kernel_path_subsurface_scatter(KernelGlobals *kg, ShaderData *sd, PathRadiance *L, PathState *state, RNG *rng, Ray *ray, float3 *throughput)
{
float bssrdf_probability;
@@ -408,7 +382,7 @@ ccl_device bool kernel_path_subsurface_scatter(KernelGlobals *kg, ShaderData *sd
#ifdef __VOLUME__
Ray volume_ray = *ray;
bool need_update_volume_stack = kernel_data.integrator.use_volumes &&
- sd->flag & SD_OBJECT_INTERSECTS_VOLUME;
+ ccl_fetch(sd, flag) & SD_OBJECT_INTERSECTS_VOLUME;
#endif
/* compute lighting with the BSDF closure */
@@ -417,7 +391,6 @@ ccl_device bool kernel_path_subsurface_scatter(KernelGlobals *kg, ShaderData *sd
PathState hit_state = *state;
Ray hit_ray = *ray;
- hit_state.flag |= PATH_RAY_BSSRDF_ANCESTOR;
hit_state.rng_offset += PRNG_BOUNCE_NUM;
kernel_path_surface_connect_light(kg, rng, &bssrdf_sd[hit], tp, state, L);
@@ -433,7 +406,7 @@ ccl_device bool kernel_path_subsurface_scatter(KernelGlobals *kg, ShaderData *sd
volume_ray.D = normalize_len(hit_ray.P - volume_ray.P,
&volume_ray.t);
- kernel_path_subsurface_update_volume_stack(
+ kernel_volume_stack_update_for_subsurface(
kg,
&volume_ray,
hit_state.volume_stack);
@@ -562,7 +535,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
/* direct light sampling */
kernel_branched_path_volume_connect_light(kg, rng, &volume_sd,
- throughput, &state, &L, 1.0f, all, &volume_ray, &volume_segment);
+ throughput, &state, &L, all, &volume_ray, &volume_segment);
/* indirect sample. if we use distance sampling and take just
* one sample for direct and indirect light, we could share
@@ -740,8 +713,8 @@ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGloba
RNG *rng, ShaderData *sd, float3 throughput, float num_samples_adjust,
PathState *state, PathRadiance *L)
{
- for(int i = 0; i< sd->num_closure; i++) {
- const ShaderClosure *sc = &sd->closure[i];
+ for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
+ const ShaderClosure *sc = &ccl_fetch(sd, closure)[i];
if(!CLOSURE_IS_BSDF(sc->type))
continue;
@@ -792,8 +765,8 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
Ray *ray,
float3 throughput)
{
- for(int i = 0; i< sd->num_closure; i++) {
- ShaderClosure *sc = &sd->closure[i];
+ for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
+ ShaderClosure *sc = &ccl_fetch(sd, closure)[i];
if(!CLOSURE_IS_BSSRDF(sc->type))
continue;
@@ -804,8 +777,6 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
float num_samples_inv = 1.0f/num_samples;
RNG bssrdf_rng = cmj_hash(*rng, i);
- state->flag |= PATH_RAY_BSSRDF_ANCESTOR;
-
/* do subsurface scatter step with copy of shader data, this will
* replace the BSSRDF with a diffuse BSDF closure */
for(int j = 0; j < num_samples; j++) {
@@ -816,7 +787,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
#ifdef __VOLUME__
Ray volume_ray = *ray;
bool need_update_volume_stack = kernel_data.integrator.use_volumes &&
- sd->flag & SD_OBJECT_INTERSECTS_VOLUME;
+ ccl_fetch(sd, flag) & SD_OBJECT_INTERSECTS_VOLUME;
#endif
/* compute lighting with the BSDF closure */
@@ -832,7 +803,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
volume_ray.D = normalize_len(P - volume_ray.P,
&volume_ray.t);
- kernel_path_subsurface_update_volume_stack(
+ kernel_volume_stack_update_for_subsurface(
kg,
&volume_ray,
hit_state.volume_stack);
@@ -857,8 +828,6 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
&hit_state, L);
}
}
-
- state->flag &= ~PATH_RAY_BSSRDF_ANCESTOR;
}
}
#endif
@@ -937,7 +906,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
bool all = kernel_data.integrator.sample_all_lights_direct;
kernel_branched_path_volume_connect_light(kg, rng, &volume_sd,
- throughput, &state, &L, 1.0f, all, &volume_ray, &volume_segment);
+ throughput, &state, &L, all, &volume_ray, &volume_segment);
/* indirect light sampling */
int num_samples = kernel_data.integrator.volume_samples;
@@ -1175,32 +1144,6 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
#endif
-ccl_device_inline void kernel_path_trace_setup(KernelGlobals *kg, ccl_global uint *rng_state, int sample, int x, int y, RNG *rng, Ray *ray)
-{
- float filter_u;
- float filter_v;
-
- int num_samples = kernel_data.integrator.aa_samples;
-
- path_rng_init(kg, rng_state, sample, num_samples, rng, x, y, &filter_u, &filter_v);
-
- /* sample camera ray */
-
- float lens_u = 0.0f, lens_v = 0.0f;
-
- if(kernel_data.cam.aperturesize > 0.0f)
- path_rng_2D(kg, rng, sample, num_samples, PRNG_LENS_U, &lens_u, &lens_v);
-
- float time = 0.0f;
-
-#ifdef __CAMERA_MOTION__
- if(kernel_data.cam.shuttertime != -1.0f)
- time = path_rng_1D(kg, rng, sample, num_samples, PRNG_TIME);
-#endif
-
- camera_sample(kg, x, y, filter_u, filter_v, lens_u, lens_v, time, ray);
-}
-
ccl_device void kernel_path_trace(KernelGlobals *kg,
ccl_global float *buffer, ccl_global uint *rng_state,
int sample, int x, int y, int offset, int stride)
diff --git a/intern/cycles/kernel/kernel_path_common.h b/intern/cycles/kernel/kernel_path_common.h
new file mode 100644
index 00000000000..1912dfa16ed
--- /dev/null
+++ b/intern/cycles/kernel/kernel_path_common.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011-2015 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.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_inline void kernel_path_trace_setup(KernelGlobals *kg,
+ ccl_global uint *rng_state,
+ int sample,
+ int x, int y,
+ ccl_addr_space RNG *rng,
+ ccl_addr_space Ray *ray)
+{
+ float filter_u;
+ float filter_v;
+
+ int num_samples = kernel_data.integrator.aa_samples;
+
+ path_rng_init(kg, rng_state, sample, num_samples, rng, x, y, &filter_u, &filter_v);
+
+ /* sample camera ray */
+
+ float lens_u = 0.0f, lens_v = 0.0f;
+
+ if(kernel_data.cam.aperturesize > 0.0f)
+ path_rng_2D(kg, rng, sample, num_samples, PRNG_LENS_U, &lens_u, &lens_v);
+
+ float time = 0.0f;
+
+#ifdef __CAMERA_MOTION__
+ if(kernel_data.cam.shuttertime != -1.0f)
+ time = path_rng_1D(kg, rng, sample, num_samples, PRNG_TIME);
+#endif
+
+ camera_sample(kg, x, y, filter_u, filter_v, lens_u, lens_v, time, ray);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_path_state.h b/intern/cycles/kernel/kernel_path_state.h
index ab146c72cd0..15efb2371de 100644
--- a/intern/cycles/kernel/kernel_path_state.h
+++ b/intern/cycles/kernel/kernel_path_state.h
@@ -16,7 +16,7 @@
CCL_NAMESPACE_BEGIN
-ccl_device_inline void path_state_init(KernelGlobals *kg, PathState *state, RNG *rng, int sample, Ray *ray)
+ccl_device_inline void path_state_init(KernelGlobals *kg, ccl_addr_space PathState *state, ccl_addr_space RNG *rng, int sample, ccl_addr_space Ray *ray)
{
state->flag = PATH_RAY_CAMERA|PATH_RAY_MIS_SKIP;
@@ -51,7 +51,7 @@ ccl_device_inline void path_state_init(KernelGlobals *kg, PathState *state, RNG
#endif
}
-ccl_device_inline void path_state_next(KernelGlobals *kg, PathState *state, int label)
+ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathState *state, int label)
{
/* ray through transparent keeps same flags from previous ray and is
* not counted as a regular bounce, transparent has separate max */
@@ -106,7 +106,7 @@ ccl_device_inline void path_state_next(KernelGlobals *kg, PathState *state, int
state->flag &= ~(PATH_RAY_GLOSSY|PATH_RAY_SINGULAR|PATH_RAY_MIS_SKIP);
}
else if(label & LABEL_GLOSSY) {
- state->flag |= PATH_RAY_GLOSSY|PATH_RAY_GLOSSY_ANCESTOR;
+ state->flag |= PATH_RAY_GLOSSY;
state->flag &= ~(PATH_RAY_DIFFUSE|PATH_RAY_SINGULAR|PATH_RAY_MIS_SKIP);
}
else {
@@ -138,7 +138,7 @@ ccl_device_inline uint path_state_ray_visibility(KernelGlobals *kg, PathState *s
return flag;
}
-ccl_device_inline float path_state_terminate_probability(KernelGlobals *kg, PathState *state, const float3 throughput)
+ccl_device_inline float path_state_terminate_probability(KernelGlobals *kg, ccl_addr_space PathState *state, const float3 throughput)
{
if(state->flag & PATH_RAY_TRANSPARENT) {
/* transparent rays treated separately */
diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h
index f0d4e98c5e0..fe85a6b6e4b 100644
--- a/intern/cycles/kernel/kernel_path_surface.h
+++ b/intern/cycles/kernel/kernel_path_surface.h
@@ -24,7 +24,7 @@ ccl_device void kernel_branched_path_surface_connect_light(KernelGlobals *kg, RN
{
#ifdef __EMISSION__
/* sample illumination from lights to find path contribution */
- if(!(sd->flag & SD_BSDF_HAS_EVAL))
+ if(!(ccl_fetch(sd, flag) & SD_BSDF_HAS_EVAL))
return;
Ray light_ray;
@@ -32,7 +32,7 @@ ccl_device void kernel_branched_path_surface_connect_light(KernelGlobals *kg, RN
bool is_lamp;
#ifdef __OBJECT_MOTION__
- light_ray.time = sd->time;
+ light_ray.time = ccl_fetch(sd, time);
#endif
if(sample_all_lights) {
@@ -53,7 +53,7 @@ ccl_device void kernel_branched_path_surface_connect_light(KernelGlobals *kg, RN
path_branched_rng_2D(kg, &lamp_rng, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
LightSample ls;
- lamp_light_sample(kg, i, light_u, light_v, sd->P, &ls);
+ lamp_light_sample(kg, i, light_u, light_v, ccl_fetch(sd, P), &ls);
if(direct_emission(kg, sd, &ls, &light_ray, &L_light, &is_lamp, state->bounce, state->transparent_bounce)) {
/* trace shadow ray */
@@ -85,7 +85,7 @@ ccl_device void kernel_branched_path_surface_connect_light(KernelGlobals *kg, RN
light_t = 0.5f*light_t;
LightSample ls;
- light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls);
+ light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls);
if(direct_emission(kg, sd, &ls, &light_ray, &L_light, &is_lamp, state->bounce, state->transparent_bounce)) {
/* trace shadow ray */
@@ -106,7 +106,7 @@ ccl_device void kernel_branched_path_surface_connect_light(KernelGlobals *kg, RN
path_state_rng_2D(kg, rng, state, PRNG_LIGHT_U, &light_u, &light_v);
LightSample ls;
- light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls);
+ light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls);
/* sample random light */
if(direct_emission(kg, sd, &ls, &light_ray, &L_light, &is_lamp, state->bounce, state->transparent_bounce)) {
@@ -149,15 +149,15 @@ ccl_device bool kernel_branched_path_surface_bounce(KernelGlobals *kg, RNG *rng,
path_state_next(kg, state, label);
/* setup ray */
- ray->P = ray_offset(sd->P, (label & LABEL_TRANSMIT)? -sd->Ng: sd->Ng);
+ ray->P = ray_offset(ccl_fetch(sd, P), (label & LABEL_TRANSMIT)? -ccl_fetch(sd, Ng): ccl_fetch(sd, Ng));
ray->D = bsdf_omega_in;
ray->t = FLT_MAX;
#ifdef __RAY_DIFFERENTIALS__
- ray->dP = sd->dP;
+ ray->dP = ccl_fetch(sd, dP);
ray->dD = bsdf_domega_in;
#endif
#ifdef __OBJECT_MOTION__
- ray->time = sd->time;
+ ray->time = ccl_fetch(sd, time);
#endif
#ifdef __VOLUME__
@@ -181,12 +181,13 @@ ccl_device bool kernel_branched_path_surface_bounce(KernelGlobals *kg, RNG *rng,
#endif
+#ifndef __SPLIT_KERNEL__
/* path tracing: connect path directly to position on a light and add it to L */
-ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, RNG *rng,
- ShaderData *sd, float3 throughput, PathState *state, PathRadiance *L)
+ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_addr_space RNG *rng,
+ ShaderData *sd, float3 throughput, ccl_addr_space PathState *state, PathRadiance *L)
{
#ifdef __EMISSION__
- if(!(kernel_data.integrator.use_direct_light && (sd->flag & SD_BSDF_HAS_EVAL)))
+ if(!(kernel_data.integrator.use_direct_light && (ccl_fetch(sd, flag) & SD_BSDF_HAS_EVAL)))
return;
/* sample illumination from lights to find path contribution */
@@ -199,11 +200,11 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, RNG
bool is_lamp;
#ifdef __OBJECT_MOTION__
- light_ray.time = sd->time;
+ light_ray.time = ccl_fetch(sd, time);
#endif
LightSample ls;
- light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls);
+ light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls);
if(direct_emission(kg, sd, &ls, &light_ray, &L_light, &is_lamp, state->bounce, state->transparent_bounce)) {
/* trace shadow ray */
@@ -216,13 +217,14 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, RNG
}
#endif
}
+#endif
/* path tracing: bounce off or through surface to with new direction stored in ray */
-ccl_device_inline bool kernel_path_surface_bounce(KernelGlobals *kg, RNG *rng,
- ShaderData *sd, float3 *throughput, PathState *state, PathRadiance *L, Ray *ray)
+ccl_device_inline bool kernel_path_surface_bounce(KernelGlobals *kg, ccl_addr_space RNG *rng,
+ ShaderData *sd, ccl_addr_space float3 *throughput, ccl_addr_space PathState *state, PathRadiance *L, ccl_addr_space Ray *ray)
{
/* no BSDF? we can stop here */
- if(sd->flag & SD_BSDF) {
+ if(ccl_fetch(sd, flag) & SD_BSDF) {
/* sample BSDF */
float bsdf_pdf;
BsdfEval bsdf_eval;
@@ -254,16 +256,16 @@ ccl_device_inline bool kernel_path_surface_bounce(KernelGlobals *kg, RNG *rng,
path_state_next(kg, state, label);
/* setup ray */
- ray->P = ray_offset(sd->P, (label & LABEL_TRANSMIT)? -sd->Ng: sd->Ng);
+ ray->P = ray_offset(ccl_fetch(sd, P), (label & LABEL_TRANSMIT)? -ccl_fetch(sd, Ng): ccl_fetch(sd, Ng));
ray->D = bsdf_omega_in;
if(state->bounce == 0)
- ray->t -= sd->ray_length; /* clipping works through transparent */
+ ray->t -= ccl_fetch(sd, ray_length); /* clipping works through transparent */
else
ray->t = FLT_MAX;
#ifdef __RAY_DIFFERENTIALS__
- ray->dP = sd->dP;
+ ray->dP = ccl_fetch(sd, dP);
ray->dD = bsdf_domega_in;
#endif
@@ -275,21 +277,21 @@ ccl_device_inline bool kernel_path_surface_bounce(KernelGlobals *kg, RNG *rng,
return true;
}
#ifdef __VOLUME__
- else if(sd->flag & SD_HAS_ONLY_VOLUME) {
+ else if(ccl_fetch(sd, flag) & SD_HAS_ONLY_VOLUME) {
/* no surface shader but have a volume shader? act transparent */
/* update path state, count as transparent */
path_state_next(kg, state, LABEL_TRANSPARENT);
if(state->bounce == 0)
- ray->t -= sd->ray_length; /* clipping works through transparent */
+ ray->t -= ccl_fetch(sd, ray_length); /* clipping works through transparent */
else
ray->t = FLT_MAX;
/* setup ray position, direction stays unchanged */
- ray->P = ray_offset(sd->P, -sd->Ng);
+ ray->P = ray_offset(ccl_fetch(sd, P), -ccl_fetch(sd, Ng));
#ifdef __RAY_DIFFERENTIALS__
- ray->dP = sd->dP;
+ ray->dP = ccl_fetch(sd, dP);
#endif
/* enter/exit volume */
diff --git a/intern/cycles/kernel/kernel_path_volume.h b/intern/cycles/kernel/kernel_path_volume.h
index 10576ac90d1..82dc0f97622 100644
--- a/intern/cycles/kernel/kernel_path_volume.h
+++ b/intern/cycles/kernel/kernel_path_volume.h
@@ -107,7 +107,7 @@ bool kernel_path_volume_bounce(KernelGlobals *kg, RNG *rng,
ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG *rng,
ShaderData *sd, float3 throughput, PathState *state, PathRadiance *L,
- float num_samples_adjust, bool sample_all_lights, Ray *ray, const VolumeSegment *segment)
+ bool sample_all_lights, Ray *ray, const VolumeSegment *segment)
{
#ifdef __EMISSION__
if(!kernel_data.integrator.use_direct_light)
@@ -127,8 +127,8 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
if(UNLIKELY(light_select_reached_max_bounces(kg, i, state->bounce)))
continue;
- int num_samples = ceil_to_int(num_samples_adjust*light_select_num_samples(kg, i));
- float num_samples_inv = num_samples_adjust/(num_samples*kernel_data.integrator.num_all_lights);
+ int num_samples = light_select_num_samples(kg, i);
+ float num_samples_inv = 1.0f/(num_samples*kernel_data.integrator.num_all_lights);
RNG lamp_rng = cmj_hash(*rng, i);
if(kernel_data.integrator.pdf_triangles != 0.0f)
@@ -174,8 +174,8 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
/* mesh light sampling */
if(kernel_data.integrator.pdf_triangles != 0.0f) {
- int num_samples = ceil_to_int(num_samples_adjust*kernel_data.integrator.mesh_light_samples);
- float num_samples_inv = num_samples_adjust/num_samples;
+ int num_samples = kernel_data.integrator.mesh_light_samples;
+ float num_samples_inv = 1.0f/num_samples;
if(kernel_data.integrator.num_all_lights)
num_samples_inv *= 0.5f;
diff --git a/intern/cycles/kernel/kernel_projection.h b/intern/cycles/kernel/kernel_projection.h
index bd18fd21354..62922df3286 100644
--- a/intern/cycles/kernel/kernel_projection.h
+++ b/intern/cycles/kernel/kernel_projection.h
@@ -163,6 +163,10 @@ ccl_device float3 mirrorball_to_direction(float u, float v)
dir.x = 2.0f*u - 1.0f;
dir.z = 2.0f*v - 1.0f;
+
+ if(dir.x*dir.x + dir.z*dir.z > 1.0f)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
dir.y = -sqrtf(max(1.0f - dir.x*dir.x - dir.z*dir.z, 0.0f));
/* reflection */
@@ -191,6 +195,8 @@ ccl_device float3 panorama_to_direction(KernelGlobals *kg, float u, float v)
switch(kernel_data.cam.panorama_type) {
case PANORAMA_EQUIRECTANGULAR:
return equirectangular_range_to_direction(u, v, kernel_data.cam.equirectangular_range);
+ case PANORAMA_MIRRORBALL:
+ return mirrorball_to_direction(u, v);
case PANORAMA_FISHEYE_EQUIDISTANT:
return fisheye_to_direction(u, v, kernel_data.cam.fisheye_fov);
case PANORAMA_FISHEYE_EQUISOLID:
@@ -205,6 +211,8 @@ ccl_device float2 direction_to_panorama(KernelGlobals *kg, float3 dir)
switch(kernel_data.cam.panorama_type) {
case PANORAMA_EQUIRECTANGULAR:
return direction_to_equirectangular_range(dir, kernel_data.cam.equirectangular_range);
+ case PANORAMA_MIRRORBALL:
+ return direction_to_mirrorball(dir);
case PANORAMA_FISHEYE_EQUIDISTANT:
return direction_to_fisheye(dir, kernel_data.cam.fisheye_fov);
case PANORAMA_FISHEYE_EQUISOLID:
diff --git a/intern/cycles/kernel/kernel_queues.h b/intern/cycles/kernel/kernel_queues.h
new file mode 100644
index 00000000000..9e65e2b0768
--- /dev/null
+++ b/intern/cycles/kernel/kernel_queues.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2011-2015 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 __KERNEL_QUEUE_H__
+#define __KERNEL_QUEUE_H__
+
+/*
+ * Queue utility functions for split kernel
+ */
+
+#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable
+#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable
+
+/*
+ * Enqueue ray index into the queue
+ */
+ccl_device void enqueue_ray_index (
+ int ray_index, /* Ray index to be enqueued */
+ int queue_number, /* Queue in which the ray index should be enqueued*/
+ ccl_global int *queues, /* Buffer of all queues */
+ int queue_size, /* Size of each queue */
+ ccl_global int *queue_index /* Array of size num_queues; Used for atomic increment */
+ )
+{
+ /* This thread's queue index */
+ int my_queue_index = atomic_inc(&queue_index[queue_number]) + (queue_number * queue_size);
+ queues[my_queue_index] = ray_index;
+}
+
+/*
+ * Get the ray index for this thread
+ * Returns a positive ray_index for threads that have to do some work;
+ * Returns 'QUEUE_EMPTY_SLOT' for threads that don't have any work
+ * i.e All ray's in the queue has been successfully allocated and there
+ * is no more ray to allocate to other threads.
+ */
+ccl_device int get_ray_index (
+ int thread_index, /* Global thread index */
+ int queue_number, /* Queue to operate on */
+ ccl_global int *queues, /* Buffer of all queues */
+ int queuesize, /* Size of a queue */
+ int empty_queue /* Empty the queue slot as soon as we fetch the ray index */
+ )
+{
+ int ray_index = queues[queue_number * queuesize + thread_index];
+
+ if(empty_queue && ray_index != QUEUE_EMPTY_SLOT) {
+ queues[queue_number * queuesize + thread_index] = QUEUE_EMPTY_SLOT;
+ }
+
+ return ray_index;
+}
+
+/* The following functions are to realize Local memory variant of enqueue ray index function */
+
+/* All threads should call this function */
+ccl_device void enqueue_ray_index_local(
+ int ray_index, /* Ray index to enqueue*/
+ int queue_number, /* Queue in which to enqueue ray index */
+ char enqueue_flag, /* True for threads whose ray index has to be enqueued */
+ int queuesize, /* queue size */
+ ccl_local unsigned int *local_queue_atomics, /* To to local queue atomics */
+ ccl_global int *Queue_data, /* Queues */
+ ccl_global int *Queue_index /* To do global queue atomics */
+ )
+{
+ int lidx = get_local_id(1) * get_local_size(0) + get_local_id(0);
+
+ /* Get local queue id */
+ unsigned int lqidx;
+ if(enqueue_flag) {
+ lqidx = atomic_inc(local_queue_atomics);
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ /* Get global queue offset */
+ if(lidx == 0) {
+ *local_queue_atomics = atomic_add(&Queue_index[queue_number], *local_queue_atomics);
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ /* Get global queue index and enqueue ray */
+ if(enqueue_flag) {
+ unsigned int my_gqidx = queue_number * queuesize + (*local_queue_atomics) + lqidx;
+ Queue_data[my_gqidx] = ray_index;
+ }
+}
+
+ccl_device unsigned int get_local_queue_index(
+ int queue_number, /* Queue in which to enqueue the ray; -1 if no queue */
+ ccl_local unsigned int *local_queue_atomics
+ )
+{
+ int my_lqidx = atomic_inc(&local_queue_atomics[queue_number]);
+ return my_lqidx;
+}
+
+ccl_device unsigned int get_global_per_queue_offset(
+ int queue_number,
+ ccl_local unsigned int *local_queue_atomics,
+ ccl_global int* global_queue_atomics
+ )
+{
+ unsigned int queue_offset = atomic_add((&global_queue_atomics[queue_number]), local_queue_atomics[queue_number]);
+ return queue_offset;
+}
+
+ccl_device unsigned int get_global_queue_index(
+ int queue_number,
+ int queuesize,
+ unsigned int lqidx,
+ ccl_local unsigned int * global_per_queue_offset
+ )
+{
+ int my_gqidx = queuesize * queue_number + lqidx + global_per_queue_offset[queue_number];
+ return my_gqidx;
+}
+
+#endif // __KERNEL_QUEUE_H__
diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h
index 40767bac013..631a2cb75de 100644
--- a/intern/cycles/kernel/kernel_random.h
+++ b/intern/cycles/kernel/kernel_random.h
@@ -98,7 +98,7 @@ ccl_device uint sobol_lookup(const uint m, const uint frame, const uint ex, cons
return index;
}
-ccl_device_inline float path_rng_1D(KernelGlobals *kg, RNG *rng, int sample, int num_samples, int dimension)
+ccl_device_inline float path_rng_1D(KernelGlobals *kg, ccl_addr_space RNG *rng, int sample, int num_samples, int dimension)
{
#ifdef __CMJ__
if(kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_CMJ) {
@@ -132,7 +132,7 @@ ccl_device_inline float path_rng_1D(KernelGlobals *kg, RNG *rng, int sample, int
#endif
}
-ccl_device_inline void path_rng_2D(KernelGlobals *kg, RNG *rng, int sample, int num_samples, int dimension, float *fx, float *fy)
+ccl_device_inline void path_rng_2D(KernelGlobals *kg, ccl_addr_space RNG *rng, int sample, int num_samples, int dimension, float *fx, float *fy)
{
#ifdef __CMJ__
if(kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_CMJ) {
@@ -149,7 +149,7 @@ ccl_device_inline void path_rng_2D(KernelGlobals *kg, RNG *rng, int sample, int
}
}
-ccl_device_inline void path_rng_init(KernelGlobals *kg, ccl_global uint *rng_state, int sample, int num_samples, RNG *rng, int x, int y, float *fx, float *fy)
+ccl_device_inline void path_rng_init(KernelGlobals *kg, ccl_global uint *rng_state, int sample, int num_samples, ccl_addr_space RNG *rng, int x, int y, float *fx, float *fy)
{
#ifdef __SOBOL_FULL_SCREEN__
uint px, py;
@@ -261,12 +261,12 @@ ccl_device uint lcg_init(uint seed)
* For branches in the path we must be careful not to reuse the same number
* in a sequence and offset accordingly. */
-ccl_device_inline float path_state_rng_1D(KernelGlobals *kg, RNG *rng, const PathState *state, int dimension)
+ccl_device_inline float path_state_rng_1D(KernelGlobals *kg, ccl_addr_space RNG *rng, const ccl_addr_space PathState *state, int dimension)
{
return path_rng_1D(kg, rng, state->sample, state->num_samples, state->rng_offset + dimension);
}
-ccl_device_inline float path_state_rng_1D_for_decision(KernelGlobals *kg, RNG *rng, const PathState *state, int dimension)
+ccl_device_inline float path_state_rng_1D_for_decision(KernelGlobals *kg, ccl_addr_space RNG *rng, const ccl_addr_space PathState *state, int dimension)
{
/* the rng_offset is not increased for transparent bounces. if we do then
* fully transparent objects can become subtly visible by the different
@@ -279,23 +279,23 @@ ccl_device_inline float path_state_rng_1D_for_decision(KernelGlobals *kg, RNG *r
return path_rng_1D(kg, rng, state->sample, state->num_samples, rng_offset + dimension);
}
-ccl_device_inline void path_state_rng_2D(KernelGlobals *kg, RNG *rng, const PathState *state, int dimension, float *fx, float *fy)
+ccl_device_inline void path_state_rng_2D(KernelGlobals *kg, ccl_addr_space RNG *rng, const ccl_addr_space PathState *state, int dimension, float *fx, float *fy)
{
path_rng_2D(kg, rng, state->sample, state->num_samples, state->rng_offset + dimension, fx, fy);
}
-ccl_device_inline float path_branched_rng_1D(KernelGlobals *kg, RNG *rng, const PathState *state, int branch, int num_branches, int dimension)
+ccl_device_inline float path_branched_rng_1D(KernelGlobals *kg, ccl_addr_space RNG *rng, const PathState *state, int branch, int num_branches, int dimension)
{
return path_rng_1D(kg, rng, state->sample*num_branches + branch, state->num_samples*num_branches, state->rng_offset + dimension);
}
-ccl_device_inline float path_branched_rng_1D_for_decision(KernelGlobals *kg, RNG *rng, const PathState *state, int branch, int num_branches, int dimension)
+ccl_device_inline float path_branched_rng_1D_for_decision(KernelGlobals *kg, ccl_addr_space RNG *rng, const PathState *state, int branch, int num_branches, int dimension)
{
int rng_offset = state->rng_offset + state->transparent_bounce*PRNG_BOUNCE_NUM;
return path_rng_1D(kg, rng, state->sample*num_branches + branch, state->num_samples*num_branches, rng_offset + dimension);
}
-ccl_device_inline void path_branched_rng_2D(KernelGlobals *kg, RNG *rng, const PathState *state, int branch, int num_branches, int dimension, float *fx, float *fy)
+ccl_device_inline void path_branched_rng_2D(KernelGlobals *kg, ccl_addr_space RNG *rng, const PathState *state, int branch, int num_branches, int dimension, float *fx, float *fy)
{
path_rng_2D(kg, rng, state->sample*num_branches + branch, state->num_samples*num_branches, state->rng_offset + dimension, fx, fy);
}
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index 87b6208bcf4..1d94de87385 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -37,13 +37,13 @@ CCL_NAMESPACE_BEGIN
#ifdef __OBJECT_MOTION__
ccl_device void shader_setup_object_transforms(KernelGlobals *kg, ShaderData *sd, float time)
{
- if(sd->flag & SD_OBJECT_MOTION) {
- sd->ob_tfm = object_fetch_transform_motion(kg, sd->object, time);
- sd->ob_itfm = transform_quick_inverse(sd->ob_tfm);
+ if(ccl_fetch(sd, flag) & SD_OBJECT_MOTION) {
+ ccl_fetch(sd, ob_tfm) = object_fetch_transform_motion(kg, ccl_fetch(sd, object), time);
+ ccl_fetch(sd, ob_itfm) = transform_quick_inverse(ccl_fetch(sd, ob_tfm));
}
else {
- sd->ob_tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
- sd->ob_itfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
+ ccl_fetch(sd, ob_tfm) = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_TRANSFORM);
+ ccl_fetch(sd, ob_itfm) = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_INVERSE_TRANSFORM);
}
}
#endif
@@ -52,55 +52,55 @@ ccl_device void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
const Intersection *isect, const Ray *ray, int bounce, int transparent_bounce)
{
#ifdef __INSTANCING__
- sd->object = (isect->object == PRIM_NONE)? kernel_tex_fetch(__prim_object, isect->prim): isect->object;
+ ccl_fetch(sd, object) = (isect->object == PRIM_NONE)? kernel_tex_fetch(__prim_object, isect->prim): isect->object;
#endif
- sd->type = isect->type;
- sd->flag = kernel_tex_fetch(__object_flag, sd->object);
+ ccl_fetch(sd, type) = isect->type;
+ ccl_fetch(sd, flag) = kernel_tex_fetch(__object_flag, ccl_fetch(sd, object));
/* matrices and time */
#ifdef __OBJECT_MOTION__
shader_setup_object_transforms(kg, sd, ray->time);
- sd->time = ray->time;
+ ccl_fetch(sd, time) = ray->time;
#endif
- sd->prim = kernel_tex_fetch(__prim_index, isect->prim);
- sd->ray_length = isect->t;
- sd->ray_depth = bounce;
- sd->transparent_depth = transparent_bounce;
+ ccl_fetch(sd, prim) = kernel_tex_fetch(__prim_index, isect->prim);
+ ccl_fetch(sd, ray_length) = isect->t;
+ ccl_fetch(sd, ray_depth) = bounce;
+ ccl_fetch(sd, transparent_depth) = transparent_bounce;
#ifdef __UV__
- sd->u = isect->u;
- sd->v = isect->v;
+ ccl_fetch(sd, u) = isect->u;
+ ccl_fetch(sd, v) = isect->v;
#endif
#ifdef __HAIR__
- if(sd->type & PRIMITIVE_ALL_CURVE) {
+ if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) {
/* curve */
- float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
+ float4 curvedata = kernel_tex_fetch(__curves, ccl_fetch(sd, prim));
- sd->shader = __float_as_int(curvedata.z);
- sd->P = bvh_curve_refine(kg, sd, isect, ray);
+ ccl_fetch(sd, shader) = __float_as_int(curvedata.z);
+ ccl_fetch(sd, P) = bvh_curve_refine(kg, sd, isect, ray);
}
else
#endif
- if(sd->type & PRIMITIVE_TRIANGLE) {
+ if(ccl_fetch(sd, type) & PRIMITIVE_TRIANGLE) {
/* static triangle */
float3 Ng = triangle_normal(kg, sd);
- sd->shader = kernel_tex_fetch(__tri_shader, sd->prim);
+ ccl_fetch(sd, shader) = kernel_tex_fetch(__tri_shader, ccl_fetch(sd, prim));
/* vectors */
- sd->P = triangle_refine(kg, sd, isect, ray);
- sd->Ng = Ng;
- sd->N = Ng;
+ ccl_fetch(sd, P) = triangle_refine(kg, sd, isect, ray);
+ ccl_fetch(sd, Ng) = Ng;
+ ccl_fetch(sd, N) = Ng;
/* smooth normal */
- if(sd->shader & SHADER_SMOOTH_NORMAL)
- sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
+ if(ccl_fetch(sd, shader) & SHADER_SMOOTH_NORMAL)
+ ccl_fetch(sd, N) = triangle_smooth_normal(kg, ccl_fetch(sd, prim), ccl_fetch(sd, u), ccl_fetch(sd, v));
#ifdef __DPDU__
/* dPdu/dPdv */
- triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv);
+ triangle_dPdudv(kg, ccl_fetch(sd, prim), &ccl_fetch(sd, dPdu), &ccl_fetch(sd, dPdv));
#endif
}
else {
@@ -108,40 +108,40 @@ ccl_device void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
motion_triangle_shader_setup(kg, sd, isect, ray, false);
}
- sd->I = -ray->D;
+ ccl_fetch(sd, I) = -ray->D;
- sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2);
+ ccl_fetch(sd, flag) |= kernel_tex_fetch(__shader_flag, (ccl_fetch(sd, shader) & SHADER_MASK)*2);
#ifdef __INSTANCING__
if(isect->object != OBJECT_NONE) {
/* instance transform */
- object_normal_transform(kg, sd, &sd->N);
- object_normal_transform(kg, sd, &sd->Ng);
+ object_normal_transform_auto(kg, sd, &ccl_fetch(sd, N));
+ object_normal_transform_auto(kg, sd, &ccl_fetch(sd, Ng));
#ifdef __DPDU__
- object_dir_transform(kg, sd, &sd->dPdu);
- object_dir_transform(kg, sd, &sd->dPdv);
+ object_dir_transform_auto(kg, sd, &ccl_fetch(sd, dPdu));
+ object_dir_transform_auto(kg, sd, &ccl_fetch(sd, dPdv));
#endif
}
#endif
/* backfacing test */
- bool backfacing = (dot(sd->Ng, sd->I) < 0.0f);
+ bool backfacing = (dot(ccl_fetch(sd, Ng), ccl_fetch(sd, I)) < 0.0f);
if(backfacing) {
- sd->flag |= SD_BACKFACING;
- sd->Ng = -sd->Ng;
- sd->N = -sd->N;
+ ccl_fetch(sd, flag) |= SD_BACKFACING;
+ ccl_fetch(sd, Ng) = -ccl_fetch(sd, Ng);
+ ccl_fetch(sd, N) = -ccl_fetch(sd, N);
#ifdef __DPDU__
- sd->dPdu = -sd->dPdu;
- sd->dPdv = -sd->dPdv;
+ ccl_fetch(sd, dPdu) = -ccl_fetch(sd, dPdu);
+ ccl_fetch(sd, dPdv) = -ccl_fetch(sd, dPdv);
#endif
}
#ifdef __RAY_DIFFERENTIALS__
/* differentials */
- differential_transfer(&sd->dP, ray->dP, ray->D, ray->dD, sd->Ng, isect->t);
- differential_incoming(&sd->dI, ray->dD);
- differential_dudv(&sd->du, &sd->dv, sd->dPdu, sd->dPdv, sd->dP, sd->Ng);
+ differential_transfer(&ccl_fetch(sd, dP), ray->dP, ray->D, ray->dD, ccl_fetch(sd, Ng), isect->t);
+ differential_incoming(&ccl_fetch(sd, dI), ray->dD);
+ differential_dudv(&ccl_fetch(sd, du), &ccl_fetch(sd, dv), ccl_fetch(sd, dPdu), ccl_fetch(sd, dPdv), ccl_fetch(sd, dP), ccl_fetch(sd, Ng));
#endif
}
@@ -166,7 +166,7 @@ ccl_device_inline void shader_setup_from_subsurface(KernelGlobals *kg, ShaderDat
/* fetch triangle data */
if(sd->type == PRIMITIVE_TRIANGLE) {
float3 Ng = triangle_normal(kg, sd);
- sd->shader = kernel_tex_fetch(__tri_shader, sd->prim);
+ sd->shader = kernel_tex_fetch(__tri_shader, sd->prim);
/* static triangle */
sd->P = triangle_refine_subsurface(kg, sd, isect, ray);
@@ -230,105 +230,105 @@ ccl_device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
int shader, int object, int prim, float u, float v, float t, float time, int bounce, int transparent_bounce)
{
/* vectors */
- sd->P = P;
- sd->N = Ng;
- sd->Ng = Ng;
- sd->I = I;
- sd->shader = shader;
- sd->type = (prim == PRIM_NONE)? PRIMITIVE_NONE: PRIMITIVE_TRIANGLE;
+ ccl_fetch(sd, P) = P;
+ ccl_fetch(sd, N) = Ng;
+ ccl_fetch(sd, Ng) = Ng;
+ ccl_fetch(sd, I) = I;
+ ccl_fetch(sd, shader) = shader;
+ ccl_fetch(sd, type) = (prim == PRIM_NONE)? PRIMITIVE_NONE: PRIMITIVE_TRIANGLE;
/* primitive */
#ifdef __INSTANCING__
- sd->object = object;
+ ccl_fetch(sd, object) = object;
#endif
/* currently no access to bvh prim index for strand sd->prim*/
- sd->prim = prim;
+ ccl_fetch(sd, prim) = prim;
#ifdef __UV__
- sd->u = u;
- sd->v = v;
+ ccl_fetch(sd, u) = u;
+ ccl_fetch(sd, v) = v;
#endif
- sd->ray_length = t;
- sd->ray_depth = bounce;
- sd->transparent_depth = transparent_bounce;
+ ccl_fetch(sd, ray_length) = t;
+ ccl_fetch(sd, ray_depth) = bounce;
+ ccl_fetch(sd, transparent_depth) = transparent_bounce;
/* detect instancing, for non-instanced the object index is -object-1 */
#ifdef __INSTANCING__
bool instanced = false;
- if(sd->prim != PRIM_NONE) {
- if(sd->object >= 0)
+ if(ccl_fetch(sd, prim) != PRIM_NONE) {
+ if(ccl_fetch(sd, object) >= 0)
instanced = true;
else
#endif
- sd->object = ~sd->object;
+ ccl_fetch(sd, object) = ~ccl_fetch(sd, object);
#ifdef __INSTANCING__
}
#endif
- sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2);
- if(sd->object != OBJECT_NONE) {
- sd->flag |= kernel_tex_fetch(__object_flag, sd->object);
+ ccl_fetch(sd, flag) = kernel_tex_fetch(__shader_flag, (ccl_fetch(sd, shader) & SHADER_MASK)*2);
+ if(ccl_fetch(sd, object) != OBJECT_NONE) {
+ ccl_fetch(sd, flag) |= kernel_tex_fetch(__object_flag, ccl_fetch(sd, object));
#ifdef __OBJECT_MOTION__
shader_setup_object_transforms(kg, sd, time);
}
- sd->time = time;
+ ccl_fetch(sd, time) = time;
#else
}
#endif
- if(sd->type & PRIMITIVE_TRIANGLE) {
+ if(ccl_fetch(sd, type) & PRIMITIVE_TRIANGLE) {
/* smooth normal */
- if(sd->shader & SHADER_SMOOTH_NORMAL) {
- sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
+ if(ccl_fetch(sd, shader) & SHADER_SMOOTH_NORMAL) {
+ ccl_fetch(sd, N) = triangle_smooth_normal(kg, ccl_fetch(sd, prim), ccl_fetch(sd, u), ccl_fetch(sd, v));
#ifdef __INSTANCING__
if(instanced)
- object_normal_transform(kg, sd, &sd->N);
+ object_normal_transform_auto(kg, sd, &ccl_fetch(sd, N));
#endif
}
/* dPdu/dPdv */
#ifdef __DPDU__
- triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv);
+ triangle_dPdudv(kg, ccl_fetch(sd, prim), &ccl_fetch(sd, dPdu), &ccl_fetch(sd, dPdv));
#ifdef __INSTANCING__
if(instanced) {
- object_dir_transform(kg, sd, &sd->dPdu);
- object_dir_transform(kg, sd, &sd->dPdv);
+ object_dir_transform_auto(kg, sd, &ccl_fetch(sd, dPdu));
+ object_dir_transform_auto(kg, sd, &ccl_fetch(sd, dPdv));
}
#endif
#endif
}
else {
#ifdef __DPDU__
- sd->dPdu = make_float3(0.0f, 0.0f, 0.0f);
- sd->dPdv = make_float3(0.0f, 0.0f, 0.0f);
+ ccl_fetch(sd, dPdu) = make_float3(0.0f, 0.0f, 0.0f);
+ ccl_fetch(sd, dPdv) = make_float3(0.0f, 0.0f, 0.0f);
#endif
}
/* backfacing test */
- if(sd->prim != PRIM_NONE) {
- bool backfacing = (dot(sd->Ng, sd->I) < 0.0f);
+ if(ccl_fetch(sd, prim) != PRIM_NONE) {
+ bool backfacing = (dot(ccl_fetch(sd, Ng), ccl_fetch(sd, I)) < 0.0f);
if(backfacing) {
- sd->flag |= SD_BACKFACING;
- sd->Ng = -sd->Ng;
- sd->N = -sd->N;
+ ccl_fetch(sd, flag) |= SD_BACKFACING;
+ ccl_fetch(sd, Ng) = -ccl_fetch(sd, Ng);
+ ccl_fetch(sd, N) = -ccl_fetch(sd, N);
#ifdef __DPDU__
- sd->dPdu = -sd->dPdu;
- sd->dPdv = -sd->dPdv;
+ ccl_fetch(sd, dPdu) = -ccl_fetch(sd, dPdu);
+ ccl_fetch(sd, dPdv) = -ccl_fetch(sd, dPdv);
#endif
}
}
#ifdef __RAY_DIFFERENTIALS__
/* no ray differentials here yet */
- sd->dP = differential3_zero();
- sd->dI = differential3_zero();
- sd->du = differential_zero();
- sd->dv = differential_zero();
+ ccl_fetch(sd, dP) = differential3_zero();
+ ccl_fetch(sd, dI) = differential3_zero();
+ ccl_fetch(sd, du) = differential_zero();
+ ccl_fetch(sd, dv) = differential_zero();
#endif
}
@@ -355,47 +355,46 @@ ccl_device void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd,
ccl_device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData *sd, const Ray *ray, int bounce, int transparent_bounce)
{
/* vectors */
- sd->P = ray->D;
- sd->N = -ray->D;
- sd->Ng = -ray->D;
- sd->I = -ray->D;
- sd->shader = kernel_data.background.surface_shader;
- sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2);
+ ccl_fetch(sd, P) = ray->D;
+ ccl_fetch(sd, N) = -ray->D;
+ ccl_fetch(sd, Ng) = -ray->D;
+ ccl_fetch(sd, I) = -ray->D;
+ ccl_fetch(sd, shader) = kernel_data.background.surface_shader;
+ ccl_fetch(sd, flag) = kernel_tex_fetch(__shader_flag, (ccl_fetch(sd, shader) & SHADER_MASK)*2);
#ifdef __OBJECT_MOTION__
- sd->time = ray->time;
+ ccl_fetch(sd, time) = ray->time;
#endif
- sd->ray_length = 0.0f;
- sd->ray_depth = bounce;
- sd->transparent_depth = transparent_bounce;
+ ccl_fetch(sd, ray_length) = 0.0f;
+ ccl_fetch(sd, ray_depth) = bounce;
+ ccl_fetch(sd, transparent_depth) = transparent_bounce;
#ifdef __INSTANCING__
- sd->object = PRIM_NONE;
+ ccl_fetch(sd, object) = PRIM_NONE;
#endif
- sd->prim = PRIM_NONE;
+ ccl_fetch(sd, prim) = PRIM_NONE;
#ifdef __UV__
- sd->u = 0.0f;
- sd->v = 0.0f;
+ ccl_fetch(sd, u) = 0.0f;
+ ccl_fetch(sd, v) = 0.0f;
#endif
#ifdef __DPDU__
/* dPdu/dPdv */
- sd->dPdu = make_float3(0.0f, 0.0f, 0.0f);
- sd->dPdv = make_float3(0.0f, 0.0f, 0.0f);
+ ccl_fetch(sd, dPdu) = make_float3(0.0f, 0.0f, 0.0f);
+ ccl_fetch(sd, dPdv) = make_float3(0.0f, 0.0f, 0.0f);
#endif
#ifdef __RAY_DIFFERENTIALS__
/* differentials */
- sd->dP = ray->dD;
- differential_incoming(&sd->dI, sd->dP);
- sd->du.dx = 0.0f;
- sd->du.dy = 0.0f;
- sd->dv.dx = 0.0f;
- sd->dv.dy = 0.0f;
+ ccl_fetch(sd, dP) = ray->dD;
+ differential_incoming(&ccl_fetch(sd, dI), ccl_fetch(sd, dP));
+ ccl_fetch(sd, du) = differential_zero();
+ ccl_fetch(sd, dv) = differential_zero();
#endif
}
/* ShaderData setup from point inside volume */
+#ifdef __VOLUME__
ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *sd, const Ray *ray, int bounce, int transparent_bounce)
{
/* vectors */
@@ -441,6 +440,7 @@ ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *s
sd->ray_P = ray->P;
sd->ray_dP = ray->dP;
}
+#endif
/* Merging */
@@ -493,11 +493,11 @@ ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderDa
{
/* this is the veach one-sample model with balance heuristic, some pdf
* factors drop out when using balance heuristic weighting */
- for(int i = 0; i< sd->num_closure; i++) {
+ for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
if(i == skip_bsdf)
continue;
- const ShaderClosure *sc = &sd->closure[i];
+ const ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
if(CLOSURE_IS_BSDF(sc->type)) {
float bsdf_pdf = 0.0f;
@@ -515,7 +515,7 @@ ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderDa
*pdf = (sum_sample_weight > 0.0f)? sum_pdf/sum_sample_weight: 0.0f;
}
-ccl_device void shader_bsdf_eval(KernelGlobals *kg, const ShaderData *sd,
+ccl_device void shader_bsdf_eval(KernelGlobals *kg, ShaderData *sd,
const float3 omega_in, BsdfEval *eval, float *pdf)
{
bsdf_eval_init(eval, NBUILTIN_CLOSURES, make_float3(0.0f, 0.0f, 0.0f), kernel_data.film.use_light_pass);
@@ -529,22 +529,22 @@ ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
{
int sampled = 0;
- if(sd->num_closure > 1) {
+ if(ccl_fetch(sd, num_closure) > 1) {
/* pick a BSDF closure based on sample weights */
float sum = 0.0f;
- for(sampled = 0; sampled < sd->num_closure; sampled++) {
- const ShaderClosure *sc = &sd->closure[sampled];
+ for(sampled = 0; sampled < ccl_fetch(sd, num_closure); sampled++) {
+ const ShaderClosure *sc = ccl_fetch_array(sd, closure, sampled);
if(CLOSURE_IS_BSDF(sc->type))
sum += sc->sample_weight;
}
- float r = sd->randb_closure*sum;
+ float r = ccl_fetch(sd, randb_closure)*sum;
sum = 0.0f;
- for(sampled = 0; sampled < sd->num_closure; sampled++) {
- const ShaderClosure *sc = &sd->closure[sampled];
+ for(sampled = 0; sampled < ccl_fetch(sd, num_closure); sampled++) {
+ const ShaderClosure *sc = ccl_fetch_array(sd, closure, sampled);
if(CLOSURE_IS_BSDF(sc->type)) {
sum += sc->sample_weight;
@@ -554,13 +554,14 @@ ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
}
}
- if(sampled == sd->num_closure) {
+ if(sampled == ccl_fetch(sd, num_closure)) {
*pdf = 0.0f;
return LABEL_NONE;
}
}
- const ShaderClosure *sc = &sd->closure[sampled];
+ const ShaderClosure *sc = ccl_fetch_array(sd, closure, sampled);
+
int label;
float3 eval;
@@ -570,7 +571,7 @@ ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
if(*pdf != 0.0f) {
bsdf_eval_init(bsdf_eval, sc->type, eval*sc->weight, kernel_data.film.use_light_pass);
- if(sd->num_closure > 1) {
+ if(ccl_fetch(sd, num_closure) > 1) {
float sweight = sc->sample_weight;
_shader_bsdf_multi_eval(kg, sd, *omega_in, pdf, sampled, bsdf_eval, *pdf*sweight, sweight);
}
@@ -597,8 +598,8 @@ ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, const ShaderData *s
ccl_device void shader_bsdf_blur(KernelGlobals *kg, ShaderData *sd, float roughness)
{
- for(int i = 0; i< sd->num_closure; i++) {
- ShaderClosure *sc = &sd->closure[i];
+ for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
if(CLOSURE_IS_BSDF(sc->type))
bsdf_blur(kg, sc, roughness);
@@ -607,13 +608,13 @@ ccl_device void shader_bsdf_blur(KernelGlobals *kg, ShaderData *sd, float roughn
ccl_device float3 shader_bsdf_transparency(KernelGlobals *kg, ShaderData *sd)
{
- if(sd->flag & SD_HAS_ONLY_VOLUME)
+ if(ccl_fetch(sd, flag) & SD_HAS_ONLY_VOLUME)
return make_float3(1.0f, 1.0f, 1.0f);
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
- for(int i = 0; i< sd->num_closure; i++) {
- ShaderClosure *sc = &sd->closure[i];
+ for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
if(sc->type == CLOSURE_BSDF_TRANSPARENT_ID) // todo: make this work for osl
eval += sc->weight;
@@ -636,8 +637,8 @@ ccl_device float3 shader_bsdf_diffuse(KernelGlobals *kg, ShaderData *sd)
{
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
- for(int i = 0; i< sd->num_closure; i++) {
- ShaderClosure *sc = &sd->closure[i];
+ for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
if(CLOSURE_IS_BSDF_DIFFUSE(sc->type))
eval += sc->weight;
@@ -650,8 +651,8 @@ ccl_device float3 shader_bsdf_glossy(KernelGlobals *kg, ShaderData *sd)
{
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
- for(int i = 0; i< sd->num_closure; i++) {
- ShaderClosure *sc = &sd->closure[i];
+ for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
if(CLOSURE_IS_BSDF_GLOSSY(sc->type))
eval += sc->weight;
@@ -664,8 +665,8 @@ ccl_device float3 shader_bsdf_transmission(KernelGlobals *kg, ShaderData *sd)
{
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
- for(int i = 0; i< sd->num_closure; i++) {
- ShaderClosure *sc = &sd->closure[i];
+ for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
if(CLOSURE_IS_BSDF_TRANSMISSION(sc->type))
eval += sc->weight;
@@ -678,8 +679,8 @@ ccl_device float3 shader_bsdf_subsurface(KernelGlobals *kg, ShaderData *sd)
{
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
- for(int i = 0; i< sd->num_closure; i++) {
- ShaderClosure *sc = &sd->closure[i];
+ for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
if(CLOSURE_IS_BSSRDF(sc->type) || CLOSURE_IS_BSDF_BSSRDF(sc->type))
eval += sc->weight;
@@ -693,8 +694,8 @@ ccl_device float3 shader_bsdf_ao(KernelGlobals *kg, ShaderData *sd, float ao_fac
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
float3 N = make_float3(0.0f, 0.0f, 0.0f);
- for(int i = 0; i< sd->num_closure; i++) {
- ShaderClosure *sc = &sd->closure[i];
+ for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
if(CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
eval += sc->weight*ao_factor;
@@ -702,12 +703,12 @@ ccl_device float3 shader_bsdf_ao(KernelGlobals *kg, ShaderData *sd, float ao_fac
}
else if(CLOSURE_IS_AMBIENT_OCCLUSION(sc->type)) {
eval += sc->weight;
- N += sd->N*average(sc->weight);
+ N += ccl_fetch(sd, N)*average(sc->weight);
}
}
if(is_zero(N))
- N = sd->N;
+ N = ccl_fetch(sd, N);
else
N = normalize(N);
@@ -721,8 +722,8 @@ ccl_device float3 shader_bssrdf_sum(ShaderData *sd, float3 *N_, float *texture_b
float3 N = make_float3(0.0f, 0.0f, 0.0f);
float texture_blur = 0.0f, weight_sum = 0.0f;
- for(int i = 0; i< sd->num_closure; i++) {
- ShaderClosure *sc = &sd->closure[i];
+ for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
if(CLOSURE_IS_BSSRDF(sc->type)) {
float avg_weight = fabsf(average(sc->weight));
@@ -735,7 +736,7 @@ ccl_device float3 shader_bssrdf_sum(ShaderData *sd, float3 *N_, float *texture_b
}
if(N_)
- *N_ = (is_zero(N))? sd->N: normalize(N);
+ *N_ = (is_zero(N))? ccl_fetch(sd, N): normalize(N);
if(texture_blur_)
*texture_blur_ = texture_blur/weight_sum;
@@ -747,7 +748,7 @@ ccl_device float3 shader_bssrdf_sum(ShaderData *sd, float3 *N_, float *texture_b
ccl_device float3 emissive_eval(KernelGlobals *kg, ShaderData *sd, ShaderClosure *sc)
{
- return emissive_simple_eval(sd->Ng, sd->I);
+ return emissive_simple_eval(ccl_fetch(sd, Ng), ccl_fetch(sd, I));
}
ccl_device float3 shader_emissive_eval(KernelGlobals *kg, ShaderData *sd)
@@ -755,8 +756,8 @@ ccl_device float3 shader_emissive_eval(KernelGlobals *kg, ShaderData *sd)
float3 eval;
eval = make_float3(0.0f, 0.0f, 0.0f);
- for(int i = 0; i < sd->num_closure; i++) {
- ShaderClosure *sc = &sd->closure[i];
+ for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
if(CLOSURE_IS_EMISSION(sc->type))
eval += emissive_eval(kg, sd, sc)*sc->weight;
@@ -771,8 +772,8 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd)
{
float3 weight = make_float3(0.0f, 0.0f, 0.0f);
- for(int i = 0; i < sd->num_closure; i++) {
- ShaderClosure *sc = &sd->closure[i];
+ for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
if(CLOSURE_IS_HOLDOUT(sc->type))
weight += sc->weight;
@@ -786,8 +787,8 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd)
ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
float randb, int path_flag, ShaderContext ctx)
{
- sd->num_closure = 0;
- sd->randb_closure = randb;
+ ccl_fetch(sd, num_closure) = 0;
+ ccl_fetch(sd, randb_closure) = randb;
#ifdef __OSL__
if(kg->osl)
@@ -798,9 +799,11 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
#ifdef __SVM__
svm_eval_nodes(kg, sd, SHADER_TYPE_SURFACE, path_flag);
#else
- sd->closure->weight = make_float3(0.8f, 0.8f, 0.8f);
- sd->closure->N = sd->N;
- sd->flag |= bsdf_diffuse_setup(&sd->closure);
+ ccl_fetch_array(sd, closure, 0)->weight = make_float3(0.8f, 0.8f, 0.8f);
+ ccl_fetch_array(sd, closure, 0)->N = ccl_fetch(sd, N);
+ ccl_fetch_array(sd, closure, 0)->data0 = 0.0f;
+ ccl_fetch_array(sd, closure, 0)->data1 = 0.0f;
+ ccl_fetch(sd, flag) |= bsdf_diffuse_setup(ccl_fetch_array(sd, closure, 0));
#endif
}
}
@@ -809,8 +812,8 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
ccl_device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx)
{
- sd->num_closure = 0;
- sd->randb_closure = 0.0f;
+ ccl_fetch(sd, num_closure) = 0;
+ ccl_fetch(sd, randb_closure) = 0.0f;
#ifdef __OSL__
if(kg->osl) {
@@ -825,8 +828,8 @@ ccl_device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
- for(int i = 0; i< sd->num_closure; i++) {
- const ShaderClosure *sc = &sd->closure[i];
+ for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
+ const ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
if(CLOSURE_IS_BACKGROUND(sc->type))
eval += sc->weight;
@@ -999,8 +1002,8 @@ ccl_device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,
ccl_device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderContext ctx)
{
- sd->num_closure = 0;
- sd->randb_closure = 0.0f;
+ ccl_fetch(sd, num_closure) = 0;
+ ccl_fetch(sd, randb_closure) = 0.0f;
/* this will modify sd->P */
#ifdef __SVM__
diff --git a/intern/cycles/kernel/kernel_shaderdata_vars.h b/intern/cycles/kernel/kernel_shaderdata_vars.h
new file mode 100644
index 00000000000..b157b82e023
--- /dev/null
+++ b/intern/cycles/kernel/kernel_shaderdata_vars.h
@@ -0,0 +1,99 @@
+/*
+* Copyright 2011-2015 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 SD_VAR
+#define SD_VAR(type, what)
+#endif
+#ifndef SD_CLOSURE_VAR
+#define SD_CLOSURE_VAR(type, what, max_closure)
+#endif
+
+/* position */
+SD_VAR(float3, P)
+/* smooth normal for shading */
+SD_VAR(float3, N)
+/* true geometric normal */
+SD_VAR(float3, Ng)
+/* view/incoming direction */
+SD_VAR(float3, I)
+/* shader id */
+SD_VAR(int, shader)
+/* booleans describing shader, see ShaderDataFlag */
+SD_VAR(int, flag)
+
+/* primitive id if there is one, ~0 otherwise */
+SD_VAR(int, prim)
+
+/* combined type and curve segment for hair */
+SD_VAR(int, type)
+
+/* parametric coordinates
+* - barycentric weights for triangles */
+SD_VAR(float, u)
+SD_VAR(float, v)
+/* object id if there is one, ~0 otherwise */
+SD_VAR(int, object)
+
+/* motion blur sample time */
+SD_VAR(float, time)
+
+/* length of the ray being shaded */
+SD_VAR(float, ray_length)
+
+/* ray bounce depth */
+SD_VAR(int, ray_depth)
+
+/* ray transparent depth */
+SD_VAR(int, transparent_depth)
+
+#ifdef __RAY_DIFFERENTIALS__
+/* differential of P. these are orthogonal to Ng, not N */
+SD_VAR(differential3, dP)
+/* differential of I */
+SD_VAR(differential3, dI)
+/* differential of u, v */
+SD_VAR(differential, du)
+SD_VAR(differential, dv)
+#endif
+#ifdef __DPDU__
+/* differential of P w.r.t. parametric coordinates. note that dPdu is
+* not readily suitable as a tangent for shading on triangles. */
+SD_VAR(float3, dPdu)
+SD_VAR(float3, dPdv)
+#endif
+
+#ifdef __OBJECT_MOTION__
+/* object <-> world space transformations, cached to avoid
+* re-interpolating them constantly for shading */
+SD_VAR(Transform, ob_tfm)
+SD_VAR(Transform, ob_itfm)
+#endif
+
+/* Closure data, we store a fixed array of closures */
+SD_CLOSURE_VAR(ShaderClosure, closure, MAX_CLOSURE)
+SD_VAR(int, num_closure)
+SD_VAR(float, randb_closure)
+
+/* ray start position, only set for backgrounds */
+SD_VAR(float3, ray_P)
+SD_VAR(differential3, ray_dP)
+
+#ifdef __OSL__
+SD_VAR(struct KernelGlobals *, osl_globals)
+#endif
+
+#undef SD_VAR
+#undef SD_CLOSURE_VAR
diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h
index 8923fcebee5..2811a8348ca 100644
--- a/intern/cycles/kernel/kernel_shadow.h
+++ b/intern/cycles/kernel/kernel_shadow.h
@@ -39,19 +39,6 @@ CCL_NAMESPACE_BEGIN
* This is CPU only because of qsort, and malloc or high stack space usage to
* record all these intersections. */
-ccl_device_noinline int shadow_intersections_compare(const void *a, const void *b)
-{
- const Intersection *isect_a = (const Intersection*)a;
- const Intersection *isect_b = (const Intersection*)b;
-
- if(isect_a->t < isect_b->t)
- return -1;
- else if(isect_a->t > isect_b->t)
- return 1;
- else
- return 0;
-}
-
#define STACK_MAX_HITS 64
ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ray, float3 *shadow)
@@ -95,7 +82,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
PathState ps = *state;
#endif
- qsort(hits, num_hits, sizeof(Intersection), shadow_intersections_compare);
+ qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
for(int hit = 0; hit < num_hits; hit++, isect++) {
/* adjust intersection distance for moving ray forward */
@@ -193,19 +180,36 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
* potentially transparent, and only in that case start marching. this gives
* one extra ray cast for the cases were we do want transparency. */
-ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ray, float3 *shadow)
+ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ccl_addr_space PathState *state, ccl_addr_space Ray *ray_input, float3 *shadow
+#ifdef __SPLIT_KERNEL__
+ , ShaderData *sd_mem, Intersection *isect_mem
+#endif
+ )
{
*shadow = make_float3(1.0f, 1.0f, 1.0f);
- if(ray->t == 0.0f)
+ if(ray_input->t == 0.0f)
return false;
- Intersection isect;
- bool blocked = scene_intersect(kg, ray, PATH_RAY_SHADOW_OPAQUE, &isect, NULL, 0.0f, 0.0f);
+#ifdef __SPLIT_KERNEL__
+ Ray private_ray = *ray_input;
+ Ray *ray = &private_ray;
+#else
+ Ray *ray = ray_input;
+#endif
+
+#ifdef __SPLIT_KERNEL__
+ Intersection *isect = isect_mem;
+#else
+ Intersection isect_object;
+ Intersection *isect = &isect_object;
+#endif
+
+ bool blocked = scene_intersect(kg, ray, PATH_RAY_SHADOW_OPAQUE, isect, NULL, 0.0f, 0.0f);
#ifdef __TRANSPARENT_SHADOWS__
if(blocked && kernel_data.integrator.transparent_shadows) {
- if(shader_transparent_shadow(kg, &isect)) {
+ if(shader_transparent_shadow(kg, isect)) {
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
float3 Pend = ray->P + ray->D*ray->t;
int bounce = state->transparent_bounce;
@@ -217,9 +221,8 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
if(bounce >= kernel_data.integrator.transparent_max_bounce)
return true;
- if(!scene_intersect(kg, ray, PATH_RAY_SHADOW_TRANSPARENT, &isect, NULL, 0.0f, 0.0f))
+ if(!scene_intersect(kg, ray, PATH_RAY_SHADOW_TRANSPARENT, isect, NULL, 0.0f, 0.0f))
{
-
#ifdef __VOLUME__
/* attenuation for last line segment towards light */
if(ps.volume_stack[0].shader != SHADER_NONE)
@@ -231,39 +234,44 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
return false;
}
- if(!shader_transparent_shadow(kg, &isect))
+ if(!shader_transparent_shadow(kg, isect))
return true;
#ifdef __VOLUME__
/* attenuation between last surface and next surface */
if(ps.volume_stack[0].shader != SHADER_NONE) {
Ray segment_ray = *ray;
- segment_ray.t = isect.t;
+ segment_ray.t = isect->t;
kernel_volume_shadow(kg, &ps, &segment_ray, &throughput);
}
#endif
/* setup shader data at surface */
- ShaderData sd;
- shader_setup_from_ray(kg, &sd, &isect, ray, state->bounce+1, bounce);
+#ifdef __SPLIT_KERNEL__
+ ShaderData *sd = sd_mem;
+#else
+ ShaderData sd_object;
+ ShaderData *sd = &sd_object;
+#endif
+ shader_setup_from_ray(kg, sd, isect, ray, state->bounce+1, bounce);
/* attenuation from transparent surface */
- if(!(sd.flag & SD_HAS_ONLY_VOLUME)) {
- shader_eval_surface(kg, &sd, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
- throughput *= shader_bsdf_transparency(kg, &sd);
+ if(!(ccl_fetch(sd, flag) & SD_HAS_ONLY_VOLUME)) {
+ shader_eval_surface(kg, sd, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
+ throughput *= shader_bsdf_transparency(kg, sd);
}
if(is_zero(throughput))
return true;
/* move ray forward */
- ray->P = ray_offset(sd.P, -sd.Ng);
+ ray->P = ray_offset(ccl_fetch(sd, P), -ccl_fetch(sd, Ng));
if(ray->t != FLT_MAX)
ray->D = normalize_len(Pend - ray->P, &ray->t);
#ifdef __VOLUME__
/* exit/enter volume */
- kernel_volume_stack_enter_exit(kg, &sd, ps.volume_stack);
+ kernel_volume_stack_enter_exit(kg, sd, ps.volume_stack);
#endif
bounce++;
diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h
index 374dc6d1dd9..f545a056cc8 100644
--- a/intern/cycles/kernel/kernel_textures.h
+++ b/intern/cycles/kernel/kernel_textures.h
@@ -24,6 +24,7 @@
/* bvh */
KERNEL_TEX(float4, texture_float4, __bvh_nodes)
+KERNEL_TEX(float4, texture_float4, __bvh_leaf_nodes)
KERNEL_TEX(float4, texture_float4, __tri_woop)
KERNEL_TEX(uint, texture_uint, __prim_type)
KERNEL_TEX(uint, texture_uint, __prim_visibility)
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 238b4b0bfdc..de108130c6f 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -24,6 +24,13 @@
#define __KERNEL_CPU__
#endif
+/* TODO(sergey): This is only to make it possible to include this header
+ * from outside of the kernel. but this could be done somewhat cleaner?
+ */
+#ifndef ccl_addr_space
+#define ccl_addr_space
+#endif
+
CCL_NAMESPACE_BEGIN
/* constants */
@@ -38,12 +45,6 @@ CCL_NAMESPACE_BEGIN
#define BSSRDF_MIN_RADIUS 1e-8f
#define BSSRDF_MAX_HITS 4
-#define BB_DRAPER 800.0f
-#define BB_MAX_TABLE_RANGE 12000.0f
-#define BB_TABLE_XPOWER 1.5f
-#define BB_TABLE_YPOWER 5.0f
-#define BB_TABLE_SPACING 2.0f
-
#define BECKMANN_TABLE_SIZE 256
#define TEX_NUM_FLOAT_IMAGES 5
@@ -72,6 +73,7 @@ CCL_NAMESPACE_BEGIN
#define __VOLUME_DECOUPLED__
#define __VOLUME_SCATTER__
#define __SHADOW_RECORD_ALL__
+#define __VOLUME_RECORD_ALL__
#endif
#ifdef __KERNEL_CUDA__
@@ -82,7 +84,7 @@ CCL_NAMESPACE_BEGIN
#define __VOLUME_SCATTER__
/* Experimental on GPU */
-#ifdef __KERNEL_CUDA_EXPERIMENTAL__
+#ifdef __KERNEL_EXPERIMENTAL__
#define __SUBSURFACE__
#define __CMJ__
#endif
@@ -94,38 +96,42 @@ CCL_NAMESPACE_BEGIN
/* keep __KERNEL_ADV_SHADING__ in sync with opencl_kernel_use_advanced_shading! */
#ifdef __KERNEL_OPENCL_NVIDIA__
-#define __KERNEL_SHADING__
-#define __KERNEL_ADV_SHADING__
+# define __KERNEL_SHADING__
+# define __KERNEL_ADV_SHADING__
+# ifdef __KERNEL_EXPERIMENTAL__
+# define __CMJ__
+# endif
#endif
#ifdef __KERNEL_OPENCL_APPLE__
-#define __KERNEL_SHADING__
+# define __KERNEL_SHADING__
//#define __KERNEL_ADV_SHADING__
#endif
#ifdef __KERNEL_OPENCL_AMD__
-#define __CL_USE_NATIVE__
-#define __KERNEL_SHADING__
-//__KERNEL_ADV_SHADING__
-#define __MULTI_CLOSURE__
-#define __TRANSPARENT_SHADOWS__
-#define __PASSES__
-#define __BACKGROUND_MIS__
-#define __LAMP_MIS__
-#define __AO__
-//#define __CAMERA_MOTION__
-//#define __OBJECT_MOTION__
-//#define __HAIR__
-//end __KERNEL_ADV_SHADING__
+# define __CL_USE_NATIVE__
+# define __KERNEL_SHADING__
+# define __MULTI_CLOSURE__
+# define __PASSES__
+# define __BACKGROUND_MIS__
+# define __LAMP_MIS__
+# define __AO__
+# define __CAMERA_MOTION__
+# define __OBJECT_MOTION__
+# define __HAIR__
+//#define __TRANSPARENT_SHADOWS__
#endif
#ifdef __KERNEL_OPENCL_INTEL_CPU__
-#define __CL_USE_NATIVE__
-#define __KERNEL_SHADING__
-#define __KERNEL_ADV_SHADING__
+# define __CL_USE_NATIVE__
+# define __KERNEL_SHADING__
+# define __KERNEL_ADV_SHADING__
+# ifdef __KERNEL_EXPERIMENTAL__
+# define __CMJ__
+# endif
#endif
-#endif
+#endif // __KERNEL_OPENCL__
/* kernel features */
#define __SOBOL__
@@ -164,6 +170,17 @@ CCL_NAMESPACE_BEGIN
# define __KERNEL_DEBUG__
#endif
+/* Scene-based selective featrues compilation/ */
+#ifdef __NO_CAMERA_MOTION__
+# undef __CAMERA_MOTION__
+#endif
+#ifdef __NO_OBJECT_MOTION__
+# undef __OBJECT_MOTION__
+#endif
+#ifdef __NO_HAIR__
+# undef __HAIR__
+#endif
+
/* Random Numbers */
typedef uint RNG;
@@ -269,9 +286,7 @@ enum PathRayFlag {
PATH_RAY_MIS_SKIP = 2048,
PATH_RAY_DIFFUSE_ANCESTOR = 4096,
- PATH_RAY_GLOSSY_ANCESTOR = 8192,
- PATH_RAY_BSSRDF_ANCESTOR = 16384,
- PATH_RAY_SINGLE_PASS_DONE = 32768,
+ PATH_RAY_SINGLE_PASS_DONE = 8192,
/* we need layer member flags to be the 20 upper bits */
PATH_RAY_LAYER_SHIFT = (32-20)
@@ -329,7 +344,7 @@ typedef enum PassType {
#ifdef __PASSES__
-typedef struct PathRadiance {
+typedef ccl_addr_space struct PathRadiance {
int use_light_pass;
float3 emission;
@@ -381,7 +396,7 @@ typedef struct BsdfEval {
#else
-typedef float3 PathRadiance;
+typedef ccl_addr_space float3 PathRadiance;
typedef float3 BsdfEval;
#endif
@@ -426,6 +441,7 @@ enum CameraType {
enum PanoramaType {
PANORAMA_EQUIRECTANGULAR,
+ PANORAMA_MIRRORBALL,
PANORAMA_FISHEYE_EQUIDISTANT,
PANORAMA_FISHEYE_EQUISOLID
};
@@ -445,10 +461,26 @@ typedef struct differential {
/* Ray */
typedef struct Ray {
+/* TODO(sergey): This is only needed because current AMD
+ * compiler has hard time building the kernel with this
+ * reshuffle. And at the same time reshuffle will cause
+ * less optimal CPU code in certain places.
+ *
+ * We'll get rid of this nasty exception once AMD compiler
+ * is fixed.
+ */
+#ifndef __KERNEL_OPENCL_AMD__
float3 P; /* origin */
float3 D; /* direction */
+
float t; /* length of the ray */
float time; /* time (for motion blur) */
+#else
+ float t; /* length of the ray */
+ float time; /* time (for motion blur) */
+ float3 P; /* origin */
+ float3 D; /* direction */
+#endif
#ifdef __RAY_DIFFERENTIALS__
differential3 dP;
@@ -458,7 +490,7 @@ typedef struct Ray {
/* Intersection */
-typedef struct Intersection {
+typedef ccl_addr_space struct Intersection {
float t, u, v;
int prim;
int object;
@@ -543,7 +575,11 @@ typedef enum AttributeStandard {
/* Closure data */
#ifdef __MULTI_CLOSURE__
-#define MAX_CLOSURE 64
+# ifndef __MAX_CLOSURE__
+# define MAX_CLOSURE 64
+# else
+# define MAX_CLOSURE __MAX_CLOSURE__
+# endif
#else
#define MAX_CLOSURE 1
#endif
@@ -553,7 +589,7 @@ typedef enum AttributeStandard {
* does not put own padding trying to align this members.
* - We make sure OSL pointer is also 16 bytes aligned.
*/
-typedef struct ShaderClosure {
+typedef ccl_addr_space struct ShaderClosure {
float3 weight;
float3 N;
float3 T;
@@ -638,78 +674,23 @@ enum ShaderDataFlag {
struct KernelGlobals;
-typedef struct ShaderData {
- /* position */
- float3 P;
- /* smooth normal for shading */
- float3 N;
- /* true geometric normal */
- float3 Ng;
- /* view/incoming direction */
- float3 I;
- /* shader id */
- int shader;
- /* booleans describing shader, see ShaderDataFlag */
- int flag;
-
- /* primitive id if there is one, ~0 otherwise */
- int prim;
-
- /* combined type and curve segment for hair */
- int type;
-
- /* parametric coordinates
- * - barycentric weights for triangles */
- float u, v;
- /* object id if there is one, ~0 otherwise */
- int object;
-
- /* motion blur sample time */
- float time;
-
- /* length of the ray being shaded */
- float ray_length;
-
- /* ray bounce depth */
- int ray_depth;
-
- /* ray transparent depth */
- int transparent_depth;
-
-#ifdef __RAY_DIFFERENTIALS__
- /* differential of P. these are orthogonal to Ng, not N */
- differential3 dP;
- /* differential of I */
- differential3 dI;
- /* differential of u, v */
- differential du;
- differential dv;
-#endif
-#ifdef __DPDU__
- /* differential of P w.r.t. parametric coordinates. note that dPdu is
- * not readily suitable as a tangent for shading on triangles. */
- float3 dPdu, dPdv;
-#endif
-
-#ifdef __OBJECT_MOTION__
- /* object <-> world space transformations, cached to avoid
- * re-interpolating them constantly for shading */
- Transform ob_tfm;
- Transform ob_itfm;
+#ifdef __SPLIT_KERNEL__
+#define SD_VAR(type, what) ccl_global type *what;
+#define SD_CLOSURE_VAR(type, what, max_closure) type *what;
+#define TIDX (get_global_id(1) * get_global_size(0) + get_global_id(0))
+#define ccl_fetch(s, t) (s->t[TIDX])
+#define ccl_fetch_array(s, t, index) (&s->t[TIDX * MAX_CLOSURE + index])
+#else
+#define SD_VAR(type, what) type what;
+#define SD_CLOSURE_VAR(type, what, max_closure) type what[max_closure];
+#define ccl_fetch(s, t) (s->t)
+#define ccl_fetch_array(s, t, index) (&s->t[index])
#endif
- /* Closure data, we store a fixed array of closures */
- ShaderClosure closure[MAX_CLOSURE];
- int num_closure;
- float randb_closure;
+typedef ccl_addr_space struct ShaderData {
- /* ray start position, only set for backgrounds */
- float3 ray_P;
- differential3 ray_dP;
+#include "kernel_shaderdata_vars.h"
-#ifdef __OSL__
- struct KernelGlobals *osl_globals;
-#endif
} ShaderData;
/* Path State */
@@ -895,6 +876,11 @@ typedef struct KernelIntegrator {
float inv_pdf_lights;
int pdf_background_res;
+ /* light portals */
+ float portal_pdf;
+ int num_portals;
+ int portal_offset;
+
/* bounces */
int min_bounce;
int max_bounce;
@@ -947,6 +933,8 @@ typedef struct KernelIntegrator {
int volume_max_steps;
float volume_step_size;
int volume_samples;
+
+ int pad;
} KernelIntegrator;
typedef struct KernelBVH {
@@ -957,7 +945,8 @@ typedef struct KernelBVH {
int have_curves;
int have_instancing;
int use_qbvh;
- int pad1, pad2;
+ int use_tri_storage;
+ int pad1;
} KernelBVH;
typedef enum CurveFlag {
@@ -980,9 +969,8 @@ typedef struct KernelCurves {
} KernelCurves;
typedef struct KernelTables {
- int blackbody_offset;
int beckmann_offset;
- int pad1, pad2;
+ int pad1, pad2, pad3;
} KernelTables;
typedef struct KernelData {
@@ -996,13 +984,62 @@ typedef struct KernelData {
} KernelData;
#ifdef __KERNEL_DEBUG__
-typedef struct DebugData {
+typedef ccl_addr_space struct DebugData {
// Total number of BVH node traversal steps and primitives intersections
// for the camera rays.
int num_bvh_traversal_steps;
} DebugData;
#endif
+/* Declarations required for split kernel */
+
+/* Macro for queues */
+/* Value marking queue's empty slot */
+#define QUEUE_EMPTY_SLOT -1
+
+/*
+* Queue 1 - Active rays
+* Queue 2 - Background queue
+* Queue 3 - Shadow ray cast kernel - AO
+* Queeu 4 - Shadow ray cast kernel - direct lighting
+*/
+#define NUM_QUEUES 4
+
+/* Queue names */
+enum QueueNumber {
+ QUEUE_ACTIVE_AND_REGENERATED_RAYS, /* All active rays and regenerated rays are enqueued here */
+ QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS, /* All
+ * 1.Background-hit rays,
+ * 2.Rays that has exited path-iteration but needs to update output buffer
+ * 3.Rays to be regenerated
+ * are enqueued here */
+ QUEUE_SHADOW_RAY_CAST_AO_RAYS, /* All rays for which a shadow ray should be cast to determine radiance
+ contribution for AO are enqueued here */
+ QUEUE_SHADOW_RAY_CAST_DL_RAYS, /* All rays for which a shadow ray should be cast to determine radiance
+ contributuin for direct lighting are enqueued here */
+};
+
+/* We use RAY_STATE_MASK to get ray_state (enums 0 to 5) */
+#define RAY_STATE_MASK 0x007
+#define RAY_FLAG_MASK 0x0F8
+enum RayState {
+ RAY_ACTIVE = 0, // Denotes ray is actively involved in path-iteration
+ RAY_INACTIVE = 1, // Denotes ray has completed processing all samples and is inactive
+ RAY_UPDATE_BUFFER = 2, // Denoted ray has exited path-iteration and needs to update output buffer
+ RAY_HIT_BACKGROUND = 3, // Donotes ray has hit background
+ RAY_TO_REGENERATE = 4, // Denotes ray has to be regenerated
+ RAY_REGENERATED = 5, // Denotes ray has been regenerated
+ RAY_SKIP_DL = 6, // Denotes ray should skip direct lighting
+ RAY_SHADOW_RAY_CAST_AO = 16, // Flag's ray has to execute shadow blocked function in AO part
+ RAY_SHADOW_RAY_CAST_DL = 32 // Flag's ray has to execute shadow blocked function in direct lighting part
+};
+
+#define ASSIGN_RAY_STATE(ray_state, ray_index, state) (ray_state[ray_index] = ((ray_state[ray_index] & RAY_FLAG_MASK) | state))
+#define IS_STATE(ray_state, ray_index, state) ((ray_state[ray_index] & RAY_STATE_MASK) == state)
+#define ADD_RAY_FLAG(ray_state, ray_index, flag) (ray_state[ray_index] = (ray_state[ray_index] | flag))
+#define REMOVE_RAY_FLAG(ray_state, ray_index, flag) (ray_state[ray_index] = (ray_state[ray_index] & (~flag)))
+#define IS_FLAG(ray_state, ray_index, flag) (ray_state[ray_index] & flag)
+
CCL_NAMESPACE_END
#endif /* __KERNEL_TYPES_H__ */
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index 8e67ad5464c..e06568457c6 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -627,7 +627,7 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta
step_size = kernel_data.integrator.volume_step_size;
/* compute exact steps in advance for malloc */
max_steps = max((int)ceilf(ray->t/step_size), 1);
- if (max_steps > global_max_steps) {
+ if(max_steps > global_max_steps) {
max_steps = global_max_steps;
step_size = ray->t / (float)max_steps;
}
@@ -649,6 +649,7 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta
segment->numsteps = 0;
segment->closure_flag = 0;
+ bool is_last_step_empty = false;
VolumeStep *step = segment->steps;
@@ -690,12 +691,24 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta
step->closure_flag = closure_flag;
segment->closure_flag |= closure_flag;
+
+ is_last_step_empty = false;
+ segment->numsteps++;
}
else {
- /* store empty step (todo: skip consecutive empty steps) */
- step->sigma_t = make_float3(0.0f, 0.0f, 0.0f);
- step->sigma_s = make_float3(0.0f, 0.0f, 0.0f);
- step->closure_flag = 0;
+ if(is_last_step_empty) {
+ /* consecutive empty step, merge */
+ step--;
+ }
+ else {
+ /* store empty step */
+ step->sigma_t = make_float3(0.0f, 0.0f, 0.0f);
+ step->sigma_s = make_float3(0.0f, 0.0f, 0.0f);
+ step->closure_flag = 0;
+
+ segment->numsteps++;
+ is_last_step_empty = true;
+ }
}
step->accum_transmittance = accum_transmittance;
@@ -703,8 +716,6 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta
step->t = new_t;
step->shade_t = t + random_jitter_offset;
- segment->numsteps++;
-
/* stop if at the end of the volume */
t = new_t;
if(t == ray->t)
@@ -982,6 +993,48 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
volume_ray.t = FLT_MAX;
int stack_index = 0, enclosed_index = 0;
+
+#ifdef __VOLUME_RECORD_ALL__
+ Intersection hits[2*VOLUME_STACK_SIZE];
+ uint num_hits = scene_intersect_volume_all(kg,
+ &volume_ray,
+ hits,
+ 2*VOLUME_STACK_SIZE);
+ if(num_hits > 0) {
+ int enclosed_volumes[VOLUME_STACK_SIZE];
+ Intersection *isect = hits;
+
+ qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
+
+ for(uint hit = 0; hit < num_hits; ++hit, ++isect) {
+ ShaderData sd;
+ shader_setup_from_ray(kg, &sd, isect, &volume_ray, 0, 0);
+ if(sd.flag & SD_BACKFACING) {
+ /* If ray exited the volume and never entered to that volume
+ * it means that camera is inside such a volume.
+ */
+ bool is_enclosed = false;
+ for(int i = 0; i < enclosed_index; ++i) {
+ if(enclosed_volumes[i] == sd.object) {
+ is_enclosed = true;
+ break;
+ }
+ }
+ if(is_enclosed == false) {
+ stack[stack_index].object = sd.object;
+ stack[stack_index].shader = sd.shader;
+ ++stack_index;
+ }
+ }
+ else {
+ /* If ray from camera enters the volume, this volume shouldn't
+ * be added to the stack on exit.
+ */
+ enclosed_volumes[enclosed_index++] = sd.object;
+ }
+ }
+ }
+#else
int enclosed_volumes[VOLUME_STACK_SIZE];
int step = 0;
@@ -1024,6 +1077,7 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
volume_ray.P = ray_offset(sd.P, -sd.Ng);
++step;
}
+#endif
/* stack_index of 0 means quick checks outside of the kernel gave false
* positive, nothing to worry about, just we've wasted quite a few of
* ticks just to come into conclusion that camera is in the air.
@@ -1086,4 +1140,49 @@ ccl_device void kernel_volume_stack_enter_exit(KernelGlobals *kg, ShaderData *sd
}
}
+#ifdef __SUBSURFACE__
+ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg,
+ Ray *ray,
+ VolumeStack *stack)
+{
+ kernel_assert(kernel_data.integrator.use_volumes);
+
+ Ray volume_ray = *ray;
+
+#ifdef __VOLUME_RECORD_ALL__
+ Intersection hits[2*VOLUME_STACK_SIZE];
+ uint num_hits = scene_intersect_volume_all(kg,
+ &volume_ray,
+ hits,
+ 2*VOLUME_STACK_SIZE);
+ if(num_hits > 0) {
+ Intersection *isect = hits;
+
+ qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
+
+ for(uint hit = 0; hit < num_hits; ++hit, ++isect) {
+ ShaderData sd;
+ shader_setup_from_ray(kg, &sd, isect, &volume_ray, 0, 0);
+ kernel_volume_stack_enter_exit(kg, &sd, stack);
+ }
+ }
+#else
+ Intersection isect;
+ int step = 0;
+ while(step < 2 * VOLUME_STACK_SIZE &&
+ scene_intersect_volume(kg, &volume_ray, &isect))
+ {
+ ShaderData sd;
+ shader_setup_from_ray(kg, &sd, &isect, &volume_ray, 0, 0);
+ kernel_volume_stack_enter_exit(kg, &sd, stack);
+
+ /* Move ray forward. */
+ volume_ray.P = ray_offset(sd.P, -sd.Ng);
+ volume_ray.t -= sd.ray_length;
+ ++step;
+ }
+#endif
+}
+#endif
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_work_stealing.h b/intern/cycles/kernel/kernel_work_stealing.h
new file mode 100644
index 00000000000..9b83d972e97
--- /dev/null
+++ b/intern/cycles/kernel/kernel_work_stealing.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2011-2015 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 __KERNEL_WORK_STEALING_H__
+#define __KERNEL_WORK_STEALING_H__
+
+/*
+ * Utility functions for work stealing
+ */
+
+#ifdef __WORK_STEALING__
+
+#ifdef __KERNEL_OPENCL__
+#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable
+#endif
+
+uint get_group_id_with_ray_index(uint ray_index,
+ uint tile_dim_x,
+ uint tile_dim_y,
+ uint parallel_samples,
+ int dim)
+{
+ if(dim == 0) {
+ uint x_span = ray_index % (tile_dim_x * parallel_samples);
+ return x_span / get_local_size(0);
+ }
+ else /*if(dim == 1)*/ {
+ kernel_assert(dim == 1);
+ uint y_span = ray_index / (tile_dim_x * parallel_samples);
+ return y_span / get_local_size(1);
+ }
+}
+
+uint get_total_work(uint tile_dim_x,
+ uint tile_dim_y,
+ uint grp_idx,
+ uint grp_idy,
+ uint num_samples)
+{
+ uint threads_within_tile_border_x =
+ (grp_idx == (get_num_groups(0) - 1)) ? tile_dim_x % get_local_size(0)
+ : get_local_size(0);
+ uint threads_within_tile_border_y =
+ (grp_idy == (get_num_groups(1) - 1)) ? tile_dim_y % get_local_size(1)
+ : get_local_size(1);
+
+ threads_within_tile_border_x =
+ (threads_within_tile_border_x == 0) ? get_local_size(0)
+ : threads_within_tile_border_x;
+ threads_within_tile_border_y =
+ (threads_within_tile_border_y == 0) ? get_local_size(1)
+ : threads_within_tile_border_y;
+
+ return threads_within_tile_border_x *
+ threads_within_tile_border_y *
+ num_samples;
+}
+
+/* Returns 0 in case there is no next work available */
+/* Returns 1 in case work assigned is valid */
+int get_next_work(ccl_global uint *work_pool,
+ ccl_private uint *my_work,
+ uint tile_dim_x,
+ uint tile_dim_y,
+ uint num_samples,
+ uint parallel_samples,
+ uint ray_index)
+{
+ uint grp_idx = get_group_id_with_ray_index(ray_index,
+ tile_dim_x,
+ tile_dim_y,
+ parallel_samples,
+ 0);
+ uint grp_idy = get_group_id_with_ray_index(ray_index,
+ tile_dim_x,
+ tile_dim_y,
+ parallel_samples,
+ 1);
+ uint total_work = get_total_work(tile_dim_x,
+ tile_dim_y,
+ grp_idx,
+ grp_idy,
+ num_samples);
+ uint group_index = grp_idy * get_num_groups(0) + grp_idx;
+ *my_work = atomic_inc(&work_pool[group_index]);
+ return (*my_work < total_work) ? 1 : 0;
+}
+
+/* This function assumes that the passed my_work is valid. */
+/* Decode sample number w.r.t. assigned my_work. */
+uint get_my_sample(uint my_work,
+ uint tile_dim_x,
+ uint tile_dim_y,
+ uint parallel_samples,
+ uint ray_index)
+{
+ uint grp_idx = get_group_id_with_ray_index(ray_index,
+ tile_dim_x,
+ tile_dim_y,
+ parallel_samples,
+ 0);
+ uint grp_idy = get_group_id_with_ray_index(ray_index,
+ tile_dim_x,
+ tile_dim_y,
+ parallel_samples,
+ 1);
+ uint threads_within_tile_border_x =
+ (grp_idx == (get_num_groups(0) - 1)) ? tile_dim_x % get_local_size(0)
+ : get_local_size(0);
+ uint threads_within_tile_border_y =
+ (grp_idy == (get_num_groups(1) - 1)) ? tile_dim_y % get_local_size(1)
+ : get_local_size(1);
+
+ threads_within_tile_border_x =
+ (threads_within_tile_border_x == 0) ? get_local_size(0)
+ : threads_within_tile_border_x;
+ threads_within_tile_border_y =
+ (threads_within_tile_border_y == 0) ? get_local_size(1)
+ : threads_within_tile_border_y;
+
+ return my_work /
+ (threads_within_tile_border_x * threads_within_tile_border_y);
+}
+
+/* Decode pixel and tile position w.r.t. assigned my_work. */
+void get_pixel_tile_position(ccl_private uint *pixel_x,
+ ccl_private uint *pixel_y,
+ ccl_private uint *tile_x,
+ ccl_private uint *tile_y,
+ uint my_work,
+ uint tile_dim_x,
+ uint tile_dim_y,
+ uint tile_offset_x,
+ uint tile_offset_y,
+ uint parallel_samples,
+ uint ray_index)
+{
+ uint grp_idx = get_group_id_with_ray_index(ray_index,
+ tile_dim_x,
+ tile_dim_y,
+ parallel_samples,
+ 0);
+ uint grp_idy = get_group_id_with_ray_index(ray_index,
+ tile_dim_x,
+ tile_dim_y,
+ parallel_samples,
+ 1);
+ uint threads_within_tile_border_x =
+ (grp_idx == (get_num_groups(0) - 1)) ? tile_dim_x % get_local_size(0)
+ : get_local_size(0);
+ uint threads_within_tile_border_y =
+ (grp_idy == (get_num_groups(1) - 1)) ? tile_dim_y % get_local_size(1)
+ : get_local_size(1);
+
+ threads_within_tile_border_x =
+ (threads_within_tile_border_x == 0) ? get_local_size(0)
+ : threads_within_tile_border_x;
+ threads_within_tile_border_y =
+ (threads_within_tile_border_y == 0) ? get_local_size(1)
+ : threads_within_tile_border_y;
+
+ uint total_associated_pixels =
+ threads_within_tile_border_x * threads_within_tile_border_y;
+ uint work_group_pixel_index = my_work % total_associated_pixels;
+ uint work_group_pixel_x =
+ work_group_pixel_index % threads_within_tile_border_x;
+ uint work_group_pixel_y =
+ work_group_pixel_index / threads_within_tile_border_x;
+
+ *pixel_x =
+ tile_offset_x + (grp_idx * get_local_size(0)) + work_group_pixel_x;
+ *pixel_y =
+ tile_offset_y + (grp_idy * get_local_size(1)) + work_group_pixel_y;
+ *tile_x = *pixel_x - tile_offset_x;
+ *tile_y = *pixel_y - tile_offset_y;
+}
+
+#endif /* __WORK_STEALING__ */
+
+#endif /* __KERNEL_WORK_STEALING_H__ */
diff --git a/intern/cycles/kernel/kernel.cpp b/intern/cycles/kernel/kernels/cpu/kernel.cpp
index 013eeff57fa..a7eaa758f5d 100644
--- a/intern/cycles/kernel/kernel.cpp
+++ b/intern/cycles/kernel/kernels/cpu/kernel.cpp
@@ -55,7 +55,7 @@ void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t
int id = atoi(name + strlen("__tex_image_float_"));
int array_index = id;
- if (array_index >= 0 && array_index < MAX_FLOAT_IMAGES) {
+ if(array_index >= 0 && array_index < MAX_FLOAT_IMAGES) {
tex = &kg->texture_float_images[array_index];
}
@@ -70,7 +70,7 @@ void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t
int id = atoi(name + strlen("__tex_image_"));
int array_index = id - MAX_FLOAT_IMAGES;
- if (array_index >= 0 && array_index < MAX_BYTE_IMAGES) {
+ if(array_index >= 0 && array_index < MAX_BYTE_IMAGES) {
tex = &kg->texture_byte_images[array_index];
}
diff --git a/intern/cycles/kernel/kernel_avx.cpp b/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp
index f1027ad413d..f1027ad413d 100644
--- a/intern/cycles/kernel/kernel_avx.cpp
+++ b/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp
diff --git a/intern/cycles/kernel/kernel_avx2.cpp b/intern/cycles/kernel/kernels/cpu/kernel_avx2.cpp
index b2f16ff54d8..b2f16ff54d8 100644
--- a/intern/cycles/kernel/kernel_avx2.cpp
+++ b/intern/cycles/kernel/kernels/cpu/kernel_avx2.cpp
diff --git a/intern/cycles/kernel/kernel_sse2.cpp b/intern/cycles/kernel/kernels/cpu/kernel_sse2.cpp
index cc8c603e8f8..cc8c603e8f8 100644
--- a/intern/cycles/kernel/kernel_sse2.cpp
+++ b/intern/cycles/kernel/kernels/cpu/kernel_sse2.cpp
diff --git a/intern/cycles/kernel/kernel_sse3.cpp b/intern/cycles/kernel/kernels/cpu/kernel_sse3.cpp
index 20919a4f26e..20919a4f26e 100644
--- a/intern/cycles/kernel/kernel_sse3.cpp
+++ b/intern/cycles/kernel/kernels/cpu/kernel_sse3.cpp
diff --git a/intern/cycles/kernel/kernel_sse41.cpp b/intern/cycles/kernel/kernels/cpu/kernel_sse41.cpp
index 48579d3b7e5..48579d3b7e5 100644
--- a/intern/cycles/kernel/kernel_sse41.cpp
+++ b/intern/cycles/kernel/kernels/cpu/kernel_sse41.cpp
diff --git a/intern/cycles/kernel/kernel.cu b/intern/cycles/kernel/kernels/cuda/kernel.cu
index 64069fc049f..29bf67d9750 100644
--- a/intern/cycles/kernel/kernel.cu
+++ b/intern/cycles/kernel/kernels/cuda/kernel.cu
@@ -16,13 +16,13 @@
/* CUDA kernel entry points */
-#include "kernel_compat_cuda.h"
-#include "kernel_math.h"
-#include "kernel_types.h"
-#include "kernel_globals.h"
-#include "kernel_film.h"
-#include "kernel_path.h"
-#include "kernel_bake.h"
+#include "../../kernel_compat_cuda.h"
+#include "../../kernel_math.h"
+#include "../../kernel_types.h"
+#include "../../kernel_globals.h"
+#include "../../kernel_film.h"
+#include "../../kernel_path.h"
+#include "../../kernel_bake.h"
/* device data taken from CUDA occupancy calculator */
diff --git a/intern/cycles/kernel/kernel.cl b/intern/cycles/kernel/kernels/opencl/kernel.cl
index 5a47260a4ee..bffcd53bab3 100644
--- a/intern/cycles/kernel/kernel.cl
+++ b/intern/cycles/kernel/kernels/opencl/kernel.cl
@@ -16,14 +16,16 @@
/* OpenCL kernel entry points - unfinished */
-#include "kernel_compat_opencl.h"
-#include "kernel_math.h"
-#include "kernel_types.h"
-#include "kernel_globals.h"
+#include "../../kernel_compat_opencl.h"
+#include "../../kernel_math.h"
+#include "../../kernel_types.h"
+#include "../../kernel_globals.h"
-#include "kernel_film.h"
-#include "kernel_path.h"
-#include "kernel_bake.h"
+#include "../../kernel_film.h"
+#include "../../kernel_path.h"
+#include "../../kernel_bake.h"
+
+#ifdef __COMPILE_ONLY_MEGAKERNEL__
__kernel void kernel_ocl_path_trace(
ccl_constant KernelData *data,
@@ -32,7 +34,7 @@ __kernel void kernel_ocl_path_trace(
#define KERNEL_TEX(type, ttype, name) \
ccl_global type *name,
-#include "kernel_textures.h"
+#include "../../kernel_textures.h"
int sample,
int sx, int sy, int sw, int sh, int offset, int stride)
@@ -43,7 +45,7 @@ __kernel void kernel_ocl_path_trace(
#define KERNEL_TEX(type, ttype, name) \
kg->name = name;
-#include "kernel_textures.h"
+#include "../../kernel_textures.h"
int x = sx + get_global_id(0);
int y = sy + get_global_id(1);
@@ -52,17 +54,18 @@ __kernel void kernel_ocl_path_trace(
kernel_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride);
}
-__kernel void kernel_ocl_convert_to_byte(
+#else // __COMPILE_ONLY_MEGAKERNEL__
+
+__kernel void kernel_ocl_shader(
ccl_constant KernelData *data,
- ccl_global uchar4 *rgba,
- ccl_global float *buffer,
+ ccl_global uint4 *input,
+ ccl_global float4 *output,
#define KERNEL_TEX(type, ttype, name) \
ccl_global type *name,
-#include "kernel_textures.h"
+#include "../../kernel_textures.h"
- float sample_scale,
- int sx, int sy, int sw, int sh, int offset, int stride)
+ int type, int sx, int sw, int offset, int sample)
{
KernelGlobals kglobals, *kg = &kglobals;
@@ -70,26 +73,24 @@ __kernel void kernel_ocl_convert_to_byte(
#define KERNEL_TEX(type, ttype, name) \
kg->name = name;
-#include "kernel_textures.h"
+#include "../../kernel_textures.h"
int x = sx + get_global_id(0);
- int y = sy + get_global_id(1);
- if(x < sx + sw && y < sy + sh)
- kernel_film_convert_to_byte(kg, rgba, buffer, sample_scale, x, y, offset, stride);
+ if(x < sx + sw)
+ kernel_shader_evaluate(kg, input, output, (ShaderEvalType)type, x, sample);
}
-__kernel void kernel_ocl_convert_to_half_float(
+__kernel void kernel_ocl_bake(
ccl_constant KernelData *data,
- ccl_global uchar4 *rgba,
- ccl_global float *buffer,
+ ccl_global uint4 *input,
+ ccl_global float4 *output,
#define KERNEL_TEX(type, ttype, name) \
ccl_global type *name,
-#include "kernel_textures.h"
+#include "../../kernel_textures.h"
- float sample_scale,
- int sx, int sy, int sw, int sh, int offset, int stride)
+ int type, int sx, int sw, int offset, int sample)
{
KernelGlobals kglobals, *kg = &kglobals;
@@ -97,25 +98,36 @@ __kernel void kernel_ocl_convert_to_half_float(
#define KERNEL_TEX(type, ttype, name) \
kg->name = name;
-#include "kernel_textures.h"
+#include "../../kernel_textures.h"
int x = sx + get_global_id(0);
- int y = sy + get_global_id(1);
- if(x < sx + sw && y < sy + sh)
- kernel_film_convert_to_half_float(kg, rgba, buffer, sample_scale, x, y, offset, stride);
+ if(x < sx + sw) {
+#if defined(__KERNEL_OPENCL_NVIDIA__) && __COMPUTE_CAPABILITY__ < 300
+ /* NVidia compiler is spending infinite amount of time trying
+ * to deal with kernel_bake_evaluate() on architectures prior
+ * to sm_30.
+ * For now we disable baking kernel for those devices, so at
+ * least rendering with split kernel could be compiled.
+ */
+ output[x] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+#else
+ kernel_bake_evaluate(kg, input, output, (ShaderEvalType)type, x, offset, sample);
+#endif
+ }
}
-__kernel void kernel_ocl_shader(
+__kernel void kernel_ocl_convert_to_byte(
ccl_constant KernelData *data,
- ccl_global uint4 *input,
- ccl_global float4 *output,
+ ccl_global uchar4 *rgba,
+ ccl_global float *buffer,
#define KERNEL_TEX(type, ttype, name) \
ccl_global type *name,
-#include "kernel_textures.h"
+#include "../../kernel_textures.h"
- int type, int sx, int sw, int offset, int sample)
+ float sample_scale,
+ int sx, int sy, int sw, int sh, int offset, int stride)
{
KernelGlobals kglobals, *kg = &kglobals;
@@ -123,24 +135,26 @@ __kernel void kernel_ocl_shader(
#define KERNEL_TEX(type, ttype, name) \
kg->name = name;
-#include "kernel_textures.h"
+#include "../../kernel_textures.h"
int x = sx + get_global_id(0);
+ int y = sy + get_global_id(1);
- if(x < sx + sw)
- kernel_shader_evaluate(kg, input, output, (ShaderEvalType)type, x, sample);
+ if(x < sx + sw && y < sy + sh)
+ kernel_film_convert_to_byte(kg, rgba, buffer, sample_scale, x, y, offset, stride);
}
-__kernel void kernel_ocl_bake(
+__kernel void kernel_ocl_convert_to_half_float(
ccl_constant KernelData *data,
- ccl_global uint4 *input,
- ccl_global float4 *output,
+ ccl_global uchar4 *rgba,
+ ccl_global float *buffer,
#define KERNEL_TEX(type, ttype, name) \
ccl_global type *name,
-#include "kernel_textures.h"
+#include "../../kernel_textures.h"
- int type, int sx, int sw, int offset, int sample)
+ float sample_scale,
+ int sx, int sy, int sw, int sh, int offset, int stride)
{
KernelGlobals kglobals, *kg = &kglobals;
@@ -148,11 +162,13 @@ __kernel void kernel_ocl_bake(
#define KERNEL_TEX(type, ttype, name) \
kg->name = name;
-#include "kernel_textures.h"
+#include "../../kernel_textures.h"
int x = sx + get_global_id(0);
+ int y = sy + get_global_id(1);
- if(x < sx + sw)
- kernel_bake_evaluate(kg, input, output, (ShaderEvalType)type, x, offset, sample);
+ if(x < sx + sw && y < sy + sh)
+ kernel_film_convert_to_half_float(kg, rgba, buffer, sample_scale, x, y, offset, stride);
}
+#endif // __COMPILE_ONLY_MEGAKERNEL__ \ No newline at end of file
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_background_buffer_update.cl b/intern/cycles/kernel/kernels/opencl/kernel_background_buffer_update.cl
new file mode 100644
index 00000000000..eff77b89a0a
--- /dev/null
+++ b/intern/cycles/kernel/kernels/opencl/kernel_background_buffer_update.cl
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2011-2015 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 "split/kernel_background_buffer_update.h"
+
+__kernel void kernel_ocl_path_trace_background_buffer_update(
+ ccl_global char *globals,
+ ccl_constant KernelData *data,
+ ccl_global char *shader_data,
+ ccl_global float *per_sample_output_buffers,
+ ccl_global uint *rng_state,
+ ccl_global uint *rng_coop, /* Required for buffer Update */
+ ccl_global float3 *throughput_coop, /* Required for background hit processing */
+ PathRadiance *PathRadiance_coop, /* Required for background hit processing and buffer Update */
+ ccl_global Ray *Ray_coop, /* Required for background hit processing */
+ ccl_global PathState *PathState_coop, /* Required for background hit processing */
+ ccl_global float *L_transparent_coop, /* Required for background hit processing and buffer Update */
+ ccl_global char *ray_state, /* Stores information on the current state of a ray */
+ int sw, int sh, int sx, int sy, int stride,
+ int rng_state_offset_x,
+ int rng_state_offset_y,
+ int rng_state_stride,
+ ccl_global unsigned int *work_array, /* Denotes work of each ray */
+ ccl_global int *Queue_data, /* Queues memory */
+ ccl_global int *Queue_index, /* Tracks the number of elements in each queue */
+ int queuesize, /* Size (capacity) of each queue */
+ int end_sample,
+ int start_sample,
+#ifdef __WORK_STEALING__
+ ccl_global unsigned int *work_pool_wgs,
+ unsigned int num_samples,
+#endif
+#ifdef __KERNEL_DEBUG__
+ DebugData *debugdata_coop,
+#endif
+ int parallel_samples) /* Number of samples to be processed in parallel */
+{
+ ccl_local unsigned int local_queue_atomics;
+ if(get_local_id(0) == 0 && get_local_id(1) == 0) {
+ local_queue_atomics = 0;
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ int ray_index = get_global_id(1) * get_global_size(0) + get_global_id(0);
+ if(ray_index == 0) {
+ /* We will empty this queue in this kernel. */
+ Queue_index[QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS] = 0;
+ }
+ char enqueue_flag = 0;
+ ray_index = get_ray_index(ray_index,
+ QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS,
+ Queue_data,
+ queuesize,
+ 1);
+
+#ifdef __COMPUTE_DEVICE_GPU__
+ /* If we are executing on a GPU device, we exit all threads that are not
+ * required.
+ *
+ * If we are executing on a CPU device, then we need to keep all threads
+ * active since we have barrier() calls later in the kernel. CPU devices,
+ * expect all threads to execute barrier statement.
+ */
+ if(ray_index == QUEUE_EMPTY_SLOT) {
+ return;
+ }
+#endif
+
+#ifndef __COMPUTE_DEVICE_GPU__
+ if(ray_index != QUEUE_EMPTY_SLOT) {
+#endif
+ enqueue_flag =
+ kernel_background_buffer_update(globals,
+ data,
+ shader_data,
+ per_sample_output_buffers,
+ rng_state,
+ rng_coop,
+ throughput_coop,
+ PathRadiance_coop,
+ Ray_coop,
+ PathState_coop,
+ L_transparent_coop,
+ ray_state,
+ sw, sh, sx, sy, stride,
+ rng_state_offset_x,
+ rng_state_offset_y,
+ rng_state_stride,
+ work_array,
+ end_sample,
+ start_sample,
+#ifdef __WORK_STEALING__
+ work_pool_wgs,
+ num_samples,
+#endif
+#ifdef __KERNEL_DEBUG__
+ debugdata_coop,
+#endif
+ parallel_samples,
+ ray_index);
+#ifndef __COMPUTE_DEVICE_GPU__
+ }
+#endif
+
+ /* Enqueue RAY_REGENERATED rays into QUEUE_ACTIVE_AND_REGENERATED_RAYS;
+ * These rays will be made active during next SceneIntersectkernel.
+ */
+ enqueue_ray_index_local(ray_index,
+ QUEUE_ACTIVE_AND_REGENERATED_RAYS,
+ enqueue_flag,
+ queuesize,
+ &local_queue_atomics,
+ Queue_data,
+ Queue_index);
+}
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_data_init.cl b/intern/cycles/kernel/kernels/opencl/kernel_data_init.cl
new file mode 100644
index 00000000000..c3277676029
--- /dev/null
+++ b/intern/cycles/kernel/kernels/opencl/kernel_data_init.cl
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2011-2015 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 "split/kernel_data_init.h"
+
+__kernel void kernel_ocl_path_trace_data_init(
+ ccl_global char *globals,
+ ccl_global char *shader_data_sd, /* Arguments related to ShaderData */
+ ccl_global char *shader_data_sd_DL_shadow, /* Arguments related to ShaderData */
+
+ ccl_global float3 *P_sd,
+ ccl_global float3 *P_sd_DL_shadow,
+
+ ccl_global float3 *N_sd,
+ ccl_global float3 *N_sd_DL_shadow,
+
+ ccl_global float3 *Ng_sd,
+ ccl_global float3 *Ng_sd_DL_shadow,
+
+ ccl_global float3 *I_sd,
+ ccl_global float3 *I_sd_DL_shadow,
+
+ ccl_global int *shader_sd,
+ ccl_global int *shader_sd_DL_shadow,
+
+ ccl_global int *flag_sd,
+ ccl_global int *flag_sd_DL_shadow,
+
+ ccl_global int *prim_sd,
+ ccl_global int *prim_sd_DL_shadow,
+
+ ccl_global int *type_sd,
+ ccl_global int *type_sd_DL_shadow,
+
+ ccl_global float *u_sd,
+ ccl_global float *u_sd_DL_shadow,
+
+ ccl_global float *v_sd,
+ ccl_global float *v_sd_DL_shadow,
+
+ ccl_global int *object_sd,
+ ccl_global int *object_sd_DL_shadow,
+
+ ccl_global float *time_sd,
+ ccl_global float *time_sd_DL_shadow,
+
+ ccl_global float *ray_length_sd,
+ ccl_global float *ray_length_sd_DL_shadow,
+
+ ccl_global int *ray_depth_sd,
+ ccl_global int *ray_depth_sd_DL_shadow,
+
+ ccl_global int *transparent_depth_sd,
+ ccl_global int *transparent_depth_sd_DL_shadow,
+
+ /* Ray differentials. */
+ ccl_global differential3 *dP_sd,
+ ccl_global differential3 *dP_sd_DL_shadow,
+
+ ccl_global differential3 *dI_sd,
+ ccl_global differential3 *dI_sd_DL_shadow,
+
+ ccl_global differential *du_sd,
+ ccl_global differential *du_sd_DL_shadow,
+
+ ccl_global differential *dv_sd,
+ ccl_global differential *dv_sd_DL_shadow,
+
+ /* Dp/Du */
+ ccl_global float3 *dPdu_sd,
+ ccl_global float3 *dPdu_sd_DL_shadow,
+
+ ccl_global float3 *dPdv_sd,
+ ccl_global float3 *dPdv_sd_DL_shadow,
+
+ /* Object motion. */
+ ccl_global Transform *ob_tfm_sd,
+ ccl_global Transform *ob_tfm_sd_DL_shadow,
+
+ ccl_global Transform *ob_itfm_sd,
+ ccl_global Transform *ob_itfm_sd_DL_shadow,
+
+ ShaderClosure *closure_sd,
+ ShaderClosure *closure_sd_DL_shadow,
+
+ ccl_global int *num_closure_sd,
+ ccl_global int *num_closure_sd_DL_shadow,
+
+ ccl_global float *randb_closure_sd,
+ ccl_global float *randb_closure_sd_DL_shadow,
+
+ ccl_global float3 *ray_P_sd,
+ ccl_global float3 *ray_P_sd_DL_shadow,
+
+ ccl_global differential3 *ray_dP_sd,
+ ccl_global differential3 *ray_dP_sd_DL_shadow,
+
+ ccl_constant KernelData *data,
+ ccl_global float *per_sample_output_buffers,
+ ccl_global uint *rng_state,
+ ccl_global uint *rng_coop, /* rng array to store rng values for all rays */
+ ccl_global float3 *throughput_coop, /* throughput array to store throughput values for all rays */
+ ccl_global float *L_transparent_coop, /* L_transparent array to store L_transparent values for all rays */
+ PathRadiance *PathRadiance_coop, /* PathRadiance array to store PathRadiance values for all rays */
+ ccl_global Ray *Ray_coop, /* Ray array to store Ray information for all rays */
+ ccl_global PathState *PathState_coop, /* PathState array to store PathState information for all rays */
+ ccl_global char *ray_state, /* Stores information on current state of a ray */
+
+#define KERNEL_TEX(type, ttype, name) \
+ ccl_global type *name,
+#include "../../kernel_textures.h"
+
+ int start_sample, int sx, int sy, int sw, int sh, int offset, int stride,
+ int rng_state_offset_x,
+ int rng_state_offset_y,
+ int rng_state_stride,
+ ccl_global int *Queue_data, /* Memory for queues */
+ ccl_global int *Queue_index, /* Tracks the number of elements in queues */
+ int queuesize, /* size (capacity) of the queue */
+ ccl_global char *use_queues_flag, /* flag to decide if scene-intersect kernel should use queues to fetch ray index */
+ ccl_global unsigned int *work_array, /* work array to store which work each ray belongs to */
+#ifdef __WORK_STEALING__
+ ccl_global unsigned int *work_pool_wgs, /* Work pool for each work group */
+ unsigned int num_samples, /* Total number of samples per pixel */
+#endif
+#ifdef __KERNEL_DEBUG__
+ DebugData *debugdata_coop,
+#endif
+ int parallel_samples) /* Number of samples to be processed in parallel */
+{
+ kernel_data_init(globals,
+ shader_data_sd,
+ shader_data_sd_DL_shadow,
+ P_sd,
+ P_sd_DL_shadow,
+ N_sd,
+ N_sd_DL_shadow,
+ Ng_sd,
+ Ng_sd_DL_shadow,
+ I_sd,
+ I_sd_DL_shadow,
+ shader_sd,
+ shader_sd_DL_shadow,
+ flag_sd,
+ flag_sd_DL_shadow,
+ prim_sd,
+ prim_sd_DL_shadow,
+ type_sd,
+ type_sd_DL_shadow,
+ u_sd,
+ u_sd_DL_shadow,
+ v_sd,
+ v_sd_DL_shadow,
+ object_sd,
+ object_sd_DL_shadow,
+ time_sd,
+ time_sd_DL_shadow,
+ ray_length_sd,
+ ray_length_sd_DL_shadow,
+ ray_depth_sd,
+ ray_depth_sd_DL_shadow,
+ transparent_depth_sd,
+ transparent_depth_sd_DL_shadow,
+
+ /* Ray differentials. */
+ dP_sd,
+ dP_sd_DL_shadow,
+ dI_sd,
+ dI_sd_DL_shadow,
+ du_sd,
+ du_sd_DL_shadow,
+ dv_sd,
+ dv_sd_DL_shadow,
+
+ /* Dp/Du */
+ dPdu_sd,
+ dPdu_sd_DL_shadow,
+ dPdv_sd,
+ dPdv_sd_DL_shadow,
+
+ /* Object motion. */
+ ob_tfm_sd,
+ ob_tfm_sd_DL_shadow,
+ ob_itfm_sd,
+ ob_itfm_sd_DL_shadow,
+
+ closure_sd,
+ closure_sd_DL_shadow,
+ num_closure_sd,
+ num_closure_sd_DL_shadow,
+ randb_closure_sd,
+ randb_closure_sd_DL_shadow,
+ ray_P_sd,
+ ray_P_sd_DL_shadow,
+ ray_dP_sd,
+ ray_dP_sd_DL_shadow,
+ data,
+ per_sample_output_buffers,
+ rng_state,
+ rng_coop,
+ throughput_coop,
+ L_transparent_coop,
+ PathRadiance_coop,
+ Ray_coop,
+ PathState_coop,
+ ray_state,
+
+#define KERNEL_TEX(type, ttype, name) name,
+#include "../../kernel_textures.h"
+
+ start_sample, sx, sy, sw, sh, offset, stride,
+ rng_state_offset_x,
+ rng_state_offset_y,
+ rng_state_stride,
+ Queue_data,
+ Queue_index,
+ queuesize,
+ use_queues_flag,
+ work_array,
+#ifdef __WORK_STEALING__
+ work_pool_wgs,
+ num_samples,
+#endif
+#ifdef __KERNEL_DEBUG__
+ debugdata_coop,
+#endif
+ parallel_samples);
+}
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_direct_lighting.cl b/intern/cycles/kernel/kernels/opencl/kernel_direct_lighting.cl
new file mode 100644
index 00000000000..6ec75013b3a
--- /dev/null
+++ b/intern/cycles/kernel/kernels/opencl/kernel_direct_lighting.cl
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2011-2015 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 "split/kernel_direct_lighting.h"
+
+__kernel void kernel_ocl_path_trace_direct_lighting(
+ ccl_global char *globals,
+ ccl_constant KernelData *data,
+ ccl_global char *shader_data, /* Required for direct lighting */
+ ccl_global char *shader_DL, /* Required for direct lighting */
+ ccl_global uint *rng_coop, /* Required for direct lighting */
+ ccl_global PathState *PathState_coop, /* Required for direct lighting */
+ ccl_global int *ISLamp_coop, /* Required for direct lighting */
+ ccl_global Ray *LightRay_coop, /* Required for direct lighting */
+ ccl_global BsdfEval *BSDFEval_coop, /* Required for direct lighting */
+ ccl_global char *ray_state, /* Denotes the state of each ray */
+ ccl_global int *Queue_data, /* Queue memory */
+ ccl_global int *Queue_index, /* Tracks the number of elements in each queue */
+ int queuesize) /* Size (capacity) of each queue */
+{
+ ccl_local unsigned int local_queue_atomics;
+ if(get_local_id(0) == 0 && get_local_id(1) == 0) {
+ local_queue_atomics = 0;
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ char enqueue_flag = 0;
+ int ray_index = get_global_id(1) * get_global_size(0) + get_global_id(0);
+ ray_index = get_ray_index(ray_index,
+ QUEUE_ACTIVE_AND_REGENERATED_RAYS,
+ Queue_data,
+ queuesize,
+ 0);
+
+#ifdef __COMPUTE_DEVICE_GPU__
+ /* If we are executing on a GPU device, we exit all threads that are not
+ * required.
+ *
+ * If we are executing on a CPU device, then we need to keep all threads
+ * active since we have barrier() calls later in the kernel. CPU devices,
+ * expect all threads to execute barrier statement.
+ */
+ if(ray_index == QUEUE_EMPTY_SLOT) {
+ return;
+ }
+#endif
+
+#ifndef __COMPUTE_DEVICE_GPU__
+ if(ray_index != QUEUE_EMPTY_SLOT) {
+#endif
+ enqueue_flag = kernel_direct_lighting(globals,
+ data,
+ shader_data,
+ shader_DL,
+ rng_coop,
+ PathState_coop,
+ ISLamp_coop,
+ LightRay_coop,
+ BSDFEval_coop,
+ ray_state,
+ ray_index);
+
+#ifndef __COMPUTE_DEVICE_GPU__
+ }
+#endif
+
+#ifdef __EMISSION__
+ /* Enqueue RAY_SHADOW_RAY_CAST_DL rays. */
+ enqueue_ray_index_local(ray_index,
+ QUEUE_SHADOW_RAY_CAST_DL_RAYS,
+ enqueue_flag,
+ queuesize,
+ &local_queue_atomics,
+ Queue_data,
+ Queue_index);
+#endif
+}
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl b/intern/cycles/kernel/kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl
new file mode 100644
index 00000000000..ae5f5cd1b3b
--- /dev/null
+++ b/intern/cycles/kernel/kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2011-2015 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 "split/kernel_holdout_emission_blurring_pathtermination_ao.h"
+
+__kernel void kernel_ocl_path_trace_holdout_emission_blurring_pathtermination_ao(
+ ccl_global char *globals,
+ ccl_constant KernelData *data,
+ ccl_global char *shader_data, /* Required throughout the kernel except probabilistic path termination and AO */
+ ccl_global float *per_sample_output_buffers,
+ ccl_global uint *rng_coop, /* Required for "kernel_write_data_passes" and AO */
+ ccl_global float3 *throughput_coop, /* Required for handling holdout material and AO */
+ ccl_global float *L_transparent_coop, /* Required for handling holdout material */
+ PathRadiance *PathRadiance_coop, /* Required for "kernel_write_data_passes" and indirect primitive emission */
+ ccl_global PathState *PathState_coop, /* Required throughout the kernel and AO */
+ Intersection *Intersection_coop, /* Required for indirect primitive emission */
+ ccl_global float3 *AOAlpha_coop, /* Required for AO */
+ ccl_global float3 *AOBSDF_coop, /* Required for AO */
+ ccl_global Ray *AOLightRay_coop, /* Required for AO */
+ int sw, int sh, int sx, int sy, int stride,
+ ccl_global char *ray_state, /* Denotes the state of each ray */
+ ccl_global unsigned int *work_array, /* Denotes the work that each ray belongs to */
+ ccl_global int *Queue_data, /* Queue memory */
+ ccl_global int *Queue_index, /* Tracks the number of elements in each queue */
+ int queuesize, /* Size (capacity) of each queue */
+#ifdef __WORK_STEALING__
+ unsigned int start_sample,
+#endif
+ int parallel_samples) /* Number of samples to be processed in parallel */
+{
+ ccl_local unsigned int local_queue_atomics_bg;
+ ccl_local unsigned int local_queue_atomics_ao;
+ if(get_local_id(0) == 0 && get_local_id(1) == 0) {
+ local_queue_atomics_bg = 0;
+ local_queue_atomics_ao = 0;
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ char enqueue_flag = 0;
+ char enqueue_flag_AO_SHADOW_RAY_CAST = 0;
+ int ray_index = get_global_id(1) * get_global_size(0) + get_global_id(0);
+ ray_index = get_ray_index(ray_index,
+ QUEUE_ACTIVE_AND_REGENERATED_RAYS,
+ Queue_data,
+ queuesize,
+ 0);
+
+#ifdef __COMPUTE_DEVICE_GPU__
+ /* If we are executing on a GPU device, we exit all threads that are not
+ * required.
+ *
+ * If we are executing on a CPU device, then we need to keep all threads
+ * active since we have barrier() calls later in the kernel. CPU devices,
+ * expect all threads to execute barrier statement.
+ */
+ if(ray_index == QUEUE_EMPTY_SLOT) {
+ return;
+ }
+#endif /* __COMPUTE_DEVICE_GPU__ */
+
+#ifndef __COMPUTE_DEVICE_GPU__
+ if(ray_index != QUEUE_EMPTY_SLOT) {
+#endif
+ kernel_holdout_emission_blurring_pathtermination_ao(
+ globals,
+ data,
+ shader_data,
+ per_sample_output_buffers,
+ rng_coop,
+ throughput_coop,
+ L_transparent_coop,
+ PathRadiance_coop,
+ PathState_coop,
+ Intersection_coop,
+ AOAlpha_coop,
+ AOBSDF_coop,
+ AOLightRay_coop,
+ sw, sh, sx, sy, stride,
+ ray_state,
+ work_array,
+#ifdef __WORK_STEALING__
+ start_sample,
+#endif
+ parallel_samples,
+ ray_index,
+ &enqueue_flag,
+ &enqueue_flag_AO_SHADOW_RAY_CAST);
+#ifndef __COMPUTE_DEVICE_GPU__
+ }
+#endif
+
+ /* Enqueue RAY_UPDATE_BUFFER rays. */
+ enqueue_ray_index_local(ray_index,
+ QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS,
+ enqueue_flag,
+ queuesize,
+ &local_queue_atomics_bg,
+ Queue_data,
+ Queue_index);
+
+#ifdef __AO__
+ /* Enqueue to-shadow-ray-cast rays. */
+ enqueue_ray_index_local(ray_index,
+ QUEUE_SHADOW_RAY_CAST_AO_RAYS,
+ enqueue_flag_AO_SHADOW_RAY_CAST,
+ queuesize,
+ &local_queue_atomics_ao,
+ Queue_data,
+ Queue_index);
+#endif
+}
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_lamp_emission.cl b/intern/cycles/kernel/kernels/opencl/kernel_lamp_emission.cl
new file mode 100644
index 00000000000..1bc7808d834
--- /dev/null
+++ b/intern/cycles/kernel/kernels/opencl/kernel_lamp_emission.cl
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2011-2015 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 "split/kernel_lamp_emission.h"
+
+__kernel void kernel_ocl_path_trace_lamp_emission(
+ ccl_global char *globals,
+ ccl_constant KernelData *data,
+ ccl_global char *shader_data, /* Required for lamp emission */
+ ccl_global float3 *throughput_coop, /* Required for lamp emission */
+ PathRadiance *PathRadiance_coop, /* Required for lamp emission */
+ ccl_global Ray *Ray_coop, /* Required for lamp emission */
+ ccl_global PathState *PathState_coop, /* Required for lamp emission */
+ Intersection *Intersection_coop, /* Required for lamp emission */
+ ccl_global char *ray_state, /* Denotes the state of each ray */
+ int sw, int sh,
+ ccl_global int *Queue_data, /* Memory for queues */
+ ccl_global int *Queue_index, /* Tracks the number of elements in queues */
+ int queuesize, /* Size (capacity) of queues */
+ ccl_global char *use_queues_flag, /* Used to decide if this kernel should use
+ * queues to fetch ray index
+ */
+ int parallel_samples) /* Number of samples to be processed in parallel */
+{
+ int x = get_global_id(0);
+ int y = get_global_id(1);
+
+ /* We will empty this queue in this kernel. */
+ if(get_global_id(0) == 0 && get_global_id(1) == 0) {
+ Queue_index[QUEUE_ACTIVE_AND_REGENERATED_RAYS] = 0;
+ }
+ /* Fetch use_queues_flag. */
+ ccl_local char local_use_queues_flag;
+ if(get_local_id(0) == 0 && get_local_id(1) == 0) {
+ local_use_queues_flag = use_queues_flag[0];
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ int ray_index;
+ if(local_use_queues_flag) {
+ int thread_index = get_global_id(1) * get_global_size(0) + get_global_id(0);
+ ray_index = get_ray_index(thread_index,
+ QUEUE_ACTIVE_AND_REGENERATED_RAYS,
+ Queue_data,
+ queuesize,
+ 1);
+ if(ray_index == QUEUE_EMPTY_SLOT) {
+ return;
+ }
+ } else {
+ if(x < (sw * parallel_samples) && y < sh){
+ ray_index = x + y * (sw * parallel_samples);
+ } else {
+ return;
+ }
+ }
+
+ kernel_lamp_emission(globals,
+ data,
+ shader_data,
+ throughput_coop,
+ PathRadiance_coop,
+ Ray_coop,
+ PathState_coop,
+ Intersection_coop,
+ ray_state,
+ sw, sh,
+ use_queues_flag,
+ parallel_samples,
+ ray_index);
+}
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_next_iteration_setup.cl b/intern/cycles/kernel/kernels/opencl/kernel_next_iteration_setup.cl
new file mode 100644
index 00000000000..dcf4db40411
--- /dev/null
+++ b/intern/cycles/kernel/kernels/opencl/kernel_next_iteration_setup.cl
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2011-2015 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 "split/kernel_next_iteration_setup.h"
+
+__kernel void kernel_ocl_path_trace_next_iteration_setup(
+ ccl_global char *globals,
+ ccl_constant KernelData *data,
+ ccl_global char *shader_data, /* Required for setting up ray for next iteration */
+ ccl_global uint *rng_coop, /* Required for setting up ray for next iteration */
+ ccl_global float3 *throughput_coop, /* Required for setting up ray for next iteration */
+ PathRadiance *PathRadiance_coop, /* Required for setting up ray for next iteration */
+ ccl_global Ray *Ray_coop, /* Required for setting up ray for next iteration */
+ ccl_global PathState *PathState_coop, /* Required for setting up ray for next iteration */
+ ccl_global Ray *LightRay_dl_coop, /* Required for radiance update - direct lighting */
+ ccl_global int *ISLamp_coop, /* Required for radiance update - direct lighting */
+ ccl_global BsdfEval *BSDFEval_coop, /* Required for radiance update - direct lighting */
+ ccl_global Ray *LightRay_ao_coop, /* Required for radiance update - AO */
+ ccl_global float3 *AOBSDF_coop, /* Required for radiance update - AO */
+ ccl_global float3 *AOAlpha_coop, /* Required for radiance update - AO */
+ ccl_global char *ray_state, /* Denotes the state of each ray */
+ ccl_global int *Queue_data, /* Queue memory */
+ ccl_global int *Queue_index, /* Tracks the number of elements in each queue */
+ int queuesize, /* Size (capacity) of each queue */
+ ccl_global char *use_queues_flag) /* flag to decide if scene_intersect kernel should
+ * use queues to fetch ray index */
+{
+ ccl_local unsigned int local_queue_atomics;
+ if(get_local_id(0) == 0 && get_local_id(1) == 0) {
+ local_queue_atomics = 0;
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ if(get_global_id(0) == 0 && get_global_id(1) == 0) {
+ /* If we are here, then it means that scene-intersect kernel
+ * has already been executed atleast once. From the next time,
+ * scene-intersect kernel may operate on queues to fetch ray index
+ */
+ use_queues_flag[0] = 1;
+
+ /* Mark queue indices of QUEUE_SHADOW_RAY_CAST_AO_RAYS and
+ * QUEUE_SHADOW_RAY_CAST_DL_RAYS queues that were made empty during the
+ * previous kernel.
+ */
+ Queue_index[QUEUE_SHADOW_RAY_CAST_AO_RAYS] = 0;
+ Queue_index[QUEUE_SHADOW_RAY_CAST_DL_RAYS] = 0;
+ }
+
+ char enqueue_flag = 0;
+ int ray_index = get_global_id(1) * get_global_size(0) + get_global_id(0);
+ ray_index = get_ray_index(ray_index,
+ QUEUE_ACTIVE_AND_REGENERATED_RAYS,
+ Queue_data,
+ queuesize,
+ 0);
+
+#ifdef __COMPUTE_DEVICE_GPU__
+ /* If we are executing on a GPU device, we exit all threads that are not
+ * required.
+ *
+ * If we are executing on a CPU device, then we need to keep all threads
+ * active since we have barrier() calls later in the kernel. CPU devices,
+ * expect all threads to execute barrier statement.
+ */
+ if(ray_index == QUEUE_EMPTY_SLOT) {
+ return;
+ }
+#endif
+
+#ifndef __COMPUTE_DEVICE_GPU__
+ if(ray_index != QUEUE_EMPTY_SLOT) {
+#endif
+ enqueue_flag = kernel_next_iteration_setup(globals,
+ data,
+ shader_data,
+ rng_coop,
+ throughput_coop,
+ PathRadiance_coop,
+ Ray_coop,
+ PathState_coop,
+ LightRay_dl_coop,
+ ISLamp_coop,
+ BSDFEval_coop,
+ LightRay_ao_coop,
+ AOBSDF_coop,
+ AOAlpha_coop,
+ ray_state,
+ use_queues_flag,
+ ray_index);
+#ifndef __COMPUTE_DEVICE_GPU__
+ }
+#endif
+
+ /* Enqueue RAY_UPDATE_BUFFER rays. */
+ enqueue_ray_index_local(ray_index,
+ QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS,
+ enqueue_flag,
+ queuesize,
+ &local_queue_atomics,
+ Queue_data,
+ Queue_index);
+}
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_queue_enqueue.cl b/intern/cycles/kernel/kernels/opencl/kernel_queue_enqueue.cl
new file mode 100644
index 00000000000..3156dc255fb
--- /dev/null
+++ b/intern/cycles/kernel/kernels/opencl/kernel_queue_enqueue.cl
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2011-2015 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 "../../kernel_compat_opencl.h"
+#include "../../kernel_math.h"
+#include "../../kernel_types.h"
+#include "../../kernel_globals.h"
+#include "../../kernel_queues.h"
+
+/*
+ * The kernel "kernel_queue_enqueue" enqueues rays of
+ * different ray state into their appropriate Queues;
+ * 1. Rays that have been determined to hit the background from the
+ * "kernel_scene_intersect" kernel
+ * are enqueued in QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS;
+ * 2. Rays that have been determined to be actively participating in path-iteration will be enqueued into QUEUE_ACTIVE_AND_REGENERATED_RAYS.
+ *
+ * The input and output of the kernel is as follows,
+ *
+ * ray_state -------------------------------------------|--- kernel_queue_enqueue --|--- Queue_data (QUEUE_ACTIVE_AND_REGENERATED_RAYS & QUEUE_HITBF_BUFF_UPDATE_TOREGEN_RAYS)
+ * Queue_index(QUEUE_ACTIVE_AND_REGENERATED_RAYS) ------| |--- Queue_index (QUEUE_ACTIVE_AND_REGENERATED_RAYS & QUEUE_HITBF_BUFF_UPDATE_TOREGEN_RAYS)
+ * Queue_index(QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS) ---| |
+ * queuesize -------------------------------------------| |
+ *
+ * Note on Queues :
+ * State of queues during the first time this kernel is called :
+ * At entry,
+ * Both QUEUE_ACTIVE_AND_REGENERATED_RAYS and QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will be empty.
+ * At exit,
+ * QUEUE_ACTIVE_AND_REGENERATED_RAYS will be filled with RAY_ACTIVE rays
+ * QUEUE_HITBF_BUFF_UPDATE_TOREGEN_RAYS will be filled with RAY_HIT_BACKGROUND rays.
+ *
+ * State of queue during other times this kernel is called :
+ * At entry,
+ * QUEUE_ACTIVE_AND_REGENERATED_RAYS will be empty.
+ * QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will contain RAY_TO_REGENERATE and RAY_UPDATE_BUFFER rays.
+ * At exit,
+ * QUEUE_ACTIVE_AND_REGENERATED_RAYS will be filled with RAY_ACTIVE rays.
+ * QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will be filled with RAY_TO_REGENERATE, RAY_UPDATE_BUFFER, RAY_HIT_BACKGROUND rays.
+ */
+__kernel void kernel_ocl_path_trace_queue_enqueue(
+ ccl_global int *Queue_data, /* Queue memory */
+ ccl_global int *Queue_index, /* Tracks the number of elements in each queue */
+ ccl_global char *ray_state, /* Denotes the state of each ray */
+ int queuesize) /* Size (capacity) of each queue */
+{
+ /* We have only 2 cases (Hit/Not-Hit) */
+ ccl_local unsigned int local_queue_atomics[2];
+
+ int lidx = get_local_id(1) * get_local_size(0) + get_local_id(0);
+ int ray_index = get_global_id(1) * get_global_size(0) + get_global_id(0);
+
+ if(lidx < 2 ) {
+ local_queue_atomics[lidx] = 0;
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ int queue_number = -1;
+
+ if(IS_STATE(ray_state, ray_index, RAY_HIT_BACKGROUND)) {
+ queue_number = QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS;
+ }
+ else if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
+ queue_number = QUEUE_ACTIVE_AND_REGENERATED_RAYS;
+ }
+
+ unsigned int my_lqidx;
+ if(queue_number != -1) {
+ my_lqidx = get_local_queue_index(queue_number, local_queue_atomics);
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ if(lidx == 0) {
+ local_queue_atomics[QUEUE_ACTIVE_AND_REGENERATED_RAYS] =
+ get_global_per_queue_offset(QUEUE_ACTIVE_AND_REGENERATED_RAYS,
+ local_queue_atomics,
+ Queue_index);
+ local_queue_atomics[QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS] =
+ get_global_per_queue_offset(QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS,
+ local_queue_atomics,
+ Queue_index);
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ unsigned int my_gqidx;
+ if(queue_number != -1) {
+ my_gqidx = get_global_queue_index(queue_number,
+ queuesize,
+ my_lqidx,
+ local_queue_atomics);
+ Queue_data[my_gqidx] = ray_index;
+ }
+}
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_scene_intersect.cl b/intern/cycles/kernel/kernels/opencl/kernel_scene_intersect.cl
new file mode 100644
index 00000000000..e5fad7bce50
--- /dev/null
+++ b/intern/cycles/kernel/kernels/opencl/kernel_scene_intersect.cl
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2011-2015 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 "split/kernel_scene_intersect.h"
+
+__kernel void kernel_ocl_path_trace_scene_intersect(
+ ccl_global char *globals,
+ ccl_constant KernelData *data,
+ ccl_global uint *rng_coop,
+ ccl_global Ray *Ray_coop, /* Required for scene_intersect */
+ ccl_global PathState *PathState_coop, /* Required for scene_intersect */
+ Intersection *Intersection_coop, /* Required for scene_intersect */
+ ccl_global char *ray_state, /* Denotes the state of each ray */
+ int sw, int sh,
+ ccl_global int *Queue_data, /* Memory for queues */
+ ccl_global int *Queue_index, /* Tracks the number of elements in queues */
+ int queuesize, /* Size (capacity) of queues */
+ ccl_global char *use_queues_flag, /* used to decide if this kernel should use
+ * queues to fetch ray index */
+#ifdef __KERNEL_DEBUG__
+ DebugData *debugdata_coop,
+#endif
+ int parallel_samples) /* Number of samples to be processed in parallel */
+{
+ int x = get_global_id(0);
+ int y = get_global_id(1);
+
+ /* Fetch use_queues_flag */
+ ccl_local char local_use_queues_flag;
+ if(get_local_id(0) == 0 && get_local_id(1) == 0) {
+ local_use_queues_flag = use_queues_flag[0];
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ int ray_index;
+ if(local_use_queues_flag) {
+ int thread_index = get_global_id(1) * get_global_size(0) + get_global_id(0);
+ ray_index = get_ray_index(thread_index,
+ QUEUE_ACTIVE_AND_REGENERATED_RAYS,
+ Queue_data,
+ queuesize,
+ 0);
+
+ if(ray_index == QUEUE_EMPTY_SLOT) {
+ return;
+ }
+ } else {
+ if(x < (sw * parallel_samples) && y < sh){
+ ray_index = x + y * (sw * parallel_samples);
+ } else {
+ return;
+ }
+ }
+
+ kernel_scene_intersect(globals,
+ data,
+ rng_coop,
+ Ray_coop,
+ PathState_coop,
+ Intersection_coop,
+ ray_state,
+ sw, sh,
+ use_queues_flag,
+#ifdef __KERNEL_DEBUG__
+ debugdata_coop,
+#endif
+ parallel_samples,
+ ray_index);
+}
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_shader_eval.cl b/intern/cycles/kernel/kernels/opencl/kernel_shader_eval.cl
new file mode 100644
index 00000000000..b9f616e6bdf
--- /dev/null
+++ b/intern/cycles/kernel/kernels/opencl/kernel_shader_eval.cl
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2011-2015 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 "split/kernel_shader_eval.h"
+
+__kernel void kernel_ocl_path_trace_shader_eval(
+ ccl_global char *globals,
+ ccl_constant KernelData *data,
+ ccl_global char *shader_data, /* Output ShaderData structure to be filled */
+ ccl_global uint *rng_coop, /* Required for rbsdf calculation */
+ ccl_global Ray *Ray_coop, /* Required for setting up shader from ray */
+ ccl_global PathState *PathState_coop, /* Required for all functions in this kernel */
+ Intersection *Intersection_coop, /* Required for setting up shader from ray */
+ ccl_global char *ray_state, /* Denotes the state of each ray */
+ ccl_global int *Queue_data, /* queue memory */
+ ccl_global int *Queue_index, /* Tracks the number of elements in each queue */
+ int queuesize) /* Size (capacity) of each queue */
+{
+ /* Enqeueue RAY_TO_REGENERATE rays into QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS queue. */
+ ccl_local unsigned int local_queue_atomics;
+ if(get_local_id(0) == 0 && get_local_id(1) == 0) {
+ local_queue_atomics = 0;
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ int ray_index = get_global_id(1) * get_global_size(0) + get_global_id(0);
+ ray_index = get_ray_index(ray_index,
+ QUEUE_ACTIVE_AND_REGENERATED_RAYS,
+ Queue_data,
+ queuesize,
+ 0);
+
+ if(ray_index == QUEUE_EMPTY_SLOT) {
+ return;
+ }
+
+ char enqueue_flag = (IS_STATE(ray_state, ray_index, RAY_TO_REGENERATE)) ? 1 : 0;
+ enqueue_ray_index_local(ray_index,
+ QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS,
+ enqueue_flag,
+ queuesize,
+ &local_queue_atomics,
+ Queue_data,
+ Queue_index);
+
+ /* Continue on with shader evaluation. */
+ kernel_shader_eval(globals,
+ data,
+ shader_data,
+ rng_coop,
+ Ray_coop,
+ PathState_coop,
+ Intersection_coop,
+ ray_state,
+ ray_index);
+}
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_shadow_blocked.cl b/intern/cycles/kernel/kernels/opencl/kernel_shadow_blocked.cl
new file mode 100644
index 00000000000..03886c0a030
--- /dev/null
+++ b/intern/cycles/kernel/kernels/opencl/kernel_shadow_blocked.cl
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2011-2015 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 "split/kernel_shadow_blocked.h"
+
+__kernel void kernel_ocl_path_trace_shadow_blocked(
+ ccl_global char *globals,
+ ccl_constant KernelData *data,
+ ccl_global char *shader_shadow, /* Required for shadow blocked */
+ ccl_global PathState *PathState_coop, /* Required for shadow blocked */
+ ccl_global Ray *LightRay_dl_coop, /* Required for direct lighting's shadow blocked */
+ ccl_global Ray *LightRay_ao_coop, /* Required for AO's shadow blocked */
+ Intersection *Intersection_coop_AO,
+ Intersection *Intersection_coop_DL,
+ ccl_global char *ray_state,
+ ccl_global int *Queue_data, /* Queue memory */
+ ccl_global int *Queue_index, /* Tracks the number of elements in each queue */
+ int queuesize, /* Size (capacity) of each queue */
+ int total_num_rays)
+{
+#if 0
+ /* We will make the Queue_index entries '0' in the next kernel. */
+ if(get_global_id(0) == 0 && get_global_id(1) == 0) {
+ /* We empty this queue here */
+ Queue_index[QUEUE_SHADOW_RAY_CAST_AO_RAYS] = 0;
+ Queue_index[QUEUE_SHADOW_RAY_CAST_DL_RAYS] = 0;
+ }
+#endif
+
+ int lidx = get_local_id(1) * get_local_id(0) + get_local_id(0);
+
+ ccl_local unsigned int ao_queue_length;
+ ccl_local unsigned int dl_queue_length;
+ if(lidx == 0) {
+ ao_queue_length = Queue_index[QUEUE_SHADOW_RAY_CAST_AO_RAYS];
+ dl_queue_length = Queue_index[QUEUE_SHADOW_RAY_CAST_DL_RAYS];
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ /* flag determining if the current ray is to process shadow ray for AO or DL */
+ char shadow_blocked_type = -1;
+
+ int ray_index = QUEUE_EMPTY_SLOT;
+ int thread_index = get_global_id(1) * get_global_size(0) + get_global_id(0);
+ if(thread_index < ao_queue_length + dl_queue_length) {
+ if(thread_index < ao_queue_length) {
+ ray_index = get_ray_index(thread_index, QUEUE_SHADOW_RAY_CAST_AO_RAYS, Queue_data, queuesize, 1);
+ shadow_blocked_type = RAY_SHADOW_RAY_CAST_AO;
+ } else {
+ ray_index = get_ray_index(thread_index - ao_queue_length, QUEUE_SHADOW_RAY_CAST_DL_RAYS, Queue_data, queuesize, 1);
+ shadow_blocked_type = RAY_SHADOW_RAY_CAST_DL;
+ }
+ }
+
+ if(ray_index == QUEUE_EMPTY_SLOT)
+ return;
+
+ kernel_shadow_blocked(globals,
+ data,
+ shader_shadow,
+ PathState_coop,
+ LightRay_dl_coop,
+ LightRay_ao_coop,
+ Intersection_coop_AO,
+ Intersection_coop_DL,
+ ray_state,
+ total_num_rays,
+ shadow_blocked_type,
+ ray_index);
+}
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_sum_all_radiance.cl b/intern/cycles/kernel/kernels/opencl/kernel_sum_all_radiance.cl
new file mode 100644
index 00000000000..88a1ed830af
--- /dev/null
+++ b/intern/cycles/kernel/kernels/opencl/kernel_sum_all_radiance.cl
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011-2015 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 "split/kernel_sum_all_radiance.h"
+
+__kernel void kernel_ocl_path_trace_sum_all_radiance(
+ ccl_constant KernelData *data, /* To get pass_stride to offet into buffer */
+ ccl_global float *buffer, /* Output buffer of RenderTile */
+ ccl_global float *per_sample_output_buffer, /* Radiance contributed by all samples */
+ int parallel_samples, int sw, int sh, int stride,
+ int buffer_offset_x,
+ int buffer_offset_y,
+ int buffer_stride,
+ int start_sample)
+{
+ kernel_sum_all_radiance(data,
+ buffer,
+ per_sample_output_buffer,
+ parallel_samples,
+ sw, sh, stride,
+ buffer_offset_x,
+ buffer_offset_y,
+ buffer_stride,
+ start_sample);
+}
diff --git a/intern/cycles/kernel/osl/SConscript b/intern/cycles/kernel/osl/SConscript
index 58b0204a1b9..74ba5e1020c 100644
--- a/intern/cycles/kernel/osl/SConscript
+++ b/intern/cycles/kernel/osl/SConscript
@@ -44,6 +44,18 @@ defs.append('CCL_NAMESPACE_BEGIN=namespace ccl {')
defs.append('CCL_NAMESPACE_END=}')
defs.append('WITH_OSL')
+if env['WITH_UNORDERED_MAP_SUPPORT']:
+ if env['UNORDERED_MAP_HEADER'] == 'unordered_map':
+ if env['UNORDERED_MAP_NAMESPACE'] == 'std':
+ defs.append('CYCLES_STD_UNORDERED_MAP')
+ elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
+ defs.append('CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE')
+ elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
+ defs.append('CYCLES_TR1_UNORDERED_MAP')
+else:
+ print("-- Replacing unordered_map/set with map/set (warning: slower!)")
+ defs.append('CYCLES_NO_UNORDERED_MAP')
+
if env['WITH_BF_CYCLES_DEBUG']:
defs.append('WITH_CYCLES_DEBUG')
diff --git a/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp b/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp
index 8f9c2efd470..43929fbe928 100644
--- a/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp
+++ b/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp
@@ -34,6 +34,7 @@
#include <OSL/genclosure.h>
+#include "kernel_compat_cpu.h"
#include "osl_closures.h"
#include "kernel_types.h"
diff --git a/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp b/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp
index c5851747b54..497c4f0dc5c 100644
--- a/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp
+++ b/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp
@@ -34,6 +34,7 @@
#include <OSL/genclosure.h>
+#include "kernel_compat_cpu.h"
#include "osl_closures.h"
#include "kernel_types.h"
diff --git a/intern/cycles/kernel/osl/osl_bssrdf.cpp b/intern/cycles/kernel/osl/osl_bssrdf.cpp
index 84ef85e089d..88998037751 100644
--- a/intern/cycles/kernel/osl/osl_bssrdf.cpp
+++ b/intern/cycles/kernel/osl/osl_bssrdf.cpp
@@ -34,6 +34,7 @@
#include <OSL/genclosure.h>
+#include "kernel_compat_cpu.h"
#include "osl_bssrdf.h"
#include "osl_closures.h"
diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h
index 5e833d738d8..ef67ef52fc0 100644
--- a/intern/cycles/kernel/osl/osl_closures.h
+++ b/intern/cycles/kernel/osl/osl_closures.h
@@ -147,14 +147,14 @@ public: \
\
float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float& pdf) const \
{ \
- pdf = 0; \
- return make_float3(0, 0, 0); \
+ pdf = 0.0f; \
+ return make_float3(0.0f, 0.0f, 0.0f); \
} \
\
float3 eval_transmit(const float3 &omega_out, const float3 &omega_in, float& pdf) const \
{ \
- pdf = 0; \
- return make_float3(0, 0, 0); \
+ pdf = 0.0f; \
+ return make_float3(0.0f, 0.0f, 0.0f); \
} \
\
int sample(const float3 &Ng, \
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index 1f6015d0d6b..bc89b7eb6ef 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -138,12 +138,12 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
{
/* this is only used for shader and object space, we don't really have
* a concept of shader space, so we just use object space for both. */
- if (xform) {
+ if(xform) {
const ShaderData *sd = (const ShaderData *)xform;
KernelGlobals *kg = sd->osl_globals;
int object = sd->object;
- if (object != OBJECT_NONE) {
+ if(object != OBJECT_NONE) {
#ifdef __OBJECT_MOTION__
Transform tfm;
@@ -168,12 +168,12 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
{
/* this is only used for shader and object space, we don't really have
* a concept of shader space, so we just use object space for both. */
- if (xform) {
+ if(xform) {
const ShaderData *sd = (const ShaderData *)xform;
KernelGlobals *kg = sd->osl_globals;
int object = sd->object;
- if (object != OBJECT_NONE) {
+ if(object != OBJECT_NONE) {
#ifdef __OBJECT_MOTION__
Transform itfm;
@@ -198,27 +198,27 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
{
KernelGlobals *kg = kernel_globals;
- if (from == u_ndc) {
+ if(from == u_ndc) {
Transform tfm = transform_transpose(transform_quick_inverse(kernel_data.cam.worldtondc));
COPY_MATRIX44(&result, &tfm);
return true;
}
- else if (from == u_raster) {
+ else if(from == u_raster) {
Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
COPY_MATRIX44(&result, &tfm);
return true;
}
- else if (from == u_screen) {
+ else if(from == u_screen) {
Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
COPY_MATRIX44(&result, &tfm);
return true;
}
- else if (from == u_camera) {
+ else if(from == u_camera) {
Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
COPY_MATRIX44(&result, &tfm);
return true;
}
- else if (from == u_world) {
+ else if(from == u_world) {
result.makeIdentity();
return true;
}
@@ -230,27 +230,27 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
{
KernelGlobals *kg = kernel_globals;
- if (to == u_ndc) {
+ if(to == u_ndc) {
Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
COPY_MATRIX44(&result, &tfm);
return true;
}
- else if (to == u_raster) {
+ else if(to == u_raster) {
Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
COPY_MATRIX44(&result, &tfm);
return true;
}
- else if (to == u_screen) {
+ else if(to == u_screen) {
Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
COPY_MATRIX44(&result, &tfm);
return true;
}
- else if (to == u_camera) {
+ else if(to == u_camera) {
Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
COPY_MATRIX44(&result, &tfm);
return true;
}
- else if (to == u_world) {
+ else if(to == u_world) {
result.makeIdentity();
return true;
}
@@ -262,11 +262,11 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
{
/* this is only used for shader and object space, we don't really have
* a concept of shader space, so we just use object space for both. */
- if (xform) {
+ if(xform) {
const ShaderData *sd = (const ShaderData *)xform;
int object = sd->object;
- if (object != OBJECT_NONE) {
+ if(object != OBJECT_NONE) {
#ifdef __OBJECT_MOTION__
Transform tfm = sd->ob_tfm;
#else
@@ -287,11 +287,11 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
{
/* this is only used for shader and object space, we don't really have
* a concept of shader space, so we just use object space for both. */
- if (xform) {
+ if(xform) {
const ShaderData *sd = (const ShaderData *)xform;
int object = sd->object;
- if (object != OBJECT_NONE) {
+ if(object != OBJECT_NONE) {
#ifdef __OBJECT_MOTION__
Transform tfm = sd->ob_itfm;
#else
@@ -312,22 +312,22 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
{
KernelGlobals *kg = kernel_globals;
- if (from == u_ndc) {
+ if(from == u_ndc) {
Transform tfm = transform_transpose(transform_quick_inverse(kernel_data.cam.worldtondc));
COPY_MATRIX44(&result, &tfm);
return true;
}
- else if (from == u_raster) {
+ else if(from == u_raster) {
Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
COPY_MATRIX44(&result, &tfm);
return true;
}
- else if (from == u_screen) {
+ else if(from == u_screen) {
Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
COPY_MATRIX44(&result, &tfm);
return true;
}
- else if (from == u_camera) {
+ else if(from == u_camera) {
Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
COPY_MATRIX44(&result, &tfm);
return true;
@@ -340,22 +340,22 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
{
KernelGlobals *kg = kernel_globals;
- if (to == u_ndc) {
+ if(to == u_ndc) {
Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
COPY_MATRIX44(&result, &tfm);
return true;
}
- else if (to == u_raster) {
+ else if(to == u_raster) {
Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
COPY_MATRIX44(&result, &tfm);
return true;
}
- else if (to == u_screen) {
+ else if(to == u_screen) {
Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
COPY_MATRIX44(&result, &tfm);
return true;
}
- else if (to == u_camera) {
+ else if(to == u_camera) {
Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
COPY_MATRIX44(&result, &tfm);
return true;
@@ -373,8 +373,8 @@ bool OSLRenderServices::get_array_attribute(OSL::ShaderGlobals *sg, bool derivat
static bool set_attribute_float3(float3 f[3], TypeDesc type, bool derivatives, void *val)
{
- if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
- type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor)
+ if(type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
+ type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor)
{
float *fval = (float *)val;
@@ -382,7 +382,7 @@ static bool set_attribute_float3(float3 f[3], TypeDesc type, bool derivatives, v
fval[1] = f[0].y;
fval[2] = f[0].z;
- if (derivatives) {
+ if(derivatives) {
fval[3] = f[1].x;
fval[4] = f[1].y;
fval[5] = f[1].z;
@@ -398,7 +398,7 @@ static bool set_attribute_float3(float3 f[3], TypeDesc type, bool derivatives, v
float *fval = (float *)val;
fval[0] = average(f[0]);
- if (derivatives) {
+ if(derivatives) {
fval[1] = average(f[1]);
fval[2] = average(f[2]);
}
@@ -422,15 +422,15 @@ static bool set_attribute_float3(float3 f, TypeDesc type, bool derivatives, void
static bool set_attribute_float(float f[3], TypeDesc type, bool derivatives, void *val)
{
- if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
- type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor)
+ if(type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
+ type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor)
{
float *fval = (float *)val;
fval[0] = f[0];
fval[1] = f[1];
fval[2] = f[2];
- if (derivatives) {
+ if(derivatives) {
fval[3] = f[1];
fval[4] = f[1];
fval[5] = f[1];
@@ -446,7 +446,7 @@ static bool set_attribute_float(float f[3], TypeDesc type, bool derivatives, voi
float *fval = (float *)val;
fval[0] = f[0];
- if (derivatives) {
+ if(derivatives) {
fval[1] = f[1];
fval[2] = f[2];
}
@@ -474,7 +474,7 @@ static bool set_attribute_int(int i, TypeDesc type, bool derivatives, void *val)
int *ival = (int *)val;
ival[0] = i;
- if (derivatives) {
+ if(derivatives) {
ival[1] = 0;
ival[2] = 0;
}
@@ -491,7 +491,7 @@ static bool set_attribute_string(ustring str, TypeDesc type, bool derivatives, v
ustring *sval = (ustring *)val;
sval[0] = str;
- if (derivatives) {
+ if(derivatives) {
sval[1] = OSLRenderServices::u_empty;
sval[2] = OSLRenderServices::u_empty;
}
@@ -521,7 +521,7 @@ static bool set_attribute_float3_3(float3 P[3], TypeDesc type, bool derivatives,
if(type.arraylen > 3)
memset(fval + 3*3, 0, sizeof(float)*3*(type.arraylen - 3));
- if (derivatives)
+ if(derivatives)
memset(fval + type.arraylen*3, 0, sizeof(float)*2*3*type.arraylen);
return true;
@@ -544,15 +544,15 @@ static bool set_attribute_matrix(const Transform& tfm, TypeDesc type, void *val)
static bool get_mesh_element_attribute(KernelGlobals *kg, const ShaderData *sd, const OSLGlobals::Attribute& attr,
const TypeDesc& type, bool derivatives, void *val)
{
- if (attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
- attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor)
+ if(attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
+ attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor)
{
float3 fval[3];
fval[0] = primitive_attribute_float3(kg, sd, attr.elem, attr.offset,
(derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
return set_attribute_float3(fval, type, derivatives, val);
}
- else if (attr.type == TypeDesc::TypeFloat) {
+ else if(attr.type == TypeDesc::TypeFloat) {
float fval[3];
fval[0] = primitive_attribute_float(kg, sd, attr.elem, attr.offset,
(derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
@@ -566,7 +566,7 @@ static bool get_mesh_element_attribute(KernelGlobals *kg, const ShaderData *sd,
static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, const OSLGlobals::Attribute& attr,
const TypeDesc& type, bool derivatives, void *val)
{
- if (attr.type == TypeDesc::TypeMatrix) {
+ if(attr.type == TypeDesc::TypeMatrix) {
Transform tfm = primitive_attribute_matrix(kg, sd, attr.offset);
return set_attribute_matrix(tfm, type, val);
}
@@ -580,7 +580,7 @@ static void get_object_attribute(const OSLGlobals::Attribute& attr, bool derivat
size_t datasize = attr.value.datasize();
memcpy(val, attr.value.data(), datasize);
- if (derivatives)
+ if(derivatives)
memset((char *)val + datasize, 0, datasize * 2);
}
@@ -590,80 +590,80 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD
/* todo: turn this into hash table? */
/* Object Attributes */
- if (name == u_object_location) {
+ if(name == u_object_location) {
float3 f = object_location(kg, sd);
return set_attribute_float3(f, type, derivatives, val);
}
- else if (name == u_object_index) {
+ else if(name == u_object_index) {
float f = object_pass_id(kg, sd->object);
return set_attribute_float(f, type, derivatives, val);
}
- else if (name == u_geom_dupli_generated) {
+ else if(name == u_geom_dupli_generated) {
float3 f = object_dupli_generated(kg, sd->object);
return set_attribute_float3(f, type, derivatives, val);
}
- else if (name == u_geom_dupli_uv) {
+ else if(name == u_geom_dupli_uv) {
float3 f = object_dupli_uv(kg, sd->object);
return set_attribute_float3(f, type, derivatives, val);
}
- else if (name == u_material_index) {
+ else if(name == u_material_index) {
float f = shader_pass_id(kg, sd);
return set_attribute_float(f, type, derivatives, val);
}
- else if (name == u_object_random) {
+ else if(name == u_object_random) {
float f = object_random_number(kg, sd->object);
return set_attribute_float(f, type, derivatives, val);
}
/* Particle Attributes */
- else if (name == u_particle_index) {
+ else if(name == u_particle_index) {
int particle_id = object_particle_id(kg, sd->object);
float f = particle_index(kg, particle_id);
return set_attribute_float(f, type, derivatives, val);
}
- else if (name == u_particle_age) {
+ else if(name == u_particle_age) {
int particle_id = object_particle_id(kg, sd->object);
float f = particle_age(kg, particle_id);
return set_attribute_float(f, type, derivatives, val);
}
- else if (name == u_particle_lifetime) {
+ else if(name == u_particle_lifetime) {
int particle_id = object_particle_id(kg, sd->object);
float f = particle_lifetime(kg, particle_id);
return set_attribute_float(f, type, derivatives, val);
}
- else if (name == u_particle_location) {
+ else if(name == u_particle_location) {
int particle_id = object_particle_id(kg, sd->object);
float3 f = particle_location(kg, particle_id);
return set_attribute_float3(f, type, derivatives, val);
}
#if 0 /* unsupported */
- else if (name == u_particle_rotation) {
+ else if(name == u_particle_rotation) {
int particle_id = object_particle_id(kg, sd->object);
float4 f = particle_rotation(kg, particle_id);
return set_attribute_float4(f, type, derivatives, val);
}
#endif
- else if (name == u_particle_size) {
+ else if(name == u_particle_size) {
int particle_id = object_particle_id(kg, sd->object);
float f = particle_size(kg, particle_id);
return set_attribute_float(f, type, derivatives, val);
}
- else if (name == u_particle_velocity) {
+ else if(name == u_particle_velocity) {
int particle_id = object_particle_id(kg, sd->object);
float3 f = particle_velocity(kg, particle_id);
return set_attribute_float3(f, type, derivatives, val);
}
- else if (name == u_particle_angular_velocity) {
+ else if(name == u_particle_angular_velocity) {
int particle_id = object_particle_id(kg, sd->object);
float3 f = particle_angular_velocity(kg, particle_id);
return set_attribute_float3(f, type, derivatives, val);
}
/* Geometry Attributes */
- else if (name == u_geom_numpolyvertices) {
+ else if(name == u_geom_numpolyvertices) {
return set_attribute_int(3, type, derivatives, val);
}
- else if ((name == u_geom_trianglevertices || name == u_geom_polyvertices)
+ else if((name == u_geom_trianglevertices || name == u_geom_polyvertices)
#ifdef __HAIR__
&& sd->type & PRIMITIVE_ALL_TRIANGLE)
#else
@@ -689,21 +689,21 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD
ustring object_name = kg->osl->object_names[sd->object];
return set_attribute_string(object_name, type, derivatives, val);
}
- else if (name == u_is_smooth) {
+ else if(name == u_is_smooth) {
float f = ((sd->shader & SHADER_SMOOTH_NORMAL) != 0);
return set_attribute_float(f, type, derivatives, val);
}
#ifdef __HAIR__
/* Hair Attributes */
- else if (name == u_is_curve) {
+ else if(name == u_is_curve) {
float f = (sd->type & PRIMITIVE_ALL_CURVE) != 0;
return set_attribute_float(f, type, derivatives, val);
}
- else if (name == u_curve_thickness) {
+ else if(name == u_curve_thickness) {
float f = curve_thickness(kg, sd);
return set_attribute_float(f, type, derivatives, val);
}
- else if (name == u_curve_tangent_normal) {
+ else if(name == u_curve_tangent_normal) {
float3 f = curve_tangent_normal(kg, sd);
return set_attribute_float3(f, type, derivatives, val);
}
@@ -715,22 +715,22 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD
bool OSLRenderServices::get_background_attribute(KernelGlobals *kg, ShaderData *sd, ustring name,
TypeDesc type, bool derivatives, void *val)
{
- if (name == u_path_ray_length) {
+ if(name == u_path_ray_length) {
/* Ray Length */
float f = sd->ray_length;
return set_attribute_float(f, type, derivatives, val);
}
- else if (name == u_path_ray_depth) {
+ else if(name == u_path_ray_depth) {
/* Ray Depth */
int f = sd->ray_depth;
return set_attribute_int(f, type, derivatives, val);
}
- else if (name == u_path_transparent_depth) {
+ else if(name == u_path_transparent_depth) {
/* Transparent Ray Depth */
int f = sd->transparent_depth;
return set_attribute_int(f, type, derivatives, val);
}
- else if (name == u_ndc) {
+ else if(name == u_ndc) {
/* NDC coordinates with special exception for otho */
OSLThreadData *tdata = kg->osl_tdata;
OSL::ShaderGlobals *globals = &tdata->globals;
@@ -762,7 +762,7 @@ bool OSLRenderServices::get_background_attribute(KernelGlobals *kg, ShaderData *
bool OSLRenderServices::get_attribute(OSL::ShaderGlobals *sg, bool derivatives, ustring object_name,
TypeDesc type, ustring name, void *val)
{
- if (sg->renderstate == NULL)
+ if(sg->renderstate == NULL)
return false;
ShaderData *sd = (ShaderData *)(sg->renderstate);
@@ -777,10 +777,10 @@ bool OSLRenderServices::get_attribute(ShaderData *sd, bool derivatives, ustring
int object;
/* lookup of attribute on another object */
- if (object_name != u_empty) {
+ if(object_name != u_empty) {
OSLGlobals::ObjectNameMap::iterator it = kg->osl->object_name_map.find(object_name);
- if (it == kg->osl->object_name_map.end())
+ if(it == kg->osl->object_name_map.end())
return false;
object = it->second;
@@ -790,7 +790,7 @@ bool OSLRenderServices::get_attribute(ShaderData *sd, bool derivatives, ustring
object = sd->object;
is_curve = (sd->type & PRIMITIVE_ALL_CURVE) != 0;
- if (object == OBJECT_NONE)
+ if(object == OBJECT_NONE)
return get_background_attribute(kg, sd, name, type, derivatives, val);
}
@@ -799,10 +799,10 @@ bool OSLRenderServices::get_attribute(ShaderData *sd, bool derivatives, ustring
OSLGlobals::AttributeMap& attribute_map = kg->osl->attribute_map[object];
OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
- if (it != attribute_map.end()) {
+ if(it != attribute_map.end()) {
const OSLGlobals::Attribute& attr = it->second;
- if (attr.elem != ATTR_ELEMENT_OBJECT) {
+ if(attr.elem != ATTR_ELEMENT_OBJECT) {
/* triangle and vertex attributes */
if(get_mesh_element_attribute(kg, sd, attr, type, derivatives, val))
return true;
@@ -819,7 +819,7 @@ bool OSLRenderServices::get_attribute(ShaderData *sd, bool derivatives, ustring
/* not found in attribute, check standard object info */
bool is_std_object_attribute = get_object_standard_attribute(kg, sd, name, type, derivatives, val);
- if (is_std_object_attribute)
+ if(is_std_object_attribute)
return true;
return get_background_attribute(kg, sd, name, type, derivatives, val);
@@ -887,7 +887,7 @@ bool OSLRenderServices::texture(ustring filename, TextureOpt &options,
#endif
bool status;
- if(filename[0] == '@' && filename.find('.') == -1) {
+ if(filename[0] == '@') {
int slot = atoi(filename.c_str() + 1);
float4 rgba = kernel_tex_image_interp(slot, s, 1.0f - t);
@@ -939,19 +939,33 @@ bool OSLRenderServices::texture3d(ustring filename, TextureOpt &options,
OSL::TextureSystem *ts = osl_ts;
ShaderData *sd = (ShaderData *)(sg->renderstate);
KernelGlobals *kg = sd->osl_globals;
- OSLThreadData *tdata = kg->osl_tdata;
- OIIO::TextureSystem::Perthread *thread_info = tdata->oiio_thread_info;
-
- OIIO::TextureSystem::TextureHandle *th = ts->get_texture_handle(filename, thread_info);
+ bool status;
+ if(filename[0] == '@') {
+ int slot = atoi(filename.c_str() + 1);
+ float4 rgba = kernel_tex_image_interp_3d(slot, P.x, P.y, P.z);
+ result[0] = rgba[0];
+ if(nchannels > 1)
+ result[1] = rgba[1];
+ if(nchannels > 2)
+ result[2] = rgba[2];
+ if(nchannels > 3)
+ result[3] = rgba[3];
+ status = true;
+ }
+ else {
+ OSLThreadData *tdata = kg->osl_tdata;
+ OIIO::TextureSystem::Perthread *thread_info = tdata->oiio_thread_info;
+ OIIO::TextureSystem::TextureHandle *th = ts->get_texture_handle(filename, thread_info);
#if OIIO_VERSION < 10500
- bool status = ts->texture3d(th, thread_info,
- options, P, dPdx, dPdy, dPdz, result);
+ status = ts->texture3d(th, thread_info,
+ options, P, dPdx, dPdy, dPdz, result);
#else
- bool status = ts->texture3d(th, thread_info,
- options, P, dPdx, dPdy, dPdz,
- nchannels, result);
+ status = ts->texture3d(th, thread_info,
+ options, P, dPdx, dPdy, dPdz,
+ nchannels, result);
#endif
+ }
if(!status) {
if(nchannels == 3 || nchannels == 4) {
@@ -979,7 +993,7 @@ bool OSLRenderServices::environment(ustring filename, TextureOpt &options,
OSLThreadData *tdata = kg->osl_tdata;
OIIO::TextureSystem::Perthread *thread_info = tdata->oiio_thread_info;
- OIIO::TextureSystem::TextureHandle *th = ts->get_texture_handle(filename, thread_info);
+ OIIO::TextureSystem::TextureHandle *th = ts->get_texture_handle(filename, thread_info);
#if OIIO_VERSION < 10500
bool status = ts->environment(th, thread_info,
diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp
index ebf72ae11f4..8cfe0cbcbd4 100644
--- a/intern/cycles/kernel/osl/osl_shader.cpp
+++ b/intern/cycles/kernel/osl/osl_shader.cpp
@@ -146,11 +146,11 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
/* OSL gives us a closure tree, we flatten it into arrays per
* closure type, for evaluation, sampling, etc later on. */
- if (closure->type == OSL::ClosureColor::COMPONENT) {
+ if(closure->type == OSL::ClosureColor::COMPONENT) {
OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
- if (prim) {
+ if(prim) {
ShaderClosure sc;
#ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
@@ -267,6 +267,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
if(fabsf(weight.x) > 0.0f) {
sc.weight = make_float3(weight.x, 0.0f, 0.0f);
sc.data0 = bssrdf->radius.x;
+ sc.data1 = 0.0f;
sd->flag |= bssrdf_setup(&sc, sc.type);
sd->closure[sd->num_closure++] = sc;
}
@@ -274,6 +275,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
if(fabsf(weight.y) > 0.0f) {
sc.weight = make_float3(0.0f, weight.y, 0.0f);
sc.data0 = bssrdf->radius.y;
+ sc.data1 = 0.0f;
sd->flag |= bssrdf_setup(&sc, sc.type);
sd->closure[sd->num_closure++] = sc;
}
@@ -281,6 +283,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
if(fabsf(weight.z) > 0.0f) {
sc.weight = make_float3(0.0f, 0.0f, weight.z);
sc.data0 = bssrdf->radius.z;
+ sc.data1 = 0.0f;
sd->flag |= bssrdf_setup(&sc, sc.type);
sd->closure[sd->num_closure++] = sc;
}
@@ -293,11 +296,11 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
}
}
}
- else if (closure->type == OSL::ClosureColor::MUL) {
+ else if(closure->type == OSL::ClosureColor::MUL) {
OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
flatten_surface_closure_tree(sd, path_flag, mul->closure, TO_FLOAT3(mul->weight) * weight);
}
- else if (closure->type == OSL::ClosureColor::ADD) {
+ else if(closure->type == OSL::ClosureColor::ADD) {
OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
flatten_surface_closure_tree(sd, path_flag, add->closureA, weight);
flatten_surface_closure_tree(sd, path_flag, add->closureB, weight);
@@ -316,11 +319,11 @@ void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, int path_flag, S
OSL::ShadingContext *octx = tdata->context[(int)ctx];
int shader = sd->shader & SHADER_MASK;
- if (kg->osl->surface_state[shader])
+ if(kg->osl->surface_state[shader])
ss->execute(*octx, *(kg->osl->surface_state[shader]), *globals);
/* flatten closure tree */
- if (globals->Ci)
+ if(globals->Ci)
flatten_surface_closure_tree(sd, path_flag, globals->Ci);
}
@@ -332,23 +335,23 @@ static float3 flatten_background_closure_tree(const OSL::ClosureColor *closure)
* is only one supported closure type at the moment, which has no evaluation
* functions, so we just sum the weights */
- if (closure->type == OSL::ClosureColor::COMPONENT) {
+ if(closure->type == OSL::ClosureColor::COMPONENT) {
OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
- if (prim && prim->category == CClosurePrimitive::Background)
+ if(prim && prim->category == CClosurePrimitive::Background)
#ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
return TO_FLOAT3(comp->w);
#else
return make_float3(1.0f, 1.0f, 1.0f);
#endif
}
- else if (closure->type == OSL::ClosureColor::MUL) {
+ else if(closure->type == OSL::ClosureColor::MUL) {
OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
return TO_FLOAT3(mul->weight) * flatten_background_closure_tree(mul->closure);
}
- else if (closure->type == OSL::ClosureColor::ADD) {
+ else if(closure->type == OSL::ClosureColor::ADD) {
OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
return flatten_background_closure_tree(add->closureA) +
@@ -369,11 +372,11 @@ float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, int path_fl
OSL::ShaderGlobals *globals = &tdata->globals;
OSL::ShadingContext *octx = tdata->context[(int)ctx];
- if (kg->osl->background_state)
+ if(kg->osl->background_state)
ss->execute(*octx, *(kg->osl->background_state), *globals);
/* return background color immediately */
- if (globals->Ci)
+ if(globals->Ci)
return flatten_background_closure_tree(globals->Ci);
return make_float3(0.0f, 0.0f, 0.0f);
@@ -387,11 +390,11 @@ static void flatten_volume_closure_tree(ShaderData *sd,
/* OSL gives us a closure tree, we flatten it into arrays per
* closure type, for evaluation, sampling, etc later on. */
- if (closure->type == OSL::ClosureColor::COMPONENT) {
+ if(closure->type == OSL::ClosureColor::COMPONENT) {
OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
- if (prim) {
+ if(prim) {
ShaderClosure sc;
#ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
@@ -448,11 +451,11 @@ static void flatten_volume_closure_tree(ShaderData *sd,
}
}
}
- else if (closure->type == OSL::ClosureColor::MUL) {
+ else if(closure->type == OSL::ClosureColor::MUL) {
OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
flatten_volume_closure_tree(sd, mul->closure, TO_FLOAT3(mul->weight) * weight);
}
- else if (closure->type == OSL::ClosureColor::ADD) {
+ else if(closure->type == OSL::ClosureColor::ADD) {
OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
flatten_volume_closure_tree(sd, add->closureA, weight);
flatten_volume_closure_tree(sd, add->closureB, weight);
@@ -471,11 +474,11 @@ void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, int path_flag, Sh
OSL::ShadingContext *octx = tdata->context[(int)ctx];
int shader = sd->shader & SHADER_MASK;
- if (kg->osl->volume_state[shader])
+ if(kg->osl->volume_state[shader])
ss->execute(*octx, *(kg->osl->volume_state[shader]), *globals);
/* flatten closure tree */
- if (globals->Ci)
+ if(globals->Ci)
flatten_volume_closure_tree(sd, globals->Ci);
}
@@ -493,7 +496,7 @@ void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderConte
OSL::ShadingContext *octx = tdata->context[(int)ctx];
int shader = sd->shader & SHADER_MASK;
- if (kg->osl->displacement_state[shader])
+ if(kg->osl->displacement_state[shader])
ss->execute(*octx, *(kg->osl->displacement_state[shader]), *globals);
/* get back position */
@@ -520,7 +523,7 @@ float3 OSLShader::bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, const
CBSDFClosure *bsdf = (CBSDFClosure *)sc->prim;
float3 bsdf_eval;
- if (dot(sd->Ng, omega_in) >= 0.0f)
+ if(dot(sd->Ng, omega_in) >= 0.0f)
bsdf_eval = bsdf->eval_reflect(sd->I, omega_in, pdf);
else
bsdf_eval = bsdf->eval_transmit(sd->I, omega_in, pdf);
@@ -548,7 +551,7 @@ int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id,
ustring stdname(std::string("geom:") + std::string(Attribute::standard_name((AttributeStandard)id)));
OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname);
- if (it != attr_map.end()) {
+ if(it != attr_map.end()) {
const OSLGlobals::Attribute &osl_attr = it->second;
*elem = osl_attr.elem;
diff --git a/intern/cycles/kernel/shaders/node_image_texture.osl b/intern/cycles/kernel/shaders/node_image_texture.osl
index 526a87525cd..46a02cab32e 100644
--- a/intern/cycles/kernel/shaders/node_image_texture.osl
+++ b/intern/cycles/kernel/shaders/node_image_texture.osl
@@ -26,7 +26,7 @@ point map_to_tube(vector dir)
{
float u, v;
v = (dir[2] + 1.0) * 0.5;
- float len = sqrt(dir[0]*dir[0] + dir[1]*dir[1]);
+ float len = sqrt(dir[0] * dir[0] + dir[1] * dir[1]);
if (len > 0.0) {
u = (1.0 - (atan2(dir[0] / len, dir[1] / len) / M_PI)) * 0.5;
}
@@ -40,8 +40,8 @@ point map_to_sphere(vector dir)
{
float len = length(dir);
float v, u;
- if(len > 0.0) {
- if(dir[0] == 0.0 && dir[1] == 0.0) {
+ if (len > 0.0) {
+ if (dir[0] == 0.0 && dir[1] == 0.0) {
u = 0.0; /* Othwise domain error. */
}
else {
diff --git a/intern/cycles/kernel/shaders/node_math.osl b/intern/cycles/kernel/shaders/node_math.osl
index bbc008b4299..7eef97fd7e8 100644
--- a/intern/cycles/kernel/shaders/node_math.osl
+++ b/intern/cycles/kernel/shaders/node_math.osl
@@ -93,8 +93,8 @@ shader node_math(
Value = Value1 > Value2;
else if (type == "Modulo")
Value = safe_modulo(Value1, Value2);
- else if (type == "Absolute")
- Value = fabs(Value1);
+ else if (type == "Absolute")
+ Value = fabs(Value1);
if (Clamp)
Value = clamp(Value, 0.0, 1.0);
diff --git a/intern/cycles/kernel/shaders/node_musgrave_texture.osl b/intern/cycles/kernel/shaders/node_musgrave_texture.osl
index a349dc8cb9a..4f95dec910a 100644
--- a/intern/cycles/kernel/shaders/node_musgrave_texture.osl
+++ b/intern/cycles/kernel/shaders/node_musgrave_texture.osl
@@ -26,7 +26,7 @@
* from "Texturing and Modelling: A procedural approach"
*/
-float noise_musgrave_fBm(point p, string basis, float H, float lacunarity, float octaves)
+float noise_musgrave_fBm(point p, float H, float lacunarity, float octaves)
{
float rmd;
float value = 0.0;
@@ -54,7 +54,7 @@ float noise_musgrave_fBm(point p, string basis, float H, float lacunarity, float
* octaves: number of frequencies in the fBm
*/
-float noise_musgrave_multi_fractal(point p, string basis, float H, float lacunarity, float octaves)
+float noise_musgrave_multi_fractal(point p, float H, float lacunarity, float octaves)
{
float rmd;
float value = 1.0;
@@ -83,7 +83,7 @@ float noise_musgrave_multi_fractal(point p, string basis, float H, float lacunar
* offset: raises the terrain from `sea level'
*/
-float noise_musgrave_hetero_terrain(point p, string basis, float H, float lacunarity, float octaves, float offset)
+float noise_musgrave_hetero_terrain(point p, float H, float lacunarity, float octaves, float offset)
{
float value, increment, rmd;
float pwHL = pow(lacunarity, -H);
@@ -118,8 +118,8 @@ float noise_musgrave_hetero_terrain(point p, string basis, float H, float lacuna
* offset: raises the terrain from `sea level'
*/
-float noise_musgrave_hybrid_multi_fractal(point p, string basis, float H,
- float lacunarity, float octaves, float offset, float gain)
+float noise_musgrave_hybrid_multi_fractal(point p, float H, float lacunarity,
+ float octaves, float offset, float gain)
{
float result, signal, weight, rmd;
float pwHL = pow(lacunarity, -H);
@@ -156,8 +156,8 @@ float noise_musgrave_hybrid_multi_fractal(point p, string basis, float H,
* offset: raises the terrain from `sea level'
*/
-float noise_musgrave_ridged_multi_fractal(point p, string basis, float H,
- float lacunarity, float octaves, float offset, float gain)
+float noise_musgrave_ridged_multi_fractal(point p, float H, float lacunarity,
+ float octaves, float offset, float gain)
{
float result, signal, weight;
float pwHL = pow(lacunarity, -H);
@@ -201,7 +201,6 @@ shader node_musgrave_texture(
float dimension = max(Dimension, 1e-5);
float octaves = clamp(Detail, 0.0, 16.0);
float lacunarity = max(Lacunarity, 1e-5);
- string Basis = "Perlin";
float intensity = 1.0;
point p = Vector;
@@ -212,15 +211,15 @@ shader node_musgrave_texture(
p = p * Scale;
if (Type == "Multifractal")
- Fac = intensity * noise_musgrave_multi_fractal(p, Basis, dimension, lacunarity, octaves);
+ Fac = intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
else if (Type == "fBM")
- Fac = intensity * noise_musgrave_fBm(p, Basis, dimension, lacunarity, octaves);
+ Fac = intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves);
else if (Type == "Hybrid Multifractal")
- Fac = intensity * noise_musgrave_hybrid_multi_fractal(p, Basis, dimension, lacunarity, octaves, Offset, Gain);
+ Fac = intensity * noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, Offset, Gain);
else if (Type == "Ridged Multifractal")
- Fac = intensity * noise_musgrave_ridged_multi_fractal(p, Basis, dimension, lacunarity, octaves, Offset, Gain);
+ Fac = intensity * noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, Offset, Gain);
else if (Type == "Hetero Terrain")
- Fac = intensity * noise_musgrave_hetero_terrain(p, Basis, dimension, lacunarity, octaves, Offset);
+ Fac = intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, Offset);
Color = color(Fac, Fac, Fac);
}
diff --git a/intern/cycles/kernel/shaders/node_noise_texture.osl b/intern/cycles/kernel/shaders/node_noise_texture.osl
index dabc0b6843f..e83e5b5b211 100644
--- a/intern/cycles/kernel/shaders/node_noise_texture.osl
+++ b/intern/cycles/kernel/shaders/node_noise_texture.osl
@@ -19,23 +19,23 @@
/* Noise */
-float noise(point p, string basis, float distortion, float detail, float fac, color Color)
+float noise(point p, float distortion, float detail, float fac, color Color)
{
point r;
int hard = 0;
if (distortion != 0.0) {
- r[0] = noise_basis(p + point(13.5), basis) * distortion;
- r[1] = noise_basis(p, basis) * distortion;
- r[2] = noise_basis(p - point(13.5), basis) * distortion;
+ r[0] = safe_noise(p + point(13.5), "unsigned") * distortion;
+ r[1] = safe_noise(p, "unsigned") * distortion;
+ r[2] = safe_noise(p - point(13.5), "unsigned") * distortion;
p += r;
}
- fac = noise_turbulence(p, basis, detail, hard);
+ fac = noise_turbulence(p, detail, hard);
- Color = color(fac, noise_turbulence(point(p[1], p[0], p[2]), basis, detail, hard),
- noise_turbulence(point(p[1], p[2], p[0]), basis, detail, hard));
+ Color = color(fac, noise_turbulence(point(p[1], p[0], p[2]), detail, hard),
+ noise_turbulence(point(p[1], p[2], p[0]), detail, hard));
return fac;
}
@@ -55,7 +55,6 @@ shader node_noise_texture(
if (use_mapping)
p = transform(mapping, p);
- string Basis = "Perlin";
- Fac = noise(p * Scale, Basis, Distortion, Detail, Fac, Color);
+ Fac = noise(p * Scale, Distortion, Detail, Fac, Color);
}
diff --git a/intern/cycles/kernel/shaders/node_texture.h b/intern/cycles/kernel/shaders/node_texture.h
index 5f9cd5afa47..fc2cfdcd55c 100644
--- a/intern/cycles/kernel/shaders/node_texture.h
+++ b/intern/cycles/kernel/shaders/node_texture.h
@@ -14,32 +14,6 @@
* limitations under the License.
*/
-/* Voronoi Distances */
-
-float voronoi_distance(string distance_metric, vector d, float e)
-{
-#if 0
- if (distance_metric == "Distance Squared")
-#endif
- return dot(d, d);
-#if 0
- if (distance_metric == "Actual Distance")
- return length(d);
- if (distance_metric == "Manhattan")
- return fabs(d[0]) + fabs(d[1]) + fabs(d[2]);
- if (distance_metric == "Chebychev")
- return max(fabs(d[0]), max(fabs(d[1]), fabs(d[2])));
- if (distance_metric == "Minkovsky 1/2")
- return sqrt(fabs(d[0])) + sqrt(fabs(d[1])) + sqrt(fabs(d[1]));
- if (distance_metric == "Minkovsky 4")
- return sqrt(sqrt(dot(d * d, d * d)));
- if (distance_metric == "Minkovsky")
- return pow(pow(fabs(d[0]), e) + pow(fabs(d[1]), e) + pow(fabs(d[2]), e), 1.0 / e);
-
- return 0.0;
-#endif
-}
-
/* Voronoi / Worley like */
color cellnoise_color(point p)
@@ -51,7 +25,7 @@ color cellnoise_color(point p)
return color(r, g, b);
}
-void voronoi(point p, string distance_metric, float e, float da[4], point pa[4])
+void voronoi(point p, float e, float da[4], point pa[4])
{
/* returns distances in da and point coords in pa */
int xx, yy, zz, xi, yi, zi;
@@ -71,7 +45,7 @@ void voronoi(point p, string distance_metric, float e, float da[4], point pa[4])
point ip = point(xx, yy, zz);
point vp = (point)cellnoise_color(ip);
point pd = p - (vp + ip);
- float d = voronoi_distance(distance_metric, pd, e);
+ float d = dot(pd, pd);
vp += point(xx, yy, zz);
@@ -111,46 +85,6 @@ void voronoi(point p, string distance_metric, float e, float da[4], point pa[4])
}
}
-float voronoi_Fn(point p, int n)
-{
- float da[4];
- point pa[4];
-
- voronoi(p, "Distance Squared", 0, da, pa);
-
- return da[n];
-}
-
-float voronoi_FnFn(point p, int n1, int n2)
-{
- float da[4];
- point pa[4];
-
- voronoi(p, "Distance Squared", 0, da, pa);
-
- return da[n2] - da[n1];
-}
-
-float voronoi_F1(point p) { return voronoi_Fn(p, 0); }
-float voronoi_F2(point p) { return voronoi_Fn(p, 1); }
-float voronoi_F3(point p) { return voronoi_Fn(p, 2); }
-float voronoi_F4(point p) { return voronoi_Fn(p, 3); }
-float voronoi_F1F2(point p) { return voronoi_FnFn(p, 0, 1); }
-
-float voronoi_Cr(point p)
-{
- /* crackle type pattern, just a scale/clamp of F2-F1 */
- float t = 10.0 * voronoi_F1F2(p);
- return (t > 1.0) ? 1.0 : t;
-}
-
-float voronoi_F1S(point p) { return 2.0 * voronoi_F1(p) - 1.0; }
-float voronoi_F2S(point p) { return 2.0 * voronoi_F2(p) - 1.0; }
-float voronoi_F3S(point p) { return 2.0 * voronoi_F3(p) - 1.0; }
-float voronoi_F4S(point p) { return 2.0 * voronoi_F4(p) - 1.0; }
-float voronoi_F1F2S(point p) { return 2.0 * voronoi_F1F2(p) - 1.0; }
-float voronoi_CrS(point p) { return 2.0 * voronoi_Cr(p) - 1.0; }
-
/* Noise Bases */
float safe_noise(point p, string type)
@@ -172,39 +106,9 @@ float safe_noise(point p, string type)
return f;
}
-float noise_basis(point p, string basis)
-{
- if (basis == "Perlin")
- return safe_noise(p, "unsigned");
- if (basis == "Voronoi F1")
- return voronoi_F1S(p);
- if (basis == "Voronoi F2")
- return voronoi_F2S(p);
- if (basis == "Voronoi F3")
- return voronoi_F3S(p);
- if (basis == "Voronoi F4")
- return voronoi_F4S(p);
- if (basis == "Voronoi F2-F1")
- return voronoi_F1F2S(p);
- if (basis == "Voronoi Crackle")
- return voronoi_CrS(p);
- if (basis == "Cell Noise")
- return cellnoise(p);
-
- return 0.0;
-}
-
-/* Soft/Hard Noise */
-
-float noise_basis_hard(point p, string basis, int hard)
-{
- float t = noise_basis(p, basis);
- return (hard) ? fabs(2.0 * t - 1.0) : t;
-}
-
/* Turbulence */
-float noise_turbulence(point p, string basis, float details, int hard)
+float noise_turbulence(point p, float details, int hard)
{
float fscale = 1.0;
float amp = 1.0;
@@ -215,7 +119,7 @@ float noise_turbulence(point p, string basis, float details, int hard)
n = (int)octaves;
for (i = 0; i <= n; i++) {
- float t = noise_basis(fscale * p, basis);
+ float t = safe_noise(fscale * p, "unsigned");
if (hard)
t = fabs(2.0 * t - 1.0);
@@ -228,7 +132,7 @@ float noise_turbulence(point p, string basis, float details, int hard)
float rmd = octaves - floor(octaves);
if (rmd != 0.0) {
- float t = noise_basis(fscale * p, basis);
+ float t = safe_noise(fscale * p, "unsigned");
if (hard)
t = fabs(2.0 * t - 1.0);
diff --git a/intern/cycles/kernel/shaders/node_voronoi_texture.osl b/intern/cycles/kernel/shaders/node_voronoi_texture.osl
index df169599d08..29e143ae207 100644
--- a/intern/cycles/kernel/shaders/node_voronoi_texture.osl
+++ b/intern/cycles/kernel/shaders/node_voronoi_texture.osl
@@ -37,7 +37,7 @@ shader node_voronoi_texture(
float da[4];
point pa[4];
- voronoi(p * Scale, "Distance Squared", 1.0, da, pa);
+ voronoi(p * Scale, 1.0, da, pa);
/* Colored output */
if (Coloring == "Intensity") {
diff --git a/intern/cycles/kernel/shaders/node_wave_texture.osl b/intern/cycles/kernel/shaders/node_wave_texture.osl
index a95752fc592..569f284cbac 100644
--- a/intern/cycles/kernel/shaders/node_wave_texture.osl
+++ b/intern/cycles/kernel/shaders/node_wave_texture.osl
@@ -31,7 +31,7 @@ float wave(point p, string type, float detail, float distortion, float dscale)
}
if (distortion != 0.0) {
- n = n + (distortion * noise_turbulence(p * dscale, "Perlin", detail, 0));
+ n = n + (distortion * noise_turbulence(p * dscale, detail, 0));
}
return 0.5 + 0.5 * sin(n);
}
diff --git a/intern/cycles/kernel/split/kernel_background_buffer_update.h b/intern/cycles/kernel/split/kernel_background_buffer_update.h
new file mode 100644
index 00000000000..181a1054a0d
--- /dev/null
+++ b/intern/cycles/kernel/split/kernel_background_buffer_update.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2011-2015 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 "kernel_split_common.h"
+
+/* Note on kernel_background_buffer_update kernel.
+ * This is the fourth kernel in the ray tracing logic, and the third
+ * of the path iteration kernels. This kernel takes care of rays that hit
+ * the background (sceneintersect kernel), and for the rays of
+ * state RAY_UPDATE_BUFFER it updates the ray's accumulated radiance in
+ * the output buffer. This kernel also takes care of rays that have been determined
+ * to-be-regenerated.
+ *
+ * We will empty QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS queue in this kernel
+ *
+ * Typically all rays that are in state RAY_HIT_BACKGROUND, RAY_UPDATE_BUFFER
+ * will be eventually set to RAY_TO_REGENERATE state in this kernel. Finally all rays of ray_state
+ * RAY_TO_REGENERATE will be regenerated and put in queue QUEUE_ACTIVE_AND_REGENERATED_RAYS.
+ *
+ * The input and output are as follows,
+ *
+ * rng_coop ---------------------------------------------|--- kernel_background_buffer_update --|--- PathRadiance_coop
+ * throughput_coop --------------------------------------| |--- L_transparent_coop
+ * per_sample_output_buffers ----------------------------| |--- per_sample_output_buffers
+ * Ray_coop ---------------------------------------------| |--- ray_state
+ * PathState_coop ---------------------------------------| |--- Queue_data (QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS)
+ * L_transparent_coop -----------------------------------| |--- Queue_data (QUEUE_ACTIVE_AND_REGENERATED_RAYS)
+ * ray_state --------------------------------------------| |--- Queue_index (QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS)
+ * Queue_data (QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS) ----| |--- Queue_index (QUEUE_ACTIVE_AND_REGENERATED_RAYS)
+ * Queue_index (QUEUE_ACTIVE_AND_REGENERATED_RAYS) ------| |--- work_array
+ * parallel_samples -------------------------------------| |--- PathState_coop
+ * end_sample -------------------------------------------| |--- throughput_coop
+ * kg (globals + data) ----------------------------------| |--- rng_coop
+ * rng_state --------------------------------------------| |--- Ray
+ * PathRadiance_coop ------------------------------------| |
+ * sw ---------------------------------------------------| |
+ * sh ---------------------------------------------------| |
+ * sx ---------------------------------------------------| |
+ * sy ---------------------------------------------------| |
+ * stride -----------------------------------------------| |
+ * work_array -------------------------------------------| |--- work_array
+ * queuesize --------------------------------------------| |
+ * start_sample -----------------------------------------| |--- work_pool_wgs
+ * work_pool_wgs ----------------------------------------| |
+ * num_samples ------------------------------------------| |
+ *
+ * note on shader_data : shader_data argument is neither an input nor an output for this kernel. It is just filled and consumed here itself.
+ * Note on Queues :
+ * This kernel fetches rays from QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS queue.
+ *
+ * State of queues when this kernel is called :
+ * At entry,
+ * QUEUE_ACTIVE_AND_REGENERATED_RAYS will be filled with RAY_ACTIVE rays
+ * QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will be filled with RAY_UPDATE_BUFFER, RAY_HIT_BACKGROUND, RAY_TO_REGENERATE rays
+ * At exit,
+ * QUEUE_ACTIVE_AND_REGENERATED_RAYS will be filled with RAY_ACTIVE and RAY_REGENERATED rays
+ * QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will be empty
+ */
+ccl_device char kernel_background_buffer_update(
+ ccl_global char *globals,
+ ccl_constant KernelData *data,
+ ccl_global char *shader_data,
+ ccl_global float *per_sample_output_buffers,
+ ccl_global uint *rng_state,
+ ccl_global uint *rng_coop, /* Required for buffer Update */
+ ccl_global float3 *throughput_coop, /* Required for background hit processing */
+ PathRadiance *PathRadiance_coop, /* Required for background hit processing and buffer Update */
+ ccl_global Ray *Ray_coop, /* Required for background hit processing */
+ ccl_global PathState *PathState_coop, /* Required for background hit processing */
+ ccl_global float *L_transparent_coop, /* Required for background hit processing and buffer Update */
+ ccl_global char *ray_state, /* Stores information on the current state of a ray */
+ int sw, int sh, int sx, int sy, int stride,
+ int rng_state_offset_x,
+ int rng_state_offset_y,
+ int rng_state_stride,
+ ccl_global unsigned int *work_array, /* Denotes work of each ray */
+ int end_sample,
+ int start_sample,
+#ifdef __WORK_STEALING__
+ ccl_global unsigned int *work_pool_wgs,
+ unsigned int num_samples,
+#endif
+#ifdef __KERNEL_DEBUG__
+ DebugData *debugdata_coop,
+#endif
+ int parallel_samples, /* Number of samples to be processed in parallel */
+ int ray_index)
+{
+ char enqueue_flag = 0;
+
+ /* Load kernel globals structure and ShaderData strucuture */
+ KernelGlobals *kg = (KernelGlobals *)globals;
+ ShaderData *sd = (ShaderData *)shader_data;
+
+#ifdef __KERNEL_DEBUG__
+ DebugData *debug_data = &debugdata_coop[ray_index];
+#endif
+ ccl_global PathState *state = &PathState_coop[ray_index];
+ PathRadiance *L = L = &PathRadiance_coop[ray_index];
+ ccl_global Ray *ray = &Ray_coop[ray_index];
+ ccl_global float3 *throughput = &throughput_coop[ray_index];
+ ccl_global float *L_transparent = &L_transparent_coop[ray_index];
+ ccl_global uint *rng = &rng_coop[ray_index];
+
+#ifdef __WORK_STEALING__
+ unsigned int my_work;
+ ccl_global float *initial_per_sample_output_buffers;
+ ccl_global uint *initial_rng;
+#endif
+ unsigned int sample;
+ unsigned int tile_x;
+ unsigned int tile_y;
+ unsigned int pixel_x;
+ unsigned int pixel_y;
+ unsigned int my_sample_tile;
+
+#ifdef __WORK_STEALING__
+ my_work = work_array[ray_index];
+ sample = get_my_sample(my_work, sw, sh, parallel_samples, ray_index) + start_sample;
+ get_pixel_tile_position(&pixel_x, &pixel_y,
+ &tile_x, &tile_y,
+ my_work,
+ sw, sh, sx, sy,
+ parallel_samples,
+ ray_index);
+ my_sample_tile = 0;
+ initial_per_sample_output_buffers = per_sample_output_buffers;
+ initial_rng = rng_state;
+#else /* __WORK_STEALING__ */
+ sample = work_array[ray_index];
+ int tile_index = ray_index / parallel_samples;
+ /* buffer and rng_state's stride is "stride". Find x and y using ray_index */
+ tile_x = tile_index % sw;
+ tile_y = tile_index / sw;
+ my_sample_tile = ray_index - (tile_index * parallel_samples);
+#endif /* __WORK_STEALING__ */
+
+ rng_state += (rng_state_offset_x + tile_x) + (rng_state_offset_y + tile_y) * rng_state_stride;
+ per_sample_output_buffers += (((tile_x + (tile_y * stride)) * parallel_samples) + my_sample_tile) * kernel_data.film.pass_stride;
+
+ if(IS_STATE(ray_state, ray_index, RAY_HIT_BACKGROUND)) {
+ /* eval background shader if nothing hit */
+ if(kernel_data.background.transparent && (state->flag & PATH_RAY_CAMERA)) {
+ *L_transparent = (*L_transparent) + average((*throughput));
+#ifdef __PASSES__
+ if(!(kernel_data.film.pass_flag & PASS_BACKGROUND))
+#endif
+ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER);
+ }
+
+ if(IS_STATE(ray_state, ray_index, RAY_HIT_BACKGROUND))
+ {
+#ifdef __BACKGROUND__
+ /* sample background shader */
+ float3 L_background = indirect_background(kg, state, ray, sd);
+ path_radiance_accum_background(L, (*throughput), L_background, state->bounce);
+#endif
+ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER);
+ }
+ }
+
+ if(IS_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER)) {
+ float3 L_sum = path_radiance_clamp_and_sum(kg, L);
+ kernel_write_light_passes(kg, per_sample_output_buffers, L, sample);
+#ifdef __KERNEL_DEBUG__
+ kernel_write_debug_passes(kg, per_sample_output_buffers, state, debug_data, sample);
+#endif
+ float4 L_rad = make_float4(L_sum.x, L_sum.y, L_sum.z, 1.0f - (*L_transparent));
+
+ /* accumulate result in output buffer */
+ kernel_write_pass_float4(per_sample_output_buffers, sample, L_rad);
+ path_rng_end(kg, rng_state, *rng);
+
+ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_TO_REGENERATE);
+ }
+
+ if(IS_STATE(ray_state, ray_index, RAY_TO_REGENERATE)) {
+#ifdef __WORK_STEALING__
+ /* We have completed current work; So get next work */
+ int valid_work = get_next_work(work_pool_wgs, &my_work, sw, sh, num_samples, parallel_samples, ray_index);
+ if(!valid_work) {
+ /* If work is invalid, this means no more work is available and the thread may exit */
+ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_INACTIVE);
+ }
+#else /* __WORK_STEALING__ */
+ if((sample + parallel_samples) >= end_sample) {
+ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_INACTIVE);
+ }
+#endif /* __WORK_STEALING__ */
+
+ if(IS_STATE(ray_state, ray_index, RAY_TO_REGENERATE)) {
+#ifdef __WORK_STEALING__
+ work_array[ray_index] = my_work;
+ /* Get the sample associated with the current work */
+ sample = get_my_sample(my_work, sw, sh, parallel_samples, ray_index) + start_sample;
+ /* Get pixel and tile position associated with current work */
+ get_pixel_tile_position(&pixel_x, &pixel_y, &tile_x, &tile_y, my_work, sw, sh, sx, sy, parallel_samples, ray_index);
+ my_sample_tile = 0;
+
+ /* Remap rng_state according to the current work */
+ rng_state = initial_rng + ((rng_state_offset_x + tile_x) + (rng_state_offset_y + tile_y) * rng_state_stride);
+ /* Remap per_sample_output_buffers according to the current work */
+ per_sample_output_buffers = initial_per_sample_output_buffers
+ + (((tile_x + (tile_y * stride)) * parallel_samples) + my_sample_tile) * kernel_data.film.pass_stride;
+#else /* __WORK_STEALING__ */
+ work_array[ray_index] = sample + parallel_samples;
+ sample = work_array[ray_index];
+
+ /* Get ray position from ray index */
+ pixel_x = sx + ((ray_index / parallel_samples) % sw);
+ pixel_y = sy + ((ray_index / parallel_samples) / sw);
+#endif /* __WORK_STEALING__ */
+
+ /* Initialize random numbers and ray. */
+ kernel_path_trace_setup(kg, rng_state, sample, pixel_x, pixel_y, rng, ray);
+
+ if(ray->t != 0.0f) {
+ /* Initialize throughput, L_transparent, Ray, PathState;
+ * These rays proceed with path-iteration.
+ */
+ *throughput = make_float3(1.0f, 1.0f, 1.0f);
+ *L_transparent = 0.0f;
+ path_radiance_init(L, kernel_data.film.use_light_pass);
+ path_state_init(kg, state, rng, sample, ray);
+#ifdef __KERNEL_DEBUG__
+ debug_data_init(debug_data);
+#endif
+ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_REGENERATED);
+ enqueue_flag = 1;
+ } else {
+ /* These rays do not participate in path-iteration. */
+ float4 L_rad = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ /* Accumulate result in output buffer. */
+ kernel_write_pass_float4(per_sample_output_buffers, sample, L_rad);
+ path_rng_end(kg, rng_state, *rng);
+
+ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_TO_REGENERATE);
+ }
+ }
+ }
+ return enqueue_flag;
+}
diff --git a/intern/cycles/kernel/split/kernel_data_init.h b/intern/cycles/kernel/split/kernel_data_init.h
new file mode 100644
index 00000000000..2cd98e466c1
--- /dev/null
+++ b/intern/cycles/kernel/split/kernel_data_init.h
@@ -0,0 +1,418 @@
+/*
+ * Copyright 2011-2015 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 "kernel_split_common.h"
+
+/* Note on kernel_data_initialization kernel
+ * This kernel Initializes structures needed in path-iteration kernels.
+ * This is the first kernel in ray-tracing logic.
+ *
+ * Ray state of rays outside the tile-boundary will be marked RAY_INACTIVE
+ *
+ * Its input and output are as follows,
+ *
+ * Un-initialized rng---------------|--- kernel_data_initialization ---|--- Initialized rng
+ * Un-initialized throughput -------| |--- Initialized throughput
+ * Un-initialized L_transparent ----| |--- Initialized L_transparent
+ * Un-initialized PathRadiance -----| |--- Initialized PathRadiance
+ * Un-initialized Ray --------------| |--- Initialized Ray
+ * Un-initialized PathState --------| |--- Initialized PathState
+ * Un-initialized QueueData --------| |--- Initialized QueueData (to QUEUE_EMPTY_SLOT)
+ * Un-initilaized QueueIndex -------| |--- Initialized QueueIndex (to 0)
+ * Un-initialized use_queues_flag---| |--- Initialized use_queues_flag (to false)
+ * Un-initialized ray_state --------| |--- Initialized ray_state
+ * parallel_samples --------------- | |--- Initialized per_sample_output_buffers
+ * rng_state -----------------------| |--- Initialized work_array
+ * data ----------------------------| |--- Initialized work_pool_wgs
+ * start_sample --------------------| |
+ * sx ------------------------------| |
+ * sy ------------------------------| |
+ * sw ------------------------------| |
+ * sh ------------------------------| |
+ * stride --------------------------| |
+ * queuesize -----------------------| |
+ * num_samples ---------------------| |
+ *
+ * Note on Queues :
+ * All slots in queues are initialized to queue empty slot;
+ * The number of elements in the queues is initialized to 0;
+ */
+ccl_device void kernel_data_init(
+ ccl_global char *globals,
+ ccl_global char *shader_data_sd, /* Arguments related to ShaderData */
+ ccl_global char *shader_data_sd_DL_shadow, /* Arguments related to ShaderData */
+
+ ccl_global float3 *P_sd,
+ ccl_global float3 *P_sd_DL_shadow,
+
+ ccl_global float3 *N_sd,
+ ccl_global float3 *N_sd_DL_shadow,
+
+ ccl_global float3 *Ng_sd,
+ ccl_global float3 *Ng_sd_DL_shadow,
+
+ ccl_global float3 *I_sd,
+ ccl_global float3 *I_sd_DL_shadow,
+
+ ccl_global int *shader_sd,
+ ccl_global int *shader_sd_DL_shadow,
+
+ ccl_global int *flag_sd,
+ ccl_global int *flag_sd_DL_shadow,
+
+ ccl_global int *prim_sd,
+ ccl_global int *prim_sd_DL_shadow,
+
+ ccl_global int *type_sd,
+ ccl_global int *type_sd_DL_shadow,
+
+ ccl_global float *u_sd,
+ ccl_global float *u_sd_DL_shadow,
+
+ ccl_global float *v_sd,
+ ccl_global float *v_sd_DL_shadow,
+
+ ccl_global int *object_sd,
+ ccl_global int *object_sd_DL_shadow,
+
+ ccl_global float *time_sd,
+ ccl_global float *time_sd_DL_shadow,
+
+ ccl_global float *ray_length_sd,
+ ccl_global float *ray_length_sd_DL_shadow,
+
+ ccl_global int *ray_depth_sd,
+ ccl_global int *ray_depth_sd_DL_shadow,
+
+ ccl_global int *transparent_depth_sd,
+ ccl_global int *transparent_depth_sd_DL_shadow,
+
+ /* Ray differentials. */
+ ccl_global differential3 *dP_sd,
+ ccl_global differential3 *dP_sd_DL_shadow,
+
+ ccl_global differential3 *dI_sd,
+ ccl_global differential3 *dI_sd_DL_shadow,
+
+ ccl_global differential *du_sd,
+ ccl_global differential *du_sd_DL_shadow,
+
+ ccl_global differential *dv_sd,
+ ccl_global differential *dv_sd_DL_shadow,
+
+ /* Dp/Du */
+ ccl_global float3 *dPdu_sd,
+ ccl_global float3 *dPdu_sd_DL_shadow,
+
+ ccl_global float3 *dPdv_sd,
+ ccl_global float3 *dPdv_sd_DL_shadow,
+
+ /* Object motion. */
+ ccl_global Transform *ob_tfm_sd,
+ ccl_global Transform *ob_tfm_sd_DL_shadow,
+
+ ccl_global Transform *ob_itfm_sd,
+ ccl_global Transform *ob_itfm_sd_DL_shadow,
+
+ ShaderClosure *closure_sd,
+ ShaderClosure *closure_sd_DL_shadow,
+
+ ccl_global int *num_closure_sd,
+ ccl_global int *num_closure_sd_DL_shadow,
+
+ ccl_global float *randb_closure_sd,
+ ccl_global float *randb_closure_sd_DL_shadow,
+
+ ccl_global float3 *ray_P_sd,
+ ccl_global float3 *ray_P_sd_DL_shadow,
+
+ ccl_global differential3 *ray_dP_sd,
+ ccl_global differential3 *ray_dP_sd_DL_shadow,
+
+ ccl_constant KernelData *data,
+ ccl_global float *per_sample_output_buffers,
+ ccl_global uint *rng_state,
+ ccl_global uint *rng_coop, /* rng array to store rng values for all rays */
+ ccl_global float3 *throughput_coop, /* throughput array to store throughput values for all rays */
+ ccl_global float *L_transparent_coop, /* L_transparent array to store L_transparent values for all rays */
+ PathRadiance *PathRadiance_coop, /* PathRadiance array to store PathRadiance values for all rays */
+ ccl_global Ray *Ray_coop, /* Ray array to store Ray information for all rays */
+ ccl_global PathState *PathState_coop, /* PathState array to store PathState information for all rays */
+ ccl_global char *ray_state, /* Stores information on current state of a ray */
+
+#define KERNEL_TEX(type, ttype, name) \
+ ccl_global type *name,
+#include "../kernel_textures.h"
+
+ int start_sample, int sx, int sy, int sw, int sh, int offset, int stride,
+ int rng_state_offset_x,
+ int rng_state_offset_y,
+ int rng_state_stride,
+ ccl_global int *Queue_data, /* Memory for queues */
+ ccl_global int *Queue_index, /* Tracks the number of elements in queues */
+ int queuesize, /* size (capacity) of the queue */
+ ccl_global char *use_queues_flag, /* flag to decide if scene-intersect kernel should use queues to fetch ray index */
+ ccl_global unsigned int *work_array, /* work array to store which work each ray belongs to */
+#ifdef __WORK_STEALING__
+ ccl_global unsigned int *work_pool_wgs, /* Work pool for each work group */
+ unsigned int num_samples, /* Total number of samples per pixel */
+#endif
+#ifdef __KERNEL_DEBUG__
+ DebugData *debugdata_coop,
+#endif
+ int parallel_samples) /* Number of samples to be processed in parallel */
+{
+
+ /* Load kernel globals structure */
+ KernelGlobals *kg = (KernelGlobals *)globals;
+
+ kg->data = data;
+#define KERNEL_TEX(type, ttype, name) \
+ kg->name = name;
+#include "../kernel_textures.h"
+
+ /* Load ShaderData structure */
+ ShaderData *sd = (ShaderData *)shader_data_sd;
+ ShaderData *sd_DL_shadow = (ShaderData *)shader_data_sd_DL_shadow;
+
+ sd->P = P_sd;
+ sd_DL_shadow->P = P_sd_DL_shadow;
+
+ sd->N = N_sd;
+ sd_DL_shadow->N = N_sd_DL_shadow;
+
+ sd->Ng = Ng_sd;
+ sd_DL_shadow->Ng = Ng_sd_DL_shadow;
+
+ sd->I = I_sd;
+ sd_DL_shadow->I = I_sd_DL_shadow;
+
+ sd->shader = shader_sd;
+ sd_DL_shadow->shader = shader_sd_DL_shadow;
+
+ sd->flag = flag_sd;
+ sd_DL_shadow->flag = flag_sd_DL_shadow;
+
+ sd->prim = prim_sd;
+ sd_DL_shadow->prim = prim_sd_DL_shadow;
+
+ sd->type = type_sd;
+ sd_DL_shadow->type = type_sd_DL_shadow;
+
+ sd->u = u_sd;
+ sd_DL_shadow->u = u_sd_DL_shadow;
+
+ sd->v = v_sd;
+ sd_DL_shadow->v = v_sd_DL_shadow;
+
+ sd->object = object_sd;
+ sd_DL_shadow->object = object_sd_DL_shadow;
+
+ sd->time = time_sd;
+ sd_DL_shadow->time = time_sd_DL_shadow;
+
+ sd->ray_length = ray_length_sd;
+ sd_DL_shadow->ray_length = ray_length_sd_DL_shadow;
+
+ sd->ray_depth = ray_depth_sd;
+ sd_DL_shadow->ray_depth = ray_depth_sd_DL_shadow;
+
+ sd->transparent_depth = transparent_depth_sd;
+ sd_DL_shadow->transparent_depth = transparent_depth_sd_DL_shadow;
+
+#ifdef __RAY_DIFFERENTIALS__
+ sd->dP = dP_sd;
+ sd_DL_shadow->dP = dP_sd_DL_shadow;
+
+ sd->dI = dI_sd;
+ sd_DL_shadow->dI = dI_sd_DL_shadow;
+
+ sd->du = du_sd;
+ sd_DL_shadow->du = du_sd_DL_shadow;
+
+ sd->dv = dv_sd;
+ sd_DL_shadow->dv = dv_sd_DL_shadow;
+#ifdef __DPDU__
+ sd->dPdu = dPdu_sd;
+ sd_DL_shadow->dPdu = dPdu_sd_DL_shadow;
+
+ sd->dPdv = dPdv_sd;
+ sd_DL_shadow->dPdv = dPdv_sd_DL_shadow;
+#endif
+#endif
+
+#ifdef __OBJECT_MOTION__
+ sd->ob_tfm = ob_tfm_sd;
+ sd_DL_shadow->ob_tfm = ob_tfm_sd_DL_shadow;
+
+ sd->ob_itfm = ob_itfm_sd;
+ sd_DL_shadow->ob_itfm = ob_itfm_sd_DL_shadow;
+#endif
+
+ sd->closure = closure_sd;
+ sd_DL_shadow->closure = closure_sd_DL_shadow;
+
+ sd->num_closure = num_closure_sd;
+ sd_DL_shadow->num_closure = num_closure_sd_DL_shadow;
+
+ sd->randb_closure = randb_closure_sd;
+ sd_DL_shadow->randb_closure = randb_closure_sd_DL_shadow;
+
+ sd->ray_P = ray_P_sd;
+ sd_DL_shadow->ray_P = ray_P_sd_DL_shadow;
+
+ sd->ray_dP = ray_dP_sd;
+ sd_DL_shadow->ray_dP = ray_dP_sd_DL_shadow;
+
+ int thread_index = get_global_id(1) * get_global_size(0) + get_global_id(0);
+
+#ifdef __WORK_STEALING__
+ int lid = get_local_id(1) * get_local_size(0) + get_local_id(0);
+ /* Initialize work_pool_wgs */
+ if(lid == 0) {
+ int group_index = get_group_id(1) * get_num_groups(0) + get_group_id(0);
+ work_pool_wgs[group_index] = 0;
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+#endif /* __WORK_STEALING__ */
+
+ /* Initialize queue data and queue index. */
+ if(thread_index < queuesize) {
+ /* Initialize active ray queue */
+ Queue_data[QUEUE_ACTIVE_AND_REGENERATED_RAYS * queuesize + thread_index] = QUEUE_EMPTY_SLOT;
+ /* Initialize background and buffer update queue */
+ Queue_data[QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS * queuesize + thread_index] = QUEUE_EMPTY_SLOT;
+ /* Initialize shadow ray cast of AO queue */
+ Queue_data[QUEUE_SHADOW_RAY_CAST_AO_RAYS * queuesize + thread_index] = QUEUE_EMPTY_SLOT;
+ /* Initialize shadow ray cast of direct lighting queue */
+ Queue_data[QUEUE_SHADOW_RAY_CAST_DL_RAYS * queuesize + thread_index] = QUEUE_EMPTY_SLOT;
+ }
+
+ if(thread_index == 0) {
+ Queue_index[QUEUE_ACTIVE_AND_REGENERATED_RAYS] = 0;
+ Queue_index[QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS] = 0;
+ Queue_index[QUEUE_SHADOW_RAY_CAST_AO_RAYS] = 0;
+ Queue_index[QUEUE_SHADOW_RAY_CAST_DL_RAYS] = 0;
+ /* The scene-intersect kernel should not use the queues very first time.
+ * since the queue would be empty.
+ */
+ use_queues_flag[0] = 0;
+ }
+
+ int x = get_global_id(0);
+ int y = get_global_id(1);
+
+ if(x < (sw * parallel_samples) && y < sh) {
+
+ int ray_index = x + y * (sw * parallel_samples);
+
+ /* This is the first assignment to ray_state;
+ * So we dont use ASSIGN_RAY_STATE macro.
+ */
+ ray_state[ray_index] = RAY_ACTIVE;
+
+ unsigned int my_sample;
+ unsigned int pixel_x;
+ unsigned int pixel_y;
+ unsigned int tile_x;
+ unsigned int tile_y;
+ unsigned int my_sample_tile;
+
+#ifdef __WORK_STEALING__
+ unsigned int my_work = 0;
+ /* Get work. */
+ get_next_work(work_pool_wgs, &my_work, sw, sh, num_samples, parallel_samples, ray_index);
+ /* Get the sample associated with the work. */
+ my_sample = get_my_sample(my_work, sw, sh, parallel_samples, ray_index) + start_sample;
+
+ my_sample_tile = 0;
+
+ /* Get pixel and tile position associated with the work. */
+ get_pixel_tile_position(&pixel_x, &pixel_y,
+ &tile_x, &tile_y,
+ my_work,
+ sw, sh, sx, sy,
+ parallel_samples,
+ ray_index);
+ work_array[ray_index] = my_work;
+#else /* __WORK_STEALING__ */
+ unsigned int tile_index = ray_index / parallel_samples;
+ tile_x = tile_index % sw;
+ tile_y = tile_index / sw;
+ my_sample_tile = ray_index - (tile_index * parallel_samples);
+ my_sample = my_sample_tile + start_sample;
+
+ /* Initialize work array. */
+ work_array[ray_index] = my_sample ;
+
+ /* Calculate pixel position of this ray. */
+ pixel_x = sx + tile_x;
+ pixel_y = sy + tile_y;
+#endif /* __WORK_STEALING__ */
+
+ rng_state += (rng_state_offset_x + tile_x) + (rng_state_offset_y + tile_y) * rng_state_stride;
+
+ /* Initialise per_sample_output_buffers to all zeros. */
+ per_sample_output_buffers += (((tile_x + (tile_y * stride)) * parallel_samples) + (my_sample_tile)) * kernel_data.film.pass_stride;
+ int per_sample_output_buffers_iterator = 0;
+ for(per_sample_output_buffers_iterator = 0;
+ per_sample_output_buffers_iterator < kernel_data.film.pass_stride;
+ per_sample_output_buffers_iterator++)
+ {
+ per_sample_output_buffers[per_sample_output_buffers_iterator] = 0.0f;
+ }
+
+ /* Initialize random numbers and ray. */
+ kernel_path_trace_setup(kg,
+ rng_state,
+ my_sample,
+ pixel_x, pixel_y,
+ &rng_coop[ray_index],
+ &Ray_coop[ray_index]);
+
+ if(Ray_coop[ray_index].t != 0.0f) {
+ /* Initialize throuput, L_transparent, Ray, PathState;
+ * These rays proceed with path-iteration.
+ */
+ throughput_coop[ray_index] = make_float3(1.0f, 1.0f, 1.0f);
+ L_transparent_coop[ray_index] = 0.0f;
+ path_radiance_init(&PathRadiance_coop[ray_index], kernel_data.film.use_light_pass);
+ path_state_init(kg,
+ &PathState_coop[ray_index],
+ &rng_coop[ray_index],
+ my_sample,
+ &Ray_coop[ray_index]);
+#ifdef __KERNEL_DEBUG__
+ debug_data_init(&debugdata_coop[ray_index]);
+#endif
+ } else {
+ /* These rays do not participate in path-iteration. */
+
+ float4 L_rad = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ /* Accumulate result in output buffer. */
+ kernel_write_pass_float4(per_sample_output_buffers, my_sample, L_rad);
+ path_rng_end(kg, rng_state, rng_coop[ray_index]);
+
+ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_TO_REGENERATE);
+ }
+ }
+
+ /* Mark rest of the ray-state indices as RAY_INACTIVE. */
+ if(thread_index < (get_global_size(0) * get_global_size(1)) - (sh * (sw * parallel_samples))) {
+ /* First assignment, hence we dont use ASSIGN_RAY_STATE macro */
+ ray_state[((sw * parallel_samples) * sh) + thread_index] = RAY_INACTIVE;
+ }
+}
diff --git a/intern/cycles/kernel/split/kernel_direct_lighting.h b/intern/cycles/kernel/split/kernel_direct_lighting.h
new file mode 100644
index 00000000000..50c83d06140
--- /dev/null
+++ b/intern/cycles/kernel/split/kernel_direct_lighting.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2011-2015 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 "kernel_split_common.h"
+
+/* Note on kernel_direct_lighting kernel.
+ * This is the eighth kernel in the ray tracing logic. This is the seventh
+ * of the path iteration kernels. This kernel takes care of direct lighting
+ * logic. However, the "shadow ray cast" part of direct lighting is handled
+ * in the next kernel.
+ *
+ * This kernels determines the rays for which a shadow_blocked() function associated with direct lighting should be executed.
+ * Those rays for which a shadow_blocked() function for direct-lighting must be executed, are marked with flag RAY_SHADOW_RAY_CAST_DL and
+ * enqueued into the queue QUEUE_SHADOW_RAY_CAST_DL_RAYS
+ *
+ * The input and output are as follows,
+ *
+ * rng_coop -----------------------------------------|--- kernel_direct_lighting --|--- BSDFEval_coop
+ * PathState_coop -----------------------------------| |--- ISLamp_coop
+ * shader_data --------------------------------------| |--- LightRay_coop
+ * ray_state ----------------------------------------| |--- ray_state
+ * Queue_data (QUEUE_ACTIVE_AND_REGENERATED_RAYS) ---| |
+ * kg (globals + data) ------------------------------| |
+ * queuesize ----------------------------------------| |
+ *
+ * note on shader_DL : shader_DL is neither input nor output to this kernel; shader_DL is filled and consumed in this kernel itself.
+ * Note on Queues :
+ * This kernel only reads from the QUEUE_ACTIVE_AND_REGENERATED_RAYS queue and processes
+ * only the rays of state RAY_ACTIVE; If a ray needs to execute the corresponding shadow_blocked
+ * part, after direct lighting, the ray is marked with RAY_SHADOW_RAY_CAST_DL flag.
+ *
+ * State of queues when this kernel is called :
+ * state of queues QUEUE_ACTIVE_AND_REGENERATED_RAYS and QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will be same
+ * before and after this kernel call.
+ * QUEUE_SHADOW_RAY_CAST_DL_RAYS queue will be filled with rays for which a shadow_blocked function must be executed, after this
+ * kernel call. Before this kernel call the QUEUE_SHADOW_RAY_CAST_DL_RAYS will be empty.
+ */
+ccl_device char kernel_direct_lighting(
+ ccl_global char *globals,
+ ccl_constant KernelData *data,
+ ccl_global char *shader_data, /* Required for direct lighting */
+ ccl_global char *shader_DL, /* Required for direct lighting */
+ ccl_global uint *rng_coop, /* Required for direct lighting */
+ ccl_global PathState *PathState_coop, /* Required for direct lighting */
+ ccl_global int *ISLamp_coop, /* Required for direct lighting */
+ ccl_global Ray *LightRay_coop, /* Required for direct lighting */
+ ccl_global BsdfEval *BSDFEval_coop, /* Required for direct lighting */
+ ccl_global char *ray_state, /* Denotes the state of each ray */
+ int ray_index)
+{
+ char enqueue_flag = 0;
+ if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
+ /* Load kernel globals structure and ShaderData structure. */
+ KernelGlobals *kg = (KernelGlobals *)globals;
+ ShaderData *sd = (ShaderData *)shader_data;
+ ShaderData *sd_DL = (ShaderData *)shader_DL;
+
+ ccl_global PathState *state = &PathState_coop[ray_index];
+
+ /* direct lighting */
+#ifdef __EMISSION__
+ if((kernel_data.integrator.use_direct_light &&
+ (ccl_fetch(sd, flag) & SD_BSDF_HAS_EVAL)))
+ {
+ /* Sample illumination from lights to find path contribution. */
+ ccl_global RNG* rng = &rng_coop[ray_index];
+ float light_t = path_state_rng_1D(kg, rng, state, PRNG_LIGHT);
+ float light_u, light_v;
+ path_state_rng_2D(kg, rng, state, PRNG_LIGHT_U, &light_u, &light_v);
+
+ LightSample ls;
+ light_sample(kg,
+ light_t, light_u, light_v,
+ ccl_fetch(sd, time),
+ ccl_fetch(sd, P),
+ state->bounce,
+ &ls);
+
+ Ray light_ray;
+#ifdef __OBJECT_MOTION__
+ light_ray.time = ccl_fetch(sd, time);
+#endif
+
+ BsdfEval L_light;
+ bool is_lamp;
+ if(direct_emission(kg, sd, &ls, &light_ray, &L_light, &is_lamp,
+ state->bounce, state->transparent_bounce, sd_DL))
+ {
+ /* Write intermediate data to global memory to access from
+ * the next kernel.
+ */
+ LightRay_coop[ray_index] = light_ray;
+ BSDFEval_coop[ray_index] = L_light;
+ ISLamp_coop[ray_index] = is_lamp;
+ /* Mark ray state for next shadow kernel. */
+ ADD_RAY_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_DL);
+ enqueue_flag = 1;
+ }
+ }
+#endif /* __EMISSION__ */
+ }
+ return enqueue_flag;
+}
diff --git a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h
new file mode 100644
index 00000000000..a75523a3e53
--- /dev/null
+++ b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2011-2015 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 "kernel_split_common.h"
+
+/* Note on kernel_holdout_emission_blurring_pathtermination_ao kernel.
+ * This is the sixth kernel in the ray tracing logic. This is the fifth
+ * of the path iteration kernels. This kernel takes care of the logic to process
+ * "material of type holdout", indirect primitive emission, bsdf blurring,
+ * probabilistic path termination and AO.
+ *
+ * This kernels determines the rays for which a shadow_blocked() function associated with AO should be executed.
+ * Those rays for which a shadow_blocked() function for AO must be executed are marked with flag RAY_SHADOW_RAY_CAST_ao and
+ * enqueued into the queue QUEUE_SHADOW_RAY_CAST_AO_RAYS
+ *
+ * Ray state of rays that are terminated in this kernel are changed to RAY_UPDATE_BUFFER
+ *
+ * The input and output are as follows,
+ *
+ * rng_coop ---------------------------------------------|--- kernel_holdout_emission_blurring_pathtermination_ao ---|--- Queue_index (QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS)
+ * throughput_coop --------------------------------------| |--- PathState_coop
+ * PathRadiance_coop ------------------------------------| |--- throughput_coop
+ * Intersection_coop ------------------------------------| |--- L_transparent_coop
+ * PathState_coop ---------------------------------------| |--- per_sample_output_buffers
+ * L_transparent_coop -----------------------------------| |--- PathRadiance_coop
+ * shader_data ------------------------------------------| |--- ShaderData
+ * ray_state --------------------------------------------| |--- ray_state
+ * Queue_data (QUEUE_ACTIVE_AND_REGENERATED_RAYS) -------| |--- Queue_data (QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS)
+ * Queue_index (QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS) ---| |--- AOAlpha_coop
+ * kg (globals + data) ----------------------------------| |--- AOBSDF_coop
+ * parallel_samples -------------------------------------| |--- AOLightRay_coop
+ * per_sample_output_buffers ----------------------------| |
+ * sw ---------------------------------------------------| |
+ * sh ---------------------------------------------------| |
+ * sx ---------------------------------------------------| |
+ * sy ---------------------------------------------------| |
+ * stride -----------------------------------------------| |
+ * work_array -------------------------------------------| |
+ * queuesize --------------------------------------------| |
+ * start_sample -----------------------------------------| |
+ *
+ * Note on Queues :
+ * This kernel fetches rays from the queue QUEUE_ACTIVE_AND_REGENERATED_RAYS and processes only
+ * the rays of state RAY_ACTIVE.
+ * There are different points in this kernel where a ray may terminate and reach RAY_UPDATE_BUFFER
+ * state. These rays are enqueued into QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS queue. These rays will
+ * still be present in QUEUE_ACTIVE_AND_REGENERATED_RAYS queue, but since their ray-state has been
+ * changed to RAY_UPDATE_BUFFER, there is no problem.
+ *
+ * State of queues when this kernel is called :
+ * At entry,
+ * QUEUE_ACTIVE_AND_REGENERATED_RAYS will be filled with RAY_ACTIVE and RAY_REGENERATED rays
+ * QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will be filled with RAY_TO_REGENERATE rays.
+ * QUEUE_SHADOW_RAY_CAST_AO_RAYS will be empty.
+ * At exit,
+ * QUEUE_ACTIVE_AND_REGENERATED_RAYS will be filled with RAY_ACTIVE, RAY_REGENERATED and RAY_UPDATE_BUFFER rays
+ * QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will be filled with RAY_TO_REGENERATE and RAY_UPDATE_BUFFER rays
+ * QUEUE_SHADOW_RAY_CAST_AO_RAYS will be filled with rays marked with flag RAY_SHADOW_RAY_CAST_AO
+ */
+ccl_device void kernel_holdout_emission_blurring_pathtermination_ao(
+ ccl_global char *globals,
+ ccl_constant KernelData *data,
+ ccl_global char *shader_data, /* Required throughout the kernel except probabilistic path termination and AO */
+ ccl_global float *per_sample_output_buffers,
+ ccl_global uint *rng_coop, /* Required for "kernel_write_data_passes" and AO */
+ ccl_global float3 *throughput_coop, /* Required for handling holdout material and AO */
+ ccl_global float *L_transparent_coop, /* Required for handling holdout material */
+ PathRadiance *PathRadiance_coop, /* Required for "kernel_write_data_passes" and indirect primitive emission */
+ ccl_global PathState *PathState_coop, /* Required throughout the kernel and AO */
+ Intersection *Intersection_coop, /* Required for indirect primitive emission */
+ ccl_global float3 *AOAlpha_coop, /* Required for AO */
+ ccl_global float3 *AOBSDF_coop, /* Required for AO */
+ ccl_global Ray *AOLightRay_coop, /* Required for AO */
+ int sw, int sh, int sx, int sy, int stride,
+ ccl_global char *ray_state, /* Denotes the state of each ray */
+ ccl_global unsigned int *work_array, /* Denotes the work that each ray belongs to */
+#ifdef __WORK_STEALING__
+ unsigned int start_sample,
+#endif
+ int parallel_samples, /* Number of samples to be processed in parallel */
+ int ray_index,
+ char *enqueue_flag,
+ char *enqueue_flag_AO_SHADOW_RAY_CAST)
+{
+ /* Load kernel globals structure and ShaderData structure */
+ KernelGlobals *kg = (KernelGlobals *)globals;
+ ShaderData *sd = (ShaderData *)shader_data;
+
+#ifdef __WORK_STEALING__
+ unsigned int my_work;
+ unsigned int pixel_x;
+ unsigned int pixel_y;
+#endif
+ unsigned int tile_x;
+ unsigned int tile_y;
+ int my_sample_tile;
+ unsigned int sample;
+
+ ccl_global RNG *rng = 0x0;
+ ccl_global PathState *state = 0x0;
+ float3 throughput;
+
+ if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
+
+ throughput = throughput_coop[ray_index];
+ state = &PathState_coop[ray_index];
+ rng = &rng_coop[ray_index];
+#ifdef __WORK_STEALING__
+ my_work = work_array[ray_index];
+ sample = get_my_sample(my_work, sw, sh, parallel_samples, ray_index) + start_sample;
+ get_pixel_tile_position(&pixel_x, &pixel_y,
+ &tile_x, &tile_y,
+ my_work,
+ sw, sh, sx, sy,
+ parallel_samples,
+ ray_index);
+ my_sample_tile = 0;
+#else /* __WORK_STEALING__ */
+ sample = work_array[ray_index];
+ /* Buffer's stride is "stride"; Find x and y using ray_index. */
+ int tile_index = ray_index / parallel_samples;
+ tile_x = tile_index % sw;
+ tile_y = tile_index / sw;
+ my_sample_tile = ray_index - (tile_index * parallel_samples);
+#endif /* __WORK_STEALING__ */
+ per_sample_output_buffers +=
+ (((tile_x + (tile_y * stride)) * parallel_samples) + my_sample_tile) *
+ kernel_data.film.pass_stride;
+
+ /* holdout */
+#ifdef __HOLDOUT__
+ if((ccl_fetch(sd, flag) & (SD_HOLDOUT|SD_HOLDOUT_MASK)) &&
+ (state->flag & PATH_RAY_CAMERA))
+ {
+ if(kernel_data.background.transparent) {
+ float3 holdout_weight;
+
+ if(ccl_fetch(sd, flag) & SD_HOLDOUT_MASK)
+ holdout_weight = make_float3(1.0f, 1.0f, 1.0f);
+ else
+ holdout_weight = shader_holdout_eval(kg, sd);
+
+ /* any throughput is ok, should all be identical here */
+ L_transparent_coop[ray_index] += average(holdout_weight*throughput);
+ }
+
+ if(ccl_fetch(sd, flag) & SD_HOLDOUT_MASK) {
+ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER);
+ *enqueue_flag = 1;
+ }
+ }
+#endif /* __HOLDOUT__ */
+ }
+
+ if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
+ PathRadiance *L = &PathRadiance_coop[ray_index];
+ /* Holdout mask objects do not write data passes. */
+ kernel_write_data_passes(kg,
+ per_sample_output_buffers,
+ L,
+ sd,
+ sample,
+ state,
+ throughput);
+ /* Blurring of bsdf after bounces, for rays that have a small likelihood
+ * of following this particular path (diffuse, rough glossy.
+ */
+ if(kernel_data.integrator.filter_glossy != FLT_MAX) {
+ float blur_pdf = kernel_data.integrator.filter_glossy*state->min_ray_pdf;
+ if(blur_pdf < 1.0f) {
+ float blur_roughness = sqrtf(1.0f - blur_pdf)*0.5f;
+ shader_bsdf_blur(kg, sd, blur_roughness);
+ }
+ }
+
+#ifdef __EMISSION__
+ /* emission */
+ if(ccl_fetch(sd, flag) & SD_EMISSION) {
+ /* TODO(sergey): is isect.t wrong here for transparent surfaces? */
+ float3 emission = indirect_primitive_emission(
+ kg,
+ sd,
+ Intersection_coop[ray_index].t,
+ state->flag,
+ state->ray_pdf);
+ path_radiance_accum_emission(L, throughput, emission, state->bounce);
+ }
+#endif /* __EMISSION__ */
+
+ /* Path termination. this is a strange place to put the termination, it's
+ * mainly due to the mixed in MIS that we use. gives too many unneeded
+ * shader evaluations, only need emission if we are going to terminate.
+ */
+ float probability = path_state_terminate_probability(kg, state, throughput);
+
+ if(probability == 0.0f) {
+ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER);
+ *enqueue_flag = 1;
+ }
+
+ if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
+ if(probability != 1.0f) {
+ float terminate = path_state_rng_1D_for_decision(kg, rng, state, PRNG_TERMINATE);
+ if(terminate >= probability) {
+ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER);
+ *enqueue_flag = 1;
+ } else {
+ throughput_coop[ray_index] = throughput/probability;
+ }
+ }
+ }
+ }
+
+#ifdef __AO__
+ if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
+ /* ambient occlusion */
+ if(kernel_data.integrator.use_ambient_occlusion ||
+ (ccl_fetch(sd, flag) & SD_AO))
+ {
+ /* todo: solve correlation */
+ float bsdf_u, bsdf_v;
+ path_state_rng_2D(kg, rng, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
+
+ float ao_factor = kernel_data.background.ao_factor;
+ float3 ao_N;
+ AOBSDF_coop[ray_index] = shader_bsdf_ao(kg, sd, ao_factor, &ao_N);
+ AOAlpha_coop[ray_index] = shader_bsdf_alpha(kg, sd);
+
+ float3 ao_D;
+ float ao_pdf;
+ sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
+
+ if(dot(ccl_fetch(sd, Ng), ao_D) > 0.0f && ao_pdf != 0.0f) {
+ Ray _ray;
+ _ray.P = ray_offset(ccl_fetch(sd, P), ccl_fetch(sd, Ng));
+ _ray.D = ao_D;
+ _ray.t = kernel_data.background.ao_distance;
+#ifdef __OBJECT_MOTION__
+ _ray.time = ccl_fetch(sd, time);
+#endif
+ _ray.dP = ccl_fetch(sd, dP);
+ _ray.dD = differential3_zero();
+ AOLightRay_coop[ray_index] = _ray;
+
+ ADD_RAY_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_AO);
+ *enqueue_flag_AO_SHADOW_RAY_CAST = 1;
+ }
+ }
+ }
+#endif /* __AO__ */
+}
diff --git a/intern/cycles/kernel/split/kernel_lamp_emission.h b/intern/cycles/kernel/split/kernel_lamp_emission.h
new file mode 100644
index 00000000000..a8e4b0a06c8
--- /dev/null
+++ b/intern/cycles/kernel/split/kernel_lamp_emission.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2011-2015 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 "kernel_split_common.h"
+
+/* Note on kernel_lamp_emission
+ * This is the 3rd kernel in the ray-tracing logic. This is the second of the
+ * path-iteration kernels. This kernel takes care of the indirect lamp emission logic.
+ * This kernel operates on QUEUE_ACTIVE_AND_REGENERATED_RAYS. It processes rays of state RAY_ACTIVE
+ * and RAY_HIT_BACKGROUND.
+ * We will empty QUEUE_ACTIVE_AND_REGENERATED_RAYS queue in this kernel.
+ * The input/output of the kernel is as follows,
+ * Throughput_coop ------------------------------------|--- kernel_lamp_emission --|--- PathRadiance_coop
+ * Ray_coop -------------------------------------------| |--- Queue_data(QUEUE_ACTIVE_AND_REGENERATED_RAYS)
+ * PathState_coop -------------------------------------| |--- Queue_index(QUEUE_ACTIVE_AND_REGENERATED_RAYS)
+ * kg (globals + data) --------------------------------| |
+ * Intersection_coop ----------------------------------| |
+ * ray_state ------------------------------------------| |
+ * Queue_data (QUEUE_ACTIVE_AND_REGENERATED_RAYS) -----| |
+ * Queue_index (QUEUE_ACTIVE_AND_REGENERATED_RAYS) ----| |
+ * queuesize ------------------------------------------| |
+ * use_queues_flag ------------------------------------| |
+ * sw -------------------------------------------------| |
+ * sh -------------------------------------------------| |
+ * parallel_samples -----------------------------------| |
+ *
+ * note : shader_data is neither input nor output. Its just filled and consumed in the same, kernel_lamp_emission, kernel.
+ */
+ccl_device void kernel_lamp_emission(
+ ccl_global char *globals,
+ ccl_constant KernelData *data,
+ ccl_global char *shader_data, /* Required for lamp emission */
+ ccl_global float3 *throughput_coop, /* Required for lamp emission */
+ PathRadiance *PathRadiance_coop, /* Required for lamp emission */
+ ccl_global Ray *Ray_coop, /* Required for lamp emission */
+ ccl_global PathState *PathState_coop, /* Required for lamp emission */
+ Intersection *Intersection_coop, /* Required for lamp emission */
+ ccl_global char *ray_state, /* Denotes the state of each ray */
+ int sw, int sh,
+ ccl_global char *use_queues_flag, /* Used to decide if this kernel should use
+ * queues to fetch ray index
+ */
+ int parallel_samples, /* Number of samples to be processed in parallel */
+ int ray_index)
+{
+ if(IS_STATE(ray_state, ray_index, RAY_ACTIVE) ||
+ IS_STATE(ray_state, ray_index, RAY_HIT_BACKGROUND))
+ {
+ KernelGlobals *kg = (KernelGlobals *)globals;
+ ShaderData *sd = (ShaderData *)shader_data;
+ PathRadiance *L = &PathRadiance_coop[ray_index];
+
+ float3 throughput = throughput_coop[ray_index];
+ Ray ray = Ray_coop[ray_index];
+ PathState state = PathState_coop[ray_index];
+
+#ifdef __LAMP_MIS__
+ if(kernel_data.integrator.use_lamp_mis && !(state.flag & PATH_RAY_CAMERA)) {
+ /* ray starting from previous non-transparent bounce */
+ Ray light_ray;
+
+ light_ray.P = ray.P - state.ray_t*ray.D;
+ state.ray_t += Intersection_coop[ray_index].t;
+ light_ray.D = ray.D;
+ light_ray.t = state.ray_t;
+ light_ray.time = ray.time;
+ light_ray.dD = ray.dD;
+ light_ray.dP = ray.dP;
+ /* intersect with lamp */
+ float3 emission;
+
+ if(indirect_lamp_emission(kg, &state, &light_ray, &emission, sd)) {
+ path_radiance_accum_emission(L, throughput, emission, state.bounce);
+ }
+ }
+#endif /* __LAMP_MIS__ */
+
+ /* __VOLUME__ feature is disabled */
+#if 0
+#ifdef __VOLUME__
+ /* volume attenuation, emission, scatter */
+ if(state.volume_stack[0].shader != SHADER_NONE) {
+ Ray volume_ray = ray;
+ volume_ray.t = (hit)? isect.t: FLT_MAX;
+
+ bool heterogeneous = volume_stack_is_heterogeneous(kg, state.volume_stack);
+
+#ifdef __VOLUME_DECOUPLED__
+ int sampling_method = volume_stack_sampling_method(kg, state.volume_stack);
+ bool decoupled = kernel_volume_use_decoupled(kg, heterogeneous, true, sampling_method);
+
+ if(decoupled) {
+ /* cache steps along volume for repeated sampling */
+ VolumeSegment volume_segment;
+ ShaderData volume_sd;
+
+ shader_setup_from_volume(kg, &volume_sd, &volume_ray, state.bounce, state.transparent_bounce);
+ kernel_volume_decoupled_record(kg, &state,
+ &volume_ray, &volume_sd, &volume_segment, heterogeneous);
+
+ volume_segment.sampling_method = sampling_method;
+
+ /* emission */
+ if(volume_segment.closure_flag & SD_EMISSION)
+ path_radiance_accum_emission(&L, throughput, volume_segment.accum_emission, state.bounce);
+
+ /* scattering */
+ VolumeIntegrateResult result = VOLUME_PATH_ATTENUATED;
+
+ if(volume_segment.closure_flag & SD_SCATTER) {
+ bool all = false;
+
+ /* direct light sampling */
+ kernel_branched_path_volume_connect_light(kg, rng, &volume_sd,
+ throughput, &state, &L, 1.0f, all, &volume_ray, &volume_segment);
+
+ /* indirect sample. if we use distance sampling and take just
+ * one sample for direct and indirect light, we could share
+ * this computation, but makes code a bit complex */
+ float rphase = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_PHASE);
+ float rscatter = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_SCATTER_DISTANCE);
+
+ result = kernel_volume_decoupled_scatter(kg,
+ &state, &volume_ray, &volume_sd, &throughput,
+ rphase, rscatter, &volume_segment, NULL, true);
+ }
+
+ if(result != VOLUME_PATH_SCATTERED)
+ throughput *= volume_segment.accum_transmittance;
+
+ /* free cached steps */
+ kernel_volume_decoupled_free(kg, &volume_segment);
+
+ if(result == VOLUME_PATH_SCATTERED) {
+ if(kernel_path_volume_bounce(kg, rng, &volume_sd, &throughput, &state, &L, &ray))
+ continue;
+ else
+ break;
+ }
+ }
+ else
+#endif /* __VOLUME_DECOUPLED__ */
+ {
+ /* integrate along volume segment with distance sampling */
+ ShaderData volume_sd;
+ VolumeIntegrateResult result = kernel_volume_integrate(
+ kg, &state, &volume_sd, &volume_ray, &L, &throughput, rng, heterogeneous);
+
+#ifdef __VOLUME_SCATTER__
+ if(result == VOLUME_PATH_SCATTERED) {
+ /* direct lighting */
+ kernel_path_volume_connect_light(kg, rng, &volume_sd, throughput, &state, &L);
+
+ /* indirect light bounce */
+ if(kernel_path_volume_bounce(kg, rng, &volume_sd, &throughput, &state, &L, &ray))
+ continue;
+ else
+ break;
+ }
+#endif /* __VOLUME_SCATTER__ */
+ }
+ }
+#endif /* __VOLUME__ */
+#endif
+ }
+}
diff --git a/intern/cycles/kernel/split/kernel_next_iteration_setup.h b/intern/cycles/kernel/split/kernel_next_iteration_setup.h
new file mode 100644
index 00000000000..2dbdabc5fd3
--- /dev/null
+++ b/intern/cycles/kernel/split/kernel_next_iteration_setup.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2011-2015 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 "kernel_split_common.h"
+
+/* Note on kernel_setup_next_iteration kernel.
+ * This is the tenth kernel in the ray tracing logic. This is the ninth
+ * of the path iteration kernels. This kernel takes care of setting up
+ * Ray for the next iteration of path-iteration and accumulating radiance
+ * corresponding to AO and direct-lighting
+ *
+ * Ray state of rays that are terminated in this kernel are changed to RAY_UPDATE_BUFFER
+ *
+ * The input and output are as follows,
+ *
+ * rng_coop ---------------------------------------------|--- kernel_next_iteration_setup -|--- Queue_index (QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS)
+ * throughput_coop --------------------------------------| |--- Queue_data (QUEUE_HITBF_BUFF_UPDATE_TOREGEN_RAYS)
+ * PathRadiance_coop ------------------------------------| |--- throughput_coop
+ * PathState_coop ---------------------------------------| |--- PathRadiance_coop
+ * shader_data ------------------------------------------| |--- PathState_coop
+ * ray_state --------------------------------------------| |--- ray_state
+ * Queue_data (QUEUE_ACTIVE_AND_REGENERATD_RAYS) --------| |--- Ray_coop
+ * Queue_index (QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS) ---| |--- use_queues_flag
+ * Ray_coop ---------------------------------------------| |
+ * kg (globals + data) ----------------------------------| |
+ * LightRay_dl_coop -------------------------------------|
+ * ISLamp_coop ------------------------------------------|
+ * BSDFEval_coop ----------------------------------------|
+ * LightRay_ao_coop -------------------------------------|
+ * AOBSDF_coop ------------------------------------------|
+ * AOAlpha_coop -----------------------------------------|
+ *
+ * Note on queues,
+ * This kernel fetches rays from the queue QUEUE_ACTIVE_AND_REGENERATED_RAYS and processes only
+ * the rays of state RAY_ACTIVE.
+ * There are different points in this kernel where a ray may terminate and reach RAY_UPDATE_BUFF
+ * state. These rays are enqueued into QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS queue. These rays will
+ * still be present in QUEUE_ACTIVE_AND_REGENERATED_RAYS queue, but since their ray-state has been
+ * changed to RAY_UPDATE_BUFF, there is no problem.
+ *
+ * State of queues when this kernel is called :
+ * At entry,
+ * QUEUE_ACTIVE_AND_REGENERATED_RAYS will be filled with RAY_ACTIVE, RAY_REGENERATED, RAY_UPDATE_BUFFER rays.
+ * QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will be filled with RAY_TO_REGENERATE and RAY_UPDATE_BUFFER rays
+ * At exit,
+ * QUEUE_ACTIVE_AND_REGENERATED_RAYS will be filled with RAY_ACTIVE, RAY_REGENERATED and more RAY_UPDATE_BUFFER rays.
+ * QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will be filled with RAY_TO_REGENERATE and more RAY_UPDATE_BUFFER rays
+ */
+ccl_device char kernel_next_iteration_setup(
+ ccl_global char *globals,
+ ccl_constant KernelData *data,
+ ccl_global char *shader_data, /* Required for setting up ray for next iteration */
+ ccl_global uint *rng_coop, /* Required for setting up ray for next iteration */
+ ccl_global float3 *throughput_coop, /* Required for setting up ray for next iteration */
+ PathRadiance *PathRadiance_coop, /* Required for setting up ray for next iteration */
+ ccl_global Ray *Ray_coop, /* Required for setting up ray for next iteration */
+ ccl_global PathState *PathState_coop, /* Required for setting up ray for next iteration */
+ ccl_global Ray *LightRay_dl_coop, /* Required for radiance update - direct lighting */
+ ccl_global int *ISLamp_coop, /* Required for radiance update - direct lighting */
+ ccl_global BsdfEval *BSDFEval_coop, /* Required for radiance update - direct lighting */
+ ccl_global Ray *LightRay_ao_coop, /* Required for radiance update - AO */
+ ccl_global float3 *AOBSDF_coop, /* Required for radiance update - AO */
+ ccl_global float3 *AOAlpha_coop, /* Required for radiance update - AO */
+ ccl_global char *ray_state, /* Denotes the state of each ray */
+ ccl_global char *use_queues_flag, /* flag to decide if scene_intersect kernel should
+ * use queues to fetch ray index */
+ int ray_index)
+{
+ char enqueue_flag = 0;
+
+ /* Load kernel globals structure and ShaderData structure. */
+ KernelGlobals *kg = (KernelGlobals *)globals;
+ ShaderData *sd = (ShaderData *)shader_data;
+ PathRadiance *L = 0x0;
+ ccl_global PathState *state = 0x0;
+
+ /* Path radiance update for AO/Direct_lighting's shadow blocked. */
+ if(IS_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_DL) ||
+ IS_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_AO))
+ {
+ state = &PathState_coop[ray_index];
+ L = &PathRadiance_coop[ray_index];
+ float3 _throughput = throughput_coop[ray_index];
+
+ if(IS_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_AO)) {
+ float3 shadow = LightRay_ao_coop[ray_index].P;
+ char update_path_radiance = LightRay_ao_coop[ray_index].t;
+ if(update_path_radiance) {
+ path_radiance_accum_ao(L,
+ _throughput,
+ AOAlpha_coop[ray_index],
+ AOBSDF_coop[ray_index],
+ shadow,
+ state->bounce);
+ }
+ REMOVE_RAY_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_AO);
+ }
+
+ if(IS_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_DL)) {
+ float3 shadow = LightRay_dl_coop[ray_index].P;
+ char update_path_radiance = LightRay_dl_coop[ray_index].t;
+ if(update_path_radiance) {
+ BsdfEval L_light = BSDFEval_coop[ray_index];
+ path_radiance_accum_light(L,
+ _throughput,
+ &L_light,
+ shadow,
+ 1.0f,
+ state->bounce,
+ ISLamp_coop[ray_index]);
+ }
+ REMOVE_RAY_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_DL);
+ }
+ }
+
+ if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
+
+ ccl_global float3 *throughput = &throughput_coop[ray_index];
+ ccl_global Ray *ray = &Ray_coop[ray_index];
+ ccl_global RNG* rng = &rng_coop[ray_index];
+ state = &PathState_coop[ray_index];
+ L = &PathRadiance_coop[ray_index];
+
+ /* compute direct lighting and next bounce */
+ if(!kernel_path_surface_bounce(kg, rng, sd, throughput, state, L, ray)) {
+ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER);
+ enqueue_flag = 1;
+ }
+ }
+
+ return enqueue_flag;
+}
diff --git a/intern/cycles/kernel/split/kernel_scene_intersect.h b/intern/cycles/kernel/split/kernel_scene_intersect.h
new file mode 100644
index 00000000000..09e3e5ddd7e
--- /dev/null
+++ b/intern/cycles/kernel/split/kernel_scene_intersect.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2011-2015 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 "kernel_split_common.h"
+
+/* Note on kernel_scene_intersect kernel.
+ * This is the second kernel in the ray tracing logic. This is the first
+ * of the path iteration kernels. This kernel takes care of scene_intersect function.
+ *
+ * This kernel changes the ray_state of RAY_REGENERATED rays to RAY_ACTIVE.
+ * This kernel processes rays of ray state RAY_ACTIVE
+ * This kernel determines the rays that have hit the background and changes their ray state to RAY_HIT_BACKGROUND.
+ *
+ * The input and output are as follows,
+ *
+ * Ray_coop ---------------------------------------|--------- kernel_scene_intersect----------|--- PathState
+ * PathState_coop ---------------------------------| |--- Intersection
+ * ray_state --------------------------------------| |--- ray_state
+ * use_queues_flag --------------------------------| |
+ * parallel_samples -------------------------------| |
+ * QueueData(QUEUE_ACTIVE_AND_REGENERATED_RAYS) ---| |
+ * kg (data + globals) ----------------------------| |
+ * rng_coop ---------------------------------------| |
+ * sw ---------------------------------------------| |
+ * sh ---------------------------------------------| |
+ * queuesize --------------------------------------| |
+ *
+ * Note on Queues :
+ * Ideally we would want kernel_scene_intersect to work on queues.
+ * But during the very first time, the queues will be empty and hence we perform a direct mapping
+ * between ray-index and thread-index; From the next time onward, the queue will be filled and
+ * we may start operating on queues.
+ *
+ * State of queue during the first time this kernel is called :
+ * QUEUE_ACTIVE_AND_REGENERATED_RAYS and QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will be empty.before and after this kernel
+ *
+ * State of queues during other times this kernel is called :
+ * At entry,
+ * QUEUE_ACTIVE_AND_REGENERATED_RAYS will have a mix of RAY_ACTIVE, RAY_UPDATE_BUFFER and RAY_REGENERATED rays;
+ * QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will be filled with RAY_TO_REGENERATE and RAY_UPDATE_BUFFER rays ;
+ * (The rays that are in the state RAY_UPDATE_BUFFER in both the queues are actually the same rays; These
+ * are the rays that were in RAY_ACTIVE state during the initial enqueue but on further processing
+ * , by different kernels, have turned into RAY_UPDATE_BUFFER rays. Since all kernel, even after fetching from
+ * QUEUE_ACTIVE_AND_REGENERATED_RAYS, proceed further based on ray state information, RAY_UPDATE_BUFFER rays
+ * being present in QUEUE_ACTIVE_AND_REGENERATED_RAYS does not cause any logical issues)
+ * At exit,
+ * QUEUE_ACTIVE_AND_REGENERATED_RAYS - All RAY_REGENERATED rays will have been converted to RAY_ACTIVE and
+ * Some rays in QUEUE_ACTIVE_AND_REGENERATED_RAYS queue will move to state RAY_HIT_BACKGROUND
+ * QUEUE_HITBF_BUFF_UPDATE_TOREGEN_RAYS - no change
+ */
+
+ccl_device void kernel_scene_intersect(
+ ccl_global char *globals,
+ ccl_constant KernelData *data,
+ ccl_global uint *rng_coop,
+ ccl_global Ray *Ray_coop, /* Required for scene_intersect */
+ ccl_global PathState *PathState_coop, /* Required for scene_intersect */
+ Intersection *Intersection_coop, /* Required for scene_intersect */
+ ccl_global char *ray_state, /* Denotes the state of each ray */
+ int sw, int sh,
+ ccl_global char *use_queues_flag, /* used to decide if this kernel should use
+ * queues to fetch ray index */
+#ifdef __KERNEL_DEBUG__
+ DebugData *debugdata_coop,
+#endif
+ int parallel_samples, /* Number of samples to be processed in parallel */
+ int ray_index)
+{
+ /* All regenerated rays become active here */
+ if(IS_STATE(ray_state, ray_index, RAY_REGENERATED))
+ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_ACTIVE);
+
+ if(!IS_STATE(ray_state, ray_index, RAY_ACTIVE))
+ return;
+
+ /* Load kernel globals structure */
+ KernelGlobals *kg = (KernelGlobals *)globals;
+
+#ifdef __KERNEL_DEBUG__
+ DebugData *debug_data = &debugdata_coop[ray_index];
+#endif
+ Intersection *isect = &Intersection_coop[ray_index];
+ PathState state = PathState_coop[ray_index];
+ Ray ray = Ray_coop[ray_index];
+
+ /* intersect scene */
+ uint visibility = path_state_ray_visibility(kg, &state);
+
+#ifdef __HAIR__
+ float difl = 0.0f, extmax = 0.0f;
+ uint lcg_state = 0;
+ RNG rng = rng_coop[ray_index];
+
+ if(kernel_data.bvh.have_curves) {
+ if((kernel_data.cam.resolution == 1) && (state.flag & PATH_RAY_CAMERA)) {
+ float3 pixdiff = ray.dD.dx + ray.dD.dy;
+ /*pixdiff = pixdiff - dot(pixdiff, ray.D)*ray.D;*/
+ difl = kernel_data.curve.minimum_width * len(pixdiff) * 0.5f;
+ }
+
+ extmax = kernel_data.curve.maximum_width;
+ lcg_state = lcg_state_init(&rng, &state, 0x51633e2d);
+ }
+
+ bool hit = scene_intersect(kg, &ray, visibility, isect, &lcg_state, difl, extmax);
+#else
+ bool hit = scene_intersect(kg, &ray, visibility, isect, NULL, 0.0f, 0.0f);
+#endif
+
+#ifdef __KERNEL_DEBUG__
+ if(state.flag & PATH_RAY_CAMERA) {
+ debug_data->num_bvh_traversal_steps += isect->num_traversal_steps;
+ }
+#endif
+
+ if(!hit) {
+ /* Change the state of rays that hit the background;
+ * These rays undergo special processing in the
+ * background_bufferUpdate kernel*/
+ ASSIGN_RAY_STATE(ray_state, ray_index, RAY_HIT_BACKGROUND);
+ }
+}
diff --git a/intern/cycles/kernel/split/kernel_shader_eval.h b/intern/cycles/kernel/split/kernel_shader_eval.h
new file mode 100644
index 00000000000..e6fdc592586
--- /dev/null
+++ b/intern/cycles/kernel/split/kernel_shader_eval.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011-2015 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 "kernel_split_common.h"
+
+/* Note on kernel_shader_eval kernel
+ * This kernel is the 5th kernel in the ray tracing logic. This is
+ * the 4rd kernel in path iteration. This kernel sets up the ShaderData
+ * structure from the values computed by the previous kernels. It also identifies
+ * the rays of state RAY_TO_REGENERATE and enqueues them in QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS queue.
+ *
+ * The input and output of the kernel is as follows,
+ * rng_coop -------------------------------------------|--- kernel_shader_eval --|--- shader_data
+ * Ray_coop -------------------------------------------| |--- Queue_data (QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS)
+ * PathState_coop -------------------------------------| |--- Queue_index (QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS)
+ * Intersection_coop ----------------------------------| |
+ * Queue_data (QUEUE_ACTIVE_AND_REGENERATD_RAYS)-------| |
+ * Queue_index(QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS)---| |
+ * ray_state ------------------------------------------| |
+ * kg (globals + data) --------------------------------| |
+ * queuesize ------------------------------------------| |
+ *
+ * Note on Queues :
+ * This kernel reads from the QUEUE_ACTIVE_AND_REGENERATED_RAYS queue and processes
+ * only the rays of state RAY_ACTIVE;
+ * State of queues when this kernel is called,
+ * at entry,
+ * QUEUE_ACTIVE_AND_REGENERATED_RAYS will be filled with RAY_ACTIVE and RAY_REGENERATED rays
+ * QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will be empty.
+ * at exit,
+ * QUEUE_ACTIVE_AND_REGENERATED_RAYS will be filled with RAY_ACTIVE and RAY_REGENERATED rays
+ * QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will be filled with RAY_TO_REGENERATE rays
+ */
+ccl_device void kernel_shader_eval(
+ ccl_global char *globals,
+ ccl_constant KernelData *data,
+ ccl_global char *shader_data, /* Output ShaderData structure to be filled */
+ ccl_global uint *rng_coop, /* Required for rbsdf calculation */
+ ccl_global Ray *Ray_coop, /* Required for setting up shader from ray */
+ ccl_global PathState *PathState_coop, /* Required for all functions in this kernel */
+ Intersection *Intersection_coop, /* Required for setting up shader from ray */
+ ccl_global char *ray_state, /* Denotes the state of each ray */
+ int ray_index)
+{
+ if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
+ KernelGlobals *kg = (KernelGlobals *)globals;
+ ShaderData *sd = (ShaderData *)shader_data;
+ Intersection *isect = &Intersection_coop[ray_index];
+ ccl_global uint *rng = &rng_coop[ray_index];
+ ccl_global PathState *state = &PathState_coop[ray_index];
+ Ray ray = Ray_coop[ray_index];
+
+ shader_setup_from_ray(kg,
+ sd,
+ isect,
+ &ray,
+ state->bounce,
+ state->transparent_bounce);
+ float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF);
+ shader_eval_surface(kg, sd, rbsdf, state->flag, SHADER_CONTEXT_MAIN);
+ }
+}
diff --git a/intern/cycles/kernel/split/kernel_shadow_blocked.h b/intern/cycles/kernel/split/kernel_shadow_blocked.h
new file mode 100644
index 00000000000..154ec53ffbb
--- /dev/null
+++ b/intern/cycles/kernel/split/kernel_shadow_blocked.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2011-2015 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 "kernel_split_common.h"
+
+/* Note on kernel_shadow_blocked kernel.
+ * This is the ninth kernel in the ray tracing logic. This is the eighth
+ * of the path iteration kernels. This kernel takes care of "shadow ray cast"
+ * logic of the direct lighting and AO part of ray tracing.
+ *
+ * The input and output are as follows,
+ *
+ * PathState_coop ----------------------------------|--- kernel_shadow_blocked --|
+ * LightRay_dl_coop --------------------------------| |--- LightRay_dl_coop
+ * LightRay_ao_coop --------------------------------| |--- LightRay_ao_coop
+ * ray_state ---------------------------------------| |--- ray_state
+ * Queue_data(QUEUE_SHADOW_RAY_CAST_AO_RAYS & | |--- Queue_data (QUEUE_SHADOW_RAY_CAST_AO_RAYS & QUEUE_SHADOW_RAY_CAST_AO_RAYS)
+ QUEUE_SHADOW_RAY_CAST_DL_RAYS) -------| |
+ * Queue_index(QUEUE_SHADOW_RAY_CAST_AO_RAYS&
+ QUEUE_SHADOW_RAY_CAST_DL_RAYS) -------| |
+ * kg (globals + data) -----------------------------| |
+ * queuesize ---------------------------------------| |
+ *
+ * Note on shader_shadow : shader_shadow is neither input nor output to this kernel. shader_shadow is filled and consumed in this kernel itself.
+ * Note on queues :
+ * The kernel fetches from QUEUE_SHADOW_RAY_CAST_AO_RAYS and QUEUE_SHADOW_RAY_CAST_DL_RAYS queues. We will empty
+ * these queues this kernel.
+ * State of queues when this kernel is called :
+ * state of queues QUEUE_ACTIVE_AND_REGENERATED_RAYS and QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will be same
+ * before and after this kernel call.
+ * QUEUE_SHADOW_RAY_CAST_AO_RAYS & QUEUE_SHADOW_RAY_CAST_DL_RAYS will be filled with rays marked with flags RAY_SHADOW_RAY_CAST_AO
+ * and RAY_SHADOW_RAY_CAST_DL respectively, during kernel entry.
+ * QUEUE_SHADOW_RAY_CAST_AO_RAYS and QUEUE_SHADOW_RAY_CAST_DL_RAYS will be empty at kernel exit.
+ */
+ccl_device void kernel_shadow_blocked(
+ ccl_global char *globals,
+ ccl_constant KernelData *data,
+ ccl_global char *shader_shadow, /* Required for shadow blocked */
+ ccl_global PathState *PathState_coop, /* Required for shadow blocked */
+ ccl_global Ray *LightRay_dl_coop, /* Required for direct lighting's shadow blocked */
+ ccl_global Ray *LightRay_ao_coop, /* Required for AO's shadow blocked */
+ Intersection *Intersection_coop_AO,
+ Intersection *Intersection_coop_DL,
+ ccl_global char *ray_state,
+ int total_num_rays,
+ char shadow_blocked_type,
+ int ray_index)
+{
+ /* Flag determining if we need to update L. */
+ char update_path_radiance = 0;
+
+ if(IS_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_DL) ||
+ IS_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_AO))
+ {
+ /* Load kernel global structure */
+ KernelGlobals *kg = (KernelGlobals *)globals;
+ ShaderData *sd_shadow = (ShaderData *)shader_shadow;
+
+ ccl_global PathState *state = &PathState_coop[ray_index];
+ ccl_global Ray *light_ray_dl_global = &LightRay_dl_coop[ray_index];
+ ccl_global Ray *light_ray_ao_global = &LightRay_ao_coop[ray_index];
+ Intersection *isect_ao_global = &Intersection_coop_AO[ray_index];
+ Intersection *isect_dl_global = &Intersection_coop_DL[ray_index];
+
+ ccl_global Ray *light_ray_global =
+ shadow_blocked_type == RAY_SHADOW_RAY_CAST_AO
+ ? light_ray_ao_global
+ : light_ray_dl_global;
+ Intersection *isect_global =
+ RAY_SHADOW_RAY_CAST_AO ? isect_ao_global : isect_dl_global;
+
+ float3 shadow;
+ update_path_radiance = !(shadow_blocked(kg,
+ state,
+ light_ray_global,
+ &shadow,
+ sd_shadow,
+ isect_global));
+
+ /* We use light_ray_global's P and t to store shadow and
+ * update_path_radiance.
+ */
+ light_ray_global->P = shadow;
+ light_ray_global->t = update_path_radiance;
+ }
+}
diff --git a/intern/cycles/kernel/split/kernel_split_common.h b/intern/cycles/kernel/split/kernel_split_common.h
new file mode 100644
index 00000000000..e1c7e2cea99
--- /dev/null
+++ b/intern/cycles/kernel/split/kernel_split_common.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2011-2015 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 __KERNEL_SPLIT_H__
+#define __KERNEL_SPLIT_H__
+
+#include "kernel_compat_opencl.h"
+#include "kernel_math.h"
+#include "kernel_types.h"
+#include "kernel_globals.h"
+
+#include "util_atomic.h"
+
+#include "kernel_random.h"
+#include "kernel_projection.h"
+#include "kernel_montecarlo.h"
+#include "kernel_differential.h"
+#include "kernel_camera.h"
+
+#include "geom/geom.h"
+
+#include "kernel_accumulate.h"
+#include "kernel_shader.h"
+#include "kernel_light.h"
+#include "kernel_passes.h"
+
+#ifdef __SUBSURFACE__
+#include "kernel_subsurface.h"
+#endif
+
+#ifdef __VOLUME__
+#include "kernel_volume.h"
+#endif
+
+#include "kernel_path_state.h"
+#include "kernel_shadow.h"
+#include "kernel_emission.h"
+#include "kernel_path_common.h"
+#include "kernel_path_surface.h"
+#include "kernel_path_volume.h"
+
+#ifdef __KERNEL_DEBUG__
+#include "kernel_debug.h"
+#endif
+
+#include "kernel_queues.h"
+#include "kernel_work_stealing.h"
+
+#endif /* __KERNEL_SPLIT_H__ */
diff --git a/intern/cycles/kernel/split/kernel_sum_all_radiance.h b/intern/cycles/kernel/split/kernel_sum_all_radiance.h
new file mode 100644
index 00000000000..a21e9b6a0b1
--- /dev/null
+++ b/intern/cycles/kernel/split/kernel_sum_all_radiance.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2011-2015 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 "../kernel_compat_opencl.h"
+#include "../kernel_math.h"
+#include "../kernel_types.h"
+#include "../kernel_globals.h"
+
+/* Since we process various samples in parallel; The output radiance of different samples
+ * are stored in different locations; This kernel combines the output radiance contributed
+ * by all different samples and stores them in the RenderTile's output buffer.
+ */
+ccl_device void kernel_sum_all_radiance(
+ ccl_constant KernelData *data, /* To get pass_stride to offet into buffer */
+ ccl_global float *buffer, /* Output buffer of RenderTile */
+ ccl_global float *per_sample_output_buffer, /* Radiance contributed by all samples */
+ int parallel_samples, int sw, int sh, int stride,
+ int buffer_offset_x,
+ int buffer_offset_y,
+ int buffer_stride,
+ int start_sample)
+{
+ int x = get_global_id(0);
+ int y = get_global_id(1);
+
+ if(x < sw && y < sh) {
+ buffer += ((buffer_offset_x + x) + (buffer_offset_y + y) * buffer_stride) * (data->film.pass_stride);
+ per_sample_output_buffer += ((x + y * stride) * parallel_samples) * (data->film.pass_stride);
+
+ int sample_stride = (data->film.pass_stride);
+
+ int sample_iterator = 0;
+ int pass_stride_iterator = 0;
+ int num_floats = data->film.pass_stride;
+
+ for(sample_iterator = 0; sample_iterator < parallel_samples; sample_iterator++) {
+ for(pass_stride_iterator = 0; pass_stride_iterator < num_floats; pass_stride_iterator++) {
+ *(buffer + pass_stride_iterator) =
+ (start_sample == 0 && sample_iterator == 0)
+ ? *(per_sample_output_buffer + pass_stride_iterator)
+ : *(buffer + pass_stride_iterator) + *(per_sample_output_buffer + pass_stride_iterator);
+ }
+ per_sample_output_buffer += sample_stride;
+ }
+ }
+}
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index d59c9b9e61c..e9b36dd1f39 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -87,7 +87,7 @@ ccl_device_inline int stack_load_int(float *stack, uint a)
return __float_as_int(stack[a]);
}
-ccl_device_inline float stack_load_int_default(float *stack, uint a, uint value)
+ccl_device_inline int stack_load_int_default(float *stack, uint a, uint value)
{
return (a == (uint)SVM_STACK_INVALID)? (int)value: stack_load_int(stack, a);
}
@@ -142,6 +142,8 @@ CCL_NAMESPACE_END
#include "svm_noise.h"
#include "svm_texture.h"
+#include "svm_math_util.h"
+
#include "svm_attribute.h"
#include "svm_gradient.h"
#include "svm_blackbody.h"
@@ -164,7 +166,6 @@ CCL_NAMESPACE_END
#include "svm_mapping.h"
#include "svm_normal.h"
#include "svm_wave.h"
-#include "svm_math_util.h"
#include "svm_math.h"
#include "svm_mix.h"
#include "svm_ramp.h"
@@ -178,20 +179,24 @@ CCL_NAMESPACE_END
#include "svm_checker.h"
#include "svm_brick.h"
#include "svm_vector_transform.h"
+#include "svm_voxel.h"
CCL_NAMESPACE_BEGIN
-/* Main Interpreter Loop */
+#define NODES_GROUP(group) ((group) <= __NODES_MAX_GROUP__)
+#define NODES_FEATURE(feature) ((__NODES_FEATURES__ & (feature)) != 0)
+/* Main Interpreter Loop */
ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderType type, int path_flag)
{
float stack[SVM_STACK_SIZE];
- int offset = sd->shader & SHADER_MASK;
+ int offset = ccl_fetch(sd, shader) & SHADER_MASK;
while(1) {
uint4 node = read_node(kg, &offset);
switch(node.x) {
+#if NODES_GROUP(NODE_GROUP_LEVEL_0)
case NODE_SHADER_JUMP: {
if(type == SHADER_TYPE_SURFACE) offset = node.y;
else if(type == SHADER_TYPE_VOLUME) offset = node.z;
@@ -208,15 +213,6 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade
case NODE_CLOSURE_BACKGROUND:
svm_node_closure_background(sd, stack, node);
break;
- case NODE_CLOSURE_HOLDOUT:
- svm_node_closure_holdout(sd, stack, node);
- break;
- case NODE_CLOSURE_AMBIENT_OCCLUSION:
- svm_node_closure_ambient_occlusion(sd, stack, node);
- break;
- case NODE_CLOSURE_VOLUME:
- svm_node_closure_volume(kg, sd, stack, node, path_flag);
- break;
case NODE_CLOSURE_SET_WEIGHT:
svm_node_closure_set_weight(sd, node.y, node.z, node.w);
break;
@@ -237,13 +233,137 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade
if(stack_load_float(stack, node.z) == 1.0f)
offset += node.y;
break;
-#ifdef __TEXTURES__
+ case NODE_GEOMETRY:
+ svm_node_geometry(kg, sd, stack, node.y, node.z);
+ break;
+ case NODE_CONVERT:
+ svm_node_convert(sd, stack, node.y, node.z, node.w);
+ break;
+ case NODE_TEX_COORD:
+ svm_node_tex_coord(kg, sd, path_flag, stack, node, &offset);
+ break;
+ case NODE_VALUE_F:
+ svm_node_value_f(kg, sd, stack, node.y, node.z);
+ break;
+ case NODE_VALUE_V:
+ svm_node_value_v(kg, sd, stack, node.y, &offset);
+ break;
+ case NODE_ATTR:
+ svm_node_attr(kg, sd, stack, node);
+ break;
+# if NODES_FEATURE(NODE_FEATURE_BUMP)
+ case NODE_GEOMETRY_BUMP_DX:
+ svm_node_geometry_bump_dx(kg, sd, stack, node.y, node.z);
+ break;
+ case NODE_GEOMETRY_BUMP_DY:
+ svm_node_geometry_bump_dy(kg, sd, stack, node.y, node.z);
+ break;
+ case NODE_SET_DISPLACEMENT:
+ svm_node_set_displacement(sd, stack, node.y);
+ break;
+# endif /* NODES_FEATURE(NODE_FEATURE_BUMP) */
+# ifdef __TEXTURES__
case NODE_TEX_IMAGE:
svm_node_tex_image(kg, sd, stack, node);
break;
case NODE_TEX_IMAGE_BOX:
svm_node_tex_image_box(kg, sd, stack, node);
break;
+ case NODE_TEX_NOISE:
+ svm_node_tex_noise(kg, sd, stack, node, &offset);
+ break;
+# endif /* __TEXTURES__ */
+# ifdef __EXTRA_NODES__
+# if NODES_FEATURE(NODE_FEATURE_BUMP)
+ case NODE_SET_BUMP:
+ svm_node_set_bump(kg, sd, stack, node);
+ break;
+ case NODE_ATTR_BUMP_DX:
+ svm_node_attr_bump_dx(kg, sd, stack, node);
+ break;
+ case NODE_ATTR_BUMP_DY:
+ svm_node_attr_bump_dy(kg, sd, stack, node);
+ break;
+ case NODE_TEX_COORD_BUMP_DX:
+ svm_node_tex_coord_bump_dx(kg, sd, path_flag, stack, node, &offset);
+ break;
+ case NODE_TEX_COORD_BUMP_DY:
+ svm_node_tex_coord_bump_dy(kg, sd, path_flag, stack, node, &offset);
+ break;
+ case NODE_CLOSURE_SET_NORMAL:
+ svm_node_set_normal(kg, sd, stack, node.y, node.z);
+ break;
+# endif /* NODES_FEATURE(NODE_FEATURE_BUMP) */
+ case NODE_HSV:
+ svm_node_hsv(kg, sd, stack, node.y, node.z, node.w, &offset);
+ break;
+# endif /* __EXTRA_NODES__ */
+#endif /* NODES_GROUP(NODE_GROUP_LEVEL_0) */
+
+#if NODES_GROUP(NODE_GROUP_LEVEL_1)
+ case NODE_CLOSURE_HOLDOUT:
+ svm_node_closure_holdout(sd, stack, node);
+ break;
+ case NODE_CLOSURE_AMBIENT_OCCLUSION:
+ svm_node_closure_ambient_occlusion(sd, stack, node);
+ break;
+ case NODE_FRESNEL:
+ svm_node_fresnel(sd, stack, node.y, node.z, node.w);
+ break;
+ case NODE_LAYER_WEIGHT:
+ svm_node_layer_weight(sd, stack, node);
+ break;
+# if NODES_FEATURE(NODE_FEATURE_VOLUME)
+ case NODE_CLOSURE_VOLUME:
+ svm_node_closure_volume(kg, sd, stack, node, path_flag);
+ break;
+# endif /* NODES_FEATURE(NODE_FEATURE_VOLUME) */
+# ifdef __EXTRA_NODES__
+ case NODE_MATH:
+ svm_node_math(kg, sd, stack, node.y, node.z, node.w, &offset);
+ break;
+ case NODE_VECTOR_MATH:
+ svm_node_vector_math(kg, sd, stack, node.y, node.z, node.w, &offset);
+ break;
+ case NODE_RGB_RAMP:
+ svm_node_rgb_ramp(kg, sd, stack, node, &offset);
+ break;
+ case NODE_GAMMA:
+ svm_node_gamma(sd, stack, node.y, node.z, node.w);
+ break;
+ case NODE_BRIGHTCONTRAST:
+ svm_node_brightness(sd, stack, node.y, node.z, node.w);
+ break;
+ case NODE_LIGHT_PATH:
+ svm_node_light_path(sd, stack, node.y, node.z, path_flag);
+ break;
+ case NODE_OBJECT_INFO:
+ svm_node_object_info(kg, sd, stack, node.y, node.z);
+ break;
+ case NODE_PARTICLE_INFO:
+ svm_node_particle_info(kg, sd, stack, node.y, node.z);
+ break;
+# ifdef __HAIR__
+# if NODES_FEATURE(NODE_FEATURE_HAIR)
+ case NODE_HAIR_INFO:
+ svm_node_hair_info(kg, sd, stack, node.y, node.z);
+ break;
+# endif /* NODES_FEATURE(NODE_FEATURE_HAIR) */
+# endif /* __HAIR__ */
+# endif /* __EXTRA_NODES__ */
+#endif /* NODES_GROUP(NODE_GROUP_LEVEL_1) */
+
+#if NODES_GROUP(NODE_GROUP_LEVEL_2)
+ case NODE_MAPPING:
+ svm_node_mapping(kg, sd, stack, node.y, node.z, &offset);
+ break;
+ case NODE_MIN_MAX:
+ svm_node_min_max(kg, sd, stack, node.y, node.z, &offset);
+ break;
+ case NODE_CAMERA:
+ svm_node_camera(kg, sd, stack, node.y, node.z, node.w);
+ break;
+# ifdef __TEXTURES__
case NODE_TEX_ENVIRONMENT:
svm_node_tex_environment(kg, sd, stack, node);
break;
@@ -253,9 +373,6 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade
case NODE_TEX_GRADIENT:
svm_node_tex_gradient(sd, stack, node);
break;
- case NODE_TEX_NOISE:
- svm_node_tex_noise(kg, sd, stack, node, &offset);
- break;
case NODE_TEX_VORONOI:
svm_node_tex_voronoi(kg, sd, stack, node, &offset);
break;
@@ -274,55 +391,37 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade
case NODE_TEX_BRICK:
svm_node_tex_brick(kg, sd, stack, node, &offset);
break;
-#endif
- case NODE_CAMERA:
- svm_node_camera(kg, sd, stack, node.y, node.z, node.w);
- break;
- case NODE_GEOMETRY:
- svm_node_geometry(kg, sd, stack, node.y, node.z);
- break;
-#ifdef __EXTRA_NODES__
- case NODE_GEOMETRY_BUMP_DX:
- svm_node_geometry_bump_dx(kg, sd, stack, node.y, node.z);
- break;
- case NODE_GEOMETRY_BUMP_DY:
- svm_node_geometry_bump_dy(kg, sd, stack, node.y, node.z);
- break;
- case NODE_LIGHT_PATH:
- svm_node_light_path(sd, stack, node.y, node.z, path_flag);
- break;
- case NODE_OBJECT_INFO:
- svm_node_object_info(kg, sd, stack, node.y, node.z);
+ case NODE_TEX_VOXEL:
+ svm_node_tex_voxel(kg, sd, stack, node, &offset);
break;
- case NODE_PARTICLE_INFO:
- svm_node_particle_info(kg, sd, stack, node.y, node.z);
+# endif /* __TEXTURES__ */
+# ifdef __EXTRA_NODES__
+ case NODE_NORMAL:
+ svm_node_normal(kg, sd, stack, node.y, node.z, node.w, &offset);
break;
-#ifdef __HAIR__
- case NODE_HAIR_INFO:
- svm_node_hair_info(kg, sd, stack, node.y, node.z);
+ case NODE_LIGHT_FALLOFF:
+ svm_node_light_falloff(sd, stack, node);
break;
-#endif
+# endif /* __EXTRA_NODES__ */
+#endif /* NODES_GROUP(NODE_GROUP_LEVEL_2) */
-#endif
- case NODE_CONVERT:
- svm_node_convert(sd, stack, node.y, node.z, node.w);
+#if NODES_GROUP(NODE_GROUP_LEVEL_3)
+ case NODE_RGB_CURVES:
+ svm_node_rgb_curves(kg, sd, stack, node, &offset);
break;
- case NODE_VALUE_F:
- svm_node_value_f(kg, sd, stack, node.y, node.z);
+ case NODE_VECTOR_CURVES:
+ svm_node_vector_curves(kg, sd, stack, node, &offset);
break;
- case NODE_VALUE_V:
- svm_node_value_v(kg, sd, stack, node.y, &offset);
+ case NODE_TANGENT:
+ svm_node_tangent(kg, sd, stack, node);
break;
-#ifdef __EXTRA_NODES__
+ case NODE_NORMAL_MAP:
+ svm_node_normal_map(kg, sd, stack, node);
+ break;
+# ifdef __EXTRA_NODES__
case NODE_INVERT:
svm_node_invert(sd, stack, node.y, node.z, node.w);
break;
- case NODE_GAMMA:
- svm_node_gamma(sd, stack, node.y, node.z, node.w);
- break;
- case NODE_BRIGHTCONTRAST:
- svm_node_brightness(sd, stack, node.y, node.z, node.w);
- break;
case NODE_MIX:
svm_node_mix(kg, sd, stack, node.y, node.z, node.w, &offset);
break;
@@ -338,28 +437,9 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade
case NODE_COMBINE_HSV:
svm_node_combine_hsv(kg, sd, stack, node.y, node.z, node.w, &offset);
break;
- case NODE_HSV:
- svm_node_hsv(kg, sd, stack, node.y, node.z, node.w, &offset);
- break;
-#endif
- case NODE_ATTR:
- svm_node_attr(kg, sd, stack, node);
- break;
-#ifdef __EXTRA_NODES__
- case NODE_ATTR_BUMP_DX:
- svm_node_attr_bump_dx(kg, sd, stack, node);
- break;
- case NODE_ATTR_BUMP_DY:
- svm_node_attr_bump_dy(kg, sd, stack, node);
- break;
-#endif
- case NODE_FRESNEL:
- svm_node_fresnel(sd, stack, node.y, node.z, node.w);
- break;
- case NODE_LAYER_WEIGHT:
- svm_node_layer_weight(sd, stack, node);
+ case NODE_VECTOR_TRANSFORM:
+ svm_node_vector_transform(kg, sd, stack, node);
break;
-#ifdef __EXTRA_NODES__
case NODE_WIREFRAME:
svm_node_wireframe(kg, sd, stack, node);
break;
@@ -369,70 +449,20 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade
case NODE_BLACKBODY:
svm_node_blackbody(kg, sd, stack, node.y, node.z);
break;
- case NODE_SET_DISPLACEMENT:
- svm_node_set_displacement(sd, stack, node.y);
- break;
- case NODE_SET_BUMP:
- svm_node_set_bump(kg, sd, stack, node);
- break;
- case NODE_MATH:
- svm_node_math(kg, sd, stack, node.y, node.z, node.w, &offset);
- break;
- case NODE_VECTOR_MATH:
- svm_node_vector_math(kg, sd, stack, node.y, node.z, node.w, &offset);
- break;
- case NODE_VECTOR_TRANSFORM:
- svm_node_vector_transform(kg, sd, stack, node);
- break;
- case NODE_NORMAL:
- svm_node_normal(kg, sd, stack, node.y, node.z, node.w, &offset);
- break;
-#endif
- case NODE_MAPPING:
- svm_node_mapping(kg, sd, stack, node.y, node.z, &offset);
- break;
- case NODE_MIN_MAX:
- svm_node_min_max(kg, sd, stack, node.y, node.z, &offset);
- break;
- case NODE_TEX_COORD:
- svm_node_tex_coord(kg, sd, path_flag, stack, node, &offset);
- break;
-#ifdef __EXTRA_NODES__
- case NODE_TEX_COORD_BUMP_DX:
- svm_node_tex_coord_bump_dx(kg, sd, path_flag, stack, node, &offset);
- break;
- case NODE_TEX_COORD_BUMP_DY:
- svm_node_tex_coord_bump_dy(kg, sd, path_flag, stack, node, &offset);
- break;
- case NODE_CLOSURE_SET_NORMAL:
- svm_node_set_normal(kg, sd, stack, node.y, node.z );
- break;
- case NODE_RGB_RAMP:
- svm_node_rgb_ramp(kg, sd, stack, node, &offset);
- break;
- case NODE_RGB_CURVES:
- svm_node_rgb_curves(kg, sd, stack, node, &offset);
- break;
- case NODE_VECTOR_CURVES:
- svm_node_vector_curves(kg, sd, stack, node, &offset);
- break;
- case NODE_LIGHT_FALLOFF:
- svm_node_light_falloff(sd, stack, node);
- break;
-#endif
- case NODE_TANGENT:
- svm_node_tangent(kg, sd, stack, node);
- break;
- case NODE_NORMAL_MAP:
- svm_node_normal_map(kg, sd, stack, node);
- break;
+# endif /* __EXTRA_NODES__ */
+#endif /* NODES_GROUP(NODE_GROUP_LEVEL_3) */
case NODE_END:
+ return;
default:
+ kernel_assert(!"Unknown node type was passed to the SVM machine");
return;
}
}
}
+#undef NODES_GROUP
+#undef NODES_FEATURE
+
CCL_NAMESPACE_END
#endif /* __SVM_H__ */
diff --git a/intern/cycles/kernel/svm/svm_attribute.h b/intern/cycles/kernel/svm/svm_attribute.h
index b63978b6e1f..025ae96f59d 100644
--- a/intern/cycles/kernel/svm/svm_attribute.h
+++ b/intern/cycles/kernel/svm/svm_attribute.h
@@ -22,12 +22,12 @@ ccl_device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd,
uint4 node, NodeAttributeType *type,
NodeAttributeType *mesh_type, AttributeElement *elem, int *offset, uint *out_offset)
{
- if(sd->object != OBJECT_NONE) {
+ if(ccl_fetch(sd, object) != OBJECT_NONE) {
/* find attribute by unique id */
uint id = node.y;
- uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride;
+ uint attr_offset = ccl_fetch(sd, object)*kernel_data.bvh.attributes_map_stride;
#ifdef __HAIR__
- attr_offset = (sd->type & PRIMITIVE_ALL_CURVE)? attr_offset + ATTR_PRIM_CURVE: attr_offset;
+ attr_offset = (ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE)? attr_offset + ATTR_PRIM_CURVE: attr_offset;
#endif
uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
diff --git a/intern/cycles/kernel/svm/svm_blackbody.h b/intern/cycles/kernel/svm/svm_blackbody.h
index 1e40e868e14..b750ad87b7f 100644
--- a/intern/cycles/kernel/svm/svm_blackbody.h
+++ b/intern/cycles/kernel/svm/svm_blackbody.h
@@ -36,48 +36,12 @@ CCL_NAMESPACE_BEGIN
ccl_device void svm_node_blackbody(KernelGlobals *kg, ShaderData *sd, float *stack, uint temperature_offset, uint col_offset)
{
- /* Output */
- float3 color_rgb = make_float3(0.0f, 0.0f, 0.0f);
-
/* Input */
float temperature = stack_load_float(stack, temperature_offset);
- if (temperature < BB_DRAPER) {
- /* just return very very dim red */
- color_rgb = make_float3(1.0e-6f,0.0f,0.0f);
- }
- else if (temperature <= BB_MAX_TABLE_RANGE) {
- /* This is the overall size of the table */
- const int lookuptablesize = 956;
- const float lookuptablenormalize = 1.0f/956.0f;
-
- /* reconstruct a proper index for the table lookup, compared to OSL we don't look up two colors
- just one (the OSL-lerp is also automatically done for us by "lookup_table_read") */
- float t = powf((temperature - BB_DRAPER) * (1.0f / BB_TABLE_SPACING), (1.0f / BB_TABLE_XPOWER));
-
- int blackbody_table_offset = kernel_data.tables.blackbody_offset;
-
- /* Retrieve colors from the lookup table */
- float lutval = t*lookuptablenormalize;
- float R = lookup_table_read(kg, lutval, blackbody_table_offset, lookuptablesize);
- lutval = (t + 319.0f*1.0f)*lookuptablenormalize;
- float G = lookup_table_read(kg, lutval, blackbody_table_offset, lookuptablesize);
- lutval = (t + 319.0f*2.0f)*lookuptablenormalize;
- float B = lookup_table_read(kg, lutval, blackbody_table_offset, lookuptablesize);
-
- R = powf(R, BB_TABLE_YPOWER);
- G = powf(G, BB_TABLE_YPOWER);
- B = powf(B, BB_TABLE_YPOWER);
-
- color_rgb = make_float3(R, G, B);
- }
-
- /* Luminance */
- float l = linear_rgb_to_gray(color_rgb);
- if (l != 0.0f)
- color_rgb /= l;
+ float3 color_rgb = svm_math_blackbody_color(temperature);
- if (stack_valid(col_offset))
+ if(stack_valid(col_offset))
stack_store_float3(stack, col_offset, color_rgb);
}
diff --git a/intern/cycles/kernel/svm/svm_brick.h b/intern/cycles/kernel/svm/svm_brick.h
index 33a2a5c7598..fcf8f47b77e 100644
--- a/intern/cycles/kernel/svm/svm_brick.h
+++ b/intern/cycles/kernel/svm/svm_brick.h
@@ -47,7 +47,7 @@ ccl_device_noinline float2 svm_brick(float3 p, float mortar_size, float bias,
y = p.y - row_height*rownum;
return make_float2(
- clamp((brick_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0f, 1.0f),
+ saturate((brick_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias)),
(x < mortar_size || y < mortar_size ||
x > (brick_width - mortar_size) ||
diff --git a/intern/cycles/kernel/svm/svm_brightness.h b/intern/cycles/kernel/svm/svm_brightness.h
index 631bd1825ee..e4d545a00ae 100644
--- a/intern/cycles/kernel/svm/svm_brightness.h
+++ b/intern/cycles/kernel/svm/svm_brightness.h
@@ -32,7 +32,7 @@ ccl_device void svm_node_brightness(ShaderData *sd, float *stack, uint in_color,
color.y = max(a*color.y + b, 0.0f);
color.z = max(a*color.z + b, 0.0f);
- if (stack_valid(out_color))
+ if(stack_valid(out_color))
stack_store_float3(stack, out_color, color);
}
diff --git a/intern/cycles/kernel/svm/svm_camera.h b/intern/cycles/kernel/svm/svm_camera.h
index e03745cb331..00678a49d70 100644
--- a/intern/cycles/kernel/svm/svm_camera.h
+++ b/intern/cycles/kernel/svm/svm_camera.h
@@ -23,17 +23,17 @@ ccl_device void svm_node_camera(KernelGlobals *kg, ShaderData *sd, float *stack,
float3 vector;
Transform tfm = kernel_data.cam.worldtocamera;
- vector = transform_point(&tfm, sd->P);
+ vector = transform_point(&tfm, ccl_fetch(sd, P));
zdepth = vector.z;
distance = len(vector);
- if (stack_valid(out_vector))
+ if(stack_valid(out_vector))
stack_store_float3(stack, out_vector, normalize(vector));
- if (stack_valid(out_zdepth))
+ if(stack_valid(out_zdepth))
stack_store_float(stack, out_zdepth, zdepth);
- if (stack_valid(out_distance))
+ if(stack_valid(out_distance))
stack_store_float(stack, out_distance, distance);
}
diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h
index 07ac7104e68..7cdcbc2d30c 100644
--- a/intern/cycles/kernel/svm/svm_closure.h
+++ b/intern/cycles/kernel/svm/svm_closure.h
@@ -25,10 +25,13 @@ ccl_device void svm_node_glass_setup(ShaderData *sd, ShaderClosure *sc, int type
sc->data0 = eta;
sc->data1 = 0.0f;
sc->data2 = 0.0f;
- sd->flag |= bsdf_refraction_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_refraction_setup(sc);
+ }
+ else {
+ sc->data0 = 0.0f;
+ sc->data1 = 0.0f;
+ ccl_fetch(sd, flag) |= bsdf_reflection_setup(sc);
}
- else
- sd->flag |= bsdf_reflection_setup(sc);
}
else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID) {
sc->data0 = roughness;
@@ -36,9 +39,9 @@ ccl_device void svm_node_glass_setup(ShaderData *sd, ShaderClosure *sc, int type
sc->data2 = eta;
if(refract)
- sd->flag |= bsdf_microfacet_beckmann_refraction_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_refraction_setup(sc);
else
- sd->flag |= bsdf_microfacet_beckmann_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_setup(sc);
}
else {
sc->data0 = roughness;
@@ -46,23 +49,23 @@ ccl_device void svm_node_glass_setup(ShaderData *sd, ShaderClosure *sc, int type
sc->data2 = eta;
if(refract)
- sd->flag |= bsdf_microfacet_ggx_refraction_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_refraction_setup(sc);
else
- sd->flag |= bsdf_microfacet_ggx_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_setup(sc);
}
}
ccl_device_inline ShaderClosure *svm_node_closure_get_non_bsdf(ShaderData *sd, ClosureType type, float mix_weight)
{
- ShaderClosure *sc = &sd->closure[sd->num_closure];
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
- if(sd->num_closure < MAX_CLOSURE) {
+ if(ccl_fetch(sd, num_closure) < MAX_CLOSURE) {
sc->weight *= mix_weight;
sc->type = type;
#ifdef __OSL__
sc->prim = NULL;
#endif
- sd->num_closure++;
+ ccl_fetch(sd, num_closure)++;
return sc;
}
@@ -71,14 +74,15 @@ ccl_device_inline ShaderClosure *svm_node_closure_get_non_bsdf(ShaderData *sd, C
ccl_device_inline ShaderClosure *svm_node_closure_get_bsdf(ShaderData *sd, float mix_weight)
{
- ShaderClosure *sc = &sd->closure[sd->num_closure];
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
+
float3 weight = sc->weight * mix_weight;
float sample_weight = fabsf(average(weight));
- if(sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure < MAX_CLOSURE) {
+ if(sample_weight > CLOSURE_WEIGHT_CUTOFF && ccl_fetch(sd, num_closure) < MAX_CLOSURE) {
sc->weight = weight;
sc->sample_weight = sample_weight;
- sd->num_closure++;
+ ccl_fetch(sd, num_closure)++;
#ifdef __OSL__
sc->prim = NULL;
#endif
@@ -90,14 +94,15 @@ ccl_device_inline ShaderClosure *svm_node_closure_get_bsdf(ShaderData *sd, float
ccl_device_inline ShaderClosure *svm_node_closure_get_absorption(ShaderData *sd, float mix_weight)
{
- ShaderClosure *sc = &sd->closure[sd->num_closure];
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
+
float3 weight = (make_float3(1.0f, 1.0f, 1.0f) - sc->weight) * mix_weight;
float sample_weight = fabsf(average(weight));
- if(sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure < MAX_CLOSURE) {
+ if(sample_weight > CLOSURE_WEIGHT_CUTOFF && ccl_fetch(sd, num_closure) < MAX_CLOSURE) {
sc->weight = weight;
sc->sample_weight = sample_weight;
- sd->num_closure++;
+ ccl_fetch(sd, num_closure)++;
#ifdef __OSL__
sc->prim = NULL;
#endif
@@ -121,7 +126,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
if(mix_weight == 0.0f)
return;
- float3 N = stack_valid(data_node.x)? stack_load_float3(stack, data_node.x): sd->N;
+ float3 N = stack_valid(data_node.x)? stack_load_float3(stack, data_node.x): ccl_fetch(sd, N);
float param1 = (stack_valid(param1_offset))? stack_load_float(stack, param1_offset): __uint_as_float(node.z);
float param2 = (stack_valid(param2_offset))? stack_load_float(stack, param2_offset): __uint_as_float(node.w);
@@ -139,13 +144,13 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sc->data0 = 0.0f;
sc->data1 = 0.0f;
sc->data2 = 0.0f;
- sd->flag |= bsdf_diffuse_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_diffuse_setup(sc);
}
else {
sc->data0 = roughness;
sc->data1 = 0.0f;
sc->data2 = 0.0f;
- sd->flag |= bsdf_oren_nayar_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_oren_nayar_setup(sc);
}
}
break;
@@ -158,7 +163,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sc->data1 = 0.0f;
sc->data2 = 0.0f;
sc->N = N;
- sd->flag |= bsdf_translucent_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_translucent_setup(sc);
}
break;
}
@@ -170,7 +175,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sc->data1 = 0.0f;
sc->data2 = 0.0f;
sc->N = N;
- sd->flag |= bsdf_transparent_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_transparent_setup(sc);
}
break;
}
@@ -192,13 +197,13 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
/* setup bsdf */
if(type == CLOSURE_BSDF_REFLECTION_ID)
- sd->flag |= bsdf_reflection_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_reflection_setup(sc);
else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_ID)
- sd->flag |= bsdf_microfacet_beckmann_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_setup(sc);
else if(type == CLOSURE_BSDF_MICROFACET_GGX_ID)
- sd->flag |= bsdf_microfacet_ggx_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_setup(sc);
else
- sd->flag |= bsdf_ashikhmin_shirley_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_setup(sc);
}
break;
@@ -216,7 +221,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sc->N = N;
float eta = fmaxf(param2, 1e-5f);
- eta = (sd->flag & SD_BACKFACING)? 1.0f/eta: eta;
+ eta = (ccl_fetch(sd, flag) & SD_BACKFACING)? 1.0f/eta: eta;
/* setup bsdf */
if(type == CLOSURE_BSDF_REFRACTION_ID) {
@@ -224,7 +229,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sc->data1 = 0.0f;
sc->data2 = 0.0f;
- sd->flag |= bsdf_refraction_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_refraction_setup(sc);
}
else {
sc->data0 = param1;
@@ -232,9 +237,9 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sc->data2 = eta;
if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID)
- sd->flag |= bsdf_microfacet_beckmann_refraction_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_refraction_setup(sc);
else
- sd->flag |= bsdf_microfacet_ggx_refraction_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_refraction_setup(sc);
}
}
@@ -251,15 +256,15 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
#endif
/* index of refraction */
float eta = fmaxf(param2, 1e-5f);
- eta = (sd->flag & SD_BACKFACING)? 1.0f/eta: eta;
+ eta = (ccl_fetch(sd, flag) & SD_BACKFACING)? 1.0f/eta: eta;
/* fresnel */
- float cosNO = dot(N, sd->I);
+ float cosNO = dot(N, ccl_fetch(sd, I));
float fresnel = fresnel_dielectric_cos(cosNO, eta);
float roughness = param1;
/* reflection */
- ShaderClosure *sc = &sd->closure[sd->num_closure];
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
float3 weight = sc->weight;
float sample_weight = sc->sample_weight;
@@ -280,7 +285,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
#endif
/* refraction */
- sc = &sd->closure[sd->num_closure];
+ sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
sc->weight = weight;
sc->sample_weight = sample_weight;
@@ -328,12 +333,12 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sc->data2 = 0.0f;
- if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID)
- sd->flag |= bsdf_microfacet_beckmann_aniso_setup(sc);
- else if (type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID)
- sd->flag |= bsdf_microfacet_ggx_aniso_setup(sc);
+ if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID)
+ ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_aniso_setup(sc);
+ else if(type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID)
+ ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_aniso_setup(sc);
else
- sd->flag |= bsdf_ashikhmin_shirley_aniso_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_aniso_setup(sc);
}
break;
}
@@ -344,10 +349,10 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sc->N = N;
/* sigma */
- sc->data0 = clamp(param1, 0.0f, 1.0f);
+ sc->data0 = saturate(param1);
sc->data1 = 0.0f;
sc->data2 = 0.0f;
- sd->flag |= bsdf_ashikhmin_velvet_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_ashikhmin_velvet_setup(sc);
}
break;
}
@@ -362,10 +367,10 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sc->data1 = param2;
sc->data2 = 0.0f;
- if (type == CLOSURE_BSDF_DIFFUSE_TOON_ID)
- sd->flag |= bsdf_diffuse_toon_setup(sc);
+ if(type == CLOSURE_BSDF_DIFFUSE_TOON_ID)
+ ccl_fetch(sd, flag) |= bsdf_diffuse_toon_setup(sc);
else
- sd->flag |= bsdf_glossy_toon_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_glossy_toon_setup(sc);
}
break;
}
@@ -373,7 +378,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
case CLOSURE_BSDF_HAIR_REFLECTION_ID:
case CLOSURE_BSDF_HAIR_TRANSMISSION_ID: {
- if(sd->flag & SD_BACKFACING && sd->type & PRIMITIVE_ALL_CURVE) {
+ if(ccl_fetch(sd, flag) & SD_BACKFACING && ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) {
ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
if(sc) {
@@ -384,11 +389,13 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
* spawned by transmission from the front */
sc->weight = make_float3(1.0f, 1.0f, 1.0f);
sc->N = N;
- sd->flag |= bsdf_transparent_setup(sc);
+ sc->data0 = 0.0f;
+ sc->data1 = 0.0f;
+ ccl_fetch(sd, flag) |= bsdf_transparent_setup(sc);
}
}
else {
- ShaderClosure *sc = &sd->closure[sd->num_closure];
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
sc = svm_node_closure_get_bsdf(sd, mix_weight);
if(sc) {
@@ -397,18 +404,18 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sc->data1 = param2;
sc->data2 = -stack_load_float(stack, data_node.z);
- if(!(sd->type & PRIMITIVE_ALL_CURVE)) {
- sc->T = normalize(sd->dPdv);
+ if(!(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE)) {
+ sc->T = normalize(ccl_fetch(sd, dPdv));
sc->data2 = 0.0f;
}
else
- sc->T = normalize(sd->dPdu);
+ sc->T = normalize(ccl_fetch(sd, dPdu));
if(type == CLOSURE_BSDF_HAIR_REFLECTION_ID) {
- sd->flag |= bsdf_hair_reflection_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_hair_reflection_setup(sc);
}
else {
- sd->flag |= bsdf_hair_transmission_setup(sc);
+ ccl_fetch(sd, flag) |= bsdf_hair_transmission_setup(sc);
}
}
}
@@ -418,9 +425,14 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
#endif
#ifdef __SUBSURFACE__
+#ifndef __SPLIT_KERNEL__
+# define sc_next(sc) sc++
+# else
+# define sc_next(sc) sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure))
+# endif
case CLOSURE_BSSRDF_CUBIC_ID:
case CLOSURE_BSSRDF_GAUSSIAN_ID: {
- ShaderClosure *sc = &sd->closure[sd->num_closure];
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
float3 weight = sc->weight * mix_weight;
float sample_weight = fabsf(average(weight));
@@ -430,7 +442,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR)
param1 = 0.0f;
- if(sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure+2 < MAX_CLOSURE) {
+ if(sample_weight > CLOSURE_WEIGHT_CUTOFF && ccl_fetch(sd, num_closure)+2 < MAX_CLOSURE) {
/* radius * scale */
float3 radius = stack_load_float3(stack, data_node.z)*param1;
/* sharpness */
@@ -450,10 +462,10 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sc->prim = NULL;
#endif
sc->N = N;
- sd->flag |= bssrdf_setup(sc, (ClosureType)type);
+ ccl_fetch(sd, flag) |= bssrdf_setup(sc, (ClosureType)type);
- sd->num_closure++;
- sc++;
+ ccl_fetch(sd, num_closure)++;
+ sc_next(sc);
}
if(fabsf(weight.y) > 0.0f) {
@@ -467,10 +479,10 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sc->prim = NULL;
#endif
sc->N = N;
- sd->flag |= bssrdf_setup(sc, (ClosureType)type);
+ ccl_fetch(sd, flag) |= bssrdf_setup(sc, (ClosureType)type);
- sd->num_closure++;
- sc++;
+ ccl_fetch(sd, num_closure)++;
+ sc_next(sc);
}
if(fabsf(weight.z) > 0.0f) {
@@ -484,15 +496,16 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sc->prim = NULL;
#endif
sc->N = N;
- sd->flag |= bssrdf_setup(sc, (ClosureType)type);
+ ccl_fetch(sd, flag) |= bssrdf_setup(sc, (ClosureType)type);
- sd->num_closure++;
- sc++;
+ ccl_fetch(sd, num_closure)++;
+ sc_next(sc);
}
}
break;
}
+# undef sc_next
#endif
default:
break;
@@ -520,7 +533,7 @@ ccl_device void svm_node_closure_volume(KernelGlobals *kg, ShaderData *sd, float
ShaderClosure *sc = svm_node_closure_get_absorption(sd, mix_weight * density);
if(sc) {
- sd->flag |= volume_absorption_setup(sc);
+ ccl_fetch(sd, flag) |= volume_absorption_setup(sc);
}
break;
}
@@ -529,7 +542,8 @@ ccl_device void svm_node_closure_volume(KernelGlobals *kg, ShaderData *sd, float
if(sc) {
sc->data0 = param2; /* g */
- sd->flag |= volume_henyey_greenstein_setup(sc);
+ sc->data1 = 0.0f;
+ ccl_fetch(sd, flag) |= volume_henyey_greenstein_setup(sc);
}
break;
}
@@ -554,7 +568,7 @@ ccl_device void svm_node_closure_emission(ShaderData *sd, float *stack, uint4 no
else
svm_node_closure_get_non_bsdf(sd, CLOSURE_EMISSION_ID, 1.0f);
- sd->flag |= SD_EMISSION;
+ ccl_fetch(sd, flag) |= SD_EMISSION;
}
ccl_device void svm_node_closure_background(ShaderData *sd, float *stack, uint4 node)
@@ -588,7 +602,7 @@ ccl_device void svm_node_closure_holdout(ShaderData *sd, float *stack, uint4 nod
else
svm_node_closure_get_non_bsdf(sd, CLOSURE_HOLDOUT_ID, 1.0f);
- sd->flag |= SD_HOLDOUT;
+ ccl_fetch(sd, flag) |= SD_HOLDOUT;
}
ccl_device void svm_node_closure_ambient_occlusion(ShaderData *sd, float *stack, uint4 node)
@@ -606,15 +620,17 @@ ccl_device void svm_node_closure_ambient_occlusion(ShaderData *sd, float *stack,
else
svm_node_closure_get_non_bsdf(sd, CLOSURE_AMBIENT_OCCLUSION_ID, 1.0f);
- sd->flag |= SD_AO;
+ ccl_fetch(sd, flag) |= SD_AO;
}
/* Closure Nodes */
ccl_device_inline void svm_node_closure_store_weight(ShaderData *sd, float3 weight)
{
- if(sd->num_closure < MAX_CLOSURE)
- sd->closure[sd->num_closure].weight = weight;
+ if(ccl_fetch(sd, num_closure) < MAX_CLOSURE) {
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
+ sc->weight = weight;
+ }
}
ccl_device void svm_node_closure_set_weight(ShaderData *sd, uint r, uint g, uint b)
@@ -649,7 +665,7 @@ ccl_device void svm_node_mix_closure(ShaderData *sd, float *stack, uint4 node)
decode_node_uchar4(node.y, &weight_offset, &in_weight_offset, &weight1_offset, &weight2_offset);
float weight = stack_load_float(stack, weight_offset);
- weight = clamp(weight, 0.0f, 1.0f);
+ weight = saturate(weight);
float in_weight = (stack_valid(in_weight_offset))? stack_load_float(stack, in_weight_offset): 1.0f;
@@ -664,7 +680,7 @@ ccl_device void svm_node_mix_closure(ShaderData *sd, float *stack, uint4 node)
ccl_device void svm_node_set_normal(KernelGlobals *kg, ShaderData *sd, float *stack, uint in_direction, uint out_normal)
{
float3 normal = stack_load_float3(stack, in_direction);
- sd->N = normal;
+ ccl_fetch(sd, N) = normal;
stack_store_float3(stack, out_normal, normal);
}
diff --git a/intern/cycles/kernel/svm/svm_displace.h b/intern/cycles/kernel/svm/svm_displace.h
index 4a058905a93..8d4b07c9973 100644
--- a/intern/cycles/kernel/svm/svm_displace.h
+++ b/intern/cycles/kernel/svm/svm_displace.h
@@ -25,11 +25,11 @@ ccl_device void svm_node_set_bump(KernelGlobals *kg, ShaderData *sd, float *stac
uint normal_offset, distance_offset, invert;
decode_node_uchar4(node.y, &normal_offset, &distance_offset, &invert, NULL);
- float3 normal_in = stack_valid(normal_offset)? stack_load_float3(stack, normal_offset): sd->N;
+ float3 normal_in = stack_valid(normal_offset)? stack_load_float3(stack, normal_offset): ccl_fetch(sd, N);
/* get surface tangents from normal */
- float3 Rx = cross(sd->dP.dy, normal_in);
- float3 Ry = cross(normal_in, sd->dP.dx);
+ float3 Rx = cross(ccl_fetch(sd, dP).dy, normal_in);
+ float3 Ry = cross(normal_in, ccl_fetch(sd, dP).dx);
/* get bump values */
uint c_offset, x_offset, y_offset, strength_offset;
@@ -40,7 +40,7 @@ ccl_device void svm_node_set_bump(KernelGlobals *kg, ShaderData *sd, float *stac
float h_y = stack_load_float(stack, y_offset);
/* compute surface gradient and determinant */
- float det = dot(sd->dP.dx, Rx);
+ float det = dot(ccl_fetch(sd, dP).dx, Rx);
float3 surfgrad = (h_x - h_c)*Rx + (h_y - h_c)*Ry;
float absdet = fabsf(det);
@@ -65,7 +65,7 @@ ccl_device void svm_node_set_bump(KernelGlobals *kg, ShaderData *sd, float *stac
ccl_device void svm_node_set_displacement(ShaderData *sd, float *stack, uint fac_offset)
{
float d = stack_load_float(stack, fac_offset);
- sd->P += sd->N*d*0.1f; /* todo: get rid of this factor */
+ ccl_fetch(sd, P) += ccl_fetch(sd, N)*d*0.1f; /* todo: get rid of this factor */
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_fresnel.h b/intern/cycles/kernel/svm/svm_fresnel.h
index 3703ec55015..23c97d80cb0 100644
--- a/intern/cycles/kernel/svm/svm_fresnel.h
+++ b/intern/cycles/kernel/svm/svm_fresnel.h
@@ -23,12 +23,12 @@ ccl_device void svm_node_fresnel(ShaderData *sd, float *stack, uint ior_offset,
uint normal_offset, out_offset;
decode_node_uchar4(node, &normal_offset, &out_offset, NULL, NULL);
float eta = (stack_valid(ior_offset))? stack_load_float(stack, ior_offset): __uint_as_float(ior_value);
- float3 normal_in = stack_valid(normal_offset)? stack_load_float3(stack, normal_offset): sd->N;
+ float3 normal_in = stack_valid(normal_offset)? stack_load_float3(stack, normal_offset): ccl_fetch(sd, N);
eta = fmaxf(eta, 1e-5f);
- eta = (sd->flag & SD_BACKFACING)? 1.0f/eta: eta;
+ eta = (ccl_fetch(sd, flag) & SD_BACKFACING)? 1.0f/eta: eta;
- float f = fresnel_dielectric_cos(dot(sd->I, normal_in), eta);
+ float f = fresnel_dielectric_cos(dot(ccl_fetch(sd, I), normal_in), eta);
stack_store_float(stack, out_offset, f);
}
@@ -44,18 +44,18 @@ ccl_device void svm_node_layer_weight(ShaderData *sd, float *stack, uint4 node)
decode_node_uchar4(node.w, &type, &normal_offset, &out_offset, NULL);
float blend = (stack_valid(blend_offset))? stack_load_float(stack, blend_offset): __uint_as_float(blend_value);
- float3 normal_in = (stack_valid(normal_offset))? stack_load_float3(stack, normal_offset): sd->N;
+ float3 normal_in = (stack_valid(normal_offset))? stack_load_float3(stack, normal_offset): ccl_fetch(sd, N);
float f;
if(type == NODE_LAYER_WEIGHT_FRESNEL) {
float eta = fmaxf(1.0f - blend, 1e-5f);
- eta = (sd->flag & SD_BACKFACING)? eta: 1.0f/eta;
+ eta = (ccl_fetch(sd, flag) & SD_BACKFACING)? eta: 1.0f/eta;
- f = fresnel_dielectric_cos(dot(sd->I, normal_in), eta);
+ f = fresnel_dielectric_cos(dot(ccl_fetch(sd, I), normal_in), eta);
}
else {
- f = fabsf(dot(sd->I, normal_in));
+ f = fabsf(dot(ccl_fetch(sd, I), normal_in));
if(blend != 0.5f) {
blend = clamp(blend, 0.0f, 1.0f-1e-5f);
diff --git a/intern/cycles/kernel/svm/svm_gamma.h b/intern/cycles/kernel/svm/svm_gamma.h
index 8bc59b9c673..b645ff3f0f9 100644
--- a/intern/cycles/kernel/svm/svm_gamma.h
+++ b/intern/cycles/kernel/svm/svm_gamma.h
@@ -21,14 +21,14 @@ ccl_device void svm_node_gamma(ShaderData *sd, float *stack, uint in_gamma, uint
float3 color = stack_load_float3(stack, in_color);
float gamma = stack_load_float(stack, in_gamma);
- if (color.x > 0.0f)
+ if(color.x > 0.0f)
color.x = powf(color.x, gamma);
- if (color.y > 0.0f)
+ if(color.y > 0.0f)
color.y = powf(color.y, gamma);
- if (color.z > 0.0f)
+ if(color.z > 0.0f)
color.z = powf(color.z, gamma);
- if (stack_valid(out_color))
+ if(stack_valid(out_color))
stack_store_float3(stack, out_color, color);
}
diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h
index efbefa77d28..bb06254c3a9 100644
--- a/intern/cycles/kernel/svm/svm_geometry.h
+++ b/intern/cycles/kernel/svm/svm_geometry.h
@@ -23,15 +23,15 @@ ccl_device void svm_node_geometry(KernelGlobals *kg, ShaderData *sd, float *stac
float3 data;
switch(type) {
- case NODE_GEOM_P: data = sd->P; break;
- case NODE_GEOM_N: data = sd->N; break;
+ case NODE_GEOM_P: data = ccl_fetch(sd, P); break;
+ case NODE_GEOM_N: data = ccl_fetch(sd, N); break;
#ifdef __DPDU__
case NODE_GEOM_T: data = primitive_tangent(kg, sd); break;
#endif
- case NODE_GEOM_I: data = sd->I; break;
- case NODE_GEOM_Ng: data = sd->Ng; break;
+ case NODE_GEOM_I: data = ccl_fetch(sd, I); break;
+ case NODE_GEOM_Ng: data = ccl_fetch(sd, Ng); break;
#ifdef __UV__
- case NODE_GEOM_uv: data = make_float3(sd->u, sd->v, 0.0f); break;
+ case NODE_GEOM_uv: data = make_float3(ccl_fetch(sd, u), ccl_fetch(sd, v), 0.0f); break;
#endif
}
@@ -44,8 +44,8 @@ ccl_device void svm_node_geometry_bump_dx(KernelGlobals *kg, ShaderData *sd, flo
float3 data;
switch(type) {
- case NODE_GEOM_P: data = sd->P + sd->dP.dx; break;
- case NODE_GEOM_uv: data = make_float3(sd->u + sd->du.dx, sd->v + sd->dv.dx, 0.0f); break;
+ case NODE_GEOM_P: data = ccl_fetch(sd, P) + ccl_fetch(sd, dP).dx; break;
+ case NODE_GEOM_uv: data = make_float3(ccl_fetch(sd, u) + ccl_fetch(sd, du).dx, ccl_fetch(sd, v) + ccl_fetch(sd, dv).dx, 0.0f); break;
default: svm_node_geometry(kg, sd, stack, type, out_offset); return;
}
@@ -61,8 +61,8 @@ ccl_device void svm_node_geometry_bump_dy(KernelGlobals *kg, ShaderData *sd, flo
float3 data;
switch(type) {
- case NODE_GEOM_P: data = sd->P + sd->dP.dy; break;
- case NODE_GEOM_uv: data = make_float3(sd->u + sd->du.dy, sd->v + sd->dv.dy, 0.0f); break;
+ case NODE_GEOM_P: data = ccl_fetch(sd, P) + ccl_fetch(sd, dP).dy; break;
+ case NODE_GEOM_uv: data = make_float3(ccl_fetch(sd, u) + ccl_fetch(sd, du).dy, ccl_fetch(sd, v) + ccl_fetch(sd, dv).dy, 0.0f); break;
default: svm_node_geometry(kg, sd, stack, type, out_offset); return;
}
@@ -83,9 +83,9 @@ ccl_device void svm_node_object_info(KernelGlobals *kg, ShaderData *sd, float *s
stack_store_float3(stack, out_offset, object_location(kg, sd));
return;
}
- case NODE_INFO_OB_INDEX: data = object_pass_id(kg, sd->object); break;
+ case NODE_INFO_OB_INDEX: data = object_pass_id(kg, ccl_fetch(sd, object)); break;
case NODE_INFO_MAT_INDEX: data = shader_pass_id(kg, sd); break;
- case NODE_INFO_OB_RANDOM: data = object_random_number(kg, sd->object); break;
+ case NODE_INFO_OB_RANDOM: data = object_random_number(kg, ccl_fetch(sd, object)); break;
default: data = 0.0f; break;
}
@@ -98,44 +98,44 @@ ccl_device void svm_node_particle_info(KernelGlobals *kg, ShaderData *sd, float
{
switch(type) {
case NODE_INFO_PAR_INDEX: {
- int particle_id = object_particle_id(kg, sd->object);
+ int particle_id = object_particle_id(kg, ccl_fetch(sd, object));
stack_store_float(stack, out_offset, particle_index(kg, particle_id));
break;
}
case NODE_INFO_PAR_AGE: {
- int particle_id = object_particle_id(kg, sd->object);
+ int particle_id = object_particle_id(kg, ccl_fetch(sd, object));
stack_store_float(stack, out_offset, particle_age(kg, particle_id));
break;
}
case NODE_INFO_PAR_LIFETIME: {
- int particle_id = object_particle_id(kg, sd->object);
+ int particle_id = object_particle_id(kg, ccl_fetch(sd, object));
stack_store_float(stack, out_offset, particle_lifetime(kg, particle_id));
break;
}
case NODE_INFO_PAR_LOCATION: {
- int particle_id = object_particle_id(kg, sd->object);
+ int particle_id = object_particle_id(kg, ccl_fetch(sd, object));
stack_store_float3(stack, out_offset, particle_location(kg, particle_id));
break;
}
#if 0 /* XXX float4 currently not supported in SVM stack */
case NODE_INFO_PAR_ROTATION: {
- int particle_id = object_particle_id(kg, sd->object);
+ int particle_id = object_particle_id(kg, ccl_fetch(sd, object));
stack_store_float4(stack, out_offset, particle_rotation(kg, particle_id));
break;
}
#endif
case NODE_INFO_PAR_SIZE: {
- int particle_id = object_particle_id(kg, sd->object);
+ int particle_id = object_particle_id(kg, ccl_fetch(sd, object));
stack_store_float(stack, out_offset, particle_size(kg, particle_id));
break;
}
case NODE_INFO_PAR_VELOCITY: {
- int particle_id = object_particle_id(kg, sd->object);
+ int particle_id = object_particle_id(kg, ccl_fetch(sd, object));
stack_store_float3(stack, out_offset, particle_velocity(kg, particle_id));
break;
}
case NODE_INFO_PAR_ANGULAR_VELOCITY: {
- int particle_id = object_particle_id(kg, sd->object);
+ int particle_id = object_particle_id(kg, ccl_fetch(sd, object));
stack_store_float3(stack, out_offset, particle_angular_velocity(kg, particle_id));
break;
}
@@ -153,7 +153,7 @@ ccl_device void svm_node_hair_info(KernelGlobals *kg, ShaderData *sd, float *sta
switch(type) {
case NODE_INFO_CURVE_IS_STRAND: {
- data = (sd->type & PRIMITIVE_ALL_CURVE) != 0;
+ data = (ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) != 0;
stack_store_float(stack, out_offset, data);
break;
}
@@ -165,7 +165,7 @@ ccl_device void svm_node_hair_info(KernelGlobals *kg, ShaderData *sd, float *sta
break;
}
/*case NODE_INFO_CURVE_FADE: {
- data = sd->curve_transparency;
+ data = ccl_fetch(sd, curve_transparency);
stack_store_float(stack, out_offset, data);
break;
}*/
diff --git a/intern/cycles/kernel/svm/svm_gradient.h b/intern/cycles/kernel/svm/svm_gradient.h
index a5e385faddc..53d7b4f812c 100644
--- a/intern/cycles/kernel/svm/svm_gradient.h
+++ b/intern/cycles/kernel/svm/svm_gradient.h
@@ -66,7 +66,7 @@ ccl_device void svm_node_tex_gradient(ShaderData *sd, float *stack, uint4 node)
float3 co = stack_load_float3(stack, co_offset);
float f = svm_gradient(co, (NodeGradientType)type);
- f = clamp(f, 0.0f, 1.0f);
+ f = saturate(f);
if(stack_valid(fac_offset))
stack_store_float(stack, fac_offset, f);
diff --git a/intern/cycles/kernel/svm/svm_hsv.h b/intern/cycles/kernel/svm/svm_hsv.h
index eeb4ba25e91..1f2cad60df7 100644
--- a/intern/cycles/kernel/svm/svm_hsv.h
+++ b/intern/cycles/kernel/svm/svm_hsv.h
@@ -46,12 +46,12 @@ ccl_device void svm_node_hsv(KernelGlobals *kg, ShaderData *sd, float *stack, ui
color.y = fac*color.y + (1.0f - fac)*in_color.y;
color.z = fac*color.z + (1.0f - fac)*in_color.z;
- /* Clamp color to prevent negative values cauzed by oversaturation. */
+ /* Clamp color to prevent negative values caused by oversaturation. */
color.x = max(color.x, 0.0f);
color.y = max(color.y, 0.0f);
color.z = max(color.z, 0.0f);
- if (stack_valid(out_color_offset))
+ if(stack_valid(out_color_offset))
stack_store_float3(stack, out_color_offset, color);
}
diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h
index 4de69479bd9..caf0b37ba35 100644
--- a/intern/cycles/kernel/svm/svm_image.h
+++ b/intern/cycles/kernel/svm/svm_image.h
@@ -65,7 +65,7 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y,
float4 r;
int ix, iy, nix, niy;
- if (interpolation == INTERPOLATION_CLOSEST) {
+ if(interpolation == INTERPOLATION_CLOSEST) {
svm_image_texture_frac(x*width, &ix);
svm_image_texture_frac(y*height, &iy);
@@ -251,9 +251,9 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y,
case 95: r = kernel_tex_image_interp(__tex_image_095, x, y); break;
case 96: r = kernel_tex_image_interp(__tex_image_096, x, y); break;
case 97: r = kernel_tex_image_interp(__tex_image_097, x, y); break;
- case 98: r = kernel_tex_image_interp(__tex_image_098, x, y); break;
#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 300)
+ case 98: r = kernel_tex_image_interp(__tex_image_098, x, y); break;
case 99: r = kernel_tex_image_interp(__tex_image_099, x, y); break;
case 100: r = kernel_tex_image_interp(__tex_image_100, x, y); break;
case 101: r = kernel_tex_image_interp(__tex_image_101, x, y); break;
@@ -392,10 +392,10 @@ ccl_device void svm_node_tex_image(KernelGlobals *kg, ShaderData *sd, float *sta
ccl_device void svm_node_tex_image_box(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
{
/* get object space normal */
- float3 N = sd->N;
+ float3 N = ccl_fetch(sd, N);
- N = sd->N;
- if(sd->object != OBJECT_NONE)
+ N = ccl_fetch(sd, N);
+ if(ccl_fetch(sd, object) != OBJECT_NONE)
object_inverse_normal_transform(kg, sd, &N);
/* project from direction vector to barycentric coordinates in triangles */
@@ -433,17 +433,17 @@ ccl_device void svm_node_tex_image_box(KernelGlobals *kg, ShaderData *sd, float
/* in case of blending, test for mixes between two textures */
if(N.z < (1.0f - limit)*(N.y + N.x)) {
weight.x = N.x/(N.x + N.y);
- weight.x = clamp((weight.x - 0.5f*(1.0f - blend))/blend, 0.0f, 1.0f);
+ weight.x = saturate((weight.x - 0.5f*(1.0f - blend))/blend);
weight.y = 1.0f - weight.x;
}
else if(N.x < (1.0f - limit)*(N.y + N.z)) {
weight.y = N.y/(N.y + N.z);
- weight.y = clamp((weight.y - 0.5f*(1.0f - blend))/blend, 0.0f, 1.0f);
+ weight.y = saturate((weight.y - 0.5f*(1.0f - blend))/blend);
weight.z = 1.0f - weight.y;
}
else if(N.y < (1.0f - limit)*(N.x + N.z)) {
weight.x = N.x/(N.x + N.z);
- weight.x = clamp((weight.x - 0.5f*(1.0f - blend))/blend, 0.0f, 1.0f);
+ weight.x = saturate((weight.x - 0.5f*(1.0f - blend))/blend);
weight.z = 1.0f - weight.x;
}
else {
diff --git a/intern/cycles/kernel/svm/svm_invert.h b/intern/cycles/kernel/svm/svm_invert.h
index 152b49174e0..5ce858e2e5d 100644
--- a/intern/cycles/kernel/svm/svm_invert.h
+++ b/intern/cycles/kernel/svm/svm_invert.h
@@ -30,7 +30,7 @@ ccl_device void svm_node_invert(ShaderData *sd, float *stack, uint in_fac, uint
color.y = invert(color.y, factor);
color.z = invert(color.z, factor);
- if (stack_valid(out_color))
+ if(stack_valid(out_color))
stack_store_float3(stack, out_color, color);
}
diff --git a/intern/cycles/kernel/svm/svm_light_path.h b/intern/cycles/kernel/svm/svm_light_path.h
index 677d139c5d4..a235dd35224 100644
--- a/intern/cycles/kernel/svm/svm_light_path.h
+++ b/intern/cycles/kernel/svm/svm_light_path.h
@@ -31,10 +31,10 @@ ccl_device void svm_node_light_path(ShaderData *sd, float *stack, uint type, uin
case NODE_LP_reflection: info = (path_flag & PATH_RAY_REFLECT)? 1.0f: 0.0f; break;
case NODE_LP_transmission: info = (path_flag & PATH_RAY_TRANSMIT)? 1.0f: 0.0f; break;
case NODE_LP_volume_scatter: info = (path_flag & PATH_RAY_VOLUME_SCATTER)? 1.0f: 0.0f; break;
- case NODE_LP_backfacing: info = (sd->flag & SD_BACKFACING)? 1.0f: 0.0f; break;
- case NODE_LP_ray_length: info = sd->ray_length; break;
- case NODE_LP_ray_depth: info = (float)sd->ray_depth; break;
- case NODE_LP_ray_transparent: info = sd->transparent_depth; break;
+ case NODE_LP_backfacing: info = (ccl_fetch(sd, flag) & SD_BACKFACING)? 1.0f: 0.0f; break;
+ case NODE_LP_ray_length: info = ccl_fetch(sd, ray_length); break;
+ case NODE_LP_ray_depth: info = (float)ccl_fetch(sd, ray_depth); break;
+ case NODE_LP_ray_transparent: info = (float)ccl_fetch(sd, transparent_depth); break;
}
stack_store_float(stack, out_offset, info);
@@ -53,14 +53,14 @@ ccl_device void svm_node_light_falloff(ShaderData *sd, float *stack, uint4 node)
switch(type) {
case NODE_LIGHT_FALLOFF_QUADRATIC: break;
- case NODE_LIGHT_FALLOFF_LINEAR: strength *= sd->ray_length; break;
- case NODE_LIGHT_FALLOFF_CONSTANT: strength *= sd->ray_length*sd->ray_length; break;
+ case NODE_LIGHT_FALLOFF_LINEAR: strength *= ccl_fetch(sd, ray_length); break;
+ case NODE_LIGHT_FALLOFF_CONSTANT: strength *= ccl_fetch(sd, ray_length)*ccl_fetch(sd, ray_length); break;
}
float smooth = stack_load_float(stack, smooth_offset);
if(smooth > 0.0f) {
- float squared = sd->ray_length*sd->ray_length;
+ float squared = ccl_fetch(sd, ray_length)*ccl_fetch(sd, ray_length);
strength *= squared/(smooth + squared);
}
diff --git a/intern/cycles/kernel/svm/svm_math_util.h b/intern/cycles/kernel/svm/svm_math_util.h
index 39cc14d5e8e..645cbd3fc73 100644
--- a/intern/cycles/kernel/svm/svm_math_util.h
+++ b/intern/cycles/kernel/svm/svm_math_util.h
@@ -97,12 +97,74 @@ ccl_device float svm_math(NodeMath type, float Fac1, float Fac2)
else if(type == NODE_MATH_ABSOLUTE)
Fac = fabsf(Fac1);
else if(type == NODE_MATH_CLAMP)
- Fac = clamp(Fac1, 0.0f, 1.0f);
+ Fac = saturate(Fac1);
else
Fac = 0.0f;
return Fac;
}
+ccl_device float3 svm_math_blackbody_color(float t) {
+ /* Calculate color in range 800..12000 using an approximation
+ * a/x+bx+c for R and G and ((at + b)t + c)t + d) for B
+ * Max absolute error for RGB is (0.00095, 0.00077, 0.00057),
+ * which is enough to get the same 8 bit/channel color.
+ */
+
+ const float rc[6][3] = {
+ { 2.52432244e+03f, -1.06185848e-03f, 3.11067539e+00f },
+ { 3.37763626e+03f, -4.34581697e-04f, 1.64843306e+00f },
+ { 4.10671449e+03f, -8.61949938e-05f, 6.41423749e-01f },
+ { 4.66849800e+03f, 2.85655028e-05f, 1.29075375e-01f },
+ { 4.60124770e+03f, 2.89727618e-05f, 1.48001316e-01f },
+ { 3.78765709e+03f, 9.36026367e-06f, 3.98995841e-01f },
+ };
+
+ const float gc[6][3] = {
+ { -7.50343014e+02f, 3.15679613e-04f, 4.73464526e-01f },
+ { -1.00402363e+03f, 1.29189794e-04f, 9.08181524e-01f },
+ { -1.22075471e+03f, 2.56245413e-05f, 1.20753416e+00f },
+ { -1.42546105e+03f, -4.01730887e-05f, 1.44002695e+00f },
+ { -1.18134453e+03f, -2.18913373e-05f, 1.30656109e+00f },
+ { -5.00279505e+02f, -4.59745390e-06f, 1.09090465e+00f },
+ };
+
+ const float bc[6][4] = {
+ { 0.0f, 0.0f, 0.0f, 0.0f }, /* zeros should be optimized by compiler */
+ { 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 0.0f },
+ { -2.02524603e-11f, 1.79435860e-07f, -2.60561875e-04f, -1.41761141e-02f },
+ { -2.22463426e-13f, -1.55078698e-08f, 3.81675160e-04f, -7.30646033e-01f },
+ { 6.72595954e-13f, -2.73059993e-08f, 4.24068546e-04f, -7.52204323e-01f },
+ };
+
+ if(t >= 12000.0f)
+ return make_float3(0.826270103f, 0.994478524f, 1.56626022f);
+
+ /* Define a macro to reduce stack usage for nvcc */
+#define MAKE_BB_RGB(i) make_float3(\
+ rc[i][0] / t + rc[i][1] * t + rc[i][2],\
+ gc[i][0] / t + gc[i][1] * t + gc[i][2],\
+ ((bc[i][0] * t + bc[i][1]) * t + bc[i][2]) * t + bc[i][3])
+
+ if(t >= 6365.0f)
+ return MAKE_BB_RGB(5);
+ if(t >= 3315.0f)
+ return MAKE_BB_RGB(4);
+ if(t >= 1902.0f)
+ return MAKE_BB_RGB(3);
+ if(t >= 1449.0f)
+ return MAKE_BB_RGB(2);
+ if(t >= 1167.0f)
+ return MAKE_BB_RGB(1);
+ if(t >= 965.0f)
+ return MAKE_BB_RGB(0);
+
+#undef MAKE_BB_RGB
+
+ /* For 800 <= t < 965 color does not change in OSL implementation, so keep color the same */
+ return make_float3(4.70366907f, 0.0f, 0.0f);
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_mix.h b/intern/cycles/kernel/svm/svm_mix.h
index b6b1966cb3b..6111214acba 100644
--- a/intern/cycles/kernel/svm/svm_mix.h
+++ b/intern/cycles/kernel/svm/svm_mix.h
@@ -254,16 +254,16 @@ ccl_device float3 svm_mix_clamp(float3 col)
{
float3 outcol = col;
- outcol.x = clamp(col.x, 0.0f, 1.0f);
- outcol.y = clamp(col.y, 0.0f, 1.0f);
- outcol.z = clamp(col.z, 0.0f, 1.0f);
+ outcol.x = saturate(col.x);
+ outcol.y = saturate(col.y);
+ outcol.z = saturate(col.z);
return outcol;
}
ccl_device float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2)
{
- float t = clamp(fac, 0.0f, 1.0f);
+ float t = saturate(fac);
switch(type) {
case NODE_MIX_BLEND: return svm_mix_blend(t, c1, c2);
diff --git a/intern/cycles/kernel/svm/svm_musgrave.h b/intern/cycles/kernel/svm/svm_musgrave.h
index 2f81ddaa74c..09eba31945e 100644
--- a/intern/cycles/kernel/svm/svm_musgrave.h
+++ b/intern/cycles/kernel/svm/svm_musgrave.h
@@ -25,7 +25,7 @@ CCL_NAMESPACE_BEGIN
* from "Texturing and Modelling: A procedural approach"
*/
-ccl_device_noinline float noise_musgrave_fBm(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves)
+ccl_device_noinline float noise_musgrave_fBm(float3 p, float H, float lacunarity, float octaves)
{
float rmd;
float value = 0.0f;
@@ -53,7 +53,7 @@ ccl_device_noinline float noise_musgrave_fBm(float3 p, NodeNoiseBasis basis, flo
* octaves: number of frequencies in the fBm
*/
-ccl_device_noinline float noise_musgrave_multi_fractal(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves)
+ccl_device_noinline float noise_musgrave_multi_fractal(float3 p, float H, float lacunarity, float octaves)
{
float rmd;
float value = 1.0f;
@@ -82,7 +82,7 @@ ccl_device_noinline float noise_musgrave_multi_fractal(float3 p, NodeNoiseBasis
* offset: raises the terrain from `sea level'
*/
-ccl_device_noinline float noise_musgrave_hetero_terrain(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves, float offset)
+ccl_device_noinline float noise_musgrave_hetero_terrain(float3 p, float H, float lacunarity, float octaves, float offset)
{
float value, increment, rmd;
float pwHL = powf(lacunarity, -H);
@@ -117,7 +117,7 @@ ccl_device_noinline float noise_musgrave_hetero_terrain(float3 p, NodeNoiseBasis
* offset: raises the terrain from `sea level'
*/
-ccl_device_noinline float noise_musgrave_hybrid_multi_fractal(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves, float offset, float gain)
+ccl_device_noinline float noise_musgrave_hybrid_multi_fractal(float3 p, float H, float lacunarity, float octaves, float offset, float gain)
{
float result, signal, weight, rmd;
float pwHL = powf(lacunarity, -H);
@@ -154,7 +154,7 @@ ccl_device_noinline float noise_musgrave_hybrid_multi_fractal(float3 p, NodeNois
* offset: raises the terrain from `sea level'
*/
-ccl_device_noinline float noise_musgrave_ridged_multi_fractal(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves, float offset, float gain)
+ccl_device_noinline float noise_musgrave_ridged_multi_fractal(float3 p, float H, float lacunarity, float octaves, float offset, float gain)
{
float result, signal, weight;
float pwHL = powf(lacunarity, -H);
@@ -168,7 +168,7 @@ ccl_device_noinline float noise_musgrave_ridged_multi_fractal(float3 p, NodeNois
for(i = 1; i < float_to_int(octaves); i++) {
p *= lacunarity;
- weight = clamp(signal * gain, 0.0f, 1.0f);
+ weight = saturate(signal * gain);
signal = offset - fabsf(snoise(p));
signal *= signal;
signal *= weight;
@@ -183,18 +183,16 @@ ccl_device_noinline float noise_musgrave_ridged_multi_fractal(float3 p, NodeNois
ccl_device float svm_musgrave(NodeMusgraveType type, float dimension, float lacunarity, float octaves, float offset, float intensity, float gain, float3 p)
{
- NodeNoiseBasis basis = NODE_NOISE_PERLIN;
-
if(type == NODE_MUSGRAVE_MULTIFRACTAL)
- return intensity*noise_musgrave_multi_fractal(p, basis, dimension, lacunarity, octaves);
+ return intensity*noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
else if(type == NODE_MUSGRAVE_FBM)
- return intensity*noise_musgrave_fBm(p, basis, dimension, lacunarity, octaves);
+ return intensity*noise_musgrave_fBm(p, dimension, lacunarity, octaves);
else if(type == NODE_MUSGRAVE_HYBRID_MULTIFRACTAL)
- return intensity*noise_musgrave_hybrid_multi_fractal(p, basis, dimension, lacunarity, octaves, offset, gain);
+ return intensity*noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
else if(type == NODE_MUSGRAVE_RIDGED_MULTIFRACTAL)
- return intensity*noise_musgrave_ridged_multi_fractal(p, basis, dimension, lacunarity, octaves, offset, gain);
+ return intensity*noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
else if(type == NODE_MUSGRAVE_HETERO_TERRAIN)
- return intensity*noise_musgrave_hetero_terrain(p, basis, dimension, lacunarity, octaves, offset);
+ return intensity*noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset);
return 0.0f;
}
diff --git a/intern/cycles/kernel/svm/svm_noisetex.h b/intern/cycles/kernel/svm/svm_noisetex.h
index eccd119b74f..62ff38cf1c5 100644
--- a/intern/cycles/kernel/svm/svm_noisetex.h
+++ b/intern/cycles/kernel/svm/svm_noisetex.h
@@ -20,23 +20,22 @@ CCL_NAMESPACE_BEGIN
ccl_device_inline void svm_noise(float3 p, float detail, float distortion, float *fac, float3 *color)
{
- NodeNoiseBasis basis = NODE_NOISE_PERLIN;
int hard = 0;
if(distortion != 0.0f) {
float3 r, offset = make_float3(13.5f, 13.5f, 13.5f);
- r.x = noise_basis(p + offset, basis) * distortion;
- r.y = noise_basis(p, basis) * distortion;
- r.z = noise_basis(p - offset, basis) * distortion;
+ r.x = noise(p + offset) * distortion;
+ r.y = noise(p) * distortion;
+ r.z = noise(p - offset) * distortion;
p += r;
}
- *fac = noise_turbulence(p, basis, detail, hard);
+ *fac = noise_turbulence(p, detail, hard);
*color = make_float3(*fac,
- noise_turbulence(make_float3(p.y, p.x, p.z), basis, detail, hard),
- noise_turbulence(make_float3(p.y, p.z, p.x), basis, detail, hard));
+ noise_turbulence(make_float3(p.y, p.x, p.z), detail, hard),
+ noise_turbulence(make_float3(p.y, p.z, p.x), detail, hard));
}
ccl_device void svm_node_tex_noise(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
diff --git a/intern/cycles/kernel/svm/svm_normal.h b/intern/cycles/kernel/svm/svm_normal.h
index 67b5321e0de..53abef71012 100644
--- a/intern/cycles/kernel/svm/svm_normal.h
+++ b/intern/cycles/kernel/svm/svm_normal.h
@@ -28,10 +28,10 @@ ccl_device void svm_node_normal(KernelGlobals *kg, ShaderData *sd, float *stack,
direction.z = __int_as_float(node1.z);
direction = normalize(direction);
- if (stack_valid(out_normal_offset))
+ if(stack_valid(out_normal_offset))
stack_store_float3(stack, out_normal_offset, direction);
- if (stack_valid(out_dot_offset))
+ if(stack_valid(out_dot_offset))
stack_store_float(stack, out_dot_offset, dot(direction, normalize(normal)));
}
diff --git a/intern/cycles/kernel/svm/svm_ramp.h b/intern/cycles/kernel/svm/svm_ramp.h
index 998f649a571..062ab013b1f 100644
--- a/intern/cycles/kernel/svm/svm_ramp.h
+++ b/intern/cycles/kernel/svm/svm_ramp.h
@@ -21,7 +21,7 @@ CCL_NAMESPACE_BEGIN
ccl_device float4 rgb_ramp_lookup(KernelGlobals *kg, int offset, float f, bool interpolate)
{
- f = clamp(f, 0.0f, 1.0f)*(RAMP_TABLE_SIZE-1);
+ f = saturate(f)*(RAMP_TABLE_SIZE-1);
/* clamp int as well in case of NaN */
int i = clamp(float_to_int(f), 0, RAMP_TABLE_SIZE-1);
diff --git a/intern/cycles/kernel/svm/svm_sepcomb_hsv.h b/intern/cycles/kernel/svm/svm_sepcomb_hsv.h
index 68f9fea02f0..6f51b163756 100644
--- a/intern/cycles/kernel/svm/svm_sepcomb_hsv.h
+++ b/intern/cycles/kernel/svm/svm_sepcomb_hsv.h
@@ -28,7 +28,7 @@ ccl_device void svm_node_combine_hsv(KernelGlobals *kg, ShaderData *sd, float *s
/* Combine, and convert back to RGB */
float3 color = hsv_to_rgb(make_float3(hue, saturation, value));
- if (stack_valid(color_out))
+ if(stack_valid(color_out))
stack_store_float3(stack, color_out, color);
}
@@ -42,11 +42,11 @@ ccl_device void svm_node_separate_hsv(KernelGlobals *kg, ShaderData *sd, float *
/* Convert to HSV */
color = rgb_to_hsv(color);
- if (stack_valid(hue_out))
+ if(stack_valid(hue_out))
stack_store_float(stack, hue_out, color.x);
- if (stack_valid(saturation_out))
+ if(stack_valid(saturation_out))
stack_store_float(stack, saturation_out, color.y);
- if (stack_valid(value_out))
+ if(stack_valid(value_out))
stack_store_float(stack, value_out, color.z);
}
diff --git a/intern/cycles/kernel/svm/svm_sepcomb_vector.h b/intern/cycles/kernel/svm/svm_sepcomb_vector.h
index 7a5a69f6dff..63570dd6942 100644
--- a/intern/cycles/kernel/svm/svm_sepcomb_vector.h
+++ b/intern/cycles/kernel/svm/svm_sepcomb_vector.h
@@ -22,7 +22,7 @@ ccl_device void svm_node_combine_vector(ShaderData *sd, float *stack, uint in_of
{
float vector = stack_load_float(stack, in_offset);
- if (stack_valid(out_offset))
+ if(stack_valid(out_offset))
stack_store_float(stack, out_offset+vector_index, vector);
}
@@ -30,10 +30,10 @@ ccl_device void svm_node_separate_vector(ShaderData *sd, float *stack, uint ivec
{
float3 vector = stack_load_float3(stack, ivector_offset);
- if (stack_valid(out_offset)) {
- if (vector_index == 0)
+ if(stack_valid(out_offset)) {
+ if(vector_index == 0)
stack_store_float(stack, out_offset, vector.x);
- else if (vector_index == 1)
+ else if(vector_index == 1)
stack_store_float(stack, out_offset, vector.y);
else
stack_store_float(stack, out_offset, vector.z);
diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h
index a399acf3c0f..eebd9bee420 100644
--- a/intern/cycles/kernel/svm/svm_tex_coord.h
+++ b/intern/cycles/kernel/svm/svm_tex_coord.h
@@ -31,9 +31,9 @@ ccl_device void svm_node_tex_coord(KernelGlobals *kg,
switch(type) {
case NODE_TEXCO_OBJECT: {
- data = sd->P;
+ data = ccl_fetch(sd, P);
if(node.w == 0) {
- if(sd->object != OBJECT_NONE) {
+ if(ccl_fetch(sd, object) != OBJECT_NONE) {
object_inverse_position_transform(kg, sd, &data);
}
}
@@ -48,48 +48,48 @@ ccl_device void svm_node_tex_coord(KernelGlobals *kg,
break;
}
case NODE_TEXCO_NORMAL: {
- data = sd->N;
- if(sd->object != OBJECT_NONE)
+ data = ccl_fetch(sd, N);
+ if(ccl_fetch(sd, object) != OBJECT_NONE)
object_inverse_normal_transform(kg, sd, &data);
break;
}
case NODE_TEXCO_CAMERA: {
Transform tfm = kernel_data.cam.worldtocamera;
- if(sd->object != OBJECT_NONE)
- data = transform_point(&tfm, sd->P);
+ if(ccl_fetch(sd, object) != OBJECT_NONE)
+ data = transform_point(&tfm, ccl_fetch(sd, P));
else
- data = transform_point(&tfm, sd->P + camera_position(kg));
+ data = transform_point(&tfm, ccl_fetch(sd, P) + camera_position(kg));
break;
}
case NODE_TEXCO_WINDOW: {
- if((path_flag & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE && kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
- data = camera_world_to_ndc(kg, sd, sd->ray_P);
+ if((path_flag & PATH_RAY_CAMERA) && ccl_fetch(sd, object) == OBJECT_NONE && kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
+ data = camera_world_to_ndc(kg, sd, ccl_fetch(sd, ray_P));
else
- data = camera_world_to_ndc(kg, sd, sd->P);
+ data = camera_world_to_ndc(kg, sd, ccl_fetch(sd, P));
data.z = 0.0f;
break;
}
case NODE_TEXCO_REFLECTION: {
- if(sd->object != OBJECT_NONE)
- data = 2.0f*dot(sd->N, sd->I)*sd->N - sd->I;
+ if(ccl_fetch(sd, object) != OBJECT_NONE)
+ data = 2.0f*dot(ccl_fetch(sd, N), ccl_fetch(sd, I))*ccl_fetch(sd, N) - ccl_fetch(sd, I);
else
- data = sd->I;
+ data = ccl_fetch(sd, I);
break;
}
case NODE_TEXCO_DUPLI_GENERATED: {
- data = object_dupli_generated(kg, sd->object);
+ data = object_dupli_generated(kg, ccl_fetch(sd, object));
break;
}
case NODE_TEXCO_DUPLI_UV: {
- data = object_dupli_uv(kg, sd->object);
+ data = object_dupli_uv(kg, ccl_fetch(sd, object));
break;
}
case NODE_TEXCO_VOLUME_GENERATED: {
- data = sd->P;
+ data = ccl_fetch(sd, P);
#ifdef __VOLUME__
- if(sd->object != OBJECT_NONE)
+ if(ccl_fetch(sd, object) != OBJECT_NONE)
data = volume_normalized_position(kg, sd, data);
#endif
break;
@@ -113,9 +113,9 @@ ccl_device void svm_node_tex_coord_bump_dx(KernelGlobals *kg,
switch(type) {
case NODE_TEXCO_OBJECT: {
- data = sd->P + sd->dP.dx;
+ data = ccl_fetch(sd, P) + ccl_fetch(sd, dP).dx;
if(node.w == 0) {
- if(sd->object != OBJECT_NONE) {
+ if(ccl_fetch(sd, object) != OBJECT_NONE) {
object_inverse_position_transform(kg, sd, &data);
}
}
@@ -130,48 +130,48 @@ ccl_device void svm_node_tex_coord_bump_dx(KernelGlobals *kg,
break;
}
case NODE_TEXCO_NORMAL: {
- data = sd->N;
- if(sd->object != OBJECT_NONE)
+ data = ccl_fetch(sd, N);
+ if(ccl_fetch(sd, object) != OBJECT_NONE)
object_inverse_normal_transform(kg, sd, &data);
break;
}
case NODE_TEXCO_CAMERA: {
Transform tfm = kernel_data.cam.worldtocamera;
- if(sd->object != OBJECT_NONE)
- data = transform_point(&tfm, sd->P + sd->dP.dx);
+ if(ccl_fetch(sd, object) != OBJECT_NONE)
+ data = transform_point(&tfm, ccl_fetch(sd, P) + ccl_fetch(sd, dP).dx);
else
- data = transform_point(&tfm, sd->P + sd->dP.dx + camera_position(kg));
+ data = transform_point(&tfm, ccl_fetch(sd, P) + ccl_fetch(sd, dP).dx + camera_position(kg));
break;
}
case NODE_TEXCO_WINDOW: {
- if((path_flag & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE && kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
- data = camera_world_to_ndc(kg, sd, sd->ray_P + sd->ray_dP.dx);
+ if((path_flag & PATH_RAY_CAMERA) && ccl_fetch(sd, object) == OBJECT_NONE && kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
+ data = camera_world_to_ndc(kg, sd, ccl_fetch(sd, ray_P) + ccl_fetch(sd, ray_dP).dx);
else
- data = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dx);
+ data = camera_world_to_ndc(kg, sd, ccl_fetch(sd, P) + ccl_fetch(sd, dP).dx);
data.z = 0.0f;
break;
}
case NODE_TEXCO_REFLECTION: {
- if(sd->object != OBJECT_NONE)
- data = 2.0f*dot(sd->N, sd->I)*sd->N - sd->I;
+ if(ccl_fetch(sd, object) != OBJECT_NONE)
+ data = 2.0f*dot(ccl_fetch(sd, N), ccl_fetch(sd, I))*ccl_fetch(sd, N) - ccl_fetch(sd, I);
else
- data = sd->I;
+ data = ccl_fetch(sd, I);
break;
}
case NODE_TEXCO_DUPLI_GENERATED: {
- data = object_dupli_generated(kg, sd->object);
+ data = object_dupli_generated(kg, ccl_fetch(sd, object));
break;
}
case NODE_TEXCO_DUPLI_UV: {
- data = object_dupli_uv(kg, sd->object);
+ data = object_dupli_uv(kg, ccl_fetch(sd, object));
break;
}
case NODE_TEXCO_VOLUME_GENERATED: {
- data = sd->P + sd->dP.dx;
+ data = ccl_fetch(sd, P) + ccl_fetch(sd, dP).dx;
#ifdef __VOLUME__
- if(sd->object != OBJECT_NONE)
+ if(ccl_fetch(sd, object) != OBJECT_NONE)
data = volume_normalized_position(kg, sd, data);
#endif
break;
@@ -198,9 +198,9 @@ ccl_device void svm_node_tex_coord_bump_dy(KernelGlobals *kg,
switch(type) {
case NODE_TEXCO_OBJECT: {
- data = sd->P + sd->dP.dy;
+ data = ccl_fetch(sd, P) + ccl_fetch(sd, dP).dy;
if(node.w == 0) {
- if(sd->object != OBJECT_NONE) {
+ if(ccl_fetch(sd, object) != OBJECT_NONE) {
object_inverse_position_transform(kg, sd, &data);
}
}
@@ -215,48 +215,48 @@ ccl_device void svm_node_tex_coord_bump_dy(KernelGlobals *kg,
break;
}
case NODE_TEXCO_NORMAL: {
- data = sd->N;
- if(sd->object != OBJECT_NONE)
+ data = ccl_fetch(sd, N);
+ if(ccl_fetch(sd, object) != OBJECT_NONE)
object_inverse_normal_transform(kg, sd, &data);
break;
}
case NODE_TEXCO_CAMERA: {
Transform tfm = kernel_data.cam.worldtocamera;
- if(sd->object != OBJECT_NONE)
- data = transform_point(&tfm, sd->P + sd->dP.dy);
+ if(ccl_fetch(sd, object) != OBJECT_NONE)
+ data = transform_point(&tfm, ccl_fetch(sd, P) + ccl_fetch(sd, dP).dy);
else
- data = transform_point(&tfm, sd->P + sd->dP.dy + camera_position(kg));
+ data = transform_point(&tfm, ccl_fetch(sd, P) + ccl_fetch(sd, dP).dy + camera_position(kg));
break;
}
case NODE_TEXCO_WINDOW: {
- if((path_flag & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE && kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
- data = camera_world_to_ndc(kg, sd, sd->ray_P + sd->ray_dP.dy);
+ if((path_flag & PATH_RAY_CAMERA) && ccl_fetch(sd, object) == OBJECT_NONE && kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
+ data = camera_world_to_ndc(kg, sd, ccl_fetch(sd, ray_P) + ccl_fetch(sd, ray_dP).dy);
else
- data = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dy);
+ data = camera_world_to_ndc(kg, sd, ccl_fetch(sd, P) + ccl_fetch(sd, dP).dy);
data.z = 0.0f;
break;
}
case NODE_TEXCO_REFLECTION: {
- if(sd->object != OBJECT_NONE)
- data = 2.0f*dot(sd->N, sd->I)*sd->N - sd->I;
+ if(ccl_fetch(sd, object) != OBJECT_NONE)
+ data = 2.0f*dot(ccl_fetch(sd, N), ccl_fetch(sd, I))*ccl_fetch(sd, N) - ccl_fetch(sd, I);
else
- data = sd->I;
+ data = ccl_fetch(sd, I);
break;
}
case NODE_TEXCO_DUPLI_GENERATED: {
- data = object_dupli_generated(kg, sd->object);
+ data = object_dupli_generated(kg, ccl_fetch(sd, object));
break;
}
case NODE_TEXCO_DUPLI_UV: {
- data = object_dupli_uv(kg, sd->object);
+ data = object_dupli_uv(kg, ccl_fetch(sd, object));
break;
}
case NODE_TEXCO_VOLUME_GENERATED: {
- data = sd->P + sd->dP.dy;
+ data = ccl_fetch(sd, P) + ccl_fetch(sd, dP).dy;
#ifdef __VOLUME__
- if(sd->object != OBJECT_NONE)
+ if(ccl_fetch(sd, object) != OBJECT_NONE)
data = volume_normalized_position(kg, sd, data);
#endif
break;
@@ -281,7 +281,7 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
if(space == NODE_NORMAL_MAP_TANGENT) {
/* tangent space */
- if(sd->object == OBJECT_NONE) {
+ if(ccl_fetch(sd, object) == OBJECT_NONE) {
stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f));
return;
}
@@ -302,11 +302,11 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
float sign = primitive_attribute_float(kg, sd, attr_sign_elem, attr_sign_offset, NULL, NULL);
float3 normal;
- if(sd->shader & SHADER_SMOOTH_NORMAL) {
+ if(ccl_fetch(sd, shader) & SHADER_SMOOTH_NORMAL) {
normal = primitive_attribute_float3(kg, sd, attr_normal_elem, attr_normal_offset, NULL, NULL);
}
else {
- normal = sd->Ng;
+ normal = ccl_fetch(sd, Ng);
object_inverse_normal_transform(kg, sd, &normal);
}
@@ -337,7 +337,7 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
if(strength != 1.0f) {
strength = max(strength, 0.0f);
- N = normalize(sd->N + (N - sd->N)*strength);
+ N = normalize(ccl_fetch(sd, N) + (N - ccl_fetch(sd, N))*strength);
}
stack_store_float3(stack, normal_offset, N);
@@ -367,7 +367,7 @@ ccl_device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack
float3 generated;
if(attr_offset == ATTR_STD_NOT_FOUND)
- generated = sd->P;
+ generated = ccl_fetch(sd, P);
else
generated = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
@@ -380,7 +380,7 @@ ccl_device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack
}
object_normal_transform(kg, sd, &tangent);
- tangent = cross(sd->N, normalize(cross(tangent, sd->N)));
+ tangent = cross(ccl_fetch(sd, N), normalize(cross(tangent, ccl_fetch(sd, N))));
stack_store_float3(stack, tangent_offset, tangent);
}
diff --git a/intern/cycles/kernel/svm/svm_texture.h b/intern/cycles/kernel/svm/svm_texture.h
index c5dc213c82d..dcb00f7dd55 100644
--- a/intern/cycles/kernel/svm/svm_texture.h
+++ b/intern/cycles/kernel/svm/svm_texture.h
@@ -16,261 +16,9 @@
CCL_NAMESPACE_BEGIN
-/* Voronoi Distances */
-
-#if 0
-ccl_device float voronoi_distance(NodeDistanceMetric distance_metric, float3 d, float e)
-{
-#if 0
- if(distance_metric == NODE_VORONOI_DISTANCE_SQUARED)
-#endif
- return dot(d, d);
-#if 0
- if(distance_metric == NODE_VORONOI_ACTUAL_DISTANCE)
- return len(d);
- if(distance_metric == NODE_VORONOI_MANHATTAN)
- return fabsf(d.x) + fabsf(d.y) + fabsf(d.z);
- if(distance_metric == NODE_VORONOI_CHEBYCHEV)
- return fmaxf(fabsf(d.x), fmaxf(fabsf(d.y), fabsf(d.z)));
- if(distance_metric == NODE_VORONOI_MINKOVSKY_H)
- return sqrtf(fabsf(d.x)) + sqrtf(fabsf(d.y)) + sqrtf(fabsf(d.y));
- if(distance_metric == NODE_VORONOI_MINKOVSKY_4)
- return sqrtf(sqrtf(dot(d*d, d*d)));
- if(distance_metric == NODE_VORONOI_MINKOVSKY)
- return powf(powf(fabsf(d.x), e) + powf(fabsf(d.y), e) + powf(fabsf(d.z), e), 1.0f/e);
-
- return 0.0f;
-#endif
-}
-
-/* Voronoi / Worley like */
-ccl_device_inline float4 voronoi_Fn(float3 p, float e, int n1, int n2)
-{
- float da[4];
- float3 pa[4];
- NodeDistanceMetric distance_metric = NODE_VORONOI_DISTANCE_SQUARED;
-
- /* returns distances in da and point coords in pa */
- int xx, yy, zz, xi, yi, zi;
-
- xi = floor_to_int(p.x);
- yi = floor_to_int(p.y);
- zi = floor_to_int(p.z);
-
- da[0] = 1e10f;
- da[1] = 1e10f;
- da[2] = 1e10f;
- da[3] = 1e10f;
-
- pa[0] = make_float3(0.0f, 0.0f, 0.0f);
- pa[1] = make_float3(0.0f, 0.0f, 0.0f);
- pa[2] = make_float3(0.0f, 0.0f, 0.0f);
- pa[3] = make_float3(0.0f, 0.0f, 0.0f);
-
- for(xx = xi-1; xx <= xi+1; xx++) {
- for(yy = yi-1; yy <= yi+1; yy++) {
- for(zz = zi-1; zz <= zi+1; zz++) {
- float3 ip = make_float3((float)xx, (float)yy, (float)zz);
- float3 vp = cellnoise_color(ip);
- float3 pd = p - (vp + ip);
- float d = voronoi_distance(distance_metric, pd, e);
-
- vp += ip;
-
- if(d < da[0]) {
- da[3] = da[2];
- da[2] = da[1];
- da[1] = da[0];
- da[0] = d;
-
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = pa[0];
- pa[0] = vp;
- }
- else if(d < da[1]) {
- da[3] = da[2];
- da[2] = da[1];
- da[1] = d;
-
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = vp;
- }
- else if(d < da[2]) {
- da[3] = da[2];
- da[2] = d;
-
- pa[3] = pa[2];
- pa[2] = vp;
- }
- else if(d < da[3]) {
- da[3] = d;
- pa[3] = vp;
- }
- }
- }
- }
-
- float4 result = make_float4(pa[n1].x, pa[n1].y, pa[n1].z, da[n1]);
-
- if(n2 != -1)
- result = make_float4(pa[n2].x, pa[n2].y, pa[n2].z, da[n2]) - result;
-
- return result;
-}
-#endif
-
-ccl_device float voronoi_F1_distance(float3 p)
-{
- /* returns squared distance in da */
- float da = 1e10f;
-
-#ifndef __KERNEL_SSE2__
- int ix = floor_to_int(p.x), iy = floor_to_int(p.y), iz = floor_to_int(p.z);
-
- for (int xx = -1; xx <= 1; xx++) {
- for (int yy = -1; yy <= 1; yy++) {
- for (int zz = -1; zz <= 1; zz++) {
- float3 ip = make_float3(ix + xx, iy + yy, iz + zz);
- float3 vp = ip + cellnoise_color(ip);
- float d = len_squared(p - vp);
- da = min(d, da);
- }
- }
- }
-#else
- ssef vec_p = load4f(p);
- ssei xyzi = quick_floor_sse(vec_p);
-
- for (int xx = -1; xx <= 1; xx++) {
- for (int yy = -1; yy <= 1; yy++) {
- for (int zz = -1; zz <= 1; zz++) {
- ssef ip = ssef(xyzi + ssei(xx, yy, zz, 0));
- ssef vp = ip + cellnoise_color(ip);
- float d = len_squared<1, 1, 1, 0>(vec_p - vp);
- da = min(d, da);
- }
- }
- }
-#endif
-
- return da;
-}
-
-ccl_device float3 voronoi_F1_color(float3 p)
-{
- /* returns color of the nearest point */
- float da = 1e10f;
-
-#ifndef __KERNEL_SSE2__
- float3 pa;
- int ix = floor_to_int(p.x), iy = floor_to_int(p.y), iz = floor_to_int(p.z);
-
- for (int xx = -1; xx <= 1; xx++) {
- for (int yy = -1; yy <= 1; yy++) {
- for (int zz = -1; zz <= 1; zz++) {
- float3 ip = make_float3(ix + xx, iy + yy, iz + zz);
- float3 vp = ip + cellnoise_color(ip);
- float d = len_squared(p - vp);
-
- if(d < da) {
- da = d;
- pa = vp;
- }
- }
- }
- }
-
- return cellnoise_color(pa);
-#else
- ssef pa, vec_p = load4f(p);
- ssei xyzi = quick_floor_sse(vec_p);
-
- for (int xx = -1; xx <= 1; xx++) {
- for (int yy = -1; yy <= 1; yy++) {
- for (int zz = -1; zz <= 1; zz++) {
- ssef ip = ssef(xyzi + ssei(xx, yy, zz, 0));
- ssef vp = ip + cellnoise_color(ip);
- float d = len_squared<1, 1, 1, 0>(vec_p - vp);
-
- if(d < da) {
- da = d;
- pa = vp;
- }
- }
- }
- }
-
- ssef color = cellnoise_color(pa);
- return (float3 &)color;
-#endif
-}
-
-#if 0
-ccl_device float voronoi_F1(float3 p) { return voronoi_Fn(p, 0.0f, 0, -1).w; }
-ccl_device float voronoi_F2(float3 p) { return voronoi_Fn(p, 0.0f, 1, -1).w; }
-ccl_device float voronoi_F3(float3 p) { return voronoi_Fn(p, 0.0f, 2, -1).w; }
-ccl_device float voronoi_F4(float3 p) { return voronoi_Fn(p, 0.0f, 3, -1).w; }
-ccl_device float voronoi_F1F2(float3 p) { return voronoi_Fn(p, 0.0f, 0, 1).w; }
-
-ccl_device float voronoi_Cr(float3 p)
-{
- /* crackle type pattern, just a scale/clamp of F2-F1 */
- float t = 10.0f*voronoi_F1F2(p);
- return (t > 1.0f)? 1.0f: t;
-}
-
-ccl_device float voronoi_F1S(float3 p) { return 2.0f*voronoi_F1(p) - 1.0f; }
-ccl_device float voronoi_F2S(float3 p) { return 2.0f*voronoi_F2(p) - 1.0f; }
-ccl_device float voronoi_F3S(float3 p) { return 2.0f*voronoi_F3(p) - 1.0f; }
-ccl_device float voronoi_F4S(float3 p) { return 2.0f*voronoi_F4(p) - 1.0f; }
-ccl_device float voronoi_F1F2S(float3 p) { return 2.0f*voronoi_F1F2(p) - 1.0f; }
-ccl_device float voronoi_CrS(float3 p) { return 2.0f*voronoi_Cr(p) - 1.0f; }
-#endif
-
-/* Noise Bases */
-
-ccl_device float noise_basis(float3 p, NodeNoiseBasis basis)
-{
- /* Only Perlin enabled for now, others break CUDA compile by making kernel
- * too big, with compile using > 4GB, due to everything being inlined. */
-
-#if 0
- if(basis == NODE_NOISE_PERLIN)
-#endif
- return noise(p);
-#if 0
- if(basis == NODE_NOISE_VORONOI_F1)
- return voronoi_F1S(p);
- if(basis == NODE_NOISE_VORONOI_F2)
- return voronoi_F2S(p);
- if(basis == NODE_NOISE_VORONOI_F3)
- return voronoi_F3S(p);
- if(basis == NODE_NOISE_VORONOI_F4)
- return voronoi_F4S(p);
- if(basis == NODE_NOISE_VORONOI_F2_F1)
- return voronoi_F1F2S(p);
- if(basis == NODE_NOISE_VORONOI_CRACKLE)
- return voronoi_CrS(p);
- if(basis == NODE_NOISE_CELL_NOISE)
- return cellnoise(p);
-
- return 0.0f;
-#endif
-}
-
-/* Soft/Hard Noise */
-
-ccl_device float noise_basis_hard(float3 p, NodeNoiseBasis basis, int hard)
-{
- float t = noise_basis(p, basis);
- return (hard)? fabsf(2.0f*t - 1.0f): t;
-}
-
/* Turbulence */
-ccl_device_noinline float noise_turbulence(float3 p, NodeNoiseBasis basis, float octaves, int hard)
+ccl_device_noinline float noise_turbulence(float3 p, float octaves, int hard)
{
float fscale = 1.0f;
float amp = 1.0f;
@@ -281,7 +29,7 @@ ccl_device_noinline float noise_turbulence(float3 p, NodeNoiseBasis basis, float
n = float_to_int(octaves);
for(i = 0; i <= n; i++) {
- float t = noise_basis(fscale*p, basis);
+ float t = noise(fscale*p);
if(hard)
t = fabsf(2.0f*t - 1.0f);
@@ -294,7 +42,7 @@ ccl_device_noinline float noise_turbulence(float3 p, NodeNoiseBasis basis, float
float rmd = octaves - floorf(octaves);
if(rmd != 0.0f) {
- float t = noise_basis(fscale*p, basis);
+ float t = noise(fscale*p);
if(hard)
t = fabsf(2.0f*t - 1.0f);
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index 7130b14a426..641d30a5737 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -28,6 +28,29 @@ CCL_NAMESPACE_BEGIN
/* Nodes */
+/* Known frequencies of used nodes, used for selective nodes compilation
+ * in the kernel. Currently only affects split OpenCL kernel.
+ *
+ * Keep as defines so it's easy to check which nodes are to be compiled
+ * from preprocessor.
+ *
+ * Lower the number of group more often the node is used.
+ */
+#define NODE_GROUP_LEVEL_0 0
+#define NODE_GROUP_LEVEL_1 1
+#define NODE_GROUP_LEVEL_2 2
+#define NODE_GROUP_LEVEL_3 3
+#define NODE_GROUP_LEVEL_MAX NODE_GROUP_LEVEL_3
+
+#define NODE_FEATURE_VOLUME (1 << 0)
+#define NODE_FEATURE_HAIR (1 << 1)
+#define NODE_FEATURE_BUMP (1 << 2)
+/* TODO(sergey): Consider using something like ((uint)(-1)).
+ * Need to ceck carefully operand types around usage of this
+ * define first.
+ */
+#define NODE_FEATURE_ALL (NODE_FEATURE_VOLUME|NODE_FEATURE_HAIR|NODE_FEATURE_BUMP)
+
typedef enum NodeType {
NODE_END = 0,
NODE_CLOSURE_BSDF,
@@ -102,7 +125,8 @@ typedef enum NodeType {
NODE_TANGENT,
NODE_NORMAL_MAP,
NODE_HAIR_INFO,
- NODE_UVMAP
+ NODE_UVMAP,
+ NODE_TEX_VOXEL,
} NodeType;
typedef enum NodeAttributeType {
@@ -256,27 +280,6 @@ typedef enum NodeConvert {
NODE_CONVERT_IV
} NodeConvert;
-typedef enum NodeDistanceMetric {
- NODE_VORONOI_DISTANCE_SQUARED,
- NODE_VORONOI_ACTUAL_DISTANCE,
- NODE_VORONOI_MANHATTAN,
- NODE_VORONOI_CHEBYCHEV,
- NODE_VORONOI_MINKOVSKY_H,
- NODE_VORONOI_MINKOVSKY_4,
- NODE_VORONOI_MINKOVSKY
-} NodeDistanceMetric;
-
-typedef enum NodeNoiseBasis {
- NODE_NOISE_PERLIN,
- NODE_NOISE_VORONOI_F1,
- NODE_NOISE_VORONOI_F2,
- NODE_NOISE_VORONOI_F3,
- NODE_NOISE_VORONOI_F4,
- NODE_NOISE_VORONOI_F2_F1,
- NODE_NOISE_VORONOI_CRACKLE,
- NODE_NOISE_CELL_NOISE
-} NodeNoiseBasis;
-
typedef enum NodeMusgraveType {
NODE_MUSGRAVE_MULTIFRACTAL,
NODE_MUSGRAVE_FBM,
@@ -347,6 +350,11 @@ typedef enum NodeBumpOffset {
NODE_BUMP_OFFSET_DY,
} NodeBumpOffset;
+typedef enum NodeTexVoxelSpace {
+ NODE_TEX_VOXEL_SPACE_OBJECT = 0,
+ NODE_TEX_VOXEL_SPACE_WORLD = 1,
+} NodeTexVoxelSpace;
+
typedef enum ShaderType {
SHADER_TYPE_SURFACE,
SHADER_TYPE_VOLUME,
@@ -426,6 +434,7 @@ typedef enum ClosureType {
#define CLOSURE_IS_BACKGROUND(type) (type == CLOSURE_BACKGROUND_ID)
#define CLOSURE_IS_AMBIENT_OCCLUSION(type) (type == CLOSURE_AMBIENT_OCCLUSION_ID)
#define CLOSURE_IS_PHASE(type) (type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
+#define CLOSURE_IS_GLASS(type) (type >= CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID && type <= CLOSURE_BSDF_SHARP_GLASS_ID)
#define CLOSURE_WEIGHT_CUTOFF 1e-5f
diff --git a/intern/cycles/kernel/svm/svm_vector_transform.h b/intern/cycles/kernel/svm/svm_vector_transform.h
index a16786f3ed3..4c32130d06d 100644
--- a/intern/cycles/kernel/svm/svm_vector_transform.h
+++ b/intern/cycles/kernel/svm/svm_vector_transform.h
@@ -33,7 +33,7 @@ ccl_device void svm_node_vector_transform(KernelGlobals *kg, ShaderData *sd, flo
NodeVectorTransformConvertSpace to = (NodeVectorTransformConvertSpace)ito;
Transform tfm;
- bool is_object = (sd->object != OBJECT_NONE);
+ bool is_object = (ccl_fetch(sd, object) != OBJECT_NONE);
bool is_direction = (type == NODE_VECTOR_TRANSFORM_TYPE_VECTOR || type == NODE_VECTOR_TRANSFORM_TYPE_NORMAL);
/* From world */
@@ -45,7 +45,7 @@ ccl_device void svm_node_vector_transform(KernelGlobals *kg, ShaderData *sd, flo
else
in = transform_point(&tfm, in);
}
- else if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT && is_object) {
+ else if(to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT && is_object) {
if(is_direction)
object_inverse_dir_transform(kg, sd, &in);
else
@@ -54,7 +54,7 @@ ccl_device void svm_node_vector_transform(KernelGlobals *kg, ShaderData *sd, flo
}
/* From camera */
- else if (from == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA) {
+ else if(from == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA) {
if(to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD || to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT) {
tfm = kernel_data.cam.cameratoworld;
if(is_direction)
diff --git a/intern/cycles/kernel/svm/svm_voronoi.h b/intern/cycles/kernel/svm/svm_voronoi.h
index 5a2e6e97dd3..d612d7e973f 100644
--- a/intern/cycles/kernel/svm/svm_voronoi.h
+++ b/intern/cycles/kernel/svm/svm_voronoi.h
@@ -18,6 +18,92 @@ CCL_NAMESPACE_BEGIN
/* Voronoi */
+ccl_device float voronoi_F1_distance(float3 p)
+{
+ /* returns squared distance in da */
+ float da = 1e10f;
+
+#ifndef __KERNEL_SSE2__
+ int ix = floor_to_int(p.x), iy = floor_to_int(p.y), iz = floor_to_int(p.z);
+
+ for(int xx = -1; xx <= 1; xx++) {
+ for(int yy = -1; yy <= 1; yy++) {
+ for(int zz = -1; zz <= 1; zz++) {
+ float3 ip = make_float3(ix + xx, iy + yy, iz + zz);
+ float3 vp = ip + cellnoise_color(ip);
+ float d = len_squared(p - vp);
+ da = min(d, da);
+ }
+ }
+ }
+#else
+ ssef vec_p = load4f(p);
+ ssei xyzi = quick_floor_sse(vec_p);
+
+ for(int xx = -1; xx <= 1; xx++) {
+ for(int yy = -1; yy <= 1; yy++) {
+ for(int zz = -1; zz <= 1; zz++) {
+ ssef ip = ssef(xyzi + ssei(xx, yy, zz, 0));
+ ssef vp = ip + cellnoise_color(ip);
+ float d = len_squared<1, 1, 1, 0>(vec_p - vp);
+ da = min(d, da);
+ }
+ }
+ }
+#endif
+
+ return da;
+}
+
+ccl_device float3 voronoi_F1_color(float3 p)
+{
+ /* returns color of the nearest point */
+ float da = 1e10f;
+
+#ifndef __KERNEL_SSE2__
+ float3 pa;
+ int ix = floor_to_int(p.x), iy = floor_to_int(p.y), iz = floor_to_int(p.z);
+
+ for(int xx = -1; xx <= 1; xx++) {
+ for(int yy = -1; yy <= 1; yy++) {
+ for(int zz = -1; zz <= 1; zz++) {
+ float3 ip = make_float3(ix + xx, iy + yy, iz + zz);
+ float3 vp = ip + cellnoise_color(ip);
+ float d = len_squared(p - vp);
+
+ if(d < da) {
+ da = d;
+ pa = vp;
+ }
+ }
+ }
+ }
+
+ return cellnoise_color(pa);
+#else
+ ssef pa, vec_p = load4f(p);
+ ssei xyzi = quick_floor_sse(vec_p);
+
+ for(int xx = -1; xx <= 1; xx++) {
+ for(int yy = -1; yy <= 1; yy++) {
+ for(int zz = -1; zz <= 1; zz++) {
+ ssef ip = ssef(xyzi + ssei(xx, yy, zz, 0));
+ ssef vp = ip + cellnoise_color(ip);
+ float d = len_squared<1, 1, 1, 0>(vec_p - vp);
+
+ if(d < da) {
+ da = d;
+ pa = vp;
+ }
+ }
+ }
+ }
+
+ ssef color = cellnoise_color(pa);
+ return (float3 &)color;
+#endif
+}
+
ccl_device_noinline float4 svm_voronoi(NodeVoronoiColoring coloring, float3 p)
{
if(coloring == NODE_VORONOI_INTENSITY) {
diff --git a/intern/cycles/kernel/svm/svm_voxel.h b/intern/cycles/kernel/svm/svm_voxel.h
new file mode 100644
index 00000000000..4838926503e
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_voxel.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011-2015 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.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device void svm_node_tex_voxel(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint4 node,
+ int *offset)
+{
+ int id = node.y;
+ uint co_offset, density_out_offset, color_out_offset, space;
+ decode_node_uchar4(node.z, &co_offset, &density_out_offset, &color_out_offset, &space);
+ float3 co = stack_load_float3(stack, co_offset);
+ if(space == NODE_TEX_VOXEL_SPACE_OBJECT) {
+ co = volume_normalized_position(kg, sd, co);
+ }
+ else {
+ kernel_assert(space == NODE_TEX_VOXEL_SPACE_WORLD);
+ Transform tfm;
+ tfm.x = read_node_float(kg, offset);
+ tfm.y = read_node_float(kg, offset);
+ tfm.z = read_node_float(kg, offset);
+ tfm.w = read_node_float(kg, offset);
+ co = transform_point(&tfm, co);
+ }
+ if(co.x < 0.0f || co.y < 0.0f || co.z < 0.0f ||
+ co.x > 1.0f || co.y > 1.0f || co.z > 1.0f)
+ {
+ if (stack_valid(density_out_offset))
+ stack_store_float(stack, density_out_offset, 0.0f);
+ if (stack_valid(color_out_offset))
+ stack_store_float3(stack, color_out_offset, make_float3(0.0f, 0.0f, 0.0f));
+ return;
+ }
+#ifdef __KERNEL_GPU__
+ float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+#else
+ float4 r = kernel_tex_image_interp_3d(id, co.x, co.y, co.z);
+#endif
+ if (stack_valid(density_out_offset))
+ stack_store_float(stack, density_out_offset, r.w);
+ if (stack_valid(color_out_offset))
+ stack_store_float3(stack, color_out_offset, make_float3(r.x, r.y, r.z));
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_wave.h b/intern/cycles/kernel/svm/svm_wave.h
index 36b59c3684c..6eaddaf301c 100644
--- a/intern/cycles/kernel/svm/svm_wave.h
+++ b/intern/cycles/kernel/svm/svm_wave.h
@@ -28,7 +28,7 @@ ccl_device_noinline float svm_wave(NodeWaveType type, float3 p, float detail, fl
n = len(p) * 20.0f;
if(distortion != 0.0f)
- n += distortion * noise_turbulence(p*dscale, NODE_NOISE_PERLIN, detail, 0);
+ n += distortion * noise_turbulence(p*dscale, detail, 0);
return 0.5f + 0.5f * sinf(n);
}
diff --git a/intern/cycles/kernel/svm/svm_wavelength.h b/intern/cycles/kernel/svm/svm_wavelength.h
index 9e57c470c0f..57030f3979d 100644
--- a/intern/cycles/kernel/svm/svm_wavelength.h
+++ b/intern/cycles/kernel/svm/svm_wavelength.h
@@ -77,7 +77,7 @@ ccl_device void svm_node_wavelength(ShaderData *sd, float *stack, uint wavelengt
int i = float_to_int(ii);
float3 color;
- if (i < 0 || i >= 80) {
+ if(i < 0 || i >= 80) {
color = make_float3(0.0f, 0.0f, 0.0f);
}
else {
diff --git a/intern/cycles/kernel/svm/svm_wireframe.h b/intern/cycles/kernel/svm/svm_wireframe.h
index 42fe3e8e429..30ccd523add 100644
--- a/intern/cycles/kernel/svm/svm_wireframe.h
+++ b/intern/cycles/kernel/svm/svm_wireframe.h
@@ -41,9 +41,9 @@ ccl_device float wireframe(KernelGlobals *kg,
float3 *P)
{
#ifdef __HAIR__
- if (sd->prim != PRIM_NONE && sd->type & PRIMITIVE_ALL_TRIANGLE)
+ if(ccl_fetch(sd, prim) != PRIM_NONE && ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE)
#else
- if (sd->prim != PRIM_NONE)
+ if(ccl_fetch(sd, prim) != PRIM_NONE)
#endif
{
float3 Co[3];
@@ -52,12 +52,12 @@ ccl_device float wireframe(KernelGlobals *kg,
/* Triangles */
int np = 3;
- if(sd->type & PRIMITIVE_TRIANGLE)
- triangle_vertices(kg, sd->prim, Co);
+ if(ccl_fetch(sd, type) & PRIMITIVE_TRIANGLE)
+ triangle_vertices(kg, ccl_fetch(sd, prim), Co);
else
- motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, Co);
+ motion_triangle_vertices(kg, ccl_fetch(sd, object), ccl_fetch(sd, prim), ccl_fetch(sd, time), Co);
- if(!(sd->flag & SD_TRANSFORM_APPLIED)) {
+ if(!(ccl_fetch(sd, flag) & SD_TRANSFORM_APPLIED)) {
object_position_transform(kg, sd, &Co[0]);
object_position_transform(kg, sd, &Co[1]);
object_position_transform(kg, sd, &Co[2]);
@@ -66,8 +66,8 @@ ccl_device float wireframe(KernelGlobals *kg,
if(pixel_size) {
// Project the derivatives of P to the viewing plane defined
// by I so we have a measure of how big is a pixel at this point
- float pixelwidth_x = len(sd->dP.dx - dot(sd->dP.dx, sd->I) * sd->I);
- float pixelwidth_y = len(sd->dP.dy - dot(sd->dP.dy, sd->I) * sd->I);
+ float pixelwidth_x = len(ccl_fetch(sd, dP).dx - dot(ccl_fetch(sd, dP).dx, ccl_fetch(sd, I)) * ccl_fetch(sd, I));
+ float pixelwidth_y = len(ccl_fetch(sd, dP).dy - dot(ccl_fetch(sd, dP).dy, ccl_fetch(sd, I)) * ccl_fetch(sd, I));
// Take the average of both axis' length
pixelwidth = (pixelwidth_x + pixelwidth_y) * 0.5f;
}
@@ -76,7 +76,7 @@ ccl_device float wireframe(KernelGlobals *kg,
// other half. And take the square for fast comparison
pixelwidth *= 0.5f * size;
pixelwidth *= pixelwidth;
- for (int i = 0; i < np; i++) {
+ for(int i = 0; i < np; i++) {
int i2 = i ? i - 1 : np - 1;
float3 dir = *P - Co[i];
float3 edge = Co[i] - Co[i2];
@@ -84,7 +84,7 @@ ccl_device float wireframe(KernelGlobals *kg,
// At this point dot(crs, crs) / dot(edge, edge) is
// the square of area / length(edge) == square of the
// distance to the edge.
- if (dot(crs, crs) < (dot(edge, edge) * pixelwidth))
+ if(dot(crs, crs) < (dot(edge, edge) * pixelwidth))
return 1.0f;
}
}
@@ -106,19 +106,30 @@ ccl_device void svm_node_wireframe(KernelGlobals *kg,
int pixel_size = (int)use_pixel_size;
/* Calculate wireframe */
- float f = wireframe(kg, sd, size, pixel_size, &sd->P);
+#ifdef __SPLIT_KERNEL__
+ /* TODO(sergey): This is because sd is actually a global space,
+ * which makes it difficult to re-use same wireframe() function.
+ *
+ * With OpenCL 2.0 it's possible to avoid this change, but for until
+ * then we'll be living with such an exception.
+ */
+ float3 P = ccl_fetch(sd, P);
+ float f = wireframe(kg, sd, size, pixel_size, &P);
+#else
+ float f = wireframe(kg, sd, size, pixel_size, &ccl_fetch(sd, P));
+#endif
/* TODO(sergey): Think of faster way to calculate derivatives. */
if(bump_offset == NODE_BUMP_OFFSET_DX) {
- float3 Px = sd->P - sd->dP.dx;
- f += (f - wireframe(kg, sd, size, pixel_size, &Px)) / len(sd->dP.dx);
+ float3 Px = ccl_fetch(sd, P) - ccl_fetch(sd, dP).dx;
+ f += (f - wireframe(kg, sd, size, pixel_size, &Px)) / len(ccl_fetch(sd, dP).dx);
}
- else if (bump_offset == NODE_BUMP_OFFSET_DY) {
- float3 Py = sd->P - sd->dP.dy;
- f += (f - wireframe(kg, sd, size, pixel_size, &Py)) / len(sd->dP.dy);
+ else if(bump_offset == NODE_BUMP_OFFSET_DY) {
+ float3 Py = ccl_fetch(sd, P) - ccl_fetch(sd, dP).dy;
+ f += (f - wireframe(kg, sd, size, pixel_size, &Py)) / len(ccl_fetch(sd, dP).dy);
}
- if (stack_valid(out_fac))
+ if(stack_valid(out_fac))
stack_store_float(stack, out_fac, f);
}
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt
index 2dc6962633d..4e8a1794813 100644
--- a/intern/cycles/render/CMakeLists.txt
+++ b/intern/cycles/render/CMakeLists.txt
@@ -18,7 +18,6 @@ set(SRC
attribute.cpp
background.cpp
bake.cpp
- blackbody.cpp
buffers.cpp
camera.cpp
film.cpp
@@ -47,7 +46,6 @@ set(SRC_HEADERS
attribute.h
bake.h
background.h
- blackbody.h
buffers.h
camera.h
film.h
diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp
index 656420f5dbc..6e94459da55 100644
--- a/intern/cycles/render/attribute.cpp
+++ b/intern/cycles/render/attribute.cpp
@@ -52,7 +52,7 @@ void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_)
void Attribute::reserve(int numverts, int numtris, int numsteps, int numcurves, int numkeys, bool resize)
{
- if (resize) {
+ if(resize) {
buffer.resize(buffer_size(numverts, numtris, numsteps, numcurves, numkeys), 0);
}
else {
diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h
index bbc6cf7f65f..b49f0ffe387 100644
--- a/intern/cycles/render/attribute.h
+++ b/intern/cycles/render/attribute.h
@@ -39,6 +39,7 @@ struct Transform;
struct VoxelAttribute {
ImageManager *manager;
int slot;
+ int from_alpha;
};
/* Attribute
diff --git a/intern/cycles/render/background.cpp b/intern/cycles/render/background.cpp
index f5e51f2e159..5fd7bd8f16f 100644
--- a/intern/cycles/render/background.cpp
+++ b/intern/cycles/render/background.cpp
@@ -93,7 +93,7 @@ void Background::device_update(Device *device, DeviceScene *dscene, Scene *scene
need_update = false;
}
-void Background::device_free(Device *device, DeviceScene *dscene)
+void Background::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
{
}
diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp
index 1e8c1ac8bc9..4bbac0f91d1 100644
--- a/intern/cycles/render/bake.cpp
+++ b/intern/cycles/render/bake.cpp
@@ -55,6 +55,11 @@ void BakeData::set(int i, int prim, float uv[2], float dudx, float dudy, float d
m_dvdy[i] = dvdy;
}
+void BakeData::set_null(int i)
+{
+ m_primitive[i] = -1;
+}
+
int BakeData::object()
{
return m_object;
@@ -221,7 +226,10 @@ bool BakeManager::bake(Device *device, DeviceScene *dscene, Scene *scene, Progre
return true;
}
-void BakeManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
+void BakeManager::device_update(Device * /*device*/,
+ DeviceScene * /*dscene*/,
+ Scene * /*scene*/,
+ Progress& progress)
{
if(!need_update)
return;
@@ -231,7 +239,7 @@ void BakeManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
need_update = false;
}
-void BakeManager::device_free(Device *device, DeviceScene *dscene)
+void BakeManager::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
{
}
diff --git a/intern/cycles/render/bake.h b/intern/cycles/render/bake.h
index 9ff10dafa0e..14d975a4b4e 100644
--- a/intern/cycles/render/bake.h
+++ b/intern/cycles/render/bake.h
@@ -31,6 +31,7 @@ public:
~BakeData();
void set(int i, int prim, float uv[2], float dudx, float dudy, float dvdx, float dvdy);
+ void set_null(int i);
int object();
size_t size();
uint4 data(int i);
diff --git a/intern/cycles/render/blackbody.cpp b/intern/cycles/render/blackbody.cpp
deleted file mode 100644
index 04e6eaf5373..00000000000
--- a/intern/cycles/render/blackbody.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Adapted from Open Shading Language with this license:
- *
- * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
- * All Rights Reserved.
- *
- * Modifications Copyright 2013, 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 Sony Pictures Imageworks 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 THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "blackbody.h"
-#include "util_color.h"
-#include "util_math.h"
-
-#include "kernel_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-vector<float> blackbody_table_build()
-{
- /* quoted from OSLs opcolor.cpp
- In order to speed up the blackbody computation, we have a table
- storing the precomputed BB values for a range of temperatures. Less
- than BB_DRAPER always returns 0. Greater than BB_MAX_TABLE_RANGE
- does the full computation, we think it'll be rare to inquire higher
- temperatures.
-
- Since the bb function is so nonlinear, we actually space the table
- entries nonlinearly, with the relationship between the table index i
- and the temperature T as follows:
- i = ((T-Draper)/spacing)^(1/xpower)
- T = pow(i, xpower) * spacing + Draper
- And furthermore, we store in the table the true value raised ^(1/5).
- I tuned this a bit, and with the current values we can have all
- blackbody results accurate to within 0.1% with a table size of 317
- (about 5 KB of data).
- */
-
- const float cie_colour_match[81][3] = {
- {0.0014f,0.0000f,0.0065f}, {0.0022f,0.0001f,0.0105f}, {0.0042f,0.0001f,0.0201f},
- {0.0076f,0.0002f,0.0362f}, {0.0143f,0.0004f,0.0679f}, {0.0232f,0.0006f,0.1102f},
- {0.0435f,0.0012f,0.2074f}, {0.0776f,0.0022f,0.3713f}, {0.1344f,0.0040f,0.6456f},
- {0.2148f,0.0073f,1.0391f}, {0.2839f,0.0116f,1.3856f}, {0.3285f,0.0168f,1.6230f},
- {0.3483f,0.0230f,1.7471f}, {0.3481f,0.0298f,1.7826f}, {0.3362f,0.0380f,1.7721f},
- {0.3187f,0.0480f,1.7441f}, {0.2908f,0.0600f,1.6692f}, {0.2511f,0.0739f,1.5281f},
- {0.1954f,0.0910f,1.2876f}, {0.1421f,0.1126f,1.0419f}, {0.0956f,0.1390f,0.8130f},
- {0.0580f,0.1693f,0.6162f}, {0.0320f,0.2080f,0.4652f}, {0.0147f,0.2586f,0.3533f},
- {0.0049f,0.3230f,0.2720f}, {0.0024f,0.4073f,0.2123f}, {0.0093f,0.5030f,0.1582f},
- {0.0291f,0.6082f,0.1117f}, {0.0633f,0.7100f,0.0782f}, {0.1096f,0.7932f,0.0573f},
- {0.1655f,0.8620f,0.0422f}, {0.2257f,0.9149f,0.0298f}, {0.2904f,0.9540f,0.0203f},
- {0.3597f,0.9803f,0.0134f}, {0.4334f,0.9950f,0.0087f}, {0.5121f,1.0000f,0.0057f},
- {0.5945f,0.9950f,0.0039f}, {0.6784f,0.9786f,0.0027f}, {0.7621f,0.9520f,0.0021f},
- {0.8425f,0.9154f,0.0018f}, {0.9163f,0.8700f,0.0017f}, {0.9786f,0.8163f,0.0014f},
- {1.0263f,0.7570f,0.0011f}, {1.0567f,0.6949f,0.0010f}, {1.0622f,0.6310f,0.0008f},
- {1.0456f,0.5668f,0.0006f}, {1.0026f,0.5030f,0.0003f}, {0.9384f,0.4412f,0.0002f},
- {0.8544f,0.3810f,0.0002f}, {0.7514f,0.3210f,0.0001f}, {0.6424f,0.2650f,0.0000f},
- {0.5419f,0.2170f,0.0000f}, {0.4479f,0.1750f,0.0000f}, {0.3608f,0.1382f,0.0000f},
- {0.2835f,0.1070f,0.0000f}, {0.2187f,0.0816f,0.0000f}, {0.1649f,0.0610f,0.0000f},
- {0.1212f,0.0446f,0.0000f}, {0.0874f,0.0320f,0.0000f}, {0.0636f,0.0232f,0.0000f},
- {0.0468f,0.0170f,0.0000f}, {0.0329f,0.0119f,0.0000f}, {0.0227f,0.0082f,0.0000f},
- {0.0158f,0.0057f,0.0000f}, {0.0114f,0.0041f,0.0000f}, {0.0081f,0.0029f,0.0000f},
- {0.0058f,0.0021f,0.0000f}, {0.0041f,0.0015f,0.0000f}, {0.0029f,0.0010f,0.0000f},
- {0.0020f,0.0007f,0.0000f}, {0.0014f,0.0005f,0.0000f}, {0.0010f,0.0004f,0.0000f},
- {0.0007f,0.0002f,0.0000f}, {0.0005f,0.0002f,0.0000f}, {0.0003f,0.0001f,0.0000f},
- {0.0002f,0.0001f,0.0000f}, {0.0002f,0.0001f,0.0000f}, {0.0001f,0.0000f,0.0000f},
- {0.0001f,0.0000f,0.0000f}, {0.0001f,0.0000f,0.0000f}, {0.0000f,0.0000f,0.0000f}
- };
-
- const double c1 = 3.74183e-16; // 2*pi*h*c^2, W*m^2
- const double c2 = 1.4388e-2; // h*c/k, m*K
- // h is Planck's const, k is Boltzmann's
- const float dlambda = 5.0f * 1e-9f; // in meters
-
- /* Blackbody table from 800 to 12k Kelvin (319 entries (317+2 offset) * 3) */
- vector<float> blackbody_table(956);
-
- float X, Y, Z;
-
- /* ToDo: bring this back to what OSL does with the lastTemperature limit ? */
- for (int i = 0; i <= 317; ++i) {
- double Temperature = pow((double)i, (double)BB_TABLE_XPOWER) * (double)BB_TABLE_SPACING + (double)BB_DRAPER;
- X = 0;
- Y = 0;
- Z = 0;
-
- /* from OSL "spectrum_to_XYZ" */
- for (int n = 0; n < 81; ++n) {
- float lambda = 380.0f + 5.0f * n;
- double wlm = lambda * 1e-9f; // Wavelength in meters
- // N.B. spec_intens returns result in W/m^2 but it's a differential,
- // needs to be scaled by dlambda!
- float spec_intens = float((c1 * pow(wlm, -5.0)) / (exp(c2 / (wlm * Temperature)) -1.0));
- float Me = spec_intens * dlambda;
-
- X += Me * cie_colour_match[n][0];
- Y += Me * cie_colour_match[n][1];
- Z += Me * cie_colour_match[n][2];
- }
-
- /* Convert from xyz color space */
- float3 col = xyz_to_rgb(X, Y, Z);
-
- /* Clamp to zero if values are smaller */
- col = max(col, make_float3(0.0f, 0.0f, 0.0f));
-
- col.x = powf(col.x, 1.0f / BB_TABLE_YPOWER);
- col.y = powf(col.y, 1.0f / BB_TABLE_YPOWER);
- col.z = powf(col.z, 1.0f / BB_TABLE_YPOWER);
-
- /* Store in table in RRRGGGBBB format */
- blackbody_table[i] = col.x;
- blackbody_table[i+319*1] = col.y;
- blackbody_table[i+319*2] = col.z;
- }
-
- return blackbody_table;
-}
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp
index 5202bf5862c..011c722c000 100644
--- a/intern/cycles/render/buffers.cpp
+++ b/intern/cycles/render/buffers.cpp
@@ -187,7 +187,7 @@ bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int
else if(type == PASS_MIST) {
for(int i = 0; i < size; i++, in += pass_stride, pixels++) {
float f = *in;
- pixels[0] = clamp(f*scale_exposure, 0.0f, 1.0f);
+ pixels[0] = saturate(f*scale_exposure);
}
}
#ifdef WITH_CYCLES_DEBUG
@@ -298,7 +298,7 @@ bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int
pixels[2] = f.z*scale_exposure;
/* clamp since alpha might be > 1.0 due to russian roulette */
- pixels[3] = clamp(f.w*scale, 0.0f, 1.0f);
+ pixels[3] = saturate(f.w*scale);
}
}
}
@@ -369,13 +369,9 @@ void DisplayBuffer::draw_set(int width, int height)
void DisplayBuffer::draw(Device *device, const DeviceDrawParams& draw_params)
{
if(draw_width != 0 && draw_height != 0) {
- glPushMatrix();
- glTranslatef(params.full_x, params.full_y, 0.0f);
device_memory& rgba = rgba_data();
- device->draw_pixels(rgba, 0, draw_width, draw_height, 0, params.width, params.height, transparent, draw_params);
-
- glPopMatrix();
+ device->draw_pixels(rgba, 0, draw_width, draw_height, params.full_x, params.full_y, params.width, params.height, transparent, draw_params);
}
}
diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp
index ea9b853d454..89505221862 100644
--- a/intern/cycles/render/camera.cpp
+++ b/intern/cycles/render/camera.cpp
@@ -80,6 +80,7 @@ Camera::Camera()
need_update = true;
need_device_update = true;
+ need_flags_update = true;
previous_need_motion = -1;
}
@@ -162,8 +163,8 @@ void Camera::update()
transform_perspective(&rastertocamera, make_float3(0, 0, 0));
}
else {
- dx = make_float3(0, 0, 0);
- dy = make_float3(0, 0, 0);
+ dx = make_float3(0.0f, 0.0f, 0.0f);
+ dy = make_float3(0.0f, 0.0f, 0.0f);
}
dx = transform_direction(&cameratoworld, dx);
@@ -171,6 +172,7 @@ void Camera::update()
need_update = false;
need_device_update = true;
+ need_flags_update = true;
}
void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene)
@@ -179,7 +181,7 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene)
update();
- if (previous_need_motion != need_motion) {
+ if(previous_need_motion != need_motion) {
/* scene's motion model could have been changed since previous device
* camera update this could happen for example in case when one render
* layer has got motion pass and another not */
@@ -284,11 +286,11 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene)
previous_need_motion = need_motion;
}
-void Camera::device_update_volume(Device *device,
+void Camera::device_update_volume(Device * /*device*/,
DeviceScene *dscene,
Scene *scene)
{
- if(!need_device_update) {
+ if(!need_device_update && !need_flags_update) {
return;
}
KernelCamera *kcam = &dscene->data.cam;
@@ -304,9 +306,10 @@ void Camera::device_update_volume(Device *device,
}
}
need_device_update = false;
+ need_flags_update = false;
}
-void Camera::device_free(Device *device, DeviceScene *dscene)
+void Camera::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
{
/* nothing to free, only writing to constant memory */
}
@@ -368,7 +371,7 @@ float3 Camera::transform_raster_to_world(float raster_x, float raster_y)
*/
P += nearclip * D / Pclip.z;
}
- else if (type == CAMERA_ORTHOGRAPHIC) {
+ else if(type == CAMERA_ORTHOGRAPHIC) {
D = make_float3(0.0f, 0.0f, 1.0f);
/* TODO(sergey): Aperture support? */
P = transform_perspective(&rastertocamera,
@@ -400,7 +403,7 @@ BoundBox Camera::viewplane_bounds_get()
bounds.grow(transform_raster_to_world((float)width, (float)height));
bounds.grow(transform_raster_to_world((float)width, 0.0f));
if(type == CAMERA_PERSPECTIVE) {
- /* Center point has the most distancei in local Z axis,
+ /* Center point has the most distance in local Z axis,
* use it to construct bounding box/
*/
bounds.grow(transform_raster_to_world(0.5f*width, 0.5f*height));
@@ -409,15 +412,4 @@ BoundBox Camera::viewplane_bounds_get()
return bounds;
}
-Transform Camera::transform_from_viewplane(BoundBox2D &viewplane)
-{
- return
- transform_scale(1.0f / (viewplane.right - viewplane.left),
- 1.0f / (viewplane.top - viewplane.bottom),
- 1.0f) *
- transform_translate(-viewplane.left,
- -viewplane.bottom,
- 0.0f);
-}
-
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h
index e1faee3543d..3efbe904e2f 100644
--- a/intern/cycles/render/camera.h
+++ b/intern/cycles/render/camera.h
@@ -105,6 +105,7 @@ public:
/* update */
bool need_update;
bool need_device_update;
+ bool need_flags_update;
int previous_need_motion;
/* functions */
@@ -123,9 +124,12 @@ public:
bool motion_modified(const Camera& cam);
void tag_update();
+ /* Public utility functions. */
BoundBox viewplane_bounds_get();
+
+private:
+ /* Private utility functions. */
float3 transform_raster_to_world(float raster_x, float raster_y);
- Transform transform_from_viewplane(BoundBox2D &viewplane);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/curves.cpp b/intern/cycles/render/curves.cpp
index 80dc6434cde..f671eb19cae 100644
--- a/intern/cycles/render/curves.cpp
+++ b/intern/cycles/render/curves.cpp
@@ -103,7 +103,10 @@ CurveSystemManager::~CurveSystemManager()
{
}
-void CurveSystemManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
+void CurveSystemManager::device_update(Device *device,
+ DeviceScene *dscene,
+ Scene * /*scene*/,
+ Progress& progress)
{
if(!need_update)
return;
@@ -144,7 +147,8 @@ void CurveSystemManager::device_update(Device *device, DeviceScene *dscene, Scen
need_update = false;
}
-void CurveSystemManager::device_free(Device *device, DeviceScene *dscene)
+void CurveSystemManager::device_free(Device * /*device*/,
+ DeviceScene * /*dscene*/)
{
}
@@ -174,7 +178,7 @@ bool CurveSystemManager::modified_mesh(const CurveSystemManager& CurveSystemMana
use_curves == CurveSystemManager.use_curves);
}
-void CurveSystemManager::tag_update(Scene *scene)
+void CurveSystemManager::tag_update(Scene * /*scene*/)
{
need_update = true;
}
diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp
index c6d12928dd4..b23678dea44 100644
--- a/intern/cycles/render/film.cpp
+++ b/intern/cycles/render/film.cpp
@@ -187,7 +187,7 @@ bool Pass::contains(const vector<Pass>& passes, PassType type)
/* Pixel Filter */
-static float filter_func_box(float v, float width)
+static float filter_func_box(float /*v*/, float /*width*/)
{
return 1.0f;
}
@@ -424,7 +424,9 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
need_update = false;
}
-void Film::device_free(Device *device, DeviceScene *dscene, Scene *scene)
+void Film::device_free(Device * /*device*/,
+ DeviceScene * /*dscene*/,
+ Scene *scene)
{
if(filter_table_offset != TABLE_OFFSET_INVALID) {
scene->lookup_tables->remove_table(filter_table_offset);
@@ -459,7 +461,7 @@ void Film::tag_passes_update(Scene *scene, const vector<Pass>& passes_)
passes = passes_;
}
-void Film::tag_update(Scene *scene)
+void Film::tag_update(Scene * /*scene*/)
{
need_update = true;
}
diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp
index 9896eaba89b..9adf6b4b1ed 100644
--- a/intern/cycles/render/graph.cpp
+++ b/intern/cycles/render/graph.cpp
@@ -33,7 +33,7 @@ ShaderInput::ShaderInput(ShaderNode *parent_, const char *name_, ShaderSocketTyp
name = name_;
type = type_;
link = NULL;
- value = make_float3(0, 0, 0);
+ value = make_float3(0.0f, 0.0f, 0.0f);
stack_offset = SVM_STACK_INVALID;
default_value = NONE;
usage = USE_ALL;
@@ -404,6 +404,21 @@ void ShaderGraph::remove_unneeded_nodes()
}
}
}
+ else if(node->special_type == SHADER_SPECIAL_TYPE_EMISSION) {
+ EmissionNode *em = static_cast<EmissionNode*>(node);
+
+ if(em->outputs[0]->links.size()) {
+ /* Black color or zero strength, remove node */
+ if((!em->inputs[0]->link && em->inputs[0]->value == make_float3(0.0f, 0.0f, 0.0f)) ||
+ (!em->inputs[1]->link && em->inputs[1]->value.x == 0.0f)) {
+ vector<ShaderInput*> inputs = em->outputs[0]->links;
+
+ relink(em->inputs, inputs, NULL);
+ removed[em->id] = true;
+ any_node_removed = true;
+ }
+ }
+ }
else if(node->special_type == SHADER_SPECIAL_TYPE_MIX_CLOSURE) {
MixClosureNode *mix = static_cast<MixClosureNode*>(node);
@@ -727,10 +742,18 @@ void ShaderGraph::bump_from_displacement()
/* connect bump output to normal input nodes that aren't set yet. actually
* this will only set the normal input to the geometry node that we created
* and connected to all other normal inputs already. */
- foreach(ShaderNode *node, nodes)
- foreach(ShaderInput *input, node->inputs)
+ foreach(ShaderNode *node, nodes) {
+ /* Don't connect normal to the bump node we're coming from,
+ * otherwise it'll be a cycle in graph.
+ */
+ if(node == bump) {
+ continue;
+ }
+ foreach(ShaderInput *input, node->inputs) {
if(!input->link && input->default_value == ShaderInput::NORMAL)
connect(set_normal->output("Normal"), input);
+ }
+ }
/* for displacement bump, clear the normal input in case the above loop
* connected the setnormal out to the bump normalin */
@@ -825,6 +848,26 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
}
}
+int ShaderGraph::get_num_closures()
+{
+ int num_closures = 0;
+ foreach(ShaderNode *node, nodes) {
+ if(node->special_type == SHADER_SPECIAL_TYPE_CLOSURE) {
+ BsdfNode *bsdf_node = static_cast<BsdfNode*>(node);
+ /* TODO(sergey): Make it more generic approach, maybe some utility
+ * macros like CLOSURE_IS_FOO()?
+ */
+ if(CLOSURE_IS_BSSRDF(bsdf_node->closure))
+ num_closures = num_closures + 3;
+ else if(CLOSURE_IS_GLASS(bsdf_node->closure))
+ num_closures = num_closures + 2;
+ else
+ num_closures = num_closures + 1;
+ }
+ }
+ return num_closures;
+}
+
void ShaderGraph::dump_graph(const char *filename)
{
FILE *fd = fopen(filename, "w");
@@ -836,29 +879,59 @@ void ShaderGraph::dump_graph(const char *filename)
fprintf(fd, "digraph shader_graph {\n");
fprintf(fd, "ranksep=1.5\n");
+ fprintf(fd, "rankdir=LR\n");
fprintf(fd, "splines=false\n");
foreach(ShaderNode *node, nodes) {
fprintf(fd, "// NODE: %p\n", node);
- fprintf(fd,
- "\"%p\" [shape=record,label=\"%s\"]\n",
- node,
- node->name.c_str());
+ fprintf(fd, "\"%p\" [shape=record,label=\"{", node);
+ if(node->inputs.size()) {
+ fprintf(fd, "{");
+ foreach(ShaderInput *socket, node->inputs) {
+ if(socket != node->inputs[0]) {
+ fprintf(fd, "|");
+ }
+ fprintf(fd, "<IN_%p>%s", socket, socket->name);
+ }
+ fprintf(fd, "}|");
+ }
+ fprintf(fd, "%s", node->name.c_str());
+ if(node->bump == SHADER_BUMP_CENTER) {
+ fprintf(fd, " (bump:center)");
+ }
+ else if(node->bump == SHADER_BUMP_DX) {
+ fprintf(fd, " (bump:dx)");
+ }
+ else if(node->bump == SHADER_BUMP_DY) {
+ fprintf(fd, " (bump:dy)");
+ }
+ if(node->outputs.size()) {
+ fprintf(fd, "|{");
+ foreach(ShaderOutput *socket, node->outputs) {
+ if(socket != node->outputs[0]) {
+ fprintf(fd, "|");
+ }
+ fprintf(fd, "<OUT_%p>%s", socket, socket->name);
+ }
+ fprintf(fd, "}");
+ }
+ fprintf(fd, "}\"]");
}
foreach(ShaderNode *node, nodes) {
foreach(ShaderOutput *output, node->outputs) {
foreach(ShaderInput *input, output->links) {
fprintf(fd,
- "// CONNECTION: %p->%p (%s:%s)\n",
+ "// CONNECTION: OUT_%p->IN_%p (%s:%s)\n",
output,
input,
output->name, input->name);
fprintf(fd,
- "\"%p\":s -> \"%p\":n [label=\"%s:%s\"]\n",
+ "\"%p\":\"OUT_%p\":e -> \"%p\":\"IN_%p\":w [label=\"\"]\n",
output->parent,
+ output,
input->parent,
- output->name, input->name);
+ input);
}
}
}
diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h
index b39b3dae324..93341b56d99 100644
--- a/intern/cycles/render/graph.h
+++ b/intern/cycles/render/graph.h
@@ -81,6 +81,9 @@ enum ShaderNodeSpecialType {
SHADER_SPECIAL_TYPE_GEOMETRY,
SHADER_SPECIAL_TYPE_SCRIPT,
SHADER_SPECIAL_TYPE_BACKGROUND,
+ SHADER_SPECIAL_TYPE_IMAGE_SLOT,
+ SHADER_SPECIAL_TYPE_CLOSURE,
+ SHADER_SPECIAL_TYPE_EMISSION,
};
/* Enum
@@ -193,7 +196,6 @@ public:
virtual bool has_surface_emission() { return false; }
virtual bool has_surface_transparent() { return false; }
virtual bool has_surface_bssrdf() { return false; }
- virtual bool has_converter_blackbody() { return false; }
virtual bool has_bssrdf_bump() { return false; }
virtual bool has_spatial_varying() { return false; }
virtual bool has_object_dependency() { return false; }
@@ -206,6 +208,24 @@ public:
ShaderBump bump; /* for bump mapping utility */
ShaderNodeSpecialType special_type; /* special node type */
+
+ /* ** Selective nodes compilation ** */
+
+ /* TODO(sergey): More explicitly mention in the function names
+ * that those functions are for selective compilation only?
+ */
+
+ /* Nodes are split into several groups, group of level 0 contains
+ * nodes which are most commonly used, further levels are extension
+ * of previous one and includes less commonly used nodes.
+ */
+ virtual int get_group() { return NODE_GROUP_LEVEL_0; }
+
+ /* Node feature are used to disable huge nodes inside the group,
+ * so it's possible to disable huge nodes inside of the required
+ * nodes group.
+ */
+ virtual int get_feature() { return bump == SHADER_BUMP_NONE ? 0 : NODE_FEATURE_BUMP; }
};
@@ -253,6 +273,8 @@ public:
void remove_unneeded_nodes();
void finalize(bool do_bump = false, bool do_osl = false);
+ int get_num_closures();
+
void dump_graph(const char *filename);
protected:
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index 61a0a81d51d..c62afcd7719 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -407,7 +407,7 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
int scanlinesize = width*components*sizeof(uchar);
in->read_image(TypeDesc::UINT8,
- (uchar*)pixels + (height-1)*scanlinesize,
+ (uchar*)pixels + (((size_t)height)-1)*scanlinesize,
AutoStride,
-scanlinesize,
AutoStride);
@@ -425,9 +425,10 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
builtin_image_pixels_cb(img->filename, img->builtin_data, pixels);
}
+ size_t num_pixels = ((size_t)width) * height * depth;
if(cmyk) {
/* CMYK */
- for(int i = width*height*depth-1; i >= 0; i--) {
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i*4+2] = (pixels[i*4+2]*pixels[i*4+3])/255;
pixels[i*4+1] = (pixels[i*4+1]*pixels[i*4+3])/255;
pixels[i*4+0] = (pixels[i*4+0]*pixels[i*4+3])/255;
@@ -436,7 +437,7 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
}
else if(components == 2) {
/* grayscale + alpha */
- for(int i = width*height*depth-1; i >= 0; i--) {
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i*4+3] = pixels[i*2+1];
pixels[i*4+2] = pixels[i*2+0];
pixels[i*4+1] = pixels[i*2+0];
@@ -445,7 +446,7 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
}
else if(components == 3) {
/* RGB */
- for(int i = width*height*depth-1; i >= 0; i--) {
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i*4+3] = 255;
pixels[i*4+2] = pixels[i*3+2];
pixels[i*4+1] = pixels[i*3+1];
@@ -454,7 +455,7 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
}
else if(components == 1) {
/* grayscale */
- for(int i = width*height*depth-1; i >= 0; i--) {
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i*4+3] = 255;
pixels[i*4+2] = pixels[i];
pixels[i*4+1] = pixels[i];
@@ -463,7 +464,7 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
}
if(img->use_alpha == false) {
- for(int i = width*height*depth-1; i >= 0; i--) {
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i*4+3] = 255;
}
}
@@ -529,7 +530,7 @@ bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_
vector<float> tmppixels;
if(components > 4) {
- tmppixels.resize(width*height*components);
+ tmppixels.resize(((size_t)width)*height*components);
readpixels = &tmppixels[0];
}
@@ -547,7 +548,8 @@ bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_
}
if(components > 4) {
- for(int i = width*height-1; i >= 0; i--) {
+ size_t dimensions = ((size_t)width)*height;
+ for(size_t i = dimensions-1, pixel = 0; pixel < dimensions; pixel++, i--) {
pixels[i*4+3] = tmppixels[i*components+3];
pixels[i*4+2] = tmppixels[i*components+2];
pixels[i*4+1] = tmppixels[i*components+1];
@@ -566,9 +568,10 @@ bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_
builtin_image_float_pixels_cb(img->filename, img->builtin_data, pixels);
}
+ size_t num_pixels = ((size_t)width) * height * depth;
if(cmyk) {
/* CMYK */
- for(int i = width*height*depth-1; i >= 0; i--) {
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i*4+3] = 255;
pixels[i*4+2] = (pixels[i*4+2]*pixels[i*4+3])/255;
pixels[i*4+1] = (pixels[i*4+1]*pixels[i*4+3])/255;
@@ -577,7 +580,7 @@ bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_
}
else if(components == 2) {
/* grayscale + alpha */
- for(int i = width*height*depth-1; i >= 0; i--) {
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i*4+3] = pixels[i*2+1];
pixels[i*4+2] = pixels[i*2+0];
pixels[i*4+1] = pixels[i*2+0];
@@ -586,7 +589,7 @@ bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_
}
else if(components == 3) {
/* RGB */
- for(int i = width*height*depth-1; i >= 0; i--) {
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i*4+3] = 1.0f;
pixels[i*4+2] = pixels[i*3+2];
pixels[i*4+1] = pixels[i*3+1];
@@ -595,7 +598,7 @@ bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_
}
else if(components == 1) {
/* grayscale */
- for(int i = width*height*depth-1; i >= 0; i--) {
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i*4+3] = 1.0f;
pixels[i*4+2] = pixels[i];
pixels[i*4+1] = pixels[i];
@@ -604,7 +607,7 @@ bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_
}
if(img->use_alpha == false) {
- for(int i = width*height*depth-1; i >= 0; i--) {
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
pixels[i*4+3] = 1.0f;
}
}
@@ -791,7 +794,36 @@ void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress&
need_update = false;
}
-void ImageManager::device_pack_images(Device *device, DeviceScene *dscene, Progress& progess)
+void ImageManager::device_update_slot(Device *device,
+ DeviceScene *dscene,
+ int slot,
+ Progress *progress)
+{
+ Image *image;
+ if(slot >= tex_image_byte_start) {
+ int byte_slot = slot - tex_image_byte_start;
+ assert(images[byte_slot] != NULL);
+ image = images[byte_slot];
+ }
+ else {
+ assert(float_images[slot] != NULL);
+ image = float_images[slot];
+ }
+ if(image->users == 0) {
+ device_free_image(device, dscene, slot);
+ }
+ else if(image->need_load) {
+ if(!osl_texture_system || float_images[slot]->builtin_data)
+ device_load_image(device,
+ dscene,
+ slot,
+ progress);
+ }
+}
+
+void ImageManager::device_pack_images(Device *device,
+ DeviceScene *dscene,
+ Progress& /*progess*/)
{
/* for OpenCL, we pack all image textures inside a single big texture, and
* will do our own interpolation in the kernel */
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
index 2f5dcb6efd5..70cc4935daa 100644
--- a/intern/cycles/render/image.h
+++ b/intern/cycles/render/image.h
@@ -63,6 +63,7 @@ public:
bool is_float_image(const string& filename, void *builtin_data, bool& is_linear);
void device_update(Device *device, DeviceScene *dscene, Progress& progress);
+ void device_update_slot(Device *device, DeviceScene *dscene, int slot, Progress *progress);
void device_free(Device *device, DeviceScene *dscene);
void device_free_builtin(Device *device, DeviceScene *dscene);
@@ -73,9 +74,9 @@ public:
bool need_update;
- boost::function<void(const string &filename, void *data, bool &is_float, int &width, int &height, int &depth, int &channels)> builtin_image_info_cb;
- boost::function<bool(const string &filename, void *data, unsigned char *pixels)> builtin_image_pixels_cb;
- boost::function<bool(const string &filename, void *data, float *pixels)> builtin_image_float_pixels_cb;
+ function<void(const string &filename, void *data, bool &is_float, int &width, int &height, int &depth, int &channels)> builtin_image_info_cb;
+ function<bool(const string &filename, void *data, unsigned char *pixels)> builtin_image_pixels_cb;
+ function<bool(const string &filename, void *data, float *pixels)> builtin_image_float_pixels_cb;
struct Image {
string filename;
diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp
index 17c50ca826f..465d7ea02c6 100644
--- a/intern/cycles/render/integrator.cpp
+++ b/intern/cycles/render/integrator.cpp
@@ -216,7 +216,7 @@ bool Integrator::modified(const Integrator& integrator)
sample_all_lights_indirect == integrator.sample_all_lights_indirect);
}
-void Integrator::tag_update(Scene *scene)
+void Integrator::tag_update(Scene * /*scene*/)
{
need_update = true;
}
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index 284012ecd63..1b7aa0ef52e 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -26,6 +26,7 @@
#include "util_foreach.h"
#include "util_progress.h"
+#include "util_logging.h"
CCL_NAMESPACE_BEGIN
@@ -128,6 +129,8 @@ Light::Light()
shader = 0;
samples = 1;
max_bounces = 1024;
+
+ is_portal = false;
}
void Light::tag_update(Scene *scene)
@@ -152,10 +155,17 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
progress.set_status("Updating Lights", "Computing distribution");
/* count */
- size_t num_lights = scene->lights.size();
+ size_t num_lights = 0;
size_t num_background_lights = 0;
size_t num_triangles = 0;
+ bool background_mis = false;
+
+ foreach(Light *light, scene->lights) {
+ if(!light->is_portal)
+ num_lights++;
+ }
+
foreach(Object *object, scene->objects) {
Mesh *mesh = object->mesh;
bool have_emission = false;
@@ -286,22 +296,29 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
float trianglearea = totarea;
/* point lights */
- float lightarea = (totarea > 0.0f)? totarea/scene->lights.size(): 1.0f;
+ float lightarea = (totarea > 0.0f) ? totarea / num_lights : 1.0f;
bool use_lamp_mis = false;
- for(int i = 0; i < scene->lights.size(); i++, offset++) {
- Light *light = scene->lights[i];
+ int light_index = 0;
+ foreach(Light *light, scene->lights) {
+ if(light->is_portal)
+ continue;
distribution[offset].x = totarea;
- distribution[offset].y = __int_as_float(~(int)i);
+ distribution[offset].y = __int_as_float(~light_index);
distribution[offset].z = 1.0f;
distribution[offset].w = light->size;
totarea += lightarea;
if(light->size > 0.0f && light->use_mis)
use_lamp_mis = true;
- if(light->type == LIGHT_BACKGROUND)
+ if(light->type == LIGHT_BACKGROUND) {
num_background_lights++;
+ background_mis = light->use_mis;
+ }
+
+ light_index++;
+ offset++;
}
/* normalize cumulative distribution functions */
@@ -363,6 +380,18 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
/* CDF */
device->tex_alloc("__light_distribution", dscene->light_distribution);
+
+ /* Portals */
+ if(num_background_lights > 0 && light_index != scene->lights.size()) {
+ kintegrator->portal_offset = light_index;
+ kintegrator->num_portals = scene->lights.size() - light_index;
+ kintegrator->portal_pdf = background_mis? 0.5f: 1.0f;
+ }
+ else {
+ kintegrator->num_portals = 0;
+ kintegrator->portal_offset = 0;
+ kintegrator->portal_pdf = 0.0f;
+ }
}
else {
dscene->light_distribution.clear();
@@ -373,10 +402,53 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
kintegrator->pdf_lights = 0.0f;
kintegrator->inv_pdf_lights = 0.0f;
kintegrator->use_lamp_mis = false;
+ kintegrator->num_portals = 0;
+ kintegrator->portal_offset = 0;
+ kintegrator->portal_pdf = 0.0f;
+
kfilm->pass_shadow_scale = 1.0f;
}
}
+static void background_cdf(int start,
+ int end,
+ int res,
+ int cdf_count,
+ const vector<float3> *pixels,
+ float2 *cond_cdf)
+{
+ /* Conditional CDFs (rows, U direction). */
+ for(int i = start; i < end; i++) {
+ float sin_theta = sinf(M_PI_F * (i + 0.5f) / res);
+ float3 env_color = (*pixels)[i * res];
+ float ave_luminamce = average(env_color);
+
+ cond_cdf[i * cdf_count].x = ave_luminamce * sin_theta;
+ cond_cdf[i * cdf_count].y = 0.0f;
+
+ for(int j = 1; j < res; j++) {
+ env_color = (*pixels)[i * res + j];
+ ave_luminamce = average(env_color);
+
+ cond_cdf[i * cdf_count + j].x = ave_luminamce * sin_theta;
+ cond_cdf[i * cdf_count + j].y = cond_cdf[i * cdf_count + j - 1].y + cond_cdf[i * cdf_count + j - 1].x / res;
+ }
+
+ float cdf_total = cond_cdf[i * cdf_count + res - 1].y + cond_cdf[i * cdf_count + res - 1].x / res;
+ float cdf_total_inv = 1.0f / cdf_total;
+
+ /* stuff the total into the brightness value for the last entry, because
+ * we are going to normalize the CDFs to 0.0 to 1.0 afterwards */
+ cond_cdf[i * cdf_count + res].x = cdf_total;
+
+ if(cdf_total > 0.0f)
+ for(int j = 1; j < res; j++)
+ cond_cdf[i * cdf_count + j].y *= cdf_total_inv;
+
+ cond_cdf[i * cdf_count + res].y = 1.0f;
+ }
+}
+
void LightManager::device_update_background(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
KernelIntegrator *kintegrator = &dscene->data.integrator;
@@ -417,34 +489,30 @@ void LightManager::device_update_background(Device *device, DeviceScene *dscene,
float2 *marg_cdf = dscene->light_background_marginal_cdf.resize(cdf_count);
float2 *cond_cdf = dscene->light_background_conditional_cdf.resize(cdf_count * cdf_count);
- /* conditional CDFs (rows, U direction) */
- for(int i = 0; i < res; i++) {
- float sin_theta = sinf(M_PI_F * (i + 0.5f) / res);
- float3 env_color = pixels[i * res];
- float ave_luminamce = average(env_color);
-
- cond_cdf[i * cdf_count].x = ave_luminamce * sin_theta;
- cond_cdf[i * cdf_count].y = 0.0f;
-
- for(int j = 1; j < res; j++) {
- env_color = pixels[i * res + j];
- ave_luminamce = average(env_color);
-
- cond_cdf[i * cdf_count + j].x = ave_luminamce * sin_theta;
- cond_cdf[i * cdf_count + j].y = cond_cdf[i * cdf_count + j - 1].y + cond_cdf[i * cdf_count + j - 1].x / res;
+ double time_start = time_dt();
+ if(res < 512) {
+ /* Small enough resolution, faster to do single-threaded. */
+ background_cdf(0, res, res, cdf_count, &pixels, cond_cdf);
+ }
+ else {
+ /* Threaded evaluation for large resolution. */
+ const int num_blocks = TaskScheduler::num_threads();
+ const int chunk_size = res / num_blocks;
+ int start_row = 0;
+ TaskPool pool;
+ for(int i = 0; i < num_blocks; ++i) {
+ const int current_chunk_size =
+ (i != num_blocks - 1) ? chunk_size
+ : (res - i * chunk_size);
+ pool.push(function_bind(&background_cdf,
+ start_row, start_row + current_chunk_size,
+ res,
+ cdf_count,
+ &pixels,
+ cond_cdf));
+ start_row += current_chunk_size;
}
-
- float cdf_total = cond_cdf[i * cdf_count + res - 1].y + cond_cdf[i * cdf_count + res - 1].x / res;
-
- /* stuff the total into the brightness value for the last entry, because
- * we are going to normalize the CDFs to 0.0 to 1.0 afterwards */
- cond_cdf[i * cdf_count + res].x = cdf_total;
-
- if(cdf_total > 0.0f)
- for(int j = 1; j < res; j++)
- cond_cdf[i * cdf_count + j].y /= cdf_total;
-
- cond_cdf[i * cdf_count + res].y = 1.0f;
+ pool.wait_work();
}
/* marginal CDFs (column, V direction, sum of rows) */
@@ -465,6 +533,8 @@ void LightManager::device_update_background(Device *device, DeviceScene *dscene,
marg_cdf[res].y = 1.0f;
+ VLOG(2) << "Background MIS build time " << time_dt() - time_start << "\n";
+
/* update device */
device->tex_alloc("__light_background_marginal_cdf", dscene->light_background_marginal_cdf);
device->tex_alloc("__light_background_conditional_cdf", dscene->light_background_conditional_cdf);
@@ -475,10 +545,8 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
if(scene->lights.size() == 0)
return;
- float4 *light_data = dscene->light_data.resize(scene->lights.size()*LIGHT_SIZE);
-
- if(!device->info.advanced_shading) {
- /* remove unsupported light */
+ /* remove background light? */
+ if(!(device->info.advanced_shading)) {
foreach(Light *light, scene->lights) {
if(light->type == LIGHT_BACKGROUND) {
scene->lights.erase(std::remove(scene->lights.begin(), scene->lights.end(), light), scene->lights.end());
@@ -487,10 +555,15 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
}
}
- for(size_t i = 0; i < scene->lights.size(); i++) {
- Light *light = scene->lights[i];
+ float4 *light_data = dscene->light_data.resize(scene->lights.size()*LIGHT_SIZE);
+ int light_index = 0;
+
+ foreach(Light *light, scene->lights) {
+ if(light->is_portal)
+ continue;
+
float3 co = light->co;
- int shader_id = scene->shader_manager->get_shader_id(scene->lights[i]->shader);
+ int shader_id = scene->shader_manager->get_shader_id(light->shader);
float samples = __int_as_float(light->samples);
float max_bounces = __int_as_float(light->max_bounces);
@@ -523,11 +596,11 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
if(light->use_mis && radius > 0.0f)
shader_id |= SHADER_USE_MIS;
- light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
- light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, 0.0f);
- light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
- light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
+ light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
+ light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, 0.0f);
+ light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
+ light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_DISTANT) {
shader_id &= ~SHADER_AREA_LIGHT;
@@ -544,11 +617,11 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
if(light->use_mis && area > 0.0f)
shader_id |= SHADER_USE_MIS;
- light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), dir.x, dir.y, dir.z);
- light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, cosangle, invarea);
- light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
- light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
+ light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), dir.x, dir.y, dir.z);
+ light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, cosangle, invarea);
+ light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
+ light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_BACKGROUND) {
uint visibility = scene->background->visibility;
@@ -573,11 +646,11 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
use_light_visibility = true;
}
- light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), 0.0f, 0.0f, 0.0f);
- light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), 0.0f, 0.0f, 0.0f);
- light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
- light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
+ light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), 0.0f, 0.0f, 0.0f);
+ light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), 0.0f, 0.0f, 0.0f);
+ light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
+ light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_AREA) {
float3 axisu = light->axisu*(light->sizeu*light->size);
@@ -591,11 +664,11 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
if(light->use_mis && area > 0.0f)
shader_id |= SHADER_USE_MIS;
- light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
- light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z);
- light_data[i*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
- light_data[i*LIGHT_SIZE + 3] = make_float4(samples, dir.x, dir.y, dir.z);
- light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
+ light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
+ light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z);
+ light_data[light_index*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
+ light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, dir.x, dir.y, dir.z);
+ light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_SPOT) {
shader_id &= ~SHADER_AREA_LIGHT;
@@ -611,19 +684,51 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
if(light->use_mis && radius > 0.0f)
shader_id |= SHADER_USE_MIS;
- light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
- light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, spot_angle);
- light_data[i*LIGHT_SIZE + 2] = make_float4(spot_smooth, dir.x, dir.y, dir.z);
- light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
- light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
+ light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
+ light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, spot_angle);
+ light_data[light_index*LIGHT_SIZE + 2] = make_float4(spot_smooth, dir.x, dir.y, dir.z);
+ light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
+ light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
+
+ light_index++;
}
-
+
+ /* TODO(sergey): Consider moving portals update to their own function
+ * keeping this one more manageable.
+ */
+ foreach(Light *light, scene->lights) {
+ if(!light->is_portal)
+ continue;
+ assert(light->type == LIGHT_AREA);
+
+ float3 co = light->co;
+ float3 axisu = light->axisu*(light->sizeu*light->size);
+ float3 axisv = light->axisv*(light->sizev*light->size);
+ float area = len(axisu)*len(axisv);
+ float invarea = (area > 0.0f) ? 1.0f / area : 1.0f;
+ float3 dir = light->dir;
+
+ dir = safe_normalize(dir);
+
+ light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
+ light_data[light_index*LIGHT_SIZE + 1] = make_float4(area, axisu.x, axisu.y, axisu.z);
+ light_data[light_index*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
+ light_data[light_index*LIGHT_SIZE + 3] = make_float4(-1, dir.x, dir.y, dir.z);
+ light_data[light_index*LIGHT_SIZE + 4] = make_float4(-1, 0.0f, 0.0f, 0.0f);
+
+ light_index++;
+ }
+
+ assert(light_index == scene->lights.size());
+
device->tex_alloc("__light_data", dscene->light_data);
}
void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
+ VLOG(1) << "Total " << scene->lights.size() << " lights.";
+
if(!need_update)
return;
@@ -661,7 +766,7 @@ void LightManager::device_free(Device *device, DeviceScene *dscene)
dscene->light_background_conditional_cdf.clear();
}
-void LightManager::tag_update(Scene *scene)
+void LightManager::tag_update(Scene * /*scene*/)
{
need_update = true;
}
diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h
index 1f8eac6a97f..824d99aeb93 100644
--- a/intern/cycles/render/light.h
+++ b/intern/cycles/render/light.h
@@ -56,6 +56,8 @@ public:
bool use_transmission;
bool use_scatter;
+ bool is_portal;
+
int shader;
int samples;
int max_bounces;
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index 9c7310d4a05..fdd1e3ea32c 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -20,9 +20,11 @@
#include "camera.h"
#include "curves.h"
#include "device.h"
+#include "graph.h"
#include "shader.h"
#include "light.h"
#include "mesh.h"
+#include "nodes.h"
#include "object.h"
#include "scene.h"
@@ -135,7 +137,7 @@ void Mesh::clear()
transform_applied = false;
transform_negative_scaled = false;
transform_normal = transform_identity();
- geometry_synced = false;
+ geometry_flags = GEOMETRY_NONE;
}
int Mesh::split_vertex(int vertex)
@@ -210,11 +212,11 @@ void Mesh::compute_bounds()
bnds.grow(float4_to_float3(curve_keys[i]), curve_keys[i].w);
Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if (use_motion_blur && attr) {
+ if(use_motion_blur && attr) {
size_t steps_size = verts.size() * (motion_steps - 1);
float3 *vert_steps = attr->data_float3();
- for (size_t i = 0; i < steps_size; i++)
+ for(size_t i = 0; i < steps_size; i++)
bnds.grow(vert_steps[i]);
}
@@ -223,7 +225,7 @@ void Mesh::compute_bounds()
size_t steps_size = curve_keys.size() * (motion_steps - 1);
float3 *key_steps = curve_attr->data_float3();
- for (size_t i = 0; i < steps_size; i++)
+ for(size_t i = 0; i < steps_size; i++)
bnds.grow(key_steps[i]);
}
@@ -237,19 +239,19 @@ void Mesh::compute_bounds()
for(size_t i = 0; i < curve_keys_size; i++)
bnds.grow_safe(float4_to_float3(curve_keys[i]), curve_keys[i].w);
- if (use_motion_blur && attr) {
+ if(use_motion_blur && attr) {
size_t steps_size = verts.size() * (motion_steps - 1);
float3 *vert_steps = attr->data_float3();
- for (size_t i = 0; i < steps_size; i++)
+ for(size_t i = 0; i < steps_size; i++)
bnds.grow_safe(vert_steps[i]);
}
- if (use_motion_blur && curve_attr) {
+ if(use_motion_blur && curve_attr) {
size_t steps_size = curve_keys.size() * (motion_steps - 1);
float3 *key_steps = curve_attr->data_float3();
- for (size_t i = 0; i < steps_size; i++)
+ for(size_t i = 0; i < steps_size; i++)
bnds.grow_safe(key_steps[i]);
}
}
@@ -513,6 +515,7 @@ void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total
BVHParams bparams;
bparams.use_cache = params->use_bvh_cache;
bparams.use_spatial_split = params->use_bvh_spatial_split;
+ bparams.use_triangle_storage = params->use_bvh_triangle_storage;
bparams.use_qbvh = params->use_qbvh;
delete bvh;
@@ -552,9 +555,10 @@ bool Mesh::has_motion_blur() const
/* Mesh Manager */
-MeshManager::MeshManager()
+MeshManager::MeshManager(const bool free_data_after_update_)
{
bvh = NULL;
+ free_data_after_update = free_data_after_update_;
need_update = true;
need_flags_update = true;
}
@@ -653,6 +657,10 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
}
}
}
+#else
+ (void)device;
+ (void)scene;
+ (void)mesh_attributes;
#endif
}
@@ -810,7 +818,10 @@ static void update_attribute_element_offset(Mesh *mesh,
if(mattr->element == ATTR_ELEMENT_VOXEL) {
/* store slot in offset value */
VoxelAttribute *voxel_data = mattr->data_voxel();
- offset = voxel_data->slot;
+ offset = voxel_data->slot << 1;
+ if(voxel_data->from_alpha) {
+ ++offset;
+ }
}
else if(mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
uchar4 *data = mattr->data_uchar4();
@@ -1079,6 +1090,7 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
bparams.use_qbvh = scene->params.use_qbvh;
bparams.use_spatial_split = scene->params.use_bvh_spatial_split;
bparams.use_cache = scene->params.use_bvh_cache;
+ bparams.use_triangle_storage = scene->params.use_bvh_triangle_storage;
delete bvh;
bvh = BVH::create(bparams, scene->objects);
@@ -1095,6 +1107,10 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
dscene->bvh_nodes.reference((float4*)&pack.nodes[0], pack.nodes.size());
device->tex_alloc("__bvh_nodes", dscene->bvh_nodes);
}
+ if(pack.leaf_nodes.size()) {
+ dscene->bvh_leaf_nodes.reference((float4*)&pack.leaf_nodes[0], pack.leaf_nodes.size());
+ device->tex_alloc("__bvh_leaf_nodes", dscene->bvh_leaf_nodes);
+ }
if(pack.object_node.size()) {
dscene->object_node.reference((uint*)&pack.object_node[0], pack.object_node.size());
device->tex_alloc("__object_node", dscene->object_node);
@@ -1122,9 +1138,13 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
dscene->data.bvh.root = pack.root_index;
dscene->data.bvh.use_qbvh = scene->params.use_qbvh;
+ dscene->data.bvh.use_tri_storage = scene->params.use_bvh_triangle_storage? 1: 0;
}
-void MeshManager::device_update_flags(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
+void MeshManager::device_update_flags(Device * /*device*/,
+ DeviceScene * /*dscene*/,
+ Scene * scene,
+ Progress& /*progress*/)
{
if(!need_update && !need_flags_update) {
return;
@@ -1141,8 +1161,59 @@ void MeshManager::device_update_flags(Device *device, DeviceScene *dscene, Scene
need_flags_update = false;
}
+void MeshManager::device_update_displacement_images(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& progress)
+{
+ progress.set_status("Updating Displacement Images");
+ TaskPool pool;
+ ImageManager *image_manager = scene->image_manager;
+ set<int> bump_images;
+ foreach(Mesh *mesh, scene->meshes) {
+ if(mesh->need_update) {
+ foreach(uint shader_index, mesh->used_shaders) {
+ Shader *shader = scene->shaders[shader_index];
+ if(shader->graph_bump == NULL) {
+ continue;
+ }
+ foreach(ShaderNode* node, shader->graph_bump->nodes) {
+ if(node->special_type != SHADER_SPECIAL_TYPE_IMAGE_SLOT) {
+ continue;
+ }
+ if(device->info.pack_images) {
+ /* If device requires packed images we need to update all
+ * images now, even if they're not used for displacement.
+ */
+ image_manager->device_update(device,
+ dscene,
+ progress);
+ return;
+ }
+ ImageSlotNode *image_node = static_cast<ImageSlotNode*>(node);
+ int slot = image_node->slot;
+ if(slot != -1) {
+ bump_images.insert(slot);
+ }
+ }
+ }
+ }
+ }
+ foreach(int slot, bump_images) {
+ pool.push(function_bind(&ImageManager::device_update_slot,
+ image_manager,
+ device,
+ dscene,
+ slot,
+ &progress));
+ }
+ pool.wait_work();
+}
+
void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
+ VLOG(1) << "Total " << scene->meshes.size() << " meshes.";
+
if(!need_update)
return;
@@ -1161,6 +1232,28 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
}
}
+ /* Update images needed for true displacement. */
+ bool need_displacement_images = false;
+ bool old_need_object_flags_update = false;
+ foreach(Mesh *mesh, scene->meshes) {
+ if(mesh->need_update &&
+ mesh->displacement_method != Mesh::DISPLACE_BUMP)
+ {
+ need_displacement_images = true;
+ break;
+ }
+ }
+ if(need_displacement_images) {
+ VLOG(1) << "Updating images used for true displacement.";
+ device_update_displacement_images(device, dscene, scene, progress);
+ old_need_object_flags_update = scene->object_manager->need_flags_update;
+ scene->object_manager->device_update_flags(device,
+ dscene,
+ scene,
+ progress,
+ false);
+ }
+
/* device update */
device_free(device, dscene);
@@ -1208,7 +1301,9 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
&progress,
i,
num_bvh));
- i++;
+ if(!mesh->transform_applied) {
+ i++;
+ }
}
}
@@ -1232,12 +1327,32 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
device_update_bvh(device, dscene, scene, progress);
+ if(free_data_after_update) {
+ foreach(Object *object, scene->objects) {
+ if(object->mesh->bvh != NULL) {
+ delete object->mesh->bvh;
+ object->mesh->bvh = NULL;
+ }
+ }
+ }
+
need_update = false;
+
+ if(need_displacement_images) {
+ /* Re-tag flags for update, so they're re-evaluated
+ * for meshes with correct bounding boxes.
+ *
+ * This wouldn't cause wrong results, just true
+ * displacement might be less optimal ot calculate.
+ */
+ scene->object_manager->need_flags_update = old_need_object_flags_update;
+ }
}
void MeshManager::device_free(Device *device, DeviceScene *dscene)
{
device->tex_free(dscene->bvh_nodes);
+ device->tex_free(dscene->bvh_leaf_nodes);
device->tex_free(dscene->object_node);
device->tex_free(dscene->tri_woop);
device->tex_free(dscene->prim_type);
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index 62e775e5bc9..887ef65004e 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -71,8 +71,13 @@ public:
ustring name;
/* Mesh Data */
- bool geometry_synced; /* used to distinguish meshes with no verts
- and meshed for which geometry is not created */
+ enum GeometryFlags {
+ GEOMETRY_NONE = 0,
+ GEOMETRY_TRIANGLES = (1 << 0),
+ GEOMETRY_CURVES = (1 << 1),
+ };
+ int geometry_flags; /* used to distinguish meshes with no verts
+ and meshed for which geometry is not created */
vector<float3> verts;
vector<Triangle> triangles;
@@ -147,7 +152,10 @@ public:
bool need_update;
bool need_flags_update;
- MeshManager();
+ /* Free memory used by BVH after device update. */
+ bool free_data_after_update;
+
+ MeshManager(const bool free_data_after_update);
~MeshManager();
bool displace(Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress& progress);
@@ -162,6 +170,7 @@ public:
void device_update_attributes(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_update_flags(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
+ void device_update_displacement_images(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_free(Device *device, DeviceScene *dscene);
void tag_update(Scene *scene);
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 7a39811cacd..f799e2682eb 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -186,7 +186,7 @@ ShaderEnum ImageTextureNode::color_space_enum = color_space_init();
ShaderEnum ImageTextureNode::projection_enum = image_projection_init();
ImageTextureNode::ImageTextureNode()
-: TextureNode("image_texture")
+: ImageSlotTextureNode("image_texture")
{
image_manager = NULL;
slot = -1;
@@ -227,7 +227,7 @@ void ImageTextureNode::attributes(Shader *shader, AttributeRequestSet *attribute
#ifdef WITH_PTEX
/* todo: avoid loading other texture coordinates when using ptex,
* and hide texture coordinate socket in the UI */
- if (shader->has_surface && string_endswith(filename, ".ptx")) {
+ if(shader->has_surface && string_endswith(filename, ".ptx")) {
/* ptex */
attributes->add(ATTR_STD_PTEX_FACE_ID);
attributes->add(ATTR_STD_PTEX_UV);
@@ -380,7 +380,7 @@ ShaderEnum EnvironmentTextureNode::color_space_enum = color_space_init();
ShaderEnum EnvironmentTextureNode::projection_enum = env_projection_init();
EnvironmentTextureNode::EnvironmentTextureNode()
-: TextureNode("environment_texture")
+: ImageSlotTextureNode("environment_texture")
{
image_manager = NULL;
slot = -1;
@@ -417,7 +417,7 @@ ShaderNode *EnvironmentTextureNode::clone() const
void EnvironmentTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
#ifdef WITH_PTEX
- if (shader->has_surface && string_endswith(filename, ".ptx")) {
+ if(shader->has_surface && string_endswith(filename, ".ptx")) {
/* ptex */
attributes->add(ATTR_STD_PTEX_FACE_ID);
attributes->add(ATTR_STD_PTEX_UV);
@@ -632,7 +632,7 @@ static void sky_texture_precompute_new(SunSky *sunsky, float3 dir, float turbidi
sky_state = arhosek_xyz_skymodelstate_alloc_init(turbidity, ground_albedo, solarElevation);
/* Copy values from sky_state to SunSky */
- for (int i = 0; i < 9; ++i) {
+ for(int i = 0; i < 9; ++i) {
sunsky->config_x[i] = (float)sky_state->configs[0][i];
sunsky->config_y[i] = (float)sky_state->configs[1][i];
sunsky->config_z[i] = (float)sky_state->configs[2][i];
@@ -1297,6 +1297,118 @@ void BrickTextureNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_brick_texture");
}
+/* Point Density Texture */
+
+static ShaderEnum point_density_space_init()
+{
+ ShaderEnum enm;
+
+ enm.insert("Object", NODE_TEX_VOXEL_SPACE_OBJECT);
+ enm.insert("World", NODE_TEX_VOXEL_SPACE_WORLD);
+
+ return enm;
+}
+
+ShaderEnum PointDensityTextureNode::space_enum = point_density_space_init();
+
+PointDensityTextureNode::PointDensityTextureNode()
+: ShaderNode("point_density")
+{
+ image_manager = NULL;
+ slot = -1;
+ filename = "";
+ space = ustring("Object");
+ builtin_data = NULL;
+ interpolation = INTERPOLATION_LINEAR;
+
+ tfm = transform_identity();
+
+ add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::POSITION);
+ add_output("Density", SHADER_SOCKET_FLOAT);
+ add_output("Color", SHADER_SOCKET_COLOR);
+}
+
+PointDensityTextureNode::~PointDensityTextureNode()
+{
+ if(image_manager)
+ image_manager->remove_image(filename, builtin_data, interpolation);
+}
+
+ShaderNode *PointDensityTextureNode::clone() const
+{
+ PointDensityTextureNode *node = new PointDensityTextureNode(*this);
+ node->image_manager = NULL;
+ node->slot = -1;
+ return node;
+}
+
+void PointDensityTextureNode::attributes(Shader *shader,
+ AttributeRequestSet *attributes)
+{
+ if(shader->has_volume)
+ attributes->add(ATTR_STD_GENERATED_TRANSFORM);
+
+ ShaderNode::attributes(shader, attributes);
+}
+
+void PointDensityTextureNode::compile(SVMCompiler& compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderOutput *density_out = output("Density");
+ ShaderOutput *color_out = output("Color");
+
+ bool use_density = !density_out->links.empty();
+ bool use_color = !color_out->links.empty();
+
+ image_manager = compiler.image_manager;
+
+ if (use_density || use_color) {
+ if (use_density)
+ compiler.stack_assign(density_out);
+ if (use_color)
+ compiler.stack_assign(color_out);
+
+ if(slot == -1) {
+ bool is_float, is_linear;
+ slot = image_manager->add_image(filename, builtin_data,
+ false, 0,
+ is_float, is_linear,
+ interpolation,
+ true);
+ }
+
+ if(slot != -1) {
+ compiler.stack_assign(vector_in);
+ compiler.add_node(NODE_TEX_VOXEL,
+ slot,
+ compiler.encode_uchar4(vector_in->stack_offset,
+ density_out->stack_offset,
+ color_out->stack_offset,
+ space_enum[space]));
+ if(space == "World") {
+ compiler.add_node(tfm.x);
+ compiler.add_node(tfm.y);
+ compiler.add_node(tfm.z);
+ compiler.add_node(tfm.w);
+ }
+ }
+ else {
+ compiler.add_node(NODE_VALUE_F,
+ __float_as_int(0.0f),
+ density_out->stack_offset);
+ compiler.add_node(NODE_VALUE_V, color_out->stack_offset);
+ compiler.add_node(NODE_VALUE_V, make_float3(TEX_IMAGE_MISSING_R,
+ TEX_IMAGE_MISSING_G,
+ TEX_IMAGE_MISSING_B));
+ }
+ }
+}
+
+void PointDensityTextureNode::compile(OSLCompiler& /*compiler*/)
+{
+ /* TODO(sergey): To be supported. */
+}
+
/* Normal */
NormalNode::NormalNode()
@@ -1507,11 +1619,11 @@ ProxyNode::ProxyNode(ShaderSocketType type_)
add_output("Output", type);
}
-void ProxyNode::compile(SVMCompiler& compiler)
+void ProxyNode::compile(SVMCompiler& /*compiler*/)
{
}
-void ProxyNode::compile(OSLCompiler& compiler)
+void ProxyNode::compile(OSLCompiler& /*compiler*/)
{
}
@@ -1520,6 +1632,8 @@ void ProxyNode::compile(OSLCompiler& compiler)
BsdfNode::BsdfNode(bool scattering_)
: ShaderNode("bsdf"), scattering(scattering_)
{
+ special_type = SHADER_SPECIAL_TYPE_CLOSURE;
+
add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL);
add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
@@ -1587,7 +1701,7 @@ void BsdfNode::compile(SVMCompiler& compiler)
compile(compiler, NULL, NULL);
}
-void BsdfNode::compile(OSLCompiler& compiler)
+void BsdfNode::compile(OSLCompiler& /*compiler*/)
{
assert(0);
}
@@ -1609,6 +1723,7 @@ ShaderEnum AnisotropicBsdfNode::distribution_enum = aniso_distribution_init();
AnisotropicBsdfNode::AnisotropicBsdfNode()
{
+ closure = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
distribution = ustring("GGX");
add_input("Tangent", SHADER_SOCKET_VECTOR, ShaderInput::TANGENT);
@@ -1661,6 +1776,7 @@ ShaderEnum GlossyBsdfNode::distribution_enum = glossy_distribution_init();
GlossyBsdfNode::GlossyBsdfNode()
{
+ closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
distribution = ustring("GGX");
add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f);
@@ -1699,6 +1815,7 @@ ShaderEnum GlassBsdfNode::distribution_enum = glass_distribution_init();
GlassBsdfNode::GlassBsdfNode()
{
+ closure = CLOSURE_BSDF_SHARP_GLASS_ID;
distribution = ustring("Sharp");
add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
@@ -1738,6 +1855,7 @@ ShaderEnum RefractionBsdfNode::distribution_enum = refraction_distribution_init(
RefractionBsdfNode::RefractionBsdfNode()
{
+ closure = CLOSURE_BSDF_REFRACTION_ID;
distribution = ustring("Sharp");
add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
@@ -1776,6 +1894,7 @@ ShaderEnum ToonBsdfNode::component_enum = toon_component_init();
ToonBsdfNode::ToonBsdfNode()
{
+ closure = CLOSURE_BSDF_DIFFUSE_TOON_ID;
component = ustring("Diffuse");
add_input("Size", SHADER_SOCKET_FLOAT, 0.5f);
@@ -1916,6 +2035,8 @@ bool SubsurfaceScatteringNode::has_bssrdf_bump()
EmissionNode::EmissionNode()
: ShaderNode("emission")
{
+ special_type = SHADER_SPECIAL_TYPE_EMISSION;
+
add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
add_input("Strength", SHADER_SOCKET_FLOAT, 10.0f);
add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
@@ -2078,7 +2199,7 @@ void VolumeNode::compile(SVMCompiler& compiler)
compile(compiler, NULL, NULL);
}
-void VolumeNode::compile(OSLCompiler& compiler)
+void VolumeNode::compile(OSLCompiler& /*compiler*/)
{
assert(0);
}
@@ -2135,6 +2256,7 @@ ShaderEnum HairBsdfNode::component_enum = hair_component_init();
HairBsdfNode::HairBsdfNode()
{
+ closure = CLOSURE_BSDF_HAIR_REFLECTION_ID;
component = ustring("Reflection");
add_input("Offset", SHADER_SOCKET_FLOAT);
@@ -2248,10 +2370,15 @@ void GeometryNode::compile(SVMCompiler& compiler)
out = output("Pointiness");
if(!out->links.empty()) {
compiler.stack_assign(out);
- compiler.add_node(attr_node,
- ATTR_STD_POINTINESS,
- out->stack_offset,
- NODE_ATTR_FLOAT);
+ if(compiler.output_type() != SHADER_TYPE_VOLUME) {
+ compiler.add_node(attr_node,
+ ATTR_STD_POINTINESS,
+ out->stack_offset,
+ NODE_ATTR_FLOAT);
+ }
+ else {
+ compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), out->stack_offset);
+ }
}
}
@@ -2442,7 +2569,7 @@ void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
if(shader->has_surface) {
if(!from_dupli) {
if(!output("UV")->links.empty()) {
- if (attribute != "")
+ if(attribute != "")
attributes->add(attribute);
else
attributes->add(ATTR_STD_UV);
@@ -2475,7 +2602,7 @@ void UVMapNode::compile(SVMCompiler& compiler)
compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, out->stack_offset);
}
else {
- if (attribute != "")
+ if(attribute != "")
attr = compiler.attribute(attribute);
else
attr = compiler.attribute(ATTR_STD_UV);
@@ -2916,7 +3043,7 @@ AddClosureNode::AddClosureNode()
add_output("Closure", SHADER_SOCKET_CLOSURE);
}
-void AddClosureNode::compile(SVMCompiler& compiler)
+void AddClosureNode::compile(SVMCompiler& /*compiler*/)
{
/* handled in the SVM compiler */
}
@@ -2939,7 +3066,7 @@ MixClosureNode::MixClosureNode()
add_output("Closure", SHADER_SOCKET_CLOSURE);
}
-void MixClosureNode::compile(SVMCompiler& compiler)
+void MixClosureNode::compile(SVMCompiler& /*compiler*/)
{
/* handled in the SVM compiler */
}
@@ -2977,7 +3104,7 @@ void MixClosureWeightNode::compile(SVMCompiler& compiler)
weight1_out->stack_offset, weight2_out->stack_offset));
}
-void MixClosureWeightNode::compile(OSLCompiler& compiler)
+void MixClosureWeightNode::compile(OSLCompiler& /*compiler*/)
{
assert(0);
}
@@ -3647,9 +3774,17 @@ void BlackbodyNode::compile(SVMCompiler& compiler)
ShaderInput *temperature_in = input("Temperature");
ShaderOutput *color_out = output("Color");
- compiler.stack_assign(temperature_in);
compiler.stack_assign(color_out);
- compiler.add_node(NODE_BLACKBODY, temperature_in->stack_offset, color_out->stack_offset);
+
+ if(temperature_in->link == NULL) {
+ float3 color = svm_math_blackbody_color(temperature_in->value.x);
+ compiler.add_node(NODE_VALUE_V, color_out->stack_offset);
+ compiler.add_node(NODE_VALUE_V, color);
+ }
+ else {
+ compiler.stack_assign(temperature_in);
+ compiler.add_node(NODE_BLACKBODY, temperature_in->stack_offset, color_out->stack_offset);
+ }
}
void BlackbodyNode::compile(OSLCompiler& compiler)
@@ -3747,7 +3882,7 @@ void MathNode::compile(SVMCompiler& compiler)
value1_in->value.x,
value2_in->value.x);
if(use_clamp) {
- optimized_value = clamp(optimized_value, 0.0f, 1.0f);
+ optimized_value = saturate(optimized_value);
}
compiler.add_node(NODE_VALUE_F,
__float_as_int(optimized_value),
@@ -3987,7 +4122,7 @@ void RGBCurvesNode::compile(OSLCompiler& compiler)
{
float ramp[RAMP_TABLE_SIZE][3];
- for (int i = 0; i < RAMP_TABLE_SIZE; ++i) {
+ for(int i = 0; i < RAMP_TABLE_SIZE; ++i) {
ramp[i][0] = curves[i].x;
ramp[i][1] = curves[i].y;
ramp[i][2] = curves[i].z;
@@ -4025,7 +4160,7 @@ void VectorCurvesNode::compile(OSLCompiler& compiler)
{
float ramp[RAMP_TABLE_SIZE][3];
- for (int i = 0; i < RAMP_TABLE_SIZE; ++i) {
+ for(int i = 0; i < RAMP_TABLE_SIZE; ++i) {
ramp[i][0] = curves[i].x;
ramp[i][1] = curves[i].y;
ramp[i][2] = curves[i].z;
@@ -4075,7 +4210,7 @@ void RGBRampNode::compile(OSLCompiler& compiler)
float ramp_color[RAMP_TABLE_SIZE][3];
float ramp_alpha[RAMP_TABLE_SIZE];
- for (int i = 0; i < RAMP_TABLE_SIZE; ++i) {
+ for(int i = 0; i < RAMP_TABLE_SIZE; ++i) {
ramp_color[i][0] = ramp[i].x;
ramp_color[i][1] = ramp[i].y;
ramp_color[i][2] = ramp[i].z;
@@ -4122,7 +4257,7 @@ OSLScriptNode::OSLScriptNode()
special_type = SHADER_SPECIAL_TYPE_SCRIPT;
}
-void OSLScriptNode::compile(SVMCompiler& compiler)
+void OSLScriptNode::compile(SVMCompiler& /*compiler*/)
{
/* doesn't work for SVM, obviously ... */
}
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 0ec0fce512f..4961cd4aebb 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -55,13 +55,28 @@ public:
/* Nodes */
+/* Any node which uses image manager's slot should be a subclass of this one. */
+class ImageSlotNode : public ShaderNode {
+public:
+ ImageSlotNode(const char *name_) : ShaderNode(name_) {
+ special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT;
+ }
+ int slot;
+};
+
class TextureNode : public ShaderNode {
public:
TextureNode(const char *name_) : ShaderNode(name_) {}
TextureMapping tex_mapping;
};
-class ImageTextureNode : public TextureNode {
+class ImageSlotTextureNode : public ImageSlotNode {
+public:
+ ImageSlotTextureNode(const char *name_) : ImageSlotNode(name_) {}
+ TextureMapping tex_mapping;
+};
+
+class ImageTextureNode : public ImageSlotTextureNode {
public:
SHADER_NODE_NO_CLONE_CLASS(ImageTextureNode)
~ImageTextureNode();
@@ -69,7 +84,6 @@ public:
void attributes(Shader *shader, AttributeRequestSet *attributes);
ImageManager *image_manager;
- int slot;
int is_float;
bool is_linear;
bool use_alpha;
@@ -85,15 +99,15 @@ public:
static ShaderEnum projection_enum;
};
-class EnvironmentTextureNode : public TextureNode {
+class EnvironmentTextureNode : public ImageSlotTextureNode {
public:
SHADER_NODE_NO_CLONE_CLASS(EnvironmentTextureNode)
~EnvironmentTextureNode();
ShaderNode *clone() const;
void attributes(Shader *shader, AttributeRequestSet *attributes);
+ virtual int get_group() { return NODE_GROUP_LEVEL_2; }
ImageManager *image_manager;
- int slot;
int is_float;
bool is_linear;
bool use_alpha;
@@ -111,6 +125,8 @@ class SkyTextureNode : public TextureNode {
public:
SHADER_NODE_CLASS(SkyTextureNode)
+ virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+
float3 sun_direction;
float turbidity;
float ground_albedo;
@@ -128,6 +144,8 @@ class GradientTextureNode : public TextureNode {
public:
SHADER_NODE_CLASS(GradientTextureNode)
+ virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+
ustring type;
static ShaderEnum type_enum;
};
@@ -141,6 +159,8 @@ class VoronoiTextureNode : public TextureNode {
public:
SHADER_NODE_CLASS(VoronoiTextureNode)
+ virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+
ustring coloring;
static ShaderEnum coloring_enum;
@@ -150,6 +170,8 @@ class MusgraveTextureNode : public TextureNode {
public:
SHADER_NODE_CLASS(MusgraveTextureNode)
+ virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+
ustring type;
static ShaderEnum type_enum;
@@ -159,6 +181,8 @@ class WaveTextureNode : public TextureNode {
public:
SHADER_NODE_CLASS(WaveTextureNode)
+ virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+
ustring type;
static ShaderEnum type_enum;
};
@@ -167,12 +191,16 @@ class MagicTextureNode : public TextureNode {
public:
SHADER_NODE_CLASS(MagicTextureNode)
+ virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+
int depth;
};
class CheckerTextureNode : public TextureNode {
public:
SHADER_NODE_CLASS(CheckerTextureNode)
+
+ virtual int get_group() { return NODE_GROUP_LEVEL_2; }
};
class BrickTextureNode : public TextureNode {
@@ -181,11 +209,37 @@ public:
float offset, squash;
int offset_frequency, squash_frequency;
+
+ virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+};
+
+class PointDensityTextureNode : public ShaderNode {
+public:
+ SHADER_NODE_NO_CLONE_CLASS(PointDensityTextureNode)
+
+ ~PointDensityTextureNode();
+ ShaderNode *clone() const;
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+
+ bool has_spatial_varying() { return true; }
+ bool has_object_dependency() { return true; }
+
+ ImageManager *image_manager;
+ int slot;
+ string filename;
+ ustring space;
+ void *builtin_data;
+ InterpolationType interpolation;
+
+ Transform tfm;
+
+ static ShaderEnum space_enum;
};
class MappingNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MappingNode)
+ virtual int get_group() { return NODE_GROUP_LEVEL_2; }
TextureMapping tex_mapping;
};
@@ -308,6 +362,7 @@ public:
class HoldoutNode : public ShaderNode {
public:
SHADER_NODE_CLASS(HoldoutNode)
+ virtual int get_group() { return NODE_GROUP_LEVEL_1; }
};
class AmbientOcclusionNode : public ShaderNode {
@@ -315,6 +370,7 @@ public:
SHADER_NODE_CLASS(AmbientOcclusionNode)
bool has_spatial_varying() { return true; }
+ virtual int get_group() { return NODE_GROUP_LEVEL_1; }
};
class VolumeNode : public ShaderNode {
@@ -322,6 +378,7 @@ public:
SHADER_NODE_CLASS(VolumeNode)
void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2);
+ virtual int get_group() { return NODE_GROUP_LEVEL_1; }
ClosureType closure;
};
@@ -369,6 +426,7 @@ public:
SHADER_NODE_CLASS(UVMapNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_spatial_varying() { return true; }
+ virtual int get_group() { return NODE_GROUP_LEVEL_1; }
ustring attribute;
bool from_dupli;
@@ -377,6 +435,7 @@ public:
class LightPathNode : public ShaderNode {
public:
SHADER_NODE_CLASS(LightPathNode)
+ virtual int get_group() { return NODE_GROUP_LEVEL_1; }
};
class LightFalloffNode : public ShaderNode {
@@ -388,12 +447,14 @@ public:
class ObjectInfoNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ObjectInfoNode)
+ virtual int get_group() { return NODE_GROUP_LEVEL_1; }
};
class ParticleInfoNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ParticleInfoNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
+ virtual int get_group() { return NODE_GROUP_LEVEL_1; }
};
class HairInfoNode : public ShaderNode {
@@ -402,6 +463,10 @@ public:
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_spatial_varying() { return true; }
+ virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+ virtual int get_feature() {
+ return ShaderNode::get_feature() | NODE_FEATURE_HAIR;
+ }
};
class ValueNode : public ShaderNode {
@@ -436,12 +501,16 @@ public:
class InvertNode : public ShaderNode {
public:
SHADER_NODE_CLASS(InvertNode)
+
+ virtual int get_group() { return NODE_GROUP_LEVEL_3; }
};
class MixNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MixNode)
+ virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+
bool use_clamp;
ustring type;
@@ -451,41 +520,55 @@ public:
class CombineRGBNode : public ShaderNode {
public:
SHADER_NODE_CLASS(CombineRGBNode)
+
+ virtual int get_group() { return NODE_GROUP_LEVEL_3; }
};
class CombineHSVNode : public ShaderNode {
public:
SHADER_NODE_CLASS(CombineHSVNode)
+
+ virtual int get_group() { return NODE_GROUP_LEVEL_3; }
};
class CombineXYZNode : public ShaderNode {
public:
SHADER_NODE_CLASS(CombineXYZNode)
+
+ virtual int get_group() { return NODE_GROUP_LEVEL_3; }
};
class GammaNode : public ShaderNode {
public:
SHADER_NODE_CLASS(GammaNode)
+ virtual int get_group() { return NODE_GROUP_LEVEL_1; }
};
class BrightContrastNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BrightContrastNode)
+ virtual int get_group() { return NODE_GROUP_LEVEL_1; }
};
class SeparateRGBNode : public ShaderNode {
public:
SHADER_NODE_CLASS(SeparateRGBNode)
+
+ virtual int get_group() { return NODE_GROUP_LEVEL_3; }
};
class SeparateHSVNode : public ShaderNode {
public:
SHADER_NODE_CLASS(SeparateHSVNode)
+
+ virtual int get_group() { return NODE_GROUP_LEVEL_3; }
};
class SeparateXYZNode : public ShaderNode {
public:
SHADER_NODE_CLASS(SeparateXYZNode)
+
+ virtual int get_group() { return NODE_GROUP_LEVEL_3; }
};
class HSVNode : public ShaderNode {
@@ -512,18 +595,21 @@ class FresnelNode : public ShaderNode {
public:
SHADER_NODE_CLASS(FresnelNode)
bool has_spatial_varying() { return true; }
+ virtual int get_group() { return NODE_GROUP_LEVEL_1; }
};
class LayerWeightNode : public ShaderNode {
public:
SHADER_NODE_CLASS(LayerWeightNode)
bool has_spatial_varying() { return true; }
+ virtual int get_group() { return NODE_GROUP_LEVEL_1; }
};
class WireframeNode : public ShaderNode {
public:
SHADER_NODE_CLASS(WireframeNode)
bool has_spatial_varying() { return true; }
+ virtual int get_group() { return NODE_GROUP_LEVEL_3; }
bool use_pixel_size;
};
@@ -531,18 +617,21 @@ public:
class WavelengthNode : public ShaderNode {
public:
SHADER_NODE_CLASS(WavelengthNode)
+
+ virtual int get_group() { return NODE_GROUP_LEVEL_3; }
};
class BlackbodyNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BlackbodyNode)
-
- bool has_converter_blackbody() { return true; }
+
+ virtual int get_group() { return NODE_GROUP_LEVEL_3; }
};
class MathNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MathNode)
+ virtual int get_group() { return NODE_GROUP_LEVEL_1; }
bool use_clamp;
@@ -553,6 +642,7 @@ public:
class NormalNode : public ShaderNode {
public:
SHADER_NODE_CLASS(NormalNode)
+ virtual int get_group() { return NODE_GROUP_LEVEL_2; }
float3 direction;
};
@@ -560,6 +650,7 @@ public:
class VectorMathNode : public ShaderNode {
public:
SHADER_NODE_CLASS(VectorMathNode)
+ virtual int get_group() { return NODE_GROUP_LEVEL_1; }
ustring type;
static ShaderEnum type_enum;
@@ -569,6 +660,8 @@ class VectorTransformNode : public ShaderNode {
public:
SHADER_NODE_CLASS(VectorTransformNode)
+ virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+
ustring type;
ustring convert_from;
ustring convert_to;
@@ -581,6 +674,10 @@ class BumpNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BumpNode)
bool has_spatial_varying() { return true; }
+ virtual int get_feature() {
+ /* TODO(sergey): Check for incoming links. */
+ return NODE_FEATURE_BUMP;
+ }
bool invert;
};
@@ -588,12 +685,18 @@ public:
class RGBCurvesNode : public ShaderNode {
public:
SHADER_NODE_CLASS(RGBCurvesNode)
+
+ virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+
float4 curves[RAMP_TABLE_SIZE];
};
class VectorCurvesNode : public ShaderNode {
public:
SHADER_NODE_CLASS(VectorCurvesNode)
+
+ virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+
float4 curves[RAMP_TABLE_SIZE];
};
@@ -602,6 +705,7 @@ public:
SHADER_NODE_CLASS(RGBRampNode)
float4 ramp[RAMP_TABLE_SIZE];
bool interpolate;
+ virtual int get_group() { return NODE_GROUP_LEVEL_1; }
};
class SetNormalNode : public ShaderNode {
@@ -630,6 +734,7 @@ public:
SHADER_NODE_CLASS(NormalMapNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_spatial_varying() { return true; }
+ virtual int get_group() { return NODE_GROUP_LEVEL_3; }
ustring space;
static ShaderEnum space_enum;
@@ -642,6 +747,7 @@ public:
SHADER_NODE_CLASS(TangentNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_spatial_varying() { return true; }
+ virtual int get_group() { return NODE_GROUP_LEVEL_3; }
ustring direction_type;
static ShaderEnum direction_type_enum;
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index 1225125b57e..ae72d728c8c 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "camera.h"
#include "device.h"
#include "light.h"
#include "mesh.h"
@@ -23,6 +24,7 @@
#include "scene.h"
#include "util_foreach.h"
+#include "util_logging.h"
#include "util_map.h"
#include "util_progress.h"
#include "util_vector.h"
@@ -104,11 +106,11 @@ void Object::apply_transform(bool apply_to_motion)
if(apply_to_motion) {
Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if (attr) {
+ if(attr) {
size_t steps_size = mesh->verts.size() * (mesh->motion_steps - 1);
float3 *vert_steps = attr->data_float3();
- for (size_t i = 0; i < steps_size; i++)
+ for(size_t i = 0; i < steps_size; i++)
vert_steps[i] = transform_point(&tfm, vert_steps[i]);
}
@@ -119,7 +121,7 @@ void Object::apply_transform(bool apply_to_motion)
size_t steps_size = mesh->verts.size() * (mesh->motion_steps - 1);
float3 *normal_steps = attr_N->data_float3();
- for (size_t i = 0; i < steps_size; i++)
+ for(size_t i = 0; i < steps_size; i++)
normal_steps[i] = normalize(transform_direction(&ntfm, normal_steps[i]));
}
}
@@ -146,12 +148,12 @@ void Object::apply_transform(bool apply_to_motion)
if(apply_to_motion) {
Attribute *curve_attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if (curve_attr) {
+ if(curve_attr) {
/* apply transform to motion curve keys */
size_t steps_size = mesh->curve_keys.size() * (mesh->motion_steps - 1);
float4 *key_steps = curve_attr->data_float4();
- for (size_t i = 0; i < steps_size; i++) {
+ for(size_t i = 0; i < steps_size; i++) {
float3 co = transform_point(&tfm, float4_to_float3(key_steps[i]));
float radius = key_steps[i].w * scalar;
@@ -191,6 +193,7 @@ void Object::tag_update(Scene *scene)
}
}
+ scene->camera->need_flags_update = true;
scene->curve_system_manager->need_update = true;
scene->mesh_manager->need_update = true;
scene->object_manager->need_update = true;
@@ -377,6 +380,8 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene
void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
+ VLOG(1) << "Total " << scene->objects.size() << " objects.";
+
if(!need_update)
return;
@@ -402,8 +407,11 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc
}
}
-void ObjectManager::device_update_flags(Device *device, DeviceScene *dscene,
- Scene *scene, Progress& progress)
+void ObjectManager::device_update_flags(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& /*progress*/,
+ bool bounds_valid)
{
if(!need_update && !need_flags_update)
return;
@@ -418,9 +426,13 @@ void ObjectManager::device_update_flags(Device *device, DeviceScene *dscene,
uint *object_flag = dscene->object_flag.get_data();
vector<Object *> volume_objects;
+ bool has_volume_objects = false;
foreach(Object *object, scene->objects) {
if(object->mesh->has_volume) {
- volume_objects.push_back(object);
+ if(bounds_valid) {
+ volume_objects.push_back(object);
+ }
+ has_volume_objects = true;
}
}
@@ -433,15 +445,23 @@ void ObjectManager::device_update_flags(Device *device, DeviceScene *dscene,
object_flag[object_index] &= ~SD_OBJECT_HAS_VOLUME;
}
- foreach(Object *volume_object, volume_objects) {
- if(object == volume_object) {
- continue;
- }
- if(object->bounds.intersects(volume_object->bounds)) {
- object_flag[object_index] |= SD_OBJECT_INTERSECTS_VOLUME;
- break;
+ if(bounds_valid) {
+ foreach(Object *volume_object, volume_objects) {
+ if(object == volume_object) {
+ continue;
+ }
+ if(object->bounds.intersects(volume_object->bounds)) {
+ object_flag[object_index] |= SD_OBJECT_INTERSECTS_VOLUME;
+ break;
+ }
}
}
+ else if(has_volume_objects) {
+ /* Not really valid, but can't make more reliable in the case
+ * of bounds not being up to date.
+ */
+ object_flag[object_index] |= SD_OBJECT_INTERSECTS_VOLUME;
+ }
++object_index;
}
diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h
index acc08a0e204..379d1748cdd 100644
--- a/intern/cycles/render/object.h
+++ b/intern/cycles/render/object.h
@@ -77,7 +77,11 @@ public:
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_update_transforms(Device *device, DeviceScene *dscene, Scene *scene, uint *object_flag, Progress& progress);
- void device_update_flags(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
+ void device_update_flags(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& progress,
+ bool bounds_valid = true);
void device_free(Device *device, DeviceScene *dscene);
void tag_update(Scene *scene);
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index 9d6f412d9ce..a02f91ad2cf 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -67,7 +67,7 @@ OSLShaderManager::~OSLShaderManager()
texture_system_free();
}
-void OSLShaderManager::reset(Scene *scene)
+void OSLShaderManager::reset(Scene * /*scene*/)
{
shading_system_free();
shading_system_init();
@@ -75,6 +75,8 @@ void OSLShaderManager::reset(Scene *scene)
void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
+ VLOG(1) << "Total " << scene->shaders.size() << " shaders.";
+
if(!need_update)
return;
@@ -211,9 +213,9 @@ void OSLShaderManager::shading_system_init()
"__unused__",
"__unused__",
- "diffuse_ancestor", /* PATH_RAY_DIFFUSE_ANCESTOR */
- "glossy_ancestor", /* PATH_RAY_GLOSSY_ANCESTOR */
- "bssrdf_ancestor", /* PATH_RAY_BSSRDF_ANCESTOR */
+ "diffuse_ancestor", /* PATH_RAY_DIFFUSE_ANCESTOR */
+ "__unused__",
+ "__unused__",
"__unused__", /* PATH_RAY_SINGLE_PASS_DONE */
"volume_scatter", /* PATH_RAY_VOLUME_SCATTER */
};
@@ -414,7 +416,7 @@ string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input)
/* if output exists with the same name, add "In" suffix */
foreach(ShaderOutput *output, node->outputs) {
- if (strcmp(input->name, output->name)==0) {
+ if(strcmp(input->name, output->name)==0) {
sname += "In";
break;
}
@@ -434,7 +436,7 @@ string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output)
/* if input exists with the same name, add "Out" suffix */
foreach(ShaderInput *input, node->inputs) {
- if (strcmp(input->name, output->name)==0) {
+ if(strcmp(input->name, output->name)==0) {
sname += "Out";
break;
}
@@ -860,75 +862,75 @@ void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
#else
-void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
+void OSLCompiler::add(ShaderNode * /*node*/, const char * /*name*/, bool /*isfilepath*/)
{
}
-void OSLCompiler::parameter(const char *name, float f)
+void OSLCompiler::parameter(const char * /*name*/, float /*f*/)
{
}
-void OSLCompiler::parameter_color(const char *name, float3 f)
+void OSLCompiler::parameter_color(const char * /*name*/, float3 /*f*/)
{
}
-void OSLCompiler::parameter_vector(const char *name, float3 f)
+void OSLCompiler::parameter_vector(const char * /*name*/, float3 /*f*/)
{
}
-void OSLCompiler::parameter_point(const char *name, float3 f)
+void OSLCompiler::parameter_point(const char * /*name*/, float3 /*f*/)
{
}
-void OSLCompiler::parameter_normal(const char *name, float3 f)
+void OSLCompiler::parameter_normal(const char * /*name*/, float3 /*f*/)
{
}
-void OSLCompiler::parameter(const char *name, int f)
+void OSLCompiler::parameter(const char * /*name*/, int /*f*/)
{
}
-void OSLCompiler::parameter(const char *name, const char *s)
+void OSLCompiler::parameter(const char * /*name*/, const char * /*s*/)
{
}
-void OSLCompiler::parameter(const char *name, ustring s)
+void OSLCompiler::parameter(const char * /*name*/, ustring /*s*/)
{
}
-void OSLCompiler::parameter(const char *name, const Transform& tfm)
+void OSLCompiler::parameter(const char * /*name*/, const Transform& /*tfm*/)
{
}
-void OSLCompiler::parameter_array(const char *name, const float f[], int arraylen)
+void OSLCompiler::parameter_array(const char * /*name*/, const float /*f*/[], int /*arraylen*/)
{
}
-void OSLCompiler::parameter_color_array(const char *name, const float f[][3], int arraylen)
+void OSLCompiler::parameter_color_array(const char * /*name*/, const float /*f*/[][3], int /*arraylen*/)
{
}
-void OSLCompiler::parameter_vector_array(const char *name, const float f[][3], int arraylen)
+void OSLCompiler::parameter_vector_array(const char * /*name*/, const float /*f*/[][3], int /*arraylen*/)
{
}
-void OSLCompiler::parameter_normal_array(const char *name, const float f[][3], int arraylen)
+void OSLCompiler::parameter_normal_array(const char * /*name*/, const float /*f*/[][3], int /*arraylen*/)
{
}
-void OSLCompiler::parameter_point_array(const char *name, const float f[][3], int arraylen)
+void OSLCompiler::parameter_point_array(const char * /*name*/, const float /*f*/[][3], int /*arraylen*/)
{
}
-void OSLCompiler::parameter_array(const char *name, const int f[], int arraylen)
+void OSLCompiler::parameter_array(const char * /*name*/, const int /*f*/[], int /*arraylen*/)
{
}
-void OSLCompiler::parameter_array(const char *name, const char * const s[], int arraylen)
+void OSLCompiler::parameter_array(const char * /*name*/, const char * const /*s*/[], int /*arraylen*/)
{
}
-void OSLCompiler::parameter_array(const char *name, const Transform tfm[], int arraylen)
+void OSLCompiler::parameter_array(const char * /*name*/, const Transform /*tfm*/[], int /*arraylen*/)
{
}
diff --git a/intern/cycles/render/particles.cpp b/intern/cycles/render/particles.cpp
index f2f154cdab4..8f9e8c6d639 100644
--- a/intern/cycles/render/particles.cpp
+++ b/intern/cycles/render/particles.cpp
@@ -19,6 +19,7 @@
#include "scene.h"
#include "util_foreach.h"
+#include "util_logging.h"
#include "util_map.h"
#include "util_progress.h"
#include "util_vector.h"
@@ -92,6 +93,9 @@ void ParticleSystemManager::device_update_particles(Device *device, DeviceScene
void ParticleSystemManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
+ VLOG(1) << "Total " << scene->particle_systems.size()
+ << " particle systems.";
+
if(!need_update)
return;
@@ -111,7 +115,7 @@ void ParticleSystemManager::device_free(Device *device, DeviceScene *dscene)
dscene->particles.clear();
}
-void ParticleSystemManager::tag_update(Scene *scene)
+void ParticleSystemManager::tag_update(Scene * /*scene*/)
{
need_update = true;
}
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index 524574f096d..d0237919f89 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -43,7 +43,9 @@
CCL_NAMESPACE_BEGIN
-Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_)
+Scene::Scene(const SceneParams& params_,
+ const DeviceInfo& device_info_,
+ const bool free_data_after_update)
: params(params_)
{
device = NULL;
@@ -54,7 +56,7 @@ Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_)
film = new Film();
background = new Background();
light_manager = new LightManager();
- mesh_manager = new MeshManager();
+ mesh_manager = new MeshManager(free_data_after_update);
object_manager = new ObjectManager();
integrator = new Integrator();
image_manager = new ImageManager();
@@ -160,11 +162,6 @@ void Scene::device_update(Device *device_, Progress& progress)
if(progress.get_cancel() || device->have_error()) return;
- progress.set_status("Updating Images");
- image_manager->device_update(device, &dscene, progress);
-
- if(progress.get_cancel() || device->have_error()) return;
-
progress.set_status("Updating Background");
background->device_update(device, &dscene, this);
@@ -185,13 +182,18 @@ void Scene::device_update(Device *device_, Progress& progress)
if(progress.get_cancel() || device->have_error()) return;
+ progress.set_status("Updating Meshes");
+ mesh_manager->device_update(device, &dscene, this, progress);
+
+ if(progress.get_cancel() || device->have_error()) return;
+
progress.set_status("Updating Objects Flags");
object_manager->device_update_flags(device, &dscene, this, progress);
if(progress.get_cancel() || device->have_error()) return;
- progress.set_status("Updating Meshes");
- mesh_manager->device_update(device, &dscene, this, progress);
+ progress.set_status("Updating Images");
+ image_manager->device_update(device, &dscene, progress);
if(progress.get_cancel() || device->have_error()) return;
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index 53c3a95903c..f4980b3e0d3 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -62,6 +62,7 @@ class DeviceScene {
public:
/* BVH */
device_vector<float4> bvh_nodes;
+ device_vector<float4> bvh_leaf_nodes;
device_vector<uint> object_node;
device_vector<float4> tri_woop;
device_vector<uint> prim_type;
@@ -127,6 +128,7 @@ public:
enum BVHType { BVH_DYNAMIC, BVH_STATIC } bvh_type;
bool use_bvh_cache;
bool use_bvh_spatial_split;
+ bool use_bvh_triangle_storage;
bool use_qbvh;
bool persistent_data;
@@ -136,6 +138,7 @@ public:
bvh_type = BVH_DYNAMIC;
use_bvh_cache = false;
use_bvh_spatial_split = false;
+ use_bvh_triangle_storage = true;
use_qbvh = false;
persistent_data = false;
}
@@ -145,6 +148,7 @@ public:
&& bvh_type == params.bvh_type
&& use_bvh_cache == params.use_bvh_cache
&& use_bvh_spatial_split == params.use_bvh_spatial_split
+ && use_bvh_triangle_storage == params.use_bvh_triangle_storage
&& use_qbvh == params.use_qbvh
&& persistent_data == params.persistent_data); }
};
@@ -193,7 +197,9 @@ public:
/* mutex must be locked manually by callers */
thread_mutex mutex;
- Scene(const SceneParams& params, const DeviceInfo& device_info);
+ Scene(const SceneParams& params,
+ const DeviceInfo& device_info,
+ const bool free_data_after_update = false);
~Scene();
void device_update(Device *device, Progress& progress);
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index 99826aa4349..bd8a5aecf78 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -20,7 +20,10 @@
#include "buffers.h"
#include "camera.h"
#include "device.h"
+#include "graph.h"
#include "integrator.h"
+#include "mesh.h"
+#include "object.h"
#include "scene.h"
#include "session.h"
#include "bake.h"
@@ -77,6 +80,9 @@ Session::Session(const SessionParams& params_)
gpu_need_tonemap = false;
pause = false;
kernels_loaded = false;
+
+ /* TODO(sergey): Check if it's indeed optimal value for the split kernel. */
+ max_closure_global = 1;
}
Session::~Session()
@@ -405,6 +411,11 @@ bool Session::acquire_tile(Device *tile_device, RenderTile& rtile)
if(tile_buffers.size() == 0)
tile_buffers.resize(tile_manager.state.num_tiles, NULL);
+ /* In certain circumstances number of tiles in the tile manager could
+ * be changed. This is not supported by the progressive refine feature.
+ */
+ assert(tile_buffers.size() == tile_manager.state.num_tiles);
+
tilebuffers = tile_buffers[tile.index];
if(tilebuffers == NULL) {
tilebuffers = new RenderBuffers(tile_device);
@@ -593,6 +604,42 @@ void Session::run_cpu()
update_progressive_refine(true);
}
+DeviceRequestedFeatures Session::get_requested_device_features()
+{
+ /* TODO(sergey): Consider moving this to the Scene level. */
+ DeviceRequestedFeatures requested_features;
+ requested_features.experimental = params.experimental;
+ if(!params.background) {
+ requested_features.max_closure = 64;
+ requested_features.max_nodes_group = NODE_GROUP_LEVEL_MAX;
+ requested_features.nodes_features = NODE_FEATURE_ALL;
+ }
+ else {
+ requested_features.max_closure = get_max_closure_count();
+ scene->shader_manager->get_requested_features(
+ scene,
+ requested_features.max_nodes_group,
+ requested_features.nodes_features);
+ }
+
+ /* This features are not being tweaked as often as shaders,
+ * so could be done selective magic for the viewport as well.
+ */
+ requested_features.use_hair = false;
+ requested_features.use_object_motion = false;
+ requested_features.use_camera_motion = scene->camera->use_motion;
+ foreach(Object *object, scene->objects) {
+ Mesh *mesh = object->mesh;
+ if(mesh->curves.size() > 0) {
+ requested_features.use_hair = true;
+ }
+ requested_features.use_object_motion |= object->use_motion | mesh->use_motion_blur;
+ requested_features.use_camera_motion |= mesh->use_motion_blur;
+ }
+
+ return requested_features;
+}
+
void Session::load_kernels()
{
thread_scoped_lock scene_lock(scene->mutex);
@@ -600,7 +647,7 @@ void Session::load_kernels()
if(!kernels_loaded) {
progress.set_status("Loading render kernels (may take a few minutes the first time)");
- if(!device->load_kernels(params.experimental)) {
+ if(!device->load_kernels(get_requested_device_features())) {
string message = device->error_message();
if(message.empty())
message = "Failed loading render kernel, see console for errors";
@@ -765,6 +812,10 @@ void Session::update_scene()
progress.set_status("Updating Scene");
scene->device_update(device, progress);
}
+
+ if(clear_database_cb) {
+ clear_database_cb();
+ }
}
void Session::update_status_time(bool show_pause, bool show_done)
@@ -784,7 +835,10 @@ void Session::update_status_time(bool show_pause, bool show_done)
substatus = string_printf("Path Tracing Tile %d/%d", tile, num_tiles);
- if((is_gpu && !is_multidevice) || (is_cpu && num_tiles == 1)) {
+ if(((is_gpu && !is_multidevice) || (is_cpu && num_tiles == 1)) && !device->info.use_split_kernel) {
+ /* When using split-kernel (OpenCL) each thread in a tile will be working on a different
+ * sample. Can't display sample number when device uses split-kernel
+ */
/* when rendering on GPU multithreading happens within single tile, as in
* tiles are handling sequentially and in this case we could display
* currently rendering sample number
@@ -852,6 +906,7 @@ void Session::path_trace()
task.update_progress_sample = function_bind(&Session::update_progress_sample, this);
task.need_finish_queue = params.progressive_refine;
task.integrator_branched = scene->integrator->method == Integrator::BRANCHED_PATH;
+ task.requested_tile_size = params.tile_size;
device->task_add(task);
}
@@ -889,9 +944,9 @@ bool Session::update_progressive_refine(bool cancel)
double current_time = time_dt();
- if (current_time - last_update_time < params.progressive_update_timeout) {
+ if(current_time - last_update_time < params.progressive_update_timeout) {
/* if last sample was processed, we need to write buffers anyway */
- if (!write)
+ if(!write && sample != 1)
return false;
}
@@ -901,10 +956,14 @@ bool Session::update_progressive_refine(bool cancel)
rtile.buffers = buffers;
rtile.sample = sample;
- if(write)
- write_render_tile_cb(rtile);
- else
- update_render_tile_cb(rtile);
+ if(write) {
+ if(write_render_tile_cb)
+ write_render_tile_cb(rtile);
+ }
+ else {
+ if(update_render_tile_cb)
+ update_render_tile_cb(rtile);
+ }
}
}
@@ -927,4 +986,15 @@ void Session::device_free()
*/
}
+int Session::get_max_closure_count()
+{
+ int max_closures = 0;
+ for(int i = 0; i < scene->shaders.size(); i++) {
+ int num_closures = scene->shaders[i]->graph->get_num_closures();
+ max_closures = max(max_closures, num_closures);
+ }
+ max_closure_global = max(max_closure_global, max_closures);
+ return max_closure_global;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h
index c77652d3722..ab9f2ddb0f2 100644
--- a/intern/cycles/render/session.h
+++ b/intern/cycles/render/session.h
@@ -32,6 +32,7 @@ CCL_NAMESPACE_BEGIN
class BufferParams;
class Device;
class DeviceScene;
+class DeviceRequestedFeatures;
class DisplayBuffer;
class Progress;
class RenderBuffers;
@@ -125,8 +126,9 @@ public:
TileManager tile_manager;
Stats stats;
- boost::function<void(RenderTile&)> write_render_tile_cb;
- boost::function<void(RenderTile&)> update_render_tile_cb;
+ function<void(RenderTile&)> write_render_tile_cb;
+ function<void(RenderTile&)> update_render_tile_cb;
+ function<void(void)> clear_database_cb;
Session(const SessionParams& params);
~Session();
@@ -204,6 +206,16 @@ protected:
bool update_progressive_refine(bool cancel);
vector<RenderBuffers *> tile_buffers;
+
+ DeviceRequestedFeatures get_requested_device_features();
+
+ /* ** Split kernel routines ** */
+
+ /* Maximumnumber of closure during session lifetime. */
+ int max_closure_global;
+
+ /* Get maximum number of closures to be used in kernel. */
+ int get_max_closure_count();
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index 5899c562f72..31be2a3d3f4 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -15,7 +15,7 @@
*/
#include "background.h"
-#include "blackbody.h"
+#include "camera.h"
#include "device.h"
#include "graph.h"
#include "light.h"
@@ -32,6 +32,8 @@
CCL_NAMESPACE_BEGIN
+vector<float> ShaderManager::beckmann_table;
+
/* Beckmann sampling precomputed table, see bsdf_microfacet.h */
/* 2D slope distribution (alpha = 1.0) */
@@ -146,7 +148,6 @@ Shader::Shader()
has_surface_transparent = false;
has_surface_emission = false;
has_surface_bssrdf = false;
- has_converter_blackbody = false;
has_volume = false;
has_displacement = false;
has_bssrdf_bump = false;
@@ -240,7 +241,6 @@ void Shader::tag_used(Scene *scene)
ShaderManager::ShaderManager()
{
need_update = true;
- blackbody_table_offset = TABLE_OFFSET_INVALID;
beckmann_table_offset = TABLE_OFFSET_INVALID;
}
@@ -252,6 +252,8 @@ ShaderManager *ShaderManager::create(Scene *scene, int shadingsystem)
{
ShaderManager *manager;
+ (void)shadingsystem; /* Ignored when built without OSL. */
+
#ifdef WITH_OSL
if(shadingsystem == SHADINGSYSTEM_OSL)
manager = new OSLShaderManager();
@@ -321,7 +323,10 @@ void ShaderManager::device_update_shaders_used(Scene *scene)
scene->shaders[light->shader]->used = true;
}
-void ShaderManager::device_update_common(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
+void ShaderManager::device_update_common(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& /*progress*/)
{
device->tex_free(dscene->shader_flag);
dscene->shader_flag.clear();
@@ -332,7 +337,6 @@ void ShaderManager::device_update_common(Device *device, DeviceScene *dscene, Sc
uint shader_flag_size = scene->shaders.size()*4;
uint *shader_flag = dscene->shader_flag.resize(shader_flag_size);
uint i = 0;
- bool has_converter_blackbody = false;
bool has_volumes = false;
foreach(Shader *shader, scene->shaders) {
@@ -359,8 +363,6 @@ void ShaderManager::device_update_common(Device *device, DeviceScene *dscene, Sc
flag |= SD_HETEROGENEOUS_VOLUME;
if(shader->has_bssrdf_bump)
flag |= SD_HAS_BSSRDF_BUMP;
- if(shader->has_converter_blackbody)
- has_converter_blackbody = true;
if(shader->volume_sampling_method == VOLUME_SAMPLING_EQUIANGULAR)
flag |= SD_VOLUME_EQUIANGULAR;
if(shader->volume_sampling_method == VOLUME_SAMPLING_MULTIPLE_IMPORTANCE)
@@ -384,26 +386,16 @@ void ShaderManager::device_update_common(Device *device, DeviceScene *dscene, Sc
device->tex_alloc("__shader_flag", dscene->shader_flag);
- /* blackbody lookup table */
+ /* lookup tables */
KernelTables *ktables = &dscene->data.tables;
-
- if(has_converter_blackbody && blackbody_table_offset == TABLE_OFFSET_INVALID) {
- if(blackbody_table.size() == 0) {
- blackbody_table = blackbody_table_build();
- }
- blackbody_table_offset = scene->lookup_tables->add_table(dscene, blackbody_table);
-
- ktables->blackbody_offset = (int)blackbody_table_offset;
- }
- else if(!has_converter_blackbody && blackbody_table_offset != TABLE_OFFSET_INVALID) {
- scene->lookup_tables->remove_table(blackbody_table_offset);
- blackbody_table_offset = TABLE_OFFSET_INVALID;
- }
/* beckmann lookup table */
if(beckmann_table_offset == TABLE_OFFSET_INVALID) {
if(beckmann_table.size() == 0) {
- beckmann_table_build(beckmann_table);
+ thread_scoped_lock lock(lookup_table_mutex);
+ if(beckmann_table.size() == 0) {
+ beckmann_table_build(beckmann_table);
+ }
}
beckmann_table_offset = scene->lookup_tables->add_table(dscene, beckmann_table);
ktables->beckmann_offset = (int)beckmann_table_offset;
@@ -416,11 +408,6 @@ void ShaderManager::device_update_common(Device *device, DeviceScene *dscene, Sc
void ShaderManager::device_free_common(Device *device, DeviceScene *dscene, Scene *scene)
{
- if(blackbody_table_offset != TABLE_OFFSET_INVALID) {
- scene->lookup_tables->remove_table(blackbody_table_offset);
- blackbody_table_offset = TABLE_OFFSET_INVALID;
- }
-
if(beckmann_table_offset != TABLE_OFFSET_INVALID) {
scene->lookup_tables->remove_table(beckmann_table_offset);
beckmann_table_offset = TABLE_OFFSET_INVALID;
@@ -494,5 +481,45 @@ void ShaderManager::add_default(Scene *scene)
}
}
+/* NOTE: Expects max_group and features to be initialized in the callee. */
+void ShaderManager::get_requested_graph_features(ShaderGraph *graph,
+ int& max_group,
+ int& features)
+{
+ foreach(ShaderNode *node, graph->nodes) {
+ max_group = max(max_group, node->get_group());
+ features |= node->get_feature();
+ if(node->special_type == SHADER_SPECIAL_TYPE_CLOSURE) {
+ BsdfNode *bsdf_node = static_cast<BsdfNode*>(node);
+ if(CLOSURE_IS_VOLUME(bsdf_node->closure)) {
+ features |= NODE_FEATURE_VOLUME;
+ }
+ }
+ }
+}
+
+void ShaderManager::get_requested_features(Scene *scene,
+ int& max_group,
+ int& features)
+{
+ max_group = NODE_GROUP_LEVEL_0;
+ features = 0;
+ for(int i = 0; i < scene->shaders.size(); i++) {
+ Shader *shader = scene->shaders[i];
+ /* Gather requested features from all the nodes from the graph nodes. */
+ get_requested_graph_features(shader->graph, max_group, features);
+ /* Gather requested features from the graph itself. */
+ if(shader->graph_bump) {
+ get_requested_graph_features(shader->graph_bump,
+ max_group,
+ features);
+ }
+ ShaderNode *output_node = shader->graph->output();
+ if(output_node->input("Displacement")->link != NULL) {
+ features |= NODE_FEATURE_BUMP;
+ }
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h
index 1dee47c7731..64d45635ef1 100644
--- a/intern/cycles/render/shader.h
+++ b/intern/cycles/render/shader.h
@@ -36,6 +36,7 @@
#include "util_map.h"
#include "util_param.h"
#include "util_string.h"
+#include "util_thread.h"
#include "util_types.h"
CCL_NAMESPACE_BEGIN
@@ -103,7 +104,6 @@ public:
bool has_volume;
bool has_displacement;
bool has_surface_bssrdf;
- bool has_converter_blackbody;
bool has_bssrdf_bump;
bool has_heterogeneous_volume;
bool has_object_dependency;
@@ -165,17 +165,25 @@ public:
* have any shader assigned explicitly */
static void add_default(Scene *scene);
+ /* Selective nodes compilation. */
+ void get_requested_features(Scene *scene,
+ int& max_group,
+ int& features);
+
protected:
ShaderManager();
typedef unordered_map<ustring, uint, ustringHash> AttributeIDMap;
AttributeIDMap unique_attribute_id;
- vector<float> blackbody_table;
- vector<float> beckmann_table;
+ thread_mutex lookup_table_mutex;
+ static vector<float> beckmann_table;
- size_t blackbody_table_offset;
size_t beckmann_table_offset;
+
+ void get_requested_graph_features(ShaderGraph *graph,
+ int& max_group,
+ int& features);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/sky_model.cpp b/intern/cycles/render/sky_model.cpp
index adb07d9e288..c8a5dbe55e0 100644
--- a/intern/cycles/render/sky_model.cpp
+++ b/intern/cycles/render/sky_model.cpp
@@ -4,7 +4,7 @@ This source is published under the following 3-clause BSD license.
Copyright (c) 2012 - 2013, Lukas Hosek and Alexander Wilkie
All rights reserved.
-Redistribution and use in source and binary forms, with or without
+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
@@ -12,8 +12,8 @@ modification, are permitted provided that the following conditions are met:
* 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.
- * None of the names of the contributors may be used to endorse or promote
- products derived from this software without specific prior written
+ * None of the names of the 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
@@ -40,24 +40,24 @@ and the 2013 IEEE CG&A paper
"Adding a Solar Radiance Function to the Hosek Skylight Model"
- both by
+ both by
Lukas Hosek and Alexander Wilkie
Charles University in Prague, Czech Republic
Version: 1.4a, February 22nd, 2013
-
+
Version history:
1.4a February 22nd, 2013
- Removed unnecessary and counter-intuitive solar radius parameters
+ Removed unnecessary and counter-intuitive solar radius parameters
from the interface of the colourspace sky dome initialisation functions.
1.4 February 11th, 2013
Fixed a bug which caused the relative brightness of the solar disc
- and the sky dome to be off by a factor of about 6. The sun was too
- bright: this affected both normal and alien sun scenarios. The
+ and the sky dome to be off by a factor of about 6. The sun was too
+ bright: this affected both normal and alien sun scenarios. The
coefficients of the solar radiance function were changed to fix this.
1.3 January 21st, 2013 (not released to the public)
@@ -81,7 +81,7 @@ Version history:
the result of a simple conversion from spectral data via the CIE 2 degree
standard observer matching functions. Therefore, after multiplication
with 683 lm / W, the Y channel now corresponds to luminance in lm.
-
+
1.0 May 11th, 2012
Initial release.
@@ -110,7 +110,7 @@ CCL_NAMESPACE_BEGIN
// Some macro definitions that occur elsewhere in ART, and that have to be
// replicated to make this a stand-alone module.
-#ifndef MATH_PI
+#ifndef MATH_PI
#define MATH_PI 3.141592653589793
#endif
@@ -138,250 +138,231 @@ typedef const double *ArHosekSkyModel_Radiance_Dataset;
// internal functions
static void ArHosekSkyModel_CookConfiguration(
- ArHosekSkyModel_Dataset dataset,
- ArHosekSkyModelConfiguration config,
- double turbidity,
- double albedo,
- double solar_elevation
- )
+ ArHosekSkyModel_Dataset dataset,
+ ArHosekSkyModelConfiguration config,
+ double turbidity,
+ double albedo,
+ double solar_elevation)
{
- const double * elev_matrix;
-
- int int_turbidity = (int)turbidity;
- double turbidity_rem = turbidity - (double)int_turbidity;
-
- solar_elevation = pow(solar_elevation / (MATH_PI / 2.0), (1.0 / 3.0));
-
- // alb 0 low turb
-
- elev_matrix = dataset + ( 9 * 6 * (int_turbidity-1) );
-
-
- for( unsigned int i = 0; i < 9; ++i )
- {
- //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
- config[i] =
- (1.0-albedo) * (1.0 - turbidity_rem)
- * ( pow(1.0-solar_elevation, 5.0) * elev_matrix[i] +
- 5.0 * pow(1.0-solar_elevation, 4.0) * solar_elevation * elev_matrix[i+9] +
- 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[i+18] +
- 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[i+27] +
- 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[i+36] +
- pow(solar_elevation, 5.0) * elev_matrix[i+45]);
- }
+ const double * elev_matrix;
- // alb 1 low turb
- elev_matrix = dataset + (9*6*10 + 9*6*(int_turbidity-1));
- for(unsigned int i = 0; i < 9; ++i)
- {
- //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
- config[i] +=
- (albedo) * (1.0 - turbidity_rem)
- * ( pow(1.0-solar_elevation, 5.0) * elev_matrix[i] +
- 5.0 * pow(1.0-solar_elevation, 4.0) * solar_elevation * elev_matrix[i+9] +
- 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[i+18] +
- 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[i+27] +
- 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[i+36] +
- pow(solar_elevation, 5.0) * elev_matrix[i+45]);
- }
+ int int_turbidity = (int)turbidity;
+ double turbidity_rem = turbidity - (double)int_turbidity;
- if(int_turbidity == 10)
- return;
-
- // alb 0 high turb
- elev_matrix = dataset + (9*6*(int_turbidity));
- for(unsigned int i = 0; i < 9; ++i)
- {
- //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
- config[i] +=
- (1.0-albedo) * (turbidity_rem)
- * ( pow(1.0-solar_elevation, 5.0) * elev_matrix[i] +
- 5.0 * pow(1.0-solar_elevation, 4.0) * solar_elevation * elev_matrix[i+9] +
- 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[i+18] +
- 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[i+27] +
- 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[i+36] +
- pow(solar_elevation, 5.0) * elev_matrix[i+45]);
- }
+ solar_elevation = pow(solar_elevation / (MATH_PI / 2.0), (1.0 / 3.0));
+
+ // alb 0 low turb
- // alb 1 high turb
- elev_matrix = dataset + (9*6*10 + 9*6*(int_turbidity));
- for(unsigned int i = 0; i < 9; ++i)
- {
- //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
- config[i] +=
- (albedo) * (turbidity_rem)
- * ( pow(1.0-solar_elevation, 5.0) * elev_matrix[i] +
- 5.0 * pow(1.0-solar_elevation, 4.0) * solar_elevation * elev_matrix[i+9] +
- 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[i+18] +
- 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[i+27] +
- 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[i+36] +
- pow(solar_elevation, 5.0) * elev_matrix[i+45]);
+ elev_matrix = dataset + ( 9 * 6 * (int_turbidity-1));
+
+ for(unsigned int i = 0; i < 9; ++i) {
+ //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
+ config[i] =
+ (1.0-albedo) * (1.0 - turbidity_rem)
+ * ( pow(1.0-solar_elevation, 5.0) * elev_matrix[i] +
+ 5.0 * pow(1.0-solar_elevation, 4.0) * solar_elevation * elev_matrix[i+9] +
+ 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[i+18] +
+ 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[i+27] +
+ 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[i+36] +
+ pow(solar_elevation, 5.0) * elev_matrix[i+45]);
}
+
+ // alb 1 low turb
+ elev_matrix = dataset + (9*6*10 + 9*6*(int_turbidity-1));
+ for(unsigned int i = 0; i < 9; ++i) {
+ //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
+ config[i] +=
+ (albedo) * (1.0 - turbidity_rem)
+ * ( pow(1.0-solar_elevation, 5.0) * elev_matrix[i] +
+ 5.0 * pow(1.0-solar_elevation, 4.0) * solar_elevation * elev_matrix[i+9] +
+ 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[i+18] +
+ 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[i+27] +
+ 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[i+36] +
+ pow(solar_elevation, 5.0) * elev_matrix[i+45]);
+ }
+
+ if(int_turbidity == 10)
+ return;
+
+ // alb 0 high turb
+ elev_matrix = dataset + (9*6*(int_turbidity));
+ for(unsigned int i = 0; i < 9; ++i) {
+ //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
+ config[i] +=
+ (1.0-albedo) * (turbidity_rem)
+ * ( pow(1.0-solar_elevation, 5.0) * elev_matrix[i] +
+ 5.0 * pow(1.0-solar_elevation, 4.0) * solar_elevation * elev_matrix[i+9] +
+ 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[i+18] +
+ 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[i+27] +
+ 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[i+36] +
+ pow(solar_elevation, 5.0) * elev_matrix[i+45]);
+ }
+
+ // alb 1 high turb
+ elev_matrix = dataset + (9*6*10 + 9*6*(int_turbidity));
+ for(unsigned int i = 0; i < 9; ++i) {
+ //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
+ config[i] +=
+ (albedo) * (turbidity_rem)
+ * ( pow(1.0-solar_elevation, 5.0) * elev_matrix[i] +
+ 5.0 * pow(1.0-solar_elevation, 4.0) * solar_elevation * elev_matrix[i+9] +
+ 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[i+18] +
+ 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[i+27] +
+ 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[i+36] +
+ pow(solar_elevation, 5.0) * elev_matrix[i+45]);
+ }
}
static double ArHosekSkyModel_CookRadianceConfiguration(
- ArHosekSkyModel_Radiance_Dataset dataset,
- double turbidity,
- double albedo,
- double solar_elevation
- )
+ ArHosekSkyModel_Radiance_Dataset dataset,
+ double turbidity,
+ double albedo,
+ double solar_elevation)
{
- const double* elev_matrix;
-
- int int_turbidity = (int)turbidity;
- double turbidity_rem = turbidity - (double)int_turbidity;
- double res;
- solar_elevation = pow(solar_elevation / (MATH_PI / 2.0), (1.0 / 3.0));
-
- // alb 0 low turb
- elev_matrix = dataset + (6*(int_turbidity-1));
- //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
- res = (1.0-albedo) * (1.0 - turbidity_rem) *
- ( pow(1.0-solar_elevation, 5.0) * elev_matrix[0] +
- 5.0*pow(1.0-solar_elevation, 4.0)*solar_elevation * elev_matrix[1] +
- 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[2] +
- 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[3] +
- 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[4] +
- pow(solar_elevation, 5.0) * elev_matrix[5]);
-
- // alb 1 low turb
- elev_matrix = dataset + (6*10 + 6*(int_turbidity-1));
- //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
- res += (albedo) * (1.0 - turbidity_rem) *
- ( pow(1.0-solar_elevation, 5.0) * elev_matrix[0] +
- 5.0*pow(1.0-solar_elevation, 4.0)*solar_elevation * elev_matrix[1] +
- 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[2] +
- 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[3] +
- 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[4] +
- pow(solar_elevation, 5.0) * elev_matrix[5]);
- if(int_turbidity == 10)
- return res;
-
- // alb 0 high turb
- elev_matrix = dataset + (6*(int_turbidity));
- //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
- res += (1.0-albedo) * (turbidity_rem) *
- ( pow(1.0-solar_elevation, 5.0) * elev_matrix[0] +
- 5.0*pow(1.0-solar_elevation, 4.0)*solar_elevation * elev_matrix[1] +
- 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[2] +
- 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[3] +
- 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[4] +
- pow(solar_elevation, 5.0) * elev_matrix[5]);
-
- // alb 1 high turb
- elev_matrix = dataset + (6*10 + 6*(int_turbidity));
- //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
- res += (albedo) * (turbidity_rem) *
- ( pow(1.0-solar_elevation, 5.0) * elev_matrix[0] +
- 5.0*pow(1.0-solar_elevation, 4.0)*solar_elevation * elev_matrix[1] +
- 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[2] +
- 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[3] +
- 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[4] +
- pow(solar_elevation, 5.0) * elev_matrix[5]);
- return res;
+ const double* elev_matrix;
+
+ int int_turbidity = (int)turbidity;
+ double turbidity_rem = turbidity - (double)int_turbidity;
+ double res;
+ solar_elevation = pow(solar_elevation / (MATH_PI / 2.0), (1.0 / 3.0));
+
+ // alb 0 low turb
+ elev_matrix = dataset + (6*(int_turbidity-1));
+ //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
+ res = (1.0-albedo) * (1.0 - turbidity_rem) *
+ ( pow(1.0-solar_elevation, 5.0) * elev_matrix[0] +
+ 5.0*pow(1.0-solar_elevation, 4.0)*solar_elevation * elev_matrix[1] +
+ 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[2] +
+ 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[3] +
+ 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[4] +
+ pow(solar_elevation, 5.0) * elev_matrix[5]);
+
+ // alb 1 low turb
+ elev_matrix = dataset + (6*10 + 6*(int_turbidity-1));
+ //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
+ res += (albedo) * (1.0 - turbidity_rem) *
+ ( pow(1.0-solar_elevation, 5.0) * elev_matrix[0] +
+ 5.0*pow(1.0-solar_elevation, 4.0)*solar_elevation * elev_matrix[1] +
+ 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[2] +
+ 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[3] +
+ 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[4] +
+ pow(solar_elevation, 5.0) * elev_matrix[5]);
+ if(int_turbidity == 10)
+ return res;
+
+ // alb 0 high turb
+ elev_matrix = dataset + (6*(int_turbidity));
+ //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
+ res += (1.0-albedo) * (turbidity_rem) *
+ ( pow(1.0-solar_elevation, 5.0) * elev_matrix[0] +
+ 5.0*pow(1.0-solar_elevation, 4.0)*solar_elevation * elev_matrix[1] +
+ 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[2] +
+ 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[3] +
+ 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[4] +
+ pow(solar_elevation, 5.0) * elev_matrix[5]);
+
+ // alb 1 high turb
+ elev_matrix = dataset + (6*10 + 6*(int_turbidity));
+ //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
+ res += (albedo) * (turbidity_rem) *
+ ( pow(1.0-solar_elevation, 5.0) * elev_matrix[0] +
+ 5.0*pow(1.0-solar_elevation, 4.0)*solar_elevation * elev_matrix[1] +
+ 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[2] +
+ 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[3] +
+ 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[4] +
+ pow(solar_elevation, 5.0) * elev_matrix[5]);
+ return res;
}
static double ArHosekSkyModel_GetRadianceInternal(
- ArHosekSkyModelConfiguration configuration,
- double theta,
- double gamma
- )
+ ArHosekSkyModelConfiguration configuration,
+ double theta,
+ double gamma)
{
- const double expM = exp(configuration[4] * gamma);
- const double rayM = cos(gamma)*cos(gamma);
- const double mieM = (1.0 + cos(gamma)*cos(gamma)) / pow((1.0 + configuration[8]*configuration[8] - 2.0*configuration[8]*cos(gamma)), 1.5);
- const double zenith = sqrt(cos(theta));
+ const double expM = exp(configuration[4] * gamma);
+ const double rayM = cos(gamma)*cos(gamma);
+ const double mieM = (1.0 + cos(gamma)*cos(gamma)) / pow((1.0 + configuration[8]*configuration[8] - 2.0*configuration[8]*cos(gamma)), 1.5);
+ const double zenith = sqrt(cos(theta));
- return (1.0 + configuration[0] * exp(configuration[1] / (cos(theta) + 0.01))) *
+ return (1.0 + configuration[0] * exp(configuration[1] / (cos(theta) + 0.01))) *
(configuration[2] + configuration[3] * expM + configuration[5] * rayM + configuration[6] * mieM + configuration[7] * zenith);
}
-void arhosekskymodelstate_free(
- ArHosekSkyModelState * state
- )
+void arhosekskymodelstate_free(ArHosekSkyModelState * state)
{
- free(state);
+ free(state);
}
-double arhosekskymodel_radiance(
- ArHosekSkyModelState * state,
- double theta,
- double gamma,
- double wavelength
- )
+double arhosekskymodel_radiance(ArHosekSkyModelState *state,
+ double theta,
+ double gamma,
+ double wavelength)
{
- int low_wl = (int)((wavelength - 320.0) / 40.0);
-
- if ( low_wl < 0 || low_wl >= 11 )
- return 0.0f;
-
- double interp = fmod((wavelength - 320.0 ) / 40.0, 1.0);
-
- double val_low =
- ArHosekSkyModel_GetRadianceInternal(
- state->configs[low_wl],
- theta,
- gamma
- )
- * state->radiances[low_wl]
- * state->emission_correction_factor_sky[low_wl];
-
- if ( interp < 1e-6 )
- return val_low;
-
- double result = ( 1.0 - interp ) * val_low;
-
- if ( low_wl+1 < 11 )
- {
- result +=
- interp
- * ArHosekSkyModel_GetRadianceInternal(
- state->configs[low_wl+1],
- theta,
- gamma
- )
- * state->radiances[low_wl+1]
- * state->emission_correction_factor_sky[low_wl+1];
- }
-
- return result;
+ int low_wl = (int)((wavelength - 320.0) / 40.0);
+
+ if(low_wl < 0 || low_wl >= 11)
+ return 0.0f;
+
+ double interp = fmod((wavelength - 320.0 ) / 40.0, 1.0);
+
+ double val_low =
+ ArHosekSkyModel_GetRadianceInternal(
+ state->configs[low_wl],
+ theta,
+ gamma)
+ * state->radiances[low_wl]
+ * state->emission_correction_factor_sky[low_wl];
+
+ if(interp < 1e-6)
+ return val_low;
+
+ double result = ( 1.0 - interp ) * val_low;
+
+ if(low_wl+1 < 11) {
+ result +=
+ interp
+ * ArHosekSkyModel_GetRadianceInternal(
+ state->configs[low_wl+1],
+ theta,
+ gamma)
+ * state->radiances[low_wl+1]
+ * state->emission_correction_factor_sky[low_wl+1];
+ }
+
+ return result;
}
// xyz and rgb versions
-ArHosekSkyModelState * arhosek_xyz_skymodelstate_alloc_init(
- const double turbidity,
- const double albedo,
- const double elevation
- )
+ArHosekSkyModelState * arhosek_xyz_skymodelstate_alloc_init(
+ const double turbidity,
+ const double albedo,
+ const double elevation)
{
- ArHosekSkyModelState * state = ALLOC(ArHosekSkyModelState);
-
- state->solar_radius = TERRESTRIAL_SOLAR_RADIUS;
- state->turbidity = turbidity;
- state->albedo = albedo;
- state->elevation = elevation;
-
- for( unsigned int channel = 0; channel < 3; ++channel )
- {
- ArHosekSkyModel_CookConfiguration(
- datasetsXYZ[channel],
- state->configs[channel],
- turbidity,
- albedo,
- elevation
- );
-
- state->radiances[channel] =
- ArHosekSkyModel_CookRadianceConfiguration(
- datasetsXYZRad[channel],
- turbidity,
- albedo,
- elevation
- );
+ ArHosekSkyModelState * state = ALLOC(ArHosekSkyModelState);
+
+ state->solar_radius = TERRESTRIAL_SOLAR_RADIUS;
+ state->turbidity = turbidity;
+ state->albedo = albedo;
+ state->elevation = elevation;
+
+ for(unsigned int channel = 0; channel < 3; ++channel) {
+ ArHosekSkyModel_CookConfiguration(
+ datasetsXYZ[channel],
+ state->configs[channel],
+ turbidity,
+ albedo,
+ elevation);
+
+ state->radiances[channel] =
+ ArHosekSkyModel_CookRadianceConfiguration(
+ datasetsXYZRad[channel],
+ turbidity,
+ albedo,
+ elevation);
}
-
+
return state;
}
diff --git a/intern/cycles/render/sky_model.h b/intern/cycles/render/sky_model.h
index 3814543c8b6..237e4e61bf5 100644
--- a/intern/cycles/render/sky_model.h
+++ b/intern/cycles/render/sky_model.h
@@ -4,7 +4,7 @@ This source is published under the following 3-clause BSD license.
Copyright (c) 2012 - 2013, Lukas Hosek and Alexander Wilkie
All rights reserved.
-Redistribution and use in source and binary forms, with or without
+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
@@ -12,8 +12,8 @@ modification, are permitted provided that the following conditions are met:
* 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.
- * None of the names of the contributors may be used to endorse or promote
- products derived from this software without specific prior written
+ * None of the names of the 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
@@ -41,24 +41,24 @@ and the 2013 IEEE CG&A paper
"Adding a Solar Radiance Function to the Hosek Skylight Model"
- both by
+ both by
Lukas Hosek and Alexander Wilkie
Charles University in Prague, Czech Republic
Version: 1.4a, February 22nd, 2013
-
+
Version history:
1.4a February 22nd, 2013
- Removed unnecessary and counter-intuitive solar radius parameters
+ Removed unnecessary and counter-intuitive solar radius parameters
from the interface of the colourspace sky dome initialisation functions.
1.4 February 11th, 2013
Fixed a bug which caused the relative brightness of the solar disc
- and the sky dome to be off by a factor of about 6. The sun was too
- bright: this affected both normal and alien sun scenarios. The
+ and the sky dome to be off by a factor of about 6. The sun was too
+ bright: this affected both normal and alien sun scenarios. The
coefficients of the solar radiance function were changed to fix this.
1.3 January 21st, 2013 (not released to the public)
@@ -82,7 +82,7 @@ Version history:
the result of a simple conversion from spectral data via the CIE 2 degree
standard observer matching functions. Therefore, after multiplication
with 683 lm / W, the Y channel now corresponds to luminance in lm.
-
+
1.0 May 11th, 2012
Initial release.
@@ -96,9 +96,9 @@ an updated version of this code has been published!
/*
This code is taken from ART, a rendering research system written in a
-mix of C99 / Objective C. Since ART is not a small system and is intended to
-be inter-operable with other libraries, and since C does not have namespaces,
-the structures and functions in ART all have to have somewhat wordy
+mix of C99 / Objective C. Since ART is not a small system and is intended to
+be inter-operable with other libraries, and since C does not have namespaces,
+the structures and functions in ART all have to have somewhat wordy
canonical names that begin with Ar.../ar..., like those seen in this example.
Usage information:
@@ -119,7 +119,7 @@ snippet, we assume that 'albedo' is defined as
double albedo[num_channels];
-with a ground albedo value between [0,1] for each channel. The solar elevation
+with a ground albedo value between [0,1] for each channel. The solar elevation
is given in radians.
for ( unsigned int i = 0; i < num_channels; i++ )
@@ -130,11 +130,11 @@ is given in radians.
solarElevation
);
-Note that starting with version 1.3, there is also a second initialisation
-function which generates skydome states for different solar emission spectra
+Note that starting with version 1.3, there is also a second initialisation
+function which generates skydome states for different solar emission spectra
and solar radii: 'arhosekskymodelstate_alienworld_alloc_init()'.
-See the notes about the "Alien World" functionality provided further down for a
+See the notes about the "Alien World" functionality provided further down for a
discussion of the usefulness and limits of that second initalisation function.
Sky model states that have been initialized with either function behave in a
completely identical fashion during use and cleanup.
@@ -155,7 +155,7 @@ on the skydome determined via the angles theta and gamma works as follows:
gamma,
channel_center[i]
);
-
+
The variable "channel_center" is assumed to hold the channel center wavelengths
for each of the num_channels samples of the spectrum we are building.
@@ -188,114 +188,114 @@ by calling arhosek_rgb_skymodelstate_alloc_init.
Solar Radiance Function
-----------------------
-For each position on the solar disc, this function returns the entire radiance
-one sees - direct emission, as well as in-scattered light in the area of the
-solar disc. The latter is important for low solar elevations - nice images of
-the setting sun would not be possible without this. This is also the reason why
-this function, just like the regular sky dome model evaluation function, needs
-access to the sky dome data structures, as these provide information on
+For each position on the solar disc, this function returns the entire radiance
+one sees - direct emission, as well as in-scattered light in the area of the
+solar disc. The latter is important for low solar elevations - nice images of
+the setting sun would not be possible without this. This is also the reason why
+this function, just like the regular sky dome model evaluation function, needs
+access to the sky dome data structures, as these provide information on
in-scattered radiance.
CAVEAT #1: in this release, this function is only provided in spectral form!
RGB/XYZ versions to follow at a later date.
-CAVEAT #2: (fixed from release 1.3 onwards)
+CAVEAT #2: (fixed from release 1.3 onwards)
CAVEAT #3: limb darkening renders the brightness of the solar disc
inhomogeneous even for high solar elevations - only taking a single
sample at the centre of the sun will yield an incorrect power
estimate for the solar disc! Always take multiple random samples
across the entire solar disc to estimate its power!
-
+
CAVEAT #4: in this version, the limb darkening calculations still use a fairly
- computationally expensive 5th order polynomial that was directly
+ computationally expensive 5th order polynomial that was directly
taken from astronomical literature. For the purposes of Computer
- Graphics, this is needlessly accurate, though, and will be replaced
+ Graphics, this is needlessly accurate, though, and will be replaced
by a cheaper approximation in a future release.
"Alien World" functionality
---------------------------
-The Hosek sky model can be used to roughly (!) predict the appearance of
-outdoor scenes on earth-like planets, i.e. planets of a similar size and
-atmospheric make-up. Since the spectral version of our model predicts sky dome
-luminance patterns and solar radiance independently for each waveband, and
-since the intensity of each waveband is solely dependent on the input radiance
-from the star that the world in question is orbiting, it is trivial to re-scale
+The Hosek sky model can be used to roughly (!) predict the appearance of
+outdoor scenes on earth-like planets, i.e. planets of a similar size and
+atmospheric make-up. Since the spectral version of our model predicts sky dome
+luminance patterns and solar radiance independently for each waveband, and
+since the intensity of each waveband is solely dependent on the input radiance
+from the star that the world in question is orbiting, it is trivial to re-scale
the wavebands to match a different star radiance.
-At least in theory, the spectral version of the model has always been capable
-of this sort of thing, and the actual sky dome and solar radiance models were
+At least in theory, the spectral version of the model has always been capable
+of this sort of thing, and the actual sky dome and solar radiance models were
actually not altered at all in this release. All we did was to add some support
-functionality for doing this more easily with the existing data and functions,
+functionality for doing this more easily with the existing data and functions,
and to add some explanations.
Just use 'arhosekskymodelstate_alienworld_alloc_init()' to initialise the sky
-model states (you will have to provide values for star temperature and solar
-intensity compared to the terrestrial sun), and do everything else as you
+model states (you will have to provide values for star temperature and solar
+intensity compared to the terrestrial sun), and do everything else as you
did before.
-CAVEAT #1: we assume the emission of the star that illuminates the alien world
- to be a perfect blackbody emission spectrum. This is never entirely
- realistic - real star emission spectra are considerably more complex
- than this, mainly due to absorption effects in the outer layers of
- stars. However, blackbody spectra are a reasonable first assumption
- in a usage scenario like this, where 100% accuracy is simply not
- necessary: for rendering purposes, there are likely no visible
- differences between a highly accurate solution based on a more
+CAVEAT #1: we assume the emission of the star that illuminates the alien world
+ to be a perfect blackbody emission spectrum. This is never entirely
+ realistic - real star emission spectra are considerably more complex
+ than this, mainly due to absorption effects in the outer layers of
+ stars. However, blackbody spectra are a reasonable first assumption
+ in a usage scenario like this, where 100% accuracy is simply not
+ necessary: for rendering purposes, there are likely no visible
+ differences between a highly accurate solution based on a more
involved simulation, and this approximation.
CAVEAT #2: we always use limb darkening data from our own sun to provide this
- "appearance feature", even for suns of strongly different
- temperature. Which is presumably not very realistic, but (as with
- the unaltered blackbody spectrum from caveat #1) probably not a bad
+ "appearance feature", even for suns of strongly different
+ temperature. Which is presumably not very realistic, but (as with
+ the unaltered blackbody spectrum from caveat #1) probably not a bad
first guess, either. If you need more accuracy than we provide here,
please make inquiries with a friendly astro-physicst of your choice.
-CAVEAT #3: you have to provide a value for the solar intensity of the star
- which illuminates the alien world. For this, please bear in mind
- that there is very likely a comparatively tight range of absolute
- solar irradiance values for which an earth-like planet with an
- atmosphere like the one we assume in our model can exist in the
+CAVEAT #3: you have to provide a value for the solar intensity of the star
+ which illuminates the alien world. For this, please bear in mind
+ that there is very likely a comparatively tight range of absolute
+ solar irradiance values for which an earth-like planet with an
+ atmosphere like the one we assume in our model can exist in the
first place!
-
- Too much irradiance, and the atmosphere probably boils off into
- space, too little, it freezes. Which means that stars of
- considerably different emission colour than our sun will have to be
- fairly different in size from it, to still provide a reasonable and
- inhabitable amount of irradiance. Red stars will need to be much
- larger than our sun, while white or blue stars will have to be
- comparatively tiny. The initialisation function handles this and
+
+ Too much irradiance, and the atmosphere probably boils off into
+ space, too little, it freezes. Which means that stars of
+ considerably different emission colour than our sun will have to be
+ fairly different in size from it, to still provide a reasonable and
+ inhabitable amount of irradiance. Red stars will need to be much
+ larger than our sun, while white or blue stars will have to be
+ comparatively tiny. The initialisation function handles this and
computes a plausible solar radius for a given emission spectrum. In
terms of absolute radiometric values, you should probably not stray
all too far from a solar intensity value of 1.0.
-CAVEAT #4: although we now support different solar radii for the actual solar
- disc, the sky dome luminance patterns are *not* parameterised by
- this value - i.e. the patterns stay exactly the same for different
- solar radii! Which is of course not correct. But in our experience,
- solar discs up to several degrees in diameter (! - our own sun is
- half a degree across) do not cause the luminance patterns on the sky
- to change perceptibly. The reason we know this is that we initially
- used unrealistically large suns in our brute force path tracer, in
- order to improve convergence speeds (which in the beginning were
- abysmal). Later, we managed to do the reference renderings much
- faster even with realistically small suns, and found that there was
- no real difference in skydome appearance anyway.
- Conclusion: changing the solar radius should not be over-done, so
- close orbits around red supergiants are a no-no. But for the
- purposes of getting a fairly credible first impression of what an
- alien world with a reasonably sized sun would look like, what we are
+CAVEAT #4: although we now support different solar radii for the actual solar
+ disc, the sky dome luminance patterns are *not* parameterised by
+ this value - i.e. the patterns stay exactly the same for different
+ solar radii! Which is of course not correct. But in our experience,
+ solar discs up to several degrees in diameter (! - our own sun is
+ half a degree across) do not cause the luminance patterns on the sky
+ to change perceptibly. The reason we know this is that we initially
+ used unrealistically large suns in our brute force path tracer, in
+ order to improve convergence speeds (which in the beginning were
+ abysmal). Later, we managed to do the reference renderings much
+ faster even with realistically small suns, and found that there was
+ no real difference in skydome appearance anyway.
+ Conclusion: changing the solar radius should not be over-done, so
+ close orbits around red supergiants are a no-no. But for the
+ purposes of getting a fairly credible first impression of what an
+ alien world with a reasonably sized sun would look like, what we are
doing here is probably still o.k.
-HINT #1: if you want to model the sky of an earth-like planet that orbits
- a binary star, just super-impose two of these models with solar
+HINT #1: if you want to model the sky of an earth-like planet that orbits
+ a binary star, just super-impose two of these models with solar
intensity of ~0.5 each, and closely spaced solar positions. Light is
additive, after all. Tattooine, here we come... :-)
P.S. according to Star Wars canon, Tattooine orbits a binary
- that is made up of a G and K class star, respectively.
- So ~5500K and ~4200K should be good first guesses for their
+ that is made up of a G and K class star, respectively.
+ So ~5500K and ~4200K should be good first guesses for their
temperature. Just in case you were wondering, after reading the
previous paragraph.
*/
@@ -316,37 +316,37 @@ typedef double ArHosekSkyModelConfiguration[9];
---------------------------
This struct holds the pre-computation data for one particular albedo value.
- Most fields are self-explanatory, but users should never directly
- manipulate any of them anyway. The only consistent way to manipulate such
- structs is via the functions 'arhosekskymodelstate_alloc_init' and
+ Most fields are self-explanatory, but users should never directly
+ manipulate any of them anyway. The only consistent way to manipulate such
+ structs is via the functions 'arhosekskymodelstate_alloc_init' and
'arhosekskymodelstate_free'.
-
+
'emission_correction_factor_sky'
'emission_correction_factor_sun'
- The original model coefficients were fitted against the emission of
+ The original model coefficients were fitted against the emission of
our local sun. If a different solar emission is desired (i.e. if the
- model is being used to predict skydome appearance for an earth-like
- planet that orbits a different star), these correction factors, which
- are determined during the alloc_init step, are applied to each waveband
- separately (they default to 1.0 in normal usage). This is the simplest
- way to retrofit this sort of capability to the existing model. The
- different factors for sky and sun are needed since the solar disc may
+ model is being used to predict skydome appearance for an earth-like
+ planet that orbits a different star), these correction factors, which
+ are determined during the alloc_init step, are applied to each waveband
+ separately (they default to 1.0 in normal usage). This is the simplest
+ way to retrofit this sort of capability to the existing model. The
+ different factors for sky and sun are needed since the solar disc may
be of a different size compared to the terrestrial sun.
---------------------------------------------------------------------------- */
typedef struct ArHosekSkyModelState
{
- ArHosekSkyModelConfiguration configs[11];
- double radiances[11];
- double turbidity;
- double solar_radius;
- double emission_correction_factor_sky[11];
- double emission_correction_factor_sun[11];
- double albedo;
- double elevation;
-}
+ ArHosekSkyModelConfiguration configs[11];
+ double radiances[11];
+ double turbidity;
+ double solar_radius;
+ double emission_correction_factor_sky[11];
+ double emission_correction_factor_sun[11];
+ double albedo;
+ double elevation;
+}
ArHosekSkyModelState;
/* ----------------------------------------------------------------------------
@@ -358,11 +358,10 @@ ArHosekSkyModelState;
---------------------------------------------------------------------------- */
-ArHosekSkyModelState * arhosekskymodelstate_alloc_init(
- const double solar_elevation,
- const double atmospheric_turbidity,
- const double ground_albedo
- );
+ArHosekSkyModelState *arhosekskymodelstate_alloc_init(
+ const double solar_elevation,
+ const double atmospheric_turbidity,
+ const double ground_albedo);
/* ----------------------------------------------------------------------------
@@ -375,78 +374,67 @@ ArHosekSkyModelState * arhosekskymodelstate_alloc_init(
'solar_intensity' controls the overall brightness of the sky, relative
to the solar irradiance on Earth. A value of 1.0 yields a sky dome that
is, on average over the wavelenghts covered in the model (!), as bright
- as the terrestrial sky in radiometric terms.
-
- Which means that the solar radius has to be adjusted, since the
- emissivity of a solar surface with a given temperature is more or less
- fixed. So hotter suns have to be smaller to be equally bright as the
+ as the terrestrial sky in radiometric terms.
+
+ Which means that the solar radius has to be adjusted, since the
+ emissivity of a solar surface with a given temperature is more or less
+ fixed. So hotter suns have to be smaller to be equally bright as the
terrestrial sun, while cooler suns have to be larger. Note that there are
limits to the validity of the luminance patterns of the underlying model:
see the discussion above for more on this. In particular, an alien sun with
a surface temperature of only 2000 Kelvin has to be very large if it is
- to be as bright as the terrestrial sun - so large that the luminance
+ to be as bright as the terrestrial sun - so large that the luminance
patterns are no longer a really good fit in that case.
-
+
If you need information about the solar radius that the model computes
- for a given temperature (say, for light source sampling purposes), you
- have to query the 'solar_radius' variable of the sky model state returned
+ for a given temperature (say, for light source sampling purposes), you
+ have to query the 'solar_radius' variable of the sky model state returned
*after* running this function.
---------------------------------------------------------------------------- */
-ArHosekSkyModelState * arhosekskymodelstate_alienworld_alloc_init(
- const double solar_elevation,
- const double solar_intensity,
- const double solar_surface_temperature_kelvin,
- const double atmospheric_turbidity,
- const double ground_albedo
- );
-
-void arhosekskymodelstate_free(
- ArHosekSkyModelState * state
- );
-
-double arhosekskymodel_radiance(
- ArHosekSkyModelState * state,
- double theta,
- double gamma,
- double wavelength
- );
+ArHosekSkyModelState* arhosekskymodelstate_alienworld_alloc_init(
+ const double solar_elevation,
+ const double solar_intensity,
+ const double solar_surface_temperature_kelvin,
+ const double atmospheric_turbidity,
+ const double ground_albedo);
+
+void arhosekskymodelstate_free(ArHosekSkyModelState *state);
+
+double arhosekskymodel_radiance(ArHosekSkyModelState *state,
+ double theta,
+ double gamma,
+ double wavelength);
// CIE XYZ and RGB versions
ArHosekSkyModelState * arhosek_xyz_skymodelstate_alloc_init(
- const double turbidity,
- const double albedo,
- const double elevation
- );
+ const double turbidity,
+ const double albedo,
+ const double elevation);
ArHosekSkyModelState * arhosek_rgb_skymodelstate_alloc_init(
- const double turbidity,
- const double albedo,
- const double elevation
- );
+ const double turbidity,
+ const double albedo,
+ const double elevation);
-double arhosek_tristim_skymodel_radiance(
- ArHosekSkyModelState * state,
- double theta,
- double gamma,
- int channel
- );
+double arhosek_tristim_skymodel_radiance(ArHosekSkyModelState* state,
+ double theta,
+ double gamma,
+ int channel);
// Delivers the complete function: sky + sun, including limb darkening.
// Please read the above description before using this - there are several
// caveats!
-double arhosekskymodel_solar_radiance(
- ArHosekSkyModelState * state,
- double theta,
- double gamma,
- double wavelength
- );
+double arhosekskymodel_solar_radiance(ArHosekSkyModelState* state,
+ double theta,
+ double gamma,
+ double wavelength);
#endif // _SKY_MODEL_H_
diff --git a/intern/cycles/render/sky_model_data.h b/intern/cycles/render/sky_model_data.h
index 4171bd12756..e6f3f761532 100644
--- a/intern/cycles/render/sky_model_data.h
+++ b/intern/cycles/render/sky_model_data.h
@@ -4,7 +4,7 @@ This source is published under the following 3-clause BSD license.
Copyright (c) 2012 - 2013, Lukas Hosek and Alexander Wilkie
All rights reserved.
-Redistribution and use in source and binary forms, with or without
+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
@@ -12,8 +12,8 @@ modification, are permitted provided that the following conditions are met:
* 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.
- * None of the names of the contributors may be used to endorse or promote
- products derived from this software without specific prior written
+ * None of the names of the 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
@@ -41,24 +41,24 @@ and the 2013 IEEE CG&A paper
"Adding a Solar Radiance Function to the Hosek Skylight Model"
- both by
+ both by
Lukas Hosek and Alexander Wilkie
Charles University in Prague, Czech Republic
Version: 1.4a, February 22nd, 2013
-
+
Version history:
1.4a February 22nd, 2013
- Removed unnecessary and counter-intuitive solar radius parameters
+ Removed unnecessary and counter-intuitive solar radius parameters
from the interface of the colourspace sky dome initialisation functions.
1.4 February 11th, 2013
Fixed a bug which caused the relative brightness of the solar disc
- and the sky dome to be off by a factor of about 6. The sun was too
- bright: this affected both normal and alien sun scenarios. The
+ and the sky dome to be off by a factor of about 6. The sun was too
+ bright: this affected both normal and alien sun scenarios. The
coefficients of the solar radiance function were changed to fix this.
1.3 January 21st, 2013 (not released to the public)
@@ -82,7 +82,7 @@ Version history:
the result of a simple conversion from spectral data via the CIE 2 degree
standard observer matching functions. Therefore, after multiplication
with 683 lm / W, the Y channel now corresponds to luminance in lm.
-
+
1.0 May 11th, 2012
Initial release.
@@ -96,15 +96,14 @@ CCL_NAMESPACE_BEGIN
/*
-This file contains the coefficient data for the XYZ colour space version of
+This file contains the coefficient data for the XYZ colour space version of
the model.
*/
// Uses Sep 9 pattern / Aug 23 mean dataset
-static const double datasetXYZ1[] =
-{
+static const double datasetXYZ1[] = {
// albedo 0, turbidity 1
-1.117001e+000,
-1.867262e-001,
@@ -3849,15 +3848,13 @@ static const double datasetXYZRad3[] =
-static const double* datasetsXYZ[] =
-{
+static const double* datasetsXYZ[] = {
datasetXYZ1,
datasetXYZ2,
datasetXYZ3
};
-static const double* datasetsXYZRad[] =
-{
+static const double* datasetsXYZRad[] = {
datasetXYZRad1,
datasetXYZRad2,
datasetXYZRad3
diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp
index 2e3abfcffb9..d0bd34915df 100644
--- a/intern/cycles/render/svm.cpp
+++ b/intern/cycles/render/svm.cpp
@@ -24,6 +24,7 @@
#include "svm.h"
#include "util_debug.h"
+#include "util_logging.h"
#include "util_foreach.h"
#include "util_progress.h"
@@ -39,12 +40,14 @@ SVMShaderManager::~SVMShaderManager()
{
}
-void SVMShaderManager::reset(Scene *scene)
+void SVMShaderManager::reset(Scene * /*scene*/)
{
}
void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
+ VLOG(1) << "Total " << scene->shaders.size() << " shaders.";
+
if(!need_update)
return;
@@ -354,7 +357,7 @@ uint SVMCompiler::attribute(AttributeStandard std)
return shader_manager->get_attribute_id(std);
}
-bool SVMCompiler::node_skip_input(ShaderNode *node, ShaderInput *input)
+bool SVMCompiler::node_skip_input(ShaderNode * /*node*/, ShaderInput *input)
{
/* nasty exception .. */
if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->name == ustring("bump"))
@@ -390,10 +393,6 @@ void SVMCompiler::generate_node(ShaderNode *node, set<ShaderNode*>& done)
current_shader->has_heterogeneous_volume = true;
}
- /* detect if we have a blackbody converter, to prepare lookup table */
- if(node->has_converter_blackbody())
- current_shader->has_converter_blackbody = true;
-
if(node->has_object_dependency()) {
current_shader->has_object_dependency = true;
}
@@ -713,7 +712,6 @@ void SVMCompiler::compile(Shader *shader, vector<int4>& global_svm_nodes, int in
shader->has_surface_transparent = false;
shader->has_surface_bssrdf = false;
shader->has_bssrdf_bump = false;
- shader->has_converter_blackbody = false;
shader->has_volume = false;
shader->has_displacement = false;
shader->has_heterogeneous_volume = false;
diff --git a/intern/cycles/render/tables.cpp b/intern/cycles/render/tables.cpp
index faf7ea3409b..ad3f4866072 100644
--- a/intern/cycles/render/tables.cpp
+++ b/intern/cycles/render/tables.cpp
@@ -19,6 +19,7 @@
#include "tables.h"
#include "util_debug.h"
+#include "util_logging.h"
CCL_NAMESPACE_BEGIN
@@ -36,6 +37,8 @@ LookupTables::~LookupTables()
void LookupTables::device_update(Device *device, DeviceScene *dscene)
{
+ VLOG(1) << "Total " << lookup_tables.size() << " lookup tables.";
+
if(!need_update)
return;
diff --git a/intern/cycles/render/tile.cpp b/intern/cycles/render/tile.cpp
index 675f49ec300..7e68ce84d94 100644
--- a/intern/cycles/render/tile.cpp
+++ b/intern/cycles/render/tile.cpp
@@ -28,6 +28,7 @@ TileManager::TileManager(bool progressive_, int num_samples_, int2 tile_size_, i
tile_size = tile_size_;
tile_order = tile_order_;
start_resolution = start_resolution_;
+ num_samples = num_samples_;
num_devices = num_devices_;
preserve_tile_device = preserve_tile_device_;
background = background_;
@@ -234,7 +235,7 @@ bool TileManager::next_tile(Tile& tile, int device)
{
list<Tile>::iterator tile_it;
- if (background)
+ if(background)
tile_it = next_background_tile(device, tile_order);
else
tile_it = next_viewport_tile(device);
diff --git a/intern/cycles/subd/subd_mesh.cpp b/intern/cycles/subd/subd_mesh.cpp
index 0db20656f39..17a730e5efe 100644
--- a/intern/cycles/subd/subd_mesh.cpp
+++ b/intern/cycles/subd/subd_mesh.cpp
@@ -109,8 +109,8 @@ public:
evalctrl.EvalLimitSample<OsdCpuVertexBuffer,OsdCpuVertexBuffer>(coords, evalctx, 0);
*P_ = make_float3(P[0], P[1], P[2]);
- if (dPdu_) *dPdu_ = make_float3(dPdv[0], dPdv[1], dPdv[2]);
- if (dPdv_) *dPdv_ = make_float3(dPdu[0], dPdu[1], dPdu[2]);
+ if(dPdu_) *dPdu_ = make_float3(dPdv[0], dPdv[1], dPdv[2]);
+ if(dPdv_) *dPdv_ = make_float3(dPdu[0], dPdu[1], dPdu[2]);
/* optimize: skip evaluating derivatives when not needed */
/* todo: swapped derivatives, different winding convention? */
@@ -234,7 +234,7 @@ bool OpenSubdMesh::finish()
void OpenSubdMesh::tessellate(DiagSplit *split)
{
- if (num_ptex_faces == 0)
+ if(num_ptex_faces == 0)
return;
const int level = 3;
diff --git a/intern/cycles/util/util_aligned_malloc.cpp b/intern/cycles/util/util_aligned_malloc.cpp
index 9ff857e3543..b161a55c15e 100644
--- a/intern/cycles/util/util_aligned_malloc.cpp
+++ b/intern/cycles/util/util_aligned_malloc.cpp
@@ -55,7 +55,7 @@ void *util_aligned_malloc(size_t size, int alignment)
return malloc(size);
#elif defined(__FreeBSD__) || defined(__NetBSD__)
void *result;
- if (posix_memalign(&result, alignment, size)) {
+ if(posix_memalign(&result, alignment, size)) {
/* Non-zero means allocation error
* either no allocation or bad alignment value.
*/
diff --git a/intern/cycles/util/util_atomic.h b/intern/cycles/util/util_atomic.h
index 7bbd97b8667..1d1e2963348 100644
--- a/intern/cycles/util/util_atomic.h
+++ b/intern/cycles/util/util_atomic.h
@@ -17,17 +17,49 @@
#ifndef __UTIL_ATOMIC_H__
#define __UTIL_ATOMIC_H__
+#ifndef __KERNEL_GPU__
+
/* Using atomic ops header from Blender. */
#include "atomic_ops.h"
ATOMIC_INLINE void atomic_update_max_z(size_t *maximum_value, size_t value)
{
size_t prev_value = *maximum_value;
- while (prev_value < value) {
- if (atomic_cas_z(maximum_value, prev_value, value) != prev_value) {
+ while(prev_value < value) {
+ if(atomic_cas_z(maximum_value, prev_value, value) != prev_value) {
break;
}
}
}
+#else /* __KERNEL_GPU__ */
+
+#ifdef __KERNEL_OPENCL__
+
+/* Float atomics implementation credits:
+ * http://suhorukov.blogspot.in/2011/12/opencl-11-atomic-operations-on-floating.html
+ */
+ccl_device_inline void atomic_add_float(volatile ccl_global float *source,
+ const float operand)
+{
+ union {
+ unsigned int int_value;
+ float float_value;
+ } new_value;
+ union {
+ unsigned int int_value;
+ float float_value;
+ } prev_value;
+ do {
+ prev_value.float_value = *source;
+ new_value.float_value = prev_value.float_value + operand;
+ } while(atomic_cmpxchg((volatile ccl_global unsigned int *)source,
+ prev_value.int_value,
+ new_value.int_value) != prev_value.int_value);
+}
+
+#endif /* __KERNEL_OPENCL__ */
+
+#endif /* __KERNEL_GPU__ */
+
#endif /* __UTIL_ATOMIC_H__ */
diff --git a/intern/cycles/util/util_cache.h b/intern/cycles/util/util_cache.h
index 9d001a6f1ff..343fa36817d 100644
--- a/intern/cycles/util/util_cache.h
+++ b/intern/cycles/util/util_cache.h
@@ -105,7 +105,7 @@ public:
return false;
}
- if(!size)
+ if((size == 0) || (size % sizeof(T)) != 0)
return false;
data.resize(size/sizeof(T));
diff --git a/intern/cycles/util/util_foreach.h b/intern/cycles/util/util_foreach.h
index 065bd33ebd2..4f7337107b3 100644
--- a/intern/cycles/util/util_foreach.h
+++ b/intern/cycles/util/util_foreach.h
@@ -19,8 +19,12 @@
/* Use Boost to get nice foreach() loops for STL data structures. */
-#include <boost/foreach.hpp>
-#define foreach BOOST_FOREACH
+#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
+# define foreach(x, y) for(x : y)
+#else
+# include <boost/foreach.hpp>
+# define foreach BOOST_FOREACH
+#endif
#endif /* __UTIL_FOREACH_H__ */
diff --git a/intern/cycles/util/util_function.h b/intern/cycles/util/util_function.h
index 7a312efaad7..6d0f0b444a9 100644
--- a/intern/cycles/util/util_function.h
+++ b/intern/cycles/util/util_function.h
@@ -17,14 +17,33 @@
#ifndef __UTIL_FUNCTION_H__
#define __UTIL_FUNCTION_H__
-#include <boost/bind.hpp>
-#include <boost/function.hpp>
+#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
+# include <functional>
+#else
+# include <boost/bind.hpp>
+# include <boost/function.hpp>
+#endif
CCL_NAMESPACE_BEGIN
+#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
+# define function_bind std::bind
+# define function_null nullptr
+using std::function;
+using std::placeholders::_1;
+using std::placeholders::_2;
+using std::placeholders::_3;
+using std::placeholders::_4;
+using std::placeholders::_5;
+using std::placeholders::_6;
+using std::placeholders::_7;
+using std::placeholders::_8;
+using std::placeholders::_9;
+#else
using boost::function;
-#define function_bind boost::bind
-
+# define function_bind boost::bind
+# define function_null NULL
+#endif
CCL_NAMESPACE_END
#endif /* __UTIL_FUNCTION_H__ */
diff --git a/intern/cycles/util/util_guarded_allocator.h b/intern/cycles/util/util_guarded_allocator.h
index 263199417c4..c4edb172eb8 100644
--- a/intern/cycles/util/util_guarded_allocator.h
+++ b/intern/cycles/util/util_guarded_allocator.h
@@ -53,6 +53,7 @@ public:
{
util_guarded_mem_alloc(n * sizeof(T));
#ifdef WITH_BLENDER_GUARDEDALLOC
+ (void)hint;
return (T*)MEM_mallocN(n * sizeof(T), "Cycles Alloc");
#else
return std::allocator<T>::allocate(n, hint);
diff --git a/intern/cycles/util/util_half.h b/intern/cycles/util/util_half.h
index 76941569bd2..f4bac9888a5 100644
--- a/intern/cycles/util/util_half.h
+++ b/intern/cycles/util/util_half.h
@@ -56,7 +56,7 @@ ccl_device_inline void float4_store_half(half *h, float4 f, float scale)
* assumes no negative, no nan, no inf, and sets denormal to 0 */
union { uint i; float f; } in;
float fscale = f[i] * scale;
- in.f = (fscale > 0.0f)? ((fscale < 65500.0f)? fscale: 65500.0f): 0.0f;
+ in.f = (fscale > 0.0f)? ((fscale < 65504.0f)? fscale: 65504.0f): 0.0f;
int x = in.i;
int absolute = x & 0x7FFFFFFF;
@@ -68,20 +68,20 @@ ccl_device_inline void float4_store_half(half *h, float4 f, float scale)
}
#else
/* same as above with SSE */
- const ssef mm_scale = ssef(scale);
- const ssei mm_38800000 = ssei(0x38800000);
- const ssei mm_7FFF = ssei(0x7FFF);
- const ssei mm_7FFFFFFF = ssei(0x7FFFFFFF);
- const ssei mm_C8000000 = ssei(0xC8000000);
-
- ssef mm_fscale = load4f(f) * mm_scale;
- ssei x = cast(min(max(mm_fscale, ssef(0.0f)), ssef(65500.0f)));
- ssei absolute = x & mm_7FFFFFFF;
- ssei Z = absolute + mm_C8000000;
- ssei result = andnot(absolute < mm_38800000, Z);
- ssei rh = (result >> 13) & mm_7FFF;
-
- _mm_storel_pi((__m64*)h, _mm_castsi128_ps(_mm_packs_epi32(rh, rh)));
+ ssef fscale = load4f(f) * scale;
+ ssef x = min(max(fscale, 0.0f), 65504.0f);
+
+#ifdef __KERNEL_AVX2__
+ ssei rpack = _mm_cvtps_ph(x, 0);
+#else
+ ssei absolute = cast(x) & 0x7FFFFFFF;
+ ssei Z = absolute + 0xC8000000;
+ ssei result = andnot(absolute < 0x38800000, Z);
+ ssei rshift = (result >> 13) & 0x7FFF;
+ ssei rpack = _mm_packs_epi32(rshift, rshift);
+#endif
+
+ _mm_storel_pi((__m64*)h, _mm_castsi128_ps(rpack));
#endif
}
diff --git a/intern/cycles/util/util_hash.h b/intern/cycles/util/util_hash.h
index bbbedc22a47..3ff2802b46d 100644
--- a/intern/cycles/util/util_hash.h
+++ b/intern/cycles/util/util_hash.h
@@ -53,7 +53,7 @@ static inline uint hash_string(const char *str)
{
uint i = 0, c;
- while ((c = *str++))
+ while((c = *str++))
i = i * 37 + c;
return i;
diff --git a/intern/cycles/util/util_map.h b/intern/cycles/util/util_map.h
index 54d6a8d6424..46c2885f8b0 100644
--- a/intern/cycles/util/util_map.h
+++ b/intern/cycles/util/util_map.h
@@ -18,13 +18,38 @@
#define __UTIL_MAP_H__
#include <map>
-#include <boost/tr1/unordered_map.hpp>
+
+#if defined(CYCLES_TR1_UNORDERED_MAP)
+# include <tr1/unordered_map>
+#endif
+
+#if defined(CYCLES_STD_UNORDERED_MAP) || defined(CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+# include <unordered_map>
+#endif
+
+#if !defined(CYCLES_NO_UNORDERED_MAP) && !defined(CYCLES_TR1_UNORDERED_MAP) && \
+ !defined(CYCLES_STD_UNORDERED_MAP) && !defined(CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
+# error One of: CYCLES_NO_UNORDERED_MAP, CYCLES_TR1_UNORDERED_MAP,\
+ CYCLES_STD_UNORDERED_MAP, CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
+#endif
+
CCL_NAMESPACE_BEGIN
using std::map;
using std::pair;
+
+#if defined(CYCLES_NO_UNORDERED_MAP)
+typedef std::map unordered_map;
+#endif
+
+#if defined(CYCLES_TR1_UNORDERED_MAP) || defined(CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
using std::tr1::unordered_map;
+#endif
+
+#if defined(CYCLES_STD_UNORDERED_MAP)
+using std::unordered_map;
+#endif
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h
index a4d49681a38..2262f8fdbb7 100644
--- a/intern/cycles/util/util_math.h
+++ b/intern/cycles/util/util_math.h
@@ -175,6 +175,15 @@ ccl_device_inline float clamp(float a, float mn, float mx)
#endif
+#ifndef __KERNEL_CUDA__
+
+ccl_device_inline float saturate(float a)
+{
+ return clamp(a, 0.0f, 1.0f);
+}
+
+#endif
+
ccl_device_inline int float_to_int(float f)
{
return (int)f;
@@ -1461,9 +1470,9 @@ ccl_device_inline float2 map_to_tube(const float3 co)
{
float len, u, v;
len = sqrtf(co.x * co.x + co.y * co.y);
- if (len > 0.0f) {
+ if(len > 0.0f) {
u = (1.0f - (atan2f(co.x / len, co.y / len) / M_PI_F)) * 0.5f;
- v = (co.x + 1.0f) * 0.5f;
+ v = (co.z + 1.0f) * 0.5f;
}
else {
u = v = 0.0f;
diff --git a/intern/cycles/util/util_math_fast.h b/intern/cycles/util/util_math_fast.h
index 4ad81e9c015..c1a1be603f4 100644
--- a/intern/cycles/util/util_math_fast.h
+++ b/intern/cycles/util/util_math_fast.h
@@ -360,7 +360,7 @@ ccl_device float fast_log2f(float x)
{
/* NOTE: clamp to avoid special cases and make result "safe" from large
* negative values/nans. */
- clamp(x, FLT_MIN, FLT_MAX);
+ x = clamp(x, FLT_MIN, FLT_MAX);
unsigned bits = __float_as_uint(x);
int exponent = (int)(bits >> 23) - 127;
float f = __uint_as_float((bits & 0x007FFFFF) | 0x3f800000) - 1.0f;
@@ -402,7 +402,7 @@ ccl_device float fast_logb(float x)
{
/* Don't bother with denormals. */
x = fabsf(x);
- clamp(x, FLT_MIN, FLT_MAX);
+ x = clamp(x, FLT_MIN, FLT_MAX);
unsigned bits = __float_as_uint(x);
return (int)(bits >> 23) - 127;
}
@@ -410,7 +410,7 @@ ccl_device float fast_logb(float x)
ccl_device float fast_exp2f(float x)
{
/* Clamp to safe range for final addition. */
- clamp(x, -126.0f, 126.0f);
+ x = clamp(x, -126.0f, 126.0f);
/* Range reduction. */
int m = (int)x; x -= m;
x = 1.0f - (1.0f - x); /* Crush denormals (does not affect max ulps!). */
@@ -539,7 +539,7 @@ ccl_device float fast_safe_powf(float x, float y)
* bsdf_microfaset.h.
*/
-ccl_device float fast_erff(float x)
+ccl_device_inline float fast_erff(float x)
{
/* Examined 1082130433 values of erff on [0,4]: 1.93715e-06 max error. */
/* Abramowitz and Stegun, 7.1.28. */
@@ -570,7 +570,7 @@ ccl_device_inline float fast_erfcf(float x)
return 1.0f - fast_erff(x);
}
-ccl_device float fast_ierff(float x)
+ccl_device_inline float fast_ierff(float x)
{
/* From: Approximating the erfinv function by Mike Giles. */
/* To avoid trouble at the limit, clamp input to 1-eps. */
diff --git a/intern/cycles/util/util_optimization.h b/intern/cycles/util/util_optimization.h
index b230bb1a627..c951c35fc76 100644
--- a/intern/cycles/util/util_optimization.h
+++ b/intern/cycles/util/util_optimization.h
@@ -102,28 +102,7 @@
#ifdef _MSC_VER
#include <intrin.h>
#else
-
-#ifdef __KERNEL_SSE2__
-#include <xmmintrin.h> /* SSE 1 */
-#include <emmintrin.h> /* SSE 2 */
-#endif
-
-#ifdef __KERNEL_SSE3__
-#include <pmmintrin.h> /* SSE 3 */
-#endif
-
-#ifdef __KERNEL_SSSE3__
-#include <tmmintrin.h> /* SSSE 3 */
-#endif
-
-#ifdef __KERNEL_SSE41__
-#include <smmintrin.h> /* SSE 4.1 */
-#endif
-
-#ifdef __KERNEL_AVX__
-#include <immintrin.h> /* AVX */
-#endif
-
+#include <x86intrin.h>
#endif
#else
diff --git a/intern/cycles/util/util_progress.h b/intern/cycles/util/util_progress.h
index 0ff48630a81..13fce655734 100644
--- a/intern/cycles/util/util_progress.h
+++ b/intern/cycles/util/util_progress.h
@@ -44,12 +44,12 @@ public:
substatus = "";
sync_status = "";
sync_substatus = "";
- update_cb = NULL;
+ update_cb = function_null;
cancel = false;
cancel_message = "";
error = false;
error_message = "";
- cancel_cb = NULL;
+ cancel_cb = function_null;
}
Progress(Progress& progress)
@@ -110,7 +110,7 @@ public:
return cancel_message;
}
- void set_cancel_callback(boost::function<void(void)> function)
+ void set_cancel_callback(function<void(void)> function)
{
cancel_cb = function;
}
@@ -275,7 +275,7 @@ public:
}
}
- void set_update_callback(boost::function<void(void)> function)
+ void set_update_callback(function<void(void)> function)
{
update_cb = function;
}
@@ -283,8 +283,8 @@ public:
protected:
thread_mutex progress_mutex;
thread_mutex update_mutex;
- boost::function<void(void)> update_cb;
- boost::function<void(void)> cancel_cb;
+ function<void(void)> update_cb;
+ function<void(void)> cancel_cb;
int tile; /* counter for rendered tiles */
int sample; /* counter of rendered samples, global for all tiles */
diff --git a/intern/cycles/util/util_set.h b/intern/cycles/util/util_set.h
index 73a2bf19899..b3cb8dd8af5 100644
--- a/intern/cycles/util/util_set.h
+++ b/intern/cycles/util/util_set.h
@@ -18,13 +18,19 @@
#define __UTIL_SET_H__
#include <set>
-#include <boost/tr1/unordered_set.hpp>
-
+#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
+# include <unordered_set>
+#else
+# include <boost/tr1/unordered_set.hpp>
+#endif
CCL_NAMESPACE_BEGIN
using std::set;
+#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
+using std::unordered_set;
+#else
using std::tr1::unordered_set;
-
+#endif
CCL_NAMESPACE_END
#endif /* __UTIL_SET_H__ */
diff --git a/intern/cycles/util/util_simd.h b/intern/cycles/util/util_simd.h
index 625f26c1316..7c15199d4e1 100644
--- a/intern/cycles/util/util_simd.h
+++ b/intern/cycles/util/util_simd.h
@@ -133,7 +133,7 @@ __forceinline int clz(const int x)
#if defined(__KERNEL_AVX2__)
return _lzcnt_u32(x);
#else
- if (UNLIKELY(x == 0)) return 32;
+ if(UNLIKELY(x == 0)) return 32;
return 31 - __bsr(x);
#endif
}
@@ -286,7 +286,7 @@ __forceinline int clz(const int x)
#if defined(__KERNEL_AVX2__)
return _lzcnt_u32(x);
#else
- if (UNLIKELY(x == 0)) return 32;
+ if(UNLIKELY(x == 0)) return 32;
return 31 - __bsr(x);
#endif
}
@@ -358,7 +358,7 @@ __forceinline __m128i _mm_mullo_epi32( __m128i value, __m128i input ) {
char* _r = (char*)(&rvalue + 1);
char* _v = (char*)(& value + 1);
char* _i = (char*)(& input + 1);
- for ( ssize_t i = -16 ; i != 0 ; i += 4 ) *((int32*)(_r + i)) = *((int32*)(_v + i))* *((int32*)(_i + i));
+ for( ssize_t i = -16 ; i != 0 ; i += 4 ) *((int32*)(_r + i)) = *((int32*)(_v + i))* *((int32*)(_i + i));
return rvalue;
}
diff --git a/intern/cycles/util/util_string.cpp b/intern/cycles/util/util_string.cpp
index 8675ff3679d..66856dd8331 100644
--- a/intern/cycles/util/util_string.cpp
+++ b/intern/cycles/util/util_string.cpp
@@ -105,5 +105,22 @@ string string_strip(const string& s)
}
+void string_replace(string& haystack, const string& needle, const string& other)
+{
+ size_t i;
+
+ while((i = haystack.find(needle)) != string::npos)
+ haystack.replace(i, needle.length(), other);
+}
+
+string string_remove_trademark(const string &s)
+{
+ string result = s;
+ string_replace(result, "(TM)", "");
+ string_replace(result, "(R)", "");
+
+ return string_strip(result);
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_string.h b/intern/cycles/util/util_string.h
index fa1671fd1ee..6cb8d8df1e1 100644
--- a/intern/cycles/util/util_string.h
+++ b/intern/cycles/util/util_string.h
@@ -40,8 +40,10 @@ string string_printf(const char *format, ...) PRINTF_ATTRIBUTE;
bool string_iequals(const string& a, const string& b);
void string_split(vector<string>& tokens, const string& str, const string& separators = "\t ");
+void string_replace(string& haystack, const string& needle, const string& other);
bool string_endswith(const string& s, const char *end);
string string_strip(const string& s);
+string string_remove_trademark(const string& s);
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_system.cpp b/intern/cycles/util/util_system.cpp
index 7206455debd..cc88320b68e 100644
--- a/intern/cycles/util/util_system.cpp
+++ b/intern/cycles/util/util_system.cpp
@@ -16,6 +16,7 @@
#include "util_system.h"
#include "util_types.h"
+#include "util_string.h"
#ifdef _WIN32
#if(!defined(FREE_WINDOWS))
@@ -75,14 +76,6 @@ static void __cpuid(int data[4], int selector)
}
#endif
-static void replace_string(string& haystack, const string& needle, const string& other)
-{
- size_t i;
-
- while((i = haystack.find(needle)) != string::npos)
- haystack.replace(i, needle.length(), other);
-}
-
string system_cpu_brand_string()
{
char buf[48];
@@ -98,10 +91,7 @@ string system_cpu_brand_string()
string brand = buf;
/* make it a bit more presentable */
- replace_string(brand, "(TM)", "");
- replace_string(brand, "(R)", "");
-
- brand = string_strip(brand);
+ brand = string_remove_trademark(brand);
return brand;
}
@@ -127,6 +117,7 @@ struct CPUCapabilities {
bool sse42;
bool sse4a;
bool avx;
+ bool f16c;
bool avx2;
bool xop;
bool fma3;
@@ -202,6 +193,8 @@ static CPUCapabilities& system_cpu_capabilities()
caps.avx = (xcr_feature_mask & 0x6) == 0x6;
}
+ caps.f16c = (result[2] & ((int)1 << 29)) != 0;
+
__cpuid(result, 0x00000007);
caps.bmi1 = (result[1] & ((int)1 << 3)) != 0;
caps.bmi2 = (result[1] & ((int)1 << 8)) != 0;
@@ -242,7 +235,7 @@ bool system_cpu_support_avx()
bool system_cpu_support_avx2()
{
CPUCapabilities& caps = system_cpu_capabilities();
- return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41 && caps.avx && caps.avx2 && caps.fma3 && caps.bmi1 && caps.bmi2;
+ return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41 && caps.avx && caps.f16c && caps.avx2 && caps.fma3 && caps.bmi1 && caps.bmi2;
}
#else
diff --git a/intern/cycles/util/util_task.cpp b/intern/cycles/util/util_task.cpp
index e43b26ddfe2..d56553d1d4a 100644
--- a/intern/cycles/util/util_task.cpp
+++ b/intern/cycles/util/util_task.cpp
@@ -237,7 +237,7 @@ bool TaskScheduler::thread_wait_pop(Entry& entry)
return true;
}
-void TaskScheduler::thread_run(int thread_id)
+void TaskScheduler::thread_run(int /*thread_id*/)
{
Entry entry;
diff --git a/intern/cycles/util/util_task.h b/intern/cycles/util/util_task.h
index 8fac12e9987..debcff3b776 100644
--- a/intern/cycles/util/util_task.h
+++ b/intern/cycles/util/util_task.h
@@ -27,7 +27,7 @@ class Task;
class TaskPool;
class TaskScheduler;
-typedef boost::function<void(void)> TaskRunFunction;
+typedef function<void(void)> TaskRunFunction;
/* Task
*
diff --git a/intern/cycles/util/util_thread.h b/intern/cycles/util/util_thread.h
index fbbb9b42e31..9c19235d41d 100644
--- a/intern/cycles/util/util_thread.h
+++ b/intern/cycles/util/util_thread.h
@@ -17,7 +17,14 @@
#ifndef __UTIL_THREAD_H__
#define __UTIL_THREAD_H__
-#include <boost/thread.hpp>
+#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
+# include <thread>
+# include <mutex>
+# include <condition_variable>
+# include <functional>
+#else
+# include <boost/thread.hpp>
+#endif
#include <pthread.h>
#include <queue>
@@ -25,18 +32,24 @@
CCL_NAMESPACE_BEGIN
+#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
+typedef std::mutex thread_mutex;
+typedef std::unique_lock<std::mutex> thread_scoped_lock;
+typedef std::condition_variable thread_condition_variable;
+#else
/* use boost for mutexes */
-
typedef boost::mutex thread_mutex;
typedef boost::mutex::scoped_lock thread_scoped_lock;
typedef boost::condition_variable thread_condition_variable;
+#endif
/* own pthread based implementation, to avoid boost version conflicts with
* dynamically loaded blender plugins */
class thread {
public:
- thread(boost::function<void(void)> run_cb_)
+ thread(function<void(void)> run_cb_)
+
{
joined = false;
run_cb = run_cb_;
@@ -63,7 +76,7 @@ public:
}
protected:
- boost::function<void(void)> run_cb;
+ function<void(void)> run_cb;
pthread_t pthread_id;
bool joined;
};
diff --git a/intern/cycles/util/util_time.cpp b/intern/cycles/util/util_time.cpp
index 9668b0f9882..964f9f1a7af 100644
--- a/intern/cycles/util/util_time.cpp
+++ b/intern/cycles/util/util_time.cpp
@@ -71,7 +71,7 @@ void time_sleep(double t)
/* get microseconds */
int us = (int)(t * 1e6);
- if (us > 0)
+ if(us > 0)
usleep(us);
}
diff --git a/intern/cycles/util/util_transform.cpp b/intern/cycles/util/util_transform.cpp
index 0a1c09ae3d5..acaca69464c 100644
--- a/intern/cycles/util/util_transform.cpp
+++ b/intern/cycles/util/util_transform.cpp
@@ -46,9 +46,11 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "util_math.h"
#include "util_transform.h"
+#include "util_boundbox.h"
+#include "util_math.h"
+
CCL_NAMESPACE_BEGIN
/* Transform Inverse */
@@ -271,5 +273,15 @@ void transform_motion_decompose(DecompMotionTransform *decomp, const MotionTrans
decomp->post_y = post.y;
}
-CCL_NAMESPACE_END
+Transform transform_from_viewplane(BoundBox2D& viewplane)
+{
+ return
+ transform_scale(1.0f / (viewplane.right - viewplane.left),
+ 1.0f / (viewplane.top - viewplane.bottom),
+ 1.0f) *
+ transform_translate(-viewplane.left,
+ -viewplane.bottom,
+ 0.0f);
+}
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h
index ac97fa53084..0b87db0a379 100644
--- a/intern/cycles/util/util_transform.h
+++ b/intern/cycles/util/util_transform.h
@@ -449,6 +449,8 @@ ccl_device void transform_motion_interpolate(Transform *tfm, const DecompMotionT
#ifndef __KERNEL_GPU__
+class BoundBox2D;
+
ccl_device_inline bool operator==(const MotionTransform& A, const MotionTransform& B)
{
return (A.pre == B.pre && A.post == B.post);
@@ -456,7 +458,39 @@ ccl_device_inline bool operator==(const MotionTransform& A, const MotionTransfor
float4 transform_to_quat(const Transform& tfm);
void transform_motion_decompose(DecompMotionTransform *decomp, const MotionTransform *motion, const Transform *mid);
+Transform transform_from_viewplane(BoundBox2D& viewplane);
+
+#endif
+
+/* TODO(sergey): This is only for until we've got OpenCL 2.0
+ * on all devices we consider supported. It'll be replaced with
+ * generic address space.
+ */
+#ifdef __KERNEL_OPENCL__
+
+#define OPENCL_TRANSFORM_ADDRSPACE_GLUE(a, b) a ## b
+#define OPENCL_TRANSFORM_ADDRSPACE_DECLARE(function) \
+ccl_device_inline float3 OPENCL_TRANSFORM_ADDRSPACE_GLUE(function, _addrspace)( \
+ ccl_addr_space const Transform *t, const float3 a) \
+{ \
+ Transform private_tfm = *t; \
+ return function(&private_tfm, a); \
+}
+
+OPENCL_TRANSFORM_ADDRSPACE_DECLARE(transform_point)
+OPENCL_TRANSFORM_ADDRSPACE_DECLARE(transform_direction)
+OPENCL_TRANSFORM_ADDRSPACE_DECLARE(transform_direction_transposed)
+
+# undef OPENCL_TRANSFORM_ADDRSPACE_DECLARE
+# undef OPENCL_TRANSFORM_ADDRSPACE_GLUE
+# define transform_point_auto transform_point_addrspace
+# define transform_direction_auto transform_direction_addrspace
+# define transform_direction_transposed_auto transform_direction_transposed_addrspace
+#else
+# define transform_point_auto transform_point
+# define transform_direction_auto transform_direction
+# define transform_direction_transposed_auto transform_direction_transposed
#endif
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_types.h b/intern/cycles/util/util_types.h
index df61b6ead21..187675e74bf 100644
--- a/intern/cycles/util/util_types.h
+++ b/intern/cycles/util/util_types.h
@@ -481,18 +481,32 @@ enum InterpolationType {
# define UNLIKELY(x) (x)
#endif
+#if defined(__cplusplus) && ((__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1800))
+# define HAS_CPP11_FEATURES
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+# if defined(HAS_CPP11_FEATURES)
+/* Some magic to be sure we don't have reference in the type. */
+template<typename T> static inline T decltype_helper(T x) { return x; }
+# define TYPEOF(x) decltype(decltype_helper(x))
+# else
+# define TYPEOF(x) typeof(x)
+# endif
+#endif
+
/* Causes warning:
* incompatible types when assigning to type 'Foo' from type 'Bar'
* ... the compiler optimizes away the temp var */
#ifdef __GNUC__
#define CHECK_TYPE(var, type) { \
- typeof(var) *__tmp; \
+ TYPEOF(var) *__tmp; \
__tmp = (type *)NULL; \
(void)__tmp; \
} (void)0
#define CHECK_TYPE_PAIR(var_a, var_b) { \
- typeof(var_a) *__tmp; \
+ TYPEOF(var_a) *__tmp; \
__tmp = (typeof(var_b) *)NULL; \
(void)__tmp; \
} (void)0
diff --git a/intern/cycles/util/util_view.cpp b/intern/cycles/util/util_view.cpp
index e77ebb2fe3e..9b5cd22fb4a 100644
--- a/intern/cycles/util/util_view.cpp
+++ b/intern/cycles/util/util_view.cpp
@@ -98,7 +98,7 @@ void view_display_help()
glColor3f(0.8f, 0.8f, 0.8f);
view_display_text(x1+20, y2-20, "Cycles Renderer");
- view_display_text(x1+20, y2-40, "(C) 2011-2014 Blender Foundation");
+ view_display_text(x1+20, y2-40, "(C) 2011-2015 Blender Foundation");
view_display_text(x1+20, y2-80, "Controls:");
view_display_text(x1+20, y2-100, "h: Info/Help");
view_display_text(x1+20, y2-120, "r: Reset");
@@ -110,6 +110,7 @@ void view_display_help()
view_display_text(x1+20, y2-230, "Left mouse: Move camera");
view_display_text(x1+20, y2-250, "Right mouse: Rotate camera");
view_display_text(x1+20, y2-270, "W/A/S/D: Move camera");
+ view_display_text(x1+20, y2-290, "0/1/2/3: Set max bounces");
glColor3f(1.0f, 1.0f, 1.0f);
}
diff --git a/intern/dualcon/CMakeLists.txt b/intern/dualcon/CMakeLists.txt
index da5e10fe6a7..40c8ef8ff9c 100644
--- a/intern/dualcon/CMakeLists.txt
+++ b/intern/dualcon/CMakeLists.txt
@@ -22,7 +22,7 @@ set(INC
)
set(INC_SYS
- ../../extern/Eigen3
+ ${EIGEN3_INCLUDE_DIRS}
)
set(SRC
diff --git a/intern/dualcon/intern/Projections.cpp b/intern/dualcon/intern/Projections.cpp
index e85589e3ff5..601812e1e21 100644
--- a/intern/dualcon/intern/Projections.cpp
+++ b/intern/dualcon/intern/Projections.cpp
@@ -158,7 +158,7 @@ static void create_projection_axes(int64_t axes[NUM_AXES][3], const int64_t tri[
/**
* Construction from a cube (axes aligned) and triangle
*/
-CubeTriangleIsect::CubeTriangleIsect(int64_t cube[2][3], int64_t tri[3][3], int64_t error, int triind)
+CubeTriangleIsect::CubeTriangleIsect(int64_t cube[2][3], int64_t tri[3][3], int64_t /*error*/, int triind)
{
int i;
inherit = new TriangleProjection;
diff --git a/intern/dualcon/intern/dualcon_c_api.cpp b/intern/dualcon/intern/dualcon_c_api.cpp
index 6c3ec4dcc3b..a6715394942 100644
--- a/intern/dualcon/intern/dualcon_c_api.cpp
+++ b/intern/dualcon/intern/dualcon_c_api.cpp
@@ -174,7 +174,7 @@ float getBoundingBox(float origin[3])
}
/* output */
-void getNextVertex(float v[3])
+void getNextVertex(float /*v*/[3])
{
/* not used */
}
diff --git a/intern/dualcon/intern/octree.cpp b/intern/dualcon/intern/octree.cpp
index bd7194cf3fd..da8638ebc4f 100644
--- a/intern/dualcon/intern/octree.cpp
+++ b/intern/dualcon/intern/octree.cpp
@@ -1448,7 +1448,7 @@ Node *Octree::locateCell(InternalNode *node, int st[3], int len, int ori[3], int
return (Node *)node;
}
-void Octree::checkElement(PathElement *ele)
+void Octree::checkElement(PathElement * /*ele*/)
{
/*
if(ele != NULL && locateLeafCheck(ele->pos) != ele->node) {
@@ -1797,7 +1797,7 @@ void Octree::clearProcessBits(Node *node, int height)
}
}
-int Octree::floodFill(LeafNode *leaf, int st[3], int len, int height, int threshold)
+int Octree::floodFill(LeafNode *leaf, int st[3], int len, int /*height*/, int threshold)
{
int i, j;
int maxtotal = 0;
@@ -2317,7 +2317,7 @@ void Octree::generateMinimizer(Node *node, int st[3], int len, int height, int&
}
}
-void Octree::processEdgeWrite(Node *node[4], int depth[4], int maxdep, int dir)
+void Octree::processEdgeWrite(Node *node[4], int /*depth*/[4], int /*maxdep*/, int dir)
{
//int color = 0;
@@ -2553,7 +2553,7 @@ void Octree::cellProcContour(Node *node, int leaf, int depth)
}
-void Octree::processEdgeParity(LeafNode *node[4], int depth[4], int maxdep, int dir)
+void Octree::processEdgeParity(LeafNode *node[4], int /*depth*/[4], int /*maxdep*/, int dir)
{
int con = 0;
for (int i = 0; i < 4; i++) {
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index dc55a81b0d8..761bcb4dd27 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -297,11 +297,6 @@ elseif(WIN32)
intern/GHOST_NDOFManagerWin32.h
)
endif()
-
- list(APPEND INC
- ../utfconv
- )
-
endif()
if(WITH_GL_EGL AND NOT (WITH_HEADLESS OR WITH_GHOST_SDL))
@@ -334,6 +329,10 @@ elseif(WIN32)
intern/GHOST_SystemPathsWin32.h
)
+ list(APPEND INC
+ ../utfconv
+ )
+
endif()
add_definitions(${GL_DEFINITIONS})
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index 5f01a13b64e..8a80a51a77b 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -660,7 +660,7 @@ extern GHOST_TSuccess GHOST_SetWindowOrder(GHOST_WindowHandle windowhandle,
/**
* Swaps front and back buffers of a window.
* \param windowhandle The handle to the window
- * \return An intean success indicator.
+ * \return A success indicator.
*/
extern GHOST_TSuccess GHOST_SwapWindowBuffers(GHOST_WindowHandle windowhandle);
@@ -688,7 +688,7 @@ extern GHOST_TUns16 GHOST_GetNumOfAASamples(GHOST_WindowHandle windowhandle);
/**
* Activates the drawing context of this window.
* \param windowhandle The handle to the window
- * \return An intean success indicator.
+ * \return A success indicator.
*/
extern GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandle);
@@ -752,7 +752,7 @@ extern void GHOST_SetRectangle(GHOST_RectangleHandle rectanglehandle,
* Returns whether this rectangle is empty.
* Empty rectangles are rectangles that have width==0 and/or height==0.
* \param rectanglehandle The handle to the rectangle
- * \return intean value (true == empty rectangle)
+ * \return Success value (true == empty rectangle)
*/
extern GHOST_TSuccess GHOST_IsEmptyRectangle(GHOST_RectangleHandle rectanglehandle);
@@ -760,7 +760,7 @@ extern GHOST_TSuccess GHOST_IsEmptyRectangle(GHOST_RectangleHandle rectanglehand
* Returns whether this rectangle is valid.
* Valid rectangles are rectangles that have m_l <= m_r and m_t <= m_b. Thus, empty rectangles are valid.
* \param rectanglehandle The handle to the rectangle
- * \return intean value (true == valid rectangle)
+ * \return Success value (true == valid rectangle)
*/
extern GHOST_TSuccess GHOST_IsValidRectangle(GHOST_RectangleHandle rectanglehandle);
@@ -798,7 +798,7 @@ extern void GHOST_UnionPointRectangle(GHOST_RectangleHandle rectanglehandle,
* \param rectanglehandle The handle to the rectangle
* \param x x-coordinate of point to test.
* \param y y-coordinate of point to test.
- * \return intean value (true if point is inside).
+ * \return Success value (true if point is inside).
*/
extern GHOST_TSuccess GHOST_IsInsideRectangle(GHOST_RectangleHandle rectanglehandle,
GHOST_TInt32 x,
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index 93ccc0fc947..25908a54872 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -396,7 +396,7 @@ public:
/**
* Returns the selection buffer
- * \return Returns "unsinged char" from X11 XA_CUT_BUFFER0 buffer
+ * \return "unsigned char" from X11 XA_CUT_BUFFER0 buffer
*
*/
virtual GHOST_TUns8 *getClipboard(bool selection) const = 0;
diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h
index 3f8215dc7c2..649f06749b6 100644
--- a/intern/ghost/GHOST_IWindow.h
+++ b/intern/ghost/GHOST_IWindow.h
@@ -323,7 +323,9 @@ public:
* \param grab The new grab state of the cursor.
* \return Indication of success.
*/
- virtual GHOST_TSuccess setCursorGrab(GHOST_TGrabCursorMode mode, GHOST_Rect *bounds, GHOST_TInt32 mouse_ungrab_xy[2]) { return GHOST_kSuccess; }
+ virtual GHOST_TSuccess setCursorGrab(GHOST_TGrabCursorMode /*mode*/,
+ GHOST_Rect * /*bounds*/,
+ GHOST_TInt32 /*mouse_ungrab_xy*/[2]) { return GHOST_kSuccess; }
/** */
virtual GHOST_TSuccess beginFullScreen() const = 0;
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index eccbaadb71d..752a45c7473 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -126,12 +126,8 @@ typedef enum {
GHOST_kWindowStateMinimized,
GHOST_kWindowStateFullScreen,
GHOST_kWindowStateEmbedded,
- GHOST_kWindowState8Normal = 8,
- GHOST_kWindowState8Maximized,
- GHOST_kWindowState8Minimized,
- GHOST_kWindowState8FullScreen,
- GHOST_kWindowStateModified,
- GHOST_kWindowStateUnModified
+ // GHOST_kWindowStateModified,
+ // GHOST_kWindowStateUnModified,
} GHOST_TWindowState;
diff --git a/intern/ghost/intern/GHOST_Context.h b/intern/ghost/intern/GHOST_Context.h
index 0dfea867703..18d36c40e9c 100644
--- a/intern/ghost/intern/GHOST_Context.h
+++ b/intern/ghost/intern/GHOST_Context.h
@@ -99,7 +99,7 @@ public:
* \param interval The swap interval to use.
* \return A boolean success indicator.
*/
- virtual GHOST_TSuccess setSwapInterval(int interval) {
+ virtual GHOST_TSuccess setSwapInterval(int /*interval*/) {
return GHOST_kFailure;
}
diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm
index 0b290c617a5..ae7e7a69854 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.mm
+++ b/intern/ghost/intern/GHOST_ContextCGL.mm
@@ -292,14 +292,16 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
[m_openGLView setPixelFormat:pixelFormat];
- m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:s_sharedOpenGLContext];
+ m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:s_sharedOpenGLContext]; // +1 refCount to pixelFormat
if (m_openGLContext == nil)
goto error;
if (s_sharedCount == 0)
s_sharedOpenGLContext = m_openGLContext;
-
+
+ [pixelFormat release]; // -1 refCount to pixelFormat
+
s_sharedCount++;
#ifdef GHOST_MULTITHREADED_OPENGL
@@ -332,6 +334,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
error:
[m_openGLView setOpenGLContext:prev_openGLContext];
+ [pixelFormat release];
[pool drain];
diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp
index 055737481ae..4f4cab77602 100644
--- a/intern/ghost/intern/GHOST_ContextWGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextWGL.cpp
@@ -120,9 +120,9 @@ GHOST_ContextWGL::~GHOST_ContextWGL()
#endif
#ifndef NDEBUG
- delete m_dummyRenderer;
- delete m_dummyVendor;
- delete m_dummyVersion;
+ free((void*)m_dummyRenderer);
+ free((void*)m_dummyVendor);
+ free((void*)m_dummyVersion);
#endif
}
@@ -393,9 +393,9 @@ void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD)
// the following are not technially WGLEW, but they also require a context to work
#ifndef NDEBUG
- delete m_dummyRenderer;
- delete m_dummyVendor;
- delete m_dummyVersion;
+ free((void*)m_dummyRenderer);
+ free((void*)m_dummyVendor);
+ free((void*)m_dummyVersion);
m_dummyRenderer = _strdup(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
m_dummyVendor = _strdup(reinterpret_cast<const char *>(glGetString(GL_VENDOR)));
@@ -888,7 +888,7 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
if (!s_warn_old) {
if ((strcmp(vendor, "Microsoft Corporation") == 0 ||
- strcmp(renderer, "GDI Generic") == 0) && version[0] == '1' && version[0] == '1')
+ strcmp(renderer, "GDI Generic") == 0) && version[0] == '1' && version[2] == '1')
{
MessageBox(m_hWnd, "Your system does not use 3D hardware acceleration.\n"
"Such systems can cause stability problems in Blender and they are unsupported.\n\n"
diff --git a/intern/ghost/intern/GHOST_Debug.h b/intern/ghost/intern/GHOST_Debug.h
index 9292235a9c7..db49627b378 100644
--- a/intern/ghost/intern/GHOST_Debug.h
+++ b/intern/ghost/intern/GHOST_Debug.h
@@ -80,7 +80,7 @@
} \
} (void)0
#else // GHOST_DEBUG
-# define GHOST_ASSERT(x, info)
+# define GHOST_ASSERT(x, info) ((void)0)
#endif // GHOST_DEBUG
#endif // __GHOST_DEBUG_H__
diff --git a/intern/ghost/intern/GHOST_DisplayManagerX11.cpp b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp
index 24289e6b006..0cc116292c0 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerX11.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp
@@ -90,6 +90,7 @@ getNumDisplaySettings(
numSettings = 1;
#endif
+ (void) display;
return GHOST_kSuccess;
}
@@ -116,6 +117,8 @@ getDisplaySetting(
if (dpy == NULL)
return GHOST_kFailure;
+ (void) display;
+
#ifdef WITH_X11_XF86VMODE
int majorVersion, minorVersion;
@@ -171,7 +174,7 @@ getCurrentDisplaySetting(
GHOST_TSuccess
GHOST_DisplayManagerX11::
setCurrentDisplaySetting(
- GHOST_TUns8 display,
+ GHOST_TUns8 /*display*/,
const GHOST_DisplaySetting& setting)
{
#ifdef WITH_X11_XF86VMODE
diff --git a/intern/ghost/intern/GHOST_DropTargetX11.cpp b/intern/ghost/intern/GHOST_DropTargetX11.cpp
index 639fd503759..0efc8a78df5 100644
--- a/intern/ghost/intern/GHOST_DropTargetX11.cpp
+++ b/intern/ghost/intern/GHOST_DropTargetX11.cpp
@@ -132,7 +132,8 @@ void GHOST_DropTargetX11::UrlDecode(char *decodedOut, int bufferSize, const char
unsigned int i;
unsigned int len = strlen(encodedIn);
DecodeState_e state = STATE_SEARCH;
- int j, asciiCharacter;
+ int j;
+ unsigned int asciiCharacter;
char tempNumBuf[3] = {0};
bool bothDigits = true;
diff --git a/intern/ghost/intern/GHOST_EventDragnDrop.h b/intern/ghost/intern/GHOST_EventDragnDrop.h
index c51f9568087..b7bf37c99d8 100644
--- a/intern/ghost/intern/GHOST_EventDragnDrop.h
+++ b/intern/ghost/intern/GHOST_EventDragnDrop.h
@@ -112,6 +112,7 @@ public:
for (i = 0; i < strArray->count; i++)
free(strArray->strings[i]);
+ free(strArray->strings);
free(strArray);
}
break;
diff --git a/intern/ghost/intern/GHOST_EventPrinter.cpp b/intern/ghost/intern/GHOST_EventPrinter.cpp
index 4b7be84ac81..f25f6637cb1 100644
--- a/intern/ghost/intern/GHOST_EventPrinter.cpp
+++ b/intern/ghost/intern/GHOST_EventPrinter.cpp
@@ -179,6 +179,9 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event)
std::cout << "not found"; handled = false;
break;
}
+
+ std::cout.flush();
+
return handled;
}
diff --git a/intern/ghost/intern/GHOST_NDOFManagerX11.cpp b/intern/ghost/intern/GHOST_NDOFManagerX11.cpp
index de44b36c73e..75e476c287f 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerX11.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManagerX11.cpp
@@ -43,7 +43,7 @@ GHOST_NDOFManagerX11::GHOST_NDOFManagerX11(GHOST_System& sys)
#define MAX_LINE_LENGTH 100
/* look for USB devices with Logitech or 3Dconnexion's vendor ID */
- FILE *command_output = popen("lsusb | grep '046d:\|256f:'", "r");
+ FILE *command_output = popen("lsusb | grep '046d:\\|256f:'", "r");
if (command_output) {
char line[MAX_LINE_LENGTH] = {0};
while (fgets(line, MAX_LINE_LENGTH, command_output)) {
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index fef8fda7da3..baa1bdff79a 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -169,7 +169,7 @@ GHOST_TSuccess GHOST_System::beginFullScreen(const GHOST_DisplaySetting& setting
}
-GHOST_TSuccess GHOST_System::updateFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow **window)
+GHOST_TSuccess GHOST_System::updateFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow ** /*window*/)
{
GHOST_TSuccess success = GHOST_kFailure;
GHOST_ASSERT(m_windowManager, "GHOST_System::updateFullScreen(): invalid window manager");
@@ -371,7 +371,7 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window, const
}
-int GHOST_System::confirmQuit(GHOST_IWindow *window) const
+int GHOST_System::confirmQuit(GHOST_IWindow * /*window*/) const
{
return 1;
}
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index 095c738e1e0..bdcaadba2f3 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -73,6 +73,10 @@ static GHOST_TButtonMask convertButton(int button)
return GHOST_kButtonMaskButton4;
case 4:
return GHOST_kButtonMaskButton5;
+ case 5:
+ return GHOST_kButtonMaskButton6;
+ case 6:
+ return GHOST_kButtonMaskButton7;
default:
return GHOST_kButtonMaskLeft;
}
@@ -882,7 +886,10 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
if (!strArray) return GHOST_kFailure;
strArray->count = [droppedArray count];
- if (strArray->count == 0) return GHOST_kFailure;
+ if (strArray->count == 0) {
+ free(strArray);
+ return GHOST_kFailure;
+ }
strArray->strings = (GHOST_TUns8**) malloc(strArray->count*sizeof(GHOST_TUns8*));
diff --git a/intern/ghost/intern/GHOST_SystemPathsCocoa.mm b/intern/ghost/intern/GHOST_SystemPathsCocoa.mm
index 50ad91eeb99..36ae534da87 100644
--- a/intern/ghost/intern/GHOST_SystemPathsCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemPathsCocoa.mm
@@ -24,14 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-#import <Cocoa/Cocoa.h>
-
-/*For the currently not ported to Cocoa keyboard layout functions (64bit & 10.6 compatible)*/
-#include <Carbon/Carbon.h>
-
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/sysctl.h>
+#import <Foundation/Foundation.h>
#include "GHOST_SystemPathsCocoa.h"
diff --git a/intern/ghost/intern/GHOST_SystemPathsX11.cpp b/intern/ghost/intern/GHOST_SystemPathsX11.cpp
index e2d9733a9b2..5473e404593 100644
--- a/intern/ghost/intern/GHOST_SystemPathsX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemPathsX11.cpp
@@ -121,7 +121,7 @@ const GHOST_TUns8 *GHOST_SystemPathsX11::getBinaryDir() const
return NULL;
}
-void GHOST_SystemPathsX11::addToSystemRecentFiles(const char *filename) const
+void GHOST_SystemPathsX11::addToSystemRecentFiles(const char * /*filename*/) const
{
/* XXXXX TODO: Implementation for X11 if possible */
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 27eb387e9f8..46ed8bbe1fc 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -714,8 +714,8 @@ GHOST_EventWheel *GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window
// zDelta /= WHEEL_DELTA;
// temporary fix below: microsoft now has added more precision, making the above division not work
- if (zDelta <= 0) zDelta = -1; else zDelta = 1;
-
+ zDelta = (zDelta <= 0) ? -1 : 1;
+
// short xPos = (short) LOWORD(lParam); // horizontal position of pointer
// short yPos = (short) HIWORD(lParam); // vertical position of pointer
return new GHOST_EventWheel(getSystem()->getMilliSeconds(), window, zDelta);
@@ -989,6 +989,10 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
eventHandled = true;
ime->UpdateImeWindow(hwnd);
ime->UpdateInfo(hwnd);
+ if (ime->eventImeData.result_len) {
+ /* remove redundant IME event */
+ eventManager->removeTypeEvents(GHOST_kEventImeComposition, window);
+ }
event = processImeEvent(
GHOST_kEventImeComposition,
window,
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index e615ef164c8..3841ae58b8d 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -182,7 +182,7 @@ public:
GHOST_TSuccess getButtons(GHOST_Buttons& buttons) const;
/**
- * Returns unsinged char from CUT_BUFFER0
+ * Returns unsigned char from CUT_BUFFER0
* \param selection Used by X11 only
* \return Returns the Clipboard
*/
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index 241ce9728cc..7a4fb254ce7 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -329,7 +329,7 @@ createWindow(const STR_String& title,
}
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
-static void destroyIMCallback(XIM xim, XPointer ptr, XPointer data)
+static void destroyIMCallback(XIM /*xim*/, XPointer ptr, XPointer /*data*/)
{
GHOST_PRINT("XIM server died\n");
@@ -1882,7 +1882,7 @@ GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType,
* Basically it will not crash blender now if you have a X device that
* is configured but not plugged in.
*/
-int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent)
+int GHOST_X11_ApplicationErrorHandler(Display * /*display*/, XErrorEvent *theEvent)
{
fprintf(stderr, "Ignoring Xlib error: error code %d request code %d\n",
theEvent->error_code, theEvent->request_code);
@@ -1891,7 +1891,7 @@ int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent)
return 0;
}
-int GHOST_X11_ApplicationIOErrorHandler(Display *display)
+int GHOST_X11_ApplicationIOErrorHandler(Display * /*display*/)
{
fprintf(stderr, "Ignoring Xlib error: error IO\n");
diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h
index 4004bda11cb..f4d4825a12a 100644
--- a/intern/ghost/intern/GHOST_SystemX11.h
+++ b/intern/ghost/intern/GHOST_SystemX11.h
@@ -157,10 +157,6 @@ public:
);
/**
- * \section Interface Inherited from GHOST_ISystem
- */
-
- /**
* Retrieves events from the system and stores them in the queue.
* \param waitForEvent Flag to wait for an event (or return immediately).
* \return Indication of the presence of events.
@@ -170,9 +166,6 @@ public:
bool waitForEvent
);
- /**
- * \section Interface Inherited from GHOST_System
- */
GHOST_TSuccess
getCursorPosition(
GHOST_TInt32& x,
@@ -206,7 +199,6 @@ public:
) const;
/**
- * \section Interface Dirty
* Flag a window as dirty. This will
* generate a GHOST window update event on a call to processEvents()
*/
@@ -241,7 +233,7 @@ public:
unsigned int *context) const;
/**
- * Returns unsinged char from CUT_BUFFER0
+ * Returns unsigned char from CUT_BUFFER0
* \param selection Get selection, X11 only feature
* \return Returns the Clipboard indicated by Flag
*/
@@ -271,7 +263,7 @@ public:
/**
* \see GHOST_ISystem
*/
- int toggleConsole(int action) {
+ int toggleConsole(int /*action*/) {
return 0;
}
diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp
index dd6154a42bb..71fa260f0f2 100644
--- a/intern/ghost/intern/GHOST_Window.cpp
+++ b/intern/ghost/intern/GHOST_Window.cpp
@@ -46,7 +46,7 @@ GHOST_Window::GHOST_Window(
GHOST_TUns32 width, GHOST_TUns32 height,
GHOST_TWindowState state,
const bool wantStereoVisual,
- const bool exclusive,
+ const bool /*exclusive*/,
const GHOST_TUns16 wantNumOfAASamples)
: m_drawingContextType(GHOST_kDrawingContextTypeNone),
m_cursorVisible(true),
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index b78a690fcad..d894a30bf25 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -182,7 +182,7 @@ public:
* Sets the progress bar value displayed in the window/application icon
* \param progress The progress % (0.0 to 1.0)
*/
- virtual GHOST_TSuccess setProgressBar(float progress) {
+ virtual GHOST_TSuccess setProgressBar(float /*progress*/) {
return GHOST_kFailure;
}
@@ -329,7 +329,7 @@ protected:
* Sets the cursor grab on the window using
* native window system calls.
*/
- virtual GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) {
+ virtual GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode /*mode*/) {
return GHOST_kSuccess;
}
diff --git a/intern/ghost/intern/GHOST_WindowManager.cpp b/intern/ghost/intern/GHOST_WindowManager.cpp
index 1f20e01ca73..83490cecce5 100644
--- a/intern/ghost/intern/GHOST_WindowManager.cpp
+++ b/intern/ghost/intern/GHOST_WindowManager.cpp
@@ -121,7 +121,7 @@ GHOST_IWindow *GHOST_WindowManager::getFullScreenWindow(void) const
GHOST_TSuccess GHOST_WindowManager::beginFullScreen(GHOST_IWindow *window,
- bool stereoVisual)
+ bool /*stereoVisual*/)
{
GHOST_TSuccess success = GHOST_kFailure;
GHOST_ASSERT(window, "GHOST_WindowManager::beginFullScreen(): invalid window");
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index 1eaef243df9..3a9b1529a8b 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -197,8 +197,6 @@ public:
GHOST_TSuccess setOrder(GHOST_TWindowOrder order);
/**
-
- /**
* Invalidates the contents of this window.
*/
GHOST_TSuccess invalidate();
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index 613b4dfe4be..bd0d6829e27 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -291,11 +291,17 @@ GHOST_WindowX11(
m_visualInfo(NULL),
m_normal_state(GHOST_kWindowStateNormal),
m_system(system),
- m_valid_setup(false),
m_invalid_window(false),
m_empty_cursor(None),
m_custom_cursor(None),
- m_visible_cursor(None)
+ m_visible_cursor(None),
+#ifdef WITH_XDND
+ m_dropTarget(NULL),
+#endif
+#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
+ m_xic(NULL),
+#endif
+ m_valid_setup(false)
{
if (type == GHOST_kDrawingContextTypeOpenGL) {
m_visualInfo = x11_visualinfo_from_glx(m_display, stereoVisual, &m_wantNumOfAASamples);
@@ -306,10 +312,10 @@ GHOST_WindowX11(
m_visualInfo = XGetVisualInfo(m_display, 0, &tmp, &n);
}
- /* exit if this is the first window */
+ /* caller needs to check 'getValid()' */
if (m_visualInfo == NULL) {
- fprintf(stderr, "initial window could not find the GLX extension, exit!\n");
- exit(EXIT_FAILURE);
+ fprintf(stderr, "initial window could not find the GLX extension\n");
+ return;
}
unsigned int xattributes_valuemask = 0;
@@ -486,11 +492,6 @@ GHOST_WindowX11(
}
}
-#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
- m_xic = NULL;
-#endif
-
-
/* Set the window hints */
{
XWMHints *xwmhints = XAllocWMHints();
@@ -561,7 +562,7 @@ GHOST_WindowX11(
}
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
-static void destroyICCallback(XIC xic, XPointer ptr, XPointer data)
+static void destroyICCallback(XIC /*xic*/, XPointer ptr, XPointer /*data*/)
{
GHOST_PRINT("XIM input context destroyed\n");
@@ -1216,15 +1217,6 @@ validate()
GHOST_WindowX11::
~GHOST_WindowX11()
{
- static Atom Primary_atom, Clipboard_atom;
- Window p_owner, c_owner;
- /*Change the owner of the Atoms to None if we are the owner*/
- Primary_atom = XInternAtom(m_display, "PRIMARY", False);
- Clipboard_atom = XInternAtom(m_display, "CLIPBOARD", False);
-
- p_owner = XGetSelectionOwner(m_display, Primary_atom);
- c_owner = XGetSelectionOwner(m_display, Clipboard_atom);
-
std::map<unsigned int, Cursor>::iterator it = m_standard_cursors.begin();
for (; it != m_standard_cursors.end(); ++it) {
XFreeCursor(m_display, it->second);
@@ -1237,11 +1229,23 @@ GHOST_WindowX11::
XFreeCursor(m_display, m_custom_cursor);
}
- if (p_owner == m_window) {
- XSetSelectionOwner(m_display, Primary_atom, None, CurrentTime);
- }
- if (c_owner == m_window) {
- XSetSelectionOwner(m_display, Clipboard_atom, None, CurrentTime);
+ if (m_valid_setup) {
+ static Atom Primary_atom, Clipboard_atom;
+ Window p_owner, c_owner;
+ /*Change the owner of the Atoms to None if we are the owner*/
+ Primary_atom = XInternAtom(m_display, "PRIMARY", False);
+ Clipboard_atom = XInternAtom(m_display, "CLIPBOARD", False);
+
+
+ p_owner = XGetSelectionOwner(m_display, Primary_atom);
+ c_owner = XGetSelectionOwner(m_display, Clipboard_atom);
+
+ if (p_owner == m_window) {
+ XSetSelectionOwner(m_display, Primary_atom, None, CurrentTime);
+ }
+ if (c_owner == m_window) {
+ XSetSelectionOwner(m_display, Clipboard_atom, None, CurrentTime);
+ }
}
if (m_visualInfo) {
@@ -1260,7 +1264,9 @@ GHOST_WindowX11::
releaseNativeHandles();
- XDestroyWindow(m_display, m_window);
+ if (m_valid_setup) {
+ XDestroyWindow(m_display, m_window);
+ }
}
@@ -1536,8 +1542,8 @@ setWindowCustomCursorShape(
int sizey,
int hotX,
int hotY,
- int fg_color,
- int bg_color)
+ int /*fg_color*/,
+ int /*bg_color*/)
{
Colormap colormap = DefaultColormap(m_display, m_visualInfo->screen);
Pixmap bitmap_pix, mask_pix;
diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h
index eaa8a5327f7..277afe38e19 100644
--- a/intern/ghost/intern/GHOST_WindowX11.h
+++ b/intern/ghost/intern/GHOST_WindowX11.h
@@ -327,8 +327,6 @@ private:
/** A pointer to the typed system class. */
GHOST_SystemX11 *m_system;
- bool m_valid_setup;
-
/** Used to concatenate calls to invalidate() on this window. */
bool m_invalid_window;
@@ -356,6 +354,8 @@ private:
XIC m_xic;
#endif
+ bool m_valid_setup;
+
void icccmSetState(int state);
int icccmGetState() const;
diff --git a/intern/ghost/test/CMakeLists.txt b/intern/ghost/test/CMakeLists.txt
index 165f5b414b6..e1475966d47 100644
--- a/intern/ghost/test/CMakeLists.txt
+++ b/intern/ghost/test/CMakeLists.txt
@@ -115,6 +115,13 @@ suffix_relpaths(SRC_NEW "${SRC}" "../../../extern/wcwidth/")
include_directories(${INC_NEW})
add_library(wcwidth_lib ${SRC_NEW})
+# glew-mx
+include(${CMAKE_SOURCE_DIR}/../../../intern/glew-mx/CMakeLists.txt)
+suffix_relpaths(INC_NEW "${INC}" "../../../intern/glew-mx/")
+suffix_relpaths(SRC_NEW "${SRC}" "../../../intern/glew-mx/")
+include_directories(${INC_NEW})
+add_library(glewmx_lib ${SRC_NEW})
+
# grr, blenfont needs BLI
include_directories(
"../../../source/blender/blenlib"
@@ -136,6 +143,7 @@ add_library(bli_lib
"../../../source/blender/blenlib/intern/BLI_linklist.c"
"../../../source/blender/blenlib/intern/BLI_memarena.c"
"../../../source/blender/blenlib/intern/BLI_mempool.c"
+ "../../../source/blender/blenlib/intern/system.c"
)
set(PLATFORM_CGLAGS)
@@ -190,6 +198,7 @@ add_executable(gears_c
target_link_libraries(gears_c
ghost_lib
+ glewmx_lib
string_lib
${OPENGL_gl_LIBRARY}
${OPENGL_glu_LIBRARY}
@@ -203,6 +212,7 @@ add_executable(gears_cpp
target_link_libraries(gears_cpp
ghost_lib
+ glewmx_lib
string_lib
${OPENGL_gl_LIBRARY}
${OPENGL_glu_LIBRARY}
@@ -231,6 +241,7 @@ target_link_libraries(multitest_c
blenfont_lib
bli_lib
ghost_lib
+ glewmx_lib
string_lib
guardedalloc_lib
wcwidth_lib
diff --git a/intern/ghost/test/gears/GHOST_C-Test.c b/intern/ghost/test/gears/GHOST_C-Test.c
index 00ae4bb25b4..c635ab9be5b 100644
--- a/intern/ghost/test/gears/GHOST_C-Test.c
+++ b/intern/ghost/test/gears/GHOST_C-Test.c
@@ -448,6 +448,7 @@ int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData)
int main(int argc, char **argv)
{
+ GHOST_GLSettings glSettings = {0};
char *title1 = "gears - main window";
char *title2 = "gears - secondary window";
GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(processEvent, NULL);
@@ -459,16 +460,12 @@ int main(int argc, char **argv)
if (shSystem)
{
/* Create the main window */
- sMainWindow = GHOST_CreateWindow(shSystem,
- title1,
- 10,
- 64,
- 320,
- 200,
- GHOST_kWindowStateNormal,
- GHOST_kDrawingContextTypeOpenGL,
- FALSE,
- FALSE);
+ sMainWindow = GHOST_CreateWindow(
+ shSystem, title1,
+ 10, 64, 320, 200,
+ GHOST_kWindowStateNormal,
+ GHOST_kDrawingContextTypeOpenGL,
+ glSettings);
if (!sMainWindow)
{
printf("could not create main window\n");
@@ -476,16 +473,13 @@ int main(int argc, char **argv)
}
/* Create a secondary window */
- sSecondaryWindow = GHOST_CreateWindow(shSystem,
- title2,
- 340,
- 64,
- 320,
- 200,
- GHOST_kWindowStateNormal,
- GHOST_kDrawingContextTypeOpenGL,
- FALSE,
- FALSE);
+ sSecondaryWindow = GHOST_CreateWindow(
+ shSystem,
+ title2,
+ 340, 64, 320, 200,
+ GHOST_kWindowStateNormal,
+ GHOST_kDrawingContextTypeOpenGL,
+ glSettings);
if (!sSecondaryWindow)
{
printf("could not create secondary window\n");
diff --git a/intern/ghost/test/gears/GHOST_Test.cpp b/intern/ghost/test/gears/GHOST_Test.cpp
index a81aaa85ecf..d6c8f25707c 100644
--- a/intern/ghost/test/gears/GHOST_Test.cpp
+++ b/intern/ghost/test/gears/GHOST_Test.cpp
@@ -418,12 +418,17 @@ Application::Application(GHOST_ISystem *system)
m_gearsTimer(0), m_testTimer(0), m_cursor(GHOST_kStandardCursorFirstCursor),
m_exitRequested(false), stereo(false)
{
+ GHOST_GLSettings glSettings = {0};
fApp = this;
// Create the main window
STR_String title1("gears - main window");
- m_mainWindow = system->createWindow(title1, 10, 64, 320, 200, GHOST_kWindowStateNormal,
- GHOST_kDrawingContextTypeOpenGL, false, false);
+ m_mainWindow = system->createWindow(
+ title1,
+ 10, 64, 320, 200,
+ GHOST_kWindowStateNormal,
+ GHOST_kDrawingContextTypeOpenGL,
+ glSettings);
if (!m_mainWindow) {
std::cout << "could not create main window\n";
@@ -432,8 +437,12 @@ Application::Application(GHOST_ISystem *system)
// Create a secondary window
STR_String title2("gears - secondary window");
- m_secondaryWindow = system->createWindow(title2, 340, 64, 320, 200, GHOST_kWindowStateNormal,
- GHOST_kDrawingContextTypeOpenGL, false, false);
+ m_secondaryWindow = system->createWindow(
+ title2,
+ 340, 64, 320, 200,
+ GHOST_kWindowStateNormal,
+ GHOST_kDrawingContextTypeOpenGL,
+ glSettings);
if (!m_secondaryWindow) {
std::cout << "could not create secondary window\n";
exit(-1);
diff --git a/intern/ghost/test/multitest/MultiTest.c b/intern/ghost/test/multitest/MultiTest.c
index 9a192c17180..a5b5a511cb2 100644
--- a/intern/ghost/test/multitest/MultiTest.c
+++ b/intern/ghost/test/multitest/MultiTest.c
@@ -309,13 +309,18 @@ static void mainwindow_timer_proc(GHOST_TimerTaskHandle task, GHOST_TUns64 time)
mainwindow_log(mw, buf);
}
-MainWindow *mainwindow_new(MultiTestApp *app) {
+MainWindow *mainwindow_new(MultiTestApp *app)
+{
GHOST_SystemHandle sys = multitestapp_get_system(app);
GHOST_WindowHandle win;
+ GHOST_GLSettings glSettings = {0};
- win = GHOST_CreateWindow(sys, "MultiTest:Main", 40, 40, 400, 400,
- GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL,
- FALSE, FALSE);
+ win = GHOST_CreateWindow(
+ sys, "MultiTest:Main",
+ 40, 40, 400, 400,
+ GHOST_kWindowStateNormal,
+ GHOST_kDrawingContextTypeOpenGL,
+ glSettings);
if (win) {
MainWindow *mw = MEM_callocN(sizeof(*mw), "mainwindow_new");
@@ -577,15 +582,20 @@ static void loggerwindow_handle(void *priv, GHOST_EventHandle evt)
/**/
-LoggerWindow *loggerwindow_new(MultiTestApp *app) {
+LoggerWindow *loggerwindow_new(MultiTestApp *app)
+{
+ GHOST_GLSettings glSettings = {0};
GHOST_SystemHandle sys = multitestapp_get_system(app);
GHOST_TUns32 screensize[2];
GHOST_WindowHandle win;
GHOST_GetMainDisplayDimensions(sys, &screensize[0], &screensize[1]);
- win = GHOST_CreateWindow(sys, "MultiTest:Logger", 40, screensize[1] - 432,
- 800, 300, GHOST_kWindowStateNormal,
- GHOST_kDrawingContextTypeOpenGL, FALSE, FALSE);
+ win = GHOST_CreateWindow(
+ sys, "MultiTest:Logger",
+ 40, screensize[1] - 432, 800, 300,
+ GHOST_kWindowStateNormal,
+ GHOST_kDrawingContextTypeOpenGL,
+ glSettings);
if (win) {
LoggerWindow *lw = MEM_callocN(sizeof(*lw), "loggerwindow_new");
@@ -775,13 +785,18 @@ static void extrawindow_handle(void *priv, GHOST_EventHandle evt)
/**/
-ExtraWindow *extrawindow_new(MultiTestApp *app) {
+ExtraWindow *extrawindow_new(MultiTestApp *app)
+{
+ GHOST_GLSettings glSettings = {0};
GHOST_SystemHandle sys = multitestapp_get_system(app);
GHOST_WindowHandle win;
- win = GHOST_CreateWindow(sys, "MultiTest:Extra", 500, 40, 400, 400,
- GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL,
- FALSE, FALSE);
+ win = GHOST_CreateWindow(
+ sys, "MultiTest:Extra",
+ 500, 40, 400, 400,
+ GHOST_kWindowStateNormal,
+ GHOST_kDrawingContextTypeOpenGL,
+ glSettings);
if (win) {
ExtraWindow *ew = MEM_callocN(sizeof(*ew), "mainwindow_new");
diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h
index f0a69f99385..05a98c1a4e5 100644
--- a/intern/guardedalloc/MEM_guardedalloc.h
+++ b/intern/guardedalloc/MEM_guardedalloc.h
@@ -177,7 +177,23 @@ extern "C" {
/** Get the peak memory usage in bytes, including mmap allocations. */
extern size_t (*MEM_get_peak_memory)(void) ATTR_WARN_UNUSED_RESULT;
-#define MEM_SAFE_FREE(v) if (v) { MEM_freeN(v); v = NULL; } (void)0
+#ifdef __GNUC__
+#define MEM_SAFE_FREE(v) do { \
+ typeof(&(v)) _v = &(v); \
+ if (*_v) { \
+ MEM_freeN(*_v); \
+ *_v = NULL; \
+ } \
+} while (0)
+#else
+#define MEM_SAFE_FREE(v) do { \
+ void ** _v = (void **)&(v); \
+ if (*_v) { \
+ MEM_freeN(*_v); \
+ *_v = NULL; \
+ } \
+} while (0)
+#endif
/* overhead for lockfree allocator (use to avoid slop-space) */
#define MEM_SIZE_OVERHEAD sizeof(size_t)
diff --git a/intern/guardedalloc/intern/mallocn_guarded_impl.c b/intern/guardedalloc/intern/mallocn_guarded_impl.c
index bdcace243d9..88d6f35d438 100644
--- a/intern/guardedalloc/intern/mallocn_guarded_impl.c
+++ b/intern/guardedalloc/intern/mallocn_guarded_impl.c
@@ -711,7 +711,7 @@ void MEM_guarded_printmemlist_stats(void)
totpb++;
pb++;
- if (!membl->mmap) {
+ if (!membl->mmap && membl->alignment == 0) {
mem_in_use_slop += (sizeof(MemHead) + sizeof(MemTail) +
malloc_usable_size((void *)membl)) - membl->len;
}
diff --git a/intern/iksolver/extern/IK_solver.h b/intern/iksolver/extern/IK_solver.h
index 4de9f143e77..55223806d5c 100644
--- a/intern/iksolver/extern/IK_solver.h
+++ b/intern/iksolver/extern/IK_solver.h
@@ -35,10 +35,10 @@
* Copyright (C) 2001 NaN Technologies B.V.
*
- * @author Laurence, Brecht
- * @mainpage IK - Blender inverse kinematics module.
+ * \author Laurence, Brecht
+ * \page IK - Blender inverse kinematics module.
*
- * @section about About the IK module
+ * \section about About the IK module
*
* This module allows you to create segments and form them into
* tree. You can then define a goal points that the end of a given
@@ -47,7 +47,7 @@
* to get the as near as possible to the goal. This solver uses an
* inverse jacobian method to find a solution.
*
- * @section issues Known issues with this IK solver.
+ * \section issues Known issues with this IK solver.
*
* - There is currently no support for joint constraints in the
* solver. This is within the realms of possibility - please ask
@@ -60,7 +60,7 @@
* Other algorithms exist which are more suitable for real-time
* applications, please ask if this functionality is required.
*
- * @section dependencies Dependencies
+ * \section dependencies Dependencies
*
* This module only depends on Moto.
*/
diff --git a/intern/itasc/CMakeLists.txt b/intern/itasc/CMakeLists.txt
index bc3ea0cf24c..bdf0f88e516 100644
--- a/intern/itasc/CMakeLists.txt
+++ b/intern/itasc/CMakeLists.txt
@@ -28,9 +28,244 @@ set(INC
)
set(INC_SYS
- ../../extern/Eigen3
+ ${EIGEN3_INCLUDE_DIRS}
)
+if(NOT WITH_SYSTEM_EIGEN3)
+ set(EIGEN3_HEADERS
+ # until we have another user...
+ ../../extern/Eigen3/Eigen/src/Cholesky/LDLT.h
+ ../../extern/Eigen3/Eigen/src/Cholesky/LLT.h
+ ../../extern/Eigen3/Eigen/src/Cholesky/LLT_MKL.h
+ ../../extern/Eigen3/Eigen/src/CholmodSupport/CholmodSupport.h
+ ../../extern/Eigen3/Eigen/src/Core/Array.h
+ ../../extern/Eigen3/Eigen/src/Core/ArrayBase.h
+ ../../extern/Eigen3/Eigen/src/Core/ArrayWrapper.h
+ ../../extern/Eigen3/Eigen/src/Core/Assign.h
+ ../../extern/Eigen3/Eigen/src/Core/Assign_MKL.h
+ ../../extern/Eigen3/Eigen/src/Core/BandMatrix.h
+ ../../extern/Eigen3/Eigen/src/Core/Block.h
+ ../../extern/Eigen3/Eigen/src/Core/BooleanRedux.h
+ ../../extern/Eigen3/Eigen/src/Core/CommaInitializer.h
+ ../../extern/Eigen3/Eigen/src/Core/CwiseBinaryOp.h
+ ../../extern/Eigen3/Eigen/src/Core/CwiseNullaryOp.h
+ ../../extern/Eigen3/Eigen/src/Core/CwiseUnaryOp.h
+ ../../extern/Eigen3/Eigen/src/Core/CwiseUnaryView.h
+ ../../extern/Eigen3/Eigen/src/Core/DenseBase.h
+ ../../extern/Eigen3/Eigen/src/Core/DenseCoeffsBase.h
+ ../../extern/Eigen3/Eigen/src/Core/DenseStorage.h
+ ../../extern/Eigen3/Eigen/src/Core/Diagonal.h
+ ../../extern/Eigen3/Eigen/src/Core/DiagonalMatrix.h
+ ../../extern/Eigen3/Eigen/src/Core/DiagonalProduct.h
+ ../../extern/Eigen3/Eigen/src/Core/Dot.h
+ ../../extern/Eigen3/Eigen/src/Core/EigenBase.h
+ ../../extern/Eigen3/Eigen/src/Core/Flagged.h
+ ../../extern/Eigen3/Eigen/src/Core/ForceAlignedAccess.h
+ ../../extern/Eigen3/Eigen/src/Core/Functors.h
+ ../../extern/Eigen3/Eigen/src/Core/Fuzzy.h
+ ../../extern/Eigen3/Eigen/src/Core/GeneralProduct.h
+ ../../extern/Eigen3/Eigen/src/Core/GenericPacketMath.h
+ ../../extern/Eigen3/Eigen/src/Core/GlobalFunctions.h
+ ../../extern/Eigen3/Eigen/src/Core/IO.h
+ ../../extern/Eigen3/Eigen/src/Core/Map.h
+ ../../extern/Eigen3/Eigen/src/Core/MapBase.h
+ ../../extern/Eigen3/Eigen/src/Core/MathFunctions.h
+ ../../extern/Eigen3/Eigen/src/Core/Matrix.h
+ ../../extern/Eigen3/Eigen/src/Core/MatrixBase.h
+ ../../extern/Eigen3/Eigen/src/Core/NestByValue.h
+ ../../extern/Eigen3/Eigen/src/Core/NoAlias.h
+ ../../extern/Eigen3/Eigen/src/Core/NumTraits.h
+ ../../extern/Eigen3/Eigen/src/Core/PermutationMatrix.h
+ ../../extern/Eigen3/Eigen/src/Core/PlainObjectBase.h
+ ../../extern/Eigen3/Eigen/src/Core/Product.h
+ ../../extern/Eigen3/Eigen/src/Core/ProductBase.h
+ ../../extern/Eigen3/Eigen/src/Core/Random.h
+ ../../extern/Eigen3/Eigen/src/Core/Redux.h
+ ../../extern/Eigen3/Eigen/src/Core/Replicate.h
+ ../../extern/Eigen3/Eigen/src/Core/ReturnByValue.h
+ ../../extern/Eigen3/Eigen/src/Core/Reverse.h
+ ../../extern/Eigen3/Eigen/src/Core/Select.h
+ ../../extern/Eigen3/Eigen/src/Core/SelfAdjointView.h
+ ../../extern/Eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h
+ ../../extern/Eigen3/Eigen/src/Core/SolveTriangular.h
+ ../../extern/Eigen3/Eigen/src/Core/StableNorm.h
+ ../../extern/Eigen3/Eigen/src/Core/Stride.h
+ ../../extern/Eigen3/Eigen/src/Core/Swap.h
+ ../../extern/Eigen3/Eigen/src/Core/Transpose.h
+ ../../extern/Eigen3/Eigen/src/Core/Transpositions.h
+ ../../extern/Eigen3/Eigen/src/Core/TriangularMatrix.h
+ ../../extern/Eigen3/Eigen/src/Core/VectorBlock.h
+ ../../extern/Eigen3/Eigen/src/Core/VectorwiseOp.h
+ ../../extern/Eigen3/Eigen/src/Core/Visitor.h
+ ../../extern/Eigen3/Eigen/src/Core/arch/AltiVec/Complex.h
+ ../../extern/Eigen3/Eigen/src/Core/arch/AltiVec/PacketMath.h
+ ../../extern/Eigen3/Eigen/src/Core/arch/Default/Settings.h
+ ../../extern/Eigen3/Eigen/src/Core/arch/NEON/Complex.h
+ ../../extern/Eigen3/Eigen/src/Core/arch/NEON/PacketMath.h
+ ../../extern/Eigen3/Eigen/src/Core/arch/SSE/Complex.h
+ ../../extern/Eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h
+ ../../extern/Eigen3/Eigen/src/Core/arch/SSE/PacketMath.h
+ ../../extern/Eigen3/Eigen/src/Core/products/CoeffBasedProduct.h
+ ../../extern/Eigen3/Eigen/src/Core/products/GeneralBlockPanelKernel.h
+ ../../extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h
+ ../../extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h
+ ../../extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h
+ ../../extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h
+ ../../extern/Eigen3/Eigen/src/Core/products/GeneralMatrixVector.h
+ ../../extern/Eigen3/Eigen/src/Core/products/GeneralMatrixVector_MKL.h
+ ../../extern/Eigen3/Eigen/src/Core/products/Parallelizer.h
+ ../../extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix.h
+ ../../extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix_MKL.h
+ ../../extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixVector.h
+ ../../extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h
+ ../../extern/Eigen3/Eigen/src/Core/products/SelfadjointProduct.h
+ ../../extern/Eigen3/Eigen/src/Core/products/SelfadjointRank2Update.h
+ ../../extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix.h
+ ../../extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h
+ ../../extern/Eigen3/Eigen/src/Core/products/TriangularMatrixVector.h
+ ../../extern/Eigen3/Eigen/src/Core/products/TriangularMatrixVector_MKL.h
+ ../../extern/Eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h
+ ../../extern/Eigen3/Eigen/src/Core/products/TriangularSolverMatrix_MKL.h
+ ../../extern/Eigen3/Eigen/src/Core/products/TriangularSolverVector.h
+ ../../extern/Eigen3/Eigen/src/Core/util/BlasUtil.h
+ ../../extern/Eigen3/Eigen/src/Core/util/Constants.h
+ ../../extern/Eigen3/Eigen/src/Core/util/DisableStupidWarnings.h
+ ../../extern/Eigen3/Eigen/src/Core/util/ForwardDeclarations.h
+ ../../extern/Eigen3/Eigen/src/Core/util/Macros.h
+ ../../extern/Eigen3/Eigen/src/Core/util/Memory.h
+ ../../extern/Eigen3/Eigen/src/Core/util/Meta.h
+ ../../extern/Eigen3/Eigen/src/Core/util/MKL_support.h
+ ../../extern/Eigen3/Eigen/src/Core/util/NonMPL2.h
+ ../../extern/Eigen3/Eigen/src/Core/util/ReenableStupidWarnings.h
+ ../../extern/Eigen3/Eigen/src/Core/util/StaticAssert.h
+ ../../extern/Eigen3/Eigen/src/Core/util/XprHelper.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Block.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Cwise.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/CwiseOperators.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Lazy.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/LeastSquares.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/LU.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Macros.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/MathFunctions.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Memory.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Meta.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Minor.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/QR.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/SVD.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/TriangularSolver.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/VectorBlock.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/AlignedBox.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/All.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/AngleAxis.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Hyperplane.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/ParametrizedLine.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Quaternion.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Rotation2D.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/RotationBase.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Scaling.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Transform.h
+ ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Translation.h
+ ../../extern/Eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h
+ ../../extern/Eigen3/Eigen/src/Eigenvalues/ComplexSchur.h
+ ../../extern/Eigen3/Eigen/src/Eigenvalues/ComplexSchur_MKL.h
+ ../../extern/Eigen3/Eigen/src/Eigenvalues/EigenSolver.h
+ ../../extern/Eigen3/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h
+ ../../extern/Eigen3/Eigen/src/Eigenvalues/HessenbergDecomposition.h
+ ../../extern/Eigen3/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h
+ ../../extern/Eigen3/Eigen/src/Eigenvalues/RealSchur.h
+ ../../extern/Eigen3/Eigen/src/Eigenvalues/RealSchur_MKL.h
+ ../../extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h
+ ../../extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_MKL.h
+ ../../extern/Eigen3/Eigen/src/Eigenvalues/Tridiagonalization.h
+ ../../extern/Eigen3/Eigen/src/Geometry/AlignedBox.h
+ ../../extern/Eigen3/Eigen/src/Geometry/AngleAxis.h
+ ../../extern/Eigen3/Eigen/src/Geometry/EulerAngles.h
+ ../../extern/Eigen3/Eigen/src/Geometry/Homogeneous.h
+ ../../extern/Eigen3/Eigen/src/Geometry/Hyperplane.h
+ ../../extern/Eigen3/Eigen/src/Geometry/OrthoMethods.h
+ ../../extern/Eigen3/Eigen/src/Geometry/ParametrizedLine.h
+ ../../extern/Eigen3/Eigen/src/Geometry/Quaternion.h
+ ../../extern/Eigen3/Eigen/src/Geometry/Rotation2D.h
+ ../../extern/Eigen3/Eigen/src/Geometry/RotationBase.h
+ ../../extern/Eigen3/Eigen/src/Geometry/Scaling.h
+ ../../extern/Eigen3/Eigen/src/Geometry/Transform.h
+ ../../extern/Eigen3/Eigen/src/Geometry/Translation.h
+ ../../extern/Eigen3/Eigen/src/Geometry/Umeyama.h
+ ../../extern/Eigen3/Eigen/src/Geometry/arch/Geometry_SSE.h
+ ../../extern/Eigen3/Eigen/src/Householder/BlockHouseholder.h
+ ../../extern/Eigen3/Eigen/src/Householder/Householder.h
+ ../../extern/Eigen3/Eigen/src/Householder/HouseholderSequence.h
+ ../../extern/Eigen3/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h
+ ../../extern/Eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h
+ ../../extern/Eigen3/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h
+ ../../extern/Eigen3/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h
+ ../../extern/Eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h
+ ../../extern/Eigen3/Eigen/src/Jacobi/Jacobi.h
+ ../../extern/Eigen3/Eigen/src/LU/Determinant.h
+ ../../extern/Eigen3/Eigen/src/LU/FullPivLU.h
+ ../../extern/Eigen3/Eigen/src/LU/Inverse.h
+ ../../extern/Eigen3/Eigen/src/LU/PartialPivLU.h
+ ../../extern/Eigen3/Eigen/src/LU/PartialPivLU_MKL.h
+ ../../extern/Eigen3/Eigen/src/LU/arch/Inverse_SSE.h
+ ../../extern/Eigen3/Eigen/src/misc/blas.h
+ ../../extern/Eigen3/Eigen/src/misc/Image.h
+ ../../extern/Eigen3/Eigen/src/misc/Kernel.h
+ ../../extern/Eigen3/Eigen/src/misc/Solve.h
+ ../../extern/Eigen3/Eigen/src/misc/SparseSolve.h
+ ../../extern/Eigen3/Eigen/src/OrderingMethods/Amd.h
+ ../../extern/Eigen3/Eigen/src/PardisoSupport/PardisoSupport.h
+ ../../extern/Eigen3/Eigen/src/PaStiXSupport/PaStiXSupport.h
+ ../../extern/Eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h
+ ../../extern/Eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h
+ ../../extern/Eigen3/Eigen/src/plugins/BlockMethods.h
+ ../../extern/Eigen3/Eigen/src/plugins/CommonCwiseBinaryOps.h
+ ../../extern/Eigen3/Eigen/src/plugins/CommonCwiseUnaryOps.h
+ ../../extern/Eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h
+ ../../extern/Eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h
+ ../../extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR.h
+ ../../extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR_MKL.h
+ ../../extern/Eigen3/Eigen/src/QR/FullPivHouseholderQR.h
+ ../../extern/Eigen3/Eigen/src/QR/HouseholderQR.h
+ ../../extern/Eigen3/Eigen/src/QR/HouseholderQR_MKL.h
+ ../../extern/Eigen3/Eigen/src/SparseCholesky/SimplicialCholesky.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/AmbiVector.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/CompressedStorage.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/CoreIterators.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/MappedSparseMatrix.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseAssign.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseBlock.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseCwiseUnaryOp.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseDenseProduct.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseDiagonalProduct.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseDot.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseFuzzy.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseMatrix.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseMatrixBase.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparsePermutation.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseProduct.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseRedux.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseSelfAdjointView.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseSparseProductWithPruning.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseTranspose.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseTriangularView.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseUtil.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseVector.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/SparseView.h
+ ../../extern/Eigen3/Eigen/src/SparseCore/TriangularSolver.h
+ ../../extern/Eigen3/Eigen/src/StlSupport/details.h
+ ../../extern/Eigen3/Eigen/src/StlSupport/StdDeque.h
+ ../../extern/Eigen3/Eigen/src/StlSupport/StdList.h
+ ../../extern/Eigen3/Eigen/src/StlSupport/StdVector.h
+ ../../extern/Eigen3/Eigen/src/SuperLUSupport/SuperLUSupport.h
+ ../../extern/Eigen3/Eigen/src/SVD/JacobiSVD.h
+ ../../extern/Eigen3/Eigen/src/SVD/JacobiSVD_MKL.h
+ ../../extern/Eigen3/Eigen/src/SVD/UpperBidiagonalization.h
+ ../../extern/Eigen3/Eigen/src/UmfPackSupport/UmfPackSupport.h
+ )
+endif()
+
set(SRC
Armature.cpp
Cache.cpp
@@ -120,237 +355,9 @@ set(SRC
kdl/frames.inl
kdl/framevel.inl
- # until we have another user...
- ../../extern/Eigen3/Eigen/src/Cholesky/LDLT.h
- ../../extern/Eigen3/Eigen/src/Cholesky/LLT.h
- ../../extern/Eigen3/Eigen/src/Cholesky/LLT_MKL.h
- ../../extern/Eigen3/Eigen/src/CholmodSupport/CholmodSupport.h
- ../../extern/Eigen3/Eigen/src/Core/Array.h
- ../../extern/Eigen3/Eigen/src/Core/ArrayBase.h
- ../../extern/Eigen3/Eigen/src/Core/ArrayWrapper.h
- ../../extern/Eigen3/Eigen/src/Core/Assign.h
- ../../extern/Eigen3/Eigen/src/Core/Assign_MKL.h
- ../../extern/Eigen3/Eigen/src/Core/BandMatrix.h
- ../../extern/Eigen3/Eigen/src/Core/Block.h
- ../../extern/Eigen3/Eigen/src/Core/BooleanRedux.h
- ../../extern/Eigen3/Eigen/src/Core/CommaInitializer.h
- ../../extern/Eigen3/Eigen/src/Core/CwiseBinaryOp.h
- ../../extern/Eigen3/Eigen/src/Core/CwiseNullaryOp.h
- ../../extern/Eigen3/Eigen/src/Core/CwiseUnaryOp.h
- ../../extern/Eigen3/Eigen/src/Core/CwiseUnaryView.h
- ../../extern/Eigen3/Eigen/src/Core/DenseBase.h
- ../../extern/Eigen3/Eigen/src/Core/DenseCoeffsBase.h
- ../../extern/Eigen3/Eigen/src/Core/DenseStorage.h
- ../../extern/Eigen3/Eigen/src/Core/Diagonal.h
- ../../extern/Eigen3/Eigen/src/Core/DiagonalMatrix.h
- ../../extern/Eigen3/Eigen/src/Core/DiagonalProduct.h
- ../../extern/Eigen3/Eigen/src/Core/Dot.h
- ../../extern/Eigen3/Eigen/src/Core/EigenBase.h
- ../../extern/Eigen3/Eigen/src/Core/Flagged.h
- ../../extern/Eigen3/Eigen/src/Core/ForceAlignedAccess.h
- ../../extern/Eigen3/Eigen/src/Core/Functors.h
- ../../extern/Eigen3/Eigen/src/Core/Fuzzy.h
- ../../extern/Eigen3/Eigen/src/Core/GeneralProduct.h
- ../../extern/Eigen3/Eigen/src/Core/GenericPacketMath.h
- ../../extern/Eigen3/Eigen/src/Core/GlobalFunctions.h
- ../../extern/Eigen3/Eigen/src/Core/IO.h
- ../../extern/Eigen3/Eigen/src/Core/Map.h
- ../../extern/Eigen3/Eigen/src/Core/MapBase.h
- ../../extern/Eigen3/Eigen/src/Core/MathFunctions.h
- ../../extern/Eigen3/Eigen/src/Core/Matrix.h
- ../../extern/Eigen3/Eigen/src/Core/MatrixBase.h
- ../../extern/Eigen3/Eigen/src/Core/NestByValue.h
- ../../extern/Eigen3/Eigen/src/Core/NoAlias.h
- ../../extern/Eigen3/Eigen/src/Core/NumTraits.h
- ../../extern/Eigen3/Eigen/src/Core/PermutationMatrix.h
- ../../extern/Eigen3/Eigen/src/Core/PlainObjectBase.h
- ../../extern/Eigen3/Eigen/src/Core/Product.h
- ../../extern/Eigen3/Eigen/src/Core/ProductBase.h
- ../../extern/Eigen3/Eigen/src/Core/Random.h
- ../../extern/Eigen3/Eigen/src/Core/Redux.h
- ../../extern/Eigen3/Eigen/src/Core/Replicate.h
- ../../extern/Eigen3/Eigen/src/Core/ReturnByValue.h
- ../../extern/Eigen3/Eigen/src/Core/Reverse.h
- ../../extern/Eigen3/Eigen/src/Core/Select.h
- ../../extern/Eigen3/Eigen/src/Core/SelfAdjointView.h
- ../../extern/Eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h
- ../../extern/Eigen3/Eigen/src/Core/SolveTriangular.h
- ../../extern/Eigen3/Eigen/src/Core/StableNorm.h
- ../../extern/Eigen3/Eigen/src/Core/Stride.h
- ../../extern/Eigen3/Eigen/src/Core/Swap.h
- ../../extern/Eigen3/Eigen/src/Core/Transpose.h
- ../../extern/Eigen3/Eigen/src/Core/Transpositions.h
- ../../extern/Eigen3/Eigen/src/Core/TriangularMatrix.h
- ../../extern/Eigen3/Eigen/src/Core/VectorBlock.h
- ../../extern/Eigen3/Eigen/src/Core/VectorwiseOp.h
- ../../extern/Eigen3/Eigen/src/Core/Visitor.h
- ../../extern/Eigen3/Eigen/src/Core/arch/AltiVec/Complex.h
- ../../extern/Eigen3/Eigen/src/Core/arch/AltiVec/PacketMath.h
- ../../extern/Eigen3/Eigen/src/Core/arch/Default/Settings.h
- ../../extern/Eigen3/Eigen/src/Core/arch/NEON/Complex.h
- ../../extern/Eigen3/Eigen/src/Core/arch/NEON/PacketMath.h
- ../../extern/Eigen3/Eigen/src/Core/arch/SSE/Complex.h
- ../../extern/Eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h
- ../../extern/Eigen3/Eigen/src/Core/arch/SSE/PacketMath.h
- ../../extern/Eigen3/Eigen/src/Core/products/CoeffBasedProduct.h
- ../../extern/Eigen3/Eigen/src/Core/products/GeneralBlockPanelKernel.h
- ../../extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h
- ../../extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h
- ../../extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_MKL.h
- ../../extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix_MKL.h
- ../../extern/Eigen3/Eigen/src/Core/products/GeneralMatrixVector.h
- ../../extern/Eigen3/Eigen/src/Core/products/GeneralMatrixVector_MKL.h
- ../../extern/Eigen3/Eigen/src/Core/products/Parallelizer.h
- ../../extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix.h
- ../../extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix_MKL.h
- ../../extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixVector.h
- ../../extern/Eigen3/Eigen/src/Core/products/SelfadjointMatrixVector_MKL.h
- ../../extern/Eigen3/Eigen/src/Core/products/SelfadjointProduct.h
- ../../extern/Eigen3/Eigen/src/Core/products/SelfadjointRank2Update.h
- ../../extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix.h
- ../../extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h
- ../../extern/Eigen3/Eigen/src/Core/products/TriangularMatrixVector.h
- ../../extern/Eigen3/Eigen/src/Core/products/TriangularMatrixVector_MKL.h
- ../../extern/Eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h
- ../../extern/Eigen3/Eigen/src/Core/products/TriangularSolverMatrix_MKL.h
- ../../extern/Eigen3/Eigen/src/Core/products/TriangularSolverVector.h
- ../../extern/Eigen3/Eigen/src/Core/util/BlasUtil.h
- ../../extern/Eigen3/Eigen/src/Core/util/Constants.h
- ../../extern/Eigen3/Eigen/src/Core/util/DisableStupidWarnings.h
- ../../extern/Eigen3/Eigen/src/Core/util/ForwardDeclarations.h
- ../../extern/Eigen3/Eigen/src/Core/util/Macros.h
- ../../extern/Eigen3/Eigen/src/Core/util/Memory.h
- ../../extern/Eigen3/Eigen/src/Core/util/Meta.h
- ../../extern/Eigen3/Eigen/src/Core/util/MKL_support.h
- ../../extern/Eigen3/Eigen/src/Core/util/NonMPL2.h
- ../../extern/Eigen3/Eigen/src/Core/util/ReenableStupidWarnings.h
- ../../extern/Eigen3/Eigen/src/Core/util/StaticAssert.h
- ../../extern/Eigen3/Eigen/src/Core/util/XprHelper.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Block.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Cwise.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/CwiseOperators.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Lazy.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/LeastSquares.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/LU.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Macros.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/MathFunctions.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Memory.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Meta.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Minor.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/QR.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/SVD.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/TriangularSolver.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/VectorBlock.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/AlignedBox.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/All.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/AngleAxis.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Hyperplane.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/ParametrizedLine.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Quaternion.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Rotation2D.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/RotationBase.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Scaling.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Transform.h
- ../../extern/Eigen3/Eigen/src/Eigen2Support/Geometry/Translation.h
- ../../extern/Eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h
- ../../extern/Eigen3/Eigen/src/Eigenvalues/ComplexSchur.h
- ../../extern/Eigen3/Eigen/src/Eigenvalues/ComplexSchur_MKL.h
- ../../extern/Eigen3/Eigen/src/Eigenvalues/EigenSolver.h
- ../../extern/Eigen3/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h
- ../../extern/Eigen3/Eigen/src/Eigenvalues/HessenbergDecomposition.h
- ../../extern/Eigen3/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h
- ../../extern/Eigen3/Eigen/src/Eigenvalues/RealSchur.h
- ../../extern/Eigen3/Eigen/src/Eigenvalues/RealSchur_MKL.h
- ../../extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h
- ../../extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_MKL.h
- ../../extern/Eigen3/Eigen/src/Eigenvalues/Tridiagonalization.h
- ../../extern/Eigen3/Eigen/src/Geometry/AlignedBox.h
- ../../extern/Eigen3/Eigen/src/Geometry/AngleAxis.h
- ../../extern/Eigen3/Eigen/src/Geometry/EulerAngles.h
- ../../extern/Eigen3/Eigen/src/Geometry/Homogeneous.h
- ../../extern/Eigen3/Eigen/src/Geometry/Hyperplane.h
- ../../extern/Eigen3/Eigen/src/Geometry/OrthoMethods.h
- ../../extern/Eigen3/Eigen/src/Geometry/ParametrizedLine.h
- ../../extern/Eigen3/Eigen/src/Geometry/Quaternion.h
- ../../extern/Eigen3/Eigen/src/Geometry/Rotation2D.h
- ../../extern/Eigen3/Eigen/src/Geometry/RotationBase.h
- ../../extern/Eigen3/Eigen/src/Geometry/Scaling.h
- ../../extern/Eigen3/Eigen/src/Geometry/Transform.h
- ../../extern/Eigen3/Eigen/src/Geometry/Translation.h
- ../../extern/Eigen3/Eigen/src/Geometry/Umeyama.h
- ../../extern/Eigen3/Eigen/src/Geometry/arch/Geometry_SSE.h
- ../../extern/Eigen3/Eigen/src/Householder/BlockHouseholder.h
- ../../extern/Eigen3/Eigen/src/Householder/Householder.h
- ../../extern/Eigen3/Eigen/src/Householder/HouseholderSequence.h
- ../../extern/Eigen3/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h
- ../../extern/Eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h
- ../../extern/Eigen3/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h
- ../../extern/Eigen3/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h
- ../../extern/Eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h
- ../../extern/Eigen3/Eigen/src/Jacobi/Jacobi.h
- ../../extern/Eigen3/Eigen/src/LU/Determinant.h
- ../../extern/Eigen3/Eigen/src/LU/FullPivLU.h
- ../../extern/Eigen3/Eigen/src/LU/Inverse.h
- ../../extern/Eigen3/Eigen/src/LU/PartialPivLU.h
- ../../extern/Eigen3/Eigen/src/LU/PartialPivLU_MKL.h
- ../../extern/Eigen3/Eigen/src/LU/arch/Inverse_SSE.h
- ../../extern/Eigen3/Eigen/src/misc/blas.h
- ../../extern/Eigen3/Eigen/src/misc/Image.h
- ../../extern/Eigen3/Eigen/src/misc/Kernel.h
- ../../extern/Eigen3/Eigen/src/misc/Solve.h
- ../../extern/Eigen3/Eigen/src/misc/SparseSolve.h
- ../../extern/Eigen3/Eigen/src/OrderingMethods/Amd.h
- ../../extern/Eigen3/Eigen/src/PardisoSupport/PardisoSupport.h
- ../../extern/Eigen3/Eigen/src/PaStiXSupport/PaStiXSupport.h
- ../../extern/Eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h
- ../../extern/Eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h
- ../../extern/Eigen3/Eigen/src/plugins/BlockMethods.h
- ../../extern/Eigen3/Eigen/src/plugins/CommonCwiseBinaryOps.h
- ../../extern/Eigen3/Eigen/src/plugins/CommonCwiseUnaryOps.h
- ../../extern/Eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h
- ../../extern/Eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h
- ../../extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR.h
- ../../extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR_MKL.h
- ../../extern/Eigen3/Eigen/src/QR/FullPivHouseholderQR.h
- ../../extern/Eigen3/Eigen/src/QR/HouseholderQR.h
- ../../extern/Eigen3/Eigen/src/QR/HouseholderQR_MKL.h
- ../../extern/Eigen3/Eigen/src/SparseCholesky/SimplicialCholesky.h
- ../../extern/Eigen3/Eigen/src/SparseCore/AmbiVector.h
- ../../extern/Eigen3/Eigen/src/SparseCore/CompressedStorage.h
- ../../extern/Eigen3/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h
- ../../extern/Eigen3/Eigen/src/SparseCore/CoreIterators.h
- ../../extern/Eigen3/Eigen/src/SparseCore/MappedSparseMatrix.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseAssign.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseBlock.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseCwiseUnaryOp.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseDenseProduct.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseDiagonalProduct.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseDot.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseFuzzy.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseMatrix.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseMatrixBase.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparsePermutation.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseProduct.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseRedux.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseSelfAdjointView.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseSparseProductWithPruning.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseTranspose.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseTriangularView.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseUtil.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseVector.h
- ../../extern/Eigen3/Eigen/src/SparseCore/SparseView.h
- ../../extern/Eigen3/Eigen/src/SparseCore/TriangularSolver.h
- ../../extern/Eigen3/Eigen/src/StlSupport/details.h
- ../../extern/Eigen3/Eigen/src/StlSupport/StdDeque.h
- ../../extern/Eigen3/Eigen/src/StlSupport/StdList.h
- ../../extern/Eigen3/Eigen/src/StlSupport/StdVector.h
- ../../extern/Eigen3/Eigen/src/SuperLUSupport/SuperLUSupport.h
- ../../extern/Eigen3/Eigen/src/SVD/JacobiSVD.h
- ../../extern/Eigen3/Eigen/src/SVD/JacobiSVD_MKL.h
- ../../extern/Eigen3/Eigen/src/SVD/UpperBidiagonalization.h
- ../../extern/Eigen3/Eigen/src/UmfPackSupport/UmfPackSupport.h
+ ${EIGEN3_HEADERS}
)
+unset(EIGEN3_HEADERS)
blender_add_lib(bf_intern_itasc "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/intern/locale/CMakeLists.txt b/intern/locale/CMakeLists.txt
index 5d933f326f7..6896702fcbf 100644
--- a/intern/locale/CMakeLists.txt
+++ b/intern/locale/CMakeLists.txt
@@ -63,6 +63,12 @@ blender_add_lib(bf_intern_locale "${SRC}" "${INC}" "${INC_SYS}")
# -----------------------------------------------------------------------------
# Build msgfmt executable
+
+if(CMAKE_COMPILER_IS_GNUCC)
+ # workaroud ld.gold linker bug
+ string(REPLACE "-fuse-ld=gold" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+endif()
+
set(MSFFMT_SRC
msgfmt.cc
)
diff --git a/intern/memutil/MEM_CacheLimiter.h b/intern/memutil/MEM_CacheLimiter.h
index 3e8ae7e5a4d..d5a44375885 100644
--- a/intern/memutil/MEM_CacheLimiter.h
+++ b/intern/memutil/MEM_CacheLimiter.h
@@ -29,20 +29,22 @@
#define __MEM_CACHELIMITER_H__
/**
- * @section MEM_CacheLimiter
+ * \section MEM_CacheLimiter
* This class defines a generic memory cache management system
* to limit memory usage to a fixed global maximum.
*
- * Please use the C-API in MEM_CacheLimiterC-Api.h for code written in C.
+ * \note Please use the C-API in MEM_CacheLimiterC-Api.h for code written in C.
*
* Usage example:
*
+ * \code{.cpp}
* class BigFatImage {
* public:
* ~BigFatImage() { tell_everyone_we_are_gone(this); }
* };
*
- * void doit() {
+ * void doit()
+ * {
* MEM_Cache<BigFatImage> BigFatImages;
*
* MEM_Cache_Handle<BigFatImage>* h = BigFatImages.insert(new BigFatImage);
@@ -50,11 +52,12 @@
* BigFatImages.enforce_limits();
* h->ref();
*
- * work with image...
+ * // work with image...
*
* h->unref();
*
- * leave image in cache.
+ * // leave image in cache.
+ * \endcode
*/
#include <list>
diff --git a/intern/memutil/MEM_RefCountPtr.h b/intern/memutil/MEM_RefCountPtr.h
index da10e689fbf..ea865eadd47 100644
--- a/intern/memutil/MEM_RefCountPtr.h
+++ b/intern/memutil/MEM_RefCountPtr.h
@@ -30,9 +30,9 @@
*/
/**
- * @file MEM_RefCountPtr.h
+ * \file MEM_RefCountPtr.h
* Declaration of MEM_RefCounted and MEM_RefCountable classes.
- * @author Laurence
+ * \author Laurence
*/
#ifndef __MEM_REFCOUNTPTR_H__
@@ -41,7 +41,7 @@
#include <stdlib.h> // for NULL !
/**
- * @section MEM_RefCountable
+ * \section MEM_RefCountable
* This is a base class for reference countable objects.
* If you want an object to be shared using a reference
* counted system derrivce from this class. All subclasses
@@ -50,9 +50,9 @@
* defining a static New() method that returns a ref counted
* ptr to a new()ly allocated instance.
*
- * @section Example subclass
- *
+ * \section Example subclass
*
+ * \code{.cpp}
* class MySharedObject : public MEM_RefCountable {
*
* private :
@@ -68,6 +68,7 @@
*
* // other member functions
* };
+ * \endcode
*
* Alternitively you may first wish to define a fully functional
* class and then define a reference counting wrapper for this class.
@@ -75,6 +76,8 @@
* counting.
*
* E.g.
+ *
+ * \code{.cpp}
* class UsefullClass {
* private :
* ...
@@ -108,7 +111,7 @@
* // mechanism to handle object lifetime.
* ~RcUsefullClass();
* };
- *
+ * \endcode
*
*/
@@ -168,7 +171,7 @@ public :
};
/**
- * @section MEM_RefCountPtr
+ * \section MEM_RefCountPtr
*/
template
diff --git a/intern/memutil/MEM_SmartPtr.h b/intern/memutil/MEM_SmartPtr.h
index dd19aae9db9..e0d7b81290f 100644
--- a/intern/memutil/MEM_SmartPtr.h
+++ b/intern/memutil/MEM_SmartPtr.h
@@ -43,7 +43,7 @@
/**
- * @section MEM_SmartPtr
+ * \section MEM_SmartPtr
* This class defines a smart pointer similar to that defined in
* the Standard Template Library but without the painful get()
* semantics to access the internal c style pointer.
@@ -58,8 +58,9 @@
* should not be shared. This is not reliably enforceable in C++
* but this class attempts to make the 1-1 relationship clear.
*
- * @section Example usage
+ * \section Example usage
*
+ * \code{.cpp}
* class foo {
* ...constructors accessors etc.
* int x[1000];
@@ -86,18 +87,21 @@
* private :
* MEM_SmartPtr<foo> m_foo;
* }
+ * \endcode
*
* You may also safely construct vectors of MEM_SmartPtrs and
* have the vector own stuff you put into it.
*
* e.g.
+ * \code{.cpp}
* {
- * std::vector<MEM_SmartPtr<foo> > foo_vector;
- * foo_vector.push_back( new foo());
- * foo_vector.push_back( new foo());
+ * std::vector<MEM_SmartPtr<foo> > foo_vector;
+ * foo_vector.push_back( new foo());
+ * foo_vector.push_back( new foo());
*
- * foo_vector[0]->bla();
+ * foo_vector[0]->bla();
* } // foo_vector out of scope => heap memory freed for both foos
+ * \endcode
*
* @warning this class should only be used for objects created
* on the heap via the new function. It will not behave correctly
diff --git a/intern/opencolorio/fallback_impl.cc b/intern/opencolorio/fallback_impl.cc
index d1493cb3ad5..1124e7fd8ab 100644
--- a/intern/opencolorio/fallback_impl.cc
+++ b/intern/opencolorio/fallback_impl.cc
@@ -162,6 +162,19 @@ const char *FallbackImpl::configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *
return "sRGB";
}
+void FallbackImpl::configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr * /*config*/, float *rgb)
+{
+ /* Here we simply use the older Blender assumed primaries of
+ * ITU-BT.709 / sRGB, or 0.2126729 0.7151522 0.0721750. Brute
+ * force stupid, but only plausible option given no color management
+ * system in place.
+ */
+
+ rgb[0] = 0.2126f;
+ rgb[1] = 0.7152f;
+ rgb[2] = 0.0722f;
+}
+
int FallbackImpl::configGetNumLooks(OCIO_ConstConfigRcPtr * /*config*/)
{
return 0;
@@ -177,7 +190,7 @@ OCIO_ConstLookRcPtr *FallbackImpl::configGetLook(OCIO_ConstConfigRcPtr * /*confi
return NULL;
}
-const char *FallbackImpl::lookGetProcessSpace(OCIO_ConstLookRcPtr *look)
+const char *FallbackImpl::lookGetProcessSpace(OCIO_ConstLookRcPtr * /*look*/)
{
return NULL;
}
diff --git a/intern/opencolorio/ocio_capi.cc b/intern/opencolorio/ocio_capi.cc
index a4f2db456e8..7a0b9faa5fc 100644
--- a/intern/opencolorio/ocio_capi.cc
+++ b/intern/opencolorio/ocio_capi.cc
@@ -132,6 +132,11 @@ const char *OCIO_configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *config, c
return impl->configGetDisplayColorSpaceName(config, display, view);
}
+void OCIO_configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr *config, float *rgb)
+{
+ impl->configGetDefaultLumaCoefs(config, rgb);
+}
+
int OCIO_configGetNumLooks(OCIO_ConstConfigRcPtr *config)
{
return impl->configGetNumLooks(config);
diff --git a/intern/opencolorio/ocio_capi.h b/intern/opencolorio/ocio_capi.h
index d667dece62a..52a86727902 100644
--- a/intern/opencolorio/ocio_capi.h
+++ b/intern/opencolorio/ocio_capi.h
@@ -140,6 +140,8 @@ int OCIO_configGetNumViews(OCIO_ConstConfigRcPtr *config, const char *di
const char *OCIO_configGetView(OCIO_ConstConfigRcPtr *config, const char *display, int index);
const char *OCIO_configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *config, const char *display, const char *view);
+void OCIO_configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr *config, float *rgb);
+
int OCIO_configGetNumLooks(OCIO_ConstConfigRcPtr *config);
const char *OCIO_configGetLookNameByIndex(OCIO_ConstConfigRcPtr *config, int index);
OCIO_ConstLookRcPtr *OCIO_configGetLook(OCIO_ConstConfigRcPtr *config, const char *name);
diff --git a/intern/opencolorio/ocio_impl.cc b/intern/opencolorio/ocio_impl.cc
index 5015f3a5c7d..bf5590077ef 100644
--- a/intern/opencolorio/ocio_impl.cc
+++ b/intern/opencolorio/ocio_impl.cc
@@ -272,6 +272,16 @@ const char *OCIOImpl::configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *conf
return NULL;
}
+void OCIOImpl::configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr *config, float *rgb)
+{
+ try {
+ (*(ConstConfigRcPtr *) config)->getDefaultLumaCoefs(rgb);
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+}
+
int OCIOImpl::configGetNumLooks(OCIO_ConstConfigRcPtr *config)
{
try {
diff --git a/intern/opencolorio/ocio_impl.h b/intern/opencolorio/ocio_impl.h
index 47e6d829902..f086bbb1a26 100644
--- a/intern/opencolorio/ocio_impl.h
+++ b/intern/opencolorio/ocio_impl.h
@@ -58,6 +58,8 @@ public:
virtual const char *configGetView(OCIO_ConstConfigRcPtr *config, const char *display, int index) = 0;
virtual const char *configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *config, const char *display, const char *view) = 0;
+ virtual void configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr *config, float *rgb) = 0;
+
virtual int configGetNumLooks(OCIO_ConstConfigRcPtr *config) = 0;
virtual const char *configGetLookNameByIndex(OCIO_ConstConfigRcPtr *config, int index) = 0;
virtual OCIO_ConstLookRcPtr *configGetLook(OCIO_ConstConfigRcPtr *config, const char *name) = 0;
@@ -145,6 +147,8 @@ public:
const char *configGetView(OCIO_ConstConfigRcPtr *config, const char *display, int index);
const char *configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *config, const char *display, const char *view);
+ void configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr *config, float *rgb);
+
int configGetNumLooks(OCIO_ConstConfigRcPtr *config);
const char *configGetLookNameByIndex(OCIO_ConstConfigRcPtr *config, int index);
OCIO_ConstLookRcPtr *configGetLook(OCIO_ConstConfigRcPtr *config, const char *name);
@@ -233,6 +237,8 @@ public:
const char *configGetView(OCIO_ConstConfigRcPtr *config, const char *display, int index);
const char *configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *config, const char *display, const char *view);
+ void configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr *config, float *rgb);
+
int configGetNumLooks(OCIO_ConstConfigRcPtr *config);
const char *configGetLookNameByIndex(OCIO_ConstConfigRcPtr *config, int index);
OCIO_ConstLookRcPtr *configGetLook(OCIO_ConstConfigRcPtr *config, const char *name);
diff --git a/intern/smoke/extern/smoke_API.h b/intern/smoke/extern/smoke_API.h
index 08dbded176e..8fa7daaad79 100644
--- a/intern/smoke/extern/smoke_API.h
+++ b/intern/smoke/extern/smoke_API.h
@@ -74,7 +74,7 @@ size_t smoke_get_index2d(int x, int max_x, int y);
void smoke_dissolve(struct FLUID_3D *fluid, int speed, int log);
// wavelet turbulence functions
-struct WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, const char *noisefile_path, int use_fire, int use_colors);
+struct WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, const char *noisefile_path, int use_fire, int use_colors, int use_sim);
void smoke_turbulence_free(struct WTURBULENCE *wt);
void smoke_turbulence_step(struct WTURBULENCE *wt, struct FLUID_3D *fluid);
@@ -109,6 +109,7 @@ int smoke_has_colors(struct FLUID_3D *fluid);
int smoke_turbulence_has_fuel(struct WTURBULENCE *wt);
int smoke_turbulence_has_colors(struct WTURBULENCE *wt);
+void smoke_ensure_simulation(struct FLUID_3D *fluid, struct WTURBULENCE *wt);
void smoke_ensure_heat(struct FLUID_3D *fluid);
void smoke_ensure_fire(struct FLUID_3D *fluid, struct WTURBULENCE *wt);
void smoke_ensure_colors(struct FLUID_3D *fluid, struct WTURBULENCE *wt, float init_r, float init_g, float init_b);
diff --git a/intern/smoke/intern/WTURBULENCE.cpp b/intern/smoke/intern/WTURBULENCE.cpp
index 3d712d2124a..2260057c0d2 100644
--- a/intern/smoke/intern/WTURBULENCE.cpp
+++ b/intern/smoke/intern/WTURBULENCE.cpp
@@ -51,8 +51,10 @@ static const float persistence = 0.56123f;
//////////////////////////////////////////////////////////////////////
// constructor
//////////////////////////////////////////////////////////////////////
-WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, const char *noisefile_path, int init_fire, int init_colors)
+WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, const char *noisefile_path, int init_fire, int init_colors, int init_sim)
{
+ _need_sim_data = init_sim != 0;
+
// if noise magnitude is below this threshold, its contribution
// is negilgible, so stop evaluating new octaves
_cullingThreshold = 1e-3;
@@ -87,11 +89,14 @@ WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int no
// allocate high resolution density field
_totalStepsBig = 0;
_densityBig = new float[_totalCellsBig];
- _densityBigOld = new float[_totalCellsBig];
-
- for(int i = 0; i < _totalCellsBig; i++) {
- _densityBig[i] =
- _densityBigOld[i] = 0.;
+ memset(_densityBig, 0, sizeof(*_densityBig) * _totalCellsBig);
+
+ if (_need_sim_data) {
+ _densityBigOld = new float[_totalCellsBig];
+ memset(_densityBigOld, 0, sizeof(*_densityBigOld) * _totalCellsBig);
+ }
+ else {
+ _densityBigOld = NULL;
}
/* fire */
@@ -112,7 +117,6 @@ WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int no
_tcU = new float[_totalCellsSm];
_tcV = new float[_totalCellsSm];
_tcW = new float[_totalCellsSm];
- _tcTemp = new float[_totalCellsSm];
// map all
const float dx = 1.0f/(float)(_resSm[0]);
@@ -126,29 +130,72 @@ WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int no
_tcU[index] = x*dx;
_tcV[index] = y*dy;
_tcW[index] = z*dz;
- _tcTemp[index] = 0.;
}
+ if (_need_sim_data) {
+ _tcTemp = new float[_totalCellsSm];
+ memset(_tcTemp, 0, sizeof(*_tcTemp) * _totalCellsSm);
+ }
+ else {
+ _tcTemp = NULL;
+ }
+
// noise tiles
_noiseTile = new float[noiseTileSize * noiseTileSize * noiseTileSize];
setNoise(noisetype, noisefile_path);
}
+void WTURBULENCE::initSimulation()
+{
+ if (_need_sim_data) {
+ return;
+ }
+
+ if(_densityBigOld == NULL) {
+ _densityBigOld = new float[_totalCellsBig];
+ memset(_densityBigOld, 0, sizeof(*_densityBigOld) * _totalCellsBig);
+ }
+
+ if (_tcTemp == NULL) {
+ _tcTemp = new float[_totalCellsSm];
+ memset(_tcTemp, 0, sizeof(*_tcTemp) * _totalCellsSm);
+ }
+
+ if (_fuelBig != NULL) {
+ if (_fuelBigOld == NULL) {
+ _fuelBigOld = new float[_totalCellsBig];
+ _reactBigOld = new float[_totalCellsBig];
+ memset(_fuelBigOld, 0, sizeof(*_fuelBigOld) * _totalCellsBig);
+ memset(_reactBigOld, 0, sizeof(*_reactBigOld) * _totalCellsBig);
+ }
+ }
+
+ if (_color_rBig != NULL) {
+ if (_color_rBigOld == NULL) {
+ _color_rBigOld = new float[_totalCellsBig];
+ _color_gBigOld = new float[_totalCellsBig];
+ _color_bBigOld = new float[_totalCellsBig];
+ memset(_color_rBigOld, 0, sizeof(*_color_rBigOld) * _totalCellsBig);
+ memset(_color_gBigOld, 0, sizeof(*_color_gBigOld) * _totalCellsBig);
+ memset(_color_bBigOld, 0, sizeof(*_color_bBigOld) * _totalCellsBig);
+ }
+ }
+}
+
void WTURBULENCE::initFire()
{
if (!_fuelBig) {
_flameBig = new float[_totalCellsBig];
_fuelBig = new float[_totalCellsBig];
- _fuelBigOld = new float[_totalCellsBig];
_reactBig = new float[_totalCellsBig];
- _reactBigOld = new float[_totalCellsBig];
-
- for(int i = 0; i < _totalCellsBig; i++) {
- _flameBig[i] =
- _fuelBig[i] =
- _fuelBigOld[i] = 0.;
- _reactBig[i] =
- _reactBigOld[i] = 0.;
+ memset(_flameBig, 0, sizeof(*_flameBig) * _totalCellsBig);
+ memset(_fuelBig, 0, sizeof(*_fuelBig) * _totalCellsBig);
+ memset(_reactBig, 0, sizeof(*_reactBig) * _totalCellsBig);
+ if (_need_sim_data) {
+ _fuelBigOld = new float[_totalCellsBig];
+ _reactBigOld = new float[_totalCellsBig];
+ memset(_fuelBigOld, 0, sizeof(*_fuelBigOld) * _totalCellsBig);
+ memset(_reactBigOld, 0, sizeof(*_reactBigOld) * _totalCellsBig);
}
}
}
@@ -157,19 +204,20 @@ void WTURBULENCE::initColors(float init_r, float init_g, float init_b)
{
if (!_color_rBig) {
_color_rBig = new float[_totalCellsBig];
- _color_rBigOld = new float[_totalCellsBig];
_color_gBig = new float[_totalCellsBig];
- _color_gBigOld = new float[_totalCellsBig];
_color_bBig = new float[_totalCellsBig];
- _color_bBigOld = new float[_totalCellsBig];
-
for(int i = 0; i < _totalCellsBig; i++) {
_color_rBig[i] = _densityBig[i] * init_r;
- _color_rBigOld[i] = 0.0f;
_color_gBig[i] = _densityBig[i] * init_g;
- _color_gBigOld[i] = 0.0f;
_color_bBig[i] = _densityBig[i] * init_b;
- _color_bBigOld[i] = 0.0f;
+ }
+ if (_need_sim_data) {
+ _color_rBigOld = new float[_totalCellsBig];
+ _color_gBigOld = new float[_totalCellsBig];
+ _color_bBigOld = new float[_totalCellsBig];
+ memset(_color_rBigOld, 0, sizeof(*_color_rBigOld) * _totalCellsBig);
+ memset(_color_gBigOld, 0, sizeof(*_color_gBigOld) * _totalCellsBig);
+ memset(_color_bBigOld, 0, sizeof(*_color_bBigOld) * _totalCellsBig);
}
}
}
@@ -179,7 +227,7 @@ void WTURBULENCE::initColors(float init_r, float init_g, float init_b)
//////////////////////////////////////////////////////////////////////
WTURBULENCE::~WTURBULENCE() {
delete[] _densityBig;
- delete[] _densityBigOld;
+ if (_densityBigOld) delete[] _densityBigOld;
if (_flameBig) delete[] _flameBig;
if (_fuelBig) delete[] _fuelBig;
if (_fuelBigOld) delete[] _fuelBigOld;
@@ -196,7 +244,7 @@ WTURBULENCE::~WTURBULENCE() {
delete[] _tcU;
delete[] _tcV;
delete[] _tcW;
- delete[] _tcTemp;
+ if (_tcTemp) delete[] _tcTemp;
delete[] _noiseTile;
}
diff --git a/intern/smoke/intern/WTURBULENCE.h b/intern/smoke/intern/WTURBULENCE.h
index 36635325f62..fbc3e9eb8ba 100644
--- a/intern/smoke/intern/WTURBULENCE.h
+++ b/intern/smoke/intern/WTURBULENCE.h
@@ -36,11 +36,14 @@ struct WTURBULENCE
{
public:
// both config files can be NULL, altCfg might override values from noiseCfg
- WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, const char *noisefile_path, int init_fire, int init_colors);
+ WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, const char *noisefile_path, int init_fire, int init_colors, int init_sim);
/// destructor
virtual ~WTURBULENCE();
+ // Ensure data needed for simulation is allocated
+ void initSimulation();
+
void initFire();
void initColors(float init_r, float init_g, float init_b);
@@ -144,6 +147,8 @@ struct WTURBULENCE
void computeEigenvalues(float *_eigMin, float *_eigMax);
void decomposeEnergy(float *energy, float *_highFreqEnergy);
+
+ bool _need_sim_data;
};
#endif // WTURBULENCE_H
diff --git a/intern/smoke/intern/smoke_API.cpp b/intern/smoke/intern/smoke_API.cpp
index d79aaf76d56..28b39531b91 100644
--- a/intern/smoke/intern/smoke_API.cpp
+++ b/intern/smoke/intern/smoke_API.cpp
@@ -44,10 +44,10 @@ extern "C" FLUID_3D *smoke_init(int *res, float dx, float dtdef, int use_heat, i
return fluid;
}
-extern "C" WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, const char *noisefile_path, int use_fire, int use_colors)
+extern "C" WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, const char *noisefile_path, int use_fire, int use_colors, int use_sim)
{
if (amplify)
- return new WTURBULENCE(res[0],res[1],res[2], amplify, noisetype, noisefile_path, use_fire, use_colors);
+ return new WTURBULENCE(res[0],res[1],res[2], amplify, noisetype, noisefile_path, use_fire, use_colors, use_sim);
else
return NULL;
}
@@ -480,6 +480,13 @@ extern "C" int smoke_turbulence_has_colors(WTURBULENCE *wt)
}
/* additional field initialization */
+extern "C" void smoke_ensure_simulation(FLUID_3D * /*fluid*/, WTURBULENCE *wt)
+{
+ if (wt) {
+ wt->initSimulation();
+ }
+}
+
extern "C" void smoke_ensure_heat(FLUID_3D *fluid)
{
if (fluid) {
diff --git a/release/bin/blender-thumbnailer.py b/release/bin/blender-thumbnailer.py
index 779c6156e70..d3b31d63fad 100755
--- a/release/bin/blender-thumbnailer.py
+++ b/release/bin/blender-thumbnailer.py
@@ -170,7 +170,7 @@ def write_png(buf, width, height):
png_pack(b'IEND', b'')])
-if __name__ == '__main__':
+def main():
import sys
if len(sys.argv) < 3:
@@ -186,3 +186,7 @@ if __name__ == '__main__':
f = open(file_out, "wb")
f.write(write_png(buf, width, height))
f.close()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/release/datafiles/brushicons/hairadd.png b/release/datafiles/brushicons/hairadd.png
new file mode 100644
index 00000000000..074111a5a0b
--- /dev/null
+++ b/release/datafiles/brushicons/hairadd.png
Binary files differ
diff --git a/release/datafiles/brushicons/haircomb.png b/release/datafiles/brushicons/haircomb.png
new file mode 100644
index 00000000000..074111a5a0b
--- /dev/null
+++ b/release/datafiles/brushicons/haircomb.png
Binary files differ
diff --git a/release/datafiles/brushicons/haircut.png b/release/datafiles/brushicons/haircut.png
new file mode 100644
index 00000000000..074111a5a0b
--- /dev/null
+++ b/release/datafiles/brushicons/haircut.png
Binary files differ
diff --git a/release/datafiles/brushicons/hairlength.png b/release/datafiles/brushicons/hairlength.png
new file mode 100644
index 00000000000..074111a5a0b
--- /dev/null
+++ b/release/datafiles/brushicons/hairlength.png
Binary files differ
diff --git a/release/datafiles/brushicons/hairpuff.png b/release/datafiles/brushicons/hairpuff.png
new file mode 100644
index 00000000000..074111a5a0b
--- /dev/null
+++ b/release/datafiles/brushicons/hairpuff.png
Binary files differ
diff --git a/release/datafiles/brushicons/hairsmooth.png b/release/datafiles/brushicons/hairsmooth.png
new file mode 100644
index 00000000000..074111a5a0b
--- /dev/null
+++ b/release/datafiles/brushicons/hairsmooth.png
Binary files differ
diff --git a/release/datafiles/brushicons/hairweight.png b/release/datafiles/brushicons/hairweight.png
new file mode 100644
index 00000000000..074111a5a0b
--- /dev/null
+++ b/release/datafiles/brushicons/hairweight.png
Binary files differ
diff --git a/release/datafiles/fonts/droidsans.ttf.gz b/release/datafiles/fonts/droidsans.ttf.gz
index c76cf67992c..a685c590795 100644
--- a/release/datafiles/fonts/droidsans.ttf.gz
+++ b/release/datafiles/fonts/droidsans.ttf.gz
Binary files differ
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject aa930e1ee3e40a2e99b77591bb7fd4f0565b331
+Subproject c651e63a9a537624f639950f3127a1dee29205d
diff --git a/release/datafiles/splash.png b/release/datafiles/splash.png
index e8d09694a64..a3e9afe6403 100644
--- a/release/datafiles/splash.png
+++ b/release/datafiles/splash.png
Binary files differ
diff --git a/release/datafiles/splash_2x.png b/release/datafiles/splash_2x.png
index d20fb682970..d45b9952633 100644
--- a/release/datafiles/splash_2x.png
+++ b/release/datafiles/splash_2x.png
Binary files differ
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject ffb9eb7eda6961af0e76fcaf81199183da55812
+Subproject 3fc5b82c6bdba2f9c954fbf497621b9bb794a1b
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject f42910f683595dcaf145f24cecd9117bbb7dd7e
+Subproject cf842d8bb7b0033ca4fa99f7ebedcbd3810fd27
diff --git a/release/scripts/freestyle/modules/freestyle/functions.py b/release/scripts/freestyle/modules/freestyle/functions.py
index 48d9b2e2b39..426d344e8ab 100644
--- a/release/scripts/freestyle/modules/freestyle/functions.py
+++ b/release/scripts/freestyle/modules/freestyle/functions.py
@@ -189,11 +189,13 @@ class CurveMaterialF0D(UnaryFunction0DMaterial):
priority is used to pick one of the two materials at material
boundaries.
- Note: expects instances of CurvePoint to be iterated over
+ Notes: expects instances of CurvePoint to be iterated over
+ can return None if no fedge can be found
"""
def __call__(self, inter):
fe = inter.object.fedge
- assert(fe is not None), "CurveMaterialF0D: fe is None"
+ if fe is None:
+ return None
if fe.is_smooth:
return fe.material
else:
diff --git a/release/scripts/freestyle/modules/freestyle/predicates.py b/release/scripts/freestyle/modules/freestyle/predicates.py
index 54656e450d9..5cbe577b956 100644
--- a/release/scripts/freestyle/modules/freestyle/predicates.py
+++ b/release/scripts/freestyle/modules/freestyle/predicates.py
@@ -43,6 +43,7 @@ __all__ = (
"FalseUP0D",
"FalseUP1D",
"Length2DBP1D",
+ "MaterialBP1D",
"NotBP1D",
"NotUP1D",
"ObjectNamesUP1D",
@@ -150,12 +151,13 @@ from freestyle.functions import (
pyViewMapGradientNormF1D,
)
+from freestyle.utils import material_from_fedge
+
import random
# -- Unary predicates for 0D elements (vertices) -- #
-
class pyHigherCurvature2DAngleUP0D(UnaryPredicate0D):
def __init__(self, a):
UnaryPredicate0D.__init__(self)
@@ -234,9 +236,10 @@ class AndUP1D(UnaryPredicate1D):
def __init__(self, *predicates):
UnaryPredicate1D.__init__(self)
self.predicates = predicates
- # there are cases in which only one predicate is supplied (in the parameter editor)
- if len(self.predicates) < 1:
- raise ValueError("Expected one or more UnaryPredicate1D, got ", len(predicates))
+ correct_types = all(isinstance(p, UnaryPredicate1D) for p in self.predicates)
+ if not (correct_types and predicates):
+ raise TypeError("%s: Expected one or more UnaryPredicate1D, got %r" %
+ (self.__class__.__name__, self.predicates))
def __call__(self, inter):
return all(pred(inter) for pred in self.predicates)
@@ -246,9 +249,10 @@ class OrUP1D(UnaryPredicate1D):
def __init__(self, *predicates):
UnaryPredicate1D.__init__(self)
self.predicates = predicates
- # there are cases in which only one predicate is supplied (in the parameter editor)
- if len(self.predicates) < 1:
- raise ValueError("Expected one or more UnaryPredicate1D, got ", len(predicates))
+ correct_types = all(isinstance(p, UnaryPredicate1D) for p in self.predicates)
+ if not (correct_types and predicates):
+ raise TypeError("%s: Expected one or more UnaryPredicate1D, got %r" %
+ (self.__class__.__name__, self.predicates))
def __call__(self, inter):
return any(pred(inter) for pred in self.predicates)
@@ -257,10 +261,10 @@ class OrUP1D(UnaryPredicate1D):
class NotUP1D(UnaryPredicate1D):
def __init__(self, pred):
UnaryPredicate1D.__init__(self)
- self.__pred = pred
+ self.predicate = pred
def __call__(self, inter):
- return not self.__pred(inter)
+ return not self.predicate(inter)
class ObjectNamesUP1D(UnaryPredicate1D):
@@ -563,32 +567,36 @@ class pyClosedCurveUP1D(UnaryPredicate1D):
class AndBP1D(BinaryPredicate1D):
def __init__(self, *predicates):
BinaryPredicate1D.__init__(self)
- self._predicates = predicates
- if len(self.predicates) < 2:
- raise ValueError("Expected two or more BinaryPredicate1D, got ", len(predictates))
+ self.predicates = tuple(predicates)
+ correct_types = all(isinstance(p, BinaryPredicate1D) for p in self.predicates)
+ if not (correct_types and predicates):
+ raise TypeError("%s: Expected one or more BinaryPredicate1D, got %r" %
+ (self.__class__.__name__, self.predicates))
def __call__(self, i1, i2):
- return all(pred(i1, i2) for pred in self._predicates)
+ return all(pred(i1, i2) for pred in self.predicates)
class OrBP1D(BinaryPredicate1D):
def __init__(self, *predicates):
BinaryPredicate1D.__init__(self)
- self._predicates = predicates
- if len(self.predicates) < 2:
- raise ValueError("Expected two or more BinaryPredicate1D, got ", len(predictates))
+ self.predicates = tuple(predicates)
+ correct_types = all(isinstance(p, BinaryPredicate1D) for p in self.predicates)
+ if not (correct_types and predicates):
+ raise TypeError("%s: Expected one or more BinaryPredicate1D, got %r" %
+ (self.__class__.__name__, self.predicates))
def __call__(self, i1, i2):
- return any(pred(i1, i2) for pred in self._predicates)
+ return any(pred(i1, i2) for pred in self.predicates)
class NotBP1D(BinaryPredicate1D):
def __init__(self, predicate):
BinaryPredicate1D.__init__(self)
- self._predicate = predicate
+ self.predicate = predicate
def __call__(self, i1, i2):
- return (not self._predicate(i1, i2))
+ return (not self.predicate(i1, i2))
class pyZBP1D(BinaryPredicate1D):
@@ -663,3 +671,10 @@ class pyShuffleBP1D(BinaryPredicate1D):
def __call__(self, inter1, inter2):
return (random.uniform(0, 1) < random.uniform(0, 1))
+
+class MaterialBP1D(BinaryPredicate1D):
+ """Checks whether the two supplied ViewEdges have the same material."""
+ def __call__(self, i1, i2):
+ fedges = (fe for ve in (i1, i2) for fe in (ve.first_fedge, ve.last_fedge))
+ materials = {material_from_fedge(fe) for fe in fedges}
+ return len(materials) < 2
diff --git a/release/scripts/freestyle/modules/freestyle/shaders.py b/release/scripts/freestyle/modules/freestyle/shaders.py
index 61365e8dd87..127db3fcd4b 100644
--- a/release/scripts/freestyle/modules/freestyle/shaders.py
+++ b/release/scripts/freestyle/modules/freestyle/shaders.py
@@ -138,7 +138,7 @@ from freestyle.predicates import (
from freestyle.utils import (
bound,
- bounding_box,
+ BoundingBox,
phase_to_direction,
)
@@ -865,7 +865,7 @@ class pyBluePrintCirclesShader(StrokeShader):
def shade(self, stroke):
# get minimum and maximum coordinates
- p_min, p_max = bounding_box(stroke)
+ p_min, p_max = BoundingBox.from_sequence(svert.point for svert in stroke).corners
stroke.resample(32 * self.__turns)
sv_nb = len(stroke) // self.__turns
@@ -917,7 +917,7 @@ class pyBluePrintEllipsesShader(StrokeShader):
self.__random_radius = random_radius
def shade(self, stroke):
- p_min, p_max = bounding_box(stroke)
+ p_min, p_max = BoundingBox.from_sequence(svert.point for svert in stroke).corners
stroke.resample(32 * self.__turns)
sv_nb = len(stroke) // self.__turns
@@ -964,7 +964,7 @@ class pyBluePrintSquaresShader(StrokeShader):
return
# get minimum and maximum coordinates
- p_min, p_max = bounding_box(stroke)
+ p_min, p_max = BoundingBox.from_sequence(svert.point for svert in stroke).corners
stroke.resample(32 * self.__turns)
num_segments = len(stroke) // self.__turns
diff --git a/release/scripts/freestyle/modules/freestyle/utils.py b/release/scripts/freestyle/modules/freestyle/utils.py
index 224734d5bfb..41d2297f723 100644
--- a/release/scripts/freestyle/modules/freestyle/utils.py
+++ b/release/scripts/freestyle/modules/freestyle/utils.py
@@ -22,24 +22,29 @@ writing.
"""
__all__ = (
- "ContextFunctions",
"bound",
- "bounding_box",
+ "BoundingBox",
+ "ContextFunctions",
"find_matching_vertex",
- "getCurrentScene",
"get_chain_length",
+ "get_object_name",
+ "get_strokes",
"get_test_stroke",
+ "getCurrentScene",
"integrate",
+ "is_poly_clockwise",
"iter_distance_along_stroke",
"iter_distance_from_camera",
"iter_distance_from_object",
"iter_material_value",
"iter_t2d_along_stroke",
+ "material_from_fedge",
"pairwise",
"phase_to_direction",
"rgb_to_bw",
"stroke_curvature",
"stroke_normal",
+ "StrokeCollector",
"tripplewise",
)
@@ -55,6 +60,7 @@ from _freestyle import (
from freestyle.types import (
Interface0DIterator,
Stroke,
+ StrokeShader,
StrokeVertexIterator,
)
@@ -79,12 +85,38 @@ def bound(lower, x, higher):
return (lower if x <= lower else higher if x >= higher else x)
-def bounding_box(stroke):
- """
- Returns the maximum and minimum coordinates (the bounding box) of the stroke's vertices
- """
- x, y = zip(*(svert.point for svert in stroke))
- return (Vector((min(x), min(y))), Vector((max(x), max(y))))
+def get_strokes():
+ """Get all strokes that are currently available"""
+ return tuple(map(Operators().get_stroke_from_index, range(Operators().get_strokes_size())))
+
+
+def is_poly_clockwise(stroke):
+ """True if the stroke is orientated in a clockwise way, False otherwise"""
+ v = sum((v2.point.x - v1.point.x) * (v1.point.y + v2.point.y) for v1, v2 in pairwise(stroke))
+ v1, v2 = stroke[0], stroke[-1]
+ if (v1.point - v2.point).length > 1e-3:
+ v += (v2.point.x - v1.point.x) * (v1.point.y + v2.point.y)
+ return v > 0
+
+
+def get_object_name(stroke):
+ """Returns the name of the object that this stroke is drawn on."""
+ fedge = stroke[0].fedge
+ if fedge is None:
+ return None
+ return fedge.viewedge.viewshape.name
+
+
+def material_from_fedge(fe):
+ "get the diffuse rgba color from an FEdge"
+ if fe is None:
+ return None
+ if fe.is_smooth:
+ material = fe.material
+ else:
+ right, left = fe.material_right, fe.material_left
+ material = right if (right.priority > left.priority) else left
+ return material
# -- General helper functions -- #
@@ -106,6 +138,54 @@ def phase_to_direction(length):
# lower bound (e.g., thickness, range and certain values)
BoundedProperty = namedtuple("BoundedProperty", ["min", "max", "delta"])
+
+class BoundingBox:
+ """Object representing a bounding box consisting out of 2 2D vectors"""
+
+ __slots__ = (
+ "minimum",
+ "maximum",
+ "size",
+ "corners",
+ )
+
+ def __init__(self, minimum: Vector, maximum: Vector):
+ self.minimum = minimum
+ self.maximum = maximum
+ if len(minimum) != len(maximum):
+ raise TypeError("Expected two vectors of size 2, got", minimum, maximum)
+ self.size = len(minimum)
+ self.corners = (minimum, maximum)
+
+ def __repr__(self):
+ return "BoundingBox(%r, %r)" % (self.minimum, self.maximum)
+
+ @classmethod
+ def from_sequence(cls, sequence):
+ """BoundingBox from sequence of 2D or 3D Vector objects"""
+ x, y = zip(*sequence)
+ mini = Vector((min(x), min(y)))
+ maxi = Vector((max(x), max(y)))
+ return cls(mini, maxi)
+
+ def inside(self, other):
+ """True if self inside other, False otherwise"""
+ if self.size != other.size:
+ raise TypeError("Expected two BoundingBox of the same size, got", self, other)
+ return (self.minimum.x >= other.minimum.x and self.minimum.y >= other.minimum.y and
+ self.maximum.x <= other.maximum.x and self.maximum.y <= other.maximum.y)
+
+
+class StrokeCollector(StrokeShader):
+ "Collects and Stores stroke objects"
+ def __init__(self):
+ StrokeShader.__init__(self)
+ self.strokes = []
+
+ def shade(self, stroke):
+ self.strokes.append(stroke)
+
+
# -- helper functions for chaining -- #
def get_chain_length(ve, orientation):
@@ -147,6 +227,7 @@ def find_matching_vertex(id, it):
"""Finds the matching vertex, or returns None."""
return next((ve for ve in it if ve.id == id), None)
+
# -- helper functions for iterating -- #
def pairwise(iterable, types={Stroke, StrokeVertexIterator}):
@@ -210,7 +291,7 @@ def iter_distance_from_object(stroke, location, range_min, range_max, normfac):
def iter_material_value(stroke, func, attribute):
- "Yields a specific material attribute from the vertex' underlying material."
+ """Yields a specific material attribute from the vertex' underlying material."""
it = Interface0DIterator(stroke)
for svert in it:
material = func(it)
@@ -252,8 +333,9 @@ def iter_material_value(stroke, func, attribute):
raise ValueError("unexpected material attribute: " + attribute)
yield (svert, value)
+
def iter_distance_along_stroke(stroke):
- "Yields the absolute distance along the stroke up to the current vertex."
+ """Yields the absolute distance along the stroke up to the current vertex."""
distance = 0.0
# the positions need to be copied, because they are changed in the calling function
points = tuple(svert.point.copy() for svert in stroke)
@@ -295,6 +377,7 @@ def stroke_curvature(it):
yield abs(K)
+
def stroke_normal(stroke):
"""
Compute the 2D normal at the stroke vertex pointed by the iterator
@@ -304,7 +387,7 @@ def stroke_normal(stroke):
The returned normals are dynamic: they update when the
vertex position (and therefore the vertex normal) changes.
- for use in geometry modifiers it is advised to
+ for use in geometry modifiers it is advised to
cast this generator function to a tuple or list
"""
n = len(stroke) - 1
@@ -323,12 +406,13 @@ def stroke_normal(stroke):
n2 = Vector((e2[1], -e2[0])).normalized()
yield (n1 + n2).normalized()
+
def get_test_stroke():
"""Returns a static stroke object for testing """
from freestyle.types import Stroke, Interface0DIterator, StrokeVertexIterator, SVertex, Id, StrokeVertex
# points for our fake stroke
points = (Vector((1.0, 5.0, 3.0)), Vector((1.0, 2.0, 9.0)),
- Vector((6.0, 2.0, 3.0)), Vector((7.0, 2.0, 3.0)),
+ Vector((6.0, 2.0, 3.0)), Vector((7.0, 2.0, 3.0)),
Vector((2.0, 6.0, 3.0)), Vector((2.0, 8.0, 3.0)))
ids = (Id(0, 0), Id(1, 1), Id(2, 2), Id(3, 3), Id(4, 4), Id(5, 5))
diff --git a/release/scripts/freestyle/modules/parameter_editor.py b/release/scripts/freestyle/modules/parameter_editor.py
index d4765847450..3c11c33a39d 100644
--- a/release/scripts/freestyle/modules/parameter_editor.py
+++ b/release/scripts/freestyle/modules/parameter_editor.py
@@ -960,11 +960,11 @@ def process(layer_name, lineset_name):
if lineset.select_external_contour:
upred = ExternalContourUP1D()
edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_external_contour else upred)
- if lineset.edge_type_combination == 'OR':
- upred = OrUP1D(*edge_type_criteria)
- else:
- upred = AndUP1D(*edge_type_criteria)
- if upred is not None:
+ if edge_type_criteria:
+ if lineset.edge_type_combination == 'OR':
+ upred = OrUP1D(*edge_type_criteria)
+ else:
+ upred = AndUP1D(*edge_type_criteria)
if lineset.edge_type_negation == 'EXCLUSIVE':
upred = NotUP1D(upred)
selection_criteria.append(upred)
@@ -989,8 +989,9 @@ def process(layer_name, lineset_name):
upred = WithinImageBoundaryUP1D(*ContextFunctions.get_border())
selection_criteria.append(upred)
# select feature edges
- upred = AndUP1D(*selection_criteria)
- if upred is None:
+ if selection_criteria:
+ upred = AndUP1D(*selection_criteria)
+ else:
upred = TrueUP1D()
Operators.select(upred)
# join feature edges to form chains
diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py
index 8c86f31022c..63b01a4b884 100644
--- a/release/scripts/modules/addon_utils.py
+++ b/release/scripts/modules/addon_utils.py
@@ -74,40 +74,43 @@ def modules_refresh(module_cache=addons_fake_modules):
print("fake_module", mod_path, mod_name)
import ast
ModuleType = type(ast)
- file_mod = open(mod_path, "r", encoding='UTF-8')
- if speedy:
- lines = []
- line_iter = iter(file_mod)
- l = ""
- while not l.startswith("bl_info"):
- try:
- l = line_iter.readline()
- except UnicodeDecodeError as e:
- if not error_encoding:
- error_encoding = True
- print("Error reading file as UTF-8:", mod_path, e)
- file_mod.close()
- return None
-
- if len(l) == 0:
- break
- while l.rstrip():
- lines.append(l)
- try:
- l = line_iter.readline()
- except UnicodeDecodeError as e:
- if not error_encoding:
- error_encoding = True
- print("Error reading file as UTF-8:", mod_path, e)
- file_mod.close()
- return None
-
- data = "".join(lines)
+ try:
+ file_mod = open(mod_path, "r", encoding='UTF-8')
+ except OSError as e:
+ print("Error opening file %r: %s" % (mod_path, e))
+ return None
- else:
- data = file_mod.read()
+ with file_mod:
+ if speedy:
+ lines = []
+ line_iter = iter(file_mod)
+ l = ""
+ while not l.startswith("bl_info"):
+ try:
+ l = line_iter.readline()
+ except UnicodeDecodeError as e:
+ if not error_encoding:
+ error_encoding = True
+ print("Error reading file as UTF-8:", mod_path, e)
+ return None
+
+ if len(l) == 0:
+ break
+ while l.rstrip():
+ lines.append(l)
+ try:
+ l = line_iter.readline()
+ except UnicodeDecodeError as e:
+ if not error_encoding:
+ error_encoding = True
+ print("Error reading file as UTF-8:", mod_path, e)
+ return None
+
+ data = "".join(lines)
- file_mod.close()
+ else:
+ data = file_mod.read()
+ del file_mod
try:
ast_data = ast.parse(data, filename=mod_path)
@@ -416,19 +419,21 @@ def reset_all(reload_scripts=False):
disable(mod_name)
-def module_bl_info(mod, info_basis={"name": "",
- "author": "",
- "version": (),
- "blender": (),
- "location": "",
- "description": "",
- "wiki_url": "",
- "support": 'COMMUNITY',
- "category": "",
- "warning": "",
- "show_expanded": False,
- }
- ):
+def module_bl_info(mod, info_basis=None):
+ if info_basis is None:
+ info_basis = {
+ "name": "",
+ "author": "",
+ "version": (),
+ "blender": (),
+ "location": "",
+ "description": "",
+ "wiki_url": "",
+ "support": 'COMMUNITY',
+ "category": "",
+ "warning": "",
+ "show_expanded": False,
+ }
addon_info = getattr(mod, "bl_info", {})
diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
index c3b2ae9908b..43a09a1acbd 100644
--- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
+++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
@@ -64,7 +64,7 @@ def _gen_check_ctxt(settings):
def _diff_check_ctxt(check_ctxt, minus_check_ctxt):
- """Returns check_ctxt - minus_check_ctxt"""
+ """Removes minus_check_ctxt from check_ctxt"""
for key in check_ctxt:
if isinstance(check_ctxt[key], set):
for warning in minus_check_ctxt[key]:
@@ -576,8 +576,9 @@ def dump_py_messages_from_files(msgs, reports, files, settings):
#print(func_translate_args)
# Break recursive nodes look up on some kind of nodes.
- # E.g. we don’t want to get strings inside subscripts (blah["foo"])!
- stopper_nodes = {ast.Subscript}
+ # E.g. we don't want to get strings inside subscripts (blah["foo"])!
+ # we don't want to get strings from comparisons (foo.type == 'BAR').
+ stopper_nodes = {ast.Subscript, ast.Compare}
# Consider strings separate: ("a" if test else "b")
separate_nodes = {ast.IfExp}
@@ -897,7 +898,7 @@ def dump_addon_messages(module_name, do_checks, settings):
del msgs[key]
if check_ctxt:
- check_ctxt = _diff_check_ctxt(check_ctxt, minus_check_ctxt)
+ _diff_check_ctxt(check_ctxt, minus_check_ctxt)
# and we are done with those!
del minus_pot
@@ -924,18 +925,18 @@ def main():
return
import sys
- back_argv = sys.argv
+ import argparse
+
# Get rid of Blender args!
- sys.argv = sys.argv[sys.argv.index("--") + 1:]
+ argv = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
- import argparse
parser = argparse.ArgumentParser(description="Process UI messages from inside Blender.")
parser.add_argument('-c', '--no_checks', default=True, action="store_false", help="No checks over UI messages.")
parser.add_argument('-m', '--no_messages', default=True, action="store_false", help="No export of UI messages.")
parser.add_argument('-o', '--output', default=None, help="Output POT file path.")
parser.add_argument('-s', '--settings', default=None,
help="Override (some) default settings. Either a JSon file name, or a JSon string.")
- args = parser.parse_args()
+ args = parser.parse_args(argv)
settings = settings_i18n.I18nSettings()
settings.from_json(args.settings)
@@ -945,8 +946,6 @@ def main():
dump_messages(do_messages=args.no_messages, do_checks=args.no_checks, settings=settings)
- sys.argv = back_argv
-
if __name__ == "__main__":
print("\n\n *** Running {} *** \n".format(__file__))
diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py
index 920a56a628b..30ee3cdc7d8 100644
--- a/release/scripts/modules/bl_i18n_utils/settings.py
+++ b/release/scripts/modules/bl_i18n_utils/settings.py
@@ -88,6 +88,7 @@ LANGUAGES = (
(38, "Uzbek (Oʻzbek)", "uz_UZ"),
(39, "Uzbek Cyrillic (Ўзбек)", "uz_UZ@cyrillic"),
(40, "Hindi (मानक हिन्दी)", "hi_IN"),
+ (41, "Vietnamese (tiếng Việt)", "vi_VN"),
)
# Default context, in py!
@@ -324,6 +325,7 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
"y",
# Sub-strings.
"available with",
+ "brown fox",
"can't save image while rendering",
"expected a timeline/animation area to be active",
"expected a view3d region",
@@ -332,6 +334,8 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
"image file not found",
"image path can't be written to",
"in memory to enable editing!",
+ "jumps over",
+ "the lazy dog",
"unable to load movie clip",
"unable to load text",
"unable to open the file",
diff --git a/release/scripts/modules/bl_i18n_utils/utils.py b/release/scripts/modules/bl_i18n_utils/utils.py
index 524fef909e8..d472621029e 100644
--- a/release/scripts/modules/bl_i18n_utils/utils.py
+++ b/release/scripts/modules/bl_i18n_utils/utils.py
@@ -162,7 +162,7 @@ def get_po_files_from_dir(root_dir, langs=set()):
yield uid, po_file
-def enable_addons(addons={}, support={}, disable=False, check_only=False):
+def enable_addons(addons=None, support=None, disable=False, check_only=False):
"""
Enable (or disable) addons based either on a set of names, or a set of 'support' types.
Returns the list of all affected addons (as fake modules)!
@@ -170,6 +170,11 @@ def enable_addons(addons={}, support={}, disable=False, check_only=False):
"""
import addon_utils
+ if addons is None:
+ addons = {}
+ if support is None:
+ support = {}
+
userpref = bpy.context.user_preferences
used_ext = {ext.module for ext in userpref.addons}
@@ -212,13 +217,13 @@ class I18nMessage:
__slots__ = ("msgctxt_lines", "msgid_lines", "msgstr_lines", "comment_lines", "is_fuzzy", "is_commented",
"settings")
- def __init__(self, msgctxt_lines=[], msgid_lines=[], msgstr_lines=[], comment_lines=[],
+ def __init__(self, msgctxt_lines=None, msgid_lines=None, msgstr_lines=None, comment_lines=None,
is_commented=False, is_fuzzy=False, settings=settings):
self.settings = settings
- self.msgctxt_lines = msgctxt_lines
- self.msgid_lines = msgid_lines
- self.msgstr_lines = msgstr_lines
- self.comment_lines = comment_lines
+ self.msgctxt_lines = msgctxt_lines or []
+ self.msgid_lines = msgid_lines or []
+ self.msgstr_lines = msgstr_lines or []
+ self.comment_lines = comment_lines or []
self.is_fuzzy = is_fuzzy
self.is_commented = is_commented
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 4126dde1225..669794799e6 100644
--- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
@@ -125,6 +125,7 @@ class SpellChecker:
"multisampling",
"multitexture",
"multiuser",
+ "multiview",
"namespace",
"keyconfig",
"online",
@@ -576,6 +577,8 @@ class SpellChecker:
"btx",
"cineon",
"dpx",
+ "dwaa",
+ "dwab",
"dxf",
"eps",
"exr",
diff --git a/release/scripts/modules/bpy/path.py b/release/scripts/modules/bpy/path.py
index 25a6c7242e0..be38fefbd2a 100644
--- a/release/scripts/modules/bpy/path.py
+++ b/release/scripts/modules/bpy/path.py
@@ -116,7 +116,11 @@ def is_subdir(path, directory):
from os.path import normpath, normcase
path = normpath(normcase(path))
directory = normpath(normcase(directory))
- return path.startswith(directory)
+ if len(path) > len(directory):
+ if path.startswith(directory):
+ sep = ord(_os.sep) if isinstance(directory, bytes) else _os.sep
+ return (path[len(directory)] == sep)
+ return False
def clean_name(name, replace="_"):
@@ -222,7 +226,8 @@ def resolve_ncase(path):
if _os.path.isdir(dirpath):
try:
files = _os.listdir(dirpath)
- except PermissionError: # We might not have the permission to list dirpath...
+ except PermissionError:
+ # We might not have the permission to list dirpath...
return path, False
else:
return path, False
diff --git a/release/scripts/modules/bpy/utils.py b/release/scripts/modules/bpy/utils/__init__.py
index 5f235ae3958..348deb2c063 100644
--- a/release/scripts/modules/bpy/utils.py
+++ b/release/scripts/modules/bpy/utils/__init__.py
@@ -38,6 +38,7 @@ __all__ = (
"unregister_manual_map",
"make_rna_paths",
"manual_map",
+ "previews",
"resource_path",
"script_path_user",
"script_path_pref",
@@ -640,10 +641,10 @@ def unregister_module(module, verbose=False):
# we start with the built-in default mapping
def _blender_default_map():
import sys
- import rna_wiki_reference as ref_mod
+ import rna_manual_reference as ref_mod
ret = (ref_mod.url_manual_prefix, ref_mod.url_manual_mapping)
# avoid storing in memory
- del sys.modules["rna_wiki_reference"]
+ del sys.modules["rna_manual_reference"]
return ret
# hooks for doc lookups
diff --git a/release/scripts/modules/bpy/utils/previews.py b/release/scripts/modules/bpy/utils/previews.py
new file mode 100644
index 00000000000..965971139e4
--- /dev/null
+++ b/release/scripts/modules/bpy/utils/previews.py
@@ -0,0 +1,153 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+"""
+This module contains utility functions to handle custom previews.
+
+It behaves as a high-level 'cached' previews manager.
+
+This allows scripts to generate their own previews, and use them as icons in UI widgets
+('icon_value' for UILayout functions).
+
+
+Custom Icon Example
+-------------------
+
+.. literalinclude:: ../../../release/scripts/templates_py/ui_previews_custom_icon.py
+"""
+
+__all__ = (
+ "new",
+ "remove",
+ "ImagePreviewCollection",
+ )
+
+import _bpy
+_utils_previews = _bpy._utils_previews
+del _bpy
+
+
+_uuid_open = set()
+
+
+# High-level previews manager.
+# not accessed directly
+class ImagePreviewCollection(dict):
+ """
+ Dictionary-like class of previews.
+
+ This is a subclass of Python's built-in dict type,
+ used to store multiple image previews.
+
+ .. note::
+
+ - instance with :mod:`bpy.utils.previews.new`
+ - keys must be ``str`` type.
+ - values will be :class:`bpy.types.ImagePreview`
+ """
+
+ # Internal notes:
+ # - Blender's internal 'PreviewImage' struct uses 'self._uuid' prefix.
+
+ def __init__(self):
+ super().__init__()
+ self._uuid = hex(id(self))
+ _uuid_open.add(self._uuid)
+
+ def __del__(self):
+ if self._uuid not in _uuid_open:
+ return
+
+ raise ResourceWarning(
+ "<%s id=%s[%d]>: left open, remove with "
+ "'bpy.utils.previews.remove()'" %
+ (self.__class__.__name__, self._uuid, len(self)))
+ self.close()
+
+ def _gen_key(self, name):
+ return ":".join((self._uuid, name))
+
+ def new(self, name):
+ if name in self:
+ raise KeyException("key %r already exists")
+ p = self[name] = _utils_previews.new(
+ self._gen_key(name))
+ return p
+ new.__doc__ = _utils_previews.new.__doc__
+
+ def load(self, name, path, path_type, force_reload=False):
+ if name in self:
+ raise KeyException("key %r already exists")
+ p = self[name] = _utils_previews.load(
+ self._gen_key(name), path, path_type, force_reload)
+ return p
+ load.__doc__ = _utils_previews.load.__doc__
+
+ def clear(self):
+ """Clear all previews."""
+ for name in self.keys():
+ _utils_previews.release(self._gen_key(name))
+ super().clear()
+
+ def close(self):
+ """Close the collection and clear all previews."""
+ self.clear()
+ _uuid_open.remove(self._uuid)
+
+ def __delitem__(self, key):
+ _utils_previews.release(self._gen_key(key))
+ super().__delitem__(key)
+
+ def __repr__(self):
+ return "<%s id=%s[%d], %s>" % (
+ self.__class__.__name__,
+ self._uuid,
+ len(self),
+ super().__repr__())
+
+
+def new():
+ """
+ :return: a new preview collection.
+ :rtype: :class:`ImagePreviewCollection`
+ """
+
+ return ImagePreviewCollection()
+
+
+def remove(pcoll):
+ """
+ Remove the specified previews collection.
+
+ :arg pcoll: Preview collection to close.
+ :type pcoll: :class:`ImagePreviewCollection`
+ """
+ pcoll.close()
+
+
+# don't complain about resources on exit (only unregister)
+import atexit
+
+
+def exit_clear_warning():
+ del ImagePreviewCollection.__del__
+
+atexit.register(exit_clear_warning)
+del atexit, exit_clear_warning
diff --git a/release/scripts/modules/bpy_extras/anim_utils.py b/release/scripts/modules/bpy_extras/anim_utils.py
index 4ee5e685668..435169c39b0 100644
--- a/release/scripts/modules/bpy_extras/anim_utils.py
+++ b/release/scripts/modules/bpy_extras/anim_utils.py
@@ -25,6 +25,304 @@ __all__ = (
import bpy
+def frange(start, stop, step=1.0):
+ while start < stop:
+ yield start
+ start += step
+
+
+def ref_curve_eval(curve, frame_start, frame_stop, frame_step, x):
+ fac = (x - frame_start) / frame_step
+ idx = int(fac)
+ fac = abs(fac - idx)
+ if idx < 0:
+ return curve[0]
+ elif idx + 1 >= len(curve):
+ return curve[-1]
+ return (1.0 - fac) * curve[idx] + fac * curve[idx + 1]
+
+
+def bezt_optimize(points, threshold, res, steps, org_ref_curve, frame_start, frame_stop, frame_step):
+ """
+ Try to optimize given pair of Bezier segments (triplet of contiguous control points).
+ """
+ # Trying to remove the center point and adjusting relevant handles of each end points.
+ # If resulting curve gives error below threshold (i.e. average difference between y-values of original
+ # and simplified curve is small enough), we keep it (i.e. remove its center point).
+
+ from mathutils.geometry import interpolate_bezier
+ from math import sqrt
+
+ def correct_bezpart(points):
+ # Same as in C code...
+ h1 = points[0] - points[1]
+ h2 = points[3] - points[2]
+ d = points[3].x - points[0].x
+ d1 = abs(h1.x)
+ d2 = abs(h2.x)
+
+ if d != 0.0 and d1 + d2 > d:
+ fac = d / (d1 + d2)
+ points[1] = points[0] - h1 * fac
+ points[2] = points[3] - h2 * fac
+
+ def bez_diff(ref_curve, cur_curve, res):
+ # start and end values shall be the same!
+ start_diff = end_diff = 0
+ for i, (ref_v, cur_pt) in enumerate(zip(ref_curve[1:-1], cur_curve[1:-1])):
+ # Note we give much higher importance (quadratic rate) to difference near matching end.
+ start_fac = (i + 1) / res
+ end_fac = 1.0 - start_fac
+ start_diff += (cur_pt.y - ref_v) / (start_fac * start_fac)
+ end_diff += (cur_pt.y - ref_v) / (end_fac * end_fac)
+ return start_diff / (res - 2), end_diff / (res - 2)
+
+ correct_bezpart(points)
+
+ start_vec = points[1] - points[0]
+ end_vec = points[2] - points[3]
+
+ neg_slope = points[1].y < points[0].y if points[1].y != points[0].y else points[2].y < points[0].y if points[2].y != points[0].y else points[3].y < points[0].y
+
+ cur_curve = interpolate_bezier(points[0], points[1], points[2], points[3], res)
+ ref_curve = [ref_curve_eval(org_ref_curve, frame_start, frame_stop, frame_step, pt.x) for pt in cur_curve]
+
+ start_diff, end_diff = bez_diff(ref_curve, cur_curve, res)
+ prev_start_diff, prev_end_diff = start_diff, end_diff
+ do_start = 0
+ #~ print(points)
+ #~ print(start_diff, end_diff)
+
+ f = 1.0
+ for i in range(steps):
+ error = max(abs(start_diff), abs(end_diff))
+ if error < threshold:
+ return error
+
+ prev_points = list(points)
+ prev_start_vec, prev_end_vec = start_vec.copy(), end_vec.copy()
+
+ if do_start > 0 or (do_start == 0 and abs(start_diff) > abs(end_diff)):
+ do_start += 1
+ if neg_slope:
+ if start_diff > 0.0:
+ start_vec /= 1 + start_diff * f
+ else:
+ start_vec *= 1 - start_diff * f
+ else:
+ if start_diff < 0.0:
+ start_vec /= 1 - start_diff * f
+ else:
+ start_vec *= 1 + start_diff * f
+ points[1] = points[0] + start_vec
+ else:
+ do_start -= 1
+ if neg_slope:
+ if end_diff > 0.0:
+ end_vec *= 1 + end_diff * f
+ else:
+ end_vec /= 1 - end_diff * f
+ else:
+ if end_diff < 0.0:
+ end_vec *= 1 - end_diff * f
+ else:
+ end_vec /= 1 + end_diff * f
+ points[2] = points[3] + end_vec
+
+ correct_bezpart(points)
+ cur_curve = interpolate_bezier(points[0], points[1], points[2], points[3], res)
+ ref_curve = [ref_curve_eval(org_ref_curve, frame_start, frame_stop, frame_step, pt.x) for pt in cur_curve]
+
+ start_diff, end_diff = bez_diff(ref_curve, cur_curve, res)
+ #~ print(points)
+ #~ print(start_diff, end_diff, f, do_start, neg_slope)
+
+ if ((do_start > 0 and abs(start_diff) > abs(prev_start_diff)) or
+ (do_start < 0 and abs(end_diff) > abs(prev_end_diff))):
+ #~ print("WRONG!!!", (start_diff, prev_start_diff) if do_start > 0 else (end_diff, prev_end_diff))
+ points[:] = prev_points
+ start_diff, end_diff = prev_start_diff, prev_end_diff
+ start_vec, end_vec = prev_start_vec, prev_end_vec
+ do_start *= -1
+ if not (do_start % 2):
+ f /= 2
+ else:
+ do_start = 0
+ prev_start_diff, prev_end_diff = start_diff, end_diff
+
+ return max(abs(start_diff), abs(end_diff))
+
+
+def simplify_fcurve(fcurve, frame_start, frame_stop, threshold):
+ """
+ This function simplifies given fcurve, removing some existing control points and adjusting the others' handles.
+ Note that it does not remove non-aligned (or auto) points, nor any using something else than Bezier interpolation.
+
+ :arg frame_start: First frame to simplify.
+ :type frame_start: int
+ :arg frame_stop: Last frame to simplify (excluded).
+ :type frame_stop: int
+ :arg threshold: Precision of simplification
+ (the smaller the more precise, never zero, typically 0.1 gives best results).
+ :type threshold: float
+
+ :return: The number of deleted keyframes.
+ :rtype: int
+ """
+
+ # * We make several passes on the curve, removing each time at most (n - 1) / 2 of its control points.
+ # * End points are never removed.
+ # * Points which do not have aligned handles are never removed, neither are points using non-Bezier interpolation.
+ # * Each set of contiguous, aligned/auto points define a single curve segment.
+ # * At each pass, for each segment, we check a set of triplets, and try to optimize it.
+
+ SIMPLIFIED_TYPES_AUTO = {'AUTO', 'AUTO_CLAMPED'}
+ SIMPLIFIED_TYPES = {'ALIGNED'} | SIMPLIFIED_TYPES_AUTO
+ SIMPLIFIED_INTERPOLATION = {'BEZIER'}
+
+ frame_step = max(0.001, threshold / 10.0)
+ res = min(1000, int(1 / threshold * 10))
+ steps = min(100, int(1 / threshold * 5))
+
+ ref_curve = [fcurve.evaluate(x) for x in frange(frame_start, frame_stop, frame_step)]
+
+ curves = [[[], False]]
+ for pt in fcurve.keyframe_points:
+ if pt.co.x < frame_start:
+ continue
+ if pt.co.x >= frame_stop:
+ break
+ if pt.interpolation not in SIMPLIFIED_INTERPOLATION:
+ # 'Break' point.
+ if len(curves[-1][0]) > 2:
+ curves.append([[], False])
+ else: # Current curve segment is too short to be simplifiable, simply ignore it!
+ curves[-1][0][:] = []
+ #~ print("breaking")
+ continue
+ if pt.handle_left_type not in SIMPLIFIED_TYPES or pt.handle_right_type not in SIMPLIFIED_TYPES:
+ # 'Break' point.
+ if len(curves[-1][0]) > 1:
+ curves[-1][0].append([[pt.handle_left, pt.co, pt.handle_right], False, pt])
+ curves.append([[], False])
+ else: # Current curve segment is too short to be simplifiable, simply ignore it!
+ curves[-1][0][:] = []
+ #~ print("breaking")
+ curves[-1][0].append([[pt.handle_left, pt.co, pt.handle_right], False, pt])
+
+ if not curves[-1][0]:
+ del curves[-1] # Cleanup.
+
+ if not curves:
+ return 0
+
+ del_keyframes = []
+ step_simplified = True
+ while step_simplified:
+ step_simplified = False
+ for crv in curves:
+ if crv[1]:
+ continue # that whole segment of curve is considered impossible to simplify further.
+
+ curve = crv[0]
+ curve_len = len(curve)
+ new_curve1 = curve[0:1]
+ del_keyframes1 = []
+ simplified1 = 0
+ tot_error1 = 0.0
+ if curve_len <= 2:
+ continue
+
+ for i in range(0, curve_len - 2, 2):
+ if curve[i + 1][1]:
+ # Center knot of this triplet is locked (marked as not removable), skip.
+ new_curve1 += curve[i + 1:i + 3]
+ points = [curve[i][0][1].copy(), curve[i][0][2].copy(), curve[i + 2][0][0].copy(), curve[i + 2][0][1].copy()]
+ error = bezt_optimize(points, threshold, res, steps, ref_curve, frame_start, frame_stop, frame_step)
+ #~ print(error)
+ if (error < threshold):
+ del_keyframes1.append(curve[i + 1][2])
+ tot_error1 += error
+ # Center points of knots do not change - ever!
+ new_curve1[-1][0][2] = points[1]
+ new_curve1.append(curve[i + 2])
+ new_curve1[-1][0][0] = points[2]
+ simplified1 += 1
+ else:
+ new_curve1 += curve[i + 1:i + 3] # Mere copy of org curve...
+ #~ new_curve1[-2][1] = True # Lock that center knot from now on.
+ step_simplified = step_simplified or (simplified1 > 0)
+
+ if curve_len > 3:
+ # If we have four or more control points, we also have to check the other possible set of triplets...
+ new_curve2 = curve[0:1]
+ del_keyframes2 = []
+ simplified2 = 0
+ tot_error2 = 0.0
+
+ for i in range(1, curve_len - 2, 2):
+ if curve[i + 1][1]:
+ # Center knot of this triplet is locked (marked as not removable), skip.
+ new_curve2 += curve[i + 1:i + 3]
+ points = [curve[i][0][1].copy(), curve[i][0][2].copy(), curve[i + 2][0][0].copy(), curve[i + 2][0][1].copy()]
+ error = bezt_optimize(points, threshold, res, steps, ref_curve, frame_start, frame_stop, frame_step)
+ #~ print(error)
+ if (error < threshold):
+ del_keyframes2.append(curve[i + 1][2])
+ tot_error2 += error
+ # Center points of knots do not change - ever!
+ new_curve2[-1][0][2] = points[1]
+ new_curve2.append(curve[i + 2])
+ new_curve2[-1][0][0] = points[2]
+ simplified2 += 1
+ else:
+ new_curve2 += curve[i + 1:i + 3] # Mere copy of org curve...
+ #~ new_curve2[-2][1] = True # Lock that center knot from now on.
+
+ if (simplified2 > simplified1) or (simplified2 and ((tot_error2 < tot_error1) or not simplified1)):
+ new_curve1 = new_curve2
+ del_keyframes1 = del_keyframes2
+ step_simplified = step_simplified or (simplified2 > 0)
+
+ if (len(new_curve1) < curve_len):
+ curve[:] = new_curve1
+ del_keyframes += del_keyframes1
+ else:
+ crv[1] = True # That segment of curve cannot be simplified further.
+
+ ret = len(del_keyframes)
+ if not del_keyframes:
+ return ret
+
+ # Now! Update our fcurve.
+
+ # 'Flatten' our curve segments into a single curve again.
+ curve = []
+ for c, _ in curves:
+ if len(c) >= 2:
+ if curve and curve[-1][2] == c[0][2]:
+ curve[-1][0][2] = c[0][2]
+ curve += c[1:]
+ else:
+ curve += c
+
+ # Update handles of kept, modified keyframes.
+ for bezt, _, pt in c:
+ # Tag 'auto' handles as 'aligned'.
+ if pt.handle_left_type in SIMPLIFIED_TYPES_AUTO:
+ pt.handle_left_type = 'ALIGNED'
+ if pt.handle_right_type in SIMPLIFIED_TYPES_AUTO:
+ pt.handle_right_type = 'ALIGNED'
+ pt.handle_left, pt.co, pt.handle_right = bezt
+
+ # Remove deleted keyframes - WARNING must be the last thing done! Otherwise, other points become invalid...
+ for pt in sorted(del_keyframes, key=lambda pt: pt.co.x, reverse=True):
+ fcurve.keyframe_points.remove(pt, fast=True)
+
+ fcurve.update()
+ return ret
+
+
# XXX visual keying is actually always considered as True in this code...
def bake_action(frame_start,
frame_end,
@@ -37,6 +335,7 @@ def bake_action(frame_start,
do_parents_clear=False,
do_clean=False,
action=None,
+ clean_threshold=0.0,
):
"""
@@ -66,6 +365,8 @@ def bake_action(frame_start,
:arg action: An action to bake the data into, or None for a new action
to be created.
:type action: :class:`bpy.types.Action` or None
+ :arg clean_threshold: How much approximation do we accept while simplifying fcurves.
+ :type clean_threshold: float
:return: an action or None
:rtype: :class:`bpy.types.Action`
@@ -241,6 +542,8 @@ def bake_action(frame_start,
keyframe_points.remove(keyframe_points[i])
else:
i += 1
+ if clean_threshold != 0.0:
+ simplify_fcurve(fcu, keyframe_points[0].co.x, keyframe_points[-1].co.x + 1, clean_threshold)
scene.frame_set(frame_back)
diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py
index 81de0d7c6f0..65ccc3f8dc3 100644
--- a/release/scripts/modules/bpy_extras/io_utils.py
+++ b/release/scripts/modules/bpy_extras/io_utils.py
@@ -21,7 +21,7 @@
__all__ = (
"ExportHelper",
"ImportHelper",
- "OrientationHelper",
+ "orientation_helper_factory",
"axis_conversion",
"axis_conversion_ensure",
"create_derived_objects",
@@ -35,7 +35,11 @@ __all__ = (
)
import bpy
-from bpy.props import StringProperty, BoolProperty, EnumProperty
+from bpy.props import (
+ StringProperty,
+ BoolProperty,
+ EnumProperty,
+ )
def _check_axis_conversion(op):
@@ -61,6 +65,12 @@ class ExportHelper:
options={'HIDDEN'},
)
+ # needed for mix-ins
+ order = [
+ "filepath",
+ "check_existing",
+ ]
+
# subclasses can override with decorator
# True == use ext, False == no ext, None == do nothing.
check_extension = True
@@ -109,6 +119,11 @@ class ImportHelper:
subtype='FILE_PATH',
)
+ # needed for mix-ins
+ order = [
+ "filepath",
+ ]
+
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
@@ -117,13 +132,14 @@ class ImportHelper:
return _check_axis_conversion(self)
-class OrientationHelper:
+def orientation_helper_factory(name, axis_forward='Y', axis_up='Z'):
+ members = {}
def _update_axis_forward(self, context):
if self.axis_forward[-1] == self.axis_up[-1]:
self.axis_up = self.axis_up[0:-1] + 'XYZ'[('XYZ'.index(self.axis_up[-1]) + 1) % 3]
- axis_forward = EnumProperty(
+ members['axis_forward'] = EnumProperty(
name="Forward",
items=(('X', "X Forward", ""),
('Y', "Y Forward", ""),
@@ -132,7 +148,7 @@ class OrientationHelper:
('-Y', "-Y Forward", ""),
('-Z', "-Z Forward", ""),
),
- default='-Z',
+ default=axis_forward,
update=_update_axis_forward,
)
@@ -140,7 +156,7 @@ class OrientationHelper:
if self.axis_up[-1] == self.axis_forward[-1]:
self.axis_forward = self.axis_forward[0:-1] + 'XYZ'[('XYZ'.index(self.axis_forward[-1]) + 1) % 3]
- axis_up = EnumProperty(
+ members['axis_up'] = EnumProperty(
name="Up",
items=(('X', "X Up", ""),
('Y', "Y Up", ""),
@@ -149,10 +165,17 @@ class OrientationHelper:
('-Y', "-Y Up", ""),
('-Z', "-Z Up", ""),
),
- default='Y',
+ default=axis_up,
update=_update_axis_up,
)
+ members["order"] = [
+ "axis_forward",
+ "axis_up",
+ ]
+
+ return type(name, (object,), members)
+
# Axis conversion function, not pretty LUT
# use lookup table to convert between any axis
@@ -349,7 +372,7 @@ def unpack_list(list_of_tuples):
# same as above except that it adds 0 for triangle faces
def unpack_face_list(list_of_tuples):
- #allocate the entire list
+ # allocate the entire list
flat_ls = [0] * (len(list_of_tuples) * 4)
i = 0
diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py
index 13ef86b23c0..16224144ee4 100644
--- a/release/scripts/modules/bpy_extras/object_utils.py
+++ b/release/scripts/modules/bpy_extras/object_utils.py
@@ -31,7 +31,10 @@ __all__ = (
import bpy
-from bpy.props import BoolProperty, FloatVectorProperty
+from bpy.props import (
+ BoolProperty,
+ FloatVectorProperty,
+ )
def add_object_align_init(context, operator):
@@ -171,7 +174,7 @@ def object_data_add(context, obdata, operator=None, use_active_layer=True, name=
obj_act.select = True
scene.update() # apply location
- #scene.objects.active = obj_new
+ # scene.objects.active = obj_new
bpy.ops.object.join() # join into the active.
if obdata:
@@ -287,7 +290,8 @@ def world_to_camera_view(scene, obj, coord):
Returns the camera space coords for a 3d point.
(also known as: normalized device coordinates - NDC).
- Where (0, 0) is the bottom left and (1, 1) is the top right of the camera frame.
+ Where (0, 0) is the bottom left and (1, 1)
+ is the top right of the camera frame.
values outside 0-1 are also supported.
A negative 'z' value means the point is behind the camera.
@@ -300,7 +304,8 @@ def world_to_camera_view(scene, obj, coord):
:type obj: :class:`bpy.types.Object`
:arg coord: World space location.
:type coord: :class:`mathutils.Vector`
- :return: a vector where X and Y map to the view plane and Z is the depth on the view axis.
+ :return: a vector where X and Y map to the view plane and
+ Z is the depth on the view axis.
:rtype: :class:`mathutils.Vector`
"""
from mathutils import Vector
diff --git a/release/scripts/modules/bpy_extras/view3d_utils.py b/release/scripts/modules/bpy_extras/view3d_utils.py
index ec4a395f1e1..4aa06262970 100644
--- a/release/scripts/modules/bpy_extras/view3d_utils.py
+++ b/release/scripts/modules/bpy_extras/view3d_utils.py
@@ -69,11 +69,13 @@ def region_2d_to_origin_3d(region, rv3d, coord, clamp=None):
.. note::
- Orthographic views have a less obvious origin, the far clip is used to define the viewport near/far extents.
- Since far clip can be a very large value, the result may give with numeric precision issues.
+ Orthographic views have a less obvious origin,
+ the far clip is used to define the viewport near/far extents.
+ Since far clip can be a very large value,
+ the result may give with numeric precision issues.
- To avoid this problem, you can optionally clamp the far clip to a smaller value
- based on the data you're operating on.
+ To avoid this problem, you can optionally clamp the far clip to a
+ smaller value based on the data you're operating on.
:arg region: region of the 3D viewport, typically bpy.context.region.
:type region: :class:`bpy.types.Region`
@@ -160,7 +162,7 @@ def region_2d_to_location_3d(region, rv3d, coord, depth_location):
)[0]
-def location_3d_to_region_2d(region, rv3d, coord):
+def location_3d_to_region_2d(region, rv3d, coord, default=None):
"""
Return the *region* relative 2d location of a 3d position.
@@ -170,8 +172,10 @@ def location_3d_to_region_2d(region, rv3d, coord):
:type rv3d: :class:`bpy.types.RegionView3D`
:arg coord: 3d worldspace location.
:type coord: 3d vector
+ :arg default: Return this value if ``coord``
+ is behind the origin of a perspective view.
:return: 2d location
- :rtype: :class:`mathutils.Vector`
+ :rtype: :class:`mathutils.Vector` or ``default`` argument.
"""
from mathutils import Vector
@@ -184,4 +188,4 @@ def location_3d_to_region_2d(region, rv3d, coord):
height_half + height_half * (prj.y / prj.w),
))
else:
- return None
+ return default
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index c7ec7e1e54a..92dbd2dbd0e 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -715,7 +715,7 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
__slots__ = ()
def path_menu(self, searchpaths, operator,
- props_default={}, filter_ext=None):
+ props_default=None, filter_ext=None):
layout = self.layout
# hard coded to set the operators 'filepath' to the filename.
@@ -745,8 +745,9 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
text=bpy.path.display_name(f),
translate=False)
- for attr, value in props_default.items():
- setattr(props, attr, value)
+ if props_default is not None:
+ for attr, value in props_default.items():
+ setattr(props, attr, value)
props.filepath = filepath
if operator == "script.execute_preset":
@@ -754,14 +755,21 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
def draw_preset(self, context):
"""
- Define these on the subclass
- - preset_operator
- - preset_subdir
+ Define these on the subclass:
+ - preset_operator (string)
+ - preset_subdir (string)
+
+ Optionally:
+ - preset_extensions (set of strings)
+ - preset_operator_defaults (dict of keyword args)
"""
import bpy
+ ext_valid = getattr(self, "preset_extensions", {".py", ".xml"})
+ props_default = getattr(self, "preset_operator_defaults", None)
self.path_menu(bpy.utils.preset_paths(self.preset_subdir),
self.preset_operator,
- filter_ext=lambda ext: ext.lower() in {".py", ".xml"})
+ props_default=props_default,
+ filter_ext=lambda ext: ext.lower() in ext_valid)
@classmethod
def draw_collapsible(cls, context, layout):
@@ -773,24 +781,6 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
layout.menu(cls.__name__, icon='COLLAPSEMENU')
-class Region(StructRNA):
- __slots__ = ()
-
- def callback_add(self, cb, args, draw_mode):
- """
- Append a draw function to this region,
- deprecated, instead use bpy.types.SpaceView3D.draw_handler_add
- """
- for area in self.id_data.areas:
- for region in area.regions:
- if region == self:
- spacetype = type(area.spaces[0])
- return spacetype.draw_handler_add(cb, args, self.type,
- draw_mode)
-
- return None
-
-
class NodeTree(bpy_types.ID, metaclass=RNAMetaPropGroup):
__slots__ = ()
diff --git a/release/scripts/modules/nodeitems_utils.py b/release/scripts/modules/nodeitems_utils.py
index 2882a08fbd4..2f69ea84386 100644
--- a/release/scripts/modules/nodeitems_utils.py
+++ b/release/scripts/modules/nodeitems_utils.py
@@ -37,13 +37,17 @@ class NodeCategory:
else:
def items_gen(context):
for item in items:
- if item.poll is None or item.poll(context):
+ if item.poll is None or context is None or item.poll(context):
yield item
self.items = items_gen
class NodeItem:
- def __init__(self, nodetype, label=None, settings={}, poll=None):
+ def __init__(self, nodetype, label=None, settings=None, poll=None):
+
+ if settings is None:
+ settings = {}
+
self.nodetype = nodetype
self._label = label
self.settings = settings
@@ -136,7 +140,7 @@ def register_node_categories(identifier, cat_list):
def node_categories_iter(context):
for cat_type in _node_categories.values():
for cat in cat_type[0]:
- if cat.poll and cat.poll(context):
+ if cat.poll and ((context is None) or cat.poll(context)):
yield cat
diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py
index 353362ed168..dae262e93d7 100644
--- a/release/scripts/modules/rna_info.py
+++ b/release/scripts/modules/rna_info.py
@@ -268,7 +268,8 @@ class InfoPropertyRNA:
self.default_str = "\"%s\"" % self.default
elif self.type == "enum":
if self.is_enum_flag:
- self.default_str = "%r" % self.default # repr or set()
+ # self.default_str = "%r" % self.default # repr or set()
+ self.default_str = "{%s}" % repr(list(sorted(self.default)))[1:-1]
else:
self.default_str = "'%s'" % self.default
elif self.array_length:
@@ -695,7 +696,7 @@ def BuildRNAInfo():
return InfoStructRNA.global_lookup, InfoFunctionRNA.global_lookup, InfoOperatorRNA.global_lookup, InfoPropertyRNA.global_lookup
-if __name__ == "__main__":
+def main():
import rna_info
struct = rna_info.BuildRNAInfo()[0]
data = []
@@ -723,3 +724,7 @@ if __name__ == "__main__":
else:
text = bpy.data.texts.new(name="api.py")
text.from_string(data)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py
index f4649453b46..44722fa7162 100644
--- a/release/scripts/modules/rna_prop_ui.py
+++ b/release/scripts/modules/rna_prop_ui.py
@@ -32,6 +32,13 @@ def rna_idprop_ui_get(item, create=True):
return None
+def rna_idprop_ui_del(item):
+ try:
+ del item['_RNA_UI']
+ except KeyError:
+ pass
+
+
def rna_idprop_ui_prop_get(item, prop, create=True):
rna_ui = rna_idprop_ui_get(item, create)
@@ -46,7 +53,7 @@ def rna_idprop_ui_prop_get(item, prop, create=True):
return rna_ui[prop]
-def rna_idprop_ui_prop_clear(item, prop):
+def rna_idprop_ui_prop_clear(item, prop, remove=True):
rna_ui = rna_idprop_ui_get(item, False)
if rna_ui is None:
@@ -54,8 +61,10 @@ def rna_idprop_ui_prop_clear(item, prop):
try:
del rna_ui[prop]
- except:
+ except KeyError:
pass
+ if remove and len(item.keys()) == 1:
+ rna_idprop_ui_del(item)
def rna_idprop_context_value(context, context_member, property_type):
diff --git a/release/scripts/modules/rna_xml.py b/release/scripts/modules/rna_xml.py
index 729d6238ac3..ad4809efbe1 100644
--- a/release/scripts/modules/rna_xml.py
+++ b/release/scripts/modules/rna_xml.py
@@ -32,7 +32,7 @@ def build_property_typemap(skip_classes, skip_typemap):
if issubclass(cls, skip_classes):
continue
- ## to support skip-save we cant get all props
+ # # to support skip-save we cant get all props
# properties = cls.bl_rna.properties.keys()
properties = []
for prop_id, prop in cls.bl_rna.properties.items():
diff --git a/release/scripts/presets/interface_theme/back_to_black.xml b/release/scripts/presets/interface_theme/back_to_black.xml
index 6520d81b900..05613e79411 100644
--- a/release/scripts/presets/interface_theme/back_to_black.xml
+++ b/release/scripts/presets/interface_theme/back_to_black.xml
@@ -241,6 +241,9 @@
<ThemeView3D grid="#222222"
wire="#888888"
wire_edit="#000000"
+ gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
lamp="#c1d40028"
speaker="#535353"
camera="#000000"
@@ -296,6 +299,7 @@
bundle_solid="#c8c8c8"
camera_path="#5a5a5a"
skin_root="#000000"
+ clipping_border_3d="#313131ff"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -542,7 +546,10 @@
</ThemeDopeSheet>
</dopesheet_editor>
<image_editor>
- <ThemeImageEditor vertex="#0f13bb"
+ <ThemeImageEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ vertex="#0f13bb"
vertex_select="#ff8500"
vertex_size="3"
vertex_unreferenced="#000000"
@@ -605,7 +612,10 @@
</ThemeImageEditor>
</image_editor>
<sequence_editor>
- <ThemeSequenceEditor grid="#282828"
+ <ThemeSequenceEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ grid="#282828"
window_sliders="#a0a0a0"
movie_strip="#516987"
movieclip_strip="#20208f"
@@ -716,7 +726,9 @@
</text_editor>
<timeline>
<ThemeTimeline grid="#272727"
- frame_current="#2e5820">
+ frame_current="#2e5820"
+ time_keyframe="#ddd700"
+ time_grease_pencil="#b5e61d">
<space>
<ThemeSpaceGeneric back="#000000"
title="#5d5d5d"
@@ -745,7 +757,10 @@
</ThemeTimeline>
</timeline>
<node_editor>
- <ThemeNodeEditor node_selected="#ffffff"
+ <ThemeNodeEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ node_selected="#ffffff"
node_active="#ffffff"
wire="#6eafff"
wire_inner="#737373"
@@ -964,7 +979,10 @@
</ThemeConsole>
</console>
<clip_editor>
- <ThemeClipEditor marker_outline="#0094af"
+ <ThemeClipEditor gp_vertex="#000000"
+ gp_vertex_select="#000000"
+ gp_vertex_size="1"
+ marker_outline="#0094af"
marker="#7f7f00"
active_marker="#ffffff"
selected_marker="#ffff00"
diff --git a/release/scripts/presets/interface_theme/blender_24x.xml b/release/scripts/presets/interface_theme/blender_24x.xml
index bb9b03d56ea..1ea335c7d73 100644
--- a/release/scripts/presets/interface_theme/blender_24x.xml
+++ b/release/scripts/presets/interface_theme/blender_24x.xml
@@ -241,6 +241,9 @@
<ThemeView3D grid="#4c4c4c"
wire="#000000"
wire_edit="#000000"
+ gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
lamp="#00000028"
speaker="#000000"
camera="#000000"
@@ -296,6 +299,7 @@
bundle_solid="#c8c8c8"
camera_path="#000000"
skin_root="#b44d4d"
+ clipping_border_3d="#313131ff"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -542,7 +546,10 @@
</ThemeDopeSheet>
</dopesheet_editor>
<image_editor>
- <ThemeImageEditor vertex="#000000"
+ <ThemeImageEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ vertex="#000000"
vertex_select="#ff8500"
vertex_size="3"
vertex_unreferenced="#000000"
@@ -605,7 +612,10 @@
</ThemeImageEditor>
</image_editor>
<sequence_editor>
- <ThemeSequenceEditor grid="#404040"
+ <ThemeSequenceEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ grid="#404040"
window_sliders="#a0a0a0"
movie_strip="#516987"
movieclip_strip="#20208f"
@@ -716,7 +726,9 @@
</text_editor>
<timeline>
<ThemeTimeline grid="#5b5b5b"
- frame_current="#60c040">
+ frame_current="#60c040"
+ time_keyframe="#ddd700"
+ time_grease_pencil="#b5e61d">
<space>
<ThemeSpaceGeneric back="#999999"
title="#000000"
@@ -745,7 +757,10 @@
</ThemeTimeline>
</timeline>
<node_editor>
- <ThemeNodeEditor node_selected="#ffffff"
+ <ThemeNodeEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ node_selected="#ffffff"
node_active="#ffffff"
wire="#000000"
wire_inner="#737373"
@@ -964,7 +979,10 @@
</ThemeConsole>
</console>
<clip_editor>
- <ThemeClipEditor marker_outline="#000000"
+ <ThemeClipEditor gp_vertex="#000000"
+ gp_vertex_select="#000000"
+ gp_vertex_size="1"
+ marker_outline="#000000"
marker="#7f7f00"
active_marker="#ffffff"
selected_marker="#ffff00"
diff --git a/release/scripts/presets/interface_theme/elsyiun.xml b/release/scripts/presets/interface_theme/elsyiun.xml
index 6734850f876..5cb7af1ccc2 100644
--- a/release/scripts/presets/interface_theme/elsyiun.xml
+++ b/release/scripts/presets/interface_theme/elsyiun.xml
@@ -241,6 +241,9 @@
<ThemeView3D grid="#585858"
wire="#000000"
wire_edit="#000000"
+ gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
lamp="#00000028"
speaker="#000000"
camera="#000000"
@@ -296,6 +299,7 @@
bundle_solid="#c8c8c8"
camera_path="#000000"
skin_root="#000000"
+ clipping_border_3d="#313131ff"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -542,7 +546,10 @@
</ThemeDopeSheet>
</dopesheet_editor>
<image_editor>
- <ThemeImageEditor vertex="#32adec"
+ <ThemeImageEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ vertex="#32adec"
vertex_select="#be6925"
vertex_size="3"
vertex_unreferenced="#000000"
@@ -605,7 +612,10 @@
</ThemeImageEditor>
</image_editor>
<sequence_editor>
- <ThemeSequenceEditor grid="#818181"
+ <ThemeSequenceEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ grid="#818181"
window_sliders="#a0a0a0"
movie_strip="#516987"
movieclip_strip="#20208f"
@@ -716,7 +726,9 @@
</text_editor>
<timeline>
<ThemeTimeline grid="#5b5b5b"
- frame_current="#60c040">
+ frame_current="#60c040"
+ time_keyframe="#ddd700"
+ time_grease_pencil="#b5e61d">
<space>
<ThemeSpaceGeneric back="#4b4b4b"
title="#000000"
@@ -745,7 +757,10 @@
</ThemeTimeline>
</timeline>
<node_editor>
- <ThemeNodeEditor node_selected="#ffffff"
+ <ThemeNodeEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ node_selected="#ffffff"
node_active="#ffffff"
wire="#000000"
wire_inner="#737373"
@@ -964,7 +979,10 @@
</ThemeConsole>
</console>
<clip_editor>
- <ThemeClipEditor marker_outline="#000000"
+ <ThemeClipEditor gp_vertex="#000000"
+ gp_vertex_select="#000000"
+ gp_vertex_size="1"
+ marker_outline="#000000"
marker="#7f7f00"
active_marker="#ffffff"
selected_marker="#ffff00"
diff --git a/release/scripts/presets/interface_theme/flatty_light.xml b/release/scripts/presets/interface_theme/flatty_light.xml
index e22d3471863..deb1101302a 100644
--- a/release/scripts/presets/interface_theme/flatty_light.xml
+++ b/release/scripts/presets/interface_theme/flatty_light.xml
@@ -242,8 +242,8 @@
wire="#000000"
wire_edit="#808080"
gp_vertex="#000000"
- gp_vertex_select="#000000"
- gp_vertex_size="1"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
lamp="#00000028"
speaker="#000000"
camera="#000000"
@@ -299,6 +299,7 @@
bundle_solid="#c8c8c8"
camera_path="#000000"
skin_root="#b44d4d"
+ clipping_border_3d="#313131ff"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -546,8 +547,8 @@
</dopesheet_editor>
<image_editor>
<ThemeImageEditor gp_vertex="#000000"
- gp_vertex_select="#000000"
- gp_vertex_size="1"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
vertex="#000000"
vertex_select="#ff8500"
vertex_size="3"
@@ -612,8 +613,8 @@
</image_editor>
<sequence_editor>
<ThemeSequenceEditor gp_vertex="#000000"
- gp_vertex_select="#000000"
- gp_vertex_size="1"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
grid="#404040"
window_sliders="#a0a0a0"
movie_strip="#516987"
@@ -726,8 +727,8 @@
<timeline>
<ThemeTimeline grid="#5b5b5b"
frame_current="#60c040"
- time_keyframe="#000000"
- time_grease_pencil="#000000">
+ time_keyframe="#ddd700"
+ time_grease_pencil="#b5e61d">
<space>
<ThemeSpaceGeneric back="#727272"
title="#000000"
@@ -757,8 +758,8 @@
</timeline>
<node_editor>
<ThemeNodeEditor gp_vertex="#000000"
- gp_vertex_select="#000000"
- gp_vertex_size="1"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
node_selected="#f15800"
node_active="#f15800"
wire="#a7a7a7"
@@ -1144,31 +1145,31 @@
<panel_title>
<ThemeFontStyle points="12"
font_kerning_style="FITTED"
- shadow="2"
- shadow_offset_x="2"
- shadow_offset_y="-2"
- shadow_alpha="0.1"
+ shadow="1"
+ shadow_offset_x="0"
+ shadow_offset_y="-1"
+ shadow_alpha="0.15"
shadow_value="1">
</ThemeFontStyle>
</panel_title>
<widget_label>
<ThemeFontStyle points="11"
font_kerning_style="FITTED"
- shadow="1"
- shadow_offset_x="1"
+ shadow="3"
+ shadow_offset_x="0"
shadow_offset_y="-1"
- shadow_alpha="0.2"
+ shadow_alpha="0.15"
shadow_value="1">
</ThemeFontStyle>
</widget_label>
<widget>
<ThemeFontStyle points="11"
font_kerning_style="FITTED"
- shadow="1"
- shadow_offset_x="1"
- shadow_offset_y="-1"
- shadow_alpha="0.1"
- shadow_value="1">
+ shadow="0"
+ shadow_offset_x="0"
+ shadow_offset_y="0"
+ shadow_alpha="0.25"
+ shadow_value="0">
</ThemeFontStyle>
</widget>
</ThemeStyle>
diff --git a/release/scripts/presets/interface_theme/graph.xml b/release/scripts/presets/interface_theme/graph.xml
index 1cb9a8985e4..063524a9187 100644
--- a/release/scripts/presets/interface_theme/graph.xml
+++ b/release/scripts/presets/interface_theme/graph.xml
@@ -241,6 +241,9 @@
<ThemeView3D grid="#585858"
wire="#000000"
wire_edit="#161616"
+ gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
lamp="#00000028"
speaker="#000000"
camera="#8d8c8d"
@@ -296,6 +299,7 @@
bundle_solid="#c8c8c8"
camera_path="#000000"
skin_root="#000000"
+ clipping_border_3d="#313131ff"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -542,7 +546,10 @@
</ThemeDopeSheet>
</dopesheet_editor>
<image_editor>
- <ThemeImageEditor vertex="#000000"
+ <ThemeImageEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ vertex="#000000"
vertex_select="#0094ff"
vertex_size="3"
vertex_unreferenced="#000000"
@@ -605,7 +612,10 @@
</ThemeImageEditor>
</image_editor>
<sequence_editor>
- <ThemeSequenceEditor grid="#6e6e6e"
+ <ThemeSequenceEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ grid="#6e6e6e"
window_sliders="#a0a0a0"
movie_strip="#5794c3"
movieclip_strip="#20208f"
@@ -716,7 +726,9 @@
</text_editor>
<timeline>
<ThemeTimeline grid="#6d6d6d"
- frame_current="#4291dc">
+ frame_current="#4291dc"
+ time_keyframe="#ddd700"
+ time_grease_pencil="#b5e61d">
<space>
<ThemeSpaceGeneric back="#5d5d5d"
title="#e4e4e4"
@@ -745,7 +757,10 @@
</ThemeTimeline>
</timeline>
<node_editor>
- <ThemeNodeEditor node_selected="#fff4f8"
+ <ThemeNodeEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ node_selected="#fff4f8"
node_active="#ffffff"
wire="#292929"
wire_inner="#737373"
@@ -964,7 +979,10 @@
</ThemeConsole>
</console>
<clip_editor>
- <ThemeClipEditor marker_outline="#000000"
+ <ThemeClipEditor gp_vertex="#000000"
+ gp_vertex_select="#000000"
+ gp_vertex_size="1"
+ marker_outline="#000000"
marker="#7f7f00"
active_marker="#ffffff"
selected_marker="#ffff00"
diff --git a/release/scripts/presets/interface_theme/hexagon.xml b/release/scripts/presets/interface_theme/hexagon.xml
index 40228e832a7..74adb9f9d27 100644
--- a/release/scripts/presets/interface_theme/hexagon.xml
+++ b/release/scripts/presets/interface_theme/hexagon.xml
@@ -241,6 +241,9 @@
<ThemeView3D grid="#5e5e83"
wire="#000000"
wire_edit="#000000"
+ gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
lamp="#00000028"
speaker="#000000"
camera="#000000"
@@ -296,6 +299,7 @@
bundle_solid="#c8c8c8"
camera_path="#000000"
skin_root="#000000"
+ clipping_border_3d="#313131ff"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -542,7 +546,10 @@
</ThemeDopeSheet>
</dopesheet_editor>
<image_editor>
- <ThemeImageEditor vertex="#334cca"
+ <ThemeImageEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ vertex="#334cca"
vertex_select="#50c8ff"
vertex_size="3"
vertex_unreferenced="#000000"
@@ -605,7 +612,10 @@
</ThemeImageEditor>
</image_editor>
<sequence_editor>
- <ThemeSequenceEditor grid="#404040"
+ <ThemeSequenceEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ grid="#404040"
window_sliders="#a0a0a0"
movie_strip="#516987"
movieclip_strip="#20208f"
@@ -716,7 +726,9 @@
</text_editor>
<timeline>
<ThemeTimeline grid="#58587c"
- frame_current="#60c040">
+ frame_current="#60c040"
+ time_keyframe="#ddd700"
+ time_grease_pencil="#b5e61d">
<space>
<ThemeSpaceGeneric back="#646875"
title="#000000"
@@ -745,7 +757,10 @@
</ThemeTimeline>
</timeline>
<node_editor>
- <ThemeNodeEditor node_selected="#ffffff"
+ <ThemeNodeEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ node_selected="#ffffff"
node_active="#ffffff"
wire="#000000"
wire_inner="#737373"
@@ -964,7 +979,10 @@
</ThemeConsole>
</console>
<clip_editor>
- <ThemeClipEditor marker_outline="#000000"
+ <ThemeClipEditor gp_vertex="#000000"
+ gp_vertex_select="#000000"
+ gp_vertex_size="1"
+ marker_outline="#000000"
marker="#7f7f00"
active_marker="#ffffff"
selected_marker="#ffff00"
diff --git a/release/scripts/presets/interface_theme/rtheme.xml b/release/scripts/presets/interface_theme/rtheme.xml
index 268b2e0f1ae..c25806729b9 100644
--- a/release/scripts/presets/interface_theme/rtheme.xml
+++ b/release/scripts/presets/interface_theme/rtheme.xml
@@ -981,7 +981,7 @@
<clip_editor>
<ThemeClipEditor gp_vertex="#000000"
gp_vertex_select="#000000"
- gp_vertex_size="0"
+ gp_vertex_size="1"
marker_outline="#000000"
marker="#7f7f00"
active_marker="#ffffff"
diff --git a/release/scripts/presets/interface_theme/science_lab.xml b/release/scripts/presets/interface_theme/science_lab.xml
index 98dddfb0014..b767e4a837b 100644
--- a/release/scripts/presets/interface_theme/science_lab.xml
+++ b/release/scripts/presets/interface_theme/science_lab.xml
@@ -241,6 +241,9 @@
<ThemeView3D grid="#416064"
wire="#439ad2"
wire_edit="#7f7f7f"
+ gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
lamp="#dbac00b9"
speaker="#229cd8"
camera="#e28400"
@@ -296,6 +299,7 @@
bundle_solid="#6e6e6e"
camera_path="#9f5500"
skin_root="#f1b66e"
+ clipping_border_3d="#313131ff"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -542,7 +546,10 @@
</ThemeDopeSheet>
</dopesheet_editor>
<image_editor>
- <ThemeImageEditor vertex="#bcf7fa"
+ <ThemeImageEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ vertex="#bcf7fa"
vertex_select="#ffc700"
vertex_size="5"
vertex_unreferenced="#000000"
@@ -605,7 +612,10 @@
</ThemeImageEditor>
</image_editor>
<sequence_editor>
- <ThemeSequenceEditor grid="#404040"
+ <ThemeSequenceEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ grid="#404040"
window_sliders="#a0a0a0"
movie_strip="#516987"
movieclip_strip="#20208f"
@@ -716,7 +726,9 @@
</text_editor>
<timeline>
<ThemeTimeline grid="#5b5b5b"
- frame_current="#bac6af">
+ frame_current="#bac6af"
+ time_keyframe="#ddd700"
+ time_grease_pencil="#b5e61d">
<space>
<ThemeSpaceGeneric back="#333333"
title="#000000"
@@ -745,7 +757,10 @@
</ThemeTimeline>
</timeline>
<node_editor>
- <ThemeNodeEditor node_selected="#6ebdff"
+ <ThemeNodeEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ node_selected="#6ebdff"
node_active="#fefff3"
wire="#9effc5"
wire_inner="#737373"
@@ -964,7 +979,10 @@
</ThemeConsole>
</console>
<clip_editor>
- <ThemeClipEditor marker_outline="#000000"
+ <ThemeClipEditor gp_vertex="#000000"
+ gp_vertex_select="#000000"
+ gp_vertex_size="1"
+ marker_outline="#000000"
marker="#7f7f00"
active_marker="#ffffff"
selected_marker="#ffff00"
diff --git a/release/scripts/presets/interface_theme/softimage.xml b/release/scripts/presets/interface_theme/softimage.xml
index d58e04619ed..5b63a775680 100644
--- a/release/scripts/presets/interface_theme/softimage.xml
+++ b/release/scripts/presets/interface_theme/softimage.xml
@@ -241,6 +241,9 @@
<ThemeView3D grid="#6b6b6b"
wire="#242424"
wire_edit="#000000"
+ gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
lamp="#ffe56666"
speaker="#c2e787"
camera="#000000"
@@ -296,6 +299,7 @@
bundle_solid="#c8c8c8"
camera_path="#000000"
skin_root="#000000"
+ clipping_border_3d="#313131ff"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -542,7 +546,10 @@
</ThemeDopeSheet>
</dopesheet_editor>
<image_editor>
- <ThemeImageEditor vertex="#000000"
+ <ThemeImageEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ vertex="#000000"
vertex_select="#ffffff"
vertex_size="3"
vertex_unreferenced="#000000"
@@ -605,7 +612,10 @@
</ThemeImageEditor>
</image_editor>
<sequence_editor>
- <ThemeSequenceEditor grid="#afafaf"
+ <ThemeSequenceEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ grid="#afafaf"
window_sliders="#777777"
movie_strip="#87a4c3"
movieclip_strip="#95add0"
@@ -716,7 +726,9 @@
</text_editor>
<timeline>
<ThemeTimeline grid="#918d8c"
- frame_current="#f06868">
+ frame_current="#f06868"
+ time_keyframe="#ddd700"
+ time_grease_pencil="#b5e61d">
<space>
<ThemeSpaceGeneric back="#aca8a7"
title="#cccccc"
@@ -745,7 +757,10 @@
</ThemeTimeline>
</timeline>
<node_editor>
- <ThemeNodeEditor node_selected="#ffffff"
+ <ThemeNodeEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ node_selected="#ffffff"
node_active="#ffffff"
wire="#222222"
wire_inner="#737373"
@@ -964,7 +979,10 @@
</ThemeConsole>
</console>
<clip_editor>
- <ThemeClipEditor marker_outline="#000000"
+ <ThemeClipEditor gp_vertex="#000000"
+ gp_vertex_select="#000000"
+ gp_vertex_size="1"
+ marker_outline="#000000"
marker="#71cd7f"
active_marker="#ffffff"
selected_marker="#ff2f7a"
diff --git a/release/scripts/presets/interface_theme/ubuntu_ambiance.xml b/release/scripts/presets/interface_theme/ubuntu_ambiance.xml
index b2743f36c02..d1c8b0a23ff 100644
--- a/release/scripts/presets/interface_theme/ubuntu_ambiance.xml
+++ b/release/scripts/presets/interface_theme/ubuntu_ambiance.xml
@@ -241,6 +241,9 @@
<ThemeView3D grid="#3c3b37"
wire="#93237f"
wire_edit="#93237f"
+ gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
lamp="#ffffff34"
speaker="#93237f"
camera="#159dce"
@@ -296,6 +299,7 @@
bundle_solid="#c8c8c8"
camera_path="#7dbd00"
skin_root="#000000"
+ clipping_border_3d="#313131ff"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -542,7 +546,10 @@
</ThemeDopeSheet>
</dopesheet_editor>
<image_editor>
- <ThemeImageEditor vertex="#000000"
+ <ThemeImageEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ vertex="#000000"
vertex_select="#f47421"
vertex_size="3"
vertex_unreferenced="#000000"
@@ -605,7 +612,10 @@
</ThemeImageEditor>
</image_editor>
<sequence_editor>
- <ThemeSequenceEditor grid="#282828"
+ <ThemeSequenceEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ grid="#282828"
window_sliders="#a0a0a0"
movie_strip="#516987"
movieclip_strip="#20208f"
@@ -716,7 +726,9 @@
</text_editor>
<timeline>
<ThemeTimeline grid="#272727"
- frame_current="#f47421">
+ frame_current="#f47421"
+ time_keyframe="#ddd700"
+ time_grease_pencil="#b5e61d">
<space>
<ThemeSpaceGeneric back="#131311"
title="#000000"
@@ -745,7 +757,10 @@
</ThemeTimeline>
</timeline>
<node_editor>
- <ThemeNodeEditor node_selected="#ffffff"
+ <ThemeNodeEditor gp_vertex="#000000"
+ gp_vertex_select="#ff8500"
+ gp_vertex_size="3"
+ node_selected="#ffffff"
node_active="#ffffff"
wire="#f45b00"
wire_inner="#737373"
@@ -964,7 +979,10 @@
</ThemeConsole>
</console>
<clip_editor>
- <ThemeClipEditor marker_outline="#000000"
+ <ThemeClipEditor gp_vertex="#000000"
+ gp_vertex_select="#000000"
+ gp_vertex_size="1"
+ marker_outline="#000000"
marker="#76243b"
active_marker="#ffffff"
selected_marker="#d5ff00"
diff --git a/release/scripts/presets/keyconfig/3dsmax.py b/release/scripts/presets/keyconfig/3dsmax.py
index f85d3b43041..7694e338d68 100644
--- a/release/scripts/presets/keyconfig/3dsmax.py
+++ b/release/scripts/presets/keyconfig/3dsmax.py
@@ -754,8 +754,6 @@ kmi = km.keymap_items.new('anim.channels_move', 'PAGE_DOWN', 'PRESS', shift=True
kmi.properties.direction = 'BOTTOM'
kmi = km.keymap_items.new('anim.channels_group', 'G', 'PRESS', ctrl=True)
kmi = km.keymap_items.new('anim.channels_ungroup', 'G', 'PRESS', alt=True)
-kmi = km.keymap_items.new('anim.channels_visibility_set', 'V', 'PRESS')
-kmi = km.keymap_items.new('anim.channels_visibility_toggle', 'V', 'PRESS', shift=True)
# Map UV Editor
km = kc.keymaps.new('UV Editor', space_type='EMPTY', region_type='WINDOW', modal=False)
@@ -1055,7 +1053,6 @@ kmi.properties.name = 'NODE_MT_add'
kmi = km.keymap_items.new('node.duplicate_move', 'D', 'PRESS', shift=True)
kmi = km.keymap_items.new('node.duplicate_move_keep_inputs', 'D', 'PRESS', shift=True, ctrl=True)
kmi = km.keymap_items.new('node.parent_set', 'P', 'PRESS', ctrl=True)
-kmi = km.keymap_items.new('node.parent_clear', 'P', 'PRESS', alt=True)
kmi = km.keymap_items.new('node.join', 'J', 'PRESS', ctrl=True)
kmi = km.keymap_items.new('node.hide_toggle', 'H', 'PRESS')
kmi = km.keymap_items.new('node.mute_toggle', 'M', 'PRESS')
diff --git a/release/scripts/presets/keyconfig/maya.py b/release/scripts/presets/keyconfig/maya.py
index 47a7a7c5f5d..cdd16f26877 100644
--- a/release/scripts/presets/keyconfig/maya.py
+++ b/release/scripts/presets/keyconfig/maya.py
@@ -698,10 +698,10 @@ kmi.properties.level = 5
km = kc.keymaps.new('Knife Tool Modal Map', space_type='EMPTY', region_type='WINDOW', modal=True)
kmi = km.keymap_items.new_modal('CANCEL', 'ESC', 'ANY', any=True)
+kmi = km.keymap_items.new_modal('ADD_CUT', 'LEFTMOUSE', 'ANY')
kmi = km.keymap_items.new_modal('PANNING', 'LEFTMOUSE', 'ANY', alt=True)
kmi = km.keymap_items.new_modal('PANNING', 'MIDDLEMOUSE', 'ANY', alt=True)
kmi = km.keymap_items.new_modal('PANNING', 'RIGHTMOUSE', 'ANY', alt=True)
-kmi = km.keymap_items.new_modal('ADD_CUT', 'LEFTMOUSE', 'PRESS', any=True)
kmi = km.keymap_items.new_modal('CANCEL', 'RIGHTMOUSE', 'ANY')
kmi = km.keymap_items.new_modal('CONFIRM', 'RET', 'PRESS', any=True)
kmi = km.keymap_items.new_modal('CONFIRM', 'NUMPAD_ENTER', 'PRESS', any=True)
@@ -1137,8 +1137,6 @@ kmi = km.keymap_items.new('anim.channels_move', 'PAGE_UP', 'PRESS', shift=True)
kmi.properties.direction = 'TOP'
kmi = km.keymap_items.new('anim.channels_move', 'PAGE_DOWN', 'PRESS', shift=True)
kmi.properties.direction = 'BOTTOM'
-kmi = km.keymap_items.new('anim.channels_visibility_set', 'V', 'PRESS')
-kmi = km.keymap_items.new('anim.channels_visibility_toggle', 'V', 'PRESS', shift=True)
# Map UV Editor
km = kc.keymaps.new('UV Editor', space_type='EMPTY', region_type='WINDOW', modal=False)
@@ -1499,11 +1497,9 @@ kmi = km.keymap_items.new('node.group_edit', 'TAB', 'PRESS')
kmi = km.keymap_items.new('node.read_renderlayers', 'R', 'PRESS', ctrl=True)
kmi = km.keymap_items.new('node.read_fullsamplelayers', 'R', 'PRESS', shift=True)
kmi = km.keymap_items.new('node.render_changed', 'Z', 'PRESS')
-kmi = km.keymap_items.new('transform.translate', 'W', 'PRESS')
-kmi = km.keymap_items.new('transform.translate', 'EVT_TWEAK_A', 'ANY')
-kmi.properties.release_confirm = True
-kmi = km.keymap_items.new('transform.translate', 'EVT_TWEAK_S', 'ANY')
-kmi.properties.release_confirm = True
+kmi = km.keymap_items.new('node.translate_attach', 'W', 'PRESS')
+kmi = km.keymap_items.new('node.translate_attach', 'EVT_TWEAK_A', 'ANY')
+kmi = km.keymap_items.new('node.translate_attach', 'EVT_TWEAK_S', 'ANY')
kmi = km.keymap_items.new('transform.rotate', 'E', 'PRESS')
kmi = km.keymap_items.new('transform.resize', 'R', 'PRESS')
kmi = km.keymap_items.new('node.move_detach_links', 'D', 'PRESS', alt=True)
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py
index 65f7bde1809..4047505652f 100644
--- a/release/scripts/startup/bl_operators/__init__.py
+++ b/release/scripts/startup/bl_operators/__init__.py
@@ -54,7 +54,7 @@ if bpy.app.build_options.freestyle:
_modules.append("freestyle")
__import__(name=__name__, fromlist=_modules)
_namespace = globals()
-_modules_loaded = {name: _namespace[name] for name in _modules if name != 'bpy'}
+_modules_loaded = {name: _namespace[name] for name in _modules if name != "bpy"}
del _namespace
diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py
index dfb734e9b5b..82014c87be9 100644
--- a/release/scripts/startup/bl_operators/add_mesh_torus.py
+++ b/release/scripts/startup/bl_operators/add_mesh_torus.py
@@ -153,40 +153,40 @@ class AddTorus(Operator, object_utils.AddObjectHelper):
col = layout.column(align=True)
col.label(text="Location")
- col.prop(self, 'location', text="")
+ col.prop(self, "location", text="")
col = layout.column(align=True)
col.label(text="Rotation")
- col.prop(self, 'rotation', text="")
+ col.prop(self, "rotation", text="")
col = layout.column(align=True)
col.label(text="Major Segments")
- col.prop(self, 'major_segments', text="")
+ col.prop(self, "major_segments", text="")
col = layout.column(align=True)
col.label(text="Minor Segments")
- col.prop(self, 'minor_segments', text="")
+ col.prop(self, "minor_segments", text="")
col = layout.column(align=True)
col.label(text="Torus Dimensions")
- col.row().prop(self, 'mode', expand=True)
+ col.row().prop(self, "mode", expand=True)
if self.mode == 'MAJOR_MINOR':
col = layout.column(align=True)
col.label(text="Major Radius")
- col.prop(self, 'major_radius', text="")
+ col.prop(self, "major_radius", text="")
col = layout.column(align=True)
col.label(text="Minor Radius")
- col.prop(self, 'minor_radius', text="")
+ col.prop(self, "minor_radius", text="")
else:
col = layout.column(align=True)
col.label(text="Exterior Radius")
- col.prop(self, 'abso_major_rad', text="")
+ col.prop(self, "abso_major_rad", text="")
col = layout.column(align=True)
col.label(text="Interior Radius")
- col.prop(self, 'abso_minor_rad', text="")
+ col.prop(self, "abso_minor_rad", text="")
def invoke(self, context, event):
object_utils.object_add_grid_scale_apply_operator(self, context)
diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py
index 1b3e719b2bd..a1b10976fe0 100644
--- a/release/scripts/startup/bl_operators/anim.py
+++ b/release/scripts/startup/bl_operators/anim.py
@@ -29,6 +29,7 @@ import bpy
from bpy.types import Operator
from bpy.props import (
IntProperty,
+ FloatProperty,
BoolProperty,
EnumProperty,
StringProperty,
@@ -210,6 +211,19 @@ class BakeAction(Operator):
description="Bake animation onto the object then clear parents (objects only)",
default=False,
)
+ use_current_action = BoolProperty(
+ name="Overwrite Current Action",
+ description="Bake animation into current action, instead of creating a new one "
+ "(useful for baking only part of bones in an armature)",
+ default=False,
+ )
+ clean_threshold = FloatProperty(
+ name="Clean Threshold",
+ description="Allowed error when simplifying baked curves (set to zero to disable)",
+ default=0.1,
+ min=0.0,
+ max=1.0,
+ )
bake_types = EnumProperty(
name="Bake Data",
description="Which data's transformations to bake",
@@ -221,9 +235,14 @@ class BakeAction(Operator):
)
def execute(self, context):
-
from bpy_extras import anim_utils
+ action = None
+ if self.use_current_action:
+ obj = context.object
+ if obj.animation_data:
+ action = obj.animation_data.action
+
action = anim_utils.bake_action(self.frame_start,
self.frame_end,
frame_step=self.step,
@@ -234,6 +253,8 @@ class BakeAction(Operator):
do_constraint_clear=self.clear_constraints,
do_parents_clear=self.clear_parents,
do_clean=True,
+ clean_threshold=self.clean_threshold,
+ action=action,
)
if action is None:
diff --git a/release/scripts/startup/bl_operators/clip.py b/release/scripts/startup/bl_operators/clip.py
index 7e4e0ea9246..0c77ea2ab7e 100644
--- a/release/scripts/startup/bl_operators/clip.py
+++ b/release/scripts/startup/bl_operators/clip.py
@@ -225,7 +225,8 @@ class CLIP_OT_track_to_empty(Operator):
bl_label = "Link Empty to Track"
bl_options = {'UNDO', 'REGISTER'}
- def _link_track(self, context, clip, tracking_object, track):
+ @staticmethod
+ def _link_track(context, clip, tracking_object, track):
sc = context.space_data
constraint = None
ob = None
@@ -331,7 +332,8 @@ class CLIP_OT_delete_proxy(Operator):
return wm.invoke_confirm(self, event)
- def _rmproxy(self, abspath):
+ @staticmethod
+ def _rmproxy(abspath):
import shutil
if not os.path.exists(abspath):
@@ -552,8 +554,8 @@ class CLIP_OT_setup_tracking_scene(Operator):
world.light_settings.sample_method = 'ADAPTIVE_QMC'
world.light_settings.samples = 7
world.light_settings.threshold = 0.005
- if hasattr(scene, 'cycles'):
- world.light_settings.ao_factor = 0.05
+ if hasattr(scene, "cycles"):
+ world.light_settings.ao_factor = 0.05
@staticmethod
def _findOrCreateCamera(context):
@@ -841,7 +843,7 @@ class CLIP_OT_setup_tracking_scene(Operator):
self._offsetNodes(tree)
scene.render.alpha_mode = 'TRANSPARENT'
- if hasattr(scene, 'cycles'):
+ if hasattr(scene, "cycles"):
scene.cycles.film_transparent = True
@staticmethod
diff --git a/release/scripts/startup/bl_operators/image.py b/release/scripts/startup/bl_operators/image.py
index 1653459bd71..f00f5d97c5e 100644
--- a/release/scripts/startup/bl_operators/image.py
+++ b/release/scripts/startup/bl_operators/image.py
@@ -33,7 +33,8 @@ class EditExternally(Operator):
subtype='FILE_PATH',
)
- def _editor_guess(self, context):
+ @staticmethod
+ def _editor_guess(context):
import sys
image_editor = context.user_preferences.filepaths.image_editor
diff --git a/release/scripts/startup/bl_operators/mask.py b/release/scripts/startup/bl_operators/mask.py
index 60208d27338..aa984659430 100644
--- a/release/scripts/startup/bl_operators/mask.py
+++ b/release/scripts/startup/bl_operators/mask.py
@@ -18,7 +18,6 @@
# <pep8-80 compliant>
-import bpy
from bpy.types import Menu
diff --git a/release/scripts/startup/bl_operators/mesh.py b/release/scripts/startup/bl_operators/mesh.py
index f86c31cd9cc..ea504d48448 100644
--- a/release/scripts/startup/bl_operators/mesh.py
+++ b/release/scripts/startup/bl_operators/mesh.py
@@ -75,7 +75,6 @@ class MeshMirrorUV(Operator):
double_warn += co in mirror_lt
mirror_lt[co] = i
- #for i, v in enumerate(mesh.vertices):
vmap = {}
for mirror_a, mirror_b in ((mirror_gt, mirror_lt),
(mirror_lt, mirror_gt)):
diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py
index e3ceeca8abe..b89890a223c 100644
--- a/release/scripts/startup/bl_operators/object.py
+++ b/release/scripts/startup/bl_operators/object.py
@@ -579,7 +579,8 @@ class MakeDupliFace(Operator):
bl_label = "Make Dupli-Face"
bl_options = {'REGISTER', 'UNDO'}
- def _main(self, context):
+ @staticmethod
+ def _main(context):
from mathutils import Vector
SCALE_FAC = 0.01
@@ -643,6 +644,9 @@ class MakeDupliFace(Operator):
ob_new.use_dupli_faces_scale = True
ob_new.dupli_faces_scale = 1.0 / SCALE_FAC
+ ob_inst.select = True
+ ob_new.select = True
+
def execute(self, context):
self._main(context)
return {'FINISHED'}
@@ -924,7 +928,7 @@ class LodGenerate(Operator):
lod.location.y = ob.location.y + 3.0 * i
if i == 1:
- modifier = lod.modifiers.new("lod_decimate", "DECIMATE")
+ modifier = lod.modifiers.new("lod_decimate", 'DECIMATE')
else:
modifier = lod.modifiers[-1]
diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py
index e843209da3c..3c84e5dc553 100644
--- a/release/scripts/startup/bl_operators/object_align.py
+++ b/release/scripts/startup/bl_operators/object_align.py
@@ -70,7 +70,8 @@ def GlobalBB_HQ(obj):
# Initialize the variables with the last vertex
- verts = obj.data.vertices
+ me = obj.to_mesh(scene=bpy.context.scene, apply_modifiers=True, settings='PREVIEW')
+ verts = me.vertices
val = matrix_world * verts[-1].co
@@ -111,6 +112,8 @@ def GlobalBB_HQ(obj):
if val > up:
up = val
+ bpy.data.meshes.remove(me)
+
return Vector((left, front, up)), Vector((right, back, down))
@@ -338,7 +341,10 @@ def align_objects(context,
return True
-from bpy.props import EnumProperty, BoolProperty
+from bpy.props import (
+ EnumProperty,
+ BoolProperty
+ )
class AlignObjects(Operator):
diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py
index 24e471ecfba..414855c7e35 100644
--- a/release/scripts/startup/bl_operators/object_quick_effects.py
+++ b/release/scripts/startup/bl_operators/object_quick_effects.py
@@ -75,7 +75,7 @@ class QuickFur(Operator):
def execute(self, context):
fake_context = context.copy()
mesh_objects = [obj for obj in context.selected_objects
- if obj.type == 'MESH']
+ if obj.type == 'MESH' and obj.mode == 'OBJECT']
if not mesh_objects:
self.report({'ERROR'}, "Select at least one mesh object")
diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py
index 7195b7819d1..ffaf1b7817b 100644
--- a/release/scripts/startup/bl_operators/presets.py
+++ b/release/scripts/startup/bl_operators/presets.py
@@ -45,12 +45,51 @@ class AddPresetBase:
options={'HIDDEN', 'SKIP_SAVE'},
)
+ # needed for mix-ins
+ order = [
+ "name",
+ "remove_active",
+ ]
+
@staticmethod
def as_filename(name): # could reuse for other presets
for char in " !@#$%^&*(){}:\";'[]<>,.\\/?":
name = name.replace(char, '_')
return name.lower().strip()
+ def write_preset_py(self, file_preset):
+ def rna_recursive_attr_expand(value, rna_path_step, level):
+ if isinstance(value, bpy.types.PropertyGroup):
+ for sub_value_attr in value.bl_rna.properties.keys():
+ if sub_value_attr == "rna_type":
+ continue
+ sub_value = getattr(value, sub_value_attr)
+ rna_recursive_attr_expand(sub_value, "%s.%s" % (rna_path_step, sub_value_attr), level)
+ elif type(value).__name__ == "bpy_prop_collection_idprop": # could use nicer method
+ file_preset.write("%s.clear()\n" % rna_path_step)
+ for sub_value in value:
+ file_preset.write("item_sub_%d = %s.add()\n" % (level, rna_path_step))
+ rna_recursive_attr_expand(sub_value, "item_sub_%d" % level, level + 1)
+ else:
+ # convert thin wrapped sequences
+ # to simple lists to repr()
+ try:
+ value = value[:]
+ except:
+ pass
+
+ file_preset.write("%s = %r\n" % (rna_path_step, value))
+
+ if hasattr(self, "preset_defines"):
+ for rna_path in self.preset_defines:
+ exec(rna_path)
+ file_preset.write("%s\n" % rna_path)
+ file_preset.write("\n")
+
+ for rna_path in self.preset_values:
+ value = eval(rna_path)
+ rna_recursive_attr_expand(value, rna_path, 1)
+
def execute(self, context):
import os
@@ -95,41 +134,10 @@ class AddPresetBase:
filepath,
preset_menu_class.preset_xml_map)
else:
-
- def rna_recursive_attr_expand(value, rna_path_step, level):
- if isinstance(value, bpy.types.PropertyGroup):
- for sub_value_attr in value.bl_rna.properties.keys():
- if sub_value_attr == "rna_type":
- continue
- sub_value = getattr(value, sub_value_attr)
- rna_recursive_attr_expand(sub_value, "%s.%s" % (rna_path_step, sub_value_attr), level)
- elif type(value).__name__ == "bpy_prop_collection_idprop": # could use nicer method
- file_preset.write("%s.clear()\n" % rna_path_step)
- for sub_value in value:
- file_preset.write("item_sub_%d = %s.add()\n" % (level, rna_path_step))
- rna_recursive_attr_expand(sub_value, "item_sub_%d" % level, level + 1)
- else:
- # convert thin wrapped sequences
- # to simple lists to repr()
- try:
- value = value[:]
- except:
- pass
-
- file_preset.write("%s = %r\n" % (rna_path_step, value))
-
file_preset = open(filepath, 'w')
file_preset.write("import bpy\n")
- if hasattr(self, "preset_defines"):
- for rna_path in self.preset_defines:
- exec(rna_path)
- file_preset.write("%s\n" % rna_path)
- file_preset.write("\n")
-
- for rna_path in self.preset_values:
- value = eval(rna_path)
- rna_recursive_attr_expand(value, rna_path, 1)
+ self.write_preset_py(file_preset)
file_preset.close()
@@ -395,6 +403,93 @@ class AddPresetHairDynamics(AddPresetBase, Operator):
]
+class AddPresetCacheLibraryHairSimulation(AddPresetBase, Operator):
+ """Add or remove a Hair Simulation Preset"""
+ bl_idname = "cachelibrary.hair_simulation_preset_add"
+ bl_label = "Add Hair Simulation Preset"
+ preset_menu = "CACHELIBRARY_MT_hair_simulation_presets"
+
+ # XXX cache_modifier should be stored in the context, but using a confirm popup
+ # for the operator causes this to get lost
+ modifier_name = StringProperty(name="Modifier Name")
+
+ '''
+ preset_defines = [
+ "cachelib = bpy.context.cache_library",
+ "md = bpy.context.cache_modifier",
+ ]
+ '''
+
+ @property
+ def preset_defines(self):
+ return [
+ "cachelib = bpy.context.object.cache_library",
+ "md = cachelib.modifiers[%r]" % self.modifier_name,
+ "params = md.parameters",
+ ]
+
+ preset_subdir = "cachelibrary_hair_simulation"
+
+ preset_values = [
+ "params.substeps",
+ "params.timescale",
+ "params.mass",
+ "params.drag",
+ "params.stretch_stiffness",
+ "params.stretch_damping",
+ "params.bend_stiffness",
+ "params.bend_damping",
+ "params.use_bend_stiffness_curve",
+ "params.goal_stiffness",
+ "params.goal_damping",
+ "params.use_goal_stiffness_curve",
+ "params.use_goal_deflect",
+ ]
+
+ def write_curve_map(self, file_preset, cuma, prop):
+ if cuma is None:
+ return
+
+ file_preset.write("from mathutils import *\n")
+
+ file_preset.write("cuma = %s\n" % prop)
+ file_preset.write("if cuma:\n")
+
+ file_preset.write(" cuma.black_level = %r\n" % cuma.black_level)
+ file_preset.write(" cuma.white_level = %r\n" % cuma.white_level)
+
+ file_preset.write(" cuma.use_clip = %r\n" % cuma.use_clip)
+ if cuma.use_clip:
+ file_preset.write(" cuma.clip_min_x = %r\n" % cuma.clip_min_x)
+ file_preset.write(" cuma.clip_max_x = %r\n" % cuma.clip_max_x)
+ file_preset.write(" cuma.clip_min_y = %r\n" % cuma.clip_min_y)
+ file_preset.write(" cuma.clip_max_y = %r\n" % cuma.clip_max_y)
+
+ for i, cu in enumerate(cuma.curves):
+ file_preset.write(" cu = cuma.curves[%d]\n" % i)
+ file_preset.write(" cu.extend = %r\n" % cu.extend)
+ file_preset.write(" for p in range(max(len(cu.points) - %d, 0)):\n" % len(cu.points))
+ file_preset.write(" cu.points.remove(cu.points[0])\n")
+ file_preset.write(" for i in range(max(%d - len(cu.points), 0)):\n" % len(cu.points))
+ file_preset.write(" cu.points.new(0, 0)\n")
+ for j, p in enumerate(cu.points):
+ file_preset.write(" cu.points[%d].handle_type = %r\n" % (j, p.handle_type))
+ file_preset.write(" cu.points[%d].location = %r\n" % (j, p.location))
+ file_preset.write(" cu.points[%d].select = %r\n" % (j, p.select))
+
+ file_preset.write(" cuma.update()\n")
+
+ def write_preset_py(self, file_preset):
+ AddPresetBase.write_preset_py(self, file_preset)
+
+ cachelib = bpy.context.object.cache_library
+ md = cachelib.modifiers[self.modifier_name]
+ params = md.parameters
+
+ self.write_curve_map(file_preset, params.bend_stiffness_curve, "params.bend_stiffness_curve")
+ self.write_curve_map(file_preset, params.goal_stiffness_curve, "params.goal_stiffness_curve")
+
+
class AddPresetSunSky(AddPresetBase, Operator):
"""Add or remove a Sky & Atmosphere Preset"""
bl_idname = "lamp.sunsky_preset_add"
diff --git a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py
index 3a7a9b99cde..a5565699364 100644
--- a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py
+++ b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py
@@ -107,11 +107,20 @@ class PlayRenderedAnim(Operator):
del file_a, file_b, frame_tmp
file = bpy.path.abspath(file) # expand '//'
else:
+ path_valid = True
# works for movies and images
- file = rd.frame_path(frame=scene.frame_start)
+ file = rd.frame_path(frame=scene.frame_start, preview=scene.use_preview_range)
file = bpy.path.abspath(file) # expand '//'
if not os.path.exists(file):
self.report({'WARNING'}, "File %r not found" % file)
+ path_valid = False
+
+ #one last try for full range if we used preview range
+ if scene.use_preview_range and not path_valid:
+ file = rd.frame_path(frame=scene.frame_start, preview=False)
+ file = bpy.path.abspath(file) # expand '//'
+ if not os.path.exists(file):
+ self.report({'WARNING'}, "File %r not found" % file)
cmd = [player_path]
# extra options, fps controls etc.
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index a48415caa9b..d923c1869c9 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -143,6 +143,7 @@ class BRUSH_OT_active_index_set(Operator):
"vertex_paint": "use_paint_vertex",
"weight_paint": "use_paint_weight",
"image_paint": "use_paint_image",
+ "hair_edit": "use_hair_edit",
}
def execute(self, context):
@@ -719,7 +720,7 @@ class WM_OT_context_modal_mouse(Operator):
"""Adjust arbitrary values with mouse input"""
bl_idname = "wm.context_modal_mouse"
bl_label = "Context Modal Mouse"
- bl_options = {'GRAB_POINTER', 'BLOCKING', 'UNDO', 'INTERNAL'}
+ bl_options = {'GRAB_CURSOR', 'BLOCKING', 'UNDO', 'INTERNAL'}
data_path_iter = data_path_iter
data_path_item = data_path_item
@@ -974,10 +975,12 @@ class WM_OT_doc_view_manual(Operator):
url = self._lookup_rna_url(rna_id)
if url is None:
- self.report({'WARNING'}, "No reference available %r, "
- "Update info in 'rna_wiki_reference.py' "
- " or callback to bpy.utils.manual_map()" %
- self.doc_id)
+ self.report(
+ {'WARNING'},
+ "No reference available %r, "
+ "Update info in 'rna_manual_reference.py' "
+ "or callback to bpy.utils.manual_map()" %
+ self.doc_id)
return {'CANCELLED'}
else:
import webbrowser
@@ -1296,9 +1299,13 @@ class WM_OT_properties_remove(Operator):
property = rna_property
def execute(self, context):
+ from rna_prop_ui import rna_idprop_ui_prop_clear
data_path = self.data_path
item = eval("context.%s" % data_path)
- del item[self.property]
+ prop = self.property
+ del item[prop]
+ rna_idprop_ui_prop_clear(item, prop)
+
return {'FINISHED'}
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index 51117f68558..c110b429aad 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -86,7 +86,7 @@ if bpy.app.build_options.freestyle:
_modules.append("properties_freestyle")
__import__(name=__name__, fromlist=_modules)
_namespace = globals()
-_modules_loaded = {name: _namespace[name] for name in _modules if name != 'bpy'}
+_modules_loaded = {name: _namespace[name] for name in _modules if name != "bpy"}
del _namespace
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index 9aa67223fc4..b37feb82461 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -38,7 +38,8 @@ class ConstraintButtonsPanel:
if con.type not in {'RIGID_BODY_JOINT', 'NULL'}:
box.prop(con, "influence")
- def space_template(self, layout, con, target=True, owner=True):
+ @staticmethod
+ def space_template(layout, con, target=True, owner=True):
if target or owner:
split = layout.split(percentage=0.2)
@@ -55,7 +56,8 @@ class ConstraintButtonsPanel:
if owner:
row.prop(con, "owner_space", text="")
- def target_template(self, layout, con, subtargets=True):
+ @staticmethod
+ def target_template(layout, con, subtargets=True):
layout.prop(con, "target") # XXX limiting settings for only 'curves' or some type of object
if con.target and subtargets:
@@ -69,6 +71,7 @@ class ConstraintButtonsPanel:
elif con.target.type in {'MESH', 'LATTICE'}:
layout.prop_search(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
+ @staticmethod
def ik_template(self, layout, con):
# only used for iTaSC
layout.prop(con, "pole_target")
@@ -894,7 +897,7 @@ class OBJECT_PT_constraints(ConstraintButtonsPanel, Panel):
obj = context.object
- if obj.type == 'ARMATURE' and obj.mode in {'POSE'}:
+ if obj.type == 'ARMATURE' and obj.mode == 'POSE':
box = layout.box()
box.alert = True # XXX: this should apply to the box background
box.label(icon='INFO', text="Constraints for active bone do not live here")
diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py
index c3ed34d7e56..24a67a22c1f 100644
--- a/release/scripts/startup/bl_ui/properties_data_camera.py
+++ b/release/scripts/startup/bl_ui/properties_data_camera.py
@@ -135,6 +135,35 @@ class DATA_PT_lens(CameraButtonsPanel, Panel):
col.prop(cam, "clip_end", text="End")
+class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel):
+ bl_label = "Stereoscopy"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ render = context.scene.render
+ return (super().poll(context) and render.use_multiview and
+ render.views_format == 'STEREO_3D')
+
+ def draw(self, context):
+ layout = self.layout
+ # render = context.scene.render
+ st = context.camera.stereo
+
+ col = layout.column()
+ col.row().prop(st, "convergence_mode", expand=True)
+
+ if st.convergence_mode == 'PARALLEL':
+ col.prop(st, "viewport_convergence")
+ else:
+ col.prop(st, "convergence_distance")
+
+ col.prop(st, "interocular_distance")
+
+ col.label(text="Pivot:")
+ col.row().prop(st, "pivot", expand=True)
+
+
class DATA_PT_camera(CameraButtonsPanel, Panel):
bl_label = "Camera"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
@@ -184,35 +213,19 @@ class DATA_PT_camera_dof(CameraButtonsPanel, Panel):
col = split.column()
col.label(text="Focus:")
col.prop(cam, "dof_object", text="")
-
- col = split.column()
- col.prop(dof_options, "fstop")
sub = col.column()
- sub.active = cam.dof_object is None
+ sub.active = (cam.dof_object is None)
sub.prop(cam, "dof_distance", text="Distance")
-
-class DATA_PT_camera_gpu_dof(Panel):
- bl_label = "GPU Depth of Field"
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "data"
-
- def draw(self, context):
- layout = self.layout
-
- cam = context.camera
-
- dof_options = cam.gpu_dof
- col = layout.column(align=True)
- col.label("Focus object or distance is set in Depth Of Field Panel")
- col.prop(dof_options, "dof_fstop")
- col.prop(dof_options, "dof_focal_length")
- col.prop(dof_options, "dof_sensor")
-
- @classmethod
- def poll(cls, context):
- return context.camera
+ hq_support = dof_options.is_hq_supported
+ col = split.column(align=True)
+ col.label("Viewport:")
+ sub = col.column()
+ sub.active = hq_support
+ sub.prop(dof_options, "use_high_quality")
+ col.prop(dof_options, "fstop")
+ if dof_options.use_high_quality and hq_support:
+ col.prop(dof_options, "blades")
class DATA_PT_camera_display(CameraButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py
index 9277bbe20f9..eb8ffa1fb60 100644
--- a/release/scripts/startup/bl_ui/properties_data_curve.py
+++ b/release/scripts/startup/bl_ui/properties_data_curve.py
@@ -321,7 +321,7 @@ class DATA_PT_font(CurveButtonsPanelText, Panel):
row.label(text="Bold & Italic")
row.template_ID(text, "font_bold_italic", open="font.open", unlink="font.unlink")
- #layout.prop(text, "font")
+ # layout.prop(text, "font")
split = layout.split()
diff --git a/release/scripts/startup/bl_ui/properties_data_lamp.py b/release/scripts/startup/bl_ui/properties_data_lamp.py
index 6fef30fa3e6..0121ad46c86 100644
--- a/release/scripts/startup/bl_ui/properties_data_lamp.py
+++ b/release/scripts/startup/bl_ui/properties_data_lamp.py
@@ -355,6 +355,7 @@ class DATA_PT_spot(DataButtonsPanel, Panel):
col = split.column()
+ col.active = (lamp.shadow_method != 'BUFFER_SHADOW' or lamp.shadow_buffer_type != 'DEEP')
col.prop(lamp, "use_halo")
sub = col.column(align=True)
sub.active = lamp.use_halo
diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index b2d3b1ff647..6004c294a23 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -29,8 +29,8 @@ class MESH_MT_vertex_group_specials(Menu):
def draw(self, context):
layout = self.layout
- layout.operator("object.vertex_group_sort", icon='SORTALPHA', text="Sort by Name").sort_type = "NAME"
- layout.operator("object.vertex_group_sort", icon='ARMATURE_DATA', text="Sort by Bone Hierarchy").sort_type = "BONE_HIERARCHY"
+ layout.operator("object.vertex_group_sort", icon='SORTALPHA', text="Sort by Name").sort_type = 'NAME'
+ layout.operator("object.vertex_group_sort", icon='ARMATURE_DATA', text="Sort by Bone Hierarchy").sort_type = 'BONE_HIERARCHY'
layout.operator("object.vertex_group_copy", icon='COPY_ID')
layout.operator("object.vertex_group_copy_to_linked", icon='LINK_AREA')
layout.operator("object.vertex_group_copy_to_selected", icon='LINK_AREA')
@@ -70,7 +70,7 @@ class MESH_UL_vgroups(UIList):
layout.prop(vgroup, "name", text="", emboss=False, icon_value=icon)
icon = 'LOCKED' if vgroup.lock_weight else 'UNLOCKED'
layout.prop(vgroup, "lock_weight", text="", icon=icon, emboss=False)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -105,7 +105,7 @@ class MESH_UL_shape_keys(UIList):
else:
row.label(text="")
row.prop(key_block, "mute", text="", emboss=False)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -117,7 +117,7 @@ class MESH_UL_uvmaps_vcols(UIList):
layout.prop(item, "name", text="", emboss=False, icon_value=icon)
icon = 'RESTRICT_RENDER_OFF' if item.active_render else 'RESTRICT_RENDER_ON'
layout.prop(item, "active_render", text="", icon=icon, emboss=False)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -422,8 +422,8 @@ class DATA_PT_customdata(MeshButtonsPanel, Panel):
me = context.mesh
col = layout.column()
- col.operator("mesh.customdata_clear_mask", icon='X')
- col.operator("mesh.customdata_clear_skin", icon='X')
+ col.operator("mesh.customdata_mask_clear", icon='X')
+ col.operator("mesh.customdata_skin_clear", icon='X')
if me.has_custom_normals:
col.operator("mesh.customdata_custom_splitnormals_clear", icon='X')
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index 9c9c42b4045..e692a2fdf13 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -40,12 +40,10 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
layout.operator_menu_enum("object.modifier_add", "type")
for md in ob.modifiers:
- layout.subblock_begin(md.name)
box = layout.template_modifier(md)
if box:
# match enum type to our functions, avoids a lookup table.
getattr(self, md.type)(box, ob, md)
- layout.subblock_end()
# the mt.type enum is (ab)used for a lookup on function names
# ...to avoid lengthy if statements
@@ -265,24 +263,37 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
row.prop(md, "decimate_type", expand=True)
if decimate_type == 'COLLAPSE':
+ has_vgroup = bool(md.vertex_group)
layout.prop(md, "ratio")
split = layout.split()
- row = split.row(align=True)
+
+ col = split.column()
+ row = col.row(align=True)
row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
row.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
- split.prop(md, "use_collapse_triangulate")
+ layout_info = col
+
+ col = split.column()
+ row = col.row()
+ row.active = has_vgroup
+ row.prop(md, "vertex_group_factor")
+
+ col.prop(md, "use_collapse_triangulate")
+
elif decimate_type == 'UNSUBDIV':
layout.prop(md, "iterations")
+ layout_info = layout
else: # decimate_type == 'DISSOLVE':
layout.prop(md, "angle_limit")
layout.prop(md, "use_dissolve_boundaries")
layout.label("Delimit:")
row = layout.row()
row.prop(md, "delimit")
+ layout_info = layout
- layout.label(text=iface_("Face Count: %d") % md.face_count, translate=False)
+ layout_info.label(text=iface_("Faces: %d") % md.face_count, translate=False)
def DISPLACE(self, layout, ob, md):
has_texture = (md.texture is not None)
@@ -684,8 +695,12 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col.prop(md, "use_preserve_shape")
col = split.column()
- col.prop(md, "position", slider=True)
- col.prop(md, "random_position", text="Random", slider=True)
+ col2 = col.column(align=True)
+ col2.prop(md, "position", slider=True)
+ col2.prop(md, "random_position", text="Random", slider=True)
+ col2 = col.column(align=True)
+ col2.prop(md, "rotation", slider=True)
+ col2.prop(md, "random_rotation", text="Random", slider=True)
col = layout.column(align=True)
col.prop(md, "index_layer_name", text="Index Layer")
@@ -1146,13 +1161,15 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
self.vertex_weight_mask(layout, ob, md)
def SKIN(self, layout, ob, md):
- layout.operator("object.skin_armature_create", text="Create Armature")
+ row = layout.row()
+ row.operator("object.skin_armature_create", text="Create Armature")
+ row.operator("mesh.customdata_skin_add")
layout.separator()
- col = layout.column(align=True)
- col.prop(md, "branch_smoothing")
- col.prop(md, "use_smooth_shade")
+ row = layout.row(align=True)
+ row.prop(md, "branch_smoothing")
+ row.prop(md, "use_smooth_shade")
split = layout.split()
@@ -1399,7 +1416,32 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
sub = row.row(align=True)
sub.active = has_vgroup
- sub.prop(md, "use_invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
+ sub.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
+
+ def CORRECTIVE_SMOOTH(self, layout, ob, md):
+ is_bind = md.is_bind
+
+ layout.prop(md, "factor", text="Factor")
+ layout.prop(md, "iterations")
+
+ row = layout.row()
+ row.prop(md, "smooth_type")
+
+ split = layout.split()
+
+ col = split.column()
+ col.label(text="Vertex Group:")
+ row = col.row(align=True)
+ row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
+
+ col = split.column()
+ col.prop(md, "use_only_smooth")
+ col.prop(md, "use_pin_boundary")
+
+ layout.prop(md, "rest_source")
+ if md.rest_source == 'BIND':
+ layout.operator("object.correctivesmooth_bind", text="Unbind" if is_bind else "Bind")
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/properties_freestyle.py b/release/scripts/startup/bl_ui/properties_freestyle.py
index 2d91c998007..995136b0d97 100644
--- a/release/scripts/startup/bl_ui/properties_freestyle.py
+++ b/release/scripts/startup/bl_ui/properties_freestyle.py
@@ -74,8 +74,8 @@ class RenderLayerFreestyleButtonsPanel:
rd = context.scene.render
with_freestyle = bpy.app.build_options.freestyle
- return (scene and with_freestyle and rd.use_freestyle
- and rd.layers.active and(scene.render.engine in cls.COMPAT_ENGINES))
+ return (scene and with_freestyle and rd.use_freestyle and
+ rd.layers.active and(scene.render.engine in cls.COMPAT_ENGINES))
class RenderLayerFreestyleEditorButtonsPanel(RenderLayerFreestyleButtonsPanel):
@@ -95,7 +95,7 @@ class RENDERLAYER_UL_linesets(UIList):
if self.layout_type in {'DEFAULT', 'COMPACT'}:
layout.prop(lineset, "name", text="", emboss=False, icon_value=icon)
layout.prop(lineset, "show_render", text="", index=index)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label("", icon_value=icon)
@@ -690,10 +690,11 @@ class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel,
row.prop(linestyle, "texture_spacing", text="Spacing Along Stroke")
row = layout.row()
- op = row.operator("wm.properties_context_change",
- text="Go to Linestyle Textures Properties",
- icon='TEXTURE')
- op.context = 'TEXTURE'
+ props = row.operator(
+ "wm.properties_context_change",
+ text="Go to Linestyle Textures Properties",
+ icon='TEXTURE')
+ props.context = 'TEXTURE'
elif linestyle.panel == 'MISC':
pass
diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py
index 32a8e734ab6..ceeb45ac485 100644
--- a/release/scripts/startup/bl_ui/properties_game.py
+++ b/release/scripts/startup/bl_ui/properties_game.py
@@ -100,7 +100,6 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel):
sub.prop(game, "damping", text="Translation", slider=True)
sub.prop(game, "rotation_damping", text="Rotation", slider=True)
- if physics_type == 'RIGID_BODY':
layout.separator()
split = layout.split()
@@ -111,6 +110,7 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel):
col.prop(game, "lock_location_y", text="Y")
col.prop(game, "lock_location_z", text="Z")
+ if physics_type == 'RIGID_BODY':
col = split.column()
col.label(text="Lock Rotation:")
col.prop(game, "lock_rotation_x", text="X")
@@ -213,15 +213,17 @@ class PHYSICS_PT_game_collision_bounds(PhysicsButtonsPanel, Panel):
layout = self.layout
game = context.active_object.game
- layout.active = game.use_collision_bounds
+ split = layout.split()
+ split.active = game.use_collision_bounds
- layout.prop(game, "collision_bounds_type", text="Bounds")
+ col = split.column()
+ col.prop(game, "collision_bounds_type", text="Bounds")
- row = layout.row()
+ row = col.row()
row.prop(game, "collision_margin", text="Margin", slider=True)
sub = row.row()
- sub.active = game.physics_type not in {'SOFT_BODY', 'CHARACTER'}
+ sub.active = game.physics_type not in {'SOFT_BODY', 'CHARACTER'}
sub.prop(game, "use_collision_compound", text="Compound")
layout.separator()
@@ -397,7 +399,6 @@ class RENDER_PT_game_shading(RenderButtonsPanel, Panel):
col.prop(gs, "use_glsl_lights", text="Lights")
col.prop(gs, "use_glsl_shaders", text="Shaders")
col.prop(gs, "use_glsl_shadows", text="Shadows")
- col.prop(gs, "use_glsl_color_management", text="Color Management")
col = split.column()
col.prop(gs, "use_glsl_ramps", text="Ramps")
@@ -523,6 +524,26 @@ class SCENE_PT_game_navmesh(SceneButtonsPanel, Panel):
row.prop(rd, "sample_max_error")
+class SCENE_PT_game_hysteresis(SceneButtonsPanel, Panel):
+ bl_label = "Level of Detail"
+ COMPAT_ENGINES = {'BLENDER_GAME'}
+
+ @classmethod
+ def poll(cls, context):
+ scene = context.scene
+ return (scene and scene.render.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ gs = context.scene.game_settings
+
+ row = layout.row()
+ row.prop(gs, "use_scene_hysteresis", text="Hysteresis")
+ row = layout.row()
+ row.active = gs.use_scene_hysteresis
+ row.prop(gs, "scene_hysteresis_percentage", text="")
+
+
class WorldButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
@@ -712,6 +733,8 @@ class DATA_PT_shadow_game(DataButtonsPanel, Panel):
col = split.column()
col.prop(lamp, "shadow_color", text="")
+ if lamp.type == 'SUN':
+ col.prop(lamp, "show_shadow_box")
col = split.column()
col.prop(lamp, "use_shadow_layer", text="This Layer Only")
@@ -765,6 +788,7 @@ class OBJECT_PT_levels_of_detail(ObjectButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
ob = context.object
+ gs = context.scene.game_settings
col = layout.column()
@@ -782,6 +806,13 @@ class OBJECT_PT_levels_of_detail(ObjectButtonsPanel, Panel):
row.prop(level, "use_mesh", text="")
row.prop(level, "use_material", text="")
+ row = box.row()
+ row.active = gs.use_scene_hysteresis
+ row.prop(level, "use_object_hysteresis", text="Hysteresis Override")
+ row = box.row()
+ row.active = gs.use_scene_hysteresis and level.use_object_hysteresis
+ row.prop(level, "object_hysteresis_percentage", text="")
+
row = col.row(align=True)
row.operator("object.lod_add", text="Add", icon='ZOOMIN')
row.menu("OBJECT_MT_lod_tools", text="", icon='TRIA_DOWN')
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index 5b5a7648d83..e86fc79e343 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -321,7 +321,7 @@ class GPENCIL_UL_layer(UIList):
row = layout.row(align=True)
row.prop(gpl, "lock", text="", emboss=False)
row.prop(gpl, "hide", text="", emboss=False)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -414,9 +414,7 @@ class GreasePencilDataPanel:
col = split.column(align=True)
col.prop(gpl, "show_x_ray")
-
- # if debug:
- # layout.prop(gpl, "show_points")
+ col.prop(gpl, "show_points", text="Points")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py
index cb4a0f5bb85..f4836da50bc 100644
--- a/release/scripts/startup/bl_ui/properties_mask_common.py
+++ b/release/scripts/startup/bl_ui/properties_mask_common.py
@@ -36,7 +36,7 @@ class MASK_UL_layers(UIList):
row.prop(mask, "hide", text="", emboss=False)
row.prop(mask, "hide_select", text="", emboss=False)
row.prop(mask, "hide_render", text="", emboss=False)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -190,7 +190,7 @@ class MASK_PT_point:
col.prop_search(parent, "parent", tracking,
"objects", icon='OBJECT_DATA', text="Object:")
- tracks_list = "tracks" if parent.type == 'POINT_TRACK' else 'plane_tracks'
+ tracks_list = "tracks" if parent.type == 'POINT_TRACK' else "plane_tracks"
if parent.parent in tracking.objects:
object = tracking.objects[parent.parent]
diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py
index 20143b81d14..d916007ea41 100644
--- a/release/scripts/startup/bl_ui/properties_material.py
+++ b/release/scripts/startup/bl_ui/properties_material.py
@@ -87,7 +87,7 @@ class MATERIAL_UL_matslots(UIList):
layout.label(text=iface_("Node %s") % manode.name, translate=False, icon_value=layout.icon(manode))
elif ma.use_nodes:
layout.label(text="Node <none>")
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -123,11 +123,16 @@ class MATERIAL_PT_context_material(MaterialButtonsPanel, Panel):
ob = context.object
slot = context.material_slot
space = context.space_data
+ is_sortable = (len(ob.material_slots) > 1)
if ob:
+ rows = 1
+ if is_sortable:
+ rows = 4
+
row = layout.row()
- row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=1)
+ row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=rows)
col = row.column(align=True)
col.operator("object.material_slot_add", icon='ZOOMIN', text="")
@@ -135,6 +140,12 @@ class MATERIAL_PT_context_material(MaterialButtonsPanel, Panel):
col.menu("MATERIAL_MT_specials", icon='DOWNARROW_HLT', text="")
+ if is_sortable:
+ col.separator()
+
+ col.operator("object.material_slot_move", icon='TRIA_UP', text="").direction = 'UP'
+ col.operator("object.material_slot_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
+
if ob.mode == 'EDIT':
row = layout.row(align=True)
row.operator("object.material_slot_assign", text="Assign")
@@ -867,12 +878,14 @@ class MATERIAL_PT_transp_game(MaterialButtonsPanel, Panel):
base_mat = context.material
mat = active_node_mat(base_mat)
+ layout.active = mat.use_transparency
+
if simple_material(base_mat):
row = layout.row()
- row.active = mat.use_transparency
row.prop(mat, "transparency_method", expand=True)
layout.prop(mat, "alpha")
+ layout.prop(mat, "specular_alpha", text="Specular")
class VolumeButtonsPanel:
diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py
index b6a2792acd4..cba1454086c 100644
--- a/release/scripts/startup/bl_ui/properties_object.py
+++ b/release/scripts/startup/bl_ui/properties_object.py
@@ -18,8 +18,9 @@
# <pep8 compliant>
import bpy
-from bpy.types import Panel, Menu
+from bpy.types import Panel, Menu, UIList
from rna_prop_ui import PropertyPanel
+from bl_ui.properties_physics_common import effector_weights_ui
class ObjectButtonsPanel:
@@ -261,6 +262,62 @@ class OBJECT_PT_display(ObjectButtonsPanel, Panel):
row.prop(obj, "show_wire_color", text="", toggle=True, icon='WIRE')
+# XXX temporary solution
+bpy.types.CacheLibrary.filter_string = \
+ bpy.props.StringProperty(
+ name="Filter Object Name",
+ description="Filter cache library objects by name",
+ )
+bpy.types.CacheLibrary.show_metadata = \
+ bpy.props.BoolProperty(
+ name="Show Metadata",
+ description="Show metadata for the input archive",
+ default=False,
+ )
+
+
+def cachelib_objects(cachelib, group):
+ if not cachelib or not group:
+ return []
+
+ filter_string = cachelib.filter_string.lower()
+ if filter_string:
+ return filter(lambda ob: filter_string in ob.name.lower(), group.objects)
+ else:
+ return group.objects
+
+# Yields (type, index, enabled)
+def cachelib_object_items(cachelib, ob):
+ filter_types = cachelib.data_types
+
+ def items_desc():
+ yield 'OBJECT', -1
+
+ if (ob.type == 'MESH'):
+ yield 'DERIVED_MESH', -1
+
+ for index, psys in enumerate(ob.particle_systems):
+ if psys.settings.type == 'EMITTER':
+ yield 'PARTICLES', index
+ if psys.settings.type == 'HAIR':
+ yield 'HAIR', index
+ yield 'HAIR_PATHS', index
+
+ for datatype, index in items_desc():
+ show = False
+ enable = False
+ # always show selected types
+ if datatype in filter_types:
+ show = True
+ enable = True
+ # special case: OBJECT type used as top level, show but disable
+ elif datatype == 'OBJECT':
+ show = True
+ enable = False
+
+ if show:
+ yield datatype, index, enable
+
class OBJECT_PT_duplication(ObjectButtonsPanel, Panel):
bl_label = "Duplication"
@@ -298,6 +355,470 @@ class OBJECT_PT_duplication(ObjectButtonsPanel, Panel):
layout.prop(ob, "dupli_group", text="Group")
+
+class CACHELIB_MT_shape_key_specials(Menu):
+ bl_label = "Shape Key Specials"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ #layout.operator("object.shape_key_transfer", icon='COPY_ID') # icon is not ideal
+ #layout.operator("object.join_shapes", icon='COPY_ID') # icon is not ideal
+ layout.operator("cachelibrary.shape_key_add", icon='ZOOMIN', text="New Shape From Mix").from_mix = True
+ layout.operator("cachelibrary.shape_key_remove", icon='X', text="Delete All Shapes").all = True
+ layout.operator("cachelibrary.shape_key_move", icon='TRIA_UP_BAR', text="Move To Top").type = 'TOP'
+ layout.operator("cachelibrary.shape_key_move", icon='TRIA_DOWN_BAR', text="Move To Bottom").type = 'BOTTOM'
+
+
+class CACHELIB_UL_shape_keys(UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+ # assert(isinstance(item, bpy.types.ShapeKey))
+ md = active_data
+ # key = data
+ key_block = item
+ if self.layout_type in {'DEFAULT', 'COMPACT'}:
+ split = layout.split(0.66, False)
+ split.prop(key_block, "name", text="", emboss=False, icon_value=icon)
+ row = split.row(align=True)
+ if key_block.mute:
+ row.active = False
+ if not item.id_data.use_relative:
+ row.prop(key_block, "frame", text="", emboss=False)
+ elif index > 0:
+ row.prop(key_block, "value", text="", emboss=False)
+ else:
+ row.label(text="")
+ row.prop(key_block, "mute", text="", emboss=False)
+ elif self.layout_type == 'GRID':
+ layout.alignment = 'CENTER'
+ layout.label(text="", icon_value=icon)
+
+
+class CACHELIBRARY_MT_hair_simulation_presets(Menu):
+ bl_label = "Hair Simulation Presets"
+ preset_subdir = "cachelibrary_hair_simulation"
+ preset_operator = "script.execute_preset"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ draw = Menu.draw_preset
+
+
+class CacheArchiveInfoPanel():
+ def draw_node_structure(self, context, layout, node, indent):
+ row = layout.row()
+ for i in range(indent):
+ row.label(text="", icon='BLANK1')
+
+ if not node.child_nodes:
+ row.label(text="", icon='DOT')
+ elif not node.expand:
+ row.prop(node, "expand", text="", icon='DISCLOSURE_TRI_RIGHT', icon_only=True, emboss=False)
+ else:
+ row.prop(node, "expand", text="", icon='DISCLOSURE_TRI_DOWN', icon_only=True, emboss=False)
+
+ for child in node.child_nodes:
+ self.draw_node_structure(context, layout, child, indent + 1)
+
+
+ info_columns = ['Name', 'Node', 'Samples', 'Size', 'Data', '', 'Array Size']
+
+ def draw_node_info(self, context, layout, node, column):
+ if column == 0:
+ layout.prop(node, "name", text="")
+ if column == 1:
+ layout.prop(node, "type", text="")
+ if column == 2:
+ if node.type in {'SCALAR_PROPERTY', 'ARRAY_PROPERTY'}:
+ layout.prop(node, "samples", text="")
+ else:
+ layout.label(" ")
+ if column == 3:
+ size = int(node.bytes_size)
+ layout.label(sizeof_fmt(size) if size >= 0 else "-")
+ if column == 4:
+ if node.type in {'SCALAR_PROPERTY', 'ARRAY_PROPERTY'}:
+ layout.prop(node, "datatype", text="")
+ else:
+ layout.label(" ")
+ if column == 5:
+ if node.type in {'SCALAR_PROPERTY', 'ARRAY_PROPERTY'}:
+ layout.prop(node, "datatype_extent", text="")
+ else:
+ layout.label(" ")
+ if column == 6:
+ if node.type in {'ARRAY_PROPERTY'}:
+ layout.label(node.array_size if node.array_size >= 0 else "-")
+ else:
+ layout.label(" ")
+
+ if node.expand:
+ for child in node.child_nodes:
+ self.draw_node_info(context, layout, child, column)
+
+ def draw_info(self, context, layout, info, metadata=None):
+ row = layout.row(align=True)
+ row.label("Created by: {} | {}".format(info.app_name if info.app_name else "-", info.date_written if info.date_written else "-"))
+ if info.description:
+ layout.label(info.description)
+
+ if metadata:
+ row = layout.row(align=True)
+ col_key = row.column()
+ col_value = row.column()
+ for key, value in metadata.items():
+ col_key.label(key)
+ col_value.label(str(value))
+
+ if info.root_node:
+ row = layout.row()
+
+ col = row.column()
+ col.label(" ")
+ self.draw_node_structure(context, col, info.root_node, 0)
+
+ for i, column in enumerate(self.info_columns):
+ col = row.column()
+ col.label(column)
+ self.draw_node_info(context, col, info.root_node, i)
+
+
+class OBJECT_PT_cache_library(CacheArchiveInfoPanel, ObjectButtonsPanel, Panel):
+ bl_label = "Cache"
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.object
+ return (ob and ob.dupli_type == 'GROUP' and ob.dupli_group)
+
+ def draw_cache_modifier(self, context, layout, cachelib, md):
+ layout.context_pointer_set("cache_library", cachelib)
+ layout.context_pointer_set("cache_modifier", md)
+
+ row = layout.row(align=True)
+ row.context_pointer_set("cache_modifier", md)
+ row.prop(md, "name", text="")
+ row.operator("cachelibrary.remove_modifier", icon='X', text="", emboss=False)
+
+ # match enum type to our functions, avoids a lookup table.
+ getattr(self, md.type)(context, layout, cachelib, md)
+
+ def draw_cachelib(self, context, layout, ob, cachelib, objects):
+ box = layout.box()
+ row = box.row()
+ row.label("Source:")
+ row.prop(cachelib, "source_mode", text="Source", expand=True)
+ row = box.row(align=True)
+ row.enabled = (cachelib.source_mode == 'CACHE')
+ row.prop(cachelib, "input_filepath", text="")
+ row.prop(cachelib, "show_metadata", text="", icon='QUESTION', toggle=True)
+ if cachelib.show_metadata and cachelib.archive_info:
+ self.draw_info(context, box, cachelib.archive_info, cachelib['input_metadata'])
+
+ layout.separator()
+
+ layout.prop(cachelib, "display_mode", expand=True)
+ row = layout.row()
+ split = row.split()
+ col = split.column()
+ col.label("Display:")
+ col.prop(cachelib, "display_motion", text="Motion")
+ col.prop(cachelib, "display_children", text="Children")
+
+ layout.separator()
+
+ row = layout.row(align=True)
+ row.enabled = (cachelib.display_mode == 'RESULT')
+ row.prop(cachelib, "output_filepath", text="")
+
+ box = layout.box()
+ row = box.row()
+
+ col = row.column()
+ row2 = col.row()
+ row2.alignment = 'LEFT'
+ row2.prop(cachelib, "data_types", icon_only=True, toggle=True)
+ row2.template_ID(cachelib, "filter_group")
+ col.prop(cachelib, "description")
+ col = row.column()
+ props = col.operator("cachelibrary.bake", text="Bake Preview", icon='RESTRICT_VIEW_OFF')
+ props.eval_mode = {'PREVIEW'}
+ if context.scene.use_preview_range:
+ props.start_frame = context.scene.frame_preview_start
+ props.end_frame = context.scene.frame_preview_end
+ else:
+ props.start_frame = context.scene.frame_start
+ props.end_frame = context.scene.frame_end
+ props = col.operator("cachelibrary.bake", text="Bake Render", icon='RESTRICT_RENDER_OFF')
+ props.eval_mode = {'RENDER'}
+ props.start_frame = context.scene.frame_start
+ props.end_frame = context.scene.frame_end
+
+ '''
+ row = layout.row(align=True)
+ row.label("Filter:")
+ row.prop(cachelib, "filter_string", icon='VIEWZOOM', text="")
+
+ first = True
+ for ob in objects:
+ if not any(cachelib_object_items(cachelib, ob)):
+ continue
+
+ if first:
+ layout.separator()
+ first = False
+
+ for datatype, index, enable in cachelib_object_items(cachelib, ob):
+ row = layout.row(align=True)
+ row.alignment = 'LEFT'
+ row.template_cache_library_item(cachelib, ob, datatype, index, enable)
+ '''
+
+ layout.operator_menu_enum("cachelibrary.add_modifier", "type")
+
+ for md in cachelib.modifiers:
+ box = layout.box()
+ self.draw_cache_modifier(context, box, cachelib, md)
+
+ def draw(self, context):
+ ob = context.object
+
+ layout = self.layout
+ row = layout.row(align=True)
+ row.template_ID(ob, "cache_library", new="cachelibrary.new")
+
+ if ob.cache_library:
+ cache_objects = cachelib_objects(ob.cache_library, ob.dupli_group)
+ self.draw_cachelib(context, layout, ob, ob.cache_library, cache_objects)
+
+ def HAIR_SIMULATION(self, context, layout, cachelib, md):
+ params = md.parameters
+
+ col = layout.column(align=True)
+ col.prop_search(md, "object", context.blend_data, "objects", icon='OBJECT_DATA')
+ sub = col.column()
+ if (md.object):
+ sub.prop_search(md, "hair_system", md.object, "particle_systems")
+ else:
+ sub.enabled = False
+ sub.prop(md, "hair_system")
+
+ layout = layout.column()
+ layout.active = md.hair_system is not None
+
+ row = layout.row(align=True)
+ row.menu("CACHELIBRARY_MT_hair_simulation_presets", text=bpy.types.CACHELIBRARY_MT_hair_simulation_presets.bl_label)
+ props = row.operator("cachelibrary.hair_simulation_preset_add", text="", icon='ZOOMIN')
+ props.modifier_name = md.name
+ props = row.operator("cachelibrary.hair_simulation_preset_add", text="", icon='ZOOMOUT')
+ props.modifier_name = md.name
+ props.remove_active = True
+
+ col = layout.column()
+ col.prop(params, "substeps")
+ col.prop(params, "timescale")
+ col.prop(params, "mass")
+ col.prop(params, "drag")
+
+ row = col.row(align=True)
+ row.prop(params, "stretch_stiffness")
+ row.prop(params, "stretch_damping")
+
+ row = col.row(align=True)
+ row.prop(params, "bend_stiffness")
+ row.prop(params, "bend_damping")
+ row.prop(params, "use_bend_stiffness_curve")
+ if params.use_bend_stiffness_curve:
+ sub = col.column()
+ sub.template_curve_mapping(params, "bend_stiffness_curve")
+
+ row = col.row(align=True)
+ row.prop(params, "goal_stiffness")
+ row.prop(params, "goal_damping")
+ row = col.row(align=True)
+ row.prop(params, "use_goal_stiffness_curve")
+ row.prop(params, "use_goal_deflect")
+ if params.use_goal_stiffness_curve:
+ sub = col.column()
+ sub.template_curve_mapping(params, "goal_stiffness_curve")
+
+ layout.separator()
+
+ effector_weights_ui(self, context, params.effector_weights, 'HAIR')
+
+ def FORCE_FIELD(self, context, layout, cachelib, md):
+ layout.prop_search(md, "object", context.blend_data, "objects", icon='OBJECT_DATA')
+
+ layout.prop(md, "force_type", text="")
+
+ row = layout.row(align=True)
+ row.prop(md, "strength")
+ row.prop(md, "falloff")
+
+ col = layout.column(align=True)
+ row = layout.row(align=True)
+ row.prop(md, "min_distance")
+ row.prop(md, "max_distance")
+ col.prop(md, "use_double_sided")
+
+ def HAIRCUT(self, context, layout, cachelib, md):
+ col = layout.column(align=True)
+ col.prop_search(md, "object", context.blend_data, "objects", icon='OBJECT_DATA')
+ sub = col.column()
+ if (md.object):
+ sub.prop_search(md, "hair_system", md.object, "particle_systems")
+ else:
+ sub.enabled = False
+ sub.prop(md, "hair_system")
+
+ row = layout.row()
+ row.prop_search(md, "target", context.blend_data, "objects", icon='OBJECT_DATA')
+ row.prop(md, "use_internal_target", text="Internal")
+ layout.prop(md, "cut_mode", toggle=True, expand=True)
+
+ layout = layout.column()
+ layout.active = md.hair_system is not None
+
+ def SHRINK_WRAP(self, context, layout, cachelib, md):
+ col = layout.column(align=True)
+ col.prop_search(md, "object", context.blend_data, "objects", icon='OBJECT_DATA')
+ sub = col.column()
+ if (md.object):
+ sub.prop_search(md, "hair_system", md.object, "particle_systems")
+ else:
+ sub.enabled = False
+ sub.prop(md, "hair_system")
+
+ row = layout.row()
+ row.prop_search(md, "target", context.blend_data, "objects", icon='OBJECT_DATA')
+ row.prop(md, "use_internal_target", text="Internal")
+
+ layout = layout.column()
+ layout.active = md.hair_system is not None
+
+ def STRANDS_KEY(self, context, layout, cachelib, md):
+ col = layout.column(align=True)
+ col.prop_search(md, "object", context.blend_data, "objects", icon='OBJECT_DATA')
+ sub = col.column()
+ if (md.object):
+ sub.prop_search(md, "hair_system", md.object, "particle_systems")
+ else:
+ sub.enabled = False
+ sub.prop(md, "hair_system")
+
+ key = md.shape_keys
+ kb = md.active_shape_key
+ kb_index = md.active_shape_key_index
+
+ row = layout.row()
+
+ rows = 2
+ if kb:
+ rows = 4
+ row.template_list("CACHELIB_UL_shape_keys", "", key, "key_blocks", md, "active_shape_key_index", rows=rows)
+
+ col = row.column()
+
+ sub = col.column(align=True)
+ #sub.operator("object.shape_key_add", icon='ZOOMIN', text="").from_mix = False
+ #sub.operator("object.shape_key_remove", icon='ZOOMOUT', text="").all = False
+ sub.menu("CACHELIB_MT_shape_key_specials", icon='DOWNARROW_HLT', text="")
+
+ col.prop(md, "use_motion_state")
+
+ if kb:
+ col.separator()
+
+ sub = col.column(align=True)
+ #sub.operator("object.shape_key_move", icon='TRIA_UP', text="").type = 'UP'
+ #sub.operator("object.shape_key_move", icon='TRIA_DOWN', text="").type = 'DOWN'
+
+ split = layout.split(percentage=0.4)
+ row = split.row()
+ row.prop(key, "use_relative")
+
+ row = split.row()
+ row.alignment = 'RIGHT'
+
+ sub = row.row(align=True)
+ sub.label() # XXX, for alignment only
+ subsub = sub.row(align=True)
+ subsub.prop(md, "show_only_shape_key", text="")
+
+ sub = row.row()
+ #if key.use_relative:
+ # sub.operator("object.shape_key_clear", icon='X', text="")
+ #else:
+ # sub.operator("object.shape_key_retime", icon='RECOVER_LAST', text="")
+
+ if key.use_relative:
+ if kb_index != 0:
+ row = layout.row()
+ row.prop(kb, "value")
+
+ split = layout.split()
+
+ col = split.column(align=True)
+ col.label(text="Range:")
+ col.prop(kb, "slider_min", text="Min")
+ col.prop(kb, "slider_max", text="Max")
+
+ col = split.column(align=True)
+ col.label(text="Blend:")
+ #col.prop_search(kb, "vertex_group", ob, "vertex_groups", text="")
+ col.prop_search(kb, "relative_key", key, "key_blocks", text="")
+
+ else:
+ layout.prop(kb, "interpolation")
+ row = layout.column()
+ row.prop(key, "eval_time")
+
+
+# Simple human-readable size (based on http://stackoverflow.com/a/1094933)
+def sizeof_fmt(num, suffix='B'):
+ for unit in ['','K','M','G','T','P','E','Z']:
+ if abs(num) < 1024.0:
+ return "%3.1f%s%s" % (num, unit, suffix)
+ num /= 1024.0
+ return "%.1f%s%s" % (num, 'Y', suffix)
+
+class OBJECT_PT_cache_archive_info(CacheArchiveInfoPanel, ObjectButtonsPanel, Panel):
+ bl_label = "Cache Archive Info"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.object
+ return (ob and ob.dupli_type == 'GROUP' and ob.dupli_group and ob.cache_library)
+
+ def draw(self, context):
+ ob = context.object
+ cachelib = ob.cache_library
+ info = cachelib.archive_info
+
+ layout = self.layout
+
+ row = layout.row()
+ props = row.operator("cachelibrary.archive_info", text="Input", icon='QUESTION')
+ props.filepath = cachelib.input_filepath
+ props.use_cache_info = True
+ props = row.operator("cachelibrary.archive_info", text="Output", icon='QUESTION')
+ props.filepath = cachelib.output_filepath
+ props.use_cache_info = True
+
+ if info:
+ row = layout.row()
+ row.enabled = bool(info.filepath)
+ props = layout.operator("cachelibrary.archive_info", text="Calculate Size", icon='FILE_REFRESH')
+ props.filepath = info.filepath
+ props.use_cache_info = True
+ props.calc_bytes_size = True
+
+ layout.separator()
+
+ layout.prop(info, "filepath", text="File")
+ self.draw_info(context, layout, info)
+
+
class OBJECT_PT_relations_extras(ObjectButtonsPanel, Panel):
bl_label = "Relations Extras"
bl_options = {'DEFAULT_CLOSED'}
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index b0da65063d1..d1f7c0f5e40 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -38,10 +38,10 @@ class UnifiedPaintPanel:
elif context.image_paint_object:
if (toolsettings.image_paint and toolsettings.image_paint.detect_data()):
return toolsettings.image_paint
-
- return None
elif context.particle_edit_object:
return toolsettings.particle_edit
+ elif context.hair_edit_object:
+ return toolsettings.hair_edit
return None
@@ -133,7 +133,7 @@ def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=Fal
else:
row = col.row(align=True)
panel.prop_unified_color(row, context, brush, "color", text="")
- if brush.image_tool == 'FILL':
+ if brush.image_tool == 'FILL' and not projpaint:
col.prop(brush, "fill_threshold")
else:
panel.prop_unified_color(row, context, brush, "secondary_color", text="")
@@ -216,7 +216,9 @@ def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=Fal
col = layout.column(align=True)
col.prop(brush, "use_accumulate")
- col.prop(brush, "use_alpha")
+ if projpaint:
+ col.prop(brush, "use_alpha")
+
col.prop(brush, "use_gradient")
col.separator()
diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py
index 2247092c976..c948658f433 100644
--- a/release/scripts/startup/bl_ui/properties_particle.py
+++ b/release/scripts/startup/bl_ui/properties_particle.py
@@ -123,7 +123,7 @@ class PARTICLE_UL_particle_systems(bpy.types.UIList):
layout.prop(md, "show_render", emboss=False, icon_only=True, icon='RESTRICT_RENDER_OFF' if md.show_render else 'RESTRICT_RENDER_ON')
layout.prop(md, "show_viewport", emboss=False, icon_only=True, icon='RESTRICT_VIEW_OFF' if md.show_viewport else 'RESTRICT_VIEW_ON')
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -1389,7 +1389,7 @@ class PARTICLE_PT_children(ParticleButtonsPanel, Panel):
split = layout.split()
split.active = part.kink != 'NO'
- if part.kink in {'SPIRAL'}:
+ if part.kink == 'SPIRAL':
col = split.column()
sub = col.column(align=True)
sub.prop(part, "kink_amplitude", text="Radius")
diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py
index 19533d2185f..61091f3ec21 100644
--- a/release/scripts/startup/bl_ui/properties_physics_common.py
+++ b/release/scripts/startup/bl_ui/properties_physics_common.py
@@ -191,7 +191,7 @@ def point_cache_ui(self, context, cache, enabled, cachetype):
col.operator("ptcache.bake", text="Bake").bake = True
sub = col.row()
- sub.enabled = (cache.frames_skipped or cache.is_outdated) and enabled
+ sub.enabled = (cache.is_frame_skip or cache.is_outdated) and enabled
sub.operator("ptcache.bake", text="Calculate To Frame").bake = False
sub = col.column()
diff --git a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
index 01dcf837546..269ffa6d371 100644
--- a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
+++ b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
@@ -40,7 +40,7 @@ class PHYSICS_UL_dynapaint_surfaces(UIList):
row.prop(surf, "show_preview", text="", emboss=False,
icon='RESTRICT_VIEW_OFF' if surf.show_preview else 'RESTRICT_VIEW_ON')
row.prop(surf, "is_active", text="")
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
row = layout.row(align=True)
row.label(text="", icon_value=icon)
diff --git a/release/scripts/startup/bl_ui/properties_physics_smoke.py b/release/scripts/startup/bl_ui/properties_physics_smoke.py
index 63268bc6672..624f36ea942 100644
--- a/release/scripts/startup/bl_ui/properties_physics_smoke.py
+++ b/release/scripts/startup/bl_ui/properties_physics_smoke.py
@@ -81,15 +81,21 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
layout.prop(flow, "smoke_flow_type", expand=False)
- if flow.smoke_flow_type != "OUTFLOW":
+ if flow.smoke_flow_type != 'OUTFLOW':
+ use_const_color = False
+
split = layout.split()
col = split.column()
col.label(text="Flow Source:")
col.prop(flow, "smoke_flow_source", expand=False, text="")
- if flow.smoke_flow_source == "PARTICLES":
+ if flow.smoke_flow_source == 'PARTICLES':
col.label(text="Particle System:")
col.prop_search(flow, "particle_system", ob, "particle_systems", text="")
col.prop(flow, "use_particle_size", text="Set Size")
+ col.prop(flow, "use_particle_texture_color", text="Set Color")
+ # disable const color button when using particle color
+ use_const_color = not flow.use_particle_texture_color
+
sub = col.column()
sub.active = flow.use_particle_size
sub.prop(flow, "particle_size")
@@ -103,7 +109,7 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
sub = sub.column()
sub.active = flow.use_initial_velocity
sub.prop(flow, "velocity_factor")
- if flow.smoke_flow_source == "MESH":
+ if flow.smoke_flow_source == 'MESH':
sub.prop(flow, "velocity_normal")
#sub.prop(flow, "velocity_random")
@@ -113,7 +119,9 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
if flow.smoke_flow_type in {'SMOKE', 'BOTH'}:
sub.prop(flow, "density")
sub.prop(flow, "temperature")
- sub.prop(flow, "smoke_color")
+ subsub = sub.column()
+ subsub.active = use_const_color
+ subsub.prop(flow, "smoke_color")
if flow.smoke_flow_type in {'FIRE', 'BOTH'}:
sub.prop(flow, "fuel_amount")
sub.label(text="Sampling:")
@@ -128,6 +136,25 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
col.prop(coll, "collision_type")
+class PHYSICS_PT_smoke_display(PhysicButtonsPanel, Panel):
+ bl_label = "Smoke Display"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ @classmethod
+ def poll(cls, context):
+ md = context.smoke
+ return md and (md.smoke_type == 'DOMAIN')
+
+ def draw(self, context):
+ layout = self.layout
+ domain = context.smoke.domain_settings
+
+ split = layout.split()
+
+ col = split.column(align=True)
+ col.prop(domain, "display_thickness")
+
+
class PHYSICS_PT_smoke_flow_advanced(PhysicButtonsPanel, Panel):
bl_label = "Smoke Flow Advanced"
bl_options = {'DEFAULT_CLOSED'}
@@ -135,7 +162,7 @@ class PHYSICS_PT_smoke_flow_advanced(PhysicButtonsPanel, Panel):
@classmethod
def poll(cls, context):
md = context.smoke
- return md and (md.smoke_type == 'FLOW') and (md.flow_settings.smoke_flow_source == "MESH")
+ return md and (md.smoke_type == 'FLOW') and (md.flow_settings.smoke_flow_source == 'MESH')
def draw(self, context):
layout = self.layout
@@ -151,9 +178,9 @@ class PHYSICS_PT_smoke_flow_advanced(PhysicButtonsPanel, Panel):
sub.prop(flow, "noise_texture", text="")
sub.label(text="Mapping:")
sub.prop(flow, "texture_map_type", expand=False, text="")
- if flow.texture_map_type == "UV":
+ if flow.texture_map_type == 'UV':
sub.prop_search(flow, "uv_layer", ob.data, "uv_textures", text="")
- if flow.texture_map_type == "AUTO":
+ if flow.texture_map_type == 'AUTO':
sub.prop(flow, "texture_size")
sub.prop(flow, "texture_offset")
@@ -309,6 +336,7 @@ class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel):
layout.label(text="Compression:")
layout.prop(md, "point_cache_compress_type", expand=True)
+ layout.prop(md, "point_cache_offset", text="Start Frame")
point_cache_ui(self, context, cache, (cache.is_baked is False), 'SMOKE')
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index b596fe48b49..0c68d98a8e1 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -274,7 +274,7 @@ class RENDER_PT_performance(RenderButtonsPanel, Panel):
col.prop(rd, "tile_y", text="Y")
col.separator()
- col.prop(rd, 'preview_start_resolution')
+ col.prop(rd, "preview_start_resolution")
col = split.column()
col.label(text="Memory:")
@@ -334,28 +334,25 @@ class RENDER_PT_post_processing(RenderButtonsPanel, Panel):
class RENDER_PT_stamp(RenderButtonsPanel, Panel):
- bl_label = "Stamp"
+ bl_label = "Metadata"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
- def draw_header(self, context):
- rd = context.scene.render
-
- self.layout.prop(rd, "use_stamp", text="")
-
def draw(self, context):
layout = self.layout
rd = context.scene.render
- layout.active = rd.use_stamp
+ layout.prop(rd, "use_stamp", text="Stamp Output")
+ col = layout.column()
+ col.active = rd.use_stamp
+ col.prop(rd, "stamp_font_size", text="Font Size")
- layout.prop(rd, "stamp_font_size", text="Font Size")
-
- row = layout.row()
+ row = col.row()
row.column().prop(rd, "stamp_foreground", slider=True)
row.column().prop(rd, "stamp_background", slider=True)
+ layout.label("Enabled Metadata")
split = layout.split()
col = split.column()
@@ -404,6 +401,8 @@ class RENDER_PT_output(RenderButtonsPanel, Panel):
col.prop(rd, "use_render_cache")
layout.template_image_settings(image_settings, color_management=False)
+ if rd.use_multiview:
+ layout.template_image_views(image_settings)
if file_format == 'QUICKTIME':
quicktime = rd.quicktime
diff --git a/release/scripts/startup/bl_ui/properties_render_layer.py b/release/scripts/startup/bl_ui/properties_render_layer.py
index 35032d38933..8a3e33f1936 100644
--- a/release/scripts/startup/bl_ui/properties_render_layer.py
+++ b/release/scripts/startup/bl_ui/properties_render_layer.py
@@ -40,7 +40,7 @@ class RENDERLAYER_UL_renderlayers(UIList):
if self.layout_type in {'DEFAULT', 'COMPACT'}:
layout.prop(layer, "name", text="", icon_value=icon, emboss=False)
layout.prop(layer, "use", text="", index=index)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label("", icon_value=icon)
@@ -87,7 +87,7 @@ class RENDERLAYER_PT_layer_options(RenderLayerButtonsPanel, Panel):
col = split.column()
col.prop(scene, "layers", text="Scene")
col.label(text="")
- col.prop(rl, "light_override", text="Light")
+ col.prop(rl, "light_override", text="Lights")
col.prop(rl, "material_override", text="Material")
col = split.column()
@@ -126,7 +126,8 @@ class RENDERLAYER_PT_layer_passes(RenderLayerButtonsPanel, Panel):
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
- def draw_pass_type_buttons(self, box, rl, pass_type):
+ @staticmethod
+ def draw_pass_type_buttons(box, rl, pass_type):
# property names
use_pass_type = "use_pass_" + pass_type
exclude_pass_type = "exclude_" + pass_type
@@ -167,5 +168,63 @@ class RENDERLAYER_PT_layer_passes(RenderLayerButtonsPanel, Panel):
self.draw_pass_type_buttons(col, rl, "refraction")
+class RENDERLAYER_UL_renderviews(UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+ # assert(isinstance(item, bpy.types.SceneRenderView)
+ view = item
+ if self.layout_type in {'DEFAULT', 'COMPACT'}:
+ if view.name in {'left', 'right'}:
+ layout.label(view.name, icon_value=icon + (not view.use))
+ else:
+ layout.prop(view, "name", text="", index=index, icon_value=icon, emboss=False)
+ layout.prop(view, "use", text="", index=index)
+
+ elif self.layout_type == 'GRID':
+ layout.alignment = 'CENTER'
+ layout.label("", icon_value=icon + (not view.use))
+
+
+class RENDERLAYER_PT_views(RenderLayerButtonsPanel, Panel):
+ bl_label = "Views"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ def draw_header(self, context):
+ rd = context.scene.render
+ self.layout.prop(rd, "use_multiview", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ scene = context.scene
+ rd = scene.render
+ rv = rd.views.active
+
+ layout.active = rd.use_multiview
+ basic_stereo = rd.views_format == 'STEREO_3D'
+
+ row = layout.row()
+ row.prop(rd, "views_format", expand=True)
+
+ if basic_stereo:
+ row = layout.row()
+ row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "stereo_views", rd.views, "active_index", rows=2)
+
+ row = layout.row()
+ row.label(text="File Suffix:")
+ row.prop(rv, "file_suffix", text="")
+
+ else:
+ row = layout.row()
+ row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "views", rd.views, "active_index", rows=2)
+
+ col = row.column(align=True)
+ col.operator("scene.render_view_add", icon='ZOOMIN', text="")
+ col.operator("scene.render_view_remove", icon='ZOOMOUT', text="")
+
+ row = layout.row()
+ row.label(text="Camera Suffix:")
+ row.prop(rv, "camera_suffix", text="")
+
+
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py
index facf54d358a..bbf11abe6d9 100644
--- a/release/scripts/startup/bl_ui/properties_scene.py
+++ b/release/scripts/startup/bl_ui/properties_scene.py
@@ -35,7 +35,7 @@ class SCENE_UL_keying_set_paths(UIList):
if self.layout_type in {'DEFAULT', 'COMPACT'}:
# Do not make this one editable in uiList for now...
layout.label(text=kspath.data_path, translate=False, icon_value=icon)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -86,19 +86,25 @@ class SCENE_PT_unit(SceneButtonsPanel, Panel):
class SceneKeyingSetsPanel:
- def draw_keyframing_settings(self, context, layout, ks, ksp):
- self.draw_keyframing_setting(context, layout, ks, ksp, "Needed",
- "use_insertkey_override_needed", "use_insertkey_needed",
- userpref_fallback="use_keyframe_insert_needed")
- self.draw_keyframing_setting(context, layout, ks, ksp, "Visual",
- "use_insertkey_override_visual", "use_insertkey_visual",
- userpref_fallback="use_visual_keying")
+ @staticmethod
+ def draw_keyframing_settings(context, layout, ks, ksp):
+ SceneKeyingSetsPanel._draw_keyframing_setting(
+ context, layout, ks, ksp, "Needed",
+ "use_insertkey_override_needed", "use_insertkey_needed",
+ userpref_fallback="use_keyframe_insert_needed")
- self.draw_keyframing_setting(context, layout, ks, ksp, "XYZ to RGB",
- "use_insertkey_override_xyz_to_rgb", "use_insertkey_xyz_to_rgb")
+ SceneKeyingSetsPanel._draw_keyframing_setting(
+ context, layout, ks, ksp, "Visual",
+ "use_insertkey_override_visual", "use_insertkey_visual",
+ userpref_fallback="use_visual_keying")
- def draw_keyframing_setting(self, context, layout, ks, ksp, label, toggle_prop, prop, userpref_fallback=None):
+ SceneKeyingSetsPanel._draw_keyframing_setting(
+ context, layout, ks, ksp, "XYZ to RGB",
+ "use_insertkey_override_xyz_to_rgb", "use_insertkey_xyz_to_rgb")
+
+ @staticmethod
+ def _draw_keyframing_setting(context, layout, ks, ksp, label, toggle_prop, prop, userpref_fallback=None):
if ksp:
item = ksp
@@ -392,14 +398,17 @@ class SCENE_PT_simplify(SceneButtonsPanel, Panel):
split = layout.split()
col = split.column()
+ col.label(text="Viewport:")
col.prop(rd, "simplify_subdivision", text="Subdivision")
col.prop(rd, "simplify_child_particles", text="Child Particles")
- col.prop(rd, "use_simplify_triangulate")
-
col = split.column()
+ col.label(text="Render:")
+ col.prop(rd, "simplify_subdivision_render", text="Subdivision")
+ col.prop(rd, "simplify_child_particles_render", text="Child Particles")
col.prop(rd, "simplify_shadow_samples", text="Shadow Samples")
col.prop(rd, "simplify_ao_sss", text="AO and SSS")
+ col.prop(rd, "use_simplify_triangulate")
class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py
index 11729df05e2..5a4937d2509 100644
--- a/release/scripts/startup/bl_ui/properties_texture.py
+++ b/release/scripts/startup/bl_ui/properties_texture.py
@@ -72,7 +72,7 @@ class TEXTURE_UL_texslots(UIList):
layout.label(text="", icon_value=icon)
if tex and isinstance(item, bpy.types.MaterialTextureSlot):
layout.prop(ma, "use_textures", text="", index=index)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
@@ -676,8 +676,7 @@ class TEXTURE_PT_musgrave(TextureTypePanel, Panel):
col = split.column()
if musgrave_type in {'HETERO_TERRAIN', 'RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL'}:
col.prop(tex, "offset")
- if musgrave_type in {'MULTIFRACTAL', 'RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL'}:
- col.prop(tex, "noise_intensity", text="Intensity")
+ col.prop(tex, "noise_intensity", text="Intensity")
if musgrave_type in {'RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL'}:
col.prop(tex, "gain")
@@ -1148,6 +1147,7 @@ class TEXTURE_PT_influence(TextureSlotPanel, Panel):
factor_but(col, "use_map_life", "life_factor", "Lifetime")
factor_but(col, "use_map_density", "density_factor", "Density")
factor_but(col, "use_map_size", "size_factor", "Size")
+ factor_but(col, "use_map_particle_color", "particle_color_factor", "Color")
col = split.column()
col.label(text="Physics:")
@@ -1182,7 +1182,8 @@ class TEXTURE_PT_influence(TextureSlotPanel, Panel):
layout.separator()
- if not isinstance(idblock, ParticleSettings):
+ show_blend_settings = (not isinstance(idblock, ParticleSettings)) or tex.use_map_particle_color
+ if show_blend_settings:
split = layout.split()
col = split.column()
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index a9fcdea35c7..33943aff0f3 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -37,7 +37,7 @@ class CLIP_UL_tracking_objects(UIList):
layout.prop(tobj, "name", text="", emboss=False,
icon='CAMERA_DATA' if tobj.is_camera
else 'OBJECT_DATA')
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="",
icon='CAMERA_DATA' if tobj.is_camera
@@ -147,7 +147,7 @@ class CLIP_HT_header(Header):
sc = context.space_data
- if sc.mode in {'TRACKING'}:
+ if sc.mode == 'TRACKING':
self._draw_tracking(context)
else:
self._draw_masking(context)
@@ -716,7 +716,7 @@ class CLIP_PT_tracking_camera(Panel):
if CLIP_PT_clip_view_panel.poll(context):
sc = context.space_data
- return sc.mode in {'TRACKING'} and sc.clip
+ return sc.mode == 'TRACKING' and sc.clip
return False
@@ -756,7 +756,7 @@ class CLIP_PT_tracking_lens(Panel):
if CLIP_PT_clip_view_panel.poll(context):
sc = context.space_data
- return sc.mode in {'TRACKING'} and sc.clip
+ return sc.mode == 'TRACKING' and sc.clip
return False
@@ -893,7 +893,7 @@ class CLIP_PT_stabilization(CLIP_PT_reconstruction_panel, Panel):
if CLIP_PT_clip_view_panel.poll(context):
sc = context.space_data
- return sc.mode in {'TRACKING'} and sc.clip
+ return sc.mode == 'TRACKING' and sc.clip
return False
@@ -987,7 +987,9 @@ class CLIP_PT_proxy(CLIP_PT_clip_view_panel, Panel):
if clip.use_proxy_custom_directory:
col.prop(clip.proxy, "directory")
- col.operator("clip.rebuild_proxy", text="Build Proxy")
+ col.operator("clip.rebuild_proxy",
+ text="Build Proxy / Timecode" if clip.source == 'MOVIE'
+ else "Build Proxy")
if clip.source == 'MOVIE':
col2 = col.column()
@@ -1147,6 +1149,7 @@ class CLIP_MT_view(Menu):
layout.operator("clip.view_selected")
layout.operator("clip.view_all")
+ layout.operator("clip.view_all", text="View Fit").fit_view = True
layout.separator()
layout.operator("clip.view_zoom_in")
@@ -1277,8 +1280,8 @@ class CLIP_MT_reconstruction(Menu):
layout.operator("clip.set_plane", text="Set Floor").plane = 'FLOOR'
layout.operator("clip.set_plane", text="Set Wall").plane = 'WALL'
- layout.operator("clip.set_axis", text="Set X Axis").axis = "X"
- layout.operator("clip.set_axis", text="Set Y Axis").axis = "Y"
+ layout.operator("clip.set_axis", text="Set X Axis").axis = 'X'
+ layout.operator("clip.set_axis", text="Set Y Axis").axis = 'Y'
layout.operator("clip.set_scale")
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index 5358670c2f2..7fd9719a6e3 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -51,6 +51,11 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False):
row.prop(dopesheet, "show_only_matching_fcurves", text="")
if dopesheet.show_only_matching_fcurves:
row.prop(dopesheet, "filter_fcurve_name", text="")
+ else:
+ row = layout.row(align=True)
+ row.prop(dopesheet, "use_filter_text", text="")
+ if dopesheet.use_filter_text:
+ row.prop(dopesheet, "filter_text", text="")
if not genericFiltersOnly:
row = layout.row(align=True)
@@ -105,6 +110,7 @@ class DOPESHEET_HT_header(Header):
layout = self.layout
st = context.space_data
+ toolsettings = context.tool_settings
row = layout.row(align=True)
row.template_header()
@@ -112,6 +118,18 @@ class DOPESHEET_HT_header(Header):
DOPESHEET_MT_editor_menus.draw_collapsible(context, layout)
layout.prop(st, "mode", text="")
+
+ if st.mode in {'ACTION', 'SHAPEKEY'}:
+ row = layout.row(align=True)
+ row.operator("action.layer_prev", text="", icon='TRIA_DOWN')
+ row.operator("action.layer_next", text="", icon='TRIA_UP')
+
+ layout.template_ID(st, "action", new="action.new", unlink="action.unlink")
+
+ row = layout.row(align=True)
+ row.operator("action.push_down", text="Push Down", icon='NLA_PUSHDOWN')
+ row.operator("action.stash", text="Stash", icon='FREEZE')
+
layout.prop(st.dopesheet, "show_summary", text="Summary")
if st.mode == 'DOPESHEET':
@@ -121,12 +139,12 @@ class DOPESHEET_HT_header(Header):
# filters which will work here and are useful (especially for character animation)
dopesheet_filter(layout, context, genericFiltersOnly=True)
- if st.mode in {'ACTION', 'SHAPEKEY'}:
- layout.template_ID(st, "action", new="action.new")
-
- row = layout.row(align=True)
- row.operator("action.push_down", text="Push Down", icon='NLA_PUSHDOWN')
- row.operator("action.stash", text="Stash", icon='FREEZE')
+ row = layout.row(align=True)
+ row.prop(toolsettings, "use_proportional_action",
+ text="", icon_only=True)
+ if toolsettings.use_proportional_action:
+ row.prop(toolsettings, "proportional_edit_falloff",
+ text="", icon_only=True)
# Grease Pencil mode doesn't need snapping, as it's frame-aligned only
if st.mode != 'GPENCIL':
@@ -190,6 +208,7 @@ class DOPESHEET_MT_view(Menu):
layout.separator()
layout.operator("action.view_all")
layout.operator("action.view_selected")
+ layout.operator("action.view_frame")
layout.separator()
layout.operator("screen.area_dupli")
@@ -320,6 +339,7 @@ class DOPESHEET_MT_key(Menu):
layout.separator()
layout.operator("action.clean")
+ layout.operator("action.clean", text="Clean Channels").channels = True
layout.operator("action.sample")
layout.separator()
@@ -390,5 +410,20 @@ class DOPESHEET_MT_gpencil_frame(Menu):
#layout.operator("action.copy")
#layout.operator("action.paste")
+
+class DOPESHEET_MT_delete(Menu):
+ bl_label = "Delete"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("action.delete")
+
+ layout.separator()
+
+ layout.operator("action.clean")
+ layout.operator("action.clean", text="Clean Channels").channels = True
+
+
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index 841e169b080..12ea0977b58 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -44,18 +44,26 @@ class FILEBROWSER_HT_header(Header):
row.separator()
row = layout.row(align=True)
- layout.operator_context = "EXEC_DEFAULT"
+ layout.operator_context = 'EXEC_DEFAULT'
row.operator("file.directory_new", icon='NEWFOLDER')
- layout.operator_context = "INVOKE_DEFAULT"
+ layout.operator_context = 'INVOKE_DEFAULT'
params = st.params
# can be None when save/reload with a file selector open
if params:
layout.prop(params, "display_type", expand=True, text="")
+
+ if params.display_type == 'FILE_IMGDISPLAY':
+ layout.prop(params, "thumbnail_size", text="")
+
layout.prop(params, "sort_method", expand=True, text="")
layout.prop(params, "show_hidden", text="", icon='FILE_HIDDEN')
+ if params.collapse_seq:
+ layout.prop(params, "collapse_seq", text="", icon='FULLSCREEN_EXIT')
+ else:
+ layout.prop(params, "collapse_seq", text="", icon='FULLSCREEN_ENTER')
layout.prop(params, "use_filter", text="", icon='FILTER')
row = layout.row(align=True)
@@ -84,7 +92,7 @@ class FILEBROWSER_HT_header(Header):
class FILEBROWSER_UL_dir(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
direntry = item
- space = context.space_data
+ # space = context.space_data
icon = 'NONE'
if active_propname == "system_folders_active":
icon = 'DISK_DRIVE'
@@ -99,12 +107,12 @@ class FILEBROWSER_UL_dir(bpy.types.UIList):
row = layout.row(align=True)
row.enabled = direntry.is_valid
# Non-editable entries would show grayed-out, which is bad in this specific case, so switch to mere label.
- if direntry.is_property_readonly('name'):
+ if direntry.is_property_readonly("name"):
row.label(text=direntry.name, icon=icon)
else:
row.prop(direntry, "name", text="", emboss=False, icon=icon)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.prop(direntry, "path", text="")
@@ -124,6 +132,7 @@ class FILEBROWSER_PT_system_folders(Panel):
row.template_list("FILEBROWSER_UL_dir", "system_folders", space, "system_folders",
space, "system_folders_active", item_dyntip_propname="path", rows=1, maxrows=10)
+
class FILEBROWSER_PT_system_bookmarks(Panel):
bl_space_type = 'FILE_BROWSER'
bl_region_type = 'TOOLS'
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index d3e1a866e43..104fd14797e 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -29,6 +29,7 @@ class GRAPH_HT_header(Header):
from bl_ui.space_dopesheet import dopesheet_filter
layout = self.layout
+ toolsettings = context.tool_settings
st = context.space_data
@@ -46,6 +47,14 @@ class GRAPH_HT_header(Header):
row.active = st.use_normalization
row.prop(st, "use_auto_normalization", text="Auto")
+ row = layout.row(align=True)
+
+ row.prop(toolsettings, "use_proportional_fcurve",
+ text="", icon_only=True)
+ if toolsettings.use_proportional_fcurve:
+ row.prop(toolsettings, "proportional_edit_falloff",
+ text="", icon_only=True)
+
layout.prop(st, "auto_snap", text="")
layout.prop(st, "pivot_point", icon_only=True)
@@ -116,6 +125,7 @@ class GRAPH_MT_view(Menu):
layout.separator()
layout.operator("graph.view_all")
layout.operator("graph.view_selected")
+ layout.operator("graph.view_frame")
layout.separator()
layout.operator("screen.area_dupli")
@@ -248,6 +258,7 @@ class GRAPH_MT_key(Menu):
layout.separator()
layout.operator("graph.clean")
+ layout.operator("graph.clean", text="Clean Channels").channels = True
layout.operator("graph.smooth")
layout.operator("graph.sample")
layout.operator("graph.bake")
@@ -271,5 +282,20 @@ class GRAPH_MT_key_transform(Menu):
layout.operator("transform.rotate", text="Rotate")
layout.operator("transform.resize", text="Scale")
+
+class GRAPH_MT_delete(Menu):
+ bl_label = "Delete"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("graph.delete")
+
+ layout.separator()
+
+ layout.operator("graph.clean")
+ layout.operator("graph.clean", text="Clean Channels").channels = True
+
+
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index a75e0916c09..4c6966b31d2 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -84,6 +84,7 @@ class IMAGE_MT_view(Menu):
layout.prop(toolsettings, "show_uv_local_view")
layout.prop(uv, "show_other_objects")
+ layout.prop(uv, "show_metadata")
if paint.brush and (context.image_paint_object or sima.mode == 'PAINT'):
layout.prop(uv, "show_texpaint")
layout.prop(toolsettings, "show_uv_local_view", text="Show same material")
@@ -106,6 +107,7 @@ class IMAGE_MT_view(Menu):
layout.operator("image.view_selected")
layout.operator("image.view_all")
+ layout.operator("image.view_all", text="View Fit").fit_view = True
layout.separator()
@@ -127,6 +129,7 @@ class IMAGE_MT_select(Menu):
layout.operator("uv.select_border").pinned = False
layout.operator("uv.select_border", text="Border Select Pinned").pinned = True
+ layout.operator("uv.circle_select")
layout.separator()
@@ -335,7 +338,8 @@ class IMAGE_MT_uvs(Menu):
layout.operator("uv.average_islands_scale")
layout.operator("uv.minimize_stretch")
layout.operator("uv.stitch")
- layout.operator("uv.mark_seam")
+ layout.operator("uv.mark_seam").clear = False
+ layout.operator("uv.mark_seam", text="Clear Seam").clear = True
layout.operator("uv.seams_from_islands")
layout.operator("mesh.faces_mirror_uv")
@@ -458,6 +462,10 @@ class IMAGE_HT_header(Header):
layout.prop_search(mesh.uv_textures, "active", mesh, "uv_textures", text="")
if ima:
+ if ima.is_stereo_3d:
+ row = layout.row()
+ row.prop(sima, "show_stereo_3d", text="")
+
# layers
layout.template_image_layers(ima, iuser)
@@ -625,6 +633,8 @@ class IMAGE_PT_view_properties(Panel):
sima = context.space_data
ima = sima.image
+
+ show_render = sima.show_render
show_uvedit = sima.show_uvedit
show_maskedit = sima.show_maskedit
uvedit = sima.uv_editor
@@ -669,7 +679,7 @@ class IMAGE_PT_view_properties(Panel):
sub.active = uvedit.show_stretch
sub.row().prop(uvedit, "draw_stretch_type", expand=True)
- if ima:
+ if show_render and ima:
layout.separator()
render_slot = ima.render_slots.active
layout.prop(render_slot, "name", text="Slot Name")
@@ -1051,10 +1061,10 @@ class ImageScopesPanel:
if not (sima and sima.image):
return False
# scopes are not updated in paint modes, hide
- if sima.mode in {'PAINT'}:
+ if sima.mode == 'PAINT':
return False
ob = context.active_object
- if ob and ob.mode in {'TEXTURE_PAINT'}:
+ if ob and ob.mode in {'TEXTURE_PAINT', 'EDIT'}:
return False
return True
diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py
index 927967c8bc6..48a1b28289e 100644
--- a/release/scripts/startup/bl_ui/space_info.py
+++ b/release/scripts/startup/bl_ui/space_info.py
@@ -282,6 +282,10 @@ class INFO_MT_window(Menu):
layout.separator()
layout.operator("wm.console_toggle", icon='CONSOLE')
+ if context.scene.render.use_multiview:
+ layout.separator()
+ layout.operator("wm.set_stereo_3d", icon='CAMERA_STEREO')
+
class INFO_MT_help(Menu):
bl_label = "Help"
diff --git a/release/scripts/startup/bl_ui/space_logic.py b/release/scripts/startup/bl_ui/space_logic.py
index 16182da1018..48b54feba17 100644
--- a/release/scripts/startup/bl_ui/space_logic.py
+++ b/release/scripts/startup/bl_ui/space_logic.py
@@ -54,11 +54,11 @@ class LOGIC_PT_properties(Panel):
row.label("See Text Object")
else:
props = layout.operator("object.game_property_new", text="Add Text Game Property", icon='ZOOMIN')
- props.name = 'Text'
+ props.name = "Text"
props.type = 'STRING'
props = layout.operator("object.game_property_new", text="Add Game Property", icon='ZOOMIN')
- props.name = ''
+ props.name = ""
for i, prop in enumerate(game.properties):
@@ -71,6 +71,13 @@ class LOGIC_PT_properties(Panel):
row.prop(prop, "type", text="")
row.prop(prop, "value", text="")
row.prop(prop, "show_debug", text="", toggle=True, icon='INFO')
+ sub = row.row(align=True)
+ props = sub.operator("object.game_property_move", text="", icon='TRIA_UP')
+ props.index = i
+ props.direction = 'UP'
+ props = sub.operator("object.game_property_move", text="", icon='TRIA_DOWN')
+ props.index = i
+ props.direction = 'DOWN'
row.operator("object.game_property_remove", text="", icon='X', emboss=False).index = i
diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py
index ae432c44bf6..c083907f017 100644
--- a/release/scripts/startup/bl_ui/space_nla.py
+++ b/release/scripts/startup/bl_ui/space_nla.py
@@ -168,8 +168,10 @@ class NLA_MT_edit(Menu):
layout.separator()
# TODO: names of these tools for 'tweak-mode' need changing?
if scene.is_nla_tweakmode:
+ layout.operator("nla.tweakmode_exit", text="Stop Editing Stashed Action").isolate_action = True
layout.operator("nla.tweakmode_exit", text="Stop Tweaking Strip Actions")
else:
+ layout.operator("nla.tweakmode_enter", text="Start Editing Stashed Action").isolate_action = True
layout.operator("nla.tweakmode_enter", text="Start Tweaking Strip Actions")
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index f229e4293a6..d50e1253970 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -19,6 +19,7 @@
# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
+from bpy.app.translations import pgettext_iface as iface_
from bl_ui.properties_grease_pencil_common import (
GreasePencilDrawingToolsPanel,
GreasePencilStrokeEditPanel,
@@ -66,7 +67,7 @@ class NODE_HT_header(Header):
if snode_id and not (scene.render.use_shading_nodes == 0 and ob.type == 'LAMP'):
layout.prop(snode_id, "use_nodes")
- if snode.shader_type == 'WORLD':
+ if scene.render.use_shading_nodes and snode.shader_type == 'WORLD':
row = layout.row()
row.enabled = not snode.pin
row.template_ID(scene, "world", new="world.new")
@@ -208,8 +209,8 @@ class NODE_MT_select(Menu):
layout.separator()
layout.operator("node.select_grouped").extend = False
- layout.operator("node.select_same_type_step").prev = True
- layout.operator("node.select_same_type_step").prev = False
+ layout.operator("node.select_same_type_step", text="Activate Same Type Previous").prev = True
+ layout.operator("node.select_same_type_step", text="Activate Same Type Next").prev = False
layout.separator()
@@ -358,7 +359,7 @@ class NODE_PT_active_node_properties(Panel):
layout.label("Inputs:")
for socket in value_inputs:
row = layout.row()
- socket.draw(context, row, node, socket.name)
+ socket.draw(context, row, node, iface_(socket.name, socket.bl_rna.translation_context))
# Node Backdrop options
@@ -439,7 +440,7 @@ class NODE_UL_interface_sockets(bpy.types.UIList):
if socket.is_output:
row.template_node_socket(color)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.template_node_socket(color)
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 95e3eb8b416..ed04983cb29 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -19,6 +19,7 @@
# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
+from rna_prop_ui import PropertyPanel
from bl_ui.properties_grease_pencil_common import GreasePencilDataPanel, GreasePencilToolsPanel
from bpy.app.translations import pgettext_iface as iface_
@@ -200,15 +201,17 @@ class SEQUENCER_MT_view(Menu):
layout.prop(st, "show_seconds")
layout.prop(st, "show_frame_indicator")
layout.prop(st, "show_strip_offset")
+ layout.prop(st, "show_info")
layout.prop_menu_enum(st, "waveform_draw_type")
if is_preview:
- if st.display_mode == 'IMAGE':
- layout.prop(st, "show_safe_areas")
- elif st.display_mode == 'WAVEFORM':
+ if st.display_mode == 'WAVEFORM':
layout.prop(st, "show_separate_color")
+ layout.prop(st, "show_metadata")
+
+
layout.separator()
if is_sequencer_view:
@@ -228,12 +231,12 @@ class SEQUENCER_MT_select(Menu):
layout.operator("sequencer.select_active_side", text="Strips to the Left").side = 'LEFT'
layout.operator("sequencer.select_active_side", text="Strips to the Right").side = 'RIGHT'
- op = layout.operator("sequencer.select", text="All strips to the Left")
- op.left_right = 'LEFT'
- op.linked_time = True
- op = layout.operator("sequencer.select", text="All strips to the Right")
- op.left_right = 'RIGHT'
- op.linked_time = True
+ props = layout.operator("sequencer.select", text="All strips to the Left")
+ props.left_right = 'LEFT'
+ props.linked_time = True
+ props = layout.operator("sequencer.select", text="All strips to the Right")
+ props.left_right = 'RIGHT'
+ props.linked_time = True
layout.separator()
layout.operator("sequencer.select_handles", text="Surrounding Handles").side = 'BOTH'
@@ -306,6 +309,7 @@ class SEQUENCER_MT_add(Menu):
layout.operator_menu_enum("sequencer.mask_strip_add", "mask", text="Mask...")
layout.operator("sequencer.movie_strip_add", text="Movie")
+ layout.operator("sequencer.image_sequence_add", text="Image Sequence")
layout.operator("sequencer.image_strip_add", text="Image")
layout.operator("sequencer.sound_strip_add", text="Sound")
@@ -472,7 +476,7 @@ class SEQUENCER_PT_edit(SequencerButtonsPanel, Panel):
split.label(text="Type:")
split.prop(strip, "type", text="")
- if strip.type not in {'SOUND'}:
+ if strip.type != 'SOUND':
split = layout.split(percentage=0.3)
split.label(text="Blend:")
split.prop(strip, "blend_type", text="")
@@ -658,6 +662,7 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ scene = context.scene
strip = act_strip(context)
@@ -671,7 +676,7 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
# Current element for the filename
- elem = strip.strip_elem_from_frame(context.scene.frame_current)
+ elem = strip.strip_elem_from_frame(scene.frame_current)
if elem:
split = layout.split(percentage=0.2)
split.label(text="File:")
@@ -717,6 +722,19 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
col.prop(strip, "frame_offset_start", text="Start")
col.prop(strip, "frame_offset_end", text="End")
+ if scene.render.use_multiview and seq_type in {'IMAGE', 'MOVIE'}:
+ layout.prop(strip, "use_multiview")
+
+ col = layout.column()
+ col.active = strip.use_multiview
+
+ col.label(text="Views Format:")
+ col.row().prop(strip, "views_format", expand=True)
+
+ box = col.box()
+ box.active = strip.views_format == 'STEREO_3D'
+ box.template_image_stereo_3d(strip.stereo_3d_format)
+
class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel):
bl_label = "Sound"
@@ -915,44 +933,43 @@ class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
+ sequencer = context.scene.sequence_editor
+
strip = act_strip(context)
- flow = layout.column_flow()
- flow.prop(strip, "use_proxy_custom_directory")
- flow.prop(strip, "use_proxy_custom_file")
if strip.proxy:
- if strip.use_proxy_custom_directory and not strip.use_proxy_custom_file:
- flow.prop(strip.proxy, "directory")
- if strip.use_proxy_custom_file:
- flow.prop(strip.proxy, "filepath")
+ proxy = strip.proxy
- layout.label("Enabled Proxies:")
- enabled = ""
- row = layout.row()
- if (strip.proxy.build_25):
- enabled += "25% "
- if (strip.proxy.build_50):
- enabled += "50% "
- if (strip.proxy.build_75):
- enabled += "75% "
- if (strip.proxy.build_100):
- enabled += "100% "
-
- row.label(enabled)
- if (strip.proxy.use_overwrite):
- layout.label("Overwrite On")
+ flow = layout.column_flow()
+ flow.prop(sequencer, "proxy_storage")
+ if sequencer.proxy_storage == 'PROJECT':
+ flow.prop(sequencer, "proxy_dir")
else:
- layout.label("Overwrite Off")
+ flow.prop(proxy, "use_proxy_custom_directory")
+ flow.prop(proxy, "use_proxy_custom_file")
+
+ if proxy.use_proxy_custom_directory and not proxy.use_proxy_custom_file:
+ flow.prop(proxy, "directory")
+ if proxy.use_proxy_custom_file:
+ flow.prop(proxy, "filepath")
+
+ row = layout.row()
+ row.prop(strip.proxy, "build_25")
+ row.prop(strip.proxy, "build_50")
+ row.prop(strip.proxy, "build_75")
+ row.prop(strip.proxy, "build_100")
+
+ layout.prop(proxy, "use_overwrite")
col = layout.column()
col.label(text="Build JPEG quality")
- col.prop(strip.proxy, "quality")
+ col.prop(proxy, "quality")
if strip.type == 'MOVIE':
col = layout.column()
col.label(text="Use timecode index:")
- col.prop(strip.proxy, "timecode")
+ col.prop(proxy, "timecode")
col = layout.column()
col.operator("sequencer.enable_proxies")
@@ -1100,5 +1117,11 @@ class SEQUENCER_PT_grease_pencil_tools(GreasePencilToolsPanel, SequencerButtonsP
# toolbar, which doesn't exist here...
+class SEQUENCER_PT_custom_props(SequencerButtonsPanel, PropertyPanel, Panel):
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ _context_path = "scene.sequence_editor.active_strip"
+ _property_type = (bpy.types.Sequence,)
+
+
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py
index 27fcf94666a..c4c4097315c 100644
--- a/release/scripts/startup/bl_ui/space_time.py
+++ b/release/scripts/startup/bl_ui/space_time.py
@@ -30,6 +30,7 @@ class TIME_HT_header(Header):
scene = context.scene
toolsettings = context.tool_settings
screen = context.screen
+ userprefs = context.user_preferences
row = layout.row(align=True)
row.template_header()
@@ -82,7 +83,7 @@ class TIME_HT_header(Header):
if toolsettings.use_keyframe_insert_auto:
row.prop(toolsettings, "use_keyframe_insert_keyingset", text="", toggle=True)
- if screen.is_animation_playing:
+ if screen.is_animation_playing and not userprefs.edit.use_keyframe_insert_available:
subsub = row.row(align=True)
subsub.prop(toolsettings, "use_record_with_nla", toggle=True)
@@ -253,6 +254,10 @@ def marker_menu_generic(layout):
layout.operator("screen.marker_jump", text="Jump to Next Marker").next = True
layout.operator("screen.marker_jump", text="Jump to Previous Marker").next = False
+ layout.separator()
+ ts = bpy.context.tool_settings
+ layout.prop(ts, "lock_markers")
+
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 91f77804d95..2316d7000a7 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -200,6 +200,11 @@ class USERPREF_PT_interface(Panel):
col.label(text="2D Viewports:")
col.prop(view, "view2d_grid_spacing_min", text="Minimum Grid Spacing")
col.prop(view, "timecode_style")
+ col.prop(view, "view_frame_type")
+ if (view.view_frame_type == 'SECONDS'):
+ col.prop(view, "view_frame_seconds")
+ elif (view.view_frame_type == 'KEYFRAMES'):
+ col.prop(view, "view_frame_keyframes")
row.separator()
row.separator()
@@ -1046,7 +1051,8 @@ class USERPREF_PT_input(Panel):
userpref = context.user_preferences
return (userpref.active_section == 'INPUT')
- def draw_input_prefs(self, inputs, layout):
+ @staticmethod
+ def draw_input_prefs(inputs, layout):
import sys
# General settings
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index e2af544a317..d005b84f59d 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -50,6 +50,8 @@ class VIEW3D_HT_header(Header):
# Particle edit
if mode == 'PARTICLE_EDIT':
row.prop(toolsettings.particle_edit, "select_mode", text="", expand=True)
+ elif mode == 'HAIR_EDIT':
+ row.prop(toolsettings.hair_edit, "select_mode", text="", expand=True)
# Occlude geometry
if ((view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'} and (mode == 'PARTICLE_EDIT' or (mode == 'EDIT' and obj.type == 'MESH'))) or
@@ -142,7 +144,7 @@ class VIEW3D_MT_editor_menus(Menu):
layout.menu("VIEW3D_MT_select_paint_mask")
elif mesh.use_paint_mask_vertex and mode_string == 'PAINT_WEIGHT':
layout.menu("VIEW3D_MT_select_paint_mask_vertex")
- elif mode_string != 'SCULPT':
+ elif mode_string not in {'SCULPT'}:
layout.menu("VIEW3D_MT_select_%s" % mode_string.lower())
if mode_string == 'OBJECT':
@@ -161,9 +163,9 @@ class VIEW3D_MT_editor_menus(Menu):
if edit_object:
layout.menu("VIEW3D_MT_edit_%s" % edit_object.type.lower())
elif obj:
- if mode_string not in {'PAINT_TEXTURE'}:
+ if mode_string != 'PAINT_TEXTURE':
layout.menu("VIEW3D_MT_%s" % mode_string.lower())
- if mode_string in {'SCULPT', 'PAINT_VERTEX', 'PAINT_WEIGHT', 'PAINT_TEXTURE'}:
+ if mode_string in {'SCULPT', 'PAINT_VERTEX', 'PAINT_WEIGHT', 'PAINT_TEXTURE', 'HAIR'}:
layout.menu("VIEW3D_MT_brush")
if mode_string == 'SCULPT':
layout.menu("VIEW3D_MT_hide_mask")
@@ -211,8 +213,10 @@ class VIEW3D_MT_transform_base(Menu):
layout.operator("transform.shear", text="Shear")
layout.operator("transform.bend", text="Bend")
layout.operator("transform.push_pull", text="Push/Pull")
- layout.operator("object.vertex_warp", text="Warp")
- layout.operator("object.vertex_random", text="Randomize")
+
+ if context.mode != 'OBJECT':
+ layout.operator("transform.vertex_warp", text="Warp")
+ layout.operator("transform.vertex_random", text="Randomize")
# Generic transform menu - geometry types
@@ -449,6 +453,9 @@ class VIEW3D_MT_view_navigation(Menu):
layout = self.layout
layout.operator_enum("view3d.view_orbit", "type")
+ props = layout.operator("view3d.view_orbit", "Orbit Opposite")
+ props.type = 'ORBITRIGHT'
+ props.angle = pi
layout.separator()
@@ -915,6 +922,13 @@ class VIEW3D_MT_select_paint_mask_vertex(Menu):
layout.operator("paint.vert_select_ungrouped", text="Ungrouped Verts")
+class VIEW3D_MT_select_hair(Menu):
+ bl_label = "Select"
+
+ def draw(self, context):
+ layout = self.layout
+
+
class VIEW3D_MT_angle_control(Menu):
bl_label = "Angle Control"
@@ -935,7 +949,7 @@ class VIEW3D_MT_angle_control(Menu):
settings = UnifiedPaintPanel.paint_settings(context)
brush = settings.brush
- sculpt = (context.sculpt_object != None)
+ sculpt = (context.sculpt_object is not None)
tex_slot = brush.texture_slot
@@ -1043,6 +1057,17 @@ class INFO_MT_armature_add(Menu):
layout.operator("object.armature_add", text="Single Bone", icon='BONE_DATA')
+class INFO_MT_lamp_add(Menu):
+ bl_idname = "INFO_MT_lamp_add"
+ bl_label = "Lamp"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator_context = 'INVOKE_REGION_WIN'
+ layout.operator_enum("object.lamp_add", "type")
+
+
class INFO_MT_add(Menu):
bl_label = "Add"
@@ -1075,7 +1100,7 @@ class INFO_MT_add(Menu):
layout.separator()
layout.operator("object.camera_add", text="Camera", icon='OUTLINER_OB_CAMERA')
- layout.operator_menu_enum("object.lamp_add", "type", text="Lamp", icon='OUTLINER_OB_LAMP')
+ layout.menu("INFO_MT_lamp_add", icon='OUTLINER_OB_LAMP')
layout.separator()
layout.operator_menu_enum("object.effector_add", "type", text="Force Field", icon='OUTLINER_OB_EMPTY')
@@ -1130,6 +1155,7 @@ class VIEW3D_MT_object(Menu):
layout.menu("VIEW3D_MT_object_parent")
layout.menu("VIEW3D_MT_object_track")
layout.menu("VIEW3D_MT_object_group")
+ layout.menu("VIEW3D_MT_object_cachelib")
layout.menu("VIEW3D_MT_object_constraints")
layout.separator()
@@ -1396,6 +1422,29 @@ class VIEW3D_MT_object_group(Menu):
layout.operator("group.objects_remove_active")
+class VIEW3D_MT_object_cachelib(Menu):
+ bl_label = "Cache Library"
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.active_object
+ if not (ob and ob.cache_library):
+ return False
+ return True
+
+ def draw(self, context):
+ layout = self.layout
+ scene = context.scene
+ ob = context.active_object
+ cachelib = ob.cache_library
+
+ layout.operator("cachelibrary.bake", text="Bake")
+ props = layout.operator("cachelibrary.archive_slice", text="Slice")
+ props.input_filepath = cachelib.input_filepath
+ props.start_frame = scene.frame_start
+ props.end_frame = scene.frame_end
+
+
class VIEW3D_MT_object_constraints(Menu):
bl_label = "Constraints"
@@ -1514,7 +1563,7 @@ class VIEW3D_MT_brush(Menu):
layout.separator()
# brush paint modes
- layout.menu("VIEW3D_MT_brush_paint_modes")
+ layout.menu("VIEW3D_MT_brush_object_modes")
# brush tool
if context.sculpt_object:
@@ -1524,6 +1573,8 @@ class VIEW3D_MT_brush(Menu):
layout.prop_menu_enum(brush, "image_tool")
elif context.vertex_paint_object or context.weight_paint_object:
layout.prop_menu_enum(brush, "vertex_tool")
+ elif context.hair_edit_object:
+ layout.prop_menu_enum(brush, "hair_tool")
# skip if no active brush
if not brush:
@@ -1551,7 +1602,7 @@ class VIEW3D_MT_brush(Menu):
layout.operator("sculpt.set_persistent_base")
-class VIEW3D_MT_brush_paint_modes(Menu):
+class VIEW3D_MT_brush_object_modes(Menu):
bl_label = "Enabled Modes"
def draw(self, context):
@@ -1564,6 +1615,7 @@ class VIEW3D_MT_brush_paint_modes(Menu):
layout.prop(brush, "use_paint_vertex", text="Vertex Paint")
layout.prop(brush, "use_paint_weight", text="Weight Paint")
layout.prop(brush, "use_paint_image", text="Texture Paint")
+ layout.prop(brush, "use_hair_edit", text="Hair Edit")
# ********** Vertex paint menu **********
@@ -1655,9 +1707,9 @@ class VIEW3D_MT_paint_weight(Menu):
layout.operator("object.vertex_group_quantize", text="Quantize")
layout.operator("object.vertex_group_levels", text="Levels")
layout.operator("object.vertex_group_blend", text="Blend")
- prop = layout.operator("object.data_transfer", text="Transfer Weights")
- prop.use_reverse_transfer = True
- prop.data_type = 'VGROUP_WEIGHTS'
+ props = layout.operator("object.data_transfer", text="Transfer Weights")
+ props.use_reverse_transfer = True
+ props.data_type = 'VGROUP_WEIGHTS'
layout.operator("object.vertex_group_limit_total", text="Limit Total")
layout.operator("object.vertex_group_fix", text="Fix Deforms")
@@ -1791,6 +1843,9 @@ class VIEW3D_MT_particle_specials(Menu):
layout.separator()
layout.operator("particle.mirror")
+ layout.separator()
+
+ layout.operator("particle.shape_propagate_to_all")
if particle_edit.select_mode == 'POINT':
layout.separator()
@@ -1816,6 +1871,14 @@ class VIEW3D_MT_particle_specials(Menu):
class VIEW3D_MT_particle_showhide(ShowHideMenu, Menu):
_operator_name = "particle"
+# ********** Hair menu **********
+
+class VIEW3D_MT_hair(Menu):
+ bl_label = "Hair"
+
+ def draw(self, context):
+ layout = self.layout
+
# ********** Pose Menu **********
@@ -1933,6 +1996,10 @@ class VIEW3D_MT_pose_propagate(Menu):
layout.separator()
+ layout.operator("pose.propagate", text="On Selected Keyframes").mode = 'SELECTED_KEYS'
+
+ layout.separator()
+
layout.operator("pose.propagate", text="On Selected Markers").mode = 'SELECTED_MARKERS'
@@ -2262,13 +2329,6 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
layout.separator()
- op = layout.operator("mesh.mark_sharp", text="Shade Smooth")
- op.use_verts = True
- op.clear = True
- layout.operator("mesh.mark_sharp", text="Shade Sharp").use_verts = True
-
- layout.separator()
-
layout.operator("mesh.bevel").vertex_only = True
layout.operator("mesh.convex_hull")
layout.operator("mesh.vertices_smooth")
@@ -2291,6 +2351,8 @@ class VIEW3D_MT_edit_mesh_edges(Menu):
def draw(self, context):
layout = self.layout
+ toolsettings = context.tool_settings
+
with_freestyle = bpy.app.build_options.freestyle
layout.operator_context = 'INVOKE_REGION_WIN'
@@ -2311,8 +2373,16 @@ class VIEW3D_MT_edit_mesh_edges(Menu):
layout.separator()
- layout.operator("mesh.mark_sharp")
- layout.operator("mesh.mark_sharp", text="Clear Sharp").clear = True
+ if not toolsettings.mesh_select_mode[0]:
+ # edge mode
+ layout.operator("mesh.mark_sharp")
+ layout.operator("mesh.mark_sharp", text="Clear Sharp").clear = True
+ else:
+ # vert mode
+ layout.operator("mesh.mark_sharp").use_verts = True
+ props = layout.operator("mesh.mark_sharp", text="Clear Sharp")
+ props.use_verts = True
+ props.clear = True
layout.separator()
@@ -2467,6 +2537,7 @@ def draw_curve(self, context):
layout.separator()
layout.operator("curve.extrude_move")
+ layout.operator("curve.spin")
layout.operator("curve.duplicate_move")
layout.operator("curve.split")
layout.operator("curve.separate")
@@ -2568,10 +2639,6 @@ class VIEW3D_MT_edit_font(Menu):
layout.operator("font.style_toggle", text="Toggle Underline").style = 'UNDERLINE'
layout.operator("font.style_toggle", text="Toggle Small Caps").style = 'SMALL_CAPS'
- layout.separator()
-
- layout.operator("font.insert_lorem")
-
class VIEW3D_MT_edit_text_chars(Menu):
bl_label = "Special Characters"
@@ -2710,6 +2777,7 @@ class VIEW3D_MT_edit_armature(Menu):
layout.separator()
layout.operator_context = 'EXEC_AREA'
+ layout.operator("armature.symmetrize")
layout.operator("armature.autoside_names", text="AutoName Left/Right").type = 'XAXIS'
layout.operator("armature.autoside_names", text="AutoName Front/Back").type = 'YAXIS'
layout.operator("armature.autoside_names", text="AutoName Top/Bottom").type = 'ZAXIS'
@@ -2748,6 +2816,7 @@ class VIEW3D_MT_armature_specials(Menu):
layout.operator("armature.autoside_names", text="AutoName Front/Back").type = 'YAXIS'
layout.operator("armature.autoside_names", text="AutoName Top/Bottom").type = 'ZAXIS'
layout.operator("armature.flip_names", text="Flip Names")
+ layout.operator("armature.symmetrize")
class VIEW3D_MT_edit_armature_parent(Menu):
@@ -2941,16 +3010,50 @@ class VIEW3D_PT_view3d_display(Panel):
row.prop(region, "use_box_clip")
-class VIEW3D_PT_view3d_shading(Panel):
+class VIEW3D_PT_view3d_stereo(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
- bl_label = "Shading"
+ bl_label = "Stereoscopy"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
+ scene = context.scene
+
+ multiview = scene.render.use_multiview
+ return context.space_data and multiview
+
+ def draw(self, context):
+ layout = self.layout
view = context.space_data
- return (view)
+
+ basic_stereo = context.scene.render.views_format == 'STEREO_3D'
+
+ col = layout.column()
+ col.row().prop(view, "stereo_3d_camera", expand=True)
+
+ col.label(text="Display:")
+ row = col.row()
+ row.active = basic_stereo
+ row.prop(view, "show_stereo_3d_cameras")
+ row = col.row()
+ row.active = basic_stereo
+ split = row.split()
+ split.prop(view, "show_stereo_3d_convergence_plane")
+ split = row.split()
+ split.prop(view, "stereo_3d_convergence_plane_alpha", text="Alpha")
+ split.active = view.show_stereo_3d_convergence_plane
+ row = col.row()
+ split = row.split()
+ split.prop(view, "show_stereo_3d_volume")
+ split = row.split()
+ split.prop(view, "stereo_3d_volume_alpha", text="Alpha")
+
+
+class VIEW3D_PT_view3d_shading(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'UI'
+ bl_label = "Shading"
def draw(self, context):
layout = self.layout
@@ -2983,12 +3086,12 @@ class VIEW3D_PT_view3d_shading(Panel):
if obj and obj.mode == 'EDIT':
col.prop(view, "show_occlude_wire")
- fx_settings = view.fx_settings
+ fx_settings = view.fx_settings
+ if view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'}:
sub = col.column()
sub.active = view.region_3d.view_perspective == 'CAMERA'
sub.prop(fx_settings, "use_dof")
-
col.prop(fx_settings, "use_ssao", text="Ambient Occlusion")
if fx_settings.use_ssao:
ssao_settings = fx_settings.ssao
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index a45892cc25d..1fba3978e67 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -100,7 +100,7 @@ class VIEW3D_PT_tools_object(View3DPanel, Panel):
row.operator("object.shade_smooth", text="Smooth")
row.operator("object.shade_flat", text="Flat")
- if obj_type in {'MESH'}:
+ if obj_type == 'MESH':
col = layout.column(align=True)
col.label(text="Data Transfer:")
row = col.row(align=True)
@@ -315,7 +315,7 @@ class VIEW3D_PT_tools_meshedit(View3DPanel, Panel):
row.operator("transform.vert_slide", text="Vertex")
col.operator("mesh.noise")
col.operator("mesh.vertices_smooth")
- col.operator("object.vertex_random")
+ col.operator("transform.vertex_random")
col = layout.column(align=True)
col.label(text="Add:")
@@ -407,9 +407,9 @@ class VIEW3D_PT_tools_shading(View3DPanel, Panel):
row.operator("mesh.mark_sharp", text="Sharp")
col.label(text="Vertices:")
row = col.row(align=True)
- op = row.operator("mesh.mark_sharp", text="Smooth")
- op.use_verts = True
- op.clear = True
+ props = row.operator("mesh.mark_sharp", text="Smooth")
+ props.use_verts = True
+ props.clear = True
row.operator("mesh.mark_sharp", text="Sharp").use_verts = True
col = layout.column(align=True)
@@ -523,7 +523,7 @@ class VIEW3D_PT_tools_curveedit(View3DPanel, Panel):
col.operator("curve.extrude_move", text="Extrude")
col.operator("curve.subdivide")
col.operator("curve.smooth")
- col.operator("object.vertex_random")
+ col.operator("transform.vertex_random")
class VIEW3D_PT_tools_add_curve_edit(View3DPanel, Panel):
@@ -573,11 +573,12 @@ class VIEW3D_PT_tools_surfaceedit(View3DPanel, Panel):
col = layout.column(align=True)
col.label(text="Modeling:")
col.operator("curve.extrude", text="Extrude")
+ col.operator("curve.spin")
col.operator("curve.subdivide")
col = layout.column(align=True)
col.label(text="Deform:")
- col.operator("object.vertex_random")
+ col.operator("transform.vertex_random")
class VIEW3D_PT_tools_add_surface_edit(View3DPanel, Panel):
@@ -654,7 +655,7 @@ class VIEW3D_PT_tools_armatureedit(View3DPanel, Panel):
col = layout.column(align=True)
col.label(text="Deform:")
- col.operator("object.vertex_random")
+ col.operator("transform.vertex_random")
class VIEW3D_PT_tools_armatureedit_options(View3DPanel, Panel):
@@ -687,7 +688,7 @@ class VIEW3D_PT_tools_mballedit(View3DPanel, Panel):
col = layout.column(align=True)
col.label(text="Deform:")
- col.operator("object.vertex_random")
+ col.operator("transform.vertex_random")
class VIEW3D_PT_tools_add_mball_edit(View3DPanel, Panel):
@@ -725,7 +726,7 @@ class VIEW3D_PT_tools_latticeedit(View3DPanel, Panel):
col = layout.column(align=True)
col.label(text="Deform:")
- col.operator("object.vertex_random")
+ col.operator("transform.vertex_random")
# ********** default tools for pose-mode ****************
@@ -758,6 +759,10 @@ class VIEW3D_PT_tools_posemode(View3DPanel, Panel):
row.operator("pose.copy", text="Copy")
row.operator("pose.paste", text="Paste")
+ row = layout.row(align=True)
+ row.operator("pose.propagate", text="Propagate")
+ row.menu("VIEW3D_MT_pose_propagate", icon='TRIA_RIGHT', text="")
+
col = layout.column(align=True)
col.operator("poselib.pose_add", text="Add To Library")
@@ -894,6 +899,21 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
layout.prop(brush, "puff_mode", expand=True)
layout.prop(brush, "use_puff_volume")
+ # Hair Mode #
+
+ elif context.hair_edit_object and brush:
+ col = layout.column()
+
+ row = col.row(align=True)
+ self.prop_unified_size(row, context, brush, "size", slider=True, text="Radius")
+ self.prop_unified_size(row, context, brush, "use_pressure_size")
+
+ row = col.row(align=True)
+ self.prop_unified_strength(row, context, brush, "strength", text="Strength")
+ self.prop_unified_strength(row, context, brush, "use_pressure_strength")
+
+ col.prop(brush, "hair_tool", text="Tool")
+
# Sculpt Mode #
elif context.sculpt_object and brush:
@@ -1075,7 +1095,7 @@ class TEXTURE_UL_texpaintslots(UIList):
if (not mat.use_nodes) and context.scene.render.engine in {'BLENDER_RENDER', 'BLENDER_GAME'}:
mtex_index = mat.texture_paint_slots[index].index
layout.prop(mat, "use_textures", text="", index=mtex_index)
- elif self.layout_type in {'GRID'}:
+ elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="")
@@ -1471,6 +1491,8 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
row = sub.row(align=True)
row.prop(sculpt, "constant_detail")
row.operator("sculpt.sample_detail_size", text="", icon='EYEDROPPER')
+ elif (sculpt.detail_type_method == 'BRUSH'):
+ sub.prop(sculpt, "detail_percent")
else:
sub.prop(sculpt, "detail_size")
sub.prop(sculpt, "detail_refine_method", text="")
@@ -1605,9 +1627,9 @@ class VIEW3D_PT_tools_weightpaint(View3DPanel, Panel):
col = layout.column()
col.operator("paint.weight_gradient")
- prop = col.operator("object.data_transfer", text="Transfer Weights")
- prop.use_reverse_transfer = True
- prop.data_type = 'VGROUP_WEIGHTS'
+ props = col.operator("object.data_transfer", text="Transfer Weights")
+ props.use_reverse_transfer = True
+ props.data_type = 'VGROUP_WEIGHTS'
class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel):
@@ -1698,6 +1720,25 @@ class VIEW3D_PT_tools_imagepaint_external(Panel, View3DPaintPanel):
col.operator("paint.project_image", text="Apply Camera Image")
+class VIEW3D_PT_tools_imagepaint_symmetry(Panel, View3DPaintPanel):
+ bl_category = "Tools"
+ bl_context = "imagepaint"
+ bl_label = "Symmetry"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ toolsettings = context.tool_settings
+ ipaint = toolsettings.image_paint
+
+ col = layout.column(align=True)
+ row = col.row(align=True)
+ row.prop(ipaint, "use_symmetry_x", text="X", toggle=True)
+ row.prop(ipaint, "use_symmetry_y", text="Y", toggle=True)
+ row.prop(ipaint, "use_symmetry_z", text="Z", toggle=True)
+
+
class VIEW3D_PT_tools_projectpaint(View3DPaintPanel, Panel):
bl_category = "Options"
bl_context = "imagepaint"
@@ -1833,6 +1874,23 @@ class VIEW3D_PT_tools_particlemode(View3DPanel, Panel):
sub.prop(pe, "fade_frames", slider=True)
+class VIEW3D_PT_tools_hairmode(View3DPanel, Panel):
+ """Tools for hair mode"""
+ bl_context = "hairmode"
+ bl_label = "Options"
+ bl_category = "Tools"
+
+ def draw(self, context):
+ layout = self.layout
+
+ settings = context.tool_settings.hair_edit
+ ob = context.active_object
+
+ if ob.data:
+ col = layout.column(align=True)
+ col.prop(ob.data, "use_mirror_x")
+
+
# Grease Pencil drawing tools
class VIEW3D_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
bl_space_type = 'VIEW_3D'
@@ -1858,7 +1916,7 @@ class VIEW3D_PT_tools_history(View3DPanel, Panel):
row = col.row(align=True)
row.operator("ed.undo")
row.operator("ed.redo")
- if obj is None or obj.mode not in {'SCULPT'}:
+ if obj is None or obj.mode != 'SCULPT':
# Sculpt mode does not generate an undo menu it seems...
col.operator("ed.undo_history")
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 1590bd49763..e056719e4cc 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -66,6 +66,8 @@ node_tree_group_type = {
# generic node group items generator for shader, compositor and texture node groups
def node_group_items(context):
+ if context is None:
+ return
space = context.space_data
if not space:
return
@@ -234,6 +236,7 @@ shader_node_categories = [
NodeItem("ShaderNodeTexMagic"),
NodeItem("ShaderNodeTexChecker"),
NodeItem("ShaderNodeTexBrick"),
+ NodeItem("ShaderNodeTexPointDensity"),
]),
ShaderNewNodeCategory("SH_NEW_OP_COLOR", "Color", items=[
NodeItem("ShaderNodeMixRGB"),
@@ -328,6 +331,7 @@ compositor_node_categories = [
NodeItem("CompositorNodeCombYUVA"),
NodeItem("CompositorNodeSepYCCA"),
NodeItem("CompositorNodeCombYCCA"),
+ NodeItem("CompositorNodeSwitchView"),
]),
CompositorNodeCategory("CMP_OP_FILTER", "Filter", items=[
NodeItem("CompositorNodeBlur"),
diff --git a/release/scripts/templates_py/addon_add_object.py b/release/scripts/templates_py/addon_add_object.py
index f0d8bede6d5..8e57d7ef8f8 100644
--- a/release/scripts/templates_py/addon_add_object.py
+++ b/release/scripts/templates_py/addon_add_object.py
@@ -2,12 +2,13 @@ bl_info = {
"name": "New Object",
"author": "Your Name Here",
"version": (1, 0),
- "blender": (2, 65, 0),
+ "blender": (2, 75, 0),
"location": "View3D > Add > Mesh > New Object",
"description": "Adds a new Mesh Object",
"warning": "",
"wiki_url": "",
- "category": "Add Mesh"}
+ "category": "Add Mesh",
+ }
import bpy
diff --git a/release/scripts/templates_py/operator_modal_timer.py b/release/scripts/templates_py/operator_modal_timer.py
index 4d36860b9e3..df4d10e656b 100644
--- a/release/scripts/templates_py/operator_modal_timer.py
+++ b/release/scripts/templates_py/operator_modal_timer.py
@@ -10,7 +10,8 @@ class ModalTimerOperator(bpy.types.Operator):
def modal(self, context, event):
if event.type in {'RIGHTMOUSE', 'ESC'}:
- return self.cancel(context)
+ self.cancel(context)
+ return {'CANCELLED'}
if event.type == 'TIMER':
# change theme color, silly!
diff --git a/release/scripts/templates_py/ui_previews_custom_icon.py b/release/scripts/templates_py/ui_previews_custom_icon.py
new file mode 100644
index 00000000000..53f84b2982f
--- /dev/null
+++ b/release/scripts/templates_py/ui_previews_custom_icon.py
@@ -0,0 +1,76 @@
+# This sample script demonstrates how to place a custom icon on a button or
+# menu entry.
+#
+# IMPORTANT NOTE: if you run this sample, there will be no icon in the button
+# You need to replace the image path with a real existing one.
+# For distributable scripts, it is recommended to place the icons inside the
+# addon folder and access it relative to the py script file for portability
+#
+#
+# Other use cases for UI-previews:
+# - provide a fixed list of previews to select from
+# - provide a dynamic list of preview (eg. calculated from reading a directory)
+#
+# For the above use cases, see the template 'ui_previews_dynamic_enum.py"
+
+
+import os
+import bpy
+
+
+class PreviewsExamplePanel(bpy.types.Panel):
+ """Creates a Panel in the Object properties window"""
+ bl_label = "Previews Example Panel"
+ bl_idname = "OBJECT_PT_previews"
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "object"
+
+ def draw(self, context):
+ layout = self.layout
+ pcoll = preview_collections["main"]
+
+ row = layout.row()
+ my_icon = pcoll["my_icon"]
+ row.operator("render.render", icon_value=my_icon.icon_id)
+
+ # my_icon.icon_id can be used in any UI function that accepts
+ # icon_value # try also setting text=""
+ # to get an icon only operator button
+
+
+# We can store multiple preview collections here,
+# however in this example we only store "main"
+preview_collections = {}
+
+
+def register():
+
+ # Note that preview collections returned by bpy.utils.previews
+ # are regular py objects - you can use them to store custom data.
+ import bpy.utils.previews
+ pcoll = bpy.utils.previews.new()
+
+ # path to the folder where the icon is
+ # the path is calculated relative to this py file inside the addon folder
+ my_icons_dir = os.path.join(os.path.dirname(__file__), "icons")
+
+ # load a preview thumbnail of a file and store in the previews collection
+ pcoll.load("my_icon", os.path.join(my_icons_dir, "icon-image.png"), 'IMAGE')
+
+ preview_collections["main"] = pcoll
+
+ bpy.utils.register_class(PreviewsExamplePanel)
+
+
+def unregister():
+
+ for pcoll in preview_collections.values():
+ bpy.utils.previews.remove(pcoll)
+ preview_collections.clear()
+
+ bpy.utils.unregister_class(PreviewsExamplePanel)
+
+
+if __name__ == "__main__":
+ register()
diff --git a/release/scripts/templates_py/ui_previews_dynamic_enum.py b/release/scripts/templates_py/ui_previews_dynamic_enum.py
new file mode 100644
index 00000000000..0cfa232116d
--- /dev/null
+++ b/release/scripts/templates_py/ui_previews_dynamic_enum.py
@@ -0,0 +1,137 @@
+# This sample script demonstrates a dynamic EnumProperty with custom icons.
+# The EnumProperty is populated dynamically with thumbnails of the contents of
+# a chosen directory in 'enum_previews_from_directory_items'.
+# Then, the same enum is displayed with different interfaces. Note that the
+# generated icon previews do not have Blender IDs, which means that they can
+# not be used with UILayout templates that require IDs,
+# such as template_list and template_ID_preview.
+#
+# Other use cases:
+# - make a fixed list of enum_items instead of calculating them in a function
+# - generate isolated thumbnails to use as custom icons in buttons
+# and menu items
+#
+# For custom icons, see the template "ui_previews_custom_icon.py".
+#
+# For distributable scripts, it is recommended to place the icons inside the
+# script directory and access it relative to the py script file for portability:
+#
+# os.path.join(os.path.dirname(__file__), "images")
+
+
+import os
+import bpy
+
+
+def enum_previews_from_directory_items(self, context):
+ """EnumProperty callback"""
+ enum_items = []
+
+ if context is None:
+ return enum_items
+
+ wm = context.window_manager
+ directory = wm.my_previews_dir
+
+ # Get the preview collection (defined in register func).
+ pcoll = preview_collections["main"]
+
+ if directory == pcoll.my_previews_dir:
+ return pcoll.my_previews
+
+ print("Scanning directory: %s" % directory)
+
+ if directory and os.path.exists(directory):
+ # Scan the directory for png files
+ image_paths = []
+ for fn in os.listdir(directory):
+ if fn.lower().endswith(".png"):
+ image_paths.append(fn)
+
+ for i, name in enumerate(image_paths):
+ # generates a thumbnail preview for a file.
+ filepath = os.path.join(directory, name)
+ thumb = pcoll.load(filepath, filepath, 'IMAGE')
+ enum_items.append((name, name, "", thumb.icon_id, i))
+
+ pcoll.my_previews = enum_items
+ pcoll.my_previews_dir = directory
+ return pcoll.my_previews
+
+
+class PreviewsExamplePanel(bpy.types.Panel):
+ """Creates a Panel in the Object properties window"""
+ bl_label = "Previews Example Panel"
+ bl_idname = "OBJECT_PT_previews"
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "object"
+
+ def draw(self, context):
+ layout = self.layout
+ wm = context.window_manager
+
+ row = layout.row()
+ row.prop(wm, "my_previews_dir")
+
+ row = layout.row()
+ row.template_icon_view(wm, "my_previews")
+
+ row = layout.row()
+ row.prop(wm, "my_previews")
+
+
+# We can store multiple preview collections here,
+# however in this example we only store "main"
+preview_collections = {}
+
+
+def register():
+ from bpy.types import WindowManager
+ from bpy.props import (
+ StringProperty,
+ EnumProperty,
+ )
+
+ WindowManager.my_previews_dir = StringProperty(
+ name="Folder Path",
+ subtype='DIR_PATH',
+ default=""
+ )
+
+ WindowManager.my_previews = EnumProperty(
+ items=enum_previews_from_directory_items,
+ )
+
+ # Note that preview collections returned by bpy.utils.previews
+ # are regular Python objects - you can use them to store custom data.
+ #
+ # This is especially useful here, since:
+ # - It avoids us regenerating the whole enum over and over.
+ # - It can store enum_items' strings
+ # (remember you have to keep those strings somewhere in py,
+ # else they get freed and Blender references invalid memory!).
+ import bpy.utils.previews
+ pcoll = bpy.utils.previews.new()
+ pcoll.my_previews_dir = ""
+ pcoll.my_previews = ()
+
+ preview_collections["main"] = pcoll
+
+ bpy.utils.register_class(PreviewsExamplePanel)
+
+
+def unregister():
+ from bpy.types import WindowManager
+
+ del WindowManager.my_previews
+
+ for pcoll in preview_collections.values():
+ bpy.utils.previews.remove(pcoll)
+ preview_collections.clear()
+
+ bpy.utils.unregister_class(PreviewsExamplePanel)
+
+
+if __name__ == "__main__":
+ register()
diff --git a/release/text/readme.html b/release/text/readme.html
index 6dbd3544a56..8e08a8ba027 100644
--- a/release/text/readme.html
+++ b/release/text/readme.html
@@ -3,9 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Style-Type" content="text/css">
- <title></title>
- <meta name="Generator" content="Cocoa HTML Writer">
- <meta name="CocoaVersion" content="1265">
+ <title>Blender Readme</title>
<style type="text/css">
p.p1 {margin: 0.0px 156.0px 22.0px 156.0px; text-align: center; font: 22.0px Helvetica}
p.p2 {margin: 0.0px 0.0px 12.0px 0.0px; font: 12.0px Times; min-height: 14.0px}
@@ -20,18 +18,38 @@
</style>
</head>
<body>
-<p class="p1"><b>Blender 2.73</b></p>
+<p class="p1"><b>Blender BLENDER_VERSION</b></p>
<p class="p2"><br></p>
<p class="p3"><b>About</b></p>
-<p class="p4">Welcome to Blender, the free, open source 3D application for modeling, animation, rendering, compositing, video editing and game creation. Blender is available for Linux, Mac OS X and Windows and has a large world-wide community.</p>
-<p class="p4">Blender can be used freely for any purpose, including commercial use and distribution. It's free and open-source software, released under the GNU GPL licence. The entire source code is available on our website.</p>
-<p class="p4">For more information, visit <a href="http://www.blender.org/"><span class="s1">blender.org</span></a>.</p>
+<p class="p4">
+Welcome to Blender, the free, open source 3D application for modeling, animation, rendering,
+compositing, video editing and game creation.
+Blender is available for Linux, Mac OS X and Windows and has a large world-wide community.
+</p>
+<p class="p4">
+Blender can be used freely for any purpose, including commercial use and distribution.
+It's free and open-source software, released under the GNU GPL licence.
+The entire source code is available on our website.
+</p>
+<p class="p4">
+For more information, visit <a href="http://www.blender.org/"><span class="s1">blender.org</span></a>.
+</p>
<p class="p2"><br></p>
-<p class="p3"><b>2.73</b></p>
-<p class="p4">The Blender Foundation and online developer community is proud to present Blender 2.73. This release is the fourth official stable release of the Blender 2.7 series. <a href="http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.73"><span class="s1">More information about this release</span></a>.</p>
+<p class="p3"><b>BLENDER_VERSION</b></p>
+<p class="p4">
+The Blender Foundation and online developer community is proud to present Blender BLENDER_VERSION.
+<a href="http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/BLENDER_VERSION">
+<span class="s1">More information about this release</span></a>.
+</p>
<p class="p2"><br></p>
<p class="p3"><b>Bugs</b></p>
-<p class="p4">Although Blender 2.73 is considered a stable release, you may encounter a bug. If you do, please help us by posting it in the bug tracker or using Help <span class="s2">→</span> Report a Bug from inside Blender. If it wasn’t reported yet, please log in (or register) and fill in detailed information about the error. Please post detailed instructions on how to reproduce it or post a .blend file showcasing the bug.</p>
+<p class="p4">
+Although this is considered a stable release, you may encounter a bug.
+If you do, please help us by posting it in the bug tracker or using Help
+<span class="s2">→</span> Report a Bug from inside Blender.
+If it wasn’t reported yet, please log in (or register) and fill in detailed information about the error.
+Please post detailed instructions on how to reproduce it or post a .blend file showcasing the bug.
+</p>
<p class="p2"><br></p>
<p class="p3"><b>Package Contents</b></p>
<p class="p4">The downloaded Blender package includes:</p>
@@ -40,31 +58,70 @@
<p class="p4">• Readme and copyright files.</p>
<p class="p2"><br></p>
<p class="p3"><b>Installation</b></p>
-<p class="p4"><b>Windows: </b>The download .zip contains a Blender folder. You may put this anywhere on your hard drive. To launch Blender, double-click on Blender.exe.</p>
-<p class="p4"><b>Linux: </b>Unpack the archive, then run the Blender executable.</p>
-<p class="p4"><b>Mac OS X: </b>The downloaded package includes blender.app. Optionally copy this to your Applications folder, and add it to the dock by dragging it from there to the dock.</p>
+<p class="p4">
+<b>Windows: </b>The download .zip contains a Blender folder. You may put this anywhere on your hard drive.
+To launch Blender, double-click on Blender.exe.
+</p>
+<p class="p4">
+<b>Linux: </b>Unpack the archive, then run the Blender executable.
+</p>
+<p class="p4">
+<b>Mac OS X: </b>The downloaded package includes blender.app.
+Optionally copy this to your Applications folder, and add it to the dock by dragging it from there to the dock.
+</p>
<p class="p2"><br></p>
-<p class="p4"><b>Installing Addons (all systems)</b> Addons can be installed from the user preferences addons section, download an addon as a .py or .zip file, then press the "Install Addon" button and select the file to install it.</p>
+<p class="p4">
+<b>Installing Addons (all systems)</b> Addons can be installed from the user preferences addons section,
+download an addon as a .py or .zip file, then press the "Install Addon" button and select the file to install it.
+</p>
<p class="p2"><br></p>
<p class="p3"><b>Getting Started</b></p>
-<p class="p4">When opening Blender, you’ll see large 3D view in the center, a Toolbar on the left, a Properties editor and an Outliner on the right and a Timeline at the bottom.</p>
-<p class="p4">Orbit around in the 3D view by holding the middle mouse button and dragging. Alternatively, hold the alt key and drag the left mouse button. Additionally, hold Shift to pan the view and Ctrl to zoom.</p>
-<p class="p4">Select objects using the right mouse button. With the object selected, perform actions by clicking any of the tool buttons on the left, or make changes to its properties by altering any of the setting on the right.</p>
-<p class="p4">For more information on how to use Blender, <a href="http://www.blender.org/support/"><span class="s1">check out the support page</span></a>.</p>
+<p class="p4">
+When opening Blender, you’ll see large 3D view in the center, a Toolbar on the left,
+a Properties editor and an Outliner on the right and a Timeline at the bottom.
+</p>
+<p class="p4">
+Orbit around in the 3D view by holding the middle mouse button and dragging.
+Alternatively, hold the alt key and drag the left mouse button.
+Additionally, hold Shift to pan the view and Ctrl to zoom.
+</p>
+<p class="p4">
+Select objects using the right mouse button.
+With the object selected, perform actions by clicking any of the tool buttons on the left,
+or make changes to its properties by altering any of the setting on the right.
+</p>
+<p class="p4">
+For more information on how to use Blender,
+<a href="http://www.blender.org/support/"><span class="s1">check out the support page</span></a>.
+</p>
<p class="p2"><br></p>
<p class="p3"><b>Links</b></p>
<p class="p4">Users:</p>
-<p class="p5"><span class="s3">General information <a href="http://www.blender.org/"><span class="s4">www.blender.org</span></a> <br>
-Full release log <a href="http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.73"><span class="s4">wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.73</span></a><br>
-Tutorials <a href="http://www.blender.org/support/tutorials/"><span class="s4">www.blender.org/support/tutorials/</span></a> <br>
+<p class="p5">
+<span class="s3">General information <a href="http://www.blender.org/">
+<span class="s4">www.blender.org</span></a> <br>
+Full release log <a href="http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/BLENDER_VERSION">
+<span class="s4">wiki.blender.org/index.php/Dev:Ref/Release_Notes/BLENDER_VERSION</span></a><br>
+Tutorials <a href="http://www.blender.org/support/tutorials/">
+<span class="s4">www.blender.org/support/tutorials/</span></a> <br>
Manual <a href="http://www.blender.org/manual"><span class="s4">www.blender.org/manual</span></a><br>
-User Forum <a href="http://www.blenderartists.org/"><span class="s4">www.blenderartists.org</span></a><br>
-IRC <a href="irc://irc.freenode.net/#blenderchat"><span class="s4">#blenderchat</span></a> or <a href="irc://irc.freenode.net/#blender"><span class="s4">#blender</span></a> on irc.freenode.net</span></p>
+User Forum <a href="http://www.blenderartists.org/">
+<span class="s4">www.blenderartists.org</span></a><br>
+IRC <a href="irc://irc.freenode.net/#blenderchat">
+<span class="s4">#blenderchat</span></a> or <a href="irc://irc.freenode.net/#blender">
+<span class="s4">#blender</span></a> on irc.freenode.net</span>
+</p>
<p class="p4">Developers:</p>
-<p class="p5"><span class="s3">Development <a href="http://www.blender.org/get-involved/developers/"><span class="s4">www.blender.org/get-involved/developers/</span></a><br>
-GIT and Bug Tracker <a href="http://developer.blender.org/"><span class="s4">developer.blender.org/</span></a><br>
-Get Involved <a href="http://www.blender.org/get-involved/"><span class="s4">www.blender.org/get-involved/</span></a><br>
-IRC <a href="irc://irc.freenode.net/#blendercoders"><span class="s4">#blendercoders</span></a> on irc.freenode.net</span></p>
+<p class="p5">
+<span class="s3">Development <a href="http://www.blender.org/get-involved/developers/">
+<span class="s4">www.blender.org/get-involved/developers/</span></a><br>
+GIT and Bug Tracker <a href="http://developer.blender.org/">
+<span class="s4">developer.blender.org/</span></a><br>
+Get Involved <a href="http://www.blender.org/get-involved/">
+<span class="s4">www.blender.org/get-involved/</span></a><br>
+IRC <a href="irc://irc.freenode.net/#blendercoders">
+<span class="s4">#blendercoders</span></a> on irc.freenode.net</span>
+</p>
<p class="p2"><br></p>
<p class="p2"><br></p>
<p class="p6">Blender is open-source and free for all to use.</p>
diff --git a/release/windows/installer/00.sconsblender.nsi b/release/windows/installer/00.sconsblender.nsi
index f6e5b783faa..2d91b9da7f1 100644
--- a/release/windows/installer/00.sconsblender.nsi
+++ b/release/windows/installer/00.sconsblender.nsi
@@ -70,6 +70,13 @@ InstallDir $INSTDIR ; $INSTDIR is set inside .onInit
BrandingText "Blender Foundation | http://www.blender.org"
ComponentText "This will install Blender [VERSION] on your computer."
+VIAddVersionKey "ProductName" "Blender"
+VIAddVersionKey "CompanyName" "http://www.blender.org"
+VIAddVersionKey "FileDescription" "Free open source 3D content creation suite."
+VIAddVersionKey "FileVersion" "[SHORTVERSION].0.0"
+
+VIProductVersion "[SHORTVERSION].0.0"
+
DirText "Use the field below to specify the folder where you want Blender to be copied to. To specify a different folder, type a new name or use the Browse button to select an existing folder."
SilentUnInstall normal
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index bdea88eb818..10a9e6f2034 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -31,6 +31,7 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_armature_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_boid_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_brush_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cache_library_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_camera_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cloth_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_color_types.h
@@ -79,6 +80,7 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sound_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_space_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_speaker_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_strands_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_text_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_texture_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_userdef_types.h
@@ -103,12 +105,14 @@ add_subdirectory(bmesh)
add_subdirectory(render)
add_subdirectory(blenfont)
add_subdirectory(blenloader)
+add_subdirectory(depsgraph)
add_subdirectory(ikplugin)
add_subdirectory(physics)
add_subdirectory(gpu)
add_subdirectory(imbuf)
add_subdirectory(nodes)
add_subdirectory(modifiers)
+add_subdirectory(pointcache)
add_subdirectory(makesdna)
add_subdirectory(makesrna)
diff --git a/source/blender/SConscript b/source/blender/SConscript
index 64eca6a62db..9bdba768448 100644
--- a/source/blender/SConscript
+++ b/source/blender/SConscript
@@ -33,6 +33,7 @@ SConscript(['avi/SConscript',
'blenkernel/SConscript',
'blenlib/SConscript',
'blenloader/SConscript',
+ 'depsgraph/SConscript',
'gpu/SConscript',
'editors/SConscript',
'imbuf/SConscript',
@@ -43,7 +44,8 @@ SConscript(['avi/SConscript',
'ikplugin/SConscript',
'physics/SConscript',
'windowmanager/SConscript',
- 'blenfont/SConscript'])
+ 'blenfont/SConscript',
+ 'pointcache/SConscript'])
makesrna = SConscript('makesrna/SConscript')
diff --git a/source/blender/avi/AVI_avi.h b/source/blender/avi/AVI_avi.h
index 44ffaad1f48..5e9fe378c38 100644
--- a/source/blender/avi/AVI_avi.h
+++ b/source/blender/avi/AVI_avi.h
@@ -28,18 +28,17 @@
/** \file AVI_avi.h
* \ingroup avi
- * \section aviabout AVI module external interface
*
- * \subsection about About the AVI module
+ * \section avi_about About the AVI module
*
* This is external code. It provides avi file import/export and
* conversions. It has been adapted to make use of Blender memory
* management functions, and because of this it needs module
* blenlib. You need to provide this lib when linking with libavi.a .
*
- * \subsection issues Known issues with AVI
+ * \subsection avi_issues Known issues with AVI
*
- * - avi uses mallocN, freeN from blenlib.
+ * - avi uses #MEM_mallocN, #MEM_freeN from blenlib.
* - Not all functions that are used externally are properly
* prototyped.
*
diff --git a/source/blender/avi/intern/avi_mjpeg.c b/source/blender/avi/intern/avi_mjpeg.c
index 857501c5796..1fa9da6b3a2 100644
--- a/source/blender/avi/intern/avi_mjpeg.c
+++ b/source/blender/avi/intern/avi_mjpeg.c
@@ -290,17 +290,6 @@ static void deinterlace(int odd, unsigned char *to, unsigned char *from, int wid
}
}
-static int check_and_decode_jpeg(unsigned char *inbuf, unsigned char *outbuf, int width, int height, int bufsize)
-{
- return Decode_JPEG(inbuf, outbuf, width, height, bufsize);
-}
-
-static void check_and_compress_jpeg(int quality, unsigned char *outbuf, const unsigned char *inbuf,
- int width, int height, int bufsize)
-{
- Compress_JPEG(quality, outbuf, inbuf, width, height, bufsize);
-}
-
void *avi_converter_from_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, int *size)
{
int deint;
@@ -310,7 +299,7 @@ void *avi_converter_from_mjpeg(AviMovie *movie, int stream, unsigned char *buffe
buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_from_mjpeg 1");
- deint = check_and_decode_jpeg(buffer, buf, movie->header->Width, movie->header->Height, *size);
+ deint = Decode_JPEG(buffer, buf, movie->header->Width, movie->header->Height, *size);
MEM_freeN(buffer);
@@ -335,11 +324,11 @@ void *avi_converter_to_mjpeg(AviMovie *movie, int stream, unsigned char *buffer,
buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_to_mjpeg 1");
if (!movie->interlace) {
- check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100,
- buf, buffer,
- movie->header->Width,
- movie->header->Height,
- bufsize);
+ Compress_JPEG(movie->streams[stream].sh.Quality / 100,
+ buf, buffer,
+ movie->header->Width,
+ movie->header->Height,
+ bufsize);
}
else {
deinterlace(movie->odd_fields, buf, buffer, movie->header->Width, movie->header->Height);
@@ -348,18 +337,18 @@ void *avi_converter_to_mjpeg(AviMovie *movie, int stream, unsigned char *buffer,
buffer = buf;
buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_to_mjpeg 2");
- check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100,
- buf, buffer,
- movie->header->Width,
- movie->header->Height / 2,
- bufsize / 2);
+ Compress_JPEG(movie->streams[stream].sh.Quality / 100,
+ buf, buffer,
+ movie->header->Width,
+ movie->header->Height / 2,
+ bufsize / 2);
*size += numbytes;
numbytes = 0;
- check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100,
- buf + *size, buffer + (movie->header->Height / 2) * movie->header->Width * 3,
- movie->header->Width,
- movie->header->Height / 2,
- bufsize / 2);
+ Compress_JPEG(movie->streams[stream].sh.Quality / 100,
+ buf + *size, buffer + (movie->header->Height / 2) * movie->header->Width * 3,
+ movie->header->Width,
+ movie->header->Height / 2,
+ bufsize / 2);
}
*size += numbytes;
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index 206345582b2..09734bd9754 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -186,6 +186,12 @@ char **BLF_dir_get(int *ndir) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* Free the data return by BLF_dir_get. */
void BLF_dir_free(char **dirs, int count) ATTR_NONNULL();
+/* blf_thumbs.c */
+void BLF_thumb_preview(
+ const char *filename, const char **draw_str, const unsigned char draw_str_lines,
+ const float font_color[4], const int font_size,
+ unsigned char *buf, int w, int h, int channels) ATTR_NONNULL();
+
#ifdef DEBUG
void BLF_state_print(int fontid);
#endif
diff --git a/source/blender/blenfont/BLF_translation.h b/source/blender/blenfont/BLF_translation.h
index b42e6f80022..badfe1f4a4c 100644
--- a/source/blender/blenfont/BLF_translation.h
+++ b/source/blender/blenfont/BLF_translation.h
@@ -79,9 +79,11 @@ bool BLF_is_default_context(const char *msgctxt);
const char *BLF_pgettext(const char *msgctxt, const char *msgid);
/* translation */
+bool BLF_translate(void);
bool BLF_translate_iface(void);
bool BLF_translate_tooltips(void);
bool BLF_translate_new_dataname(void);
+const char *BLF_translate_do(const char *msgctxt, const char *msgid);
const char *BLF_translate_do_iface(const char *msgctxt, const char *msgid);
const char *BLF_translate_do_tooltip(const char *msgctxt, const char *msgid);
const char *BLF_translate_do_new_dataname(const char *msgctxt, const char *msgid);
@@ -146,6 +148,7 @@ const char *BLF_translate_do_new_dataname(const char *msgctxt, const char *msgid
#define BLF_I18NCONTEXT_ID_ACTION "Action"
#define BLF_I18NCONTEXT_ID_ARMATURE "Armature"
#define BLF_I18NCONTEXT_ID_BRUSH "Brush"
+#define BLF_I18NCONTEXT_ID_CACHELIBRARY "CacheLibrary"
#define BLF_I18NCONTEXT_ID_CAMERA "Camera"
#define BLF_I18NCONTEXT_ID_CURVE "Curve"
#define BLF_I18NCONTEXT_ID_FREESTYLELINESTYLE "FreestyleLineStyle"
@@ -180,8 +183,7 @@ const char *BLF_translate_do_new_dataname(const char *msgctxt, const char *msgid
#define BLF_I18NCONTEXT_ID_MASK "Mask"
/* Helper for bpy.app.i18n object... */
-typedef struct
-{
+typedef struct {
const char *c_id;
const char *py_id;
const char *value;
diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt
index 392a9ede100..059e2cac680 100644
--- a/source/blender/blenfont/CMakeLists.txt
+++ b/source/blender/blenfont/CMakeLists.txt
@@ -29,7 +29,6 @@ set(INC
../gpu
../makesdna
../makesrna
- ../python
../imbuf
../../../intern/guardedalloc
../../../intern/glew-mx
@@ -47,6 +46,7 @@ set(SRC
intern/blf_font.c
intern/blf_glyph.c
intern/blf_lang.c
+ intern/blf_thumbs.c
intern/blf_translation.c
intern/blf_util.c
@@ -66,7 +66,13 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_PYTHON)
+ add_definitions(-DWITH_PYTHON)
+ list(APPEND INC
+ ../python
+ )
+endif()
+
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_blenfont "${SRC}" "${INC}" "${INC_SYS}")
-
diff --git a/source/blender/blenfont/SConscript b/source/blender/blenfont/SConscript
index b6cf052a980..61d2ca9b12d 100644
--- a/source/blender/blenfont/SConscript
+++ b/source/blender/blenfont/SConscript
@@ -44,7 +44,6 @@ incs = [
'../imbuf',
'../makesdna',
'../makesrna',
- '../python',
]
incs.extend(Split(env['BF_FREETYPE_INC']))
@@ -57,6 +56,10 @@ if sys.platform == 'win32' or env['OURPLATFORM'] == 'linuxcross':
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_PYTHON']:
+ defs.append('WITH_PYTHON')
+ incs.append('../python')
+
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs.append(env['BF_PTHREADS_INC'])
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 087c7c7345e..2057b0f6bbf 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -286,10 +286,9 @@ void blf_font_buffer(FontBLF *font, const char *str)
(unsigned char)(buf_info->col[2] * 255),
(unsigned char)(buf_info->col[3] * 255)};
- unsigned char *cbuf;
int chx, chy;
int y, x;
- float a, *fbuf;
+ float a;
BLF_KERNING_VARS(font, has_kerning, kern_mode);
@@ -349,8 +348,12 @@ void blf_font_buffer(FontBLF *font, const char *str)
a = *(g->bitmap + x + (yb * g->pitch)) / 255.0f;
if (a > 0.0f) {
+ const size_t buf_ofs = (
+ ((size_t)(chx + x) + ((size_t)(pen_y + y) * (size_t)buf_info->w)) *
+ (size_t)buf_info->ch);
+ float *fbuf = buf_info->fbuf + buf_ofs;
float alphatest;
- fbuf = buf_info->fbuf + buf_info->ch * ((chx + x) + ((pen_y + y) * buf_info->w));
+
if (a >= 1.0f) {
fbuf[0] = b_col_float[0];
fbuf[1] = b_col_float[1];
@@ -375,13 +378,17 @@ void blf_font_buffer(FontBLF *font, const char *str)
if (buf_info->cbuf) {
int yb = yb_start;
- for (y = 0; y < height_clip; y++) {
- for (x = 0; x < width_clip; x++) {
+ for (y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
+ for (x = ((chx >= 0) ? 0 : -chx); x < width_clip; x++) {
a = *(g->bitmap + x + (yb * g->pitch)) / 255.0f;
if (a > 0.0f) {
+ const size_t buf_ofs = (
+ ((size_t)(chx + x) + ((size_t)(pen_y + y) * (size_t)buf_info->w)) *
+ (size_t)buf_info->ch);
+ unsigned char *cbuf = buf_info->cbuf + buf_ofs;
int alphatest;
- cbuf = buf_info->cbuf + buf_info->ch * ((chx + x) + ((pen_y + y) * buf_info->w));
+
if (a >= 1.0f) {
cbuf[0] = b_col_char[0];
cbuf[1] = b_col_char[1];
@@ -667,6 +674,28 @@ float blf_font_fixed_width(FontBLF *font)
return g->advance;
}
+int blf_font_count_missing_chars(FontBLF *font, const char *str, const size_t len, int *r_tot_chars)
+{
+ int missing = 0;
+ size_t i = 0;
+
+ *r_tot_chars = 0;
+ while (i < len) {
+ unsigned int c;
+
+ if ((c = str[i]) < 0x80) {
+ i++;
+ }
+ else if ((c = BLI_str_utf8_as_unicode_step(str, &i)) != BLI_UTF8_ERR) {
+ if (FT_Get_Char_Index((font)->face, c) == 0) {
+ missing++;
+ }
+ }
+ (*r_tot_chars)++;
+ }
+ return missing;
+}
+
void blf_font_free(FontBLF *font)
{
GlyphCacheBLF *gc;
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index c65a0825a49..215d2484c18 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -199,7 +199,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
GlyphBLF *g;
FT_Error err;
FT_Bitmap bitmap, tempbitmap;
- int sharp = (U.text_render & USER_TEXT_DISABLE_AA);
+ const bool is_sharp = (U.text_render & USER_TEXT_DISABLE_AA) != 0;
int flags = FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP;
FT_BBox bbox;
unsigned int key;
@@ -224,7 +224,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
if (font->flags & BLF_HINTING)
flags &= ~FT_LOAD_NO_HINTING;
- if (sharp)
+ if (is_sharp)
err = FT_Load_Glyph(font->face, (FT_UInt)index, FT_LOAD_TARGET_MONO);
else
err = FT_Load_Glyph(font->face, (FT_UInt)index, flags);
@@ -237,7 +237,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
/* get the glyph. */
slot = font->face->glyph;
- if (sharp) {
+ if (is_sharp) {
err = FT_Render_Glyph(slot, FT_RENDER_MODE_MONO);
/* Convert result from 1 bit per pixel to 8 bit per pixel */
@@ -266,7 +266,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
g->height = (int)bitmap.rows;
if (g->width && g->height) {
- if (sharp) {
+ if (is_sharp) {
/* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range */
int i;
for (i = 0; i < (g->width * g->height); i++) {
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index 39b3e3397be..85410a4d856 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -62,6 +62,9 @@ void blf_font_width_and_height(struct FontBLF *font, const char *str, size_t len
float blf_font_width(struct FontBLF *font, const char *str, size_t len);
float blf_font_height(struct FontBLF *font, const char *str, size_t len);
float blf_font_fixed_width(struct FontBLF *font);
+
+int blf_font_count_missing_chars(struct FontBLF *font, const char *str, const size_t len, int *r_tot_chars);
+
void blf_font_free(struct FontBLF *font);
struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font, unsigned int size, unsigned int dpi);
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index da756d65483..1404b9de250 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -48,7 +48,7 @@ typedef struct GlyphCacheBLF {
struct GlyphBLF *glyph_ascii_table[256];
/* texture array, to draw the glyphs. */
- GLuint *textures;
+ unsigned int *textures;
/* size of the array. */
unsigned int ntex;
@@ -103,7 +103,7 @@ typedef struct GlyphBLF {
int advance_i;
/* texture id where this glyph is store. */
- GLuint tex;
+ unsigned int tex;
/* position inside the texture where this glyph is store. */
int xoff;
diff --git a/source/blender/blenfont/intern/blf_lang.c b/source/blender/blenfont/intern/blf_lang.c
index 99e1aa5d3e3..4683081a1ed 100644
--- a/source/blender/blenfont/intern/blf_lang.c
+++ b/source/blender/blenfont/intern/blf_lang.c
@@ -284,12 +284,15 @@ void BLF_lang_set(const char *str)
const char *BLF_lang_get(void)
{
#ifdef WITH_INTERNATIONAL
- const char *locale = LOCALE(ULANGUAGE);
- if (locale[0] == '\0') {
- /* Default locale, we have to find which one we are actually using! */
- locale = bl_locale_get();
+ if (BLF_translate()) {
+ const char *locale = LOCALE(ULANGUAGE);
+ if (locale[0] == '\0') {
+ /* Default locale, we have to find which one we are actually using! */
+ locale = bl_locale_get();
+ }
+ return locale;
}
- return locale;
+ return "en_US"; /* Kind of default locale in Blender when no translation enabled. */
#else
return "";
#endif
diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c
new file mode 100644
index 00000000000..4b7a568b8b0
--- /dev/null
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -0,0 +1,121 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Thomas Beck
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenfont/intern/blf_thumbs.c
+ * \ingroup blf
+ *
+ * Utility function to generate font preview images.
+ *
+ * Isolate since this needs to be called by #ImBuf code (bad level call).
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <ft2build.h>
+
+#include FT_FREETYPE_H
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_rect.h"
+#include "BLI_threads.h"
+
+#include "blf_internal.h"
+#include "blf_internal_types.h"
+
+#include "BLF_api.h"
+#include "BLF_translation.h"
+
+#include "BLI_strict_flags.h"
+
+/**
+ * This function is used for generating thumbnail previews.
+ *
+ * \note called from a thread, so it bypasses the normal BLF_* api (which isn't thread-safe).
+ */
+void BLF_thumb_preview(
+ const char *filename,
+ const char **draw_str, const unsigned char draw_str_lines,
+ const float font_color[4], const int font_size,
+ unsigned char *buf, int w, int h, int channels)
+{
+ const unsigned int dpi = 72;
+ const int font_size_min = 6;
+ int font_size_curr;
+ /* shrink 1/th each line */
+ int font_shrink = 4;
+
+ FontBLF *font;
+ int i;
+
+ /* Create a new blender font obj and fill it with default values */
+ font = blf_font_new("thumb_font", filename);
+ if (!font) {
+ printf("Info: Can't load font '%s', no preview possible\n", filename);
+ return;
+ }
+
+ /* Would be done via the BLF API, but we're not using a fontid here */
+ font->buf_info.cbuf = buf;
+ font->buf_info.ch = channels;
+ font->buf_info.w = w;
+ font->buf_info.h = h;
+
+ /* Always create the image with a white font,
+ * the caller can theme how it likes */
+ memcpy(font->buf_info.col, font_color, sizeof(font->buf_info.col));
+ font->pos[1] = (float)h;
+
+ font_size_curr = font_size;
+
+ for (i = 0; i < draw_str_lines; i++) {
+ const char *draw_str_i18n = BLF_translate_do(BLF_I18NCONTEXT_DEFAULT, draw_str[i]);
+ const size_t draw_str_i18n_len = strlen(draw_str_i18n);
+ int draw_str_i18n_nbr = 0;
+
+ blf_font_size(font, (unsigned int)MAX2(font_size_min, font_size_curr), dpi);
+
+ /* decrease font size each time */
+ font_size_curr -= (font_size_curr / font_shrink);
+ font_shrink += 1;
+
+ font->pos[1] -= font->glyph_cache->ascender * 1.1f;
+
+ /* We fallback to default english strings in case not enough chars are available in current font for given
+ * translated string (useful in non-latin i18n context, like chinese, since many fonts will then show
+ * nothing but ugly 'missing char' in their preview).
+ * Does not handle all cases, but much better than nothing.
+ */
+ if (blf_font_count_missing_chars(
+ font, draw_str_i18n, draw_str_i18n_len, &draw_str_i18n_nbr) > (draw_str_i18n_nbr / 2))
+ {
+ blf_font_buffer(font, draw_str[i]);
+ }
+ else {
+ blf_font_buffer(font, draw_str_i18n);
+ }
+ }
+
+ blf_font_free(font);
+}
diff --git a/source/blender/blenfont/intern/blf_translation.c b/source/blender/blenfont/intern/blf_translation.c
index 2a4a152f0eb..5d828d9b7be 100644
--- a/source/blender/blenfont/intern/blf_translation.c
+++ b/source/blender/blenfont/intern/blf_translation.c
@@ -46,7 +46,9 @@
#include "DNA_userdef_types.h" /* For user settings. */
+#ifdef WITH_PYTHON
#include "BPY_extern.h"
+#endif
#ifdef WITH_INTERNATIONAL
@@ -152,9 +154,11 @@ const char *BLF_pgettext(const char *msgctxt, const char *msgid)
/* We assume if the returned string is the same (memory level) as the msgid, no translation was found,
* and we can try py scripts' ones!
*/
+#ifdef WITH_PYTHON
if (ret == msgid) {
ret = BPY_app_translations_py_pgettext(msgctxt, msgid);
}
+#endif
}
return ret;
@@ -164,6 +168,15 @@ const char *BLF_pgettext(const char *msgctxt, const char *msgid)
#endif
}
+bool BLF_translate(void)
+{
+#ifdef WITH_INTERNATIONAL
+ return (U.transopts & USER_DOTRANSLATE) != 0;
+#else
+ return false;
+#endif
+}
+
bool BLF_translate_iface(void)
{
#ifdef WITH_INTERNATIONAL
@@ -191,6 +204,21 @@ bool BLF_translate_new_dataname(void)
#endif
}
+const char *BLF_translate_do(const char *msgctxt, const char *msgid)
+{
+#ifdef WITH_INTERNATIONAL
+ if (BLF_translate()) {
+ return BLF_pgettext(msgctxt, msgid);
+ }
+ else {
+ return msgid;
+ }
+#else
+ (void)msgctxt;
+ return msgid;
+#endif
+}
+
const char *BLF_translate_do_iface(const char *msgctxt, const char *msgid)
{
#ifdef WITH_INTERNATIONAL
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index a026cc2e76e..65e7d47c46c 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -97,7 +97,6 @@ struct ColorBand;
struct GPUVertexAttribs;
struct GPUDrawObject;
struct BMEditMesh;
-struct ListBase;
struct PBVH;
/* number of sub-elements each mesh element has (for interpolation) */
@@ -115,11 +114,6 @@ typedef struct DMCoNo {
float no[3];
} DMCoNo;
-typedef struct DMGridAdjacency {
- int index[4];
- int rotation[4];
-} DMGridAdjacency;
-
/* keep in sync with MFace/MPoly types */
typedef struct DMFlagMat {
short mat_nr;
@@ -291,7 +285,6 @@ struct DerivedMesh {
int (*getNumGrids)(DerivedMesh *dm);
int (*getGridSize)(DerivedMesh *dm);
struct CCGElem **(*getGridData)(DerivedMesh * dm);
- DMGridAdjacency *(*getGridAdjacency)(DerivedMesh * dm);
int *(*getGridOffset)(DerivedMesh * dm);
void (*getGridKey)(DerivedMesh *dm, struct CCGKey *key);
DMFlagMat *(*getGridFlagMats)(DerivedMesh * dm);
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 57ba6fd55ca..fdb465f7105 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -46,8 +46,6 @@ struct bItasc;
struct bPoseChannel;
struct Main;
struct Object;
-struct Scene;
-struct ID;
/* Kernel prototypes */
#ifdef __cplusplus
@@ -161,6 +159,9 @@ void extract_pose_from_pose(struct bPose *pose, const struct bPose *src);
/* sets constraint flags */
void BKE_pose_update_constraint_flags(struct bPose *pose);
+/* tag constraint flags for update */
+void BKE_pose_tag_update_constraint_flags(struct bPose *pose);
+
/* return the name of structure pointed by pose->ikparam */
const char *BKE_pose_ikparam_get_name(struct bPose *pose);
@@ -197,6 +198,9 @@ bool BKE_pose_copy_result(struct bPose *to, struct bPose *from);
/* clear all transforms */
void BKE_pose_rest(struct bPose *pose);
+/* Tag pose for recalc. Also tag all related data to be recalc. */
+void BKE_pose_tag_recalc(struct Main *bmain, struct bPose *pose);
+
#ifdef __cplusplus
};
#endif
diff --git a/source/blender/blenkernel/BKE_addon.h b/source/blender/blenkernel/BKE_addon.h
index 9c09fffe0a0..74c1edd1c1b 100644
--- a/source/blender/blenkernel/BKE_addon.h
+++ b/source/blender/blenkernel/BKE_addon.h
@@ -38,7 +38,7 @@ typedef struct bAddonPrefType {
bAddonPrefType *BKE_addon_pref_type_find(const char *idname, bool quiet);
void BKE_addon_pref_type_add(bAddonPrefType *apt);
-void BKE_addon_pref_type_remove(bAddonPrefType *apt);
+void BKE_addon_pref_type_remove(const bAddonPrefType *apt);
void BKE_addon_pref_type_init(void);
void BKE_addon_pref_type_free(void);
diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h
index d1a5bcbf8aa..90af9a15a97 100644
--- a/source/blender/blenkernel/BKE_anim.h
+++ b/source/blender/blenkernel/BKE_anim.h
@@ -36,13 +36,21 @@ struct bContext;
struct EvaluationContext;
struct Path;
struct Object;
-struct PartEff;
struct Scene;
struct ListBase;
struct bAnimVizSettings;
struct bMotionPath;
struct bPoseChannel;
struct ReportList;
+struct GHash;
+struct DupliCache;
+struct DupliObject;
+struct DupliObjectData;
+struct DerivedMesh;
+struct Strands;
+struct StrandsChildren;
+struct DupliCacheIterator;
+struct CacheLibrary;
/* ---------------------------------------------------- */
/* Animation Visualization */
@@ -68,11 +76,43 @@ int where_on_path(struct Object *ob, float ctime, float vec[4], float dir[3], fl
/* ---------------------------------------------------- */
/* Dupli-Geometry */
-struct ListBase *object_duplilist_ex(struct EvaluationContext *eval_ctx, struct Scene *sce, struct Object *ob, bool update);
-struct ListBase *object_duplilist(struct EvaluationContext *eval_ctx, struct Scene *sce, struct Object *ob);
+struct ListBase *object_duplilist_ex(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, bool update);
+struct ListBase *object_duplilist(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob);
+struct ListBase *group_duplilist_ex(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Group *group, bool update);
+struct ListBase *group_duplilist(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Group *group);
void free_object_duplilist(struct ListBase *lb);
int count_duplilist(struct Object *ob);
+void BKE_object_dupli_cache_update(struct Scene *scene, struct Object *ob, struct EvaluationContext *eval_ctx, float frame);
+void BKE_object_dupli_cache_clear(struct Object *ob);
+void BKE_object_dupli_cache_free(struct Object *ob);
+bool BKE_object_dupli_cache_contains(struct Object *ob, struct Object *other);
+struct DupliObjectData *BKE_dupli_cache_find_data(struct DupliCache *dupcache, struct Object *ob);
+
+void BKE_dupli_object_data_init(struct DupliObjectData *data, struct Object *ob);
+/* does not free data itself */
+void BKE_dupli_object_data_clear(struct DupliObjectData *data);
+void BKE_dupli_object_data_set_mesh(struct DupliObjectData *data, struct DerivedMesh *dm);
+void BKE_dupli_object_data_add_strands(struct DupliObjectData *data, const char *name, struct Strands *strands);
+void BKE_dupli_object_data_add_strands_children(struct DupliObjectData *data, const char *name, struct StrandsChildren *children);
+void BKE_dupli_object_data_find_strands(struct DupliObjectData *data, const char *name, struct Strands **r_strands, struct StrandsChildren **r_children);
+bool BKE_dupli_object_data_acquire_strands(struct DupliObjectData *data, struct Strands *strands);
+bool BKE_dupli_object_data_acquire_strands_children(struct DupliObjectData *data, struct StrandsChildren *children);
+
+struct DupliCache *BKE_dupli_cache_new(void);
+void BKE_dupli_cache_free(struct DupliCache *dupcache);
+void BKE_dupli_cache_clear(struct DupliCache *dupcache);
+void BKE_dupli_cache_clear_instances(struct DupliCache *dupcache);
+struct DupliObjectData *BKE_dupli_cache_add_object(struct DupliCache *dupcache, struct Object *ob);
+struct DupliObject *BKE_dupli_cache_add_instance(struct DupliCache *dupcache, float obmat[4][4], struct DupliObjectData *data);
+void BKE_dupli_cache_from_group(struct Scene *scene, struct Group *group, struct CacheLibrary *cachelib, struct DupliCache *dupcache, struct EvaluationContext *eval_ctx, bool calc_strands_base);
+
+struct DupliCacheIterator *BKE_dupli_cache_iter_new(struct DupliCache *dupcache);
+void BKE_dupli_cache_iter_free(struct DupliCacheIterator *iter);
+bool BKE_dupli_cache_iter_valid(struct DupliCacheIterator *iter);
+void BKE_dupli_cache_iter_next(struct DupliCacheIterator *iter);
+struct DupliObjectData *BKE_dupli_cache_iter_get(struct DupliCacheIterator *iter);
+
typedef struct DupliExtraData {
float obmat[4][4];
unsigned int lay;
@@ -83,7 +123,7 @@ typedef struct DupliApplyData {
DupliExtraData *extra;
} DupliApplyData;
-DupliApplyData *duplilist_apply(struct Object *ob, struct ListBase *duplilist);
+DupliApplyData *duplilist_apply(struct Object *ob, struct Scene *scene, struct ListBase *duplilist);
void duplilist_restore(struct ListBase *duplilist, DupliApplyData *apply_data);
void duplilist_free_apply_data(DupliApplyData *apply_data);
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 0acfd40a110..dc751747f32 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -56,22 +56,22 @@ bool id_type_can_have_animdata(struct ID *id);
struct AnimData *BKE_animdata_from_id(struct ID *id);
/* Add AnimData to the given ID-block */
-struct AnimData *BKE_id_add_animdata(struct ID *id);
+struct AnimData *BKE_animdata_add_id(struct ID *id);
/* Set active action used by AnimData from the given ID-block */
bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act);
/* Free AnimData */
-void BKE_free_animdata(struct ID *id);
+void BKE_animdata_free(struct ID *id);
/* Copy AnimData */
-struct AnimData *BKE_copy_animdata(struct AnimData *adt, const bool do_action);
+struct AnimData *BKE_animdata_copy(struct AnimData *adt, const bool do_action);
/* Copy AnimData */
-bool BKE_copy_animdata_id(struct ID *id_to, struct ID *id_from, const bool do_action);
+bool BKE_animdata_copy_id(struct ID *id_to, struct ID *id_from, const bool do_action);
/* Copy AnimData Actions */
-void BKE_copy_animdata_id_action(struct ID *id);
+void BKE_animdata_copy_id_action(struct ID *id);
/* Merge copies of data from source AnimData block */
typedef enum eAnimData_MergeCopy_Modes {
@@ -91,7 +91,7 @@ void BKE_animdata_merge_copy(struct ID *dst_id, struct ID *src_id, eAnimData_Mer
void BKE_animdata_make_local(struct AnimData *adt);
/* Re-Assign ID's */
-void BKE_relink_animdata(struct AnimData *adt);
+void BKE_animdata_relink(struct AnimData *adt);
/* ************************************* */
/* KeyingSets API */
@@ -134,7 +134,7 @@ void BKE_animdata_fix_paths_rename(struct ID *owner_id, struct AnimData *adt, st
bool verify_paths);
/* Fix all the paths for the entire database... */
-void BKE_all_animdata_fix_paths_rename(ID *ref_id, const char *prefix, const char *oldName, const char *newName);
+void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const char *oldName, const char *newName);
/* Fix the path after removing elements that are not ID (e.g., node) */
void BKE_animdata_fix_paths_remove(struct ID *id, const char *path);
@@ -175,6 +175,9 @@ void BKE_animsys_evaluate_animdata(struct Scene *scene, struct ID *id, struct An
/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only */
void BKE_animsys_evaluate_all_animation(struct Main *main, struct Scene *scene, float ctime);
+/* TODO(sergey): This is mainly a temp public function. */
+struct FCurve;
+bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct AnimMapper *remap, struct FCurve *fcu);
/* ------------ Specialized API --------------- */
/* There are a few special tools which require these following functions. They are NOT to be used
@@ -192,4 +195,13 @@ void animsys_evaluate_action_group(struct PointerRNA *ptr, struct bAction *act,
/* ************************************* */
+/* ------------ Evaluation API --------------- */
+
+struct EvaluationContext;
+
+void BKE_animsys_eval_animdata(struct EvaluationContext *eval_ctx, struct ID *id);
+void BKE_animsys_eval_driver(struct EvaluationContext *eval_ctx, struct ID *id, struct FCurve *fcurve);
+
+/* ************************************* */
+
#endif /* __BKE_ANIMSYS_H__*/
diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h
index 5e42f17be03..077fe2a629c 100644
--- a/source/blender/blenkernel/BKE_appdir.h
+++ b/source/blender/blenkernel/BKE_appdir.h
@@ -38,6 +38,11 @@ void BKE_appdir_program_path_init(const char *argv0);
const char *BKE_appdir_program_path(void);
const char *BKE_appdir_program_dir(void);
+/* find python executable */
+bool BKE_appdir_program_python_search(
+ char *fullpath, const size_t fullpath_len,
+ const int version_major, const int version_minor);
+
/* Initialize path to temporary directory. */
void BKE_tempdir_init(char *userdir);
void BKE_tempdir_system_init(char *dir);
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 66e204e51e0..a834a83ca00 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -36,13 +36,10 @@
struct Bone;
struct Main;
struct bArmature;
-struct bPose;
struct bPoseChannel;
struct bConstraint;
struct Scene;
struct Object;
-struct MDeformVert;
-struct Mesh;
struct PoseTree;
struct ListBase;
@@ -145,6 +142,57 @@ void b_bone_spline_setup(struct bPoseChannel *pchan, int rest, Mat4 result_array
#define PBONE_SELECTABLE(arm, bone) \
(PBONE_VISIBLE(arm, bone) && !((bone)->flag & BONE_UNSELECTABLE))
+/* Evaluation helpers */
+struct bKinematicConstraint;
+struct bPose;
+struct bSplineIKConstraint;
+struct EvaluationContext;
+
+struct bPoseChannel *BKE_armature_ik_solver_find_root(
+ struct bPoseChannel *pchan,
+ struct bKinematicConstraint *data);
+struct bPoseChannel *BKE_armature_splineik_solver_find_root(
+ struct bPoseChannel *pchan,
+ struct bSplineIKConstraint *data);
+
+void BKE_pose_splineik_init_tree(struct Scene *scene, struct Object *ob, float ctime);
+void BKE_splineik_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan_root, float ctime);
+
+void BKE_pose_eval_init(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob,
+ struct bPose *pose);
+
+void BKE_pose_eval_bone(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob,
+ struct bPoseChannel *pchan);
+
+void BKE_pose_constraints_evaluate(struct EvaluationContext *eval_ctx,
+ struct Object *ob,
+ struct bPoseChannel *pchan);
+
+void BKE_pose_bone_done(struct EvaluationContext *eval_ctx,
+ struct bPoseChannel *pchan);
+
+void BKE_pose_iktree_evaluate(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob,
+ struct bPoseChannel *rootchan);
+
+void BKE_pose_splineik_evaluate(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob,
+ struct bPoseChannel *rootchan);
+
+void BKE_pose_eval_flush(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob,
+ struct bPose *pose);
+
+void BKE_pose_eval_proxy_copy(struct EvaluationContext *eval_ctx,
+ struct Object *ob);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index 63cc9213b2e..80332c08fc2 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -41,9 +41,9 @@ extern "C" {
/* these lines are grep'd, watch out for our not-so-awesome regex
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
-#define BLENDER_VERSION 273
-#define BLENDER_SUBVERSION 9
-/* 262 was the last editmesh release but it has compatibility code for bmesh data */
+#define BLENDER_VERSION 274
+#define BLENDER_SUBVERSION 5
+/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 5
@@ -55,7 +55,6 @@ extern "C" {
extern char versionstr[]; /* from blender.c */
-struct ListBase;
struct MemFile;
struct bContext;
struct ReportList;
@@ -88,21 +87,21 @@ void BKE_userdef_free(void);
void BKE_userdef_state(void);
/* set this callback when a UI is running */
-void set_blender_test_break_cb(void (*func)(void));
+void BKE_blender_callback_test_break_set(void (*func)(void));
int blender_test_break(void);
#define BKE_UNDO_STR_MAX 64
/* global undo */
-extern void BKE_write_undo(struct bContext *C, const char *name);
-extern void BKE_undo_step(struct bContext *C, int step);
-extern void BKE_undo_name(struct bContext *C, const char *name);
-extern int BKE_undo_valid(const char *name);
-extern void BKE_reset_undo(void);
-extern void BKE_undo_number(struct bContext *C, int nr);
-extern const char *BKE_undo_get_name(int nr, int *active);
-extern bool BKE_undo_save_file(const char *filename);
-extern struct Main *BKE_undo_get_main(struct Scene **scene);
+extern void BKE_undo_write(struct bContext *C, const char *name);
+extern void BKE_undo_step(struct bContext *C, int step);
+extern void BKE_undo_name(struct bContext *C, const char *name);
+extern bool BKE_undo_is_valid(const char *name);
+extern void BKE_undo_reset(void);
+extern void BKE_undo_number(struct bContext *C, int nr);
+extern const char *BKE_undo_get_name(int nr, bool *r_active);
+extern bool BKE_undo_save_file(const char *filename);
+extern struct Main *BKE_undo_get_main(struct Scene **r_scene);
/* copybuffer */
void BKE_copybuffer_begin(struct Main *bmain);
diff --git a/source/blender/blenkernel/BKE_bpath.h b/source/blender/blenkernel/BKE_bpath.h
index 990b414a4cf..10ee504f244 100644
--- a/source/blender/blenkernel/BKE_bpath.h
+++ b/source/blender/blenkernel/BKE_bpath.h
@@ -48,13 +48,21 @@ void *BKE_bpath_list_backup(struct Main *bmain, const int flag);
void BKE_bpath_list_restore(struct Main *bmain, const int flag, void *ls_handle);
void BKE_bpath_list_free(void *ls_handle);
-#define BKE_BPATH_TRAVERSE_ABS (1 << 0) /* convert paths to absolute */
-#define BKE_BPATH_TRAVERSE_SKIP_LIBRARY (1 << 2) /* skip library paths */
-#define BKE_BPATH_TRAVERSE_SKIP_PACKED (1 << 3) /* skip packed data */
-#define BKE_BPATH_TRAVERSE_SKIP_MULTIFILE (1 << 4) /* skip paths where a single dir is used with an array of files, eg.
- * sequence strip images and pointcache. in this case only use the first
- * file, this is needed for directory manipulation functions which might
- * otherwise modify the same directory multiple times */
+enum {
+ /* convert paths to absolute */
+ BKE_BPATH_TRAVERSE_ABS = (1 << 0),
+ /* skip library paths */
+ BKE_BPATH_TRAVERSE_SKIP_LIBRARY = (1 << 1),
+ /* skip packed data */
+ BKE_BPATH_TRAVERSE_SKIP_PACKED = (1 << 2),
+ /* skip paths where a single dir is used with an array of files, eg.
+ * sequence strip images and pointcache. in this case only use the first
+ * file, this is needed for directory manipulation functions which might
+ * otherwise modify the same directory multiple times */
+ BKE_BPATH_TRAVERSE_SKIP_MULTIFILE = (1 << 3),
+ /* reload data (when the path is edited) */
+ BKE_BPATH_TRAVERSE_RELOAD_EDITED = (1 << 4),
+};
/* high level funcs */
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 49975fa0276..023303fe602 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -27,14 +27,11 @@
* General operations for brushes.
*/
-struct ID;
struct Brush;
struct ImBuf;
struct ImagePool;
struct Main;
-struct rctf;
struct Scene;
-struct wmOperator;
// enum CurveMappingPreset;
@@ -82,34 +79,36 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br, bool secondar
/* unified strength size and color */
-float *BKE_brush_color_get(const struct Scene *scene, struct Brush *brush);
-float *BKE_brush_secondary_color_get(const struct Scene *scene, struct Brush *brush);
+const float *BKE_brush_color_get(const struct Scene *scene, const struct Brush *brush);
+const float *BKE_brush_secondary_color_get(const struct Scene *scene, const struct Brush *brush);
void BKE_brush_color_set(struct Scene *scene, struct Brush *brush, const float color[3]);
-int BKE_brush_size_get(const struct Scene *scene, struct Brush *brush);
+int BKE_brush_size_get(const struct Scene *scene, const struct Brush *brush);
void BKE_brush_size_set(struct Scene *scene, struct Brush *brush, int value);
-float BKE_brush_unprojected_radius_get(const struct Scene *scene, struct Brush *brush);
+float BKE_brush_unprojected_radius_get(const struct Scene *scene, const struct Brush *brush);
void BKE_brush_unprojected_radius_set(struct Scene *scene, struct Brush *brush, float value);
-float BKE_brush_alpha_get(const struct Scene *scene, struct Brush *brush);
+float BKE_brush_alpha_get(const struct Scene *scene, const struct Brush *brush);
void BKE_brush_alpha_set(Scene *scene, struct Brush *brush, float alpha);
-float BKE_brush_weight_get(const Scene *scene, struct Brush *brush);
+float BKE_brush_weight_get(const Scene *scene, const struct Brush *brush);
void BKE_brush_weight_set(const Scene *scene, struct Brush *brush, float value);
-int BKE_brush_use_locked_size(const struct Scene *scene, struct Brush *brush);
-int BKE_brush_use_alpha_pressure(const struct Scene *scene, struct Brush *brush);
-int BKE_brush_use_size_pressure(const struct Scene *scene, struct Brush *brush);
+int BKE_brush_use_locked_size(const struct Scene *scene, const struct Brush *brush);
+int BKE_brush_use_alpha_pressure(const struct Scene *scene, const struct Brush *brush);
+int BKE_brush_use_size_pressure(const struct Scene *scene, const struct Brush *brush);
/* scale unprojected radius to reflect a change in the brush's 2D size */
-void BKE_brush_scale_unprojected_radius(float *unprojected_radius,
- int new_brush_size,
- int old_brush_size);
+void BKE_brush_scale_unprojected_radius(
+ float *unprojected_radius,
+ int new_brush_size,
+ int old_brush_size);
/* scale brush size to reflect a change in the brush's unprojected radius */
-void BKE_brush_scale_size(int *BKE_brush_size_get,
- float new_unprojected_radius,
- float old_unprojected_radius);
+void BKE_brush_scale_size(
+ int *r_brush_size,
+ float new_unprojected_radius,
+ float old_unprojected_radius);
/* debugging only */
void BKE_brush_debug_print_state(struct Brush *br);
diff --git a/source/blender/blenkernel/BKE_cache_library.h b/source/blender/blenkernel/BKE_cache_library.h
new file mode 100644
index 00000000000..62ec261f123
--- /dev/null
+++ b/source/blender/blenkernel/BKE_cache_library.h
@@ -0,0 +1,254 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_CACHE_LIBRARY_H__
+#define __BKE_CACHE_LIBRARY_H__
+
+/** \file BKE_cache_library.h
+ * \ingroup bke
+ */
+
+#include "DNA_cache_library_types.h"
+
+struct ListBase;
+struct Main;
+struct bContext;
+struct DerivedMesh;
+struct Group;
+struct Object;
+struct Scene;
+struct EvaluationContext;
+struct ParticleSystem;
+struct DupliCache;
+struct DupliObjectData;
+struct CacheModifier;
+struct ID;
+struct CacheProcessData;
+struct BVHTreeFromMesh;
+struct Strands;
+struct StrandsChildren;
+struct StrandsKeyCacheModifier;
+struct Key;
+struct KeyBlock;
+
+struct ClothModifierData;
+
+struct CacheLibrary *BKE_cache_library_add(struct Main *bmain, const char *name);
+struct CacheLibrary *BKE_cache_library_copy(struct CacheLibrary *cachelib);
+void BKE_cache_library_free(struct CacheLibrary *cachelib);
+void BKE_cache_library_unlink(struct CacheLibrary *cachelib);
+
+const char *BKE_cache_item_name_prefix(int type);
+void BKE_cache_item_name(struct Object *ob, int type, int index, char *name);
+int BKE_cache_item_name_length(struct Object *ob, int type, int index);
+eCacheReadSampleResult BKE_cache_read_result(int ptc_result);
+
+bool BKE_cache_library_validate_item(struct CacheLibrary *cachelib, struct Object *ob, int type, int index);
+
+struct IDProperty *BKE_cache_library_get_input_metadata(struct CacheLibrary *cachelib, bool create);
+struct IDProperty *BKE_cache_library_get_output_metadata(struct CacheLibrary *cachelib, bool create);
+
+/* ========================================================================= */
+
+void BKE_cache_library_get_read_flags(struct CacheLibrary *cachelib, bool use_render, bool for_display, bool *read_strands_motion, bool *read_strands_children);
+
+bool BKE_cache_archive_path_test(struct CacheLibrary *cachelib, const char *path);
+void BKE_cache_archive_path_ex(const char *path, struct Library *lib, const char *default_filename, char *result, int max);
+void BKE_cache_archive_input_path(struct CacheLibrary *cachelib, char *result, int max);
+void BKE_cache_archive_output_path(struct CacheLibrary *cachelib, char *result, int max);
+
+void BKE_cache_library_dag_recalc_tag(struct EvaluationContext *eval_ctx, struct Main *bmain);
+
+/*void BKE_cache_library_filter_duplilist(struct CacheLibrary *cachelib, struct ListBase *duplilist);*/
+void BKE_cache_library_tag_used_objects(CacheLibrary *cachelib);
+
+bool BKE_cache_read_dupli_cache(struct CacheLibrary *cachelib, struct DupliCache *dupcache,
+ struct Scene *scene, struct Group *dupgroup, float frame, bool use_render, bool for_display);
+bool BKE_cache_read_dupli_object(struct CacheLibrary *cachelib, struct DupliObjectData *data,
+ struct Scene *scene, struct Object *ob, float frame, bool use_render, bool for_display);
+
+void BKE_cache_process_dupli_cache(struct CacheLibrary *cachelib, struct CacheProcessData *data,
+ struct Scene *scene, struct Group *dupgroup, float frame_prev, float frame,
+ bool do_modifiers, bool do_strands_child_deform, bool do_strands_motion);
+
+/* ========================================================================= */
+
+typedef void (*CacheModifier_IDWalkFunc)(void *userdata, struct CacheLibrary *cachelib, struct CacheModifier *md, struct ID **id_ptr);
+
+typedef struct CacheProcessContext {
+ struct Main *bmain;
+ struct Scene *scene;
+ struct CacheLibrary *cachelib;
+ struct Group *group;
+} CacheProcessContext;
+
+typedef struct CacheProcessData {
+ unsigned int lay;
+ float mat[4][4];
+ struct DupliCache *dupcache;
+} CacheProcessData;
+
+typedef enum eCacheProcessFlag {
+ eCacheProcessFlag_DoStrands = (1 << 0),
+ eCacheProcessFlag_DoStrandsChildren = (1 << 1),
+} eCacheProcessFlag;
+
+typedef void (*CacheModifier_InitFunc)(struct CacheModifier *md);
+typedef void (*CacheModifier_FreeFunc)(struct CacheModifier *md);
+typedef void (*CacheModifier_CopyFunc)(struct CacheModifier *md, struct CacheModifier *target);
+typedef void (*CacheModifier_ForeachIDLinkFunc)(struct CacheModifier *md, struct CacheLibrary *cachelib,
+ CacheModifier_IDWalkFunc walk, void *userData);
+typedef void (*CacheModifier_ProcessFunc)(struct CacheModifier *md, struct CacheProcessContext *ctx, struct CacheProcessData *data,
+ int frame, int frame_prev, int process_flag);
+
+typedef struct CacheModifierTypeInfo {
+ /* The user visible name for this modifier */
+ char name[32];
+
+ /* The DNA struct name for the modifier data type,
+ * used to write the DNA data out.
+ */
+ char struct_name[32];
+
+ /* The size of the modifier data type, used by allocation. */
+ int struct_size;
+
+ /********************* Non-optional functions *********************/
+
+ /* Copy instance data for this modifier type. Should copy all user
+ * level settings to the target modifier.
+ */
+ CacheModifier_CopyFunc copy;
+
+ /* Should call the given walk function with a pointer to each ID
+ * pointer (i.e. each datablock pointer) that the modifier data
+ * stores. This is used for linking on file load and for
+ * unlinking datablocks or forwarding datablock references.
+ *
+ * This function is optional.
+ */
+ CacheModifier_ForeachIDLinkFunc foreachIDLink;
+
+ /* Process data and write results to the modifier's output archive */
+ CacheModifier_ProcessFunc process;
+
+ /********************* Optional functions *********************/
+
+ /* Initialize new instance data for this modifier type, this function
+ * should set modifier variables to their default values.
+ *
+ * This function is optional.
+ */
+ CacheModifier_InitFunc init;
+
+ /* Free internal modifier data variables, this function should
+ * not free the md variable itself.
+ *
+ * This function is optional.
+ */
+ CacheModifier_FreeFunc free;
+} CacheModifierTypeInfo;
+
+void BKE_cache_modifier_init(void);
+
+const char *BKE_cache_modifier_type_name(eCacheModifier_Type type);
+const char *BKE_cache_modifier_type_struct_name(eCacheModifier_Type type);
+int BKE_cache_modifier_type_struct_size(eCacheModifier_Type type);
+
+bool BKE_cache_modifier_unique_name(struct ListBase *modifiers, struct CacheModifier *md);
+struct CacheModifier *BKE_cache_modifier_add(struct CacheLibrary *cachelib, const char *name, eCacheModifier_Type type);
+void BKE_cache_modifier_remove(struct CacheLibrary *cachelib, struct CacheModifier *md);
+void BKE_cache_modifier_clear(struct CacheLibrary *cachelib);
+struct CacheModifier *BKE_cache_modifier_copy(struct CacheLibrary *cachelib, struct CacheModifier *md);
+
+void BKE_cache_modifier_foreachIDLink(struct CacheLibrary *cachelib, struct CacheModifier *md, CacheModifier_IDWalkFunc walk, void *userdata);
+
+bool BKE_cache_modifier_find_object(struct DupliCache *dupcache, struct Object *ob, struct DupliObjectData **r_data);
+bool BKE_cache_modifier_find_strands(struct DupliCache *dupcache, struct Object *ob, int hair_system, struct DupliObjectData **r_data, struct Strands **r_strands, struct StrandsChildren **r_children, const char **r_name);
+
+struct KeyBlock *BKE_cache_modifier_strands_key_insert_key(struct StrandsKeyCacheModifier *md, struct Strands *strands, const char *name, const bool from_mix);
+bool BKE_cache_modifier_strands_key_get(struct Object *ob, struct StrandsKeyCacheModifier **r_skmd, struct DerivedMesh **r_dm, struct Strands **r_strands,
+ struct DupliObjectData **r_dobdata, const char **r_name, float r_mat[4][4]);
+bool BKE_cache_library_uses_key(struct CacheLibrary *cachelib, struct Key *key);
+
+/* ========================================================================= */
+
+typedef struct CacheEffectorInstance {
+ struct CacheEffectorInstance *next, *prev;
+
+ float mat[4][4];
+ float imat[4][4];
+ // TODO add linear/angular velocity if necessary
+} CacheEffectorInstance;
+
+typedef struct CacheEffector {
+ int type;
+
+ ListBase instances;
+
+ struct DerivedMesh *dm;
+ struct BVHTreeFromMesh *treedata;
+ struct ForceFieldVertexCache *vertex_cache;
+
+ float strength, falloff;
+ float mindist, maxdist;
+ bool double_sided;
+} CacheEffector;
+
+typedef enum eCacheEffector_Type {
+ eCacheEffector_Type_Deflect = 0,
+ eCacheEffector_Type_Drag = 1,
+} eCacheEffector_Type;
+
+typedef struct CacheEffectorPoint {
+ int index;
+ float x[3], v[3];
+} CacheEffectorPoint;
+
+typedef struct CacheEffectorResult {
+ float f[3];
+} CacheEffectorResult;
+
+int BKE_cache_effectors_get(struct CacheEffector *effectors, int max, struct CacheLibrary *cachelib, struct DupliCache *dupcache, float obmat[4][4]);
+void BKE_cache_effectors_free(struct CacheEffector *effectors, int tot);
+void BKE_cache_effector_velocity_update(struct CacheLibrary *cachelib, struct DupliCache *dupcache, float obmat[4][4], float frame);
+int BKE_cache_effectors_eval(struct CacheEffector *effectors, int tot, struct CacheEffectorPoint *point, struct CacheEffectorResult *result);
+int BKE_cache_effectors_eval_ex(struct CacheEffector *effectors, int tot, struct CacheEffectorPoint *point, struct CacheEffectorResult *result,
+ bool (*filter)(void *, struct CacheEffector *), void *filter_data);
+
+/* ========================================================================= */
+
+struct CacheArchiveInfo *BKE_cache_archive_info_new(void);
+void BKE_cache_archive_info_free(struct CacheArchiveInfo *info);
+void BKE_cache_archive_info_clear(struct CacheArchiveInfo *info);
+
+struct CacheArchiveInfoNode *BKE_cache_archive_info_find_node(struct CacheArchiveInfo *info, struct CacheArchiveInfoNode *parent,
+ eCacheArchiveInfoNode_Type type, const char *name);
+struct CacheArchiveInfoNode *BKE_cache_archive_info_add_node(struct CacheArchiveInfo *info, struct CacheArchiveInfoNode *parent,
+ eCacheArchiveInfoNode_Type type, const char *name);
+
+#endif
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index 77296920ee2..aacb7a4066b 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -104,26 +104,45 @@ typedef struct CameraParams {
float winmat[4][4];
} CameraParams;
+/* values for CameraParams.zoom, need to be taken into account for some operations */
+#define CAMERA_PARAM_ZOOM_INIT_CAMOB 1.0f
+#define CAMERA_PARAM_ZOOM_INIT_PERSP 2.0f
+
void BKE_camera_params_init(CameraParams *params);
-void BKE_camera_params_from_object(CameraParams *params, struct Object *camera);
-void BKE_camera_params_from_view3d(CameraParams *params, struct View3D *v3d, struct RegionView3D *rv3d);
+void BKE_camera_params_from_object(CameraParams *params, const struct Object *camera);
+void BKE_camera_params_from_view3d(CameraParams *params, const struct View3D *v3d, const struct RegionView3D *rv3d);
void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int winy, float aspx, float aspy);
void BKE_camera_params_compute_matrix(CameraParams *params);
/* Camera View Frame */
-void BKE_camera_view_frame_ex(struct Scene *scene, struct Camera *camera, float drawsize, const bool do_clip, const float scale[3],
- float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3]);
+void BKE_camera_view_frame_ex(
+ const struct Scene *scene, const struct Camera *camera,
+ const float drawsize, const bool do_clip, const float scale[3],
+ float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3]);
+void BKE_camera_view_frame(
+ const struct Scene *scene, const struct Camera *camera,
+ float r_vec[4][3]);
+
+bool BKE_camera_view_frame_fit_to_scene(
+ struct Scene *scene, struct View3D *v3d, struct Object *camera_ob,
+ float r_co[3], float *r_scale);
+bool BKE_camera_view_frame_fit_to_coords(
+ const struct Scene *scene,
+ const float (*cos)[3], int num_cos,
+ const struct Object *camera_ob,
+ float r_co[3], float *r_scale);
-void BKE_camera_view_frame(struct Scene *scene, struct Camera *camera, float r_vec[4][3]);
+void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings);
-bool BKE_camera_view_frame_fit_to_scene(struct Scene *scene, struct View3D *v3d, struct Object *camera_ob,
- float r_co[3], float *r_scale);
-bool BKE_camera_view_frame_fit_to_coords(struct Scene *scene, float (*cos)[3], int num_cos,
- struct Object *camera_ob, float r_co[3], float *r_scale);
+/* Camera multi-view API */
-void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings);
+struct Object *BKE_camera_multiview_render(struct Scene *scene, struct Object *camera, const char *viewname);
+void BKE_camera_multiview_view_matrix(struct RenderData *rd, struct Object *camera, const bool is_left, float r_viewmat[4][4]);
+void BKE_camera_multiview_model_matrix(struct RenderData *rd, struct Object *camera, const char *viewname, float r_modelmat[4][4]);
+float BKE_camera_multiview_shift_x(struct RenderData *rd, struct Object *camera, const char *viewname);
+void BKE_camera_multiview_params(struct RenderData *rd, struct CameraParams *params, struct Object *camera, const char *viewname);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index a7fad85ed42..81621f9d3e7 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -36,15 +36,11 @@
#include "BLI_math_inline.h"
struct Object;
-struct ListBase;
struct Scene;
struct MFace;
struct DerivedMesh;
struct ClothModifierData;
struct CollisionModifierData;
-struct CollisionTree;
-struct VoxelData;
-struct PartDeflect;
#define DO_INLINE MALWAYS_INLINE
diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h
index b81b8f04817..bdc20324bee 100644
--- a/source/blender/blenkernel/BKE_collision.h
+++ b/source/blender/blenkernel/BKE_collision.h
@@ -43,16 +43,12 @@
#include "BLI_kdopbvh.h"
-struct Cloth;
-struct ClothModifierData;
struct CollisionModifierData;
-struct DerivedMesh;
struct Group;
struct MFace;
struct MVert;
struct Object;
struct Scene;
-struct LinkNode;
////////////////////////////////////////
// used for collisions in collision.c
diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h
index 9234625a37c..74a327c3808 100644
--- a/source/blender/blenkernel/BKE_colortools.h
+++ b/source/blender/blenkernel/BKE_colortools.h
@@ -103,5 +103,6 @@ void BKE_color_managed_view_settings_free(struct ColorManagedViewSettings *setti
void BKE_color_managed_colorspace_settings_init(struct ColorManagedColorspaceSettings *colorspace_settings);
void BKE_color_managed_colorspace_settings_copy(struct ColorManagedColorspaceSettings *colorspace_settings,
const struct ColorManagedColorspaceSettings *settings);
-
+bool BKE_color_managed_colorspace_settings_equals(const struct ColorManagedColorspaceSettings *settings1,
+ const struct ColorManagedColorspaceSettings *settings2);
#endif
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h
index 1346feec82c..f3cfb901154 100644
--- a/source/blender/blenkernel/BKE_constraint.h
+++ b/source/blender/blenkernel/BKE_constraint.h
@@ -108,8 +108,8 @@ typedef struct bConstraintTypeInfo {
} bConstraintTypeInfo;
/* Function Prototypes for bConstraintTypeInfo's */
-bConstraintTypeInfo *BKE_constraint_typeinfo_get(struct bConstraint *con);
-bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type);
+const bConstraintTypeInfo *BKE_constraint_typeinfo_get(struct bConstraint *con);
+const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type);
/* ---------------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 04990ad7144..74dafcac671 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -53,7 +53,6 @@ struct StructRNA;
struct ToolSettings;
struct Image;
struct Text;
-struct ImBuf;
struct EditBone;
struct bPoseChannel;
struct bGPdata;
@@ -108,6 +107,7 @@ enum {
CTX_MODE_PAINT_VERTEX,
CTX_MODE_PAINT_TEXTURE,
CTX_MODE_PARTICLE,
+ CTX_MODE_HAIR,
CTX_MODE_OBJECT
};
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 60cbf8b302e..9bae2ad948d 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -33,7 +33,6 @@
* \author nzc
*/
-struct BevList;
struct BezTriple;
struct Curve;
struct EditNurb;
@@ -91,6 +90,7 @@ void BKE_curve_translate(struct Curve *cu, float offset[3], const bool do_keys);
void BKE_curve_material_index_remove(struct Curve *cu, int index);
void BKE_curve_material_index_clear(struct Curve *cu);
int BKE_curve_material_index_validate(struct Curve *cu);
+void BKE_curve_material_remap(struct Curve *cu, const unsigned int *remap, unsigned int remap_len);
ListBase *BKE_curve_nurbs_get(struct Curve *cu);
@@ -120,6 +120,7 @@ void BKE_curve_bevel_make(struct Scene *scene, struct Object *ob, struct ListBa
const bool for_render, const bool use_render_resolution);
void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride);
+void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride);
void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *tb, struct rctf *r_rect);
@@ -183,4 +184,14 @@ void BKE_nurb_handles_autocalc(struct Nurb *nu, int flag);
void BKE_nurb_bezt_handle_test(struct BezTriple *bezt, const bool use_handle);
void BKE_nurb_handles_test(struct Nurb *nu, const bool use_handles);
+/* **** Depsgraph evaluation **** */
+
+struct EvaluationContext;
+
+void BKE_curve_eval_geometry(struct EvaluationContext *eval_ctx,
+ struct Curve *curve);
+
+void BKE_curve_eval_path(struct EvaluationContext *eval_ctx,
+ struct Curve *curve);
+
#endif /* __BKE_CURVE_H__ */
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 6a0cfefb1c2..8cd6311e84c 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -46,7 +46,6 @@ extern "C" {
struct BMesh;
struct ID;
struct CustomData;
-struct CustomDataLayer;
typedef uint64_t CustomDataMask;
/*a data type large enough to hold 1 element from any customdata layer type*/
@@ -58,6 +57,8 @@ extern const CustomDataMask CD_MASK_EDITMESH;
extern const CustomDataMask CD_MASK_DERIVEDMESH;
extern const CustomDataMask CD_MASK_BMESH;
extern const CustomDataMask CD_MASK_FACECORNERS;
+extern const CustomDataMask CD_MASK_STRANDS;
+extern const CustomDataMask CD_MASK_STRANDS_BMESH;
extern const CustomDataMask CD_MASK_EVERYTHING;
/* for ORIGINDEX layer type, indicates no original index for this element */
@@ -260,6 +261,7 @@ void *CustomData_get(const struct CustomData *data, int index, int type);
void *CustomData_get_n(const struct CustomData *data, int type, int index, int n);
void *CustomData_bmesh_get(const struct CustomData *data, void *block, int type);
void *CustomData_bmesh_get_n(const struct CustomData *data, void *block, int type, int n);
+void *CustomData_bmesh_get_named(const struct CustomData *data, void *block, int type, const char *name);
/* gets the layer at physical index n, with no type checking.
*/
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
index 08312035e40..a45893b00fa 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -39,7 +39,6 @@ struct Object;
struct ListBase;
struct bDeformGroup;
struct MDeformVert;
-struct MVert;
struct MEdge;
struct MLoop;
struct MPoly;
diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h
index 27cf19d7d06..d1214d39469 100644
--- a/source/blender/blenkernel/BKE_depsgraph.h
+++ b/source/blender/blenkernel/BKE_depsgraph.h
@@ -44,11 +44,11 @@
extern "C" {
#endif
+struct Group;
struct ID;
struct Main;
struct Object;
struct Scene;
-struct ListBase;
/* Dependency graph evaluation context
*
@@ -57,6 +57,7 @@ struct ListBase;
*/
typedef struct EvaluationContext {
int mode; /* evaluation mode */
+ float ctime; /* evaluation time */
} EvaluationContext;
typedef enum eEvaluationMode {
@@ -92,6 +93,7 @@ void DAG_exit(void);
*/
void DAG_scene_relations_update(struct Main *bmain, struct Scene *sce);
+void DAG_scene_relations_validate(struct Main *bmain, struct Scene *sce);
void DAG_relations_tag_update(struct Main *bmain);
void DAG_scene_relations_rebuild(struct Main *bmain, struct Scene *scene);
void DAG_scene_free(struct Scene *sce);
@@ -112,6 +114,7 @@ void DAG_scene_free(struct Scene *sce);
* example a datablock was removed. */
void DAG_scene_update_flags(struct Main *bmain, struct Scene *sce, unsigned int lay, const bool do_time, const bool do_invisible_flush);
+void DAG_scene_update_group_flags(struct Main *bmain, struct Scene *scene, struct Group *group, unsigned int lay, const bool do_time, const bool do_invisible_flush);
void DAG_on_visible_update(struct Main *bmain, const bool do_time);
void DAG_id_tag_update(struct ID *id, short flag);
diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h
index 0afc457f2b5..3b096773d96 100644
--- a/source/blender/blenkernel/BKE_displist.h
+++ b/source/blender/blenkernel/BKE_displist.h
@@ -53,14 +53,9 @@
/* prototypes */
-struct Base;
struct Scene;
struct Object;
-struct Curve;
struct ListBase;
-struct Material;
-struct Bone;
-struct Mesh;
struct DerivedMesh;
struct EvaluationContext;
diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h
index a8e152fd301..e7384fb1a9c 100644
--- a/source/blender/blenkernel/BKE_dynamicpaint.h
+++ b/source/blender/blenkernel/BKE_dynamicpaint.h
@@ -27,8 +27,6 @@
* \ingroup bke
*/
-struct bContext;
-struct wmOperator;
struct Scene;
/* Actual surface point */
@@ -70,8 +68,8 @@ void dynamicPaint_Modifier_copy(struct DynamicPaintModifierData *pmd, struct Dyn
bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, struct Scene *scene);
struct DynamicPaintSurface *dynamicPaint_createNewSurface(struct DynamicPaintCanvasSettings *canvas, struct Scene *scene);
-void dynamicPaint_clearSurface(struct Scene *scene, struct DynamicPaintSurface *surface);
-bool dynamicPaint_resetSurface(struct Scene *scene, struct DynamicPaintSurface *surface);
+void dynamicPaint_clearSurface(const struct Scene *scene, struct DynamicPaintSurface *surface);
+bool dynamicPaint_resetSurface(const struct Scene *scene, struct DynamicPaintSurface *surface);
void dynamicPaint_freeSurface(struct DynamicPaintSurface *surface);
void dynamicPaint_freeCanvas(struct DynamicPaintModifierData *pmd);
void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd);
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index 38c8cf12969..d350eea7ac7 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -32,7 +32,6 @@
struct BMesh;
struct BMLoop;
-struct BMFace;
struct Mesh;
struct Scene;
struct DerivedMesh;
@@ -93,11 +92,12 @@ void BKE_editmesh_update_linked_customdata(BMEditMesh *em);
void BKE_editmesh_color_free(BMEditMesh *em);
void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype);
+float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3];
/* editderivedmesh.c */
/* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */
void BKE_editmesh_statvis_calc(BMEditMesh *em, struct DerivedMesh *dm,
- struct MeshStatVis *statvis);
+ const struct MeshStatVis *statvis);
float (*BKE_editmesh_vertexCos_get(struct BMEditMesh *em, struct Scene *scene, int *r_numVerts))[3];
diff --git a/source/blender/blenkernel/BKE_editmesh_bvh.h b/source/blender/blenkernel/BKE_editmesh_bvh.h
index 3ee7dcd94b8..3736efff146 100644
--- a/source/blender/blenkernel/BKE_editmesh_bvh.h
+++ b/source/blender/blenkernel/BKE_editmesh_bvh.h
@@ -39,7 +39,6 @@ struct BMVert;
struct BMLoop;
struct BMBVHTree;
struct BVHTree;
-struct Scene;
typedef struct BMBVHTree BMBVHTree;
diff --git a/source/blender/blenkernel/BKE_editstrands.h b/source/blender/blenkernel/BKE_editstrands.h
new file mode 100644
index 00000000000..ddca51e4736
--- /dev/null
+++ b/source/blender/blenkernel/BKE_editstrands.h
@@ -0,0 +1,104 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_EDITSTRANDS_H__
+#define __BKE_EDITSTRANDS_H__
+
+/** \file blender/blenkernel/BKE_editstrands.h
+ * \ingroup bke
+ */
+
+#include "BLI_utildefines.h"
+
+#include "DNA_customdata_types.h"
+
+#include "BKE_customdata.h"
+#include "bmesh.h"
+
+struct BMesh;
+struct DerivedMesh;
+struct Key;
+struct Object;
+struct Strands;
+
+typedef struct BMEditStrands {
+ struct BMesh *bm;
+
+ /*this is for undoing failed operations*/
+ struct BMEditStrands *emcopy;
+ int emcopyusers;
+
+ /* Object this editmesh came from (if it came from one) */
+ struct Object *ob;
+ struct DerivedMesh *root_dm;
+
+ int flag;
+
+ unsigned int vertex_glbuf;
+ unsigned int elem_glbuf;
+ unsigned int dot_glbuf;
+
+ /*temp variables for x-mirror editing*/
+ int mirror_cdlayer; /* -1 is invalid */
+} BMEditStrands;
+
+/* BMEditStrands->flag */
+typedef enum BMEditStrandsFlag {
+ BM_STRANDS_DIRTY_SEGLEN = 1,
+} BMEditStrandsFlag;
+
+struct BMEditStrands *BKE_editstrands_create(struct BMesh *bm, struct DerivedMesh *root_dm, float mat[4][4]);
+struct BMEditStrands *BKE_editstrands_copy(struct BMEditStrands *es);
+struct BMEditStrands *BKE_editstrands_from_object(struct Object *ob);
+void BKE_editstrands_update_linked_customdata(struct BMEditStrands *es);
+void BKE_editstrands_free(struct BMEditStrands *es);
+
+/* === constraints === */
+
+/* Stores vertex locations for temporary reference:
+ * Vertex locations get modified by tools, but then need to be corrected
+ * by calculating a smooth solution based on the difference to original pre-tool locations.
+ */
+typedef float (*BMEditStrandsLocations)[3];
+BMEditStrandsLocations BKE_editstrands_get_locations(struct BMEditStrands *edit);
+void BKE_editstrands_free_locations(BMEditStrandsLocations locs);
+
+void BKE_editstrands_solve_constraints(struct Object *ob, struct BMEditStrands *es, BMEditStrandsLocations orig);
+void BKE_editstrands_ensure(struct BMEditStrands *es);
+
+
+/* === cache shape key conversion === */
+
+struct BMesh *BKE_cache_strands_to_bmesh(struct Strands *strands, struct Key *key, float mat[4][4], int act_key_nr, struct DerivedMesh *dm);
+struct Strands *BKE_cache_strands_from_bmesh(struct BMEditStrands *edit, struct Key *key, float mat[4][4], struct DerivedMesh *dm);
+
+/* === particle conversion === */
+
+struct BMesh *BKE_particles_to_bmesh(struct Object *ob, struct ParticleSystem *psys);
+void BKE_particles_from_bmesh(struct Object *ob, struct ParticleSystem *psys);
+
+#endif
diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h
index c4c27e1060d..69c3d632c49 100644
--- a/source/blender/blenkernel/BKE_effect.h
+++ b/source/blender/blenkernel/BKE_effect.h
@@ -39,11 +39,8 @@
struct Object;
struct Scene;
-struct Effect;
struct ListBase;
-struct Particle;
struct Group;
-struct RNG;
struct ParticleSimulationData;
struct ParticleData;
struct ParticleKey;
@@ -113,7 +110,8 @@ typedef struct EffectorCache {
} EffectorCache;
void free_partdeflect(struct PartDeflect *pd);
-struct ListBase *pdInitEffectors(struct Scene *scene, struct Object *ob_src, struct ParticleSystem *psys_src, struct EffectorWeights *weights, bool precalc);
+struct ListBase *pdInitEffectors(struct Scene *scene, struct Object *ob_src, struct ParticleSystem *psys_src, struct EffectorWeights *weights);
+struct ListBase *pdInitEffectors_ex(struct Scene *scene, struct Object *ob_src, struct ParticleSystem *psys_src, int layers, struct EffectorWeights *weights, bool precalc);
void pdEndEffectors(struct ListBase **effectors);
void pdPrecalculateEffectors(struct ListBase *effectors);
void pdDoEffectors(struct ListBase *effectors, struct ListBase *colliders, struct EffectorWeights *weights, struct EffectedPoint *point, float *force, float *impulse);
@@ -196,7 +194,10 @@ void BKE_sim_debug_data_free(void);
void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3],
float r, float g, float b, const char *category, unsigned int hash);
+void BKE_sim_debug_data_add_element_ex(struct SimDebugData *debug_data, int type, const float v1[3], const float v2[3],
+ float r, float g, float b, unsigned int category_hash, unsigned int hash);
void BKE_sim_debug_data_remove_element(unsigned int hash);
+void BKE_sim_debug_data_remove_element_ex(struct SimDebugData *debug_data, unsigned int hash);
#define BKE_sim_debug_data_add_dot(p, r, g, b, category, ...) { \
const float v2[3] = { 0.0f, 0.0f, 0.0f }; \
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 83783946d4f..443a03a475a 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -172,8 +172,8 @@ typedef enum eFMI_Requirement_Flags {
} eFMI_Requirement_Flags;
/* Function Prototypes for FModifierTypeInfo's */
-FModifierTypeInfo *fmodifier_get_typeinfo(struct FModifier *fcm);
-FModifierTypeInfo *get_fmodifier_typeinfo(int type);
+const FModifierTypeInfo *fmodifier_get_typeinfo(struct FModifier *fcm);
+const FModifierTypeInfo *get_fmodifier_typeinfo(int type);
/* ---------------------- */
@@ -223,12 +223,12 @@ struct FCurve *id_data_find_fcurve(ID *id, void *data, struct StructRNA *type, c
*/
int list_find_data_fcurves(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName);
-/* find an f-curve based on an rna property. */
+/* Find an f-curve based on an rna property. */
struct FCurve *rna_get_fcurve(struct PointerRNA *ptr, struct PropertyRNA *prop, int rnaindex,
- struct AnimData **adt, struct bAction **action, bool *r_driven);
+ struct AnimData **adt, struct bAction **action, bool *r_driven, bool *r_special);
/* Same as above, but takes a context data, temp hack needed for complex paths like texture ones. */
struct FCurve *rna_get_fcurve_context_ui(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop,
- int rnaindex, struct AnimData **adt, struct bAction **action, bool *r_driven);
+ int rnaindex, struct AnimData **adt, struct bAction **action, bool *r_driven, bool *r_special);
/* Binary search algorithm for finding where to 'insert' BezTriple with given frame number.
* Returns the index to insert at (data already at that index will be offset if replace is 0)
diff --git a/source/blender/blenkernel/BKE_fluidsim.h b/source/blender/blenkernel/BKE_fluidsim.h
index 433c10b82f1..6501c968abc 100644
--- a/source/blender/blenkernel/BKE_fluidsim.h
+++ b/source/blender/blenkernel/BKE_fluidsim.h
@@ -34,9 +34,7 @@
struct Object;
struct Scene;
-struct FluidsimModifierData;
struct FluidsimSettings;
-struct DerivedMesh;
struct MVert;
/* old interface */
diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h
index e12ce3df476..137670215cc 100644
--- a/source/blender/blenkernel/BKE_font.h
+++ b/source/blender/blenkernel/BKE_font.h
@@ -40,8 +40,6 @@ extern "C" {
struct VFont;
struct Object;
struct Curve;
-struct objfnt;
-struct TmpFont;
struct CharInfo;
struct Main;
diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h
index bb909e4aa9d..e10594634f0 100644
--- a/source/blender/blenkernel/BKE_freestyle.h
+++ b/source/blender/blenkernel/BKE_freestyle.h
@@ -41,6 +41,7 @@ extern "C" {
struct FreestyleConfig;
struct FreestyleLineSet;
struct FreestyleModuleConfig;
+struct Main;
/* RNA aliases */
typedef struct FreestyleSettings FreestyleSettings;
@@ -58,7 +59,7 @@ bool BKE_freestyle_module_move_up(FreestyleConfig *config, FreestyleModuleConfig
bool BKE_freestyle_module_move_down(FreestyleConfig *config, FreestyleModuleConfig *module_conf);
/* FreestyleConfig.linesets */
-FreestyleLineSet *BKE_freestyle_lineset_add(FreestyleConfig *config, const char *name);
+FreestyleLineSet *BKE_freestyle_lineset_add(struct Main *bmain, FreestyleConfig *config, const char *name);
bool BKE_freestyle_lineset_delete(FreestyleConfig *config, FreestyleLineSet *lineset);
FreestyleLineSet *BKE_freestyle_lineset_get_active(FreestyleConfig *config);
short BKE_freestyle_lineset_get_active_index(FreestyleConfig *config);
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 57003ffc3aa..7585dc23342 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -45,7 +45,6 @@ extern "C" {
/* forwards */
struct Main;
-struct Object;
typedef struct Global {
@@ -127,10 +126,12 @@ enum {
G_DEBUG_FREESTYLE = (1 << 7), /* freestyle messages */
G_DEBUG_DEPSGRAPH = (1 << 8), /* depsgraph messages */
G_DEBUG_SIMDATA = (1 << 9), /* sim debug data display */
+ G_DEBUG_GPU_MEM = (1 << 10), /* gpu memory in status bar */
+ G_DEBUG_DEPSGRAPH_NO_THREADS = (1 << 11), /* sinle threaded depsgraph */
};
#define G_DEBUG_ALL (G_DEBUG | G_DEBUG_FFMPEG | G_DEBUG_PYTHON | G_DEBUG_EVENTS | G_DEBUG_WM | G_DEBUG_JOBS | \
- G_DEBUG_FREESTYLE | G_DEBUG_DEPSGRAPH)
+ G_DEBUG_FREESTYLE | G_DEBUG_DEPSGRAPH | G_DEBUG_GPU_MEM)
/* G.fileflags */
diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h
index 820e1ea1494..d856e90a340 100644
--- a/source/blender/blenkernel/BKE_group.h
+++ b/source/blender/blenkernel/BKE_group.h
@@ -36,10 +36,8 @@
struct Base;
struct EvaluationContext;
struct Group;
-struct GroupObject;
struct Main;
struct Object;
-struct bAction;
struct Scene;
void BKE_group_free(struct Group *group);
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index 9af0d96884a..763a3874d4e 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -48,10 +48,14 @@ typedef struct Icon Icon;
struct PreviewImage;
struct ID;
+enum eIconSizes;
+
void BKE_icons_init(int first_dyn_id);
/* return icon id for library object or create new icon if not found */
-int BKE_icon_getid(struct ID *id);
+int BKE_icon_id_ensure(struct ID *id);
+
+int BKE_icon_preview_ensure(struct PreviewImage *preview);
/* retrieve icon for id */
struct Icon *BKE_icon_get(int icon_id);
@@ -60,8 +64,10 @@ struct Icon *BKE_icon_get(int icon_id);
/* used for inserting the internal icons */
void BKE_icon_set(int icon_id, struct Icon *icon);
-/* remove icon and free date if library object becomes invalid */
-void BKE_icon_delete(struct ID *id);
+/* remove icon and free data if library object becomes invalid */
+void BKE_icon_id_delete(struct ID *id);
+
+void BKE_icon_delete(int icon_id);
/* report changes - icon needs to be recalculated */
void BKE_icon_changed(int icon_id);
@@ -75,8 +81,17 @@ void BKE_previewimg_freefunc(void *link);
/* free the preview image */
void BKE_previewimg_free(struct PreviewImage **prv);
+/* clear the preview image or icon, but does not free it */
+void BKE_previewimg_clear(struct PreviewImage *prv);
+
+/* clear the preview image or icon at a specific size */
+void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size);
+
+/* get the preview from any pointer */
+struct PreviewImage **BKE_previewimg_id_get_p(struct ID *id);
+
/* free the preview image belonging to the id */
-void BKE_previewimg_free_id(struct ID *id);
+void BKE_previewimg_id_free(struct ID *id);
/* create a new preview image */
struct PreviewImage *BKE_previewimg_create(void);
@@ -85,6 +100,19 @@ struct PreviewImage *BKE_previewimg_create(void);
struct PreviewImage *BKE_previewimg_copy(struct PreviewImage *prv);
/* retrieve existing or create new preview image */
-struct PreviewImage *BKE_previewimg_get(struct ID *id);
+struct PreviewImage *BKE_previewimg_id_ensure(struct ID *id);
+
+void BKE_previewimg_ensure(struct PreviewImage *prv, const int size);
+
+struct PreviewImage *BKE_previewimg_cached_get(const char *name);
+
+struct PreviewImage *BKE_previewimg_cached_ensure(const char *name);
+
+struct PreviewImage *BKE_previewimg_cached_thumbnail_read(
+ const char *name, const char *path, const int source, bool force_update);
+
+void BKE_previewimg_cached_release(const char *name);
+
+#define ICON_RENDER_DEFAULT_HEIGHT 32
#endif /* __BKE_ICONS_H__ */
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 2c9ecef4c2d..facf3cf2103 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -39,41 +39,46 @@ extern "C" {
struct Image;
struct ImBuf;
-struct Tex;
struct anim;
struct Scene;
struct Object;
struct ImageFormatData;
struct ImagePool;
struct Main;
+struct ReportList;
+struct RenderResult;
+struct StampData;
#define IMA_MAX_SPACE 64
void BKE_images_init(void);
void BKE_images_exit(void);
+void BKE_image_free_packedfiles(struct Image *image);
+void BKE_image_free_views(struct Image *image);
void BKE_image_free_buffers(struct Image *image);
/* call from library */
void BKE_image_free(struct Image *image);
-void BKE_imbuf_stamp_info(struct Scene *scene, struct Object *camera, struct ImBuf *ibuf);
-void BKE_image_stamp_buf(
- struct Scene *scene, struct Object *camera,
- unsigned char *rect, float *rectf, int width, int height, int channels);
+typedef void (StampCallback)(void *data, const char *propname, const char *propvalue);
+
+void BKE_render_result_stamp_info(struct Scene *scene, struct Object *camera, struct RenderResult *rr);
+void BKE_imbuf_stamp_info(struct RenderResult *rr, struct ImBuf *ibuf);
+void BKE_stamp_info_callback(void *data, const struct StampData *stamp_data, StampCallback callback);
+void BKE_image_stamp_buf(struct Scene *scene, struct Object *camera, unsigned char *rect, float *rectf, int width, int height, int channels);
bool BKE_imbuf_alpha_test(struct ImBuf *ibuf);
-int BKE_imbuf_write_stamp(struct Scene *scene, struct Object *camera, struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf);
+int BKE_imbuf_write_stamp(struct Scene *scene, struct RenderResult *rr, struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf);
+void BKE_imbuf_write_prepare(struct ImBuf *ibuf, struct ImageFormatData *imf);
int BKE_imbuf_write(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf);
int BKE_imbuf_write_as(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf, const bool is_copy);
-
void BKE_image_path_from_imformat(
char *string, const char *base, const char *relbase, int frame,
- const struct ImageFormatData *im_format, const bool use_ext, const bool use_frames);
+ const struct ImageFormatData *im_format, const bool use_ext, const bool use_frames, const char *suffix);
void BKE_image_path_from_imtype(
char *string, const char *base, const char *relbase, int frame,
- const char imtype, const bool use_ext, const bool use_frames);
-
-bool BKE_image_path_ensure_ext_from_imformat(char *string, const struct ImageFormatData *im_format);
-bool BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype);
+ const char imtype, const bool use_ext, const bool use_frames, const char *suffix);
+int BKE_image_path_ensure_ext_from_imformat(char *string, const struct ImageFormatData *im_format);
+int BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype);
char BKE_image_ftype_to_imtype(const int ftype);
int BKE_image_imtype_to_ftype(const char imtype);
@@ -104,6 +109,7 @@ void BKE_image_tag_time(struct Image *ima);
/* ImageUser is in Texture, in Nodes, Background Image, Image Window, .... */
/* should be used in conjunction with an ID * to Image. */
struct ImageUser;
+struct RenderData;
struct RenderPass;
struct RenderResult;
@@ -153,7 +159,7 @@ bool BKE_image_has_ibuf(struct Image *ima, struct ImageUser *iuser);
/* same as above, but can be used to retrieve images being rendered in
* a thread safe way, always call both acquire and release */
-struct ImBuf *BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **lock_r);
+struct ImBuf *BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **r_lock);
void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock);
struct ImagePool *BKE_image_pool_new(void);
@@ -173,11 +179,12 @@ struct Image *BKE_image_load_exists(const char *filepath);
/* adds image, adds ibuf, generates color or pattern */
struct Image *BKE_image_add_generated(
- struct Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4]);
+ struct Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4], const bool stereo3d);
/* adds image from imbuf, owns imbuf */
-struct Image *BKE_image_add_from_imbuf(struct ImBuf *ibuf);
+struct Image *BKE_image_add_from_imbuf(struct ImBuf *ibuf, const char *name);
/* for reload, refresh, pack */
+void BKE_image_init_imageuser(struct Image *ima, struct ImageUser *iuser);
void BKE_image_signal(struct Image *ima, struct ImageUser *iuser, int signal);
void BKE_image_walk_all_users(const struct Main *mainp, void *customdata,
@@ -185,6 +192,8 @@ void BKE_image_walk_all_users(const struct Main *mainp, void *customdata,
/* ensures an Image exists for viewing nodes or render */
struct Image *BKE_image_verify_viewer(int type, const char *name);
+/* ensures the view node cache is compatible with the scene views */
+void BKE_image_verify_viewer_views(const struct RenderData *rd, struct Image *ima, struct ImageUser *iuser);
/* called on frame change or before render */
void BKE_image_user_frame_calc(struct ImageUser *iuser, int cfra, int fieldnr);
@@ -196,13 +205,23 @@ void BKE_image_update_frame(const struct Main *bmain, int cfra);
/* sets index offset for multilayer files */
struct RenderPass *BKE_image_multilayer_index(struct RenderResult *rr, struct ImageUser *iuser);
+/* sets index offset for multiview files */
+void BKE_image_multiview_index(struct Image *ima, struct ImageUser *iuser);
+
/* for multilayer images as well as for render-viewer */
+bool BKE_image_is_multilayer(struct Image *ima);
struct RenderResult *BKE_image_acquire_renderresult(struct Scene *scene, struct Image *ima);
void BKE_image_release_renderresult(struct Scene *scene, struct Image *ima);
+/* for multilayer images as well as for singlelayer */
+bool BKE_image_is_openexr(struct Image *ima);
+
/* for multiple slot render, call this before render */
void BKE_image_backup_render(struct Scene *scene, struct Image *ima);
-
+
+/* for singlelayer openexr saving */
+bool BKE_image_save_openexr_multiview(struct Image *ima, struct ImBuf *ibuf, const char *filepath, const int flags);
+
/* goes over all textures that use images */
void BKE_image_free_all_textures(void);
@@ -213,6 +232,8 @@ void BKE_image_free_anim_ibufs(struct Image *ima, int except_frame);
void BKE_image_all_free_anim_ibufs(int except_frame);
void BKE_image_memorypack(struct Image *ima);
+void BKE_image_packfiles(struct ReportList *reports, struct Image *ima, const char *basepath);
+void BKE_image_packfiles_from_mem(struct ReportList *reports, struct Image *ima, char *data, const size_t data_len);
/* prints memory statistics for images */
void BKE_image_print_memlist(void);
@@ -244,7 +265,8 @@ float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame);
/* Guess offset for the first frame in the sequence */
int BKE_image_sequence_guess_offset(struct Image *image);
-
+bool BKE_image_has_anim(struct Image *image);
+bool BKE_image_has_packedfile(struct Image *image);
bool BKE_image_is_animated(struct Image *image);
bool BKE_image_is_dirty(struct Image *image);
void BKE_image_file_format_set(struct Image *image, int ftype);
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index 61aac255762..1e9e392406b 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -38,10 +38,10 @@ struct ID;
struct ListBase;
struct Curve;
struct Object;
-struct Scene;
struct Lattice;
struct Mesh;
struct ParticleSystem;
+struct Strands;
struct WeightsArrayCache;
/* Kernel prototypes */
@@ -52,6 +52,7 @@ extern "C" {
void BKE_key_free(struct Key *sc);
void BKE_key_free_nolib(struct Key *key);
struct Key *BKE_key_add(struct ID *id);
+struct Key *BKE_key_add_ex(struct ID *from, int fromtype, int fromindex);
struct Key *BKE_key_add_particles(struct Object *ob, struct ParticleSystem *psys);
struct Key *BKE_key_copy(struct Key *key);
struct Key *BKE_key_copy_nolib(struct Key *key);
@@ -70,12 +71,19 @@ float *BKE_key_evaluate_object_ex(
float *arr, size_t arr_size);
float *BKE_key_evaluate_object(
struct Object *ob, int *r_totelem);
+float *BKE_key_evaluate_strands_ex(
+ struct Strands *strands, struct Key *key, struct KeyBlock *actkb, bool lock_shape,
+ int *r_totelem, float *arr, size_t arr_size);
+float *BKE_key_evaluate_strands(
+ struct Strands *strand, struct Key *key, struct KeyBlock *actkbs, bool lock_shape,
+ int *r_totelem, bool use_motion);
float *BKE_key_evaluate_particles_ex(
struct Object *ob, struct ParticleSystem *psys, float cfra, int *r_totelem,
float *arr, size_t arr_size);
float *BKE_key_evaluate_particles(
struct Object *ob, struct ParticleSystem *psys, float cfra, int *r_totelem);
+struct Key **BKE_key_from_object_p(struct Object *ob);
struct Key *BKE_key_from_object(struct Object *ob);
struct KeyBlock *BKE_keyblock_from_object(struct Object *ob);
struct KeyBlock *BKE_keyblock_from_object_reference(struct Object *ob);
@@ -96,10 +104,13 @@ typedef struct WeightsArrayCache {
} WeightsArrayCache;
float **BKE_keyblock_get_per_block_object_weights(struct Object *ob, struct Key *key, struct WeightsArrayCache *cache);
+float **BKE_keyblock_strands_get_per_block_weights(struct Strands *strands, struct Key *key, struct WeightsArrayCache *cache);
float **BKE_keyblock_get_per_block_particle_weights(struct Object *ob, struct ParticleSystem *psys, float cfra, struct Key *key, struct WeightsArrayCache *cache);
void BKE_keyblock_free_per_block_weights(struct Key *key, float **per_keyblock_weights, struct WeightsArrayCache *cache);
void BKE_key_evaluate_relative(const int start, int end, const int tot, char *basispoin, struct Key *key, struct KeyBlock *actkb,
float **per_keyblock_weights, const int mode);
+void BKE_key_evaluate_strands_relative(const int start, int end, const int tot, char *basispoin, struct Key *key, struct KeyBlock *actkb,
+ float **per_keyblock_weights, const int mode);
/* conversion functions */
/* Note: 'update_from' versions do not (re)allocate mem in kb, while 'convert_from' do. */
@@ -115,6 +126,10 @@ void BKE_keyblock_update_from_mesh(struct Mesh *me, struct KeyBlock *kb);
void BKE_keyblock_convert_from_mesh(struct Mesh *me, struct KeyBlock *kb);
void BKE_keyblock_convert_to_mesh(struct KeyBlock *kb, struct Mesh *me);
+void BKE_keyblock_update_from_strands(struct Strands *strands, struct KeyBlock *kb, bool use_motion);
+void BKE_keyblock_convert_from_strands(struct Strands *strands, struct Key *key, struct KeyBlock *kb, bool use_motion);
+void BKE_keyblock_convert_to_strands(struct KeyBlock *kb, struct Strands *strands, bool use_motion);
+
void BKE_keyblock_update_from_vertcos(struct Object *ob, struct KeyBlock *kb, float (*vertCos)[3]);
void BKE_keyblock_convert_from_vertcos(struct Object *ob, struct KeyBlock *kb, float (*vertCos)[3]);
float (*BKE_keyblock_convert_to_vertcos(struct Object *ob, struct KeyBlock *kb))[3];
@@ -126,6 +141,7 @@ void BKE_keyblock_convert_from_hair_keys(struct Object *ob, struct ParticleSy
/* other management */
bool BKE_keyblock_move(struct Object *ob, int org_index, int new_index);
+bool BKE_keyblock_move_ex(struct Key *key, int *shapenr, int org_index, int new_index);
bool BKE_keyblock_is_basis(struct Key *key, const int index);
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index 5fb1053b53f..4ffdb632513 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -93,4 +93,11 @@ int BKE_lattice_index_flip(struct Lattice *lt, const int index,
void BKE_lattice_bitmap_from_flag(struct Lattice *lt, unsigned int *bitmap, const short flag,
const bool clear, const bool respecthide);
+/* **** Depsgraph evaluation **** */
+
+struct EvaluationContext;
+
+void BKE_lattice_eval_geometry(struct EvaluationContext *eval_ctx,
+ struct Lattice *latt);
+
#endif /* __BKE_LATTICE_H__ */
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index e88a4e88209..63192cad11d 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -71,7 +71,7 @@ void id_clear_lib_data(struct Main *bmain, struct ID *id);
struct ListBase *which_libbase(struct Main *mainlib, short type);
-#define MAX_LIBARRAY 35
+#define MAX_LIBARRAY 36
int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
void BKE_libblock_free(struct Main *bmain, void *idv);
@@ -107,8 +107,9 @@ void BKE_library_make_local(struct Main *bmain, struct Library *lib, bool untagg
struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void set_free_windowmanager_cb(void (*func)(struct bContext *, struct wmWindowManager *));
-void set_free_notifier_reference_cb(void (*func)(const void *));
+void BKE_library_callback_free_window_manager_set(void (*func)(struct bContext *, struct wmWindowManager *));
+void BKE_library_callback_free_notifier_reference_set(void (*func)(const void *));
+void BKE_library_callback_free_editor_id_reference_set(void (*func)(const struct ID *));
/* use when "" is given to new_id() */
#define ID_FALLBACK_NAME N_("Untitled")
diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h
index ae10ba4caab..e77b4f5e8fe 100644
--- a/source/blender/blenkernel/BKE_linestyle.h
+++ b/source/blender/blenkernel/BKE_linestyle.h
@@ -49,9 +49,9 @@ struct Object;
struct ColorBand;
struct bContext;
-FreestyleLineStyle *BKE_linestyle_new(const char *name, struct Main *main);
+FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name);
void BKE_linestyle_free(FreestyleLineStyle *linestyle);
-FreestyleLineStyle *BKE_linestyle_copy(FreestyleLineStyle *linestyle);
+FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *linestyle);
FreestyleLineStyle *BKE_linestyle_active_from_scene(struct Scene *scene);
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index ec654ea4b71..a0c67e055ae 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -94,6 +94,7 @@ typedef struct Main {
ListBase movieclip;
ListBase mask;
ListBase linestyle;
+ ListBase cache_library;
char id_tag_update[256];
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index 2f20505bea3..0cfa1aeecb5 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -40,8 +40,6 @@ struct Main;
struct Material;
struct ID;
struct Object;
-struct Mesh;
-struct MTFace;
struct Scene;
/* materials */
@@ -52,6 +50,7 @@ void BKE_material_free_ex(struct Material *ma, bool do_id_user);
void test_object_materials(struct Main *bmain, struct ID *id);
void BKE_material_resize_object(struct Object *ob, const short totcol, bool do_id_user);
void init_material(struct Material *ma);
+void BKE_material_remap_object(struct Object *ob, const unsigned int *remap);
struct Material *BKE_material_add(struct Main *bmain, const char *name);
struct Material *BKE_material_copy(struct Material *ma);
struct Material *localize_material(struct Material *ma);
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index c021960e730..62cd50099fd 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -32,7 +32,6 @@
* \since March 2001
* \author nzc
*/
-struct EvaluationContext;
struct Main;
struct MetaBall;
struct Object;
@@ -46,9 +45,6 @@ struct MetaBall *BKE_mball_copy(struct MetaBall *mb);
void BKE_mball_make_local(struct MetaBall *mb);
-void BKE_mball_cubeTable_free(void);
-
-void BKE_mball_polygonize(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, struct ListBase *dispbase);
bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2);
bool BKE_mball_is_basis(struct Object *ob);
struct Object *BKE_mball_basis_find(struct Scene *scene, struct Object *ob);
@@ -72,4 +68,11 @@ void BKE_mball_select_all(struct MetaBall *mb);
void BKE_mball_deselect_all(struct MetaBall *mb);
void BKE_mball_select_swap(struct MetaBall *mb);
+/* **** Depsgraph evaluation **** */
+
+struct EvaluationContext;
+
+void BKE_mball_eval_geometry(struct EvaluationContext *eval_ctx,
+ struct MetaBall *mball);
+
#endif
diff --git a/source/blender/blenkernel/BKE_mball_tessellate.h b/source/blender/blenkernel/BKE_mball_tessellate.h
new file mode 100644
index 00000000000..361f31b704c
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mball_tessellate.h
@@ -0,0 +1,36 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_MBALL_TESSELLATE_H__
+#define __BKE_MBALL_TESSELLATE_H__
+
+/** \file BKE_mball_tessellate.h
+ * \ingroup bke
+ */
+struct EvaluationContext;
+struct Object;
+struct Scene;
+
+void BKE_mball_polygonize(
+ struct EvaluationContext *eval_ctx, struct Scene *scene,
+ struct Object *ob, struct ListBase *dispbase);
+
+void BKE_mball_cubeTable_free(void);
+
+#endif /* __BKE_MBALL_TESSELLATE_H__ */
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 224be0f3685..7cb121bcf5e 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -33,14 +33,13 @@
struct ID;
struct BoundBox;
-struct DispList;
struct EdgeHash;
struct ListBase;
struct LinkNode;
struct BLI_Stack;
struct MemArena;
-struct BMEditMesh;
struct BMesh;
+struct DupliObjectData;
struct Main;
struct Mesh;
struct MPoly;
@@ -49,18 +48,11 @@ struct MFace;
struct MEdge;
struct MVert;
struct MDeformVert;
-struct MCol;
struct Object;
-struct MTFace;
-struct VecNor;
struct CustomData;
struct DerivedMesh;
struct Scene;
struct MLoopUV;
-struct UvVertMap;
-struct UvMapVert;
-struct UvElementMap;
-struct UvElement;
struct ReportList;
#ifdef __cplusplus
@@ -78,12 +70,13 @@ extern "C" {
struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob);
-int poly_find_loop_from_vert(const struct MPoly *poly,
- const struct MLoop *loopstart,
- unsigned vert);
-
-int poly_get_adj_loops_from_vert(unsigned r_adj[3], const struct MPoly *poly,
- const struct MLoop *mloop, unsigned vert);
+int poly_find_loop_from_vert(
+ const struct MPoly *poly,
+ const struct MLoop *loopstart,
+ unsigned vert);
+int poly_get_adj_loops_from_vert(
+ unsigned r_adj[2], const struct MPoly *poly,
+ const struct MLoop *mloop, unsigned vert);
int BKE_mesh_edge_other_vert(const struct MEdge *e, int v);
@@ -116,6 +109,7 @@ void BKE_mesh_to_curve_nurblist(struct DerivedMesh *dm, struct ListBase *nurblis
void BKE_mesh_to_curve(struct Scene *scene, struct Object *ob);
void BKE_mesh_material_index_remove(struct Mesh *me, short index);
void BKE_mesh_material_index_clear(struct Mesh *me);
+void BKE_mesh_material_remap(struct Mesh *me, const unsigned int *remap, unsigned int remap_len);
void BKE_mesh_smooth_flag_set(struct Object *meshOb, int enableSmooth);
const char *BKE_mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh);
@@ -128,10 +122,14 @@ bool BKE_mesh_uv_cdlayer_rename_index(struct Mesh *me, const int poly_index, con
const char *new_name, const bool do_tessface);
bool BKE_mesh_uv_cdlayer_rename(struct Mesh *me, const char *old_name, const char *new_name, bool do_tessface);
-float (*BKE_mesh_vertexCos_get(struct Mesh *me, int *r_numVerts))[3];
+float (*BKE_mesh_vertexCos_get(const struct Mesh *me, int *r_numVerts))[3];
+
+void BKE_mesh_calc_normals_split(struct Mesh *mesh);
+void BKE_mesh_split_faces(struct Mesh *mesh);
struct Mesh *BKE_mesh_new_from_object(struct Main *bmain, struct Scene *sce, struct Object *ob,
int apply_modifiers, int settings, int calc_tessface, int calc_undeformed);
+struct Mesh *BKE_mesh_new_from_dupli_data(struct Main *bmain, struct DupliObjectData *data, bool calc_tessface, bool calc_undeformed);
/* vertex level transformations & checks (no derived mesh) */
@@ -280,7 +278,7 @@ int BKE_mesh_recalc_tessellation(
struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata,
struct MVert *mvert,
int totface, int totloop, int totpoly,
- const bool do_face_normals);
+ const bool do_face_nor_copy);
int BKE_mesh_mpoly_to_mface(
struct CustomData *fdata, struct CustomData *ldata,
struct CustomData *pdata, int totface, int totloop, int totpoly);
@@ -364,6 +362,13 @@ void BKE_mesh_strip_loose_edges(struct Mesh *me);
void BKE_mesh_calc_edges_legacy(struct Mesh *me, const bool use_old);
void BKE_mesh_calc_edges(struct Mesh *mesh, bool update, const bool select);
+/* **** Depsgraph evaluation **** */
+
+struct EvaluationContext;
+
+void BKE_mesh_eval_geometry(struct EvaluationContext *eval_ctx,
+ struct Mesh *mesh);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index da44c989146..a2f47858f90 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -102,7 +102,8 @@ typedef struct MeshElemMap {
/* mapping */
UvVertMap *BKE_mesh_uv_vert_map_create(
struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv,
- unsigned int totpoly, unsigned int totvert, int selected, float *limit);
+ unsigned int totpoly, unsigned int totvert,
+ const float limit[2], const bool selected, const bool use_winding);
UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v);
void BKE_mesh_uv_vert_map_free(UvVertMap *vmap);
diff --git a/source/blender/blenkernel/BKE_mesh_remap.h b/source/blender/blenkernel/BKE_mesh_remap.h
index 752270a8120..c6d8da16565 100644
--- a/source/blender/blenkernel/BKE_mesh_remap.h
+++ b/source/blender/blenkernel/BKE_mesh_remap.h
@@ -28,7 +28,6 @@
struct CustomData;
struct DerivedMesh;
struct MVert;
-struct MeshElemMap;
struct MemArena;
/* Generic ways to map some geometry elements from a source mesh to a dest one. */
diff --git a/source/blender/blenkernel/BKE_mesh_sample.h b/source/blender/blenkernel/BKE_mesh_sample.h
new file mode 100644
index 00000000000..6b489550847
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mesh_sample.h
@@ -0,0 +1,68 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_MESH_SAMPLE_H__
+#define __BKE_MESH_SAMPLE_H__
+
+/** \file BKE_mesh_sample.h
+ * \ingroup bke
+ */
+
+struct DerivedMesh;
+struct Key;
+struct KeyBlock;
+
+struct MSurfaceSample;
+
+/* ==== Evaluate ==== */
+
+bool BKE_mesh_sample_eval(struct DerivedMesh *dm, const struct MSurfaceSample *sample, float loc[3], float nor[3], float tang[3]);
+bool BKE_mesh_sample_shapekey(struct Key *key, struct KeyBlock *kb, const struct MSurfaceSample *sample, float loc[3]);
+
+
+/* ==== Sampling ==== */
+
+/* Storage descriptor to allow generic data storage by arbitrary algorithms */
+typedef struct MSurfaceSampleStorage {
+ bool (*store_sample)(void *data, int capacity, int index, const struct MSurfaceSample *sample);
+ void *data;
+ int capacity;
+ int free_data;
+} MSurfaceSampleStorage;
+
+void BKE_mesh_sample_storage_single(struct MSurfaceSampleStorage *storage, struct MSurfaceSample *sample);
+void BKE_mesh_sample_storage_array(struct MSurfaceSampleStorage *storage, struct MSurfaceSample *samples, int capacity);
+void BKE_mesh_sample_storage_release(struct MSurfaceSampleStorage *storage);
+
+int BKE_mesh_sample_generate_random(struct MSurfaceSampleStorage *dst, struct DerivedMesh *dm, unsigned int seed, int totsample);
+
+typedef bool (*MeshSampleRayCallback)(void *userdata, float ray_start[3], float ray_end[3]);
+int BKE_mesh_sample_generate_raycast(struct MSurfaceSampleStorage *dst, struct DerivedMesh *dm, MeshSampleRayCallback ray_cb, void *userdata, int totsample);
+
+/* ==== Utilities ==== */
+
+struct ParticleSystem;
+struct ParticleData;
+struct BVHTreeFromMesh;
+
+bool BKE_mesh_sample_from_particle(struct MSurfaceSample *sample, struct ParticleSystem *psys, struct DerivedMesh *dm, struct ParticleData *pa);
+bool BKE_mesh_sample_to_particle(struct MSurfaceSample *sample, struct ParticleSystem *psys, struct DerivedMesh *dm, struct BVHTreeFromMesh *bvhtree, struct ParticleData *pa);
+
+#endif /* __BKE_MESH_SAMPLE_H__ */
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 12eb78e422b..cc53f9409fd 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -39,10 +39,11 @@ struct DagNode;
struct Object;
struct Scene;
struct ListBase;
-struct LinkNode;
struct bArmature;
+struct Main;
struct ModifierData;
struct BMEditMesh;
+struct DepsNodeHandle;
typedef enum {
/* Should not be used, only for None modifier type */
@@ -256,9 +257,21 @@ typedef struct ModifierTypeInfo {
*
* This function is optional.
*/
- void (*updateDepgraph)(struct ModifierData *md, struct DagForest *forest, struct Scene *scene,
+ void (*updateDepgraph)(struct ModifierData *md, struct DagForest *forest,
+ struct Main *bmain, struct Scene *scene,
struct Object *ob, struct DagNode *obNode);
+ /* Add the appropriate relations to the dependency graph.
+ *
+ * This function is optional.
+ */
+ /* TODO(sergey): Remove once we finalyl switched to the new depsgraph. */
+ void (*updateDepsgraph)(struct ModifierData *md,
+ struct Main *bmain,
+ struct Scene *scene,
+ struct Object *ob,
+ struct DepsNodeHandle *node);
+
/* Should return true if the modifier needs to be recalculated on time
* changes.
*
@@ -311,7 +324,7 @@ typedef struct ModifierTypeInfo {
/* Initialize modifier's global data (type info and some common global storages). */
void BKE_modifier_init(void);
-ModifierTypeInfo *modifierType_getInfo(ModifierType type);
+const ModifierTypeInfo *modifierType_getInfo(ModifierType type);
/* Modifier utility calls, do call through type pointer and return
* default values if pointer is optional.
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index a4aa58e22f1..7d7675270de 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -37,7 +37,6 @@ struct Main;
struct MovieClip;
struct MovieClipScopes;
struct MovieClipUser;
-struct MovieTrackingTrack;
struct MovieDistortion;
void BKE_movieclip_free(struct MovieClip *clip);
@@ -61,7 +60,7 @@ void BKE_movieclip_user_set_frame(struct MovieClipUser *user, int framenr);
void BKE_movieclip_update_scopes(struct MovieClip *clip, struct MovieClipUser *user, struct MovieClipScopes *scopes);
-void BKE_movieclip_get_cache_segments(struct MovieClip *clip, struct MovieClipUser *user, int *totseg_r, int **points_r);
+void BKE_movieclip_get_cache_segments(struct MovieClip *clip, struct MovieClipUser *user, int *r_totseg, int **r_points);
void BKE_movieclip_build_proxy_frame(struct MovieClip *clip, int clip_flag, struct MovieDistortion *distortion,
int cfra, int *build_sizes, int build_count, bool undistorted);
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index 11d81a149b1..a8242a529f3 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -34,9 +34,7 @@
enum MultiresModifiedFlags;
struct DerivedMesh;
-struct GridHidden;
struct MDisps;
-struct MFace;
struct Mesh;
struct ModifierData;
struct Multires;
@@ -81,8 +79,9 @@ struct DerivedMesh *get_multires_dm(struct Scene *scene, struct MultiresModifier
struct Object *ob);
void multiresModifier_del_levels(struct MultiresModifierData *, struct Object *, int direction);
void multiresModifier_base_apply(struct MultiresModifierData *mmd, struct Object *ob);
-void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Object *ob,
- int updateblock, int simple);
+void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Object *ob, int updateblock, int simple);
+void multiresModifier_sync_levels_ex(
+ struct Object *ob_dst, struct MultiresModifierData *mmd_src, struct MultiresModifierData *mmd_dst);
int multiresModifier_reshape(struct Scene *scene, struct MultiresModifierData *mmd,
struct Object *dst, struct Object *src);
int multiresModifier_reshapeFromDM(struct Scene *scene, struct MultiresModifierData *mmd,
diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h
index c3fc29e811f..3bf8bba47f5 100644
--- a/source/blender/blenkernel/BKE_nla.h
+++ b/source/blender/blenkernel/BKE_nla.h
@@ -76,6 +76,8 @@ void BKE_nlameta_flush_transforms(struct NlaStrip *mstrip);
struct NlaTrack *BKE_nlatrack_find_active(ListBase *tracks);
void BKE_nlatrack_set_active(ListBase *tracks, struct NlaTrack *nlt);
+struct NlaTrack *BKE_nlatrack_find_tweaked(struct AnimData *adt);
+
void BKE_nlatrack_solo_toggle(struct AnimData *adt, struct NlaTrack *nlt);
bool BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 44ac3b7bb38..0a6c21c2c60 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -62,24 +62,20 @@ struct bNodeTreeExec;
struct bNodeExecContext;
struct bNodeExecData;
struct GPUMaterial;
-struct GPUNode;
struct GPUNodeStack;
struct ID;
struct ImBuf;
struct ImageFormatData;
struct ListBase;
struct Main;
-struct uiBlock;
struct uiLayout;
struct MTex;
struct PointerRNA;
-struct rctf;
struct RenderData;
struct Scene;
struct Tex;
struct SpaceNode;
struct ARegion;
-struct Object;
struct ColorManagedViewSettings;
struct ColorManagedDisplaySettings;
struct bNodeInstanceHash;
@@ -323,7 +319,7 @@ typedef struct bNodeTreeType {
struct bNodeTreeType *ntreeTypeFind(const char *idname);
void ntreeTypeAdd(struct bNodeTreeType *nt);
-void ntreeTypeFreeLink(struct bNodeTreeType *nt);
+void ntreeTypeFreeLink(const struct bNodeTreeType *nt);
bool ntreeIsRegistered(struct bNodeTree *ntree);
struct GHashIterator *ntreeTypeGetIterator(void);
@@ -511,8 +507,7 @@ const struct ListBase *BKE_node_clipboard_get_links(void);
int BKE_node_clipboard_get_type(void);
/* Node Instance Hash */
-typedef struct bNodeInstanceHash
-{
+typedef struct bNodeInstanceHash {
GHash *ghash; /* XXX should be made a direct member, GHash allocation needs to support it */
} bNodeInstanceHash;
@@ -787,6 +782,7 @@ struct ShadeResult;
#define SH_NODE_COMBXYZ 189
#define SH_NODE_OUTPUT_LINESTYLE 190
#define SH_NODE_UVALONGSTROKE 191
+#define SH_NODE_TEX_POINTDENSITY 192
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1
@@ -945,6 +941,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
#define CMP_NODE_MAP_RANGE 319
#define CMP_NODE_PLANETRACKDEFORM 320
#define CMP_NODE_CORNERPIN 321
+#define CMP_NODE_SWITCH_VIEW 322
/* channel toggles */
#define CMP_CHAN_RGB 1
@@ -978,9 +975,9 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
#define CMP_TRACKPOS_ABSOLUTE_FRAME 3
/* API */
-struct CompBuf;
void ntreeCompositExecTree(struct Scene *scene, struct bNodeTree *ntree, struct RenderData *rd, int rendering, int do_previews,
- const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings);
+ const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings,
+ const char *view_name);
void ntreeCompositTagRender(struct Scene *sce);
int ntreeCompositTagAnimated(struct bNodeTree *ntree);
void ntreeCompositTagGenerators(struct bNodeTree *ntree);
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 614ed9962f1..d134701fc80 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -33,33 +33,31 @@
extern "C" {
#endif
+#include "BLI_compiler_attrs.h"
+
struct Base;
struct EvaluationContext;
struct Scene;
struct Object;
-struct Camera;
struct BoundBox;
struct View3D;
struct SoftBody;
struct BulletSoftBody;
-struct Group;
-struct bAction;
-struct RenderData;
-struct rctf;
struct MovieClip;
struct Main;
struct RigidBodyWorld;
struct HookModifierData;
+struct ModifierData;
void BKE_object_workob_clear(struct Object *workob);
void BKE_object_workob_calc_parent(struct Scene *scene, struct Object *ob, struct Object *workob);
void BKE_object_transform_copy(struct Object *ob_tar, const struct Object *ob_src);
-struct SoftBody *copy_softbody(struct SoftBody *sb, bool copy_caches);
+struct SoftBody *copy_softbody(const struct SoftBody *sb, bool copy_caches);
struct BulletSoftBody *copy_bulletsoftbody(struct BulletSoftBody *sb);
struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys);
-void BKE_object_copy_particlesystems(struct Object *obn, struct Object *ob);
-void BKE_object_copy_softbody(struct Object *obn, struct Object *ob);
+void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src);
+void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src);
void BKE_object_free_particlesystems(struct Object *ob);
void BKE_object_free_softbody(struct Object *ob);
void BKE_object_free_bulletsoftbody(struct Object *ob);
@@ -69,13 +67,13 @@ void BKE_object_update_base_layer(struct Scene *scene, struct Object *ob);
void BKE_object_free(struct Object *ob);
void BKE_object_free_ex(struct Object *ob, bool do_id_user);
void BKE_object_free_derived_caches(struct Object *ob);
-void BKE_object_free_caches(struct Object *object);
+void BKE_object_free_caches(struct Object *object, bool free_smoke_sim);
void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd);
bool BKE_object_support_modifier_type_check(struct Object *ob, int modifier_type);
-void BKE_object_link_modifiers(struct Object *ob, struct Object *from);
+void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src);
void BKE_object_free_modifiers(struct Object *ob);
void BKE_object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob);
@@ -87,9 +85,18 @@ bool BKE_object_is_in_editmode(struct Object *ob);
bool BKE_object_is_in_editmode_vgroup(struct Object *ob);
bool BKE_object_is_in_wpaint_select_vert(struct Object *ob);
-struct Object *BKE_object_add_only_object(struct Main *bmain, int type, const char *name);
-struct Object *BKE_object_add(struct Main *bmain, struct Scene *scene, int type);
-void *BKE_object_obdata_add_from_type(struct Main *bmain, int type);
+struct Object *BKE_object_add_only_object(
+ struct Main *bmain,
+ int type, const char *name)
+ ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
+struct Object *BKE_object_add(
+ struct Main *bmain, struct Scene *scene,
+ int type, const char *name)
+ ATTR_NONNULL(1, 2) ATTR_RETURNS_NONNULL;
+void *BKE_object_obdata_add_from_type(
+ struct Main *bmain,
+ int type, const char *name)
+ ATTR_NONNULL(1);
void BKE_object_lod_add(struct Object *ob);
void BKE_object_lod_sort(struct Object *ob);
@@ -118,6 +125,7 @@ void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4]);
bool BKE_object_pose_context_check(struct Object *ob);
struct Object *BKE_object_pose_armature_get(struct Object *ob);
+void BKE_object_get_parent_matrix(struct Scene *scene, struct Object *ob, struct Object *par, float parentmat[4][4]);
void BKE_object_where_is_calc(struct Scene *scene, struct Object *ob);
void BKE_object_where_is_calc_ex(struct Scene *scene, struct RigidBodyWorld *rbw, struct Object *ob, float r_originmat[3][3]);
void BKE_object_where_is_calc_time(struct Scene *scene, struct Object *ob, float ctime);
@@ -172,6 +180,32 @@ void BKE_object_tfm_protected_restore(struct Object *ob,
const ObjectTfmProtectedChannels *obtfm,
const short protectflag);
+/* Dependency graph evaluation callbacks. */
+void BKE_object_eval_local_transform(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob);
+void BKE_object_eval_parent(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob);
+void BKE_object_eval_constraints(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob);
+void BKE_object_eval_done(struct EvaluationContext *eval_ctx, struct Object *ob);
+
+void BKE_object_eval_modifier(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob,
+ struct ModifierData *md);
+void BKE_object_eval_uber_transform(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob);
+void BKE_object_eval_uber_data(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob);
+
+void BKE_object_handle_data_update(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob);
void BKE_object_handle_update(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob);
void BKE_object_handle_update_ex(struct EvaluationContext *eval_ctx,
struct Scene *scene, struct Object *ob,
@@ -183,7 +217,9 @@ int BKE_object_obdata_texspace_get(struct Object *ob, short **r_texflag, float *
int BKE_object_insert_ptcache(struct Object *ob);
void BKE_object_delete_ptcache(struct Object *ob, int index);
-struct KeyBlock *BKE_object_insert_shape_key(struct Object *ob, const char *name, const bool from_mix);
+struct KeyBlock *BKE_object_shapekey_insert(struct Object *ob, const char *name, const bool from_mix);
+bool BKE_object_shapekey_remove(struct Main *bmain, struct Object *ob, struct KeyBlock *kb);
+bool BKE_object_shapekey_free(struct Main *bmain, struct Object *ob);
bool BKE_object_flag_test_recursive(const struct Object *ob, short flag);
@@ -222,6 +258,8 @@ void BKE_object_groups_clear(struct Scene *scene, struct Base *base,
struct KDTree *BKE_object_as_kdtree(struct Object *ob, int *r_tot);
+bool BKE_object_modifier_use_time(struct Object *ob, struct ModifierData *md);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_ocean.h b/source/blender/blenkernel/BKE_ocean.h
index b750d8b283a..9b1b937febf 100644
--- a/source/blender/blenkernel/BKE_ocean.h
+++ b/source/blender/blenkernel/BKE_ocean.h
@@ -74,13 +74,14 @@ typedef struct OceanCache {
#define OCEAN_CACHING 1
#define OCEAN_CACHED 2
-struct Ocean *BKE_add_ocean(void);
-void BKE_free_ocean_data(struct Ocean *oc);
-void BKE_free_ocean(struct Ocean *oc);
+struct Ocean *BKE_ocean_add(void);
+void BKE_ocean_free_data(struct Ocean *oc);
+void BKE_ocean_free(struct Ocean *oc);
-void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp,
- float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals, short do_jacobian, int seed);
-void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount);
+void BKE_ocean_init(
+ struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp,
+ float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals, short do_jacobian, int seed);
+void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount);
/* sampling the ocean surface */
float BKE_ocean_jminus_to_foam(float jminus, float coverage);
@@ -92,16 +93,17 @@ void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j)
/* ocean cache handling */
-struct OceanCache *BKE_init_ocean_cache(const char *bakepath, const char *relbase,
- int start, int end, float wave_scale,
- float chop_amount, float foam_coverage, float foam_fade, int resolution);
-void BKE_simulate_ocean_cache(struct OceanCache *och, int frame);
+struct OceanCache *BKE_ocean_init_cache(
+ const char *bakepath, const char *relbase,
+ int start, int end, float wave_scale,
+ float chop_amount, float foam_coverage, float foam_fade, int resolution);
+void BKE_ocean_simulate_cache(struct OceanCache *och, int frame);
-void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel), void *update_cb_data);
+void BKE_ocean_bake(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel), void *update_cb_data);
void BKE_ocean_cache_eval_uv(struct OceanCache *och, struct OceanResult *ocr, int f, float u, float v);
void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, int f, int i, int j);
-void BKE_free_ocean_cache(struct OceanCache *och);
+void BKE_ocean_free_cache(struct OceanCache *och);
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_treehash.h b/source/blender/blenkernel/BKE_outliner_treehash.h
index 54deef1ce2f..454edb40c4e 100644
--- a/source/blender/blenkernel/BKE_treehash.h
+++ b/source/blender/blenkernel/BKE_outliner_treehash.h
@@ -19,34 +19,33 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
-#ifndef __BKE_TREEHASH_H__
-#define __BKE_TREEHASH_H__
+#ifndef __BKE_OUTLINER_TREEHASH_H__
+#define __BKE_OUTLINER_TREEHASH_H__
-/** \file BKE_treehash.h
+/** \file BKE_outliner_treehash.h
* \ingroup bke
*/
struct ID;
-struct GHash;
struct BLI_mempool;
struct TreeStoreElem;
/* create and fill hashtable with treestore elements */
-void *BKE_treehash_create_from_treestore(struct BLI_mempool *treestore);
+void *BKE_outliner_treehash_create_from_treestore(struct BLI_mempool *treestore);
/* full rebuild for already allocated hashtable */
-void *BKE_treehash_rebuild_from_treestore(void *treehash, struct BLI_mempool *treestore);
+void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, struct BLI_mempool *treestore);
/* full rebuild for already allocated hashtable */
-void BKE_treehash_add_element(void *treehash, struct TreeStoreElem *elem);
+void BKE_outliner_treehash_add_element(void *treehash, struct TreeStoreElem *elem);
/* find first unused element with specific type, nr and id */
-struct TreeStoreElem *BKE_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id);
+struct TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id);
/* find user or unused element with specific type, nr and id */
-struct TreeStoreElem *BKE_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id);
+struct TreeStoreElem *BKE_outliner_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id);
/* free treehash structure */
-void BKE_treehash_free(void *treehash);
+void BKE_outliner_treehash_free(void *treehash);
#endif
diff --git a/source/blender/blenkernel/BKE_packedFile.h b/source/blender/blenkernel/BKE_packedFile.h
index 8fab44121de..a2397922061 100644
--- a/source/blender/blenkernel/BKE_packedFile.h
+++ b/source/blender/blenkernel/BKE_packedFile.h
@@ -48,7 +48,7 @@ struct PackedFile *dupPackedFile(const struct PackedFile *pf_src);
struct PackedFile *newPackedFile(struct ReportList *reports, const char *filename, const char *relabase);
struct PackedFile *newPackedFileMemory(void *mem, int memlen);
-void packAll(struct Main *bmain, struct ReportList *reports);
+void packAll(struct Main *bmain, struct ReportList *reports, bool verbose);
void packLibraries(struct Main *bmain, struct ReportList *reports);
/* unpack */
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 3e4e6ab4146..09ccc3dced7 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -37,12 +37,10 @@ struct BMesh;
struct BMFace;
struct Brush;
struct CurveMapping;
-struct MDisps;
struct MeshElemMap;
struct GridPaintMask;
struct Main;
struct MFace;
-struct MultireModifierData;
struct MVert;
struct Object;
struct Paint;
@@ -57,7 +55,6 @@ struct StrokeCache;
struct Tex;
struct ImagePool;
struct UnifiedPaintSettings;
-struct wmOperator;
enum OverlayFlags;
@@ -103,7 +100,7 @@ struct Palette *BKE_palette_add(struct Main *bmain, const char *name);
struct PaletteColor *BKE_palette_color_add(struct Palette *palette);
bool BKE_palette_is_empty(const struct Palette *palette);
void BKE_palette_color_remove(struct Palette *palette, struct PaletteColor *color);
-void BKE_palette_cleanup(struct Palette *palette);
+void BKE_palette_clear(struct Palette *palette);
/* paint curves */
struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name);
@@ -123,6 +120,7 @@ void BKE_paint_brush_set(struct Paint *paint, struct Brush *br);
struct Palette *BKE_paint_palette(struct Paint *paint);
void BKE_paint_palette_set(struct Paint *p, struct Palette *palette);
void BKE_paint_curve_set(struct Brush *br, struct PaintCurve *pc);
+void BKE_paint_curve_clamp_endpoint_add_index(struct PaintCurve *pc, const int add_index);
void BKE_paint_data_warning(struct ReportList *reports, bool uvs, bool mat, bool tex, bool stencil);
bool BKE_paint_proj_mesh_data_check(struct Scene *scene, struct Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil);
@@ -146,6 +144,7 @@ float paint_grid_paint_mask(const struct GridPaintMask *gpm, unsigned level,
/* stroke related */
void paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, const float mouse_pos[2]);
+void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, float rotation);
void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]);
@@ -158,7 +157,6 @@ typedef struct SculptSession {
struct MPoly *mpoly;
struct MLoop *mloop;
int totvert, totpoly;
- float (*face_normals)[3];
struct KeyBlock *kb;
float *vmask;
@@ -197,8 +195,8 @@ typedef struct SculptSession {
struct StrokeCache *cache;
} SculptSession;
-void BKE_free_sculptsession(struct Object *ob);
-void BKE_free_sculptsession_deformMats(struct SculptSession *ss);
+void BKE_sculptsession_free(struct Object *ob);
+void BKE_sculptsession_free_deformMats(struct SculptSession *ss);
void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder);
void BKE_sculptsession_bm_to_me_for_render(struct Object *object);
void BKE_sculpt_update_mesh_elements(struct Scene *scene, struct Sculpt *sd, struct Object *ob,
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index ab3231d7c12..f8ddb33b0ba 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -45,10 +45,8 @@ struct ParticleSystemModifierData;
struct ParticleSystem;
struct ParticleKey;
struct ParticleSettings;
-struct HairKey;
struct Main;
-struct Group;
struct Object;
struct Scene;
struct DerivedMesh;
@@ -57,12 +55,10 @@ struct MTFace;
struct MCol;
struct MFace;
struct MVert;
-struct IpoCurve;
struct LatticeDeformData;
struct LinkNode;
struct KDTree;
struct RNG;
-struct SurfaceModifierData;
struct BVHTreeRay;
struct BVHTreeRayHit;
struct EdgeHash;
@@ -122,6 +118,7 @@ typedef struct ParticleTexture {
float damp, gravity, field; /* used in physics */
float length, clump, kink_freq, kink_amp, effector; /* used in path caching */
float rough1, rough2, roughe; /* used in path caching */
+ float color[3];
} ParticleTexture;
typedef struct ParticleSeam {
@@ -395,7 +392,7 @@ void psys_get_dupli_path_transform(struct ParticleSimulationData *sim, struct Pa
void psys_thread_context_init(struct ParticleThreadContext *ctx, struct ParticleSimulationData *sim);
void psys_thread_context_free(struct ParticleThreadContext *ctx);
-void psys_tasks_create(struct ParticleThreadContext *ctx, int totpart, struct ParticleTask **r_tasks, int *r_numtasks);
+void psys_tasks_create(struct ParticleThreadContext *ctx, int startpart, int endpart, struct ParticleTask **r_tasks, int *r_numtasks);
void psys_tasks_free(struct ParticleTask *tasks, int numtasks);
void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3], float zvec[3], float center[3]);
@@ -431,6 +428,7 @@ void psys_vec_rot_to_face(struct DerivedMesh *dm, struct ParticleData *pa, float
void psys_mat_hair_to_object(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]);
void psys_mat_hair_to_global(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]);
void psys_mat_hair_to_orco(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]);
+void psys_child_mat_to_object(struct Object *ob, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd, struct ChildParticle *cpa, float hairmat[4][4]);
float psys_get_dietime_from_cache(struct PointCache *cache, int index);
@@ -445,6 +443,7 @@ void psys_interpolate_face(struct MVert *mvert, struct MFace *mface, struct MTFa
float orco[3], float ornor[3]);
float psys_particle_value_from_verts(struct DerivedMesh *dm, short from, struct ParticleData *pa, float *values);
void psys_get_from_key(struct ParticleKey *key, float loc[3], float vel[3], float rot[4], float *time);
+int psys_get_index_on_dm(struct ParticleSystem *psys, struct DerivedMesh *dm, ParticleData *pa, int *mapindex, float mapfw[4]);
/* BLI_bvhtree_ray_cast callback */
void BKE_psys_collision_neartest_cb(void *userdata, int index, const struct BVHTreeRay *ray, struct BVHTreeRayHit *hit);
@@ -499,4 +498,12 @@ typedef struct ParticleRenderData {
#define DMCACHE_NOTFOUND -1
#define DMCACHE_ISCHILD -2
+/* **** Depsgraph evaluation **** */
+
+struct EvaluationContext;
+
+void BKE_particle_system_eval(struct EvaluationContext *eval_ctx,
+ struct Object *ob,
+ struct ParticleSystem *psys);
+
#endif
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index c8c693fc342..227994b73ee 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -34,8 +34,6 @@ struct CCGElem;
struct CCGKey;
struct CustomData;
struct DMFlagMat;
-struct DMGridAdjacency;
-struct GHash;
struct MFace;
struct MVert;
struct PBVH;
@@ -64,7 +62,7 @@ PBVH *BKE_pbvh_new(void);
void BKE_pbvh_build_mesh(PBVH *bvh, struct MFace *faces, struct MVert *verts,
int totface, int totvert, struct CustomData *vdata);
void BKE_pbvh_build_grids(PBVH *bvh, struct CCGElem **grid_elems,
- struct DMGridAdjacency *gridadj, int totgrid,
+ int totgrid,
struct CCGKey *key, void **gridfaces, struct DMFlagMat *flagmats,
unsigned int **grid_hidden);
void BKE_pbvh_build_bmesh(PBVH *bvh, struct BMesh *bm, bool smooth_shading, struct BMLog *log, const int cd_vert_node_offset, const int cd_face_node_offset);
@@ -105,8 +103,9 @@ bool BKE_pbvh_bmesh_node_raycast_detail(
/* for orthographic cameras, project the far away ray segment points to the root node so
* we can have better precision. */
-void BKE_pbvh_raycast_project_ray_root(PBVH *bvh, bool original, float ray_start[3],
- float ray_end[3], float ray_normal[3]);
+void BKE_pbvh_raycast_project_ray_root(
+ PBVH *bvh, bool original,
+ float ray_start[3], float ray_end[3], float ray_normal[3]);
/* Drawing */
@@ -122,6 +121,7 @@ typedef enum {
} PBVHType;
PBVHType BKE_pbvh_type(const PBVH *bvh);
+bool BKE_pbvh_has_faces(const PBVH *bvh);
/* Get the PBVH root's bounding box */
void BKE_pbvh_bounding_box(const PBVH *bvh, float min[3], float max[3]);
@@ -144,8 +144,10 @@ typedef enum {
PBVH_Subdivide = 1,
PBVH_Collapse = 2,
} PBVHTopologyUpdateMode;
-bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode,
- const float center[3], float radius);
+bool BKE_pbvh_bmesh_update_topology(
+ PBVH *bvh, PBVHTopologyUpdateMode mode,
+ const float center[3], const float view_normal[3],
+ float radius);
/* Node Access */
@@ -173,7 +175,7 @@ void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden);
void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node,
int **grid_indices, int *totgrid, int *maxgrid, int *gridsize,
- struct CCGElem ***grid_elems, struct DMGridAdjacency **gridadj);
+ struct CCGElem ***grid_elems);
void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node,
int *uniquevert, int *totvert);
void BKE_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node,
@@ -201,7 +203,7 @@ void BKE_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]);
void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]);
void BKE_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***r_gridfaces, int *r_totface);
void BKE_pbvh_grids_update(PBVH *bvh, struct CCGElem **grid_elems,
- struct DMGridAdjacency *gridadj, void **gridfaces,
+ void **gridfaces,
struct DMFlagMat *flagmats, unsigned int **grid_hidden);
/* Layer displacement */
@@ -334,6 +336,9 @@ void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *pro
void BKE_pbvh_node_free_proxies(PBVHNode *node);
PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node);
void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***nodes, int *totnode);
+void BKE_pbvh_node_get_bm_orco_data(
+ PBVHNode *node,
+ int (**r_orco_tris)[3], int *r_orco_tris_num, float (**r_orco_coords)[3]);
//void BKE_pbvh_node_BB_reset(PBVHNode *node);
//void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]);
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index e18e9d46a25..3d67b91d767 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -267,10 +267,8 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, struct Object *ob, struct Rig
void BKE_ptcache_ids_from_object(struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis);
-/***************** Global funcs ****************************/
-void BKE_ptcache_remove(void);
-
/************ ID specific functions ************************/
+void BKE_ptcache_id_clear_ex(PTCacheID *pid, int mode, unsigned int cfra, bool allow_file_delete);
void BKE_ptcache_id_clear(PTCacheID *id, int mode, unsigned int cfra);
int BKE_ptcache_id_exist(PTCacheID *id, int cfra);
int BKE_ptcache_id_reset(struct Scene *scene, PTCacheID *id, int mode);
@@ -303,7 +301,7 @@ struct PointCache *BKE_ptcache_add(struct ListBase *ptcaches);
void BKE_ptcache_free_mem(struct ListBase *mem_cache);
void BKE_ptcache_free(struct PointCache *cache);
void BKE_ptcache_free_list(struct ListBase *ptcaches);
-struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, struct ListBase *ptcaches_old, bool copy_data);
+struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, const struct ListBase *ptcaches_old, bool copy_data);
/********************** Baking *********************/
@@ -314,10 +312,10 @@ void BKE_ptcache_quick_cache_all(struct Main *bmain, struct Scene *scene);
void BKE_ptcache_bake(struct PTCacheBaker *baker);
/* Convert disk cache to memory cache. */
-void BKE_ptcache_disk_to_mem(struct PTCacheID *pid);
+void BKE_ptcache_disk_to_mem(struct PTCacheID *pid, bool clear);
/* Convert memory cache to disk cache. */
-void BKE_ptcache_mem_to_disk(struct PTCacheID *pid);
+void BKE_ptcache_mem_to_disk(struct PTCacheID *pid, bool clear);
/* Convert disk cache to memory cache and vice versa. Clears the cache that was converted. */
void BKE_ptcache_toggle_disk_cache(struct PTCacheID *pid);
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index c946f3ac9e8..b327f0c2574 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -39,7 +39,6 @@ struct RigidBodyOb;
struct Scene;
struct Object;
-struct Group;
/* -------------- */
/* Memory Management */
@@ -99,4 +98,19 @@ void BKE_rigidbody_cache_reset(struct RigidBodyWorld *rbw);
void BKE_rigidbody_rebuild_world(struct Scene *scene, float ctime);
void BKE_rigidbody_do_simulation(struct Scene *scene, float ctime);
+/* -------------------- */
+/* Depsgraph evaluation */
+
+struct EvaluationContext;
+
+void BKE_rigidbody_rebuild_sim(struct EvaluationContext *eval_ctx,
+ struct Scene *scene);
+
+void BKE_rigidbody_eval_simulation(struct EvaluationContext *eval_ctx,
+ struct Scene *scene);
+
+void BKE_rigidbody_object_sync_transforms(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob);
+
#endif /* __BKE_RIGIDBODY_H__ */
diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h
index d598a26fdf9..ebdd159b40c 100644
--- a/source/blender/blenkernel/BKE_sca.h
+++ b/source/blender/blenkernel/BKE_sca.h
@@ -31,7 +31,6 @@
* \ingroup bke
*/
-struct Text;
struct bSensor;
struct Object;
struct bController;
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index 149472db8fa..e6b19296068 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -39,16 +39,14 @@ extern "C" {
struct AviCodecData;
struct Base;
-struct DisplaySafeAreas;
struct EvaluationContext;
-struct bglMats;
+struct Group;
struct Main;
struct Object;
struct QuicktimeCodecData;
struct RenderData;
struct SceneRenderLayer;
struct Scene;
-struct Text;
struct UnitSettings;
struct Main;
@@ -73,6 +71,7 @@ void BKE_scene_free(struct Scene *sce);
struct Scene *BKE_scene_add(struct Main *bmain, const char *name);
/* base functions */
+struct Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name);
struct Base *BKE_scene_base_find(struct Scene *scene, struct Object *ob);
struct Base *BKE_scene_base_add(struct Scene *sce, struct Object *ob);
void BKE_scene_base_unlink(struct Scene *sce, struct Base *base);
@@ -113,28 +112,37 @@ char *BKE_scene_find_last_marker_name(struct Scene *scene, int frame);
/* checks for cycle, returns 1 if it's all OK */
bool BKE_scene_validate_setscene(struct Main *bmain, struct Scene *sce);
-float BKE_scene_frame_get(struct Scene *scene);
-float BKE_scene_frame_get_from_ctime(struct Scene *scene, const float frame);
+float BKE_scene_frame_get(const struct Scene *scene);
+float BKE_scene_frame_get_from_ctime(const struct Scene *scene, const float frame);
void BKE_scene_frame_set(struct Scene *scene, double cfra);
/* ** Scene evaluation ** */
void BKE_scene_update_tagged(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce);
void BKE_scene_update_for_newframe(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce, unsigned int lay);
void BKE_scene_update_for_newframe_ex(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce, unsigned int lay, bool do_invisible_flush);
+void BKE_scene_update_group_for_newframe(struct EvaluationContext *eval_ctx,
+ struct Main *bmain,
+ struct Scene *scene,
+ struct Group *group,
+ unsigned int lay);
struct SceneRenderLayer *BKE_scene_add_render_layer(struct Scene *sce, const char *name);
bool BKE_scene_remove_render_layer(struct Main *main, struct Scene *scene, struct SceneRenderLayer *srl);
+struct SceneRenderView *BKE_scene_add_render_view(struct Scene *sce, const char *name);
+bool BKE_scene_remove_render_view(struct Scene *scene, struct SceneRenderView *srv);
+
/* render profile */
-int get_render_subsurf_level(struct RenderData *r, int level);
-int get_render_child_particle_number(struct RenderData *r, int num);
-int get_render_shadow_samples(struct RenderData *r, int samples);
-float get_render_aosss_error(struct RenderData *r, float error);
+int get_render_subsurf_level(const struct RenderData *r, int level, bool for_render);
+int get_render_child_particle_number(const struct RenderData *r, int num, bool for_render);
+int get_render_shadow_samples(const struct RenderData *r, int samples);
+float get_render_aosss_error(const struct RenderData *r, float error);
-bool BKE_scene_use_new_shading_nodes(struct Scene *scene);
+bool BKE_scene_use_new_shading_nodes(const struct Scene *scene);
+bool BKE_scene_use_shading_nodes_custom(struct Scene *scene);
-bool BKE_scene_uses_blender_internal(struct Scene *scene);
-bool BKE_scene_uses_blender_game(struct Scene *scene);
+bool BKE_scene_uses_blender_internal(const struct Scene *scene);
+bool BKE_scene_uses_blender_game(const struct Scene *scene);
void BKE_scene_disable_color_management(struct Scene *scene);
bool BKE_scene_check_color_management_enabled(const struct Scene *scene);
@@ -145,6 +153,23 @@ int BKE_render_num_threads(const struct RenderData *r);
double BKE_scene_unit_scale(const struct UnitSettings *unit, const int unit_type, double value);
+/* multiview */
+bool BKE_scene_multiview_is_stereo3d(const struct RenderData *rd);
+bool BKE_scene_multiview_is_render_view_active(const struct RenderData *rd, const struct SceneRenderView *srv);
+bool BKE_scene_multiview_is_render_view_first(const struct RenderData *rd, const char *viewname);
+bool BKE_scene_multiview_is_render_view_last(const struct RenderData *rd, const char *viewname);
+size_t BKE_scene_multiview_num_views_get(const struct RenderData *rd);
+struct SceneRenderView *BKE_scene_multiview_render_view_findindex(const struct RenderData *rd, const int view_id);
+const char *BKE_scene_multiview_render_view_name_get(const struct RenderData *rd, const int view_id);
+size_t BKE_scene_multiview_view_id_get(const struct RenderData *rd, const char *viewname);
+void BKE_scene_multiview_filepath_get(struct SceneRenderView *srv, const char *filepath, char *r_filepath);
+void BKE_scene_multiview_view_filepath_get(const struct RenderData *rd, const char *filepath, const char *view, char *r_filepath);
+const char *BKE_scene_multiview_view_suffix_get(const struct RenderData *rd, const char *viewname);
+const char *BKE_scene_multiview_view_id_suffix_get(const struct RenderData *rd, const size_t view_id);
+void BKE_scene_multiview_view_prefix_get(struct Scene *scene, const char *name, char *rprefix, char **rext);
+void BKE_scene_multiview_videos_dimensions_get(const struct RenderData *rd, const size_t width, const size_t height, size_t *r_width, size_t *r_height);
+size_t BKE_scene_multiview_num_videos_get(const struct RenderData *rd);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index efe2c52e99c..60fd402ef4b 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -47,7 +47,6 @@ struct bContextDataResult;
struct bScreen;
struct uiLayout;
struct uiList;
-struct uiMenuItem;
struct wmKeyConfig;
struct wmNotifier;
struct wmWindow;
@@ -277,6 +276,9 @@ void BKE_spacedata_freelist(ListBase *lb);
void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2);
void BKE_spacedata_draw_locks(int set);
+void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *));
+void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id);
+
/* area/regions */
struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar);
void BKE_area_region_free(struct SpaceType *st, struct ARegion *ar);
@@ -284,6 +286,7 @@ void BKE_screen_area_free(struct ScrArea *sa);
struct ARegion *BKE_area_find_region_type(struct ScrArea *sa, int type);
struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa);
+struct ARegion *BKE_area_find_region_xy(struct ScrArea *sa, const int regiontype, int x, int y);
struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, struct SpaceLink *sl) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
struct ScrArea *BKE_screen_find_big_area(struct bScreen *sc, const int spacetype, const short min);
struct ScrArea *BKE_screen_find_area_xy(struct bScreen *sc, const int spacetype, int x, int y);
@@ -293,6 +296,8 @@ unsigned int BKE_screen_view3d_layer_active_ex(
unsigned int BKE_screen_view3d_layer_active(
const struct View3D *v3d, const struct Scene *scene) ATTR_NONNULL(2);
+unsigned int BKE_screen_view3d_layer_all(const struct bScreen *sc) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+
void BKE_screen_view3d_sync(struct View3D *v3d, struct Scene *scene);
void BKE_screen_view3d_scene_sync(struct bScreen *sc);
void BKE_screen_view3d_main_sync(ListBase *screen_lb, struct Scene *scene);
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 8958fc2ca85..5f159b14fb8 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -38,11 +38,10 @@ struct GSet;
struct ImBuf;
struct Main;
struct Mask;
-struct MovieClip;
struct Scene;
struct Sequence;
struct SequenceModifierData;
-struct Strip;
+struct Stereo3dFormat;
struct StripElem;
struct bSound;
@@ -101,6 +100,7 @@ typedef struct SeqRenderData {
float motion_blur_shutter;
bool skip_cache;
bool is_proxy_render;
+ size_t view_id;
} SeqRenderData;
void BKE_sequencer_new_render_data(
@@ -225,6 +225,7 @@ void BKE_sequencer_base_clipboard_pointers_store(struct ListBase *seqbase);
void BKE_sequencer_base_clipboard_pointers_restore(struct ListBase *seqbase, struct Main *bmain);
void BKE_sequence_free(struct Scene *scene, struct Sequence *seq);
+void BKE_sequence_free_anim(struct Sequence *seq);
const char *BKE_sequence_give_name(struct Sequence *seq);
ListBase *BKE_sequence_seqbase_get(struct Sequence *seq, int *r_offset);
void BKE_sequence_calc(struct Scene *scene, struct Sequence *seq);
@@ -238,7 +239,7 @@ struct StripElem *BKE_sequencer_give_stripelem(struct Sequence *seq, int cfra);
void BKE_sequencer_update_changed_seq_and_deps(struct Scene *scene, struct Sequence *changed_seq, int len_change, int ibuf_change);
bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context, struct Sequence *seq, float cfra);
-struct SeqIndexBuildContext *BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Scene *scene, struct Sequence *seq, struct GSet *file_list);
+void BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Scene *scene, struct Sequence *seq, struct GSet *file_list, ListBase *queue);
void BKE_sequencer_proxy_rebuild(struct SeqIndexBuildContext *context, short *stop, short *do_update, float *progress);
void BKE_sequencer_proxy_rebuild_finish(struct SeqIndexBuildContext *context, bool stop);
@@ -296,7 +297,7 @@ int BKE_sequence_effect_get_supports_mask(int seq_type);
* Sequencer editing functions
* **********************************************************************
*/
-
+
/* for transform but also could use elsewhere */
int BKE_sequence_tx_get_final_left(struct Sequence *seq, bool metaclip);
int BKE_sequence_tx_get_final_right(struct Sequence *seq, bool metaclip);
@@ -358,6 +359,10 @@ typedef struct SeqLoadInfo {
int len; /* only for image strips */
char path[1024]; /* 1024 = FILE_MAX */
+ /* multiview */
+ char views_format;
+ struct Stereo3dFormat *stereo3d_format;
+
/* return values */
char name[64];
struct Sequence *seq_sound; /* for movie's */
@@ -402,7 +407,7 @@ struct Sequence *BKE_sequencer_add_sound_strip(struct bContext *C, ListBase *seq
struct Sequence *BKE_sequencer_add_movie_strip(struct bContext *C, ListBase *seqbasep, struct SeqLoadInfo *seq_load);
/* view3d draw callback, run when not in background view */
-typedef struct ImBuf *(*SequencerDrawView)(struct Scene *, struct Object *, int, int, unsigned int, int, bool, bool, bool, int, char[256]);
+typedef struct ImBuf *(*SequencerDrawView)(struct Scene *, struct Object *, int, int, unsigned int, int, bool, bool, bool, int, const char *, char[256]);
extern SequencerDrawView sequencer_view3d_cb;
/* copy/paste */
@@ -436,7 +441,7 @@ typedef struct SequenceModifierTypeInfo {
void (*apply) (struct SequenceModifierData *smd, struct ImBuf *ibuf, struct ImBuf *mask);
} SequenceModifierTypeInfo;
-struct SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type);
+const struct SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type);
struct SequenceModifierData *BKE_sequence_modifier_new(struct Sequence *seq, const char *name, int type);
bool BKE_sequence_modifier_remove(struct Sequence *seq, struct SequenceModifierData *smd);
@@ -450,7 +455,9 @@ void BKE_sequence_modifier_list_copy(struct Sequence *seqn, struct Sequence *seq
int BKE_sequence_supports_modifiers(struct Sequence *seq);
/* internal filters */
-struct ImBuf *BKE_sequencer_render_mask_input(const SeqRenderData *context, int mask_input_type, struct Sequence *mask_sequence, struct Mask *mask_id, int cfra, bool make_float);
+struct ImBuf *BKE_sequencer_render_mask_input(
+ const SeqRenderData *context, int mask_input_type, struct Sequence *mask_sequence, struct Mask *mask_id,
+ int cfra, int fra_offset, bool make_float);
void BKE_sequencer_color_balance_apply(struct StripColorBalance *cb, struct ImBuf *ibuf, float mul, bool make_float, struct ImBuf *mask_input);
#endif /* __BKE_SEQUENCER_H__ */
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h
index 070cd4a9cf0..070f5c762db 100644
--- a/source/blender/blenkernel/BKE_shrinkwrap.h
+++ b/source/blender/blenkernel/BKE_shrinkwrap.h
@@ -47,7 +47,6 @@
*/
struct Object;
-struct Scene;
struct DerivedMesh;
struct MVert;
struct MDeformVert;
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index a4182b8405f..819b49da8e9 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -35,9 +35,7 @@
#define SOUND_WAVE_SAMPLES_PER_SECOND 250
-struct PackedFile;
struct bSound;
-struct ListBase;
struct Main;
struct Sequence;
@@ -46,98 +44,98 @@ typedef struct SoundWaveform {
float *data;
} SoundWaveform;
-void sound_init_once(void);
-void sound_exit_once(void);
+void BKE_sound_init_once(void);
+void BKE_sound_exit_once(void);
-void sound_init(struct Main *main);
+void BKE_sound_init(struct Main *main);
-void sound_init_main(struct Main *bmain);
+void BKE_sound_init_main(struct Main *bmain);
-void sound_exit(void);
+void BKE_sound_exit(void);
-void sound_force_device(int device);
-int sound_define_from_str(const char *str);
+void BKE_sound_force_device(int device);
+int BKE_sound_define_from_str(const char *str);
-struct bSound *sound_new_file(struct Main *main, const char *filename);
+struct bSound *BKE_sound_new_file(struct Main *main, const char *filename);
// XXX unused currently
#if 0
-struct bSound *sound_new_buffer(struct Main *bmain, struct bSound *source);
+struct bSound *BKE_sound_new_buffer(struct Main *bmain, struct bSound *source);
-struct bSound *sound_new_limiter(struct Main *bmain, struct bSound *source, float start, float end);
+struct bSound *BKE_sound_new_limiter(struct Main *bmain, struct bSound *source, float start, float end);
#endif
-void sound_delete(struct Main *bmain, struct bSound *sound);
+void BKE_sound_delete(struct Main *bmain, struct bSound *sound);
-void sound_cache(struct bSound *sound);
+void BKE_sound_cache(struct bSound *sound);
-void sound_delete_cache(struct bSound *sound);
+void BKE_sound_delete_cache(struct bSound *sound);
-void sound_load(struct Main *main, struct bSound *sound);
+void BKE_sound_load(struct Main *main, struct bSound *sound);
void BKE_sound_free(struct bSound *sound);
#ifdef __AUD_C_API_H__
-AUD_Device *sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume);
+AUD_Device *BKE_sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume);
#endif
-void sound_create_scene(struct Scene *scene);
+void BKE_sound_create_scene(struct Scene *scene);
-void sound_destroy_scene(struct Scene *scene);
+void BKE_sound_destroy_scene(struct Scene *scene);
-void sound_mute_scene(struct Scene *scene, int muted);
+void BKE_sound_mute_scene(struct Scene *scene, int muted);
-void sound_update_fps(struct Scene *scene);
+void BKE_sound_update_fps(struct Scene *scene);
-void sound_update_scene_listener(struct Scene *scene);
+void BKE_sound_update_scene_listener(struct Scene *scene);
-void *sound_scene_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip);
-void *sound_scene_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence);
+void *BKE_sound_scene_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip);
+void *BKE_sound_scene_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence);
-void *sound_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip);
-void *sound_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence);
+void *BKE_sound_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip);
+void *BKE_sound_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence);
-void sound_remove_scene_sound(struct Scene *scene, void *handle);
+void BKE_sound_remove_scene_sound(struct Scene *scene, void *handle);
-void sound_mute_scene_sound(void *handle, char mute);
+void BKE_sound_mute_scene_sound(void *handle, char mute);
-void sound_move_scene_sound(struct Scene *scene, void *handle, int startframe, int endframe, int frameskip);
-void sound_move_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence);
+void BKE_sound_move_scene_sound(struct Scene *scene, void *handle, int startframe, int endframe, int frameskip);
+void BKE_sound_move_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence);
-void sound_update_scene_sound(void *handle, struct bSound *sound);
+void BKE_sound_update_scene_sound(void *handle, struct bSound *sound);
-void sound_set_cfra(int cfra);
+void BKE_sound_set_cfra(int cfra);
-void sound_set_scene_volume(struct Scene *scene, float volume);
+void BKE_sound_set_scene_volume(struct Scene *scene, float volume);
-void sound_set_scene_sound_volume(void *handle, float volume, char animated);
+void BKE_sound_set_scene_sound_volume(void *handle, float volume, char animated);
-void sound_set_scene_sound_pitch(void *handle, float pitch, char animated);
+void BKE_sound_set_scene_sound_pitch(void *handle, float pitch, char animated);
-void sound_set_scene_sound_pan(void *handle, float pan, char animated);
+void BKE_sound_set_scene_sound_pan(void *handle, float pan, char animated);
-void sound_update_sequencer(struct Main *main, struct bSound *sound);
+void BKE_sound_update_sequencer(struct Main *main, struct bSound *sound);
-void sound_play_scene(struct Scene *scene);
+void BKE_sound_play_scene(struct Scene *scene);
-void sound_stop_scene(struct Scene *scene);
+void BKE_sound_stop_scene(struct Scene *scene);
-void sound_seek_scene(struct Main *bmain, struct Scene *scene);
+void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene);
-float sound_sync_scene(struct Scene *scene);
+float BKE_sound_sync_scene(struct Scene *scene);
-int sound_scene_playing(struct Scene *scene);
+int BKE_sound_scene_playing(struct Scene *scene);
-void sound_free_waveform(struct bSound *sound);
+void BKE_sound_free_waveform(struct bSound *sound);
-void sound_read_waveform(struct bSound *sound, short *stop);
+void BKE_sound_read_waveform(struct bSound *sound, short *stop);
-void sound_update_scene(struct Main *bmain, struct Scene *scene);
+void BKE_sound_update_scene(struct Main *bmain, struct Scene *scene);
-void *sound_get_factory(void *sound);
+void *BKE_sound_get_factory(void *sound);
-float sound_get_length(struct bSound *sound);
+float BKE_sound_get_length(struct bSound *sound);
-bool sound_is_jack_supported(void);
+bool BKE_sound_is_jack_supported(void);
#endif /* __BKE_SOUND_H__ */
diff --git a/source/blender/blenkernel/BKE_strands.h b/source/blender/blenkernel/BKE_strands.h
new file mode 100644
index 00000000000..2ec1363727b
--- /dev/null
+++ b/source/blender/blenkernel/BKE_strands.h
@@ -0,0 +1,358 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BKE_STRANDS_H__
+#define __BKE_STRANDS_H__
+
+#include "BLI_utildefines.h"
+
+#include "DNA_strands_types.h"
+
+struct StrandChildIterator;
+
+struct Strands *BKE_strands_new(int strands, int verts);
+struct Strands *BKE_strands_copy(struct Strands *strands);
+void BKE_strands_free(struct Strands *strands);
+
+void BKE_strands_add_motion_state(struct Strands *strands);
+void BKE_strands_remove_motion_state(struct Strands *strands);
+void BKE_strands_state_copy_rest_positions(struct Strands *strands);
+void BKE_strands_state_clear_velocities(struct Strands *strands);
+
+void BKE_strands_ensure_normals(struct Strands *strands);
+
+void BKE_strands_get_minmax(struct Strands *strands, float min[3], float max[3], bool use_motion_state);
+
+
+struct StrandsChildren *BKE_strands_children_new(int strands, int verts);
+struct StrandsChildren *BKE_strands_children_copy(struct StrandsChildren *strands);
+void BKE_strands_children_free(struct StrandsChildren *strands);
+
+void BKE_strands_children_add_uvs(struct StrandsChildren *strands, int num_layers);
+void BKE_strands_children_add_vcols(struct StrandsChildren *strands, int num_layers);
+
+void BKE_strands_children_deform(struct StrandsChildren *strands, struct Strands *parents, bool use_motion);
+
+void BKE_strands_children_ensure_normals(struct StrandsChildren *strands);
+
+void BKE_strands_children_get_minmax(struct StrandsChildren *strands, float min[3], float max[3]);
+
+/* ------------------------------------------------------------------------- */
+/* Strand Curves Iterator */
+
+typedef struct StrandIterator {
+ int index, tot;
+ struct StrandsCurve *curve;
+ struct StrandsVertex *verts;
+ struct StrandsMotionState *state;
+} StrandIterator;
+
+BLI_INLINE void BKE_strand_iter_init(StrandIterator *iter, Strands *strands)
+{
+ iter->tot = strands->totcurves;
+ iter->index = 0;
+ iter->curve = strands->curves;
+ iter->verts = strands->verts;
+ iter->state = strands->state;
+}
+
+BLI_INLINE bool BKE_strand_iter_valid(StrandIterator *iter)
+{
+ return iter->index < iter->tot;
+}
+
+BLI_INLINE void BKE_strand_iter_next(StrandIterator *iter)
+{
+ const int numverts = iter->curve->numverts;
+
+ ++iter->index;
+ ++iter->curve;
+ iter->verts += numverts;
+ if (iter->state)
+ iter->state += numverts;
+}
+
+BLI_INLINE size_t BKE_strand_iter_curve_offset(Strands *strands, StrandIterator *iter)
+{
+ return iter->curve - strands->curves;
+}
+
+BLI_INLINE size_t BKE_strand_iter_vertex_offset(Strands *strands, StrandIterator *iter)
+{
+ return iter->verts - strands->verts;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Strand Vertices Iterator */
+
+typedef struct StrandVertexIterator {
+ int index, tot;
+ StrandsVertex *vertex;
+ StrandsMotionState *state;
+} StrandVertexIterator;
+
+BLI_INLINE void BKE_strand_vertex_iter_init(StrandVertexIterator *iter, StrandIterator *strand_iter)
+{
+ iter->tot = strand_iter->curve->numverts;
+ iter->index = 0;
+ iter->vertex = strand_iter->verts;
+ iter->state = strand_iter->state;
+}
+
+BLI_INLINE bool BKE_strand_vertex_iter_valid(StrandVertexIterator *iter)
+{
+ return iter->index < iter->tot;
+}
+
+BLI_INLINE void BKE_strand_vertex_iter_next(StrandVertexIterator *iter)
+{
+ ++iter->vertex;
+ if (iter->state)
+ ++iter->state;
+ ++iter->index;
+}
+
+BLI_INLINE size_t BKE_strand_vertex_iter_vertex_offset(Strands *strands, StrandVertexIterator *iter)
+{
+ return iter->vertex - strands->verts;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Strand Edges Iterator */
+
+typedef struct StrandEdgeIterator {
+ int index, tot;
+ StrandsVertex *vertex0, *vertex1;
+ StrandsMotionState *state0, *state1;
+} StrandEdgeIterator;
+
+BLI_INLINE void BKE_strand_edge_iter_init(StrandEdgeIterator *iter, StrandIterator *strand_iter)
+{
+ iter->tot = strand_iter->curve->numverts - 1;
+ iter->index = 0;
+ iter->vertex0 = strand_iter->verts;
+ iter->state0 = strand_iter->state;
+ iter->vertex1 = strand_iter->verts + 1;
+ iter->state1 = strand_iter->state + 1;
+}
+
+BLI_INLINE bool BKE_strand_edge_iter_valid(StrandEdgeIterator *iter)
+{
+ return iter->index < iter->tot;
+}
+
+BLI_INLINE void BKE_strand_edge_iter_next(StrandEdgeIterator *iter)
+{
+ ++iter->vertex0;
+ ++iter->vertex1;
+ if (iter->state0) {
+ ++iter->state0;
+ ++iter->state1;
+ }
+ ++iter->index;
+}
+
+BLI_INLINE size_t BKE_strand_edge_iter_vertex0_offset(Strands *strands, StrandEdgeIterator *iter)
+{
+ return iter->vertex0 - strands->verts;
+}
+
+BLI_INLINE size_t BKE_strand_edge_iter_vertex1_offset(Strands *strands, StrandEdgeIterator *iter)
+{
+ return iter->vertex1 - strands->verts;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Strand Bends Iterator */
+
+typedef struct StrandBendIterator {
+ int index, tot;
+ StrandsVertex *vertex0, *vertex1, *vertex2;
+ StrandsMotionState *state0, *state1, *state2;
+} StrandBendIterator;
+
+BLI_INLINE void BKE_strand_bend_iter_init(StrandBendIterator *iter, StrandIterator *strand_iter)
+{
+ iter->tot = strand_iter->curve->numverts - 2;
+ iter->index = 0;
+ iter->vertex0 = strand_iter->verts;
+ iter->state0 = strand_iter->state;
+ iter->vertex1 = strand_iter->verts + 1;
+ iter->state1 = strand_iter->state + 1;
+ iter->vertex2 = strand_iter->verts + 2;
+ iter->state2 = strand_iter->state + 2;
+}
+
+BLI_INLINE bool BKE_strand_bend_iter_valid(StrandBendIterator *iter)
+{
+ return iter->index < iter->tot;
+}
+
+BLI_INLINE void BKE_strand_bend_iter_next(StrandBendIterator *iter)
+{
+ ++iter->vertex0;
+ ++iter->vertex1;
+ ++iter->vertex2;
+ if (iter->state0) {
+ ++iter->state0;
+ ++iter->state1;
+ ++iter->state2;
+ }
+ ++iter->index;
+}
+
+BLI_INLINE size_t BKE_strand_bend_iter_vertex0_offset(Strands *strands, StrandBendIterator *iter)
+{
+ return iter->vertex0 - strands->verts;
+}
+
+BLI_INLINE size_t BKE_strand_bend_iter_vertex1_offset(Strands *strands, StrandBendIterator *iter)
+{
+ return iter->vertex1 - strands->verts;
+}
+
+BLI_INLINE size_t BKE_strand_bend_iter_vertex2_offset(Strands *strands, StrandBendIterator *iter)
+{
+ return iter->vertex2 - strands->verts;
+}
+
+void BKE_strand_bend_iter_transform_rest(StrandBendIterator *iter, float mat[3][3]);
+void BKE_strand_bend_iter_transform_state(StrandBendIterator *iter, float mat[3][3]);
+
+/* ------------------------------------------------------------------------- */
+/* Strand Child Curves Iterator */
+
+typedef struct StrandChildIterator {
+ int index, tot, numuv, numvcol;
+ StrandsChildCurve *curve;
+ StrandsChildCurveUV *curve_uv;
+ StrandsChildCurveVCol *curve_vcol;
+ StrandsChildVertex *verts;
+} StrandChildIterator;
+
+BLI_INLINE void BKE_strand_child_iter_init(StrandChildIterator *iter, StrandsChildren *strands)
+{
+ iter->tot = strands->totcurves;
+ iter->numuv = strands->numuv;
+ iter->numvcol = strands->numvcol;
+ iter->index = 0;
+
+ iter->curve = strands->curves;
+ iter->curve_uv = strands->curve_uvs;
+ iter->curve_vcol = strands->curve_vcols;
+ iter->verts = strands->verts;
+}
+
+BLI_INLINE bool BKE_strand_child_iter_valid(StrandChildIterator *iter)
+{
+ return iter->index < iter->tot;
+}
+
+BLI_INLINE void BKE_strand_child_iter_next(StrandChildIterator *iter)
+{
+ const int numverts = iter->curve->numverts;
+
+ ++iter->index;
+ ++iter->curve;
+ if (iter->curve_uv)
+ iter->curve_uv += iter->numuv;
+ if (iter->curve_vcol)
+ iter->curve_vcol += iter->numvcol;
+ iter->verts += numverts;
+}
+
+BLI_INLINE size_t BKE_strand_child_iter_curve_offset(StrandsChildren *strands, StrandChildIterator *iter)
+{
+ return iter->curve - strands->curves;
+}
+
+BLI_INLINE size_t BKE_strand_child_iter_vertex_offset(StrandsChildren *strands, StrandChildIterator *iter)
+{
+ return iter->verts - strands->verts;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Strand Child Vertices Iterator */
+
+typedef struct StrandChildVertexIterator {
+ int index, tot;
+ StrandsChildVertex *vertex;
+} StrandChildVertexIterator;
+
+BLI_INLINE void BKE_strand_child_vertex_iter_init(StrandChildVertexIterator *iter, StrandChildIterator *strand_iter)
+{
+ iter->tot = strand_iter->curve->numverts;
+ iter->index = 0;
+ iter->vertex = strand_iter->verts;
+}
+
+BLI_INLINE bool BKE_strand_child_vertex_iter_valid(StrandChildVertexIterator *iter)
+{
+ return iter->index < iter->tot;
+}
+
+BLI_INLINE void BKE_strand_child_vertex_iter_next(StrandChildVertexIterator *iter)
+{
+ ++iter->vertex;
+ ++iter->index;
+}
+
+BLI_INLINE size_t BKE_strand_child_vertex_iter_vertex_offset(StrandsChildren *strands, StrandChildVertexIterator *iter)
+{
+ return iter->vertex - strands->verts;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Strand Child Edges Iterator */
+
+typedef struct StrandChildEdgeIterator {
+ int index, tot;
+ StrandsChildVertex *vertex0, *vertex1;
+} StrandChildEdgeIterator;
+
+BLI_INLINE void BKE_strand_child_edge_iter_init(StrandChildEdgeIterator *iter, StrandChildIterator *strand_iter)
+{
+ iter->tot = strand_iter->curve->numverts - 1;
+ iter->index = 0;
+ iter->vertex0 = strand_iter->verts;
+ iter->vertex1 = strand_iter->verts + 1;
+}
+
+BLI_INLINE bool BKE_strand_child_edge_iter_valid(StrandChildEdgeIterator *iter)
+{
+ return iter->index < iter->tot;
+}
+
+BLI_INLINE void BKE_strand_child_edge_iter_next(StrandChildEdgeIterator *iter)
+{
+ ++iter->vertex0;
+ ++iter->vertex1;
+ ++iter->index;
+}
+
+BLI_INLINE size_t BKE_strand_child_edge_iter_vertex0_offset(StrandsChildren *strands, StrandChildEdgeIterator *iter)
+{
+ return iter->vertex0 - strands->verts;
+}
+
+BLI_INLINE size_t BKE_strand_child_edge_iter_vertex1_offset(StrandsChildren *strands, StrandChildEdgeIterator *iter)
+{
+ return iter->vertex1 - strands->verts;
+}
+
+#endif /* __BKE_STRANDS_H__ */
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index 3dae4087866..c1c96c8228c 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -41,17 +41,14 @@ struct DerivedMesh;
struct MeshElemMap;
struct Mesh;
struct MPoly;
-struct MultiresSubsurf;
struct Object;
struct PBVH;
struct SubsurfModifierData;
struct CCGEdge;
struct CCGFace;
-struct CCGSubsurf;
struct CCGVert;
struct EdgeHash;
struct PBVH;
-struct DMGridAdjacency;
/**************************** External *****************************/
@@ -120,7 +117,6 @@ typedef struct CCGDerivedMesh {
int *pmap_mem;
struct CCGElem **gridData;
- struct DMGridAdjacency *gridAdjacency;
int *gridOffset;
struct CCGFace **gridFaces;
struct DMFlagMat *gridFlagMats;
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index 96e88f80464..a5a59d14c92 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -40,14 +40,13 @@ extern "C" {
struct Main;
struct Text;
struct TextLine;
-struct SpaceText;
void BKE_text_free (struct Text *text);
void txt_set_undostate (int u);
int txt_get_undostate (void);
struct Text *BKE_text_add (struct Main *bmain, const char *name);
int txt_extended_ascii_as_utf8(char **str);
-int BKE_text_reload (struct Text *text);
+bool BKE_text_reload(struct Text *text);
struct Text *BKE_text_load_ex(struct Main *bmain, const char *file, const char *relpath,
const bool is_internal);
struct Text *BKE_text_load (struct Main *bmain, const char *file, const char *relpath);
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index ebf85ff51d1..95918b9ca0b 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -42,9 +42,7 @@ struct Brush;
struct ColorBand;
struct EnvMap;
struct FreestyleLineStyle;
-struct HaloRen;
struct Lamp;
-struct LampRen;
struct Main;
struct Material;
struct MTex;
@@ -61,8 +59,6 @@ struct World;
#define MAXCOLORBAND 32
-void BKE_texture_free(struct Tex *t);
-
void init_colorband(struct ColorBand *coba, bool rangetype);
struct ColorBand *add_colorband(bool rangetype);
bool do_colorband(const struct ColorBand *coba, float in, float out[4]);
@@ -71,15 +67,17 @@ struct CBData *colorband_element_add(struct ColorBand *coba, float position);
int colorband_element_remove(struct ColorBand *coba, int index);
void colorband_update_sort(struct ColorBand *coba);
-void default_tex(struct Tex *tex);
-struct Tex *add_texture(struct Main *bmain, const char *name);
-void tex_set_type(struct Tex *tex, int type);
-void default_mtex(struct MTex *mtex);
-struct MTex *add_mtex(void);
-struct MTex *add_mtex_id(struct ID *id, int slot);
-struct Tex *BKE_texture_copy(struct Tex *tex);
-struct Tex *localize_texture(struct Tex *tex);
-void BKE_texture_make_local(struct Tex *tex);
+void BKE_texture_free(struct Tex *tex);
+void BKE_texture_default(struct Tex *tex);
+struct Tex *BKE_texture_copy(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 Tex *tex);
+void BKE_texture_type_set(struct Tex *tex, int type);
+
+void BKE_texture_mtex_default(struct MTex *mtex);
+struct MTex *BKE_texture_mtex_add(void);
+struct MTex *BKE_texture_mtex_add_id(struct ID *id, int slot);
/* UNUSED */
// void autotexname(struct Tex *tex);
@@ -105,36 +103,39 @@ void set_current_particle_texture(struct ParticleSettings *part, struct Tex *tex
bool has_current_material_texture(struct Material *ma);
-struct TexMapping *add_tex_mapping(int type);
-void default_tex_mapping(struct TexMapping *texmap, int type);
-void init_tex_mapping(struct TexMapping *texmap);
+struct TexMapping *BKE_texture_mapping_add(int type);
+void BKE_texture_mapping_default(struct TexMapping *texmap, int type);
+void BKE_texture_mapping_init(struct TexMapping *texmap);
+
+struct ColorMapping *BKE_texture_colormapping_add(void);
+void BKE_texture_colormapping_default(struct ColorMapping *colormap);
-struct ColorMapping *add_color_mapping(void);
-void default_color_mapping(struct ColorMapping *colormap);
+void BKE_texture_envmap_free_data(struct EnvMap *env);
+void BKE_texture_envmap_free(struct EnvMap *env);
+struct EnvMap *BKE_texture_envmap_add(void);
+struct EnvMap *BKE_texture_envmap_copy(struct EnvMap *env);
-void BKE_free_envmapdata(struct EnvMap *env);
-void BKE_free_envmap(struct EnvMap *env);
-struct EnvMap *BKE_add_envmap(void);
-struct EnvMap *BKE_copy_envmap(struct EnvMap *env);
+void BKE_texture_pointdensity_init_data(struct PointDensity *pd);
+void BKE_texture_pointdensity_free_data(struct PointDensity *pd);
+void BKE_texture_pointdensity_free(struct PointDensity *pd);
+struct PointDensity *BKE_texture_pointdensity_add(void);
+struct PointDensity *BKE_texture_pointdensity_copy(struct PointDensity *pd);
-void BKE_free_pointdensitydata(struct PointDensity *pd);
-void BKE_free_pointdensity(struct PointDensity *pd);
-struct PointDensity *BKE_add_pointdensity(void);
-struct PointDensity *BKE_copy_pointdensity(struct PointDensity *pd);
+void BKE_texture_voxeldata_free_data(struct VoxelData *vd);
+void BKE_texture_voxeldata_free(struct VoxelData *vd);
+struct VoxelData *BKE_texture_voxeldata_add(void);
+struct VoxelData *BKE_texture_voxeldata_copy(struct VoxelData *vd);
-void BKE_free_voxeldatadata(struct VoxelData *vd);
-void BKE_free_voxeldata(struct VoxelData *vd);
-struct VoxelData *BKE_add_voxeldata(void);
-struct VoxelData *BKE_copy_voxeldata(struct VoxelData *vd);
+void BKE_texture_ocean_free(struct OceanTex *ot);
+struct OceanTex *BKE_texture_ocean_add(void);
+struct OceanTex *BKE_texture_ocean_copy(struct OceanTex *ot);
-void BKE_free_oceantex(struct OceanTex *ot);
-struct OceanTex *BKE_add_oceantex(void);
-struct OceanTex *BKE_copy_oceantex(struct OceanTex *ot);
-
bool BKE_texture_dependsOnTime(const struct Tex *texture);
bool BKE_texture_is_image_user(const struct Tex *tex);
-void BKE_texture_get_value(struct Scene *scene, struct Tex *texture, float *tex_co, struct TexResult *texres, bool use_color_management);
+void BKE_texture_get_value(
+ const struct Scene *scene, struct Tex *texture,
+ float *tex_co, struct TexResult *texres, bool use_color_management);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index e5fb60cf1b5..b03a234e1e7 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -41,7 +41,6 @@ struct MovieTrackingMarker;
struct MovieTrackingPlaneTrack;
struct MovieTrackingPlaneMarker;
struct MovieTracking;
-struct MovieTrackingContext;
struct MovieTrackingObject;
struct MovieClipUser;
struct MovieDistortion;
@@ -91,7 +90,7 @@ struct MovieTrackingTrack *BKE_tracking_track_get_named(struct MovieTracking *tr
struct MovieTrackingObject *object,
const char *name);
struct MovieTrackingTrack *BKE_tracking_track_get_indexed(struct MovieTracking *tracking, int tracknr,
- struct ListBase **tracksbase_r);
+ struct ListBase **r_tracksbase);
struct MovieTrackingTrack *BKE_tracking_track_get_active(struct MovieTracking *tracking);
@@ -137,6 +136,21 @@ struct MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_active(struct Movie
void BKE_tracking_plane_tracks_deselect_all(struct ListBase *plane_tracks_base);
+bool BKE_tracking_plane_track_has_point_track(struct MovieTrackingPlaneTrack *plane_track,
+ struct MovieTrackingTrack *track);
+bool BKE_tracking_plane_track_remove_point_track(struct MovieTrackingPlaneTrack *plane_track,
+ struct MovieTrackingTrack *track);
+
+void BKE_tracking_plane_tracks_remove_point_track(struct MovieTracking *tracking,
+ struct MovieTrackingTrack *track);
+
+void BKE_tracking_plane_track_replace_point_track(struct MovieTrackingPlaneTrack *plane_track,
+ struct MovieTrackingTrack *old_track,
+ struct MovieTrackingTrack *new_track);
+void BKE_tracking_plane_tracks_replace_point_track(struct MovieTracking *tracking,
+ struct MovieTrackingTrack *old_track,
+ struct MovieTrackingTrack *new_track);
+
/* **** Plane Marker **** */
struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(struct MovieTrackingPlaneTrack *plane_track,
struct MovieTrackingPlaneMarker *plane_marker);
diff --git a/source/blender/blenkernel/BKE_writeavi.h b/source/blender/blenkernel/BKE_writeavi.h
index 78875951ca4..ca295c51f5d 100644
--- a/source/blender/blenkernel/BKE_writeavi.h
+++ b/source/blender/blenkernel/BKE_writeavi.h
@@ -43,16 +43,20 @@ struct ReportList;
struct Scene;
typedef struct bMovieHandle {
- int (*start_movie)(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports);
- int (*append_movie)(struct RenderData *rd, int start_frame, int frame, int *pixels,
- int rectx, int recty, struct ReportList *reports);
- void (*end_movie)(void);
- int (*get_next_frame)(struct RenderData *rd, struct ReportList *reports); /* optional */
- void (*get_movie_path)(char *string, struct RenderData *rd); /* optional */
+ int (*start_movie)(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty,
+ struct ReportList *reports, bool preview, const char *suffix);
+ int (*append_movie)(void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels,
+ int rectx, int recty, const char *suffix, struct ReportList *reports);
+ void (*end_movie)(void *context_v);
+ int (*get_next_frame)(void *context_v, struct RenderData *rd, struct ReportList *reports); /* optional */
+ void (*get_movie_path)(char *string, struct RenderData *rd, bool preview, const char *suffix); /* optional */
+ void *(*context_create)(void);
+ void (*context_free)(void *context_v);
} bMovieHandle;
bMovieHandle *BKE_movie_handle_get(const char imtype);
-void BKE_movie_filepath_get(char *string, struct RenderData *rd);
+void BKE_movie_filepath_get(char *string, struct RenderData *rd, bool preview, const char *suffix);
+void BKE_context_create(bMovieHandle *mh);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_writeffmpeg.h b/source/blender/blenkernel/BKE_writeffmpeg.h
index 703e84b3798..a40c31022e3 100644
--- a/source/blender/blenkernel/BKE_writeffmpeg.h
+++ b/source/blender/blenkernel/BKE_writeffmpeg.h
@@ -64,16 +64,15 @@ enum {
FFMPEG_PRESET_XVID = 7,
};
-struct IDProperty;
struct RenderData;
struct ReportList;
struct Scene;
-int BKE_ffmpeg_start(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports);
-void BKE_ffmpeg_end(void);
-int BKE_ffmpeg_append(struct RenderData *rd, int start_frame, int frame, int *pixels,
- int rectx, int recty, struct ReportList *reports);
-void BKE_ffmpeg_filepath_get(char *string, struct RenderData *rd);
+int BKE_ffmpeg_start(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports, bool preview, const char *suffix);
+void BKE_ffmpeg_end(void *context_v);
+int BKE_ffmpeg_append(void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels,
+ int rectx, int recty, const char *suffix, struct ReportList *reports);
+void BKE_ffmpeg_filepath_get(char *string, struct RenderData *rd, bool preview, const char *suffix);
void BKE_ffmpeg_preset_set(struct RenderData *rd, int preset);
void BKE_ffmpeg_image_type_verify(struct RenderData *rd, struct ImageFormatData *imf);
@@ -83,6 +82,9 @@ bool BKE_ffmpeg_alpha_channel_is_supported(struct RenderData *rd);
int BKE_ffmpeg_property_add_string(struct RenderData *rd, const char *type, const char *str);
void BKE_ffmpeg_property_del(struct RenderData *rd, void *type, void *prop_);
+void *BKE_ffmpeg_context_create(void);
+void BKE_ffmpeg_context_free(void *context_v);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_writeframeserver.h b/source/blender/blenkernel/BKE_writeframeserver.h
index bdce9abe8ad..0837e9bce79 100644
--- a/source/blender/blenkernel/BKE_writeframeserver.h
+++ b/source/blender/blenkernel/BKE_writeframeserver.h
@@ -40,11 +40,16 @@ struct RenderData;
struct ReportList;
struct Scene;
-int BKE_frameserver_start(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports);
-void BKE_frameserver_end(void);
-int BKE_frameserver_append(struct RenderData *rd, int start_frame, int frame, int *pixels,
- int rectx, int recty, struct ReportList *reports);
-int BKE_frameserver_loop(struct RenderData *rd, struct ReportList *reports);
+int BKE_frameserver_start(
+ void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty,
+ struct ReportList *reports, bool preview, const char *suffix);
+void BKE_frameserver_end(void *context_v);
+int BKE_frameserver_append(
+ void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels,
+ int rectx, int recty, const char *suffix, struct ReportList *reports);
+int BKE_frameserver_loop(void *context_v, struct RenderData *rd, struct ReportList *reports);
+void *BKE_frameserver_context_create(void);
+void BKE_frameserver_context_free(void *context_v);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index d61d6ee135c..70d26e8b27e 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
../blenfont
../blenlib
../blenloader
+ ../depsgraph
../gpu
../ikplugin
../imbuf
@@ -37,6 +38,7 @@ set(INC
../modifiers
../nodes
../physics
+ ../pointcache
../render/extern/include
../../../intern/ghost
../../../intern/guardedalloc
@@ -67,6 +69,7 @@ set(SRC
intern/anim_sys.c
intern/appdir.c
intern/armature.c
+ intern/armature_update.c
intern/autoexec.c
intern/blender.c
intern/bmfont.c
@@ -75,6 +78,7 @@ set(SRC
intern/brush.c
intern/bullet.c
intern/bvhutils.c
+ intern/cache_library.c
intern/camera.c
intern/cdderivedmesh.c
intern/cloth.c
@@ -94,6 +98,7 @@ set(SRC
intern/editderivedmesh.c
intern/editmesh.c
intern/editmesh_bvh.c
+ intern/editstrands.c
intern/effect.c
intern/facemap.c
intern/fcurve.c
@@ -120,10 +125,12 @@ set(SRC
intern/mask_rasterize.c
intern/material.c
intern/mball.c
+ intern/mball_tessellate.c
intern/mesh.c
intern/mesh_evaluate.c
intern/mesh_mapping.c
intern/mesh_remap.c
+ intern/mesh_sample.c
intern/mesh_validate.c
intern/modifier.c
intern/modifiers_bmesh.c
@@ -134,7 +141,9 @@ set(SRC
intern/object.c
intern/object_deform.c
intern/object_dupli.c
+ intern/object_update.c
intern/ocean.c
+ intern/outliner_treehash.c
intern/packedFile.c
intern/paint.c
intern/particle.c
@@ -161,6 +170,7 @@ set(SRC
intern/softbody.c
intern/sound.c
intern/speaker.c
+ intern/strands.c
intern/subsurf_ccg.c
intern/suggestions.c
intern/text.c
@@ -173,7 +183,6 @@ set(SRC
intern/tracking_solver.c
intern/tracking_stabilize.c
intern/tracking_util.c
- intern/treehash.c
intern/unit.c
intern/world.c
intern/writeavi.c
@@ -195,6 +204,7 @@ set(SRC
BKE_brush.h
BKE_bullet.h
BKE_bvhutils.h
+ BKE_cache_library.h
BKE_camera.h
BKE_ccg.h
BKE_cdderivedmesh.h
@@ -212,6 +222,9 @@ set(SRC
BKE_depsgraph.h
BKE_displist.h
BKE_dynamicpaint.h
+ BKE_editstrands.h
+ BKE_editmesh.h
+ BKE_editmesh_bvh.h
BKE_effect.h
BKE_facemap.h
BKE_fcurve.h
@@ -236,9 +249,11 @@ set(SRC
BKE_mask.h
BKE_material.h
BKE_mball.h
+ BKE_mball_tessellate.h
BKE_mesh.h
BKE_mesh_mapping.h
BKE_mesh_remap.h
+ BKE_mesh_sample.h
BKE_modifier.h
BKE_movieclip.h
BKE_multires.h
@@ -247,6 +262,7 @@ set(SRC
BKE_object.h
BKE_object_deform.h
BKE_ocean.h
+ BKE_outliner_treehash.h
BKE_packedFile.h
BKE_paint.h
BKE_particle.h
@@ -265,14 +281,12 @@ set(SRC
BKE_softbody.h
BKE_sound.h
BKE_speaker.h
+ BKE_strands.h
BKE_subsurf.h
BKE_suggestions.h
- BKE_editmesh.h
- BKE_editmesh_bvh.h
BKE_text.h
BKE_texture.h
BKE_tracking.h
- BKE_treehash.h
BKE_unit.h
BKE_utildefines.h
BKE_world.h
@@ -425,9 +439,16 @@ if(WITH_JACK)
endif()
if(WITH_LZO)
- list(APPEND INC_SYS
- ../../../extern/lzo/minilzo
- )
+ if(WITH_SYSTEM_LZO)
+ list(APPEND INC_SYS
+ ${LZO_INCLUDE_DIR}
+ )
+ add_definitions(-DWITH_SYSTEM_LZO)
+ else()
+ list(APPEND INC_SYS
+ ../../../extern/lzo/minilzo
+ )
+ endif()
add_definitions(-DWITH_LZO)
endif()
@@ -474,4 +495,8 @@ endif()
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
#endif()
+if(WITH_LEGACY_DEPSGRAPH)
+ add_definitions(-DWITH_LEGACY_DEPSGRAPH)
+endif()
+
blender_add_lib(bf_blenkernel "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript
index 47bba5f5537..ec2cf90a32a 100644
--- a/source/blender/blenkernel/SConscript
+++ b/source/blender/blenkernel/SConscript
@@ -58,6 +58,7 @@ incs = [
'../blenlib',
'../blenloader',
'../bmesh',
+ '../depsgraph',
'../gpu',
'../ikplugin',
'../imbuf',
@@ -66,6 +67,7 @@ incs = [
'../modifiers',
'../nodes',
'../physics',
+ '../pointcache',
'../render/extern/include',
'../windowmanager',
env['BF_ZLIB_INC'],
@@ -175,6 +177,9 @@ if env['WITH_BF_BINRELOC']:
incs += ' #extern/binreloc/include'
defs.append('WITH_BINRELOC')
+if env['WITH_BF_LEGACY_DEPSGRAPH']:
+ defs.append('WITH_LEGACY_DEPSGRAPH')
+
if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
env.BlenderLib ( libname = 'bf_blenkernel', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [166,25]) #, cc_compileflags = env['CCFLAGS'].append('/WX') )
else:
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index dd129228dd8..d850dd3ee26 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -295,11 +295,11 @@ void DM_init(DerivedMesh *dm, DerivedMeshType type, int numVerts, int numEdges,
dm->dirty = 0;
/* don't use CustomData_reset(...); because we dont want to touch customdata */
- fill_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1);
- fill_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1);
- fill_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1);
- fill_vn_i(dm->loopData.typemap, CD_NUMTYPES, -1);
- fill_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->loopData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1);
}
void DM_from_template(DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type,
@@ -931,7 +931,7 @@ DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob,
ModifierData *md, int build_shapekey_layers)
{
Mesh *me = ob->data;
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
DerivedMesh *dm;
KeyBlock *kb;
@@ -1011,8 +1011,9 @@ static float (*get_orco_coords_dm(Object *ob, BMEditMesh *em, int layer, int *fr
ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
KeyBlock *kb = BKE_keyblock_from_key(BKE_key_from_object(ob), clmd->sim_parms->shapekey_rest);
- if (kb->data)
+ if (kb && kb->data) {
return kb->data;
+ }
}
return NULL;
@@ -1131,7 +1132,7 @@ typedef struct DMWeightColorInfo {
} DMWeightColorInfo;
-static int dm_drawflag_calc(ToolSettings *ts)
+static int dm_drawflag_calc(const ToolSettings *ts)
{
return ((ts->multipaint ? CALC_WP_MULTIPAINT :
/* CALC_WP_GROUP_USER_ACTIVE or CALC_WP_GROUP_USER_ALL*/
@@ -1275,7 +1276,7 @@ static void calc_weightpaint_vert_array(Object *ob, DerivedMesh *dm, int const d
else {
weightpaint_color(col, dm_wcinfo, 0.0f);
}
- fill_vn_i((int *)r_wtcol_v, numVerts, *((int *)col));
+ copy_vn_i((int *)r_wtcol_v, numVerts, *((int *)col));
}
}
@@ -1368,7 +1369,7 @@ void DM_update_weight_mcol(Object *ob, DerivedMesh *dm, int const draw_flag,
}
}
-static void DM_update_statvis_color(Scene *scene, Object *ob, DerivedMesh *dm)
+static void DM_update_statvis_color(const Scene *scene, Object *ob, DerivedMesh *dm)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
@@ -1585,7 +1586,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
/* Apply all leading deforming modifiers */
for (; md; md = md->next, curr = curr->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -1639,7 +1640,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
clothorcodm = NULL;
for (; md; md = md->next, curr = curr->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -1938,7 +1939,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
DM_calc_loop_normals(finaldm, do_loop_normals, loop_normals_split_angle);
}
- {
+ if (sculpt_dyntopo == false) {
DM_ensure_tessface(finaldm);
/* without this, drawing ngon tri's faces will show ugly tessellated face
@@ -2000,7 +2001,7 @@ float (*editbmesh_get_vertex_cos(BMEditMesh *em, int *r_numVerts))[3]
bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *dm)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
if (!modifier_isEnabled(scene, md, required_mode)) return 0;
@@ -2059,7 +2060,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
curr = datamasks;
for (i = 0; md; i++, md = md->next, curr = curr->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -2291,13 +2292,8 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
}
static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask,
- int build_shapekey_layers)
+ int build_shapekey_layers, int needMapping)
{
- Object *obact = scene->basact ? scene->basact->object : NULL;
- bool editing = BKE_paint_select_face_test(ob);
- /* weight paint and face select need original indices because of selection buffer drawing */
- int needMapping = (ob == obact) && (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)));
-
BLI_assert(ob->type == OB_MESH);
BKE_object_free_derived_caches(ob);
@@ -2312,6 +2308,7 @@ static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask,
ob->derivedFinal->needsFree = 0;
ob->derivedDeform->needsFree = 0;
ob->lastDataMask = dataMask;
+ ob->lastNeedMapping = needMapping;
if ((ob->mode & OB_MODE_SCULPT) && ob->sculpt) {
/* create PBVH immediately (would be created on the fly too,
@@ -2340,14 +2337,23 @@ static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, C
BLI_assert(!(em->derivedFinal->dirty & DM_DIRTY_NORMALS));
}
-static CustomDataMask object_get_datamask(Scene *scene, Object *ob)
+static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, int *r_needmapping)
{
Object *actob = scene->basact ? scene->basact->object : NULL;
CustomDataMask mask = ob->customdata_mask;
+ bool editing = BKE_paint_select_face_test(ob);
+
+ if (r_needmapping)
+ *r_needmapping = 0;
if (ob == actob) {
+
+ /* weight paint and face select need original indices because of selection buffer drawing */
+ if (r_needmapping)
+ *r_needmapping = (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT)));
+
/* check if we need tfaces & mcols due to face select or texture paint */
- if (BKE_paint_select_face_test(ob) || (ob->mode & OB_MODE_TEXTURE_PAINT)) {
+ if ((ob->mode & OB_MODE_TEXTURE_PAINT) || editing) {
mask |= CD_MASK_MTFACE | CD_MASK_MCOL;
}
@@ -2370,13 +2376,14 @@ static CustomDataMask object_get_datamask(Scene *scene, Object *ob)
void makeDerivedMesh(Scene *scene, Object *ob, BMEditMesh *em,
CustomDataMask dataMask, int build_shapekey_layers)
{
- dataMask |= object_get_datamask(scene, ob);
+ int needMapping;
+ dataMask |= object_get_datamask(scene, ob, &needMapping);
if (em) {
editbmesh_build_data(scene, ob, em, dataMask);
}
else {
- mesh_build_data(scene, ob, dataMask, build_shapekey_layers);
+ mesh_build_data(scene, ob, dataMask, build_shapekey_layers, needMapping);
}
}
@@ -2387,10 +2394,11 @@ DerivedMesh *mesh_get_derived_final(Scene *scene, Object *ob, CustomDataMask dat
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- dataMask |= object_get_datamask(scene, ob);
+ int needMapping;
+ dataMask |= object_get_datamask(scene, ob, &needMapping);
- if (!ob->derivedFinal || (dataMask & ob->lastDataMask) != dataMask)
- mesh_build_data(scene, ob, dataMask, 0);
+ if (!ob->derivedFinal || (dataMask & ob->lastDataMask) != dataMask || (needMapping != ob->lastNeedMapping))
+ mesh_build_data(scene, ob, dataMask, 0, needMapping);
if (ob->derivedFinal) { BLI_assert(!(ob->derivedFinal->dirty & DM_DIRTY_NORMALS)); }
return ob->derivedFinal;
@@ -2401,10 +2409,12 @@ DerivedMesh *mesh_get_derived_deform(Scene *scene, Object *ob, CustomDataMask da
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- dataMask |= object_get_datamask(scene, ob);
+ int needmapping;
- if (!ob->derivedDeform || (dataMask & ob->lastDataMask) != dataMask)
- mesh_build_data(scene, ob, dataMask, 0);
+ dataMask |= object_get_datamask(scene, ob, &needmapping);
+
+ if (!ob->derivedDeform || (dataMask & ob->lastDataMask) != dataMask || (needmapping != ob->lastNeedMapping))
+ mesh_build_data(scene, ob, dataMask, 0, needmapping);
return ob->derivedDeform;
}
@@ -2493,7 +2503,7 @@ DerivedMesh *editbmesh_get_derived_cage_and_final(Scene *scene, Object *obedit,
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- dataMask |= object_get_datamask(scene, obedit);
+ dataMask |= object_get_datamask(scene, obedit, NULL);
if (!em->derivedCage ||
(em->lastDataMask & dataMask) != dataMask)
@@ -2511,7 +2521,7 @@ DerivedMesh *editbmesh_get_derived_cage(Scene *scene, Object *obedit, BMEditMesh
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- dataMask |= object_get_datamask(scene, obedit);
+ dataMask |= object_get_datamask(scene, obedit, NULL);
if (!em->derivedCage ||
(em->lastDataMask & dataMask) != dataMask)
@@ -3235,7 +3245,8 @@ static void navmesh_drawColored(DerivedMesh *dm)
#endif
glDisable(GL_LIGHTING);
- /* if (GPU_buffer_legacy(dm) ) */ { /* TODO - VBO draw code, not high priority - campbell */
+ /* if (GPU_buffer_legacy(dm) ) */ /* TODO - VBO draw code, not high priority - campbell */
+ {
DEBUG_VBO("Using legacy code. drawNavMeshColored\n");
//glShadeModel(GL_SMOOTH);
glBegin(glmode = GL_QUADS);
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index f9556bf39ab..7e09ad355a7 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -54,6 +54,7 @@
#include "BKE_animsys.h"
#include "BKE_constraint.h"
#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
@@ -929,6 +930,12 @@ void BKE_pose_update_constraint_flags(bPose *pose)
pchan->constflag |= PCHAN_HAS_CONST;
}
}
+ pose->flag &= ~POSE_CONSTRAINTS_NEED_UPDATE_FLAGS;
+}
+
+void BKE_pose_tag_update_constraint_flags(bPose *pose)
+{
+ pose->flag |= POSE_CONSTRAINTS_NEED_UPDATE_FLAGS;
}
/* Clears all BONE_UNKEYED flags for every pose channel in every pose
@@ -1311,6 +1318,16 @@ bool BKE_pose_copy_result(bPose *to, bPose *from)
return true;
}
+/* Tag pose for recalc. Also tag all related data to be recalc. */
+void BKE_pose_tag_recalc(Main *bmain, bPose *pose)
+{
+ pose->flag |= POSE_RECALC;
+ /* Depsgraph components depends on actual pose state,
+ * if pose was changed depsgraph is to be updated as well.
+ */
+ DAG_relations_tag_update(bmain);
+}
+
/* For the calculation of the effects of an Action at the given frame on an object
* This is currently only used for the Action Constraint
*/
diff --git a/source/blender/blenkernel/intern/addon.c b/source/blender/blenkernel/intern/addon.c
index 28667d458b8..811461b84c1 100644
--- a/source/blender/blenkernel/intern/addon.c
+++ b/source/blender/blenkernel/intern/addon.c
@@ -62,12 +62,12 @@ bAddonPrefType *BKE_addon_pref_type_find(const char *idname, bool quiet)
void BKE_addon_pref_type_add(bAddonPrefType *apt)
{
- BLI_ghash_insert(global_addonpreftype_hash, (void *)apt->idname, apt);
+ BLI_ghash_insert(global_addonpreftype_hash, apt->idname, apt);
}
-void BKE_addon_pref_type_remove(bAddonPrefType *apt)
+void BKE_addon_pref_type_remove(const bAddonPrefType *apt)
{
- BLI_ghash_remove(global_addonpreftype_hash, (void *)apt->idname, NULL, MEM_freeN);
+ BLI_ghash_remove(global_addonpreftype_hash, apt->idname, NULL, MEM_freeN);
}
void BKE_addon_pref_type_init(void)
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index effe32a8079..d5a8b8f857c 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -134,7 +134,7 @@ AnimData *BKE_animdata_from_id(ID *id)
* the AnimData pointer is stored immediately after the given ID-block in the struct,
* as per IdAdtTemplate. Also note that
*/
-AnimData *BKE_id_add_animdata(ID *id)
+AnimData *BKE_animdata_add_id(ID *id)
{
/* Only some ID-blocks have this info for now, so we cast the
* types that do to be of type IdAdtTemplate, and add the AnimData
@@ -216,7 +216,7 @@ bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
/* Freeing -------------------------------------------- */
/* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */
-void BKE_free_animdata(ID *id)
+void BKE_animdata_free(ID *id)
{
/* Only some ID-blocks have this info for now, so we cast the
* types that do to be of type IdAdtTemplate
@@ -253,7 +253,7 @@ void BKE_free_animdata(ID *id)
/* Copying -------------------------------------------- */
/* Make a copy of the given AnimData - to be used when copying datablocks */
-AnimData *BKE_copy_animdata(AnimData *adt, const bool do_action)
+AnimData *BKE_animdata_copy(AnimData *adt, const bool do_action)
{
AnimData *dadt;
@@ -285,25 +285,25 @@ AnimData *BKE_copy_animdata(AnimData *adt, const bool do_action)
return dadt;
}
-bool BKE_copy_animdata_id(ID *id_to, ID *id_from, const bool do_action)
+bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action)
{
AnimData *adt;
if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name)))
return false;
- BKE_free_animdata(id_to);
+ BKE_animdata_free(id_to);
adt = BKE_animdata_from_id(id_from);
if (adt) {
IdAdtTemplate *iat = (IdAdtTemplate *)id_to;
- iat->adt = BKE_copy_animdata(adt, do_action);
+ iat->adt = BKE_animdata_copy(adt, do_action);
}
return true;
}
-void BKE_copy_animdata_id_action(ID *id)
+void BKE_animdata_copy_id_action(ID *id)
{
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
@@ -426,7 +426,7 @@ void BKE_animdata_make_local(AnimData *adt)
/* When duplicating data (i.e. objects), drivers referring to the original data will
* get updated to point to the duplicated data (if drivers belong to the new data)
*/
-void BKE_relink_animdata(AnimData *adt)
+void BKE_animdata_relink(AnimData *adt)
{
/* sanity check */
if (adt == NULL)
@@ -571,7 +571,7 @@ void BKE_animdata_separate_by_basepath(ID *srcID, ID *dstID, ListBase *basepaths
/* get animdata from src, and create for destination (if needed) */
srcAdt = BKE_animdata_from_id(srcID);
- dstAdt = BKE_id_add_animdata(dstID);
+ dstAdt = BKE_animdata_add_id(dstID);
if (ELEM(NULL, srcAdt, dstAdt)) {
if (G.debug & G_DEBUG)
@@ -1167,7 +1167,7 @@ void BKE_animdata_main_cb(Main *mainptr, ID_AnimData_Edit_Callback func, void *u
* i.e. pose.bones["Bone"]
*/
/* TODO: use BKE_animdata_main_cb for looping over all data */
-void BKE_all_animdata_fix_paths_rename(ID *ref_id, const char *prefix, const char *oldName, const char *newName)
+void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const char *oldName, const char *newName)
{
Main *mainptr = G.main;
ID *id;
@@ -1496,8 +1496,11 @@ static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_ind
/* get property to write to */
if (RNA_path_resolve_property(ptr, path, &new_ptr, &prop)) {
- /* set value - only for animatable numerical values */
- if (RNA_property_animateable(&new_ptr, prop)) {
+ /* set value for animatable numerical values only
+ * HACK: some local F-Curves (e.g. those on NLA Strips) are evaluated
+ * without an ID provided, which causes the animateable test to fail!
+ */
+ if (RNA_property_animateable(&new_ptr, prop) || (ptr->id.data == NULL)) {
int array_len = RNA_property_array_length(&new_ptr, prop);
bool written = false;
@@ -1617,7 +1620,7 @@ static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_ind
}
/* Simple replacement based data-setting of the FCurve using RNA */
-static bool animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu)
+bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu)
{
char *path = NULL;
bool free_path = false;
@@ -1652,7 +1655,7 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr, ListBase *list, AnimMapper
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
calculate_fcurve(fcu, ctime);
- animsys_execute_fcurve(ptr, remap, fcu);
+ BKE_animsys_execute_fcurve(ptr, remap, fcu);
}
}
}
@@ -1682,7 +1685,7 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime
* NOTE: for 'layering' option later on, we should check if we should remove old value before adding
* new to only be done when drivers only changed */
calculate_fcurve(fcu, ctime);
- ok = animsys_execute_fcurve(ptr, NULL, fcu);
+ ok = BKE_animsys_execute_fcurve(ptr, NULL, fcu);
/* clear recalc flag */
driver->flag &= ~DRIVER_FLAG_RECALC;
@@ -1751,7 +1754,7 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
calculate_fcurve(fcu, ctime);
- animsys_execute_fcurve(ptr, remap, fcu);
+ BKE_animsys_execute_fcurve(ptr, remap, fcu);
}
}
}
@@ -1797,12 +1800,6 @@ static float nlastrip_get_influence(NlaStrip *strip, float cframe)
/* evaluate the evaluation time and influence for the strip, storing the results in the strip */
static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime)
{
- /* firstly, analytically generate values for influence and time (if applicable) */
- if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0)
- strip->strip_time = nlastrip_get_frame(strip, ctime, NLATIME_CONVERT_EVAL);
- if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0)
- strip->influence = nlastrip_get_influence(strip, ctime);
-
/* now strip's evaluate F-Curves for these settings (if applicable) */
if (strip->fcurves.first) {
PointerRNA strip_ptr;
@@ -1813,6 +1810,15 @@ static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime)
/* execute these settings as per normal */
animsys_evaluate_fcurves(&strip_ptr, &strip->fcurves, NULL, ctime);
}
+
+ /* analytically generate values for influence and time (if applicable)
+ * - we do this after the F-Curves have been evaluated to override the effects of those
+ * in case the override has been turned off.
+ */
+ if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0)
+ strip->strip_time = nlastrip_get_frame(strip, ctime, NLATIME_CONVERT_EVAL);
+ if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0)
+ strip->influence = nlastrip_get_influence(strip, ctime);
/* if user can control the evaluation time (using F-Curves), consider the option which allows this time to be clamped
* to lie within extents of the action-clip, so that a steady changing rate of progress through several cycles of the clip
@@ -2840,3 +2846,62 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
}
/* ***************************************** */
+
+/* ************** */
+/* Evaluation API */
+
+#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
+
+void BKE_animsys_eval_animdata(EvaluationContext *eval_ctx, ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ Scene *scene = NULL; /* XXX: this is only needed for flushing RNA updates,
+ * which should get handled as part of the graph instead...
+ */
+ DEBUG_PRINT("%s on %s, time=%f\n\n", __func__, id->name, (double)eval_ctx->ctime);
+ BKE_animsys_evaluate_animdata(scene, id, adt, eval_ctx->ctime, ADT_RECALC_ANIM);
+}
+
+void BKE_animsys_eval_driver(EvaluationContext *eval_ctx,
+ ID *id,
+ FCurve *fcu)
+{
+ /* TODO(sergey): De-duplicate with BKE animsys. */
+ ChannelDriver *driver = fcu->driver;
+ PointerRNA id_ptr;
+ bool ok = false;
+
+ DEBUG_PRINT("%s on %s (%s[%d])\n",
+ __func__,
+ id->name,
+ fcu->rna_path,
+ fcu->array_index);
+
+ RNA_id_pointer_create(id, &id_ptr);
+
+ /* check if this driver's curve should be skipped */
+ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
+ /* check if driver itself is tagged for recalculation */
+ /* XXX driver recalc flag is not set yet by depsgraph! */
+ if ((driver) && !(driver->flag & DRIVER_FLAG_INVALID) /*&& (driver->flag & DRIVER_FLAG_RECALC)*/) {
+ /* evaluate this using values set already in other places
+ * NOTE: for 'layering' option later on, we should check if we should remove old value before adding
+ * new to only be done when drivers only changed */
+ //printf("\told val = %f\n", fcu->curval);
+ calculate_fcurve(fcu, eval_ctx->ctime);
+ ok = BKE_animsys_execute_fcurve(&id_ptr, NULL, fcu);
+ //printf("\tnew val = %f\n", fcu->curval);
+
+ /* clear recalc flag */
+ driver->flag &= ~DRIVER_FLAG_RECALC;
+
+ /* set error-flag if evaluation failed */
+ if (ok == 0) {
+ printf("invalid driver - %s[%d]\n", fcu->rna_path, fcu->array_index);
+ driver->flag |= DRIVER_FLAG_INVALID;
+ }
+ }
+ }
+}
+
+#undef DEBUG_PRINT
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 60e81003c40..b1b32e75f59 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -501,54 +501,6 @@ const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, con
/* Preset paths */
/**
- * Tries appending each of the semicolon-separated extensions in the PATHEXT
- * environment variable (Windows-only) onto *name in turn until such a file is found.
- * Returns success/failure.
- */
-static int add_win32_extension(char *name)
-{
- int retval = 0;
- int type;
-
- type = BLI_exists(name);
- if ((type == 0) || S_ISDIR(type)) {
-#ifdef _WIN32
- char filename[FILE_MAX];
- char ext[FILE_MAX];
- const char *extensions = getenv("PATHEXT");
- if (extensions) {
- char *temp;
- do {
- strcpy(filename, name);
- temp = strstr(extensions, ";");
- if (temp) {
- strncpy(ext, extensions, temp - extensions);
- ext[temp - extensions] = 0;
- extensions = temp + 1;
- strcat(filename, ext);
- }
- else {
- strcat(filename, extensions);
- }
-
- type = BLI_exists(filename);
- if (type && (!S_ISDIR(type))) {
- retval = 1;
- strcpy(name, filename);
- break;
- }
- } while (temp);
- }
-#endif
- }
- else {
- retval = 1;
- }
-
- return (retval);
-}
-
-/**
* Checks if name is a fully qualified filename to an executable.
* If not it searches $PATH for the file. On Windows it also
* adds the correct extension (.com .exe etc) from
@@ -562,39 +514,34 @@ static int add_win32_extension(char *name)
*/
static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name)
{
- char filename[FILE_MAX];
- const char *path = NULL, *temp;
-
-#ifdef _WIN32
- const char *separator = ";";
-#else
- const char *separator = ":";
-#endif
-
-
#ifdef WITH_BINRELOC
/* linux uses binreloc since argv[0] is not reliable, call br_init( NULL ) first */
- path = br_find_exe(NULL);
- if (path) {
- BLI_strncpy(fullname, path, maxlen);
- free((void *)path);
- return;
+ {
+ const char *path = NULL;
+ path = br_find_exe(NULL);
+ if (path) {
+ BLI_strncpy(fullname, path, maxlen);
+ free((void *)path);
+ return;
+ }
}
#endif
#ifdef _WIN32
- wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath");
- if (GetModuleFileNameW(0, fullname_16, maxlen)) {
- conv_utf_16_to_8(fullname_16, fullname, maxlen);
- if (!BLI_exists(fullname)) {
- printf("path can't be found: \"%.*s\"\n", (int)maxlen, fullname);
- MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK);
+ {
+ wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath");
+ if (GetModuleFileNameW(0, fullname_16, maxlen)) {
+ conv_utf_16_to_8(fullname_16, fullname, maxlen);
+ if (!BLI_exists(fullname)) {
+ printf("path can't be found: \"%.*s\"\n", (int)maxlen, fullname);
+ MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK);
+ }
+ MEM_freeN(fullname_16);
+ return;
}
+
MEM_freeN(fullname_16);
- return;
}
-
- MEM_freeN(fullname_16);
#endif
/* unix and non linux */
@@ -611,34 +558,19 @@ static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name
else
BLI_join_dirfile(fullname, maxlen, wdir, name);
- add_win32_extension(fullname); /* XXX, doesnt respect length */
+#ifdef _WIN32
+ BLI_path_program_extensions_add_win32(fullname, maxlen);
+#endif
}
else if (BLI_last_slash(name)) {
// full path
BLI_strncpy(fullname, name, maxlen);
- add_win32_extension(fullname);
+#ifdef _WIN32
+ BLI_path_program_extensions_add_win32(fullname, maxlen);
+#endif
}
else {
- // search for binary in $PATH
- path = getenv("PATH");
- if (path) {
- do {
- temp = strstr(path, separator);
- if (temp) {
- strncpy(filename, path, temp - path);
- filename[temp - path] = 0;
- path = temp + 1;
- }
- else {
- strncpy(filename, path, sizeof(filename));
- }
- BLI_path_append(fullname, maxlen, name);
- if (add_win32_extension(filename)) {
- BLI_strncpy(fullname, filename, maxlen);
- break;
- }
- } while (temp);
- }
+ BLI_path_program_search(fullname, maxlen, name);
}
#if defined(DEBUG)
if (!STREQ(name, fullname)) {
@@ -670,6 +602,58 @@ const char *BKE_appdir_program_dir(void)
return bprogdir;
}
+bool BKE_appdir_program_python_search(
+ char *fullpath, const size_t fullpath_len,
+ const int version_major, const int version_minor)
+{
+ const char *basename = "python";
+ char python_ver[16];
+ /* check both possible names */
+ const char *python_names[] = {basename, python_ver};
+ int i;
+
+ bool is_found = false;
+
+ BLI_snprintf(python_ver, sizeof(python_ver), "%s%d.%d", basename, version_major, version_minor);
+
+ {
+ const char *python_bin_dir = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, "bin");
+ if (python_bin_dir) {
+
+ for (i = 0; i < ARRAY_SIZE(python_names); i++) {
+ BLI_join_dirfile(fullpath, fullpath_len, python_bin_dir, python_names[i]);
+
+ if (
+#ifdef _WIN32
+ BLI_path_program_extensions_add_win32(fullpath, fullpath_len)
+#else
+ BLI_exists(fullpath)
+#endif
+ )
+ {
+ is_found = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (is_found == false) {
+ for (i = 0; i < ARRAY_SIZE(python_names); i++) {
+ if (BLI_path_program_search(fullpath, fullpath_len, python_names[i])) {
+ is_found = true;
+ break;
+ }
+ }
+ }
+
+ if (is_found == false) {
+ *fullpath = '\0';
+ }
+
+ return is_found;
+}
+
/**
* Gets the temp directory when blender first runs.
* If the default path is not found, use try $TEMP
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 6b67a4e5763..27d3d1c50fb 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -127,7 +127,7 @@ void BKE_armature_free(bArmature *arm)
/* free animation data */
if (arm->adt) {
- BKE_free_animdata(&arm->id);
+ BKE_animdata_free(&arm->id);
arm->adt = NULL;
}
}
@@ -1700,7 +1700,7 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
/* constraints - set target ob pointer to own object */
for (con = pchanw.constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -1825,9 +1825,12 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm)
BKE_pose_update_constraint_flags(ob->pose); /* for IK detection for example */
+#ifdef WITH_LEGACY_DEPSGRAPH
/* the sorting */
+ /* Sorting for new dependnecy graph is done on the scene graph level. */
if (counter > 1)
DAG_pose_sort(ob);
+#endif
ob->pose->flag &= ~POSE_RECALC;
ob->pose->flag |= POSE_WAS_REBUILT;
@@ -1835,494 +1838,6 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm)
BKE_pose_channels_hash_make(ob->pose);
}
-
-/* ********************** SPLINE IK SOLVER ******************* */
-
-/* Temporary evaluation tree data used for Spline IK */
-typedef struct tSplineIK_Tree {
- struct tSplineIK_Tree *next, *prev;
-
- int type; /* type of IK that this serves (CONSTRAINT_TYPE_KINEMATIC or ..._SPLINEIK) */
-
- bool free_points; /* free the point positions array */
- short chainlen; /* number of bones in the chain */
-
- float *points; /* parametric positions for the joints along the curve */
- bPoseChannel **chain; /* chain of bones to affect using Spline IK (ordered from the tip) */
-
- bPoseChannel *root; /* bone that is the root node of the chain */
-
- bConstraint *con; /* constraint for this chain */
- bSplineIKConstraint *ikData; /* constraint settings for this chain */
-} tSplineIK_Tree;
-
-/* ----------- */
-
-/* Tag the bones in the chain formed by the given bone for IK */
-static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPoseChannel *pchan_tip)
-{
- bPoseChannel *pchan, *pchanRoot = NULL;
- bPoseChannel *pchanChain[255];
- bConstraint *con = NULL;
- bSplineIKConstraint *ikData = NULL;
- float boneLengths[255], *jointPoints;
- float totLength = 0.0f;
- bool free_joints = 0;
- int segcount = 0;
-
- /* find the SplineIK constraint */
- for (con = pchan_tip->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_SPLINEIK) {
- ikData = con->data;
-
- /* target can only be curve */
- if ((ikData->tar == NULL) || (ikData->tar->type != OB_CURVE))
- continue;
- /* skip if disabled */
- if ((con->enforce == 0.0f) || (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)))
- continue;
-
- /* otherwise, constraint is ok... */
- break;
- }
- }
- if (con == NULL)
- return;
-
- /* make sure that the constraint targets are ok
- * - this is a workaround for a depsgraph bug...
- */
- if (ikData->tar) {
- /* note: when creating constraints that follow path, the curve gets the CU_PATH set now,
- * currently for paths to work it needs to go through the bevlist/displist system (ton)
- */
-
- /* only happens on reload file, but violates depsgraph still... fix! */
- if (ELEM(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
- BKE_displist_make_curveTypes(scene, ikData->tar, 0);
-
- /* path building may fail in EditMode after removing verts [#33268]*/
- if (ELEM(NULL, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
- /* BLI_assert(cu->path != NULL); */
- return;
- }
- }
- }
-
- /* find the root bone and the chain of bones from the root to the tip
- * NOTE: this assumes that the bones are connected, but that may not be true... */
- for (pchan = pchan_tip; pchan && (segcount < ikData->chainlen); pchan = pchan->parent, segcount++) {
- /* store this segment in the chain */
- pchanChain[segcount] = pchan;
-
- /* if performing rebinding, calculate the length of the bone */
- boneLengths[segcount] = pchan->bone->length;
- totLength += boneLengths[segcount];
- }
-
- if (segcount == 0)
- return;
- else
- pchanRoot = pchanChain[segcount - 1];
-
- /* perform binding step if required */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_BOUND) == 0) {
- float segmentLen = (1.0f / (float)segcount);
- int i;
-
- /* setup new empty array for the points list */
- if (ikData->points)
- MEM_freeN(ikData->points);
- ikData->numpoints = ikData->chainlen + 1;
- ikData->points = MEM_mallocN(sizeof(float) * ikData->numpoints, "Spline IK Binding");
-
- /* bind 'tip' of chain (i.e. first joint = tip of bone with the Spline IK Constraint) */
- ikData->points[0] = 1.0f;
-
- /* perform binding of the joints to parametric positions along the curve based
- * proportion of the total length that each bone occupies
- */
- for (i = 0; i < segcount; i++) {
- /* 'head' joints, traveling towards the root of the chain
- * - 2 methods; the one chosen depends on whether we've got usable lengths
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totLength == 0.0f)) {
- /* 1) equi-spaced joints */
- ikData->points[i + 1] = ikData->points[i] - segmentLen;
- }
- else {
- /* 2) to find this point on the curve, we take a step from the previous joint
- * a distance given by the proportion that this bone takes
- */
- ikData->points[i + 1] = ikData->points[i] - (boneLengths[i] / totLength);
- }
- }
-
- /* spline has now been bound */
- ikData->flag |= CONSTRAINT_SPLINEIK_BOUND;
- }
-
- /* disallow negative values (happens with float precision) */
- CLAMP_MIN(ikData->points[segcount], 0.0f);
-
- /* apply corrections for sensitivity to scaling on a copy of the bind points,
- * since it's easier to determine the positions of all the joints beforehand this way
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) && (totLength != 0.0f)) {
- float splineLen, maxScale;
- int i;
-
- /* make a copy of the points array, that we'll store in the tree
- * - although we could just multiply the points on the fly, this approach means that
- * we can introduce per-segment stretchiness later if it is necessary
- */
- jointPoints = MEM_dupallocN(ikData->points);
- free_joints = 1;
-
- /* get the current length of the curve */
- /* NOTE: this is assumed to be correct even after the curve was resized */
- splineLen = ikData->tar->curve_cache->path->totdist;
-
- /* calculate the scale factor to multiply all the path values by so that the
- * bone chain retains its current length, such that
- * maxScale * splineLen = totLength
- */
- maxScale = totLength / splineLen;
-
- /* apply scaling correction to all of the temporary points */
- /* TODO: this is really not adequate enough on really short chains */
- for (i = 0; i < segcount; i++)
- jointPoints[i] *= maxScale;
- }
- else {
- /* just use the existing points array */
- jointPoints = ikData->points;
- free_joints = 0;
- }
-
- /* 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... */
- {
- /* make new tree */
- tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree");
- tree->type = CONSTRAINT_TYPE_SPLINEIK;
-
- tree->chainlen = segcount;
-
- /* copy over the array of links to bones in the chain (from tip to root) */
- tree->chain = MEM_mallocN(sizeof(bPoseChannel *) * segcount, "SplineIK Chain");
- memcpy(tree->chain, pchanChain, sizeof(bPoseChannel *) * segcount);
-
- /* store reference to joint position array */
- tree->points = jointPoints;
- tree->free_points = free_joints;
-
- /* store references to different parts of the chain */
- tree->root = pchanRoot;
- tree->con = con;
- tree->ikData = ikData;
-
- /* AND! link the tree to the root */
- BLI_addtail(&pchanRoot->siktree, tree);
- }
-
- /* mark root channel having an IK tree */
- pchanRoot->flag |= POSE_IKSPLINE;
-}
-
-/* Tag which bones are members of Spline IK chains */
-static void splineik_init_tree(Scene *scene, Object *ob, float UNUSED(ctime))
-{
- bPoseChannel *pchan;
-
- /* find the tips of Spline IK chains, which are simply the bones which have been tagged as such */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->constflag & PCHAN_HAS_SPLINEIK)
- splineik_init_tree_from_pchan(scene, ob, pchan);
- }
-}
-
-/* ----------- */
-
-/* Evaluate spline IK for a given bone */
-static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan,
- int index, float ctime)
-{
- bSplineIKConstraint *ikData = tree->ikData;
- float poseHead[3], poseTail[3], poseMat[4][4];
- float splineVec[3], scaleFac, radius = 1.0f;
-
- /* firstly, calculate the bone matrix the standard way, since this is needed for roll control */
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
-
- copy_v3_v3(poseHead, pchan->pose_head);
- copy_v3_v3(poseTail, pchan->pose_tail);
-
- /* step 1: determine the positions for the endpoints of the bone */
- {
- float vec[4], dir[3], rad;
- float tailBlendFac = 1.0f;
-
- /* determine if the bone should still be affected by SplineIK */
- if (tree->points[index + 1] >= 1.0f) {
- /* spline doesn't affect the bone anymore, so done... */
- pchan->flag |= POSE_DONE;
- return;
- }
- else if ((tree->points[index] >= 1.0f) && (tree->points[index + 1] < 1.0f)) {
- /* blending factor depends on the amount of the bone still left on the chain */
- tailBlendFac = (1.0f - tree->points[index + 1]) / (tree->points[index] - tree->points[index + 1]);
- }
-
- /* tail endpoint */
- if (where_on_path(ikData->tar, tree->points[index], vec, dir, NULL, &rad, NULL)) {
- /* apply curve's object-mode transforms to the position
- * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0)
- mul_m4_v3(ikData->tar->obmat, vec);
-
- /* convert the position to pose-space, then store it */
- mul_m4_v3(ob->imat, vec);
- interp_v3_v3v3(poseTail, pchan->pose_tail, vec, tailBlendFac);
-
- /* set the new radius */
- radius = rad;
- }
-
- /* head endpoint */
- if (where_on_path(ikData->tar, tree->points[index + 1], vec, dir, NULL, &rad, NULL)) {
- /* apply curve's object-mode transforms to the position
- * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0)
- mul_m4_v3(ikData->tar->obmat, vec);
-
- /* store the position, and convert it to pose space */
- mul_m4_v3(ob->imat, vec);
- copy_v3_v3(poseHead, vec);
-
- /* set the new radius (it should be the average value) */
- radius = (radius + rad) / 2;
- }
- }
-
- /* step 2: determine the implied transform from these endpoints
- * - splineVec: the vector direction that the spline applies on the bone
- * - scaleFac: the factor that the bone length is scaled by to get the desired amount
- */
- sub_v3_v3v3(splineVec, poseTail, poseHead);
- scaleFac = len_v3(splineVec) / pchan->bone->length;
-
- /* step 3: compute the shortest rotation needed to map from the bone rotation to the current axis
- * - this uses the same method as is used for the Damped Track Constraint (see the code there for details)
- */
- {
- float dmat[3][3], rmat[3][3], tmat[3][3];
- float raxis[3], rangle;
-
- /* compute the raw rotation matrix from the bone's current matrix by extracting only the
- * orientation-relevant axes, and normalizing them
- */
- copy_v3_v3(rmat[0], pchan->pose_mat[0]);
- copy_v3_v3(rmat[1], pchan->pose_mat[1]);
- copy_v3_v3(rmat[2], pchan->pose_mat[2]);
- normalize_m3(rmat);
-
- /* also, normalize the orientation imposed by the bone, now that we've extracted the scale factor */
- normalize_v3(splineVec);
-
- /* calculate smallest axis-angle rotation necessary for getting from the
- * current orientation of the bone, to the spline-imposed direction
- */
- cross_v3_v3v3(raxis, rmat[1], splineVec);
-
- rangle = dot_v3v3(rmat[1], splineVec);
- CLAMP(rangle, -1.0f, 1.0f);
- rangle = acosf(rangle);
-
- /* multiply the magnitude of the angle by the influence of the constraint to
- * control the influence of the SplineIK effect
- */
- rangle *= tree->con->enforce;
-
- /* construct rotation matrix from the axis-angle rotation found above
- * - this call takes care to make sure that the axis provided is a unit vector first
- */
- axis_angle_to_mat3(dmat, raxis, rangle);
-
- /* combine these rotations so that the y-axis of the bone is now aligned as the spline dictates,
- * while still maintaining roll control from the existing bone animation
- */
- mul_m3_m3m3(tmat, dmat, rmat); /* m1, m3, m2 */
- normalize_m3(tmat); /* attempt to reduce shearing, though I doubt this'll really help too much now... */
- copy_m4_m3(poseMat, tmat);
- }
-
- /* step 4: set the scaling factors for the axes */
- {
- /* only multiply the y-axis by the scaling factor to get nice volume-preservation */
- mul_v3_fl(poseMat[1], scaleFac);
-
- /* set the scaling factors of the x and z axes from... */
- switch (ikData->xzScaleMode) {
- case CONSTRAINT_SPLINEIK_XZS_ORIGINAL:
- {
- /* original scales get used */
- float scale;
-
- /* x-axis scale */
- scale = len_v3(pchan->pose_mat[0]);
- mul_v3_fl(poseMat[0], scale);
- /* z-axis scale */
- scale = len_v3(pchan->pose_mat[2]);
- mul_v3_fl(poseMat[2], scale);
- break;
- }
- case CONSTRAINT_SPLINEIK_XZS_INVERSE:
- {
- /* old 'volume preservation' method using the inverse scale */
- float scale;
-
- /* calculate volume preservation factor which is
- * basically the inverse of the y-scaling factor
- */
- if (fabsf(scaleFac) != 0.0f) {
- scale = 1.0f / fabsf(scaleFac);
-
- /* we need to clamp this within sensible values */
- /* NOTE: these should be fine for now, but should get sanitised in future */
- CLAMP(scale, 0.0001f, 100000.0f);
- }
- else
- scale = 1.0f;
-
- /* apply the scaling */
- mul_v3_fl(poseMat[0], scale);
- mul_v3_fl(poseMat[2], scale);
- break;
- }
- case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC:
- {
- /* improved volume preservation based on the Stretch To constraint */
- float final_scale;
-
- /* as the basis for volume preservation, we use the inverse scale factor... */
- if (fabsf(scaleFac) != 0.0f) {
- /* NOTE: The method here is taken wholesale from the Stretch To constraint */
- float bulge = powf(1.0f / fabsf(scaleFac), ikData->bulge);
-
- if (bulge > 1.0f) {
- if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MAX) {
- float bulge_max = max_ff(ikData->bulge_max, 1.0f);
- float hard = min_ff(bulge, bulge_max);
-
- float range = bulge_max - 1.0f;
- float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
- float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2;
-
- bulge = interpf(soft, hard, ikData->bulge_smooth);
- }
- }
- if (bulge < 1.0f) {
- if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MIN) {
- float bulge_min = CLAMPIS(ikData->bulge_min, 0.0f, 1.0f);
- float hard = max_ff(bulge, bulge_min);
-
- float range = 1.0f - bulge_min;
- float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
- float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2;
-
- bulge = interpf(soft, hard, ikData->bulge_smooth);
- }
- }
-
- /* compute scale factor for xz axes from this value */
- final_scale = sqrt(bulge);
- }
- else {
- /* no scaling, so scale factor is simple */
- final_scale = 1.0f;
- }
-
- /* apply the scaling (assuming normalised scale) */
- mul_v3_fl(poseMat[0], final_scale);
- mul_v3_fl(poseMat[2], final_scale);
- break;
- }
- }
-
- /* finally, multiply the x and z scaling by the radius of the curve too,
- * to allow automatic scales to get tweaked still
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) {
- mul_v3_fl(poseMat[0], radius);
- mul_v3_fl(poseMat[2], radius);
- }
- }
-
- /* step 5: set the location of the bone in the matrix */
- if (ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) {
- /* when the 'no-root' option is affected, the chain can retain
- * the shape but be moved elsewhere
- */
- copy_v3_v3(poseHead, pchan->pose_head);
- }
- else if (tree->con->enforce < 1.0f) {
- /* when the influence is too low
- * - blend the positions for the 'root' bone
- * - stick to the parent for any other
- */
- if (pchan->parent) {
- copy_v3_v3(poseHead, pchan->pose_head);
- }
- else {
- /* FIXME: this introduces popping artifacts when we reach 0.0 */
- interp_v3_v3v3(poseHead, pchan->pose_head, poseHead, tree->con->enforce);
- }
- }
- copy_v3_v3(poseMat[3], poseHead);
-
- /* finally, store the new transform */
- copy_m4_m4(pchan->pose_mat, poseMat);
- copy_v3_v3(pchan->pose_head, poseHead);
-
- /* recalculate tail, as it's now outdated after the head gets adjusted above! */
- BKE_pose_where_is_bone_tail(pchan);
-
- /* done! */
- pchan->flag |= POSE_DONE;
-}
-
-/* Evaluate the chain starting from the nominated bone */
-static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
-{
- tSplineIK_Tree *tree;
-
- /* for each pose-tree, execute it if it is spline, otherwise just free it */
- while ((tree = pchan_root->siktree.first) != NULL) {
- int i;
-
- /* walk over each bone in the chain, calculating the effects of spline IK
- * - the chain is traversed in the opposite order to storage order (i.e. parent to children)
- * so that dependencies are correct
- */
- for (i = tree->chainlen - 1; i >= 0; i--) {
- bPoseChannel *pchan = tree->chain[i];
- splineik_evaluate_bone(tree, scene, ob, pchan, i, ctime);
- }
-
- /* free the tree info specific to SplineIK trees now */
- if (tree->chain)
- MEM_freeN(tree->chain);
- if (tree->free_points)
- MEM_freeN(tree->points);
-
- /* free this tree */
- BLI_freelinkN(&pchan_root->siktree, tree);
- }
-}
-
/* ********************** THE POSE SOLVER ******************* */
/* loc/rot/size to given mat4 */
@@ -2623,7 +2138,7 @@ void BKE_pose_where_is(Scene *scene, Object *ob)
* - this is not integrated as an IK plugin, since it should be able
* to function in conjunction with standard IK
*/
- splineik_init_tree(scene, ob, ctime);
+ BKE_pose_splineik_init_tree(scene, ob, ctime);
/* 3. the main loop, channels are already hierarchical sorted from root to children */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
@@ -2633,7 +2148,7 @@ void BKE_pose_where_is(Scene *scene, Object *ob)
}
/* 4b. if we find a Spline IK root, we handle it separated too */
else if (pchan->flag & POSE_IKSPLINE) {
- splineik_execute_tree(scene, ob, pchan, ctime);
+ BKE_splineik_execute_tree(scene, ob, pchan, ctime);
}
/* 5. otherwise just call the normal solver */
else if (!(pchan->flag & POSE_DONE)) {
@@ -2703,3 +2218,46 @@ BoundBox *BKE_armature_boundbox_get(Object *ob)
return ob->bb;
}
+
+/************** Graph evaluation ********************/
+
+bPoseChannel *BKE_armature_ik_solver_find_root(
+ bPoseChannel *pchan,
+ bKinematicConstraint *data)
+{
+ bPoseChannel *rootchan = pchan;
+ if (!(data->flag & CONSTRAINT_IK_TIP)) {
+ /* Exclude tip from chain. */
+ rootchan = rootchan->parent;
+ }
+ if (rootchan != NULL) {
+ int segcount = 0;
+ while (rootchan->parent) {
+ /* Continue up chain, until we reach target number of items. */
+ segcount++;
+ if (segcount == data->rootbone) {
+ break;
+ }
+ rootchan = rootchan->parent;
+ }
+ }
+ return rootchan;
+}
+
+bPoseChannel *BKE_armature_splineik_solver_find_root(
+ bPoseChannel *pchan,
+ bSplineIKConstraint *data)
+{
+ bPoseChannel *rootchan = pchan;
+ int segcount = 0;
+ BLI_assert(rootchan != NULL);
+ while (rootchan->parent) {
+ /* Continue up chain, until we reach target number of items. */
+ segcount++;
+ if (segcount == data->chainlen) {
+ break;
+ }
+ rootchan = rootchan->parent;
+ }
+ return rootchan;
+}
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
new file mode 100644
index 00000000000..ceda9f056bb
--- /dev/null
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -0,0 +1,697 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Defines and code for core node types
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_action.h"
+#include "BKE_anim.h"
+#include "BKE_armature.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_displist.h"
+#include "BKE_fcurve.h"
+#include "BKE_scene.h"
+
+#include "BIK_api.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "DEG_depsgraph.h"
+
+#ifdef WITH_LEGACY_DEPSGRAPH
+# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf
+#else
+# define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
+#endif
+
+/* ********************** SPLINE IK SOLVER ******************* */
+
+/* Temporary evaluation tree data used for Spline IK */
+typedef struct tSplineIK_Tree {
+ struct tSplineIK_Tree *next, *prev;
+
+ int type; /* type of IK that this serves (CONSTRAINT_TYPE_KINEMATIC or ..._SPLINEIK) */
+
+ bool free_points; /* free the point positions array */
+ short chainlen; /* number of bones in the chain */
+
+ float *points; /* parametric positions for the joints along the curve */
+ bPoseChannel **chain; /* chain of bones to affect using Spline IK (ordered from the tip) */
+
+ bPoseChannel *root; /* bone that is the root node of the chain */
+
+ bConstraint *con; /* constraint for this chain */
+ bSplineIKConstraint *ikData; /* constraint settings for this chain */
+} tSplineIK_Tree;
+
+/* ----------- */
+
+/* Tag the bones in the chain formed by the given bone for IK */
+static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPoseChannel *pchan_tip)
+{
+ bPoseChannel *pchan, *pchanRoot = NULL;
+ bPoseChannel *pchanChain[255];
+ bConstraint *con = NULL;
+ bSplineIKConstraint *ikData = NULL;
+ float boneLengths[255], *jointPoints;
+ float totLength = 0.0f;
+ bool free_joints = 0;
+ int segcount = 0;
+
+ /* find the SplineIK constraint */
+ for (con = pchan_tip->constraints.first; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_SPLINEIK) {
+ ikData = con->data;
+
+ /* target can only be curve */
+ if ((ikData->tar == NULL) || (ikData->tar->type != OB_CURVE))
+ continue;
+ /* skip if disabled */
+ if ((con->enforce == 0.0f) || (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)))
+ continue;
+
+ /* otherwise, constraint is ok... */
+ break;
+ }
+ }
+ if (con == NULL)
+ return;
+
+ /* make sure that the constraint targets are ok
+ * - this is a workaround for a depsgraph bug...
+ */
+ if (ikData->tar) {
+ /* note: when creating constraints that follow path, the curve gets the CU_PATH set now,
+ * currently for paths to work it needs to go through the bevlist/displist system (ton)
+ */
+
+ /* only happens on reload file, but violates depsgraph still... fix! */
+ if (ELEM(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
+ BKE_displist_make_curveTypes(scene, ikData->tar, 0);
+
+ /* path building may fail in EditMode after removing verts [#33268]*/
+ if (ELEM(NULL, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
+ /* BLI_assert(cu->path != NULL); */
+ return;
+ }
+ }
+ }
+
+ /* find the root bone and the chain of bones from the root to the tip
+ * NOTE: this assumes that the bones are connected, but that may not be true... */
+ for (pchan = pchan_tip; pchan && (segcount < ikData->chainlen); pchan = pchan->parent, segcount++) {
+ /* store this segment in the chain */
+ pchanChain[segcount] = pchan;
+
+ /* if performing rebinding, calculate the length of the bone */
+ boneLengths[segcount] = pchan->bone->length;
+ totLength += boneLengths[segcount];
+ }
+
+ if (segcount == 0)
+ return;
+ else
+ pchanRoot = pchanChain[segcount - 1];
+
+ /* perform binding step if required */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_BOUND) == 0) {
+ float segmentLen = (1.0f / (float)segcount);
+ int i;
+
+ /* setup new empty array for the points list */
+ if (ikData->points)
+ MEM_freeN(ikData->points);
+ ikData->numpoints = ikData->chainlen + 1;
+ ikData->points = MEM_mallocN(sizeof(float) * ikData->numpoints, "Spline IK Binding");
+
+ /* bind 'tip' of chain (i.e. first joint = tip of bone with the Spline IK Constraint) */
+ ikData->points[0] = 1.0f;
+
+ /* perform binding of the joints to parametric positions along the curve based
+ * proportion of the total length that each bone occupies
+ */
+ for (i = 0; i < segcount; i++) {
+ /* 'head' joints, traveling towards the root of the chain
+ * - 2 methods; the one chosen depends on whether we've got usable lengths
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totLength == 0.0f)) {
+ /* 1) equi-spaced joints */
+ ikData->points[i + 1] = ikData->points[i] - segmentLen;
+ }
+ else {
+ /* 2) to find this point on the curve, we take a step from the previous joint
+ * a distance given by the proportion that this bone takes
+ */
+ ikData->points[i + 1] = ikData->points[i] - (boneLengths[i] / totLength);
+ }
+ }
+
+ /* spline has now been bound */
+ ikData->flag |= CONSTRAINT_SPLINEIK_BOUND;
+ }
+
+ /* disallow negative values (happens with float precision) */
+ CLAMP_MIN(ikData->points[segcount], 0.0f);
+
+ /* apply corrections for sensitivity to scaling on a copy of the bind points,
+ * since it's easier to determine the positions of all the joints beforehand this way
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) && (totLength != 0.0f)) {
+ float splineLen, maxScale;
+ int i;
+
+ /* make a copy of the points array, that we'll store in the tree
+ * - although we could just multiply the points on the fly, this approach means that
+ * we can introduce per-segment stretchiness later if it is necessary
+ */
+ jointPoints = MEM_dupallocN(ikData->points);
+ free_joints = 1;
+
+ /* get the current length of the curve */
+ /* NOTE: this is assumed to be correct even after the curve was resized */
+ splineLen = ikData->tar->curve_cache->path->totdist;
+
+ /* calculate the scale factor to multiply all the path values by so that the
+ * bone chain retains its current length, such that
+ * maxScale * splineLen = totLength
+ */
+ maxScale = totLength / splineLen;
+
+ /* apply scaling correction to all of the temporary points */
+ /* TODO: this is really not adequate enough on really short chains */
+ for (i = 0; i < segcount; i++)
+ jointPoints[i] *= maxScale;
+ }
+ else {
+ /* just use the existing points array */
+ jointPoints = ikData->points;
+ free_joints = 0;
+ }
+
+ /* 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... */
+ {
+ /* make new tree */
+ tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree");
+ tree->type = CONSTRAINT_TYPE_SPLINEIK;
+
+ tree->chainlen = segcount;
+
+ /* copy over the array of links to bones in the chain (from tip to root) */
+ tree->chain = MEM_mallocN(sizeof(bPoseChannel *) * segcount, "SplineIK Chain");
+ memcpy(tree->chain, pchanChain, sizeof(bPoseChannel *) * segcount);
+
+ /* store reference to joint position array */
+ tree->points = jointPoints;
+ tree->free_points = free_joints;
+
+ /* store references to different parts of the chain */
+ tree->root = pchanRoot;
+ tree->con = con;
+ tree->ikData = ikData;
+
+ /* AND! link the tree to the root */
+ BLI_addtail(&pchanRoot->siktree, tree);
+ }
+
+ /* mark root channel having an IK tree */
+ pchanRoot->flag |= POSE_IKSPLINE;
+}
+
+/* Tag which bones are members of Spline IK chains */
+static void splineik_init_tree(Scene *scene, Object *ob, float UNUSED(ctime))
+{
+ bPoseChannel *pchan;
+
+ /* find the tips of Spline IK chains, which are simply the bones which have been tagged as such */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->constflag & PCHAN_HAS_SPLINEIK)
+ splineik_init_tree_from_pchan(scene, ob, pchan);
+ }
+}
+
+/* ----------- */
+
+/* Evaluate spline IK for a given bone */
+static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan,
+ int index, float ctime)
+{
+ bSplineIKConstraint *ikData = tree->ikData;
+ float poseHead[3], poseTail[3], poseMat[4][4];
+ float splineVec[3], scaleFac, radius = 1.0f;
+
+ /* firstly, calculate the bone matrix the standard way, since this is needed for roll control */
+ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+
+ copy_v3_v3(poseHead, pchan->pose_head);
+ copy_v3_v3(poseTail, pchan->pose_tail);
+
+ /* step 1: determine the positions for the endpoints of the bone */
+ {
+ float vec[4], dir[3], rad;
+ float tailBlendFac = 1.0f;
+
+ /* determine if the bone should still be affected by SplineIK */
+ if (tree->points[index + 1] >= 1.0f) {
+ /* spline doesn't affect the bone anymore, so done... */
+ pchan->flag |= POSE_DONE;
+ return;
+ }
+ else if ((tree->points[index] >= 1.0f) && (tree->points[index + 1] < 1.0f)) {
+ /* blending factor depends on the amount of the bone still left on the chain */
+ tailBlendFac = (1.0f - tree->points[index + 1]) / (tree->points[index] - tree->points[index + 1]);
+ }
+
+ /* tail endpoint */
+ if (where_on_path(ikData->tar, tree->points[index], vec, dir, NULL, &rad, NULL)) {
+ /* apply curve's object-mode transforms to the position
+ * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0)
+ mul_m4_v3(ikData->tar->obmat, vec);
+
+ /* convert the position to pose-space, then store it */
+ mul_m4_v3(ob->imat, vec);
+ interp_v3_v3v3(poseTail, pchan->pose_tail, vec, tailBlendFac);
+
+ /* set the new radius */
+ radius = rad;
+ }
+
+ /* head endpoint */
+ if (where_on_path(ikData->tar, tree->points[index + 1], vec, dir, NULL, &rad, NULL)) {
+ /* apply curve's object-mode transforms to the position
+ * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0)
+ mul_m4_v3(ikData->tar->obmat, vec);
+
+ /* store the position, and convert it to pose space */
+ mul_m4_v3(ob->imat, vec);
+ copy_v3_v3(poseHead, vec);
+
+ /* set the new radius (it should be the average value) */
+ radius = (radius + rad) / 2;
+ }
+ }
+
+ /* step 2: determine the implied transform from these endpoints
+ * - splineVec: the vector direction that the spline applies on the bone
+ * - scaleFac: the factor that the bone length is scaled by to get the desired amount
+ */
+ sub_v3_v3v3(splineVec, poseTail, poseHead);
+ scaleFac = len_v3(splineVec) / pchan->bone->length;
+
+ /* step 3: compute the shortest rotation needed to map from the bone rotation to the current axis
+ * - this uses the same method as is used for the Damped Track Constraint (see the code there for details)
+ */
+ {
+ float dmat[3][3], rmat[3][3], tmat[3][3];
+ float raxis[3], rangle;
+
+ /* compute the raw rotation matrix from the bone's current matrix by extracting only the
+ * orientation-relevant axes, and normalizing them
+ */
+ copy_v3_v3(rmat[0], pchan->pose_mat[0]);
+ copy_v3_v3(rmat[1], pchan->pose_mat[1]);
+ copy_v3_v3(rmat[2], pchan->pose_mat[2]);
+ normalize_m3(rmat);
+
+ /* also, normalize the orientation imposed by the bone, now that we've extracted the scale factor */
+ normalize_v3(splineVec);
+
+ /* calculate smallest axis-angle rotation necessary for getting from the
+ * current orientation of the bone, to the spline-imposed direction
+ */
+ cross_v3_v3v3(raxis, rmat[1], splineVec);
+
+ rangle = dot_v3v3(rmat[1], splineVec);
+ CLAMP(rangle, -1.0f, 1.0f);
+ rangle = acosf(rangle);
+
+ /* multiply the magnitude of the angle by the influence of the constraint to
+ * control the influence of the SplineIK effect
+ */
+ rangle *= tree->con->enforce;
+
+ /* construct rotation matrix from the axis-angle rotation found above
+ * - this call takes care to make sure that the axis provided is a unit vector first
+ */
+ axis_angle_to_mat3(dmat, raxis, rangle);
+
+ /* combine these rotations so that the y-axis of the bone is now aligned as the spline dictates,
+ * while still maintaining roll control from the existing bone animation
+ */
+ mul_m3_m3m3(tmat, dmat, rmat); /* m1, m3, m2 */
+ normalize_m3(tmat); /* attempt to reduce shearing, though I doubt this'll really help too much now... */
+ copy_m4_m3(poseMat, tmat);
+ }
+
+ /* step 4: set the scaling factors for the axes */
+ {
+ /* only multiply the y-axis by the scaling factor to get nice volume-preservation */
+ mul_v3_fl(poseMat[1], scaleFac);
+
+ /* set the scaling factors of the x and z axes from... */
+ switch (ikData->xzScaleMode) {
+ case CONSTRAINT_SPLINEIK_XZS_ORIGINAL:
+ {
+ /* original scales get used */
+ float scale;
+
+ /* x-axis scale */
+ scale = len_v3(pchan->pose_mat[0]);
+ mul_v3_fl(poseMat[0], scale);
+ /* z-axis scale */
+ scale = len_v3(pchan->pose_mat[2]);
+ mul_v3_fl(poseMat[2], scale);
+ break;
+ }
+ case CONSTRAINT_SPLINEIK_XZS_INVERSE:
+ {
+ /* old 'volume preservation' method using the inverse scale */
+ float scale;
+
+ /* calculate volume preservation factor which is
+ * basically the inverse of the y-scaling factor
+ */
+ if (fabsf(scaleFac) != 0.0f) {
+ scale = 1.0f / fabsf(scaleFac);
+
+ /* we need to clamp this within sensible values */
+ /* NOTE: these should be fine for now, but should get sanitised in future */
+ CLAMP(scale, 0.0001f, 100000.0f);
+ }
+ else
+ scale = 1.0f;
+
+ /* apply the scaling */
+ mul_v3_fl(poseMat[0], scale);
+ mul_v3_fl(poseMat[2], scale);
+ break;
+ }
+ case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC:
+ {
+ /* improved volume preservation based on the Stretch To constraint */
+ float final_scale;
+
+ /* as the basis for volume preservation, we use the inverse scale factor... */
+ if (fabsf(scaleFac) != 0.0f) {
+ /* NOTE: The method here is taken wholesale from the Stretch To constraint */
+ float bulge = powf(1.0f / fabsf(scaleFac), ikData->bulge);
+
+ if (bulge > 1.0f) {
+ if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MAX) {
+ float bulge_max = max_ff(ikData->bulge_max, 1.0f);
+ float hard = min_ff(bulge, bulge_max);
+
+ float range = bulge_max - 1.0f;
+ float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
+ float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2;
+
+ bulge = interpf(soft, hard, ikData->bulge_smooth);
+ }
+ }
+ if (bulge < 1.0f) {
+ if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MIN) {
+ float bulge_min = CLAMPIS(ikData->bulge_min, 0.0f, 1.0f);
+ float hard = max_ff(bulge, bulge_min);
+
+ float range = 1.0f - bulge_min;
+ float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
+ float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2;
+
+ bulge = interpf(soft, hard, ikData->bulge_smooth);
+ }
+ }
+
+ /* compute scale factor for xz axes from this value */
+ final_scale = sqrtf(bulge);
+ }
+ else {
+ /* no scaling, so scale factor is simple */
+ final_scale = 1.0f;
+ }
+
+ /* apply the scaling (assuming normalised scale) */
+ mul_v3_fl(poseMat[0], final_scale);
+ mul_v3_fl(poseMat[2], final_scale);
+ break;
+ }
+ }
+
+ /* finally, multiply the x and z scaling by the radius of the curve too,
+ * to allow automatic scales to get tweaked still
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) {
+ mul_v3_fl(poseMat[0], radius);
+ mul_v3_fl(poseMat[2], radius);
+ }
+ }
+
+ /* step 5: set the location of the bone in the matrix */
+ if (ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) {
+ /* when the 'no-root' option is affected, the chain can retain
+ * the shape but be moved elsewhere
+ */
+ copy_v3_v3(poseHead, pchan->pose_head);
+ }
+ else if (tree->con->enforce < 1.0f) {
+ /* when the influence is too low
+ * - blend the positions for the 'root' bone
+ * - stick to the parent for any other
+ */
+ if (pchan->parent) {
+ copy_v3_v3(poseHead, pchan->pose_head);
+ }
+ else {
+ /* FIXME: this introduces popping artifacts when we reach 0.0 */
+ interp_v3_v3v3(poseHead, pchan->pose_head, poseHead, tree->con->enforce);
+ }
+ }
+ copy_v3_v3(poseMat[3], poseHead);
+
+ /* finally, store the new transform */
+ copy_m4_m4(pchan->pose_mat, poseMat);
+ copy_v3_v3(pchan->pose_head, poseHead);
+
+ /* recalculate tail, as it's now outdated after the head gets adjusted above! */
+ BKE_pose_where_is_bone_tail(pchan);
+
+ /* done! */
+ pchan->flag |= POSE_DONE;
+}
+
+/* Evaluate the chain starting from the nominated bone */
+static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
+{
+ tSplineIK_Tree *tree;
+
+ /* for each pose-tree, execute it if it is spline, otherwise just free it */
+ while ((tree = pchan_root->siktree.first) != NULL) {
+ int i;
+
+ /* walk over each bone in the chain, calculating the effects of spline IK
+ * - the chain is traversed in the opposite order to storage order (i.e. parent to children)
+ * so that dependencies are correct
+ */
+ for (i = tree->chainlen - 1; i >= 0; i--) {
+ bPoseChannel *pchan = tree->chain[i];
+ splineik_evaluate_bone(tree, scene, ob, pchan, i, ctime);
+ }
+
+ /* free the tree info specific to SplineIK trees now */
+ if (tree->chain)
+ MEM_freeN(tree->chain);
+ if (tree->free_points)
+ MEM_freeN(tree->points);
+
+ /* free this tree */
+ BLI_freelinkN(&pchan_root->siktree, tree);
+ }
+}
+
+void BKE_pose_splineik_init_tree(Scene *scene, Object *ob, float ctime)
+{
+ splineik_init_tree(scene, ob, ctime);
+}
+
+void BKE_splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
+{
+ splineik_execute_tree(scene, ob, pchan_root, ctime);
+}
+
+/* *************** Depsgraph evaluation callbacks ************ */
+
+void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob,
+ bPose *pose)
+{
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ bPoseChannel *pchan;
+
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+
+ BLI_assert(ob->type == OB_ARMATURE);
+
+ /* We demand having proper pose. */
+ BLI_assert(ob->pose != NULL);
+ BLI_assert((ob->pose->flag & POSE_RECALC) == 0);
+
+ /* imat is needed for solvers. */
+ invert_m4_m4(ob->imat, ob->obmat);
+
+ /* 1. clear flags */
+ for (pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
+ pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE);
+ }
+
+ /* 2a. construct the IK tree (standard IK) */
+ BIK_initialize_tree(scene, ob, ctime);
+
+ /* 2b. construct the Spline IK trees
+ * - this is not integrated as an IK plugin, since it should be able
+ * to function in conjunction with standard IK
+ */
+ BKE_pose_splineik_init_tree(scene, ob, ctime);
+}
+
+void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob,
+ bPoseChannel *pchan)
+{
+ bArmature *arm = (bArmature *)ob->data;
+ DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
+ BLI_assert(ob->type == OB_ARMATURE);
+ if (arm->edbo || (arm->flag & ARM_RESTPOS)) {
+ Bone *bone = pchan->bone;
+ if (bone) {
+ copy_m4_m4(pchan->pose_mat, bone->arm_mat);
+ copy_v3_v3(pchan->pose_head, bone->arm_head);
+ copy_v3_v3(pchan->pose_tail, bone->arm_tail);
+ }
+ }
+ else {
+ /* TODO(sergey): Currently if there are constraints full transform is being
+ * evaluated in BKE_pose_constraints_evaluate.
+ */
+ if (pchan->constraints.first == NULL) {
+ if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
+ /* pass */
+ }
+ else {
+ /* TODO(sergey): Use time source node for time. */
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ }
+ }
+ }
+}
+
+void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
+ Object *ob,
+ bPoseChannel *pchan)
+{
+ Scene *scene = G.main->scene.first;
+ DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
+ if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
+ /* IK are being solved separately/ */
+ }
+ else {
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ }
+}
+
+void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx),
+ bPoseChannel *pchan)
+{
+ float imat[4][4];
+ DEBUG_PRINT("%s on pchan %s\n", __func__, pchan->name);
+ if (pchan->bone) {
+ invert_m4_m4(imat, pchan->bone->arm_mat);
+ mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat);
+ }
+}
+
+void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob,
+ bPoseChannel *rootchan)
+{
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name);
+ BIK_execute_tree(scene, ob, rootchan, ctime);
+}
+
+void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob,
+ bPoseChannel *rootchan)
+{
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name);
+ BKE_splineik_execute_tree(scene, ob, rootchan, ctime);
+}
+
+void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob,
+ bPose *UNUSED(pose))
+{
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+ BLI_assert(ob->type == OB_ARMATURE);
+
+ /* 6. release the IK tree */
+ BIK_release_tree(scene, ob, ctime);
+
+ ob->recalc &= ~OB_RECALC_ALL;
+}
+
+void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob)
+{
+ BLI_assert(ob->id.lib != NULL && 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",
+ ob->id.name + 2, ob->proxy_from->id.name + 2);
+ }
+}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index b6ea780576e..37bd9c5db5c 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -263,7 +263,7 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
/* but use new Scene pointer */
curscene = bfd->curscene;
- track_undo_scene = (mode == LOAD_UNDO && curscreen && bfd->main->wm.first);
+ track_undo_scene = (mode == LOAD_UNDO && curscreen && curscene && bfd->main->wm.first);
if (curscene == NULL) curscene = bfd->main->scene.first;
/* empty file, we add a scene to make Blender work */
@@ -283,13 +283,17 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
/* clear_global will free G.main, here we can still restore pointers */
blo_lib_link_screen_restore(bfd->main, curscreen, curscene);
- curscene = curscreen->scene;
+ /* curscreen might not be set when loading without ui (see T44217) so only re-assign if available */
+ if (curscreen) {
+ curscene = curscreen->scene;
+ }
if (track_undo_scene) {
wmWindowManager *wm = bfd->main->wm.first;
if (wm_scene_is_visible(wm, bfd->curscene) == false) {
curscene = bfd->curscene;
curscreen->scene = curscene;
+ BKE_screen_view3d_scene_sync(curscreen);
}
}
}
@@ -305,7 +309,7 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
CTX_data_main_set(C, G.main);
- sound_init_main(G.main);
+ BKE_sound_init_main(G.main);
if (bfd->user) {
@@ -619,7 +623,7 @@ int BKE_write_file_userdef(const char *filepath, ReportList *reports)
static void (*blender_test_break_cb)(void) = NULL;
-void set_blender_test_break_cb(void (*func)(void))
+void BKE_blender_callback_test_break_set(void (*func)(void))
{
blender_test_break_cb = func;
}
@@ -683,7 +687,7 @@ static int read_undosave(bContext *C, UndoElem *uel)
}
/* name can be a dynamic string */
-void BKE_write_undo(bContext *C, const char *name)
+void BKE_undo_write(bContext *C, const char *name)
{
uintptr_t maxmem, totmem, memused;
int nr /*, success */ /* UNUSED */;
@@ -701,7 +705,7 @@ void BKE_write_undo(bContext *C, const char *name)
while (undobase.last != curundo) {
uel = undobase.last;
BLI_remlink(&undobase, uel);
- BLO_free_memfile(&uel->memfile);
+ BLO_memfile_free(&uel->memfile);
MEM_freeN(uel);
}
@@ -723,7 +727,7 @@ void BKE_write_undo(bContext *C, const char *name)
UndoElem *first = undobase.first;
BLI_remlink(&undobase, first);
/* the merge is because of compression */
- BLO_merge_memfile(&first->memfile, &first->next->memfile);
+ BLO_memfile_merge(&first->memfile, &first->next->memfile);
MEM_freeN(first);
}
}
@@ -778,7 +782,7 @@ void BKE_write_undo(bContext *C, const char *name)
UndoElem *first = undobase.first;
BLI_remlink(&undobase, first);
/* the merge is because of compression */
- BLO_merge_memfile(&first->memfile, &first->next->memfile);
+ BLO_memfile_merge(&first->memfile, &first->next->memfile);
MEM_freeN(first);
}
}
@@ -817,13 +821,13 @@ void BKE_undo_step(bContext *C, int step)
}
}
-void BKE_reset_undo(void)
+void BKE_undo_reset(void)
{
UndoElem *uel;
uel = undobase.first;
while (uel) {
- BLO_free_memfile(&uel->memfile);
+ BLO_memfile_free(&uel->memfile);
uel = uel->next;
}
@@ -850,7 +854,7 @@ void BKE_undo_name(bContext *C, const char *name)
}
/* name optional */
-int BKE_undo_valid(const char *name)
+bool BKE_undo_is_valid(const char *name)
{
if (name) {
UndoElem *uel = BLI_rfindstring(&undobase, name, offsetof(UndoElem, name));
@@ -862,15 +866,16 @@ int BKE_undo_valid(const char *name)
/* get name of undo item, return null if no item with this index */
/* if active pointer, set it to 1 if true */
-const char *BKE_undo_get_name(int nr, int *active)
+const char *BKE_undo_get_name(int nr, bool *r_active)
{
UndoElem *uel = BLI_findlink(&undobase, nr);
- if (active) *active = 0;
+ if (r_active) *r_active = false;
if (uel) {
- if (active && uel == curundo)
- *active = 1;
+ if (r_active && (uel == curundo)) {
+ *r_active = true;
+ }
return uel->name;
}
return NULL;
@@ -936,15 +941,16 @@ bool BKE_undo_save_file(const char *filename)
}
/* sets curscene */
-Main *BKE_undo_get_main(Scene **scene)
+Main *BKE_undo_get_main(Scene **r_scene)
{
Main *mainp = NULL;
BlendFileData *bfd = BLO_read_from_memfile(G.main, G.main->name, &curundo->memfile, NULL);
if (bfd) {
mainp = bfd->main;
- if (scene)
- *scene = bfd->curscene;
+ if (r_scene) {
+ *r_scene = bfd->curscene;
+ }
MEM_freeN(bfd);
}
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 4d40aba67fd..8248ea2fa37 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -80,6 +80,10 @@
#include "BKE_bpath.h" /* own include */
+#ifndef _MSC_VER
+# include "BLI_strict_flags.h"
+#endif
+
static bool checkMissingFiles_visit_cb(void *userdata, char *UNUSED(path_dst), const char *path_src)
{
ReportList *reports = (ReportList *)userdata;
@@ -206,18 +210,19 @@ void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *re
* \returns found: 1/0.
*/
#define MAX_RECUR 16
-static int findFileRecursive(char *filename_new,
- const char *dirname,
- const char *filename,
- int *filesize,
- int *recur_depth)
+static bool missing_files_find__recursive(
+ char *filename_new,
+ const char *dirname,
+ const char *filename,
+ off_t *r_filesize,
+ int *r_recur_depth)
{
/* file searching stuff */
DIR *dir;
struct dirent *de;
BLI_stat_t status;
char path[FILE_MAX];
- int size;
+ off_t size;
bool found = false;
dir = opendir(dirname);
@@ -225,8 +230,8 @@ static int findFileRecursive(char *filename_new,
if (dir == NULL)
return found;
- if (*filesize == -1)
- *filesize = 0; /* dir opened fine */
+ if (*r_filesize == -1)
+ *r_filesize = 0; /* dir opened fine */
while ((de = readdir(dir)) != NULL) {
@@ -242,18 +247,18 @@ static int findFileRecursive(char *filename_new,
if (STREQLEN(filename, de->d_name, FILE_MAX)) { /* name matches */
/* open the file to read its size */
size = status.st_size;
- if ((size > 0) && (size > *filesize)) { /* find the biggest file */
- *filesize = size;
+ if ((size > 0) && (size > *r_filesize)) { /* find the biggest file */
+ *r_filesize = size;
BLI_strncpy(filename_new, path, FILE_MAX);
found = true;
}
}
}
else if (S_ISDIR(status.st_mode)) { /* is subdir */
- if (*recur_depth <= MAX_RECUR) {
- (*recur_depth)++;
- found |= findFileRecursive(filename_new, path, filename, filesize, recur_depth);
- (*recur_depth)--;
+ if (*r_recur_depth <= MAX_RECUR) {
+ (*r_recur_depth)++;
+ found |= missing_files_find__recursive(filename_new, path, filename, r_filesize, r_recur_depth);
+ (*r_recur_depth)--;
}
}
}
@@ -268,14 +273,14 @@ typedef struct BPathFind_Data {
bool find_all;
} BPathFind_Data;
-static bool findMissingFiles_visit_cb(void *userdata, char *path_dst, const char *path_src)
+static bool missing_files_find__visit_cb(void *userdata, char *path_dst, const char *path_src)
{
BPathFind_Data *data = (BPathFind_Data *)userdata;
char filename_new[FILE_MAX];
- int filesize = -1;
+ off_t filesize = -1;
int recur_depth = 0;
- int found;
+ bool found;
if (data->find_all == false) {
if (BLI_exists(path_src)) {
@@ -285,9 +290,10 @@ static bool findMissingFiles_visit_cb(void *userdata, char *path_dst, const char
filename_new[0] = '\0';
- found = findFileRecursive(filename_new,
- data->searchdir, BLI_path_basename(path_src),
- &filesize, &recur_depth);
+ found = missing_files_find__recursive(
+ filename_new,
+ data->searchdir, BLI_path_basename(path_src),
+ &filesize, &recur_depth);
if (filesize == -1) { /* could not open dir */
BKE_reportf(data->reports, RPT_WARNING,
@@ -318,13 +324,14 @@ void BKE_bpath_missing_files_find(Main *bmain, const char *searchpath, ReportLis
const bool find_all)
{
struct BPathFind_Data data = {NULL};
+ const int flag = BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_RELOAD_EDITED;
data.basedir = bmain->name;
data.reports = reports;
data.searchdir = searchpath;
data.find_all = find_all;
- BKE_bpath_traverse_main(bmain, findMissingFiles_visit_cb, BKE_BPATH_TRAVERSE_ABS, (void *)&data);
+ BKE_bpath_traverse_main(bmain, missing_files_find__visit_cb, flag, (void *)&data);
}
/* Run a visitor on a string, replacing the contents of the string as needed. */
@@ -366,6 +373,9 @@ static bool rewrite_path_fixed_dirfile(char path_dir[FILE_MAXDIR],
BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file);
+ /* so functions can check old value */
+ BLI_strncpy(path_dst, path_src, FILE_MAX);
+
if (absbase) {
BLI_path_abs(path_src, absbase);
}
@@ -395,7 +405,7 @@ static bool rewrite_path_alloc(char **path, BPathVisitor visit_cb, const char *a
}
if (visit_cb(userdata, path_dst, path_src)) {
- MEM_freeN((*path));
+ MEM_freeN(*path);
(*path) = BLI_strdup(path_dst);
return true;
}
@@ -425,12 +435,17 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
{
Image *ima;
ima = (Image *)id;
- if (ima->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
+ if (BKE_image_has_packedfile(ima) == false || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
if (rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data)) {
- if (!ima->packedfile) {
- BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
- BKE_image_walk_all_users(bmain, ima, bpath_traverse_image_user_cb);
+ if (flag & BKE_BPATH_TRAVERSE_RELOAD_EDITED) {
+ if (!BKE_image_has_packedfile(ima) &&
+ /* image may have been painted onto (and not saved, T44543) */
+ !BKE_image_is_dirty(ima))
+ {
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
+ BKE_image_walk_all_users(bmain, ima, bpath_traverse_image_user_cb);
+ }
}
}
}
@@ -484,10 +499,6 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
BPATH_TRAVERSE_POINTCACHE(smd->domain->ptcaches[0]);
}
}
- else if (md->type == eModifierType_Cloth) {
- ClothModifierData *clmd = (ClothModifierData *) md;
- BPATH_TRAVERSE_POINTCACHE(clmd->ptcaches);
- }
else if (md->type == eModifierType_Ocean) {
OceanModifierData *omd = (OceanModifierData *) md;
rewrite_path_fixed(omd->cachepath, visit_cb, absbase, bpath_user_data);
@@ -591,12 +602,12 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
}
else if ((seq->type == SEQ_TYPE_IMAGE) && se) {
/* might want an option not to loop over all strips */
- int len = MEM_allocN_len(se) / sizeof(*se);
- int i;
+ unsigned int len = (unsigned int)MEM_allocN_len(se) / (unsigned int)sizeof(*se);
+ unsigned int i;
if (flag & BKE_BPATH_TRAVERSE_SKIP_MULTIFILE) {
/* only operate on one path */
- len = MIN2(1, len);
+ len = MIN2(1u, len);
}
for (i = 0; i < len; i++, se++) {
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 10d77921515..d5c5fb5fe43 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -68,7 +68,7 @@ static void brush_defaults(Brush *brush)
brush->blend = 0;
brush->flag = 0;
- brush->ob_mode = OB_MODE_ALL_PAINT;
+ brush->ob_mode = OB_MODE_ALL_BRUSH;
/* BRUSH SCULPT TOOL SETTINGS */
brush->weight = 1.0f; /* weight of brush 0 - 1.0 */
@@ -103,8 +103,8 @@ static void brush_defaults(Brush *brush)
brush->jitter = 0.0f;
/* BRUSH TEXTURE SETTINGS */
- default_mtex(&brush->mtex);
- default_mtex(&brush->mask_mtex);
+ BKE_texture_mtex_default(&brush->mtex);
+ BKE_texture_mtex_default(&brush->mask_mtex);
brush->texture_sample_bias = 0; /* value to added to texture samples */
brush->texture_overlay_alpha = 33;
@@ -469,7 +469,7 @@ int BKE_brush_texture_set_nr(Brush *brush, int nr)
idtest = (ID *)BLI_findlink(&G.main->tex, nr - 1);
if (idtest == NULL) { /* new tex */
if (id) idtest = (ID *)BKE_texture_copy((Tex *)id);
- else idtest = (ID *)add_texture(G.main, "Tex");
+ else idtest = (ID *)BKE_texture_add(G.main, "Tex");
idtest->us--;
}
if (idtest != id) {
@@ -782,13 +782,13 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br,
* inconsistency. */
-float *BKE_brush_color_get(const struct Scene *scene, struct Brush *brush)
+const float *BKE_brush_color_get(const struct Scene *scene, const struct Brush *brush)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
return (ups->flag & UNIFIED_PAINT_COLOR) ? ups->rgb : brush->rgb;
}
-float *BKE_brush_secondary_color_get(const struct Scene *scene, struct Brush *brush)
+const float *BKE_brush_secondary_color_get(const struct Scene *scene, const struct Brush *brush)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
return (ups->flag & UNIFIED_PAINT_COLOR) ? ups->secondary_rgb : brush->secondary_rgb;
@@ -819,7 +819,7 @@ void BKE_brush_size_set(Scene *scene, Brush *brush, int size)
brush->size = size;
}
-int BKE_brush_size_get(const Scene *scene, Brush *brush)
+int BKE_brush_size_get(const Scene *scene, const Brush *brush)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
int size = (ups->flag & UNIFIED_PAINT_SIZE) ? ups->size : brush->size;
@@ -827,7 +827,7 @@ int BKE_brush_size_get(const Scene *scene, Brush *brush)
return (int)((float)size * U.pixelsize);
}
-int BKE_brush_use_locked_size(const Scene *scene, Brush *brush)
+int BKE_brush_use_locked_size(const Scene *scene, const Brush *brush)
{
const short us_flag = scene->toolsettings->unified_paint_settings.flag;
@@ -836,7 +836,7 @@ int BKE_brush_use_locked_size(const Scene *scene, Brush *brush)
(brush->flag & BRUSH_LOCK_SIZE);
}
-int BKE_brush_use_size_pressure(const Scene *scene, Brush *brush)
+int BKE_brush_use_size_pressure(const Scene *scene, const Brush *brush)
{
const short us_flag = scene->toolsettings->unified_paint_settings.flag;
@@ -845,7 +845,7 @@ int BKE_brush_use_size_pressure(const Scene *scene, Brush *brush)
(brush->flag & BRUSH_SIZE_PRESSURE);
}
-int BKE_brush_use_alpha_pressure(const Scene *scene, Brush *brush)
+int BKE_brush_use_alpha_pressure(const Scene *scene, const Brush *brush)
{
const short us_flag = scene->toolsettings->unified_paint_settings.flag;
@@ -864,7 +864,7 @@ void BKE_brush_unprojected_radius_set(Scene *scene, Brush *brush, float unprojec
brush->unprojected_radius = unprojected_radius;
}
-float BKE_brush_unprojected_radius_get(const Scene *scene, Brush *brush)
+float BKE_brush_unprojected_radius_get(const Scene *scene, const Brush *brush)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
@@ -883,14 +883,14 @@ void BKE_brush_alpha_set(Scene *scene, Brush *brush, float alpha)
brush->alpha = alpha;
}
-float BKE_brush_alpha_get(const Scene *scene, Brush *brush)
+float BKE_brush_alpha_get(const Scene *scene, const Brush *brush)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
return (ups->flag & UNIFIED_PAINT_ALPHA) ? ups->alpha : brush->alpha;
}
-float BKE_brush_weight_get(const Scene *scene, Brush *brush)
+float BKE_brush_weight_get(const Scene *scene, const Brush *brush)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
@@ -920,9 +920,10 @@ void BKE_brush_scale_unprojected_radius(float *unprojected_radius,
}
/* scale brush size to reflect a change in the brush's unprojected radius */
-void BKE_brush_scale_size(int *r_brush_size,
- float new_unprojected_radius,
- float old_unprojected_radius)
+void BKE_brush_scale_size(
+ int *r_brush_size,
+ float new_unprojected_radius,
+ float old_unprojected_radius)
{
float scale = new_unprojected_radius;
/* avoid division by zero */
diff --git a/source/blender/blenkernel/intern/cache_library.c b/source/blender/blenkernel/intern/cache_library.c
new file mode 100644
index 00000000000..370a2fc1887
--- /dev/null
+++ b/source/blender/blenkernel/intern/cache_library.c
@@ -0,0 +1,2256 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/cache_library.c
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_fileops.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_cache_library_types.h"
+#include "DNA_group_types.h"
+#include "DNA_key_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_force.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_anim.h"
+#include "BKE_bvhutils.h"
+#include "BKE_cache_library.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_editstrands.h"
+#include "BKE_effect.h"
+#include "BKE_global.h"
+#include "BKE_group.h"
+#include "BKE_idprop.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_strands.h"
+
+#include "BLF_translation.h"
+
+#include "PTC_api.h"
+
+#include "BPH_mass_spring.h"
+
+CacheLibrary *BKE_cache_library_add(Main *bmain, const char *name)
+{
+ CacheLibrary *cachelib;
+ char basename[MAX_NAME];
+
+ cachelib = BKE_libblock_alloc(bmain, ID_CL, name);
+
+ BLI_strncpy(basename, cachelib->id.name+2, sizeof(basename));
+ BLI_filename_make_safe(basename);
+ BLI_snprintf(cachelib->output_filepath, sizeof(cachelib->output_filepath), "//cache/%s.%s", basename, PTC_get_default_archive_extension());
+
+ cachelib->source_mode = CACHE_LIBRARY_SOURCE_SCENE;
+ cachelib->display_mode = CACHE_LIBRARY_DISPLAY_MODIFIERS;
+ cachelib->display_flag = CACHE_LIBRARY_DISPLAY_MOTION | CACHE_LIBRARY_DISPLAY_CHILDREN;
+
+ /* cache everything by default */
+ cachelib->data_types = CACHE_TYPE_ALL;
+
+ return cachelib;
+}
+
+CacheLibrary *BKE_cache_library_copy(CacheLibrary *cachelib)
+{
+ CacheLibrary *cachelibn;
+
+ cachelibn = BKE_libblock_copy(&cachelib->id);
+
+ if (cachelibn->filter_group)
+ id_us_plus(&cachelibn->filter_group->id);
+
+ {
+ CacheModifier *md;
+ BLI_listbase_clear(&cachelibn->modifiers);
+ for (md = cachelib->modifiers.first; md; md = md->next) {
+ BKE_cache_modifier_copy(cachelibn, md);
+ }
+ }
+
+ cachelibn->archive_info = NULL;
+
+ if (cachelib->id.lib) {
+ BKE_id_lib_local_paths(G.main, cachelib->id.lib, &cachelibn->id);
+ }
+
+ return cachelibn;
+}
+
+void BKE_cache_library_free(CacheLibrary *cachelib)
+{
+ BKE_cache_modifier_clear(cachelib);
+
+ if (cachelib->filter_group)
+ id_us_min(&cachelib->filter_group->id);
+
+ if (cachelib->archive_info)
+ BKE_cache_archive_info_free(cachelib->archive_info);
+}
+
+void BKE_cache_library_unlink(CacheLibrary *UNUSED(cachelib))
+{
+}
+
+/* ========================================================================= */
+
+const char *BKE_cache_item_name_prefix(int type)
+{
+ /* note: avoid underscores and the like here,
+ * the prefixes must be unique and safe when combined with arbitrary strings!
+ */
+ switch (type) {
+ case CACHE_TYPE_OBJECT: return "OBJECT";
+ case CACHE_TYPE_DERIVED_MESH: return "MESH";
+ case CACHE_TYPE_HAIR: return "HAIR";
+ case CACHE_TYPE_HAIR_PATHS: return "HAIRPATHS";
+ case CACHE_TYPE_PARTICLES: return "PARTICLES";
+ default: BLI_assert(false); return NULL; break;
+ }
+}
+
+void BKE_cache_item_name(Object *ob, int type, int index, char *name)
+{
+ if (index >= 0)
+ sprintf(name, "%s_%s_%d", BKE_cache_item_name_prefix(type), ob->id.name+2, index);
+ else
+ sprintf(name, "%s_%s", BKE_cache_item_name_prefix(type), ob->id.name+2);
+}
+
+int BKE_cache_item_name_length(Object *ob, int type, int index)
+{
+ char *str_dummy = (char *)"";
+ if (index >= 0)
+ return BLI_snprintf(str_dummy, 0, "%s_%s_%d", BKE_cache_item_name_prefix(type), ob->id.name + 2, index);
+ else
+ return BLI_snprintf(str_dummy, 0, "%s_%s", BKE_cache_item_name_prefix(type), ob->id.name + 2);
+}
+
+eCacheReadSampleResult BKE_cache_read_result(int ptc_result)
+{
+ switch (ptc_result) {
+ case PTC_READ_SAMPLE_INVALID: return CACHE_READ_SAMPLE_INVALID;
+ case PTC_READ_SAMPLE_EARLY: return CACHE_READ_SAMPLE_EARLY;
+ case PTC_READ_SAMPLE_LATE: return CACHE_READ_SAMPLE_LATE;
+ case PTC_READ_SAMPLE_EXACT: return CACHE_READ_SAMPLE_EXACT;
+ case PTC_READ_SAMPLE_INTERPOLATED: return CACHE_READ_SAMPLE_INTERPOLATED;
+ default: BLI_assert(false); break; /* should never happen, enums out of sync? */
+ }
+ return CACHE_READ_SAMPLE_INVALID;
+}
+
+bool BKE_cache_library_validate_item(CacheLibrary *cachelib, Object *ob, int type, int index)
+{
+ if (!cachelib)
+ return false;
+
+ if (ELEM(type, CACHE_TYPE_DERIVED_MESH)) {
+ if (ob->type != OB_MESH)
+ return false;
+ }
+ else if (ELEM(type, CACHE_TYPE_PARTICLES, CACHE_TYPE_HAIR, CACHE_TYPE_HAIR_PATHS)) {
+ ParticleSystem *psys = BLI_findlink(&ob->particlesystem, index);
+
+ if (!psys)
+ return false;
+
+ if (ELEM(type, CACHE_TYPE_PARTICLES)) {
+ if (psys->part->type != PART_EMITTER)
+ return false;
+ }
+
+ if (ELEM(type, CACHE_TYPE_HAIR, CACHE_TYPE_HAIR_PATHS)) {
+ if (psys->part->type != PART_HAIR)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* ========================================================================= */
+
+/* unused
+ * filtering now only tags objects to exclude them from storing data,
+ * but does not actually remove them from the duplilist.
+ */
+#if 0
+void BKE_cache_library_filter_duplilist(CacheLibrary *cachelib, ListBase *duplilist)
+{
+ if (cachelib->filter_group) {
+ GroupObject *gob;
+
+ /* tag only filter group objects as valid */
+ BKE_main_id_tag_idcode(G.main, ID_OB, false);
+ for (gob = cachelib->filter_group->gobject.first; gob; gob = gob->next)
+ gob->ob->id.flag |= LIB_DOIT;
+ }
+ else {
+ /* all objects valid */
+ BKE_main_id_tag_idcode(G.main, ID_OB, true);
+ }
+
+ {
+ /* remove invalid duplis */
+ DupliObject *dob, *dob_next;
+ for (dob = duplilist->first; dob; dob = dob_next) {
+ dob_next = dob->next;
+
+ if (!(dob->ob->id.flag & LIB_DOIT)) {
+ BLI_remlink(duplilist, dob);
+ MEM_freeN(dob);
+ }
+ }
+ }
+
+ /* clear LIB_DOIT tags */
+ BKE_main_id_tag_idcode(G.main, ID_OB, false);
+}
+#endif
+
+void BKE_cache_library_tag_used_objects(CacheLibrary *cachelib)
+{
+ if (cachelib->filter_group) {
+ GroupObject *gob;
+
+ /* tag only filter group objects as valid */
+ BKE_main_id_tag_idcode(G.main, ID_OB, false);
+ for (gob = cachelib->filter_group->gobject.first; gob; gob = gob->next)
+ gob->ob->id.flag |= LIB_DOIT;
+ }
+ else {
+ /* all objects valid */
+ BKE_main_id_tag_idcode(G.main, ID_OB, true);
+ }
+}
+
+/* ========================================================================= */
+
+static IDProperty *cache_library_get_metadata(CacheLibrary *cachelib, const char *name, bool create)
+{
+ IDProperty *idprops = IDP_GetProperties((ID *)cachelib, create);
+ IDProperty *metadata = NULL;
+ if (idprops) {
+ metadata = IDP_GetPropertyFromGroup(idprops, name);
+ if (!metadata && create) {
+ IDPropertyTemplate val;
+ val.i = 0;
+ metadata = IDP_New(IDP_GROUP, &val, name);
+ IDP_AddToGroup(idprops, metadata);
+ }
+ }
+ return metadata;
+}
+
+IDProperty *BKE_cache_library_get_input_metadata(CacheLibrary *cachelib, bool create)
+{
+ return cache_library_get_metadata(cachelib, "input_metadata", create);
+}
+
+IDProperty *BKE_cache_library_get_output_metadata(CacheLibrary *cachelib, bool create)
+{
+ return cache_library_get_metadata(cachelib, "output_metadata", create);
+}
+
+BLI_INLINE bool path_is_dirpath(const char *path)
+{
+ /* last char is a slash? */
+ const char *last_slash = BLI_last_slash(path);
+ return last_slash ? (*(last_slash + 1) == '\0') : false;
+}
+
+bool BKE_cache_archive_path_test(CacheLibrary *cachelib, const char *path)
+{
+ if (BLI_path_is_rel(path)) {
+ if (!(G.relbase_valid || cachelib->id.lib))
+ return false;
+ }
+
+ return true;
+
+}
+
+void BKE_cache_archive_path_ex(const char *path, Library *lib, const char *default_filename, char *result, int max)
+{
+ char abspath[FILE_MAX];
+
+ result[0] = '\0';
+
+ if (BLI_path_is_rel(path)) {
+ if (G.relbase_valid || lib) {
+ const char *relbase = lib ? lib->filepath : G.main->name;
+
+ BLI_strncpy(abspath, path, sizeof(abspath));
+ BLI_path_abs(abspath, relbase);
+ }
+ else {
+ /* can't construct a valid path */
+ return;
+ }
+ }
+ else {
+ BLI_strncpy(abspath, path, sizeof(abspath));
+ }
+
+ if (abspath[0] != '\0') {
+ if (path_is_dirpath(abspath) || BLI_is_dir(abspath)) {
+ if (default_filename && default_filename[0] != '\0')
+ BLI_join_dirfile(result, max, abspath, default_filename);
+ }
+ else {
+ BLI_strncpy(result, abspath, max);
+ }
+ }
+}
+
+void BKE_cache_archive_input_path(CacheLibrary *cachelib, char *result, int max)
+{
+ BKE_cache_archive_path_ex(cachelib->input_filepath, cachelib->id.lib, NULL, result, max);
+}
+
+void BKE_cache_archive_output_path(CacheLibrary *cachelib, char *result, int max)
+{
+ BKE_cache_archive_path_ex(cachelib->output_filepath, cachelib->id.lib, cachelib->id.name+2, result, max);
+}
+
+static bool has_active_cache(CacheLibrary *cachelib)
+{
+ const bool is_baking = cachelib->flag & CACHE_LIBRARY_BAKING;
+
+ /* don't read results from output archive when baking */
+ if (!is_baking) {
+ if (cachelib->display_mode == CACHE_LIBRARY_DISPLAY_RESULT) {
+ return true;
+ }
+ }
+
+ if (ELEM(cachelib->source_mode, CACHE_LIBRARY_SOURCE_CACHE, CACHE_LIBRARY_DISPLAY_MODIFIERS)) {
+ return true;
+ }
+
+ return false;
+}
+
+static struct PTCReaderArchive *find_active_cache(Scene *scene, CacheLibrary *cachelib)
+{
+ char filename[FILE_MAX];
+ struct PTCReaderArchive *archive = NULL;
+
+ const bool is_baking = cachelib->flag & CACHE_LIBRARY_BAKING;
+
+ /* don't read results from output archive when baking */
+ if (!is_baking) {
+ if (cachelib->display_mode == CACHE_LIBRARY_DISPLAY_RESULT) {
+ /* try using the output cache */
+ BKE_cache_archive_output_path(cachelib, filename, sizeof(filename));
+ archive = PTC_open_reader_archive(scene, filename);
+ }
+ }
+
+ if (!archive && ELEM(cachelib->source_mode, CACHE_LIBRARY_SOURCE_CACHE, CACHE_LIBRARY_DISPLAY_MODIFIERS)) {
+ BKE_cache_archive_input_path(cachelib, filename, sizeof(filename));
+ archive = PTC_open_reader_archive(scene, filename);
+ }
+
+ /* get basic archive info */
+ if (cachelib->archive_info)
+ BKE_cache_archive_info_clear(cachelib->archive_info);
+ else
+ cachelib->archive_info = BKE_cache_archive_info_new();
+ BLI_strncpy(cachelib->archive_info->filepath, filename, sizeof(cachelib->archive_info->filepath));
+ if (archive) {
+ IDProperty *metadata = BKE_cache_library_get_input_metadata(cachelib, true);
+ PTC_get_archive_info(archive, cachelib->archive_info, metadata);
+ }
+
+ return archive;
+}
+
+void BKE_cache_library_get_read_flags(CacheLibrary *cachelib, bool use_render, bool for_display, bool *read_strands_motion, bool *read_strands_children)
+{
+ if (!use_render && for_display) {
+ *read_strands_motion = cachelib->display_flag & CACHE_LIBRARY_DISPLAY_MOTION;
+ *read_strands_children = cachelib->display_flag & CACHE_LIBRARY_DISPLAY_CHILDREN;
+ }
+ else {
+ *read_strands_motion = true;
+ *read_strands_children = true;
+ }
+}
+
+bool BKE_cache_read_dupli_cache(CacheLibrary *cachelib, DupliCache *dupcache,
+ Scene *scene, Group *dupgroup, float frame, bool use_render, bool for_display)
+{
+ bool read_strands_motion, read_strands_children, read_simdebug = G.debug & G_DEBUG_SIMDATA;
+ struct PTCReaderArchive *archive;
+ struct PTCReader *reader;
+
+ if (!dupcache)
+ return false;
+
+ dupcache->result = CACHE_READ_SAMPLE_INVALID;
+
+ if (!dupgroup || !cachelib)
+ return false;
+
+ archive = find_active_cache(scene, cachelib);
+ if (!archive)
+ return false;
+
+ PTC_reader_archive_use_render(archive, use_render);
+
+ BKE_cache_library_get_read_flags(cachelib, use_render, for_display, &read_strands_motion, &read_strands_children);
+ // TODO duplicache reader should only overwrite data that is not sequentially generated by modifiers (simulations) ...
+ reader = PTC_reader_duplicache(dupgroup->id.name, dupgroup, dupcache,
+ read_strands_motion, read_strands_children, read_simdebug);
+ PTC_reader_init(reader, archive);
+
+ dupcache->result = BKE_cache_read_result(PTC_read_sample(reader, frame));
+
+ PTC_reader_free(reader);
+ PTC_close_reader_archive(archive);
+
+ return (dupcache->result != CACHE_READ_SAMPLE_INVALID);
+}
+
+bool BKE_cache_read_dupli_object(CacheLibrary *cachelib, DupliObjectData *data,
+ Scene *scene, Object *ob, float frame, bool use_render, bool for_display)
+{
+ bool read_strands_motion, read_strands_children;
+ struct PTCReaderArchive *archive;
+ struct PTCReader *reader;
+ /*eCacheReadSampleResult result;*/ /* unused */
+
+ if (!data || !ob || !cachelib)
+ return false;
+
+ archive = find_active_cache(scene, cachelib);
+ if (!archive)
+ return false;
+
+ PTC_reader_archive_use_render(archive, use_render);
+
+ BKE_cache_library_get_read_flags(cachelib, use_render, for_display, &read_strands_motion, &read_strands_children);
+ reader = PTC_reader_duplicache_object(ob->id.name, ob, data, read_strands_motion, read_strands_children);
+ PTC_reader_init(reader, archive);
+
+ /*result = */BKE_cache_read_result(PTC_read_sample(reader, frame));
+
+ PTC_reader_free(reader);
+ PTC_close_reader_archive(archive);
+
+ return true;
+}
+
+
+void BKE_cache_library_dag_recalc_tag(EvaluationContext *UNUSED(eval_ctx), Main *bmain)
+{
+ CacheLibrary *cachelib;
+ for (cachelib = bmain->cache_library.first; cachelib; cachelib = cachelib->id.next) {
+ if (has_active_cache(cachelib))
+ DAG_id_tag_update(&cachelib->id, OB_RECALC_DATA | OB_RECALC_TIME);
+ }
+}
+
+/* ========================================================================= */
+
+CacheModifierTypeInfo cache_modifier_types[NUM_CACHE_MODIFIER_TYPES];
+
+static CacheModifierTypeInfo *cache_modifier_type_get(eCacheModifier_Type type)
+{
+ return &cache_modifier_types[type];
+}
+
+static void cache_modifier_type_set(eCacheModifier_Type type, CacheModifierTypeInfo *mti)
+{
+ memcpy(&cache_modifier_types[type], mti, sizeof(CacheModifierTypeInfo));
+}
+
+const char *BKE_cache_modifier_type_name(eCacheModifier_Type type)
+{
+ return cache_modifier_type_get(type)->name;
+}
+
+const char *BKE_cache_modifier_type_struct_name(eCacheModifier_Type type)
+{
+ return cache_modifier_type_get(type)->struct_name;
+}
+
+int BKE_cache_modifier_type_struct_size(eCacheModifier_Type type)
+{
+ return cache_modifier_type_get(type)->struct_size;
+}
+
+/* ------------------------------------------------------------------------- */
+
+bool BKE_cache_modifier_unique_name(ListBase *modifiers, CacheModifier *md)
+{
+ if (modifiers && md) {
+ CacheModifierTypeInfo *mti = cache_modifier_type_get(md->type);
+
+ return BLI_uniquename(modifiers, md, DATA_(mti->name), '.', offsetof(CacheModifier, name), sizeof(md->name));
+ }
+ return false;
+}
+
+CacheModifier *BKE_cache_modifier_add(CacheLibrary *cachelib, const char *name, eCacheModifier_Type type)
+{
+ CacheModifierTypeInfo *mti = cache_modifier_type_get(type);
+
+ CacheModifier *md = MEM_callocN(mti->struct_size, "cache modifier");
+ md->type = type;
+
+ if (!name)
+ name = mti->name;
+ BLI_strncpy_utf8(md->name, name, sizeof(md->name));
+ /* make sure modifier has unique name */
+ BKE_cache_modifier_unique_name(&cachelib->modifiers, md);
+
+ if (mti->init)
+ mti->init(md);
+
+ BLI_addtail(&cachelib->modifiers, md);
+
+ return md;
+}
+
+void BKE_cache_modifier_remove(CacheLibrary *cachelib, CacheModifier *md)
+{
+ CacheModifierTypeInfo *mti = cache_modifier_type_get(md->type);
+
+ BLI_remlink(&cachelib->modifiers, md);
+
+ if (mti->free)
+ mti->free(md);
+
+ MEM_freeN(md);
+}
+
+void BKE_cache_modifier_clear(CacheLibrary *cachelib)
+{
+ CacheModifier *md, *md_next;
+ for (md = cachelib->modifiers.first; md; md = md_next) {
+ CacheModifierTypeInfo *mti = cache_modifier_type_get(md->type);
+ md_next = md->next;
+
+ if (mti->free)
+ mti->free(md);
+
+ MEM_freeN(md);
+ }
+
+ BLI_listbase_clear(&cachelib->modifiers);
+}
+
+CacheModifier *BKE_cache_modifier_copy(CacheLibrary *cachelib, CacheModifier *md)
+{
+ CacheModifierTypeInfo *mti = cache_modifier_type_get(md->type);
+
+ CacheModifier *tmd = MEM_dupallocN(md);
+
+ if (mti->copy)
+ mti->copy(md, tmd);
+
+ BLI_addtail(&cachelib->modifiers, tmd);
+
+ return tmd;
+}
+
+void BKE_cache_modifier_foreachIDLink(struct CacheLibrary *cachelib, struct CacheModifier *md, CacheModifier_IDWalkFunc walk, void *userdata)
+{
+ CacheModifierTypeInfo *mti = cache_modifier_type_get(md->type);
+
+ if (mti->foreachIDLink)
+ mti->foreachIDLink(md, cachelib, walk, userdata);
+}
+
+void BKE_cache_process_dupli_cache(CacheLibrary *cachelib, CacheProcessData *data,
+ Scene *scene, Group *dupgroup, float frame_prev, float frame,
+ bool do_modifiers, bool do_strands_child_deform, bool do_strands_motion)
+{
+ CacheProcessContext ctx;
+ CacheModifier *md;
+
+ ctx.bmain = G.main;
+ ctx.scene = scene;
+ ctx.cachelib = cachelib;
+ ctx.group = dupgroup;
+
+ if (do_modifiers) {
+ for (md = cachelib->modifiers.first; md; md = md->next) {
+ CacheModifierTypeInfo *mti = cache_modifier_type_get(md->type);
+
+ // TODO parent modifiers only here
+ if (mti->process)
+ mti->process(md, &ctx, data, frame, frame_prev, eCacheProcessFlag_DoStrands);
+ }
+ }
+
+ /* deform child strands to follow parent motion */
+ if (do_modifiers || do_strands_child_deform) {
+ struct DupliCacheIterator *it;
+
+ it = BKE_dupli_cache_iter_new(data->dupcache);
+ for (; BKE_dupli_cache_iter_valid(it); BKE_dupli_cache_iter_next(it)) {
+ DupliObjectData *dobdata = BKE_dupli_cache_iter_get(it);
+ DupliObjectDataStrands *link;
+
+ for (link = dobdata->strands.first; link; link = link->next) {
+ if (link->strands_children)
+ BKE_strands_children_deform(link->strands_children, link->strands, do_strands_motion);
+ }
+ }
+ BKE_dupli_cache_iter_free(it);
+ }
+
+ if (do_modifiers) {
+ for (md = cachelib->modifiers.first; md; md = md->next) {
+ CacheModifierTypeInfo *mti = cache_modifier_type_get(md->type);
+
+ // TODO child modifiers only here
+ if (mti->process)
+ mti->process(md, &ctx, data, frame, frame_prev, eCacheProcessFlag_DoStrandsChildren);
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static ForceFieldVertexCache *forcefield_vertex_cache_new(void);
+static void forcefield_vertex_cache_free(ForceFieldVertexCache *cache);
+static void forcefield_vertex_cache_clear(ForceFieldVertexCache *cache);
+static void forcefield_vertex_cache_init(ForceFieldVertexCache *cache, float frame, DerivedMesh *dm);
+
+static void effector_set_mesh(CacheEffector *eff, Object *ob, DerivedMesh *dm, bool create_dm, bool create_bvhtree, bool world_space)
+{
+ if (create_dm && dm) {
+ unsigned int numverts, i;
+ MVert *mvert, *mv;
+
+ eff->dm = CDDM_copy(dm);
+ if (!eff->dm)
+ return;
+
+ DM_ensure_tessface(eff->dm);
+ CDDM_calc_normals(eff->dm);
+
+ numverts = eff->dm->getNumVerts(eff->dm);
+ mvert = eff->dm->getVertArray(eff->dm);
+
+ if (world_space) {
+ /* convert to world coordinates */
+ for (i = 0, mv = mvert; i < numverts; ++i, ++mv) {
+ mul_m4_v3(ob->obmat, mv->co);
+ }
+ }
+
+ if (create_bvhtree) {
+ if (eff->treedata)
+ free_bvhtree_from_mesh(eff->treedata);
+ else
+ eff->treedata = MEM_callocN(sizeof(BVHTreeFromMesh), "cache effector bvhtree data");
+
+ bvhtree_from_mesh_faces(eff->treedata, eff->dm, 0.0, 2, 6);
+ }
+ }
+}
+
+static void effector_set_instances(CacheEffector *eff, Object *ob, float obmat[4][4], ListBase *duplilist)
+{
+ DupliObject *dob;
+
+ for (dob = duplilist->first; dob; dob = dob->next) {
+ CacheEffectorInstance *inst;
+
+ if (dob->ob != ob)
+ continue;
+
+ inst = MEM_callocN(sizeof(CacheEffectorInstance), "cache effector instance");
+ mul_m4_m4m4(inst->mat, obmat, dob->mat);
+ invert_m4_m4(inst->imat, inst->mat);
+
+ BLI_addtail(&eff->instances, inst);
+ }
+}
+
+static bool forcefield_get_effector(DupliCache *dupcache, float obmat[4][4], ForceFieldCacheModifier *ffmd, CacheEffector *eff)
+{
+ DupliObjectData *dobdata;
+
+ if (!ffmd->object)
+ return false;
+
+ dobdata = BKE_dupli_cache_find_data(dupcache, ffmd->object);
+ if (!dobdata)
+ return false;
+
+ effector_set_mesh(eff, dobdata->ob, dobdata->dm, true, true, false);
+ effector_set_instances(eff, dobdata->ob, obmat, &dupcache->duplilist);
+
+ switch (ffmd->type) {
+ case eForceFieldCacheModifier_Type_Deflect:
+ eff->type = eCacheEffector_Type_Deflect;
+ break;
+ case eForceFieldCacheModifier_Type_Drag:
+ eff->type = eCacheEffector_Type_Drag;
+ break;
+ }
+
+ eff->strength = ffmd->strength;
+ eff->falloff = ffmd->falloff;
+ eff->mindist = ffmd->min_distance;
+ eff->maxdist = ffmd->max_distance;
+ eff->double_sided = ffmd->flag & eForceFieldCacheModifier_Flag_DoubleSided;
+ eff->vertex_cache = ffmd->vertex_cache;
+
+ return true;
+}
+
+int BKE_cache_effectors_get(CacheEffector *effectors, int max, CacheLibrary *cachelib, DupliCache *dupcache, float obmat[4][4])
+{
+ CacheModifier *md;
+ int tot = 0;
+
+ if (tot >= max)
+ return tot;
+
+ memset(effectors, 0, sizeof(CacheEffector) * max);
+
+ for (md = cachelib->modifiers.first; md; md = md->next) {
+ switch (md->type) {
+ case eCacheModifierType_ForceField: {
+ ForceFieldCacheModifier *ffmd = (ForceFieldCacheModifier *)md;
+ if (forcefield_get_effector(dupcache, obmat, ffmd, &effectors[tot]))
+ tot++;
+ break;
+ }
+ }
+
+ BLI_assert(tot <= max);
+ if (tot == max)
+ break;
+ }
+
+ return tot;
+}
+
+void BKE_cache_effectors_free(CacheEffector *effectors, int tot)
+{
+ CacheEffector *eff;
+ int i;
+
+ for (i = 0, eff = effectors; i < tot; ++i, ++eff) {
+ BLI_freelistN(&eff->instances);
+
+ if (eff->treedata) {
+ free_bvhtree_from_mesh(eff->treedata);
+ MEM_freeN(eff->treedata);
+ }
+
+ if (eff->dm) {
+ eff->dm->release(eff->dm);
+ }
+ }
+}
+
+static bool forcefield_velocity_update(DupliCache *dupcache, float obmat[4][4], float frame, ForceFieldCacheModifier *ffmd)
+{
+ DupliObjectData *dobdata;
+ bool use_vertex_cache = false;
+
+ if (!ffmd->object)
+ return false;
+
+ dobdata = BKE_dupli_cache_find_data(dupcache, ffmd->object);
+ if (!dobdata)
+ return false;
+
+ switch (ffmd->type) {
+ case eForceFieldCacheModifier_Type_Drag:
+ use_vertex_cache = true;
+ break;
+ }
+
+ if (use_vertex_cache) {
+ if (!ffmd->vertex_cache) {
+ ffmd->vertex_cache = forcefield_vertex_cache_new();
+ }
+
+ forcefield_vertex_cache_init(ffmd->vertex_cache, frame, dobdata->dm);
+ {
+ int i;
+ for (i = 0; i < ffmd->vertex_cache->totvert; ++i) {
+ float x[3], v[3];
+ mul_v3_m4v3(x, obmat, ffmd->vertex_cache->co_prev[i]);
+ copy_v3_v3(v, ffmd->vertex_cache->vel[i]);
+ mul_mat3_m4_v3(obmat, v);
+ BKE_sim_debug_data_add_vector(x, v, 1,1,0, "hairsim", 45232, i);
+ }
+ }
+ }
+
+ return true;
+}
+
+void BKE_cache_effector_velocity_update(CacheLibrary *cachelib, DupliCache *dupcache, float obmat[4][4], float frame)
+{
+ CacheModifier *md;
+
+ for (md = cachelib->modifiers.first; md; md = md->next) {
+ switch (md->type) {
+ case eCacheModifierType_ForceField:
+ forcefield_velocity_update(dupcache, obmat, frame, (ForceFieldCacheModifier *)md);
+ break;
+ }
+ }
+}
+
+static bool cache_effector_falloff(const CacheEffector *eff, float distance, float *r_factor)
+{
+ float mindist = eff->mindist;
+ float maxdist = eff->maxdist;
+ float falloff = eff->falloff;
+ float range = maxdist - mindist;
+
+ if (r_factor) *r_factor = 0.0f;
+
+ if (range <= 0.0f)
+ return false;
+
+ if (distance > eff->maxdist)
+ return false;
+ CLAMP_MIN(distance, eff->mindist);
+ CLAMP_MIN(falloff, 0.0f);
+
+ if (r_factor) *r_factor = powf(1.0f - (distance - mindist) / range, falloff);
+ return true;
+}
+
+typedef struct CacheEffectorTessfaceData {
+ int face_index;
+ MFace *mface;
+ MVert *mvert[4];
+ float weight[4];
+} CacheEffectorTessfaceData;
+
+static void cache_effector_velocity(const CacheEffector *eff, CacheEffectorInstance *inst, CacheEffectorTessfaceData *tessface, float vel[3])
+{
+ zero_v3(vel);
+
+ if (!eff->vertex_cache)
+ return;
+
+ BLI_assert(eff->vertex_cache->totvert == eff->dm->getNumVerts(eff->dm));
+
+ madd_v3_v3fl(vel, eff->vertex_cache->vel[tessface->mface->v1], tessface->weight[0]);
+ madd_v3_v3fl(vel, eff->vertex_cache->vel[tessface->mface->v2], tessface->weight[1]);
+ madd_v3_v3fl(vel, eff->vertex_cache->vel[tessface->mface->v3], tessface->weight[2]);
+ if (tessface->mface->v4)
+ madd_v3_v3fl(vel, eff->vertex_cache->vel[tessface->mface->v4], tessface->weight[3]);
+
+ /* vertex cache velocities are in local space, effector results are all expected in world space */
+ mul_mat3_m4_v3(inst->mat, vel);
+}
+
+static bool cache_effector_find_nearest(CacheEffector *eff, CacheEffectorInstance *inst, CacheEffectorPoint *point,
+ float r_vec[3], float r_nor[3], float *r_dist, bool *r_inside,
+ CacheEffectorTessfaceData *r_tessface)
+{
+ const bool need_inside = r_dist || r_inside;
+
+ BVHTreeNearest nearest = {0, };
+ float world_near_co[3], world_near_no[3];
+ float co[3], vec[3], dist;
+ bool inside;
+
+ if (!eff->treedata)
+ return false;
+
+ nearest.dist_sq = FLT_MAX;
+
+ /* lookup in object space */
+ mul_v3_m4v3(co, inst->imat, point->x);
+
+ BLI_bvhtree_find_nearest(eff->treedata->tree, co, &nearest, eff->treedata->nearest_callback, eff->treedata);
+ if (nearest.index < 0)
+ return false;
+
+ /* convert back to world space */
+ mul_v3_m4v3(world_near_co, inst->mat, nearest.co);
+ copy_v3_v3(world_near_no, nearest.no);
+ mul_mat3_m4_v3(inst->mat, world_near_no);
+
+ sub_v3_v3v3(vec, point->x, world_near_co);
+ dist = normalize_v3(vec);
+
+ if (need_inside) {
+ inside = false;
+ if (!eff->double_sided) {
+ if (dot_v3v3(vec, world_near_no) < 0.0f) {
+ dist = -dist;
+ inside = true;
+ }
+ }
+ }
+
+ if (r_vec) copy_v3_v3(r_vec, vec);
+ if (r_nor) copy_v3_v3(r_nor, world_near_no);
+ if (r_dist) *r_dist = dist;
+ if (r_inside) *r_inside = inside;
+
+ if (r_tessface && eff->dm) {
+ CacheEffectorTessfaceData *t = r_tessface;
+ DerivedMesh *dm = eff->dm;
+ MFace *mf = dm->getTessFaceArray(dm) + nearest.index;
+ MVert *mverts = dm->getVertArray(dm);
+
+ t->face_index = nearest.index;
+ t->mface = mf;
+ t->mvert[0] = &mverts[mf->v1];
+ t->mvert[1] = &mverts[mf->v2];
+ t->mvert[2] = &mverts[mf->v3];
+
+ if (mf->v4) {
+ t->mvert[3] = &mverts[mf->v4];
+ interp_weights_face_v3(t->weight, t->mvert[0]->co, t->mvert[1]->co, t->mvert[2]->co, t->mvert[3]->co, nearest.co);
+ }
+ else {
+ t->mvert[3] = NULL;
+ interp_weights_face_v3(t->weight, t->mvert[0]->co, t->mvert[1]->co, t->mvert[2]->co, NULL, nearest.co);
+ }
+ }
+
+ return true;
+}
+
+static bool cache_effector_deflect(CacheEffector *eff, CacheEffectorInstance *inst, CacheEffectorPoint *point, CacheEffectorResult *result)
+{
+ float vec[3], dist, falloff;
+ bool inside;
+
+ if (!cache_effector_find_nearest(eff, inst, point, vec, NULL, &dist, &inside, NULL))
+ return false;
+ if (!cache_effector_falloff(eff, dist, &falloff))
+ return false;
+
+ mul_v3_v3fl(result->f, vec, eff->strength * falloff);
+ if (inside)
+ negate_v3(result->f);
+ return true;
+}
+
+static bool cache_effector_drag(CacheEffector *eff, CacheEffectorInstance *inst, CacheEffectorPoint *point, CacheEffectorResult *result)
+{
+ float vec[3], dist, vel[3];
+ float falloff;
+ CacheEffectorTessfaceData facedata;
+
+ if (!cache_effector_find_nearest(eff, inst, point, vec, NULL, &dist, NULL, &facedata))
+ return false;
+ if (!cache_effector_falloff(eff, dist, &falloff))
+ return false;
+
+ cache_effector_velocity(eff, inst, &facedata, vel);
+
+ /* relative velocity */
+ sub_v3_v3v3(vel, point->v, vel);
+
+ mul_v3_v3fl(result->f, vel, -eff->strength * falloff);
+
+ return true;
+}
+
+static void cache_effector_result_init(CacheEffectorResult *result)
+{
+ zero_v3(result->f);
+}
+
+static void cache_effector_result_add(CacheEffectorResult *result, const CacheEffectorResult *other)
+{
+ add_v3_v3(result->f, other->f);
+}
+
+int BKE_cache_effectors_eval_ex(CacheEffector *effectors, int tot, CacheEffectorPoint *point, CacheEffectorResult *result,
+ bool (*filter)(void *, CacheEffector *), void *filter_data)
+{
+ CacheEffector *eff;
+ int i, applied = 0;
+
+ cache_effector_result_init(result);
+
+ for (i = 0, eff = effectors; i < tot; ++i, ++eff) {
+ const eCacheEffector_Type type = eff->type;
+ CacheEffectorInstance *inst;
+
+ for (inst = eff->instances.first; inst; inst = inst->next) {
+ CacheEffectorResult inst_result;
+ cache_effector_result_init(&inst_result);
+
+ if (filter && !filter(filter_data, eff))
+ continue;
+
+ switch (type) {
+ case eCacheEffector_Type_Deflect:
+ if (cache_effector_deflect(eff, inst, point, &inst_result)) {
+ cache_effector_result_add(result, &inst_result);
+ ++applied;
+ }
+ break;
+ case eCacheEffector_Type_Drag:
+ if (cache_effector_drag(eff, inst, point, &inst_result)) {
+ cache_effector_result_add(result, &inst_result);
+ ++applied;
+ }
+ break;
+ }
+ }
+ }
+
+ return applied;
+}
+
+int BKE_cache_effectors_eval(CacheEffector *effectors, int tot, CacheEffectorPoint *point, CacheEffectorResult *result)
+{
+ return BKE_cache_effectors_eval_ex(effectors, tot, point, result, NULL, NULL);
+}
+
+/* ========================================================================= */
+
+bool BKE_cache_modifier_find_object(DupliCache *dupcache, Object *ob, DupliObjectData **r_data)
+{
+ DupliObjectData *dobdata;
+
+ if (!ob)
+ return false;
+ dobdata = BKE_dupli_cache_find_data(dupcache, ob);
+ if (!dobdata)
+ return false;
+
+ if (r_data) *r_data = dobdata;
+ return true;
+}
+
+bool BKE_cache_modifier_find_strands(DupliCache *dupcache, Object *ob, int hair_system, DupliObjectData **r_data, Strands **r_strands, StrandsChildren **r_children, const char **r_name)
+{
+ DupliObjectData *dobdata;
+ ParticleSystem *psys;
+ DupliObjectDataStrands *link;
+ Strands *strands;
+ StrandsChildren *children;
+
+ if (!ob)
+ return false;
+ dobdata = BKE_dupli_cache_find_data(dupcache, ob);
+ if (!dobdata)
+ return false;
+
+ psys = BLI_findlink(&ob->particlesystem, hair_system);
+ if (!psys || (psys->part->type != PART_HAIR))
+ return false;
+
+ strands = NULL;
+ children = NULL;
+ for (link = dobdata->strands.first; link; link = link->next) {
+ if (link->strands && STREQ(link->name, psys->name)) {
+ strands = link->strands;
+ children = link->strands_children;
+ break;
+ }
+ }
+ if ((r_strands && !strands) || (r_children && !children))
+ return false;
+
+ if (r_data) *r_data = dobdata;
+ if (r_strands) *r_strands = strands;
+ if (r_children) *r_children = children;
+ if (r_name) *r_name = psys->name;
+ return true;
+}
+
+static void hairsim_params_init(HairSimParams *params)
+{
+ params->timescale = 1.0f;
+ params->substeps = 5;
+
+ params->mass = 0.3f;
+ params->drag = 0.1f;
+
+ params->stretch_stiffness = 10000.0f;
+ params->stretch_damping = 0.1f;
+ params->bend_stiffness = 100.0f;
+ params->bend_damping = 1.0f;
+ params->goal_stiffness = 0.0f;
+ params->goal_damping = 1.0f;
+ {
+ CurveMapping *cm = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ cm->cm[0].curve[0].x = 0.0f;
+ cm->cm[0].curve[0].y = 1.0f;
+ cm->cm[0].curve[1].x = 1.0f;
+ cm->cm[0].curve[1].y = 0.0f;
+ curvemapping_changed_all(cm);
+ params->goal_stiffness_mapping = cm;
+ }
+ {
+ CurveMapping *cm = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ cm->cm[0].curve[0].x = 0.0f;
+ cm->cm[0].curve[0].y = 1.0f;
+ cm->cm[0].curve[1].x = 1.0f;
+ cm->cm[0].curve[1].y = 1.0f;
+ curvemapping_changed_all(cm);
+ params->bend_stiffness_mapping = cm;
+ }
+
+ params->effector_weights = BKE_add_effector_weights(NULL);
+}
+
+static void hairsim_init(HairSimCacheModifier *hsmd)
+{
+ hsmd->object = NULL;
+ hsmd->hair_system = -1;
+
+ hairsim_params_init(&hsmd->sim_params);
+}
+
+static void hairsim_copy(HairSimCacheModifier *hsmd, HairSimCacheModifier *thsmd)
+{
+ if (hsmd->sim_params.effector_weights)
+ thsmd->sim_params.effector_weights = MEM_dupallocN(hsmd->sim_params.effector_weights);
+ if (hsmd->sim_params.goal_stiffness_mapping)
+ thsmd->sim_params.goal_stiffness_mapping = curvemapping_copy(hsmd->sim_params.goal_stiffness_mapping);
+ if (hsmd->sim_params.bend_stiffness_mapping)
+ thsmd->sim_params.bend_stiffness_mapping = curvemapping_copy(hsmd->sim_params.bend_stiffness_mapping);
+}
+
+static void hairsim_free(HairSimCacheModifier *hsmd)
+{
+ if (hsmd->sim_params.effector_weights)
+ MEM_freeN(hsmd->sim_params.effector_weights);
+ if (hsmd->sim_params.goal_stiffness_mapping)
+ curvemapping_free(hsmd->sim_params.goal_stiffness_mapping);
+ if (hsmd->sim_params.bend_stiffness_mapping)
+ curvemapping_free(hsmd->sim_params.bend_stiffness_mapping);
+}
+
+static void hairsim_foreach_id_link(HairSimCacheModifier *hsmd, CacheLibrary *cachelib, CacheModifier_IDWalkFunc walk, void *userdata)
+{
+ walk(userdata, cachelib, &hsmd->modifier, (ID **)(&hsmd->object));
+ if (hsmd->sim_params.effector_weights)
+ walk(userdata, cachelib, &hsmd->modifier, (ID **)(&hsmd->sim_params.effector_weights->group));
+}
+
+static void hairsim_process(HairSimCacheModifier *hsmd, CacheProcessContext *ctx, CacheProcessData *data, int frame, int frame_prev, int process_flag)
+{
+#define MAX_CACHE_EFFECTORS 64
+
+ Object *ob = hsmd->object;
+ Strands *strands;
+ float mat[4][4];
+ ListBase *effectors;
+ CacheEffector cache_effectors[MAX_CACHE_EFFECTORS];
+ int tot_cache_effectors;
+ struct Implicit_Data *solver_data;
+
+ /* only applies to parent strands */
+ if (!(process_flag & eCacheProcessFlag_DoStrands))
+ return;
+
+ if (!BKE_cache_modifier_find_strands(data->dupcache, ob, hsmd->hair_system, NULL, &strands, NULL, NULL))
+ return;
+
+ /* Note: motion state data should always be created regardless of actual sim.
+ * This is necessary so the cache writer actually writes the first (empty) sample
+ * and the samples get mapped correctly to frames when reading.
+ */
+ BKE_strands_add_motion_state(strands);
+
+ /* skip first step and potential backward steps */
+ if (frame > frame_prev) {
+ if (hsmd->sim_params.flag & eHairSimParams_Flag_UseGoalStiffnessCurve && hsmd->sim_params.goal_stiffness_mapping)
+ curvemapping_changed_all(hsmd->sim_params.goal_stiffness_mapping);
+ if (hsmd->sim_params.flag & eHairSimParams_Flag_UseBendStiffnessCurve && hsmd->sim_params.bend_stiffness_mapping)
+ curvemapping_changed_all(hsmd->sim_params.bend_stiffness_mapping);
+
+ if (ob)
+ mul_m4_m4m4(mat, data->mat, ob->obmat);
+ else
+ copy_m4_m4(mat, data->mat);
+
+ BKE_cache_effector_velocity_update(ctx->cachelib, data->dupcache, data->mat, (float)frame);
+
+ solver_data = BPH_strands_solver_create(strands, &hsmd->sim_params);
+ effectors = pdInitEffectors_ex(ctx->scene, ob, NULL, data->lay, hsmd->sim_params.effector_weights, true);
+ tot_cache_effectors = BKE_cache_effectors_get(cache_effectors, MAX_CACHE_EFFECTORS, ctx->cachelib, data->dupcache, data->mat);
+
+ BPH_strands_solve(strands, mat, solver_data, &hsmd->sim_params, (float)frame, (float)frame_prev, ctx->scene, effectors, cache_effectors, tot_cache_effectors);
+
+ pdEndEffectors(&effectors);
+ BKE_cache_effectors_free(cache_effectors, tot_cache_effectors);
+ BPH_mass_spring_solver_free(solver_data);
+ }
+
+#undef MAX_CACHE_EFFECTORS
+}
+
+CacheModifierTypeInfo cacheModifierType_HairSimulation = {
+ /* name */ "HairSimulation",
+ /* structName */ "HairSimCacheModifier",
+ /* structSize */ sizeof(HairSimCacheModifier),
+
+ /* copy */ (CacheModifier_CopyFunc)hairsim_copy,
+ /* foreachIDLink */ (CacheModifier_ForeachIDLinkFunc)hairsim_foreach_id_link,
+ /* process */ (CacheModifier_ProcessFunc)hairsim_process,
+ /* init */ (CacheModifier_InitFunc)hairsim_init,
+ /* free */ (CacheModifier_FreeFunc)hairsim_free,
+};
+
+/* ------------------------------------------------------------------------- */
+
+static ForceFieldVertexCache *forcefield_vertex_cache_new(void)
+{
+ ForceFieldVertexCache *cache = MEM_callocN(sizeof(ForceFieldVertexCache), "force field vertex cache");
+ return cache;
+}
+
+static void forcefield_vertex_cache_free(ForceFieldVertexCache *cache)
+{
+ if (cache->co_prev)
+ MEM_freeN(cache->co_prev);
+ if (cache->vel)
+ MEM_freeN(cache->vel);
+ MEM_freeN(cache);
+}
+
+static void forcefield_vertex_cache_clear(ForceFieldVertexCache *cache)
+{
+ if (cache->co_prev)
+ MEM_freeN(cache->co_prev);
+ if (cache->vel)
+ MEM_freeN(cache->vel);
+ memset(cache, 0, sizeof(ForceFieldVertexCache));
+}
+
+static void forcefield_vertex_cache_init(ForceFieldVertexCache *cache, float frame, DerivedMesh *dm)
+{
+ MVert *mvert = dm->getVertArray(dm);
+ float dframe = frame - cache->frame_prev;
+ float inv_dframe = dframe > 0.0f ? 1.0f / dframe : 0.0f;
+ bool has_co_prev = (cache->co_prev != NULL);
+ int totvert = dm->getNumVerts(dm);
+ int i;
+
+ if (cache->totvert != totvert) {
+ forcefield_vertex_cache_clear(cache);
+ dframe = 0.0f;
+ }
+
+ if (!cache->co_prev)
+ cache->co_prev = MEM_mallocN(sizeof(float) * 3 * totvert, "force field vertex cache vertices");
+ if (!cache->vel)
+ cache->vel = MEM_mallocN(sizeof(float) * 3 * totvert, "force field vertex cache vertices");
+
+ for (i = 0; i < totvert; ++i) {
+ if (has_co_prev) {
+ sub_v3_v3v3(cache->vel[i], mvert[i].co, cache->co_prev[i]);
+ mul_v3_fl(cache->vel[i], inv_dframe);
+ }
+ else {
+ zero_v3(cache->vel[i]);
+ }
+
+ copy_v3_v3(cache->co_prev[i], mvert[i].co);
+ }
+ cache->frame_prev = frame;
+ cache->totvert = totvert;
+}
+
+static void forcefield_init(ForceFieldCacheModifier *ffmd)
+{
+ ffmd->object = NULL;
+
+ ffmd->vertex_cache = NULL;
+
+ ffmd->strength = 0.0f;
+ ffmd->falloff = 1.0f;
+ ffmd->min_distance = 0.0f;
+ ffmd->max_distance = 1.0f;
+}
+
+static void forcefield_copy(ForceFieldCacheModifier *UNUSED(ffmd), ForceFieldCacheModifier *tffmd)
+{
+ tffmd->vertex_cache = NULL;
+}
+
+static void forcefield_free(ForceFieldCacheModifier *ffmd)
+{
+ if (ffmd->vertex_cache) {
+ forcefield_vertex_cache_free(ffmd->vertex_cache);
+ ffmd->vertex_cache = NULL;
+ }
+}
+
+static void forcefield_foreach_id_link(ForceFieldCacheModifier *ffmd, CacheLibrary *cachelib, CacheModifier_IDWalkFunc walk, void *userdata)
+{
+ walk(userdata, cachelib, &ffmd->modifier, (ID **)(&ffmd->object));
+}
+
+CacheModifierTypeInfo cacheModifierType_ForceField = {
+ /* name */ "ForceField",
+ /* structName */ "ForceFieldCacheModifier",
+ /* structSize */ sizeof(ForceFieldCacheModifier),
+
+ /* copy */ (CacheModifier_CopyFunc)forcefield_copy,
+ /* foreachIDLink */ (CacheModifier_ForeachIDLinkFunc)forcefield_foreach_id_link,
+ /* process */ (CacheModifier_ProcessFunc)NULL,
+ /* init */ (CacheModifier_InitFunc)forcefield_init,
+ /* free */ (CacheModifier_FreeFunc)forcefield_free,
+};
+
+/* ------------------------------------------------------------------------- */
+
+static void shrinkwrap_init(ShrinkWrapCacheModifier *smd)
+{
+ smd->object = NULL;
+ smd->hair_system = -1;
+}
+
+static void shrinkwrap_copy(ShrinkWrapCacheModifier *UNUSED(smd), ShrinkWrapCacheModifier *UNUSED(tsmd))
+{
+}
+
+static void shrinkwrap_free(ShrinkWrapCacheModifier *UNUSED(smd))
+{
+}
+
+static void shrinkwrap_foreach_id_link(ShrinkWrapCacheModifier *smd, CacheLibrary *cachelib, CacheModifier_IDWalkFunc walk, void *userdata)
+{
+ walk(userdata, cachelib, &smd->modifier, (ID **)(&smd->object));
+ walk(userdata, cachelib, &smd->modifier, (ID **)(&smd->target));
+}
+
+typedef struct ShrinkWrapCacheData {
+ DerivedMesh *dm;
+ BVHTreeFromMesh treedata;
+
+ ListBase instances;
+} ShrinkWrapCacheData;
+
+typedef struct ShrinkWrapCacheInstance {
+ struct ShrinkWrapCacheInstance *next, *prev;
+
+ float mat[4][4];
+ float imat[4][4];
+} ShrinkWrapCacheInstance;
+
+static void shrinkwrap_data_get_bvhtree(ShrinkWrapCacheData *data, DerivedMesh *dm, bool create_bvhtree)
+{
+ data->dm = CDDM_copy(dm);
+ if (!data->dm)
+ return;
+
+ DM_ensure_tessface(data->dm);
+ CDDM_calc_normals(data->dm);
+
+ if (create_bvhtree) {
+ bvhtree_from_mesh_faces(&data->treedata, data->dm, 0.0, 2, 6);
+ }
+}
+
+static void shrinkwrap_data_get_instances(ShrinkWrapCacheData *data, Object *ob, float obmat[4][4], ListBase *duplilist)
+{
+ if (duplilist) {
+ DupliObject *dob;
+
+ for (dob = duplilist->first; dob; dob = dob->next) {
+ ShrinkWrapCacheInstance *inst;
+
+ if (dob->ob != ob)
+ continue;
+
+ inst = MEM_callocN(sizeof(ShrinkWrapCacheInstance), "shrink wrap instance");
+ mul_m4_m4m4(inst->mat, obmat, dob->mat);
+ invert_m4_m4(inst->imat, inst->mat);
+
+ BLI_addtail(&data->instances, inst);
+ }
+ }
+ else {
+ ShrinkWrapCacheInstance *inst = MEM_callocN(sizeof(ShrinkWrapCacheInstance), "shrink wrap instance");
+ mul_m4_m4m4(inst->mat, obmat, ob->obmat);
+ invert_m4_m4(inst->imat, inst->mat);
+
+ BLI_addtail(&data->instances, inst);
+ }
+}
+
+static void shrinkwrap_data_free(ShrinkWrapCacheData *data)
+{
+ BLI_freelistN(&data->instances);
+
+ free_bvhtree_from_mesh(&data->treedata);
+
+ if (data->dm) {
+ data->dm->release(data->dm);
+ }
+}
+
+static void shrinkwrap_apply_vertex(ShrinkWrapCacheModifier *UNUSED(smd), ShrinkWrapCacheData *data, ShrinkWrapCacheInstance *inst, const float *point, float *out)
+{
+ BVHTreeNearest nearest = {0, };
+ float co[3], near_co[3], near_no[3];
+
+ if (!data->treedata.tree)
+ return;
+
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+
+ /* lookup in target space */
+ mul_v3_m4v3(co, inst->imat, point);
+
+ BLI_bvhtree_find_nearest(data->treedata.tree, co, &nearest, data->treedata.nearest_callback, &data->treedata);
+ if (nearest.index < 0)
+ return;
+
+ /* convert back to world space */
+ mul_v3_m4v3(near_co, inst->mat, nearest.co);
+ copy_v3_v3(near_no, nearest.no);
+ mul_mat3_m4_v3(inst->mat, near_no);
+
+ {
+ float vec[3];
+
+ sub_v3_v3v3(vec, point, near_co);
+
+ /* project along the distance vector */
+ if (dot_v3v3(vec, near_no) < 0.0f) {
+ copy_v3_v3(out, near_co);
+ }
+ }
+}
+
+static void shrinkwrap_apply(ShrinkWrapCacheModifier *smd, ShrinkWrapCacheData *data, Strands *strands, StrandsChildren *children, bool do_motion)
+{
+ /* XXX this is not great, the result depends on order of instances in the duplilist ...
+ * but good enough for single instance use case.
+ */
+ ShrinkWrapCacheInstance *inst;
+ for (inst = data->instances.first; inst; inst = inst->next) {
+
+ if (strands) {
+ StrandIterator it_strand;
+ for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+ StrandVertexIterator it_vert;
+ for (BKE_strand_vertex_iter_init(&it_vert, &it_strand); BKE_strand_vertex_iter_valid(&it_vert); BKE_strand_vertex_iter_next(&it_vert)) {
+ if (do_motion && strands->state)
+ shrinkwrap_apply_vertex(smd, data, inst, it_vert.state->co, it_vert.state->co);
+ else
+ shrinkwrap_apply_vertex(smd, data, inst, it_vert.vertex->co, it_vert.vertex->co);
+ }
+ }
+ }
+
+ if (children) {
+ StrandChildIterator it_strand;
+ for (BKE_strand_child_iter_init(&it_strand, children); BKE_strand_child_iter_valid(&it_strand); BKE_strand_child_iter_next(&it_strand)) {
+ StrandChildVertexIterator it_vert;
+ for (BKE_strand_child_vertex_iter_init(&it_vert, &it_strand); BKE_strand_child_vertex_iter_valid(&it_vert); BKE_strand_child_vertex_iter_next(&it_vert)) {
+ shrinkwrap_apply_vertex(smd, data, inst, it_vert.vertex->co, it_vert.vertex->co);
+ }
+ }
+ }
+ }
+}
+
+static void shrinkwrap_process(ShrinkWrapCacheModifier *smd, CacheProcessContext *ctx, CacheProcessData *data, int UNUSED(frame), int UNUSED(frame_prev), int process_flag)
+{
+ bool do_strands_motion = true;
+
+ const bool dupli_target = smd->flag & eShrinkWrapCacheModifier_Flag_InternalTarget;
+ Object *ob = smd->object;
+ DupliObject *dob;
+ Strands *strands = NULL;
+ DerivedMesh *target_dm;
+ float mat[4][4];
+
+ ShrinkWrapCacheData shrinkwrap;
+
+ /* only applies to parent strands */
+ if (!(process_flag & eCacheProcessFlag_DoStrands))
+ return;
+
+ if (!BKE_cache_modifier_find_strands(data->dupcache, ob, smd->hair_system, NULL, &strands, NULL, NULL))
+ return;
+
+ if (dupli_target) {
+ DupliObjectData *target_data;
+ if (!BKE_cache_modifier_find_object(data->dupcache, smd->target, &target_data))
+ return;
+ target_dm = target_data->dm;
+ }
+ else {
+ if (!smd->target)
+ return;
+ target_dm = mesh_get_derived_final(ctx->scene, smd->target, CD_MASK_BAREMESH);
+ }
+
+ for (dob = data->dupcache->duplilist.first; dob; dob = dob->next) {
+ if (dob->ob != ob)
+ continue;
+
+ memset(&shrinkwrap, 0, sizeof(shrinkwrap));
+ shrinkwrap_data_get_bvhtree(&shrinkwrap, target_dm, true);
+
+ if (dupli_target) {
+ /* instances are calculated relative to the strands object */
+ invert_m4_m4(mat, dob->mat);
+ shrinkwrap_data_get_instances(&shrinkwrap, smd->target, mat, &data->dupcache->duplilist);
+ }
+ else {
+ /* instances are calculated relative to the strands object */
+ mul_m4_m4m4(mat, data->mat, dob->mat);
+ invert_m4(mat);
+ shrinkwrap_data_get_instances(&shrinkwrap, smd->target, mat, NULL);
+ }
+
+ shrinkwrap_apply(smd, &shrinkwrap, strands, NULL, do_strands_motion);
+
+ shrinkwrap_data_free(&shrinkwrap);
+
+ /* XXX assume a single instance ... otherwise would just overwrite previous strands data */
+ break;
+ }
+}
+
+CacheModifierTypeInfo cacheModifierType_ShrinkWrap = {
+ /* name */ "ShrinkWrap",
+ /* structName */ "ShrinkWrapCacheModifier",
+ /* structSize */ sizeof(ShrinkWrapCacheModifier),
+
+ /* copy */ (CacheModifier_CopyFunc)shrinkwrap_copy,
+ /* foreachIDLink */ (CacheModifier_ForeachIDLinkFunc)shrinkwrap_foreach_id_link,
+ /* process */ (CacheModifier_ProcessFunc)shrinkwrap_process,
+ /* init */ (CacheModifier_InitFunc)shrinkwrap_init,
+ /* free */ (CacheModifier_FreeFunc)shrinkwrap_free,
+};
+
+/* ------------------------------------------------------------------------- */
+
+static void strandskey_init(StrandsKeyCacheModifier *skmd)
+{
+ skmd->object = NULL;
+ skmd->hair_system = -1;
+
+ skmd->key = BKE_key_add_ex(NULL, KEY_OWNER_CACHELIB, -1);
+ skmd->key->type = KEY_RELATIVE;
+}
+
+static void strandskey_copy(StrandsKeyCacheModifier *skmd, StrandsKeyCacheModifier *tskmd)
+{
+ tskmd->key = BKE_key_copy(skmd->key);
+
+ tskmd->edit = NULL;
+}
+
+static void strandskey_free(StrandsKeyCacheModifier *skmd)
+{
+ BKE_key_free(skmd->key);
+
+ if (skmd->edit) {
+ BKE_editstrands_free(skmd->edit);
+ MEM_freeN(skmd->edit);
+ skmd->edit = NULL;
+ }
+}
+
+static void strandskey_foreach_id_link(StrandsKeyCacheModifier *skmd, CacheLibrary *cachelib, CacheModifier_IDWalkFunc walk, void *userdata)
+{
+ walk(userdata, cachelib, &skmd->modifier, (ID **)(&skmd->object));
+}
+
+static void strandskey_process(StrandsKeyCacheModifier *skmd, CacheProcessContext *UNUSED(ctx), CacheProcessData *data, int UNUSED(frame), int UNUSED(frame_prev), int process_flag)
+{
+ const bool use_motion = skmd->flag & eStrandsKeyCacheModifier_Flag_UseMotionState;
+ Object *ob = skmd->object;
+ Strands *strands;
+ KeyBlock *actkb;
+ float *shape;
+
+ /* only applies to parents */
+ if (!(process_flag & eCacheProcessFlag_DoStrands))
+ return;
+ if (!BKE_cache_modifier_find_strands(data->dupcache, ob, skmd->hair_system, NULL, &strands, NULL, NULL))
+ return;
+ if (use_motion && !strands->state)
+ return;
+
+ actkb = BLI_findlink(&skmd->key->block, skmd->shapenr);
+ shape = BKE_key_evaluate_strands(strands, skmd->key, actkb, skmd->flag & eStrandsKeyCacheModifier_Flag_ShapeLock, NULL, use_motion);
+ if (shape) {
+ StrandsVertex *vert = strands->verts;
+ StrandsMotionState *state = use_motion ? strands->state : NULL;
+ int totvert = strands->totverts;
+ int i;
+
+ float *fp = shape;
+ for (i = 0; i < totvert; ++i) {
+ if (state) {
+ copy_v3_v3(state->co, fp);
+ ++state;
+ }
+ else {
+ copy_v3_v3(vert->co, fp);
+ ++vert;
+ }
+ fp += 3;
+ }
+
+ MEM_freeN(shape);
+ }
+}
+
+CacheModifierTypeInfo cacheModifierType_StrandsKey = {
+ /* name */ "StrandsKey",
+ /* structName */ "StrandsKeyCacheModifier",
+ /* structSize */ sizeof(StrandsKeyCacheModifier),
+
+ /* copy */ (CacheModifier_CopyFunc)strandskey_copy,
+ /* foreachIDLink */ (CacheModifier_ForeachIDLinkFunc)strandskey_foreach_id_link,
+ /* process */ (CacheModifier_ProcessFunc)strandskey_process,
+ /* init */ (CacheModifier_InitFunc)strandskey_init,
+ /* free */ (CacheModifier_FreeFunc)strandskey_free,
+};
+
+KeyBlock *BKE_cache_modifier_strands_key_insert_key(StrandsKeyCacheModifier *skmd, Strands *strands, const char *name, const bool from_mix)
+{
+ const bool use_motion = skmd->flag & eStrandsKeyCacheModifier_Flag_UseMotionState;
+ Key *key = skmd->key;
+ KeyBlock *kb;
+ bool newkey = false;
+
+ if (key == NULL) {
+ key = skmd->key = BKE_key_add_ex(NULL, KEY_OWNER_CACHELIB, -1);
+ key->type = KEY_RELATIVE;
+ newkey = true;
+ }
+ else if (BLI_listbase_is_empty(&key->block)) {
+ newkey = true;
+ }
+
+ if (newkey || from_mix == false) {
+ /* create from mesh */
+ kb = BKE_keyblock_add_ctime(key, name, false);
+ BKE_keyblock_convert_from_strands(strands, key, kb, use_motion);
+ }
+ else {
+ /* copy from current values */
+ KeyBlock *actkb = BLI_findlink(&skmd->key->block, skmd->shapenr);
+ bool shape_lock = skmd->flag & eStrandsKeyCacheModifier_Flag_ShapeLock;
+ int totelem;
+ float *data = BKE_key_evaluate_strands(strands, key, actkb, shape_lock, &totelem, use_motion);
+
+ /* create new block with prepared data */
+ kb = BKE_keyblock_add_ctime(key, name, false);
+ kb->data = data;
+ kb->totelem = totelem;
+ }
+
+ return kb;
+}
+
+bool BKE_cache_modifier_strands_key_get(Object *ob, StrandsKeyCacheModifier **r_skmd, DerivedMesh **r_dm, Strands **r_strands, DupliObjectData **r_dobdata, const char **r_name, float r_mat[4][4])
+{
+ CacheLibrary *cachelib = ob->cache_library;
+ CacheModifier *md;
+
+ if (!cachelib)
+ return false;
+
+ /* ignore when the object is not actually using the cachelib */
+ if (!((ob->transflag & OB_DUPLIGROUP) && ob->dup_group && ob->dup_cache))
+ return false;
+
+ for (md = cachelib->modifiers.first; md; md = md->next) {
+ if (md->type == eCacheModifierType_StrandsKey) {
+ StrandsKeyCacheModifier *skmd = (StrandsKeyCacheModifier *)md;
+ DupliObjectData *dobdata;
+
+ if (BKE_cache_modifier_find_strands(ob->dup_cache, skmd->object, skmd->hair_system, &dobdata, r_strands, NULL, r_name)) {
+ if (r_skmd) *r_skmd = skmd;
+ if (r_dm) *r_dm = dobdata->dm;
+ if (r_dobdata) *r_dobdata = dobdata;
+
+ /* relative transform from the original hair object to the duplicator local space */
+ /* XXX bad hack, common problem: we want to display strand edit data in the place of "the" instance,
+ * but in fact there can be multiple instances of the same dupli object data, so this is ambiguous ...
+ * For our basic use case, just pick the first dupli instance, assuming that it's the only one.
+ * ugh ...
+ */
+ if (r_mat) {
+ DupliObject *dob;
+ for (dob = ob->dup_cache->duplilist.first; dob; dob = dob->next) {
+ if (dob->ob == skmd->object)
+ break;
+ }
+ if (dob) {
+ /* note: plain duplis from the dupli cache list are relative
+ * to the duplicator already! (not in world space like final duplis)
+ */
+ copy_m4_m4(r_mat, dob->mat);
+ }
+ else
+ unit_m4(r_mat);
+ }
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void haircut_init(HaircutCacheModifier *hmd)
+{
+ hmd->object = NULL;
+ hmd->hair_system = -1;
+}
+
+static void haircut_copy(HaircutCacheModifier *UNUSED(hmd), HaircutCacheModifier *UNUSED(thmd))
+{
+}
+
+static void haircut_free(HaircutCacheModifier *UNUSED(hmd))
+{
+}
+
+static void haircut_foreach_id_link(HaircutCacheModifier *smd, CacheLibrary *cachelib, CacheModifier_IDWalkFunc walk, void *userdata)
+{
+ walk(userdata, cachelib, &smd->modifier, (ID **)(&smd->object));
+ walk(userdata, cachelib, &smd->modifier, (ID **)(&smd->target));
+}
+
+typedef struct HaircutCacheData {
+ DerivedMesh *dm;
+ BVHTreeFromMesh treedata;
+
+ ListBase instances;
+} HaircutCacheData;
+
+typedef struct HaircutCacheInstance {
+ struct HaircutCacheInstance *next, *prev;
+
+ float mat[4][4];
+ float imat[4][4];
+} HaircutCacheInstance;
+
+static void haircut_data_get_bvhtree(HaircutCacheData *data, DerivedMesh *dm, bool create_bvhtree)
+{
+ data->dm = CDDM_copy(dm);
+ if (!data->dm)
+ return;
+
+ DM_ensure_tessface(data->dm);
+ CDDM_calc_normals(data->dm);
+
+ if (create_bvhtree) {
+ bvhtree_from_mesh_faces(&data->treedata, data->dm, 0.0, 2, 6);
+ }
+}
+
+static void haircut_data_get_instances(HaircutCacheData *data, Object *ob, float obmat[4][4], ListBase *duplilist)
+{
+ if (duplilist) {
+ DupliObject *dob;
+
+ for (dob = duplilist->first; dob; dob = dob->next) {
+ HaircutCacheInstance *inst;
+
+ if (dob->ob != ob)
+ continue;
+
+ inst = MEM_callocN(sizeof(HaircutCacheInstance), "haircut instance");
+ mul_m4_m4m4(inst->mat, obmat, dob->mat);
+ invert_m4_m4(inst->imat, inst->mat);
+
+ BLI_addtail(&data->instances, inst);
+ }
+ }
+ else {
+ HaircutCacheInstance *inst = MEM_callocN(sizeof(HaircutCacheInstance), "haircut instance");
+ mul_m4_m4m4(inst->mat, obmat, ob->obmat);
+ invert_m4_m4(inst->imat, inst->mat);
+
+ BLI_addtail(&data->instances, inst);
+ }
+}
+
+static void haircut_data_free(HaircutCacheData *data)
+{
+ BLI_freelistN(&data->instances);
+
+ free_bvhtree_from_mesh(&data->treedata);
+
+ if (data->dm) {
+ data->dm->release(data->dm);
+ }
+}
+
+/* XXX intersection counting does not work reliably */
+#if 0
+typedef struct PointInsideBVH {
+ BVHTreeFromMesh bvhdata;
+ int num_hits;
+} PointInsideBVH;
+
+static void point_inside_bvh_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+{
+ PointInsideBVH *data = userdata;
+
+ data->bvhdata.raycast_callback(&data->bvhdata, index, ray, hit);
+
+ if (hit->index != -1)
+ ++data->num_hits;
+}
+
+/* true if the point is inside the target mesh */
+static bool haircut_test_point(HaircutCacheModifier *hmd, HaircutCacheData *data, HaircutCacheInstance *inst, const float *v)
+{
+ const float dir[3] = {1.0f, 0.0f, 0.0f};
+ float start[3];
+ PointInsideBVH userdata;
+
+ if (!(hmd->cut_mode & eHaircutCacheModifier_CutMode_Enter))
+ return false;
+
+ userdata.bvhdata = data->treedata;
+ userdata.num_hits = 0;
+
+ /* lookup in target space */
+ mul_v3_m4v3(start, inst->imat, v);
+
+ BLI_bvhtree_ray_cast_all(data->treedata.tree, start, dir, 0.0f, point_inside_bvh_cb, &userdata);
+
+ /* for any point inside a watertight mesh the number of hits is uneven */
+ return (userdata.num_hits % 2) == 1;
+}
+#else
+/* true if the point is inside the target mesh */
+static bool haircut_test_point(HaircutCacheModifier *hmd, HaircutCacheData *data, HaircutCacheInstance *inst, const float *v)
+{
+ BVHTreeRayHit hit = {0, };
+ float start[3], dir[3] = {0.0f, 0.0f, 1.0f};
+ bool is_entering;
+
+ if (!(hmd->cut_mode & eHaircutCacheModifier_CutMode_Enter))
+ return false;
+ if (!data->treedata.tree)
+ return false;
+
+ /* lookup in target space */
+ mul_v3_m4v3(start, inst->imat, v);
+
+ hit.index = -1;
+ hit.dist = FLT_MAX;
+
+ BLI_bvhtree_ray_cast(data->treedata.tree, start, dir, 0.0f, &hit, data->treedata.raycast_callback, &data->treedata);
+ if (hit.index < 0) {
+ return false;
+ }
+
+ mul_mat3_m4_v3(inst->mat, hit.no);
+
+ is_entering = (dot_v3v3(dir, hit.no) < 0.0f);
+
+ return !is_entering;
+}
+#endif
+
+static bool haircut_find_segment_cut(HaircutCacheModifier *hmd, HaircutCacheData *data, HaircutCacheInstance *inst,
+ const float *v1, const float *v2, float *r_lambda)
+{
+ BVHTreeRayHit hit = {0, };
+ float start[3], dir[3], length;
+ bool is_entering;
+
+ if (!data->treedata.tree)
+ return false;
+
+ /* lookup in target space */
+ mul_v3_m4v3(start, inst->imat, v1);
+ sub_v3_v3v3(dir, v2, v1);
+ mul_mat3_m4_v3(inst->imat, dir);
+ length = normalize_v3(dir);
+
+ if (length == 0.0f)
+ return false;
+
+ hit.index = -1;
+ hit.dist = length;
+
+ BLI_bvhtree_ray_cast(data->treedata.tree, start, dir, 0.0f, &hit, data->treedata.raycast_callback, &data->treedata);
+ if (hit.index < 0)
+ return false;
+
+ is_entering = (dot_v3v3(dir, hit.no) < 0.0f);
+ if ((hmd->cut_mode & eHaircutCacheModifier_CutMode_Enter && is_entering) ||
+ (hmd->cut_mode & eHaircutCacheModifier_CutMode_Exit && !is_entering))
+ {
+ if (r_lambda) *r_lambda = len_v3v3(hit.co, start) / length;
+ return true;
+ }
+
+ return false;
+}
+
+static bool haircut_find_first_strand_cut(HaircutCacheModifier *hmd, HaircutCacheData *data, StrandChildIterator *it_strand, float *r_cutoff)
+{
+ StrandChildVertexIterator it_vert;
+ int vprev = -1;
+ float cutoff = 0.0f;
+
+ for (BKE_strand_child_vertex_iter_init(&it_vert, it_strand); BKE_strand_child_vertex_iter_valid(&it_vert); BKE_strand_child_vertex_iter_next(&it_vert)) {
+ StrandsChildVertex *verts = it_strand->verts;
+ bool found_cut = false;
+ float lambda_min = 1.0f;
+ HaircutCacheInstance *inst;
+
+ if (it_vert.index == 0) {
+ for (inst = data->instances.first; inst; inst = inst->next) {
+ /* test root vertex */
+ if (haircut_test_point(hmd, data, inst, verts[it_vert.index].co)) {
+ if (r_cutoff) *r_cutoff = 0.0f;
+ return true;
+ }
+ }
+ }
+ else {
+ for (inst = data->instances.first; inst; inst = inst->next) {
+ float lambda;
+ if (haircut_find_segment_cut(hmd, data, inst, verts[vprev].co, verts[it_vert.index].co, &lambda)) {
+ found_cut = true;
+ if (lambda < lambda_min)
+ lambda_min = lambda;
+ }
+ }
+
+ if (found_cut) {
+ cutoff += lambda_min;
+ if (r_cutoff) *r_cutoff = cutoff;
+ return true;
+ }
+ else
+ cutoff += 1.0f;
+ }
+
+ vprev = it_vert.index;
+ }
+
+ if (r_cutoff) *r_cutoff = -1.0f; /* indicates "no cutoff" */
+ return false;
+}
+
+/* shortens the last visible segment to have exact cutoff length */
+static void haircut_strand_adjust_tip(StrandChildIterator *it_strand, float cutoff)
+{
+ StrandsChildCurve *curve = it_strand->curve;
+
+ int last, end;
+ float *a, *b;
+ float t;
+
+ if (cutoff < 0 || cutoff >= (float)(curve->numverts-1))
+ return;
+
+ last = (int)cutoff;
+ end = last + 1;
+ BLI_assert(last < curve->numverts);
+ BLI_assert(end < curve->numverts);
+
+ a = it_strand->verts[last].co;
+ b = it_strand->verts[end].co;
+ t = cutoff - floorf(cutoff);
+ interp_v3_v3v3(b, a, b, t);
+}
+
+static void haircut_apply(HaircutCacheModifier *hmd, CacheProcessContext *UNUSED(ctx), HaircutCacheData *data, StrandsChildren *strands)
+{
+ StrandChildIterator it_strand;
+ for (BKE_strand_child_iter_init(&it_strand, strands); BKE_strand_child_iter_valid(&it_strand); BKE_strand_child_iter_next(&it_strand)) {
+ float cutoff = -1.0f;
+ if (haircut_find_first_strand_cut(hmd, data, &it_strand, &cutoff)) {
+ it_strand.curve->cutoff = cutoff;
+ haircut_strand_adjust_tip(&it_strand, cutoff);
+ }
+ }
+}
+
+static void haircut_process(HaircutCacheModifier *hmd, CacheProcessContext *ctx, CacheProcessData *data, int UNUSED(frame), int UNUSED(frame_prev), int process_flag)
+{
+ bool do_strands_children = (process_flag & eCacheProcessFlag_DoStrandsChildren);
+ const bool dupli_target = hmd->flag & eHaircutCacheModifier_Flag_InternalTarget;
+ Object *ob = hmd->object;
+ DupliObject *dob;
+ StrandsChildren *strands;
+ DerivedMesh *target_dm;
+ float mat[4][4];
+
+ HaircutCacheData haircut;
+
+ /* only applies to children */
+ if (!do_strands_children)
+ return;
+ if (!BKE_cache_modifier_find_strands(data->dupcache, ob, hmd->hair_system, NULL, NULL, do_strands_children ? &strands : NULL, NULL))
+ return;
+
+ if (dupli_target) {
+ DupliObjectData *target_data;
+ if (!BKE_cache_modifier_find_object(data->dupcache, hmd->target, &target_data))
+ return;
+ target_dm = target_data->dm;
+ }
+ else {
+ if (!hmd->target)
+ return;
+ target_dm = mesh_get_derived_final(ctx->scene, hmd->target, CD_MASK_BAREMESH);
+ }
+
+ for (dob = data->dupcache->duplilist.first; dob; dob = dob->next) {
+ if (dob->ob != ob)
+ continue;
+
+ memset(&haircut, 0, sizeof(haircut));
+ haircut_data_get_bvhtree(&haircut, target_dm, true);
+ if (dupli_target) {
+ /* instances are calculated relative to the strands object */
+ invert_m4_m4(mat, dob->mat);
+ haircut_data_get_instances(&haircut, hmd->target, mat, &data->dupcache->duplilist);
+ }
+ else {
+ /* instances are calculated relative to the strands object */
+ mul_m4_m4m4(mat, data->mat, dob->mat);
+ invert_m4(mat);
+ haircut_data_get_instances(&haircut, hmd->target, mat, NULL);
+ }
+
+ haircut_apply(hmd, ctx, &haircut, strands);
+
+ haircut_data_free(&haircut);
+
+ /* XXX assume a single instance ... otherwise would just overwrite previous strands data */
+ break;
+ }
+}
+
+CacheModifierTypeInfo cacheModifierType_Haircut = {
+ /* name */ "Haircut",
+ /* structName */ "HaircutCacheModifier",
+ /* structSize */ sizeof(HaircutCacheModifier),
+
+ /* copy */ (CacheModifier_CopyFunc)haircut_copy,
+ /* foreachIDLink */ (CacheModifier_ForeachIDLinkFunc)haircut_foreach_id_link,
+ /* process */ (CacheModifier_ProcessFunc)haircut_process,
+ /* init */ (CacheModifier_InitFunc)haircut_init,
+ /* free */ (CacheModifier_FreeFunc)haircut_free,
+};
+
+/* ------------------------------------------------------------------------- */
+
+bool BKE_cache_library_uses_key(CacheLibrary *cachelib, Key *key)
+{
+ CacheModifier *md;
+ for (md = cachelib->modifiers.first; md; md = md->next) {
+ if (md->type == eCacheModifierType_StrandsKey) {
+ StrandsKeyCacheModifier *skmd = (StrandsKeyCacheModifier *)md;
+ if (skmd->key == key)
+ return true;
+ }
+ }
+ return false;
+}
+
+void BKE_cache_modifier_init(void)
+{
+ cache_modifier_type_set(eCacheModifierType_HairSimulation, &cacheModifierType_HairSimulation);
+ cache_modifier_type_set(eCacheModifierType_ForceField, &cacheModifierType_ForceField);
+ cache_modifier_type_set(eCacheModifierType_ShrinkWrap, &cacheModifierType_ShrinkWrap);
+ cache_modifier_type_set(eCacheModifierType_StrandsKey, &cacheModifierType_StrandsKey);
+ cache_modifier_type_set(eCacheModifierType_Haircut, &cacheModifierType_Haircut);
+}
+
+/* ========================================================================= */
+
+#if 0
+static unsigned int hash_combine(unsigned int kx, unsigned int ky)
+{
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+ unsigned int a, b, c;
+
+ a = b = c = 0xdeadbeef + (2 << 2) + 13;
+ a += kx;
+ b += ky;
+
+ c ^= b; c -= rot(b,14);
+ a ^= c; a -= rot(c,11);
+ b ^= a; b -= rot(a,25);
+ c ^= b; c -= rot(b,16);
+ a ^= c; a -= rot(c,4);
+ b ^= a; b -= rot(a,14);
+ c ^= b; c -= rot(b,24);
+
+ return c;
+
+#undef rot
+}
+
+static unsigned int cache_archive_info_node_hash(const void *key)
+{
+ const CacheArchiveInfoNode *node = key;
+
+ unsigned int hash = hash_combine(BLI_ghashutil_strhash(node->name), BLI_ghashutil_inthash(node->type));
+ if (node->parent_hash != 0)
+ hash = hash_combine(hash, node->parent_hash);
+ return hash;
+}
+
+static bool cache_archive_info_node_cmp(const CacheArchiveInfoNode *a, const CacheArchiveInfoNode *b)
+{
+ if (a->parent_hash != b->parent_hash)
+ return true;
+ else if (a->type != b->type)
+ return true;
+ else if (!STREQ(a->name, b->name))
+ return true;
+ else
+ return false;
+}
+#endif
+
+static void cache_archive_info_node_free(CacheArchiveInfoNode *node)
+{
+ CacheArchiveInfoNode *child, *child_next;
+ for (child = node->child_nodes.first; child; child = child_next) {
+ child_next = child->next;
+ cache_archive_info_node_free(child);
+ }
+
+ MEM_freeN(node);
+}
+
+CacheArchiveInfo *BKE_cache_archive_info_new(void)
+{
+ CacheArchiveInfo *info = MEM_callocN(sizeof(CacheArchiveInfo), "cache archive info");
+
+ return info;
+}
+
+void BKE_cache_archive_info_free(CacheArchiveInfo *info)
+{
+ if (info) {
+ if (info->root_node)
+ cache_archive_info_node_free(info->root_node);
+
+ MEM_freeN(info);
+ }
+}
+
+void BKE_cache_archive_info_clear(CacheArchiveInfo *info)
+{
+ info->filepath[0] = '\0';
+ info->app_name[0] = '\0';
+ info->date_written[0] = '\0';
+ info->description[0] = '\0';
+
+ if (info->root_node) {
+ cache_archive_info_node_free(info->root_node);
+ info->root_node = NULL;
+ }
+}
+
+CacheArchiveInfoNode *BKE_cache_archive_info_find_node(CacheArchiveInfo *info, CacheArchiveInfoNode *parent,
+ eCacheArchiveInfoNode_Type type, const char *name)
+{
+ if (parent) {
+ CacheArchiveInfoNode *child;
+ for (child = parent->child_nodes.first; child; child = child->next) {
+ if (STREQ(child->name, name) && child->type == type)
+ return child;
+ }
+ }
+ else if (info->root_node) {
+ if (STREQ(info->root_node->name, name) && info->root_node->type == type)
+ return info->root_node;
+ }
+ return NULL;
+}
+
+CacheArchiveInfoNode *BKE_cache_archive_info_add_node(CacheArchiveInfo *info, CacheArchiveInfoNode *parent,
+ eCacheArchiveInfoNode_Type type, const char *name)
+{
+ CacheArchiveInfoNode *node;
+
+ BLI_assert(parent || !info->root_node);
+
+ node = MEM_callocN(sizeof(CacheArchiveInfoNode), "cache archive info node");
+ node->type = type;
+ BLI_strncpy(node->name, name, sizeof(node->name));
+
+ /* these values are only optionally calculated, -1 indicates unknown */
+ node->bytes_size = -1;
+ node->array_size = -1;
+
+ if (parent)
+ BLI_addtail(&parent->child_nodes, node);
+ else
+ info->root_node = node;
+
+ return node;
+}
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 451656a9bca..87d81a9e921 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -30,16 +30,19 @@
*/
#include <stdlib.h>
+#include <stddef.h>
#include "DNA_camera_types.h"
#include "DNA_lamp_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
+#include "DNA_ID.h"
#include "BLI_math.h"
-#include "BLI_utildefines.h"
#include "BLI_rect.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
#include "BKE_animsys.h"
#include "BKE_camera.h"
@@ -47,6 +50,7 @@
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "GPU_compositing.h"
@@ -71,6 +75,10 @@ void *BKE_camera_add(Main *bmain, const char *name)
GPU_fx_compositor_init_dof_settings(&cam->gpu_dof);
+ /* stereoscopy 3d */
+ cam->stereo.interocular_distance = 0.065f;
+ cam->stereo.convergence_distance = 30.f * 0.065f;
+
return cam;
}
@@ -138,7 +146,7 @@ void BKE_camera_make_local(Camera *cam)
void BKE_camera_free(Camera *ca)
{
- BKE_free_animdata((ID *)ca);
+ BKE_animdata_free((ID *)ca);
}
/******************************** Camera Usage *******************************/
@@ -213,7 +221,7 @@ void BKE_camera_params_init(CameraParams *params)
params->clipend = 100.0f;
}
-void BKE_camera_params_from_object(CameraParams *params, Object *ob)
+void BKE_camera_params_from_object(CameraParams *params, const Object *ob)
{
if (!ob)
return;
@@ -255,7 +263,7 @@ void BKE_camera_params_from_object(CameraParams *params, Object *ob)
}
}
-void BKE_camera_params_from_view3d(CameraParams *params, View3D *v3d, RegionView3D *rv3d)
+void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, const RegionView3D *rv3d)
{
/* common */
params->lens = v3d->lens;
@@ -274,7 +282,7 @@ void BKE_camera_params_from_view3d(CameraParams *params, View3D *v3d, RegionView
params->shiftx *= params->zoom;
params->shifty *= params->zoom;
- params->zoom = 1.0f / params->zoom;
+ params->zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB / params->zoom;
}
else if (rv3d->persp == RV3D_ORTHO) {
/* orthographic view */
@@ -283,13 +291,13 @@ void BKE_camera_params_from_view3d(CameraParams *params, View3D *v3d, RegionView
params->clipsta = -params->clipend;
params->is_ortho = true;
- /* make sure any changes to this match ED_view3d_radius_to_ortho_dist() */
+ /* make sure any changes to this match ED_view3d_radius_to_dist_ortho() */
params->ortho_scale = rv3d->dist * sensor_size / v3d->lens;
- params->zoom = 2.0f;
+ params->zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
}
else {
/* perspective view */
- params->zoom = 2.0f;
+ params->zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
}
}
@@ -384,8 +392,10 @@ void BKE_camera_params_compute_matrix(CameraParams *params)
/***************************** Camera View Frame *****************************/
-void BKE_camera_view_frame_ex(Scene *scene, Camera *camera, float drawsize, const bool do_clip, const float scale[3],
- float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3])
+void BKE_camera_view_frame_ex(
+ const Scene *scene, const Camera *camera,
+ const float drawsize, const bool do_clip, const float scale[3],
+ float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3])
{
float facx, facy;
float depth;
@@ -456,7 +466,7 @@ void BKE_camera_view_frame_ex(Scene *scene, Camera *camera, float drawsize, cons
r_vec[3][0] = r_shift[0] - facx; r_vec[3][1] = r_shift[1] + facy; r_vec[3][2] = depth;
}
-void BKE_camera_view_frame(Scene *scene, Camera *camera, float r_vec[4][3])
+void BKE_camera_view_frame(const Scene *scene, const Camera *camera, float r_vec[4][3])
{
float dummy_asp[2];
float dummy_shift[2];
@@ -502,7 +512,9 @@ static void camera_to_frame_view_cb(const float co[3], void *user_data)
data->tot++;
}
-static void camera_frame_fit_data_init(Scene *scene, Object *ob, CameraParams *params, CameraViewFrameData *data)
+static void camera_frame_fit_data_init(
+ const Scene *scene, const Object *ob,
+ CameraParams *params, CameraViewFrameData *data)
{
float camera_rotmat_transposed_inversed[4][4];
unsigned int i;
@@ -521,7 +533,7 @@ static void camera_frame_fit_data_init(Scene *scene, Object *ob, CameraParams *p
BKE_camera_params_compute_matrix(params);
/* initialize callback data */
- copy_m3_m4(data->camera_rotmat, ob->obmat);
+ copy_m3_m4(data->camera_rotmat, (float (*)[4])ob->obmat);
normalize_m3(data->camera_rotmat);
/* To transform a plane which is in its homogeneous representation (4d vector),
* we need the inverse of the transpose of the transform matrix... */
@@ -672,7 +684,8 @@ bool BKE_camera_view_frame_fit_to_scene(
}
bool BKE_camera_view_frame_fit_to_coords(
- Scene *scene, float (*cos)[3], int num_cos, Object *camera_ob, float r_co[3], float *r_scale)
+ const Scene *scene, const float (*cos)[3], int num_cos, const Object *camera_ob,
+ float r_co[3], float *r_scale)
{
CameraParams params;
CameraViewFrameData data_cb;
@@ -690,6 +703,255 @@ bool BKE_camera_view_frame_fit_to_coords(
return camera_frame_fit_calc_from_data(&params, &data_cb, r_co, r_scale);
}
+/******************* multiview matrix functions ***********************/
+
+static void camera_model_matrix(Object *camera, float r_modelmat[4][4])
+{
+ copy_m4_m4(r_modelmat, camera->obmat);
+}
+
+static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, float r_modelmat[4][4])
+{
+ Camera *data = (Camera *)camera->data;
+ float interocular_distance, convergence_distance;
+ short convergence_mode, pivot;
+ float sizemat[4][4];
+
+ float fac = 1.0f;
+ float fac_signed;
+
+ interocular_distance = data->stereo.interocular_distance;
+ convergence_distance = data->stereo.convergence_distance;
+ convergence_mode = data->stereo.convergence_mode;
+ pivot = data->stereo.pivot;
+
+ if (((pivot == CAM_S3D_PIVOT_LEFT) && is_left) ||
+ ((pivot == CAM_S3D_PIVOT_RIGHT) && !is_left))
+ {
+ camera_model_matrix(camera, r_modelmat);
+ return;
+ }
+ else {
+ float size[3];
+ mat4_to_size(size, camera->obmat);
+ size_to_mat4(sizemat, size);
+ }
+
+ if (pivot == CAM_S3D_PIVOT_CENTER)
+ fac = 0.5f;
+
+ fac_signed = is_left ? fac : -fac;
+
+ /* rotation */
+ if (convergence_mode == CAM_S3D_TOE) {
+ float angle;
+ float angle_sin, angle_cos;
+ float toeinmat[4][4];
+ float rotmat[4][4];
+
+ unit_m4(rotmat);
+
+ if (pivot == CAM_S3D_PIVOT_CENTER) {
+ fac = -fac;
+ fac_signed = -fac_signed;
+ }
+
+ angle = atanf((interocular_distance * 0.5f) / convergence_distance) / fac;
+
+ angle_cos = cosf(angle * fac_signed);
+ angle_sin = sinf(angle * fac_signed);
+
+ rotmat[0][0] = angle_cos;
+ rotmat[2][0] = -angle_sin;
+ rotmat[0][2] = angle_sin;
+ rotmat[2][2] = angle_cos;
+
+ if (pivot == CAM_S3D_PIVOT_CENTER) {
+ /* set the rotation */
+ copy_m4_m4(toeinmat, rotmat);
+ /* set the translation */
+ toeinmat[3][0] = interocular_distance * fac_signed;
+
+ /* transform */
+ normalize_m4_m4(r_modelmat, camera->obmat);
+ mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat);
+
+ /* scale back to the original size */
+ mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
+ }
+ else { /* CAM_S3D_PIVOT_LEFT, CAM_S3D_PIVOT_RIGHT */
+ /* rotate perpendicular to the interocular line */
+ normalize_m4_m4(r_modelmat, camera->obmat);
+ mul_m4_m4m4(r_modelmat, r_modelmat, rotmat);
+
+ /* translate along the interocular line */
+ unit_m4(toeinmat);
+ toeinmat[3][0] = -interocular_distance * fac_signed;
+ mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat);
+
+ /* rotate to toe-in angle */
+ mul_m4_m4m4(r_modelmat, r_modelmat, rotmat);
+
+ /* scale back to the original size */
+ mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
+ }
+ }
+ else {
+ normalize_m4_m4(r_modelmat, camera->obmat);
+
+ /* translate - no rotation in CAM_S3D_OFFAXIS, CAM_S3D_PARALLEL */
+ translate_m4(r_modelmat, -interocular_distance * fac_signed, 0.0f, 0.0f);
+
+ /* scale back to the original size */
+ mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
+ }
+}
+
+/* the view matrix is used by the viewport drawing, it is basically the inverted model matrix */
+void BKE_camera_multiview_view_matrix(RenderData *rd, Object *camera, const bool is_left, float r_viewmat[4][4])
+{
+ BKE_camera_multiview_model_matrix(rd, camera, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, r_viewmat);
+ invert_m4(r_viewmat);
+}
+
+/* left is the default */
+static bool camera_is_left(const char *viewname)
+{
+ if (viewname && viewname[0] != '\0') {
+ return !STREQ(viewname, STEREO_RIGHT_NAME);
+ }
+ return true;
+}
+
+void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const char *viewname, float r_modelmat[4][4])
+{
+ const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
+
+ if (!is_multiview) {
+ camera_model_matrix(camera, r_modelmat);
+ }
+ else if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW) {
+ camera_model_matrix(camera, r_modelmat);
+ }
+ else { /* SCE_VIEWS_SETUP_BASIC */
+ const bool is_left = camera_is_left(viewname);
+ camera_stereo3d_model_matrix(camera, is_left, r_modelmat);
+ }
+ normalize_m4(r_modelmat);
+}
+
+static Object *camera_multiview_advanced(Scene *scene, Object *camera, const char *suffix)
+{
+ SceneRenderView *srv;
+ char name[MAX_NAME];
+ const char *camera_name = camera->id.name + 2;
+ const int len_name = strlen(camera_name);
+
+ name[0] = '\0';
+
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ const int len_suffix = strlen(srv->suffix);
+
+ if (len_name < len_suffix)
+ continue;
+
+ if (STREQ(camera_name + (len_name - len_suffix), srv->suffix)) {
+ BLI_snprintf(name, sizeof(name), "%.*s%s", (len_name - len_suffix), camera_name, suffix);
+ break;
+ }
+ }
+
+ if (name[0] != '\0') {
+ Base *base = BKE_scene_base_find_by_name(scene, name);
+ if (base) {
+ return base->object;
+ }
+ }
+
+ return camera;
+}
+
+/* returns the camera to be used for render */
+Object *BKE_camera_multiview_render(Scene *scene, Object *camera, const char *viewname)
+{
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
+
+ if (!is_multiview) {
+ return camera;
+ }
+ else if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
+ return camera;
+ }
+ else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
+ const char *suffix = BKE_scene_multiview_view_suffix_get(&scene->r, viewname);
+ return camera_multiview_advanced(scene, camera, suffix);
+ }
+}
+
+static float camera_stereo3d_shift_x(Object *camera, const char *viewname)
+{
+ Camera *data = camera->data;
+ float shift = data->shiftx;
+ float interocular_distance, convergence_distance;
+ short convergence_mode, pivot;
+ bool is_left = true;
+
+ float fac = 1.0f;
+ float fac_signed;
+
+ if (viewname && viewname[0]) {
+ is_left = STREQ(viewname, STEREO_LEFT_NAME);
+ }
+
+ interocular_distance = data->stereo.interocular_distance;
+ convergence_distance = data->stereo.convergence_distance;
+ convergence_mode = data->stereo.convergence_mode;
+ pivot = data->stereo.pivot;
+
+ if (((pivot == CAM_S3D_PIVOT_LEFT) && is_left) ||
+ ((pivot == CAM_S3D_PIVOT_RIGHT) && !is_left))
+ {
+ return shift;
+ }
+
+ if (pivot == CAM_S3D_PIVOT_CENTER)
+ fac = 0.5f;
+
+ fac_signed = is_left ? fac : -fac;
+
+ /* Note: in viewport, parallel renders as offaxis, but in render it does parallel */
+ if (ELEM(convergence_mode, CAM_S3D_OFFAXIS, CAM_S3D_PARALLEL)) {
+ shift += ((interocular_distance / data->sensor_x) * (data->lens / convergence_distance)) * fac_signed;
+ }
+
+ return shift;
+}
+
+float BKE_camera_multiview_shift_x(RenderData *rd, Object *camera, const char *viewname)
+{
+ const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
+ Camera *data = camera->data;
+
+ BLI_assert(camera->type == OB_CAMERA);
+
+ if (!is_multiview) {
+ return data->shiftx;
+ }
+ else if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW) {
+ return data->shiftx;
+ }
+ else { /* SCE_VIEWS_SETUP_BASIC */
+ return camera_stereo3d_shift_x(camera, viewname);
+ }
+}
+
+void BKE_camera_multiview_params(RenderData *rd, CameraParams *params, Object *camera, const char *viewname)
+{
+ if (camera->type == OB_CAMERA) {
+ params->shiftx = BKE_camera_multiview_shift_x(rd, camera, viewname);
+ }
+}
+
void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings)
{
if (camera->type == OB_CAMERA) {
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 2a38418f94d..8660f122c10 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -470,7 +470,7 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm,
int a;
if (cddm->pbvh && cddm->pbvh_draw) {
- if (dm->numTessFaceData) {
+ if (BKE_pbvh_has_faces(cddm->pbvh)) {
float (*face_nors)[3] = CustomData_get_layer(&dm->faceData, CD_NORMAL);
BKE_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors,
@@ -527,7 +527,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
* (the same as it'll display without UV maps in textured view)
*/
if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) {
- if (dm->numTessFaceData) {
+ if (BKE_pbvh_has_faces(cddm->pbvh)) {
GPU_set_tpage(NULL, false, false);
BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false);
}
@@ -786,14 +786,14 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm,
if (tottri == 0) {
/* avoid buffer problems in following code */
}
- if (setDrawOptions == NULL) {
+ else if (setDrawOptions == NULL) {
/* just draw the entire face array */
glDrawArrays(GL_TRIANGLES, 0, (tottri) * 3);
}
else {
/* we need to check if the next material changes */
int next_actualFace = dm->drawObject->triangle_to_mface[0];
- int prev_mat_nr = -1;
+ short prev_mat_nr = -1;
for (i = 0; i < tottri; i++) {
//int actualFace = dm->drawObject->triangle_to_mface[i];
@@ -912,7 +912,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm,
* works fine for matcap
*/
if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) {
- if (dm->numTessFaceData) {
+ if (BKE_pbvh_has_faces(cddm->pbvh)) {
setMaterial(1, &gattribs);
BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false);
}
@@ -927,7 +927,10 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm,
glShadeModel(GL_SMOOTH);
- if (setDrawOptions != NULL) {
+ /* workaround for NVIDIA GPUs on Mac not supporting vertex arrays + interleaved formats, see T43342 */
+ if ((GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_MAC, GPU_DRIVER_ANY) && (U.gameflags & USER_DISABLE_VBO)) ||
+ setDrawOptions != NULL)
+ {
DEBUG_VBO("Using legacy code. cdDM_drawMappedFacesGLSL\n");
memset(&attribs, 0, sizeof(attribs));
@@ -1082,9 +1085,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm,
elementsize = GPU_attrib_element_size(datatypes, numdata);
buffer = GPU_buffer_alloc(elementsize * dm->drawObject->tot_triangle_point, false);
if (buffer == NULL) {
- GPU_buffer_unbind();
buffer = GPU_buffer_alloc(elementsize * dm->drawObject->tot_triangle_point, true);
- return;
}
varray = GPU_buffer_lock_stream(buffer);
if (varray == NULL) {
@@ -1245,7 +1246,7 @@ static void cdDM_drawMappedFacesMat(DerivedMesh *dm,
* works fine for matcap
*/
if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) {
- if (dm->numTessFaceData) {
+ if (BKE_pbvh_has_faces(cddm->pbvh)) {
setMaterial(userData, 1, &gattribs);
BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false);
}
@@ -2544,16 +2545,16 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
const unsigned int v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
const unsigned int v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
if (LIKELY(v1 != v2)) {
- void **eh_p = BLI_edgehash_lookup_p(ehash, v1, v2);
+ void **val_p;
- if (eh_p) {
- newe[i] = GET_INT_FROM_POINTER(*eh_p);
+ if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
+ newe[i] = GET_INT_FROM_POINTER(*val_p);
}
else {
STACK_PUSH(olde, i);
STACK_PUSH(medge, *med);
newe[i] = c;
- BLI_edgehash_insert(ehash, v1, v2, SET_INT_IN_POINTER(c));
+ *val_p = SET_INT_IN_POINTER(c);
c++;
}
}
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index bf99992956a..17ed9de91e0 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -370,7 +370,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
mul_m4_v3(ob->obmat, verts->xconst);
}
- effectors = pdInitEffectors(clmd->scene, ob, NULL, clmd->sim_parms->effector_weights, true);
+ effectors = pdInitEffectors(clmd->scene, ob, NULL, clmd->sim_parms->effector_weights);
/* Support for dynamic vertex groups, changing from frame to frame */
cloth_apply_vgroup ( clmd, result );
@@ -500,7 +500,6 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe);
if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED) {
- BPH_cloth_solver_set_positions(clmd);
cloth_to_object (ob, clmd, vertexCos);
BKE_ptcache_validate(cache, framenr);
@@ -779,17 +778,15 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
}
}
- if (clmd->sim_parms->vgroup_shrink > 0 )
- {
- if ( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink-1))
- {
- verts->shrink_factor = clmd->sim_parms->shrink_min*(1.0f-dvert->dw[j].weight)+clmd->sim_parms->shrink_max*dvert->dw [j].weight; // linear interpolation between min and max shrink factor based on weight
+ if (clmd->sim_parms->vgroup_shrink > 0) {
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink - 1)) {
+ /* linear interpolation between min and max shrink factor based on weight */
+ verts->shrink_factor = clmd->sim_parms->shrink_min * (1.0f - dvert->dw[j].weight) + clmd->sim_parms->shrink_max * dvert->dw [j].weight;
+ }
+ }
+ else {
+ verts->shrink_factor = clmd->sim_parms->shrink_min;
}
- }
- else {
- verts->shrink_factor = clmd->sim_parms->shrink_min;
- }
-
}
}
}
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 8846eccc9f3..9ff131157ac 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -953,7 +953,7 @@ static bool cloth_points_collision_response_static(ClothModifierData *clmd, Coll
float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree );
for ( ; collpair != collision_end; collpair++ ) {
- float margin_distance = collpair->distance - epsilon2;
+ float margin_distance = (float)(collpair->distance - (double)epsilon2);
float impulse[3];
float mag_v_rel;
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index 89c3e4b0cfc..c5f7e12c9d0 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -994,7 +994,7 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorM
copy_v3_v3(rgb, fp);
IMB_colormanagement_processor_apply_v3(cm_processor, rgb);
- hist->data_luma[i] = rgb_to_luma(rgb);
+ hist->data_luma[i] = IMB_colormanagement_get_luminance(rgb);
hist->data_r[i] = rgb[0];
hist->data_g[i] = rgb[1];
hist->data_b[i] = rgb[2];
@@ -1002,7 +1002,7 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorM
}
else if (ibuf->rect) {
cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
- hist->data_luma[i] = (float)rgb_to_luma_byte(cp) / 255.0f;
+ hist->data_luma[i] = (float)IMB_colormanagement_get_luminance_byte(cp) / 255.0f;
hist->data_r[i] = (float)cp[0] / 255.0f;
hist->data_g[i] = (float)cp[1] / 255.0f;
hist->data_b[i] = (float)cp[2] / 255.0f;
@@ -1124,7 +1124,7 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
}
/* we still need luma for histogram */
- luma = rgb_to_luma(rgba);
+ luma = IMB_colormanagement_get_luminance(rgba);
/* check for min max */
if (ycc_mode == -1) {
@@ -1303,3 +1303,9 @@ void BKE_color_managed_colorspace_settings_copy(ColorManagedColorspaceSettings *
{
BLI_strncpy(colorspace_settings->name, settings->name, sizeof(colorspace_settings->name));
}
+
+bool BKE_color_managed_colorspace_settings_equals(const ColorManagedColorspaceSettings *settings1,
+ const ColorManagedColorspaceSettings *settings2)
+{
+ return STREQ(settings1->name, settings2->name);
+}
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index c38a1239f12..fa8ab14de06 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -4318,7 +4318,7 @@ static void constraints_init_typeinfo(void)
/* This function should be used for getting the appropriate type-info when only
* a constraint type is known
*/
-bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type)
+const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type)
{
/* initialize the type-info list? */
if (CTI_INIT) {
@@ -4343,7 +4343,7 @@ bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type)
/* This function should always be used to get the appropriate type-info, as it
* has checks which prevent segfaults in some weird cases.
*/
-bConstraintTypeInfo *BKE_constraint_typeinfo_get(bConstraint *con)
+const bConstraintTypeInfo *BKE_constraint_typeinfo_get(bConstraint *con)
{
/* only return typeinfo for valid constraints */
if (con)
@@ -4373,7 +4373,7 @@ static void con_unlink_refs_cb(bConstraint *UNUSED(con), ID **idpoin, bool is_re
void BKE_constraint_free_data_ex(bConstraint *con, bool do_id_user)
{
if (con->data) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (cti) {
/* perform any special freeing constraint may have */
@@ -4447,7 +4447,7 @@ bool BKE_constraint_remove_ex(ListBase *list, Object *ob, bConstraint *con, bool
static bConstraint *add_new_constraint_internal(const char *name, short type)
{
bConstraint *con = MEM_callocN(sizeof(bConstraint), "Constraint");
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(type);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(type);
const char *newName;
/* Set up a generic constraint datablock */
@@ -4574,7 +4574,7 @@ void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *use
bConstraint *con;
for (con = conlist->first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (cti) {
if (cti->id_looper)
@@ -4609,7 +4609,7 @@ void BKE_constraints_copy(ListBase *dst, const ListBase *src, bool do_extern)
BLI_duplicatelist(dst, src);
for (con = dst->first, srccon = src->first; con && srccon; srccon = srccon->next, con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
/* make a new copy of the constraint's data */
con->data = MEM_dupallocN(con->data);
@@ -4724,7 +4724,7 @@ bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan)
*/
void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index, short ownertype, void *ownerdata, float mat[4][4], float ctime)
{
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintOb *cob;
bConstraintTarget *ct;
@@ -4791,7 +4791,7 @@ void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index,
/* Get the list of targets required for solving a constraint */
void BKE_constraint_targets_for_solving_get(bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime)
{
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (cti && cti->get_constraint_targets) {
bConstraintTarget *ct;
@@ -4836,7 +4836,7 @@ void BKE_constraints_solve(ListBase *conlist, bConstraintOb *cob, float ctime)
/* loop over available constraints, solving and blending them */
for (con = conlist->first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
/* these we can skip completely (invalid constraints...) */
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 59f7da83925..b463a1650b7 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -928,6 +928,7 @@ int CTX_data_mode_enum(const bContext *C)
else if (ob->mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX;
else if (ob->mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE;
else if (ob->mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE;
+ else if (ob->mode & OB_MODE_HAIR_EDIT) return CTX_MODE_HAIR;
}
}
@@ -951,6 +952,7 @@ static const char *data_mode_strings[] = {
"vertexpaint",
"imagepaint",
"particlemode",
+ "hairmode",
"objectmode",
NULL
};
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 911bb19a594..392aac13999 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -266,7 +266,7 @@ int editbmesh_get_first_deform_matrices(Scene *scene, Object *ob, BMEditMesh *em
* modifiers with on cage editing that are enabled and support computing
* deform matrices */
for (i = 0; md && i <= cageIndex; i++, md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!editbmesh_modifier_is_enabled(scene, md, dm))
continue;
@@ -322,7 +322,7 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo
md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
@@ -343,7 +343,7 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo
}
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
@@ -377,7 +377,7 @@ void BKE_crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[
Mesh *me = (Mesh *)ob->data;
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 2b886ef9be9..9f83ffa2577 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -147,7 +147,7 @@ void BKE_curve_free(Curve *cu)
BKE_curve_editNurb_free(cu);
BKE_curve_unlink(cu);
- BKE_free_animdata((ID *)cu);
+ BKE_animdata_free((ID *)cu);
if (cu->mat)
MEM_freeN(cu->mat);
@@ -1384,6 +1384,30 @@ void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float
}
}
+/* forward differencing method for first derivative of cubic bezier curve */
+void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
+{
+ float rt0, rt1, rt2, f;
+ int a;
+
+ f = 1.0f / (float)it;
+
+ rt0 = 3.0f * (q1 - q0);
+ rt1 = f * (3.0f * (q3 - q0) + 9.0f * (q1 - q2));
+ rt2 = 6.0f * (q0 + q2) - 12.0f * q1;
+
+ q0 = rt0;
+ q1 = f * (rt1 + rt2);
+ q2 = 2.0f * f * rt1;
+
+ for (a = 0; a <= it; a++) {
+ *p = q0;
+ p = (float *)(((char *)p) + stride);
+ q0 += q1;
+ q1 += q2;
+ }
+}
+
static void forward_diff_bezier_cotangent(const float p0[3], const float p1[3], const float p2[3], const float p3[3],
float p[3], int it, int stride)
{
@@ -4344,8 +4368,10 @@ void BKE_curve_transform_ex(Curve *cu, float mat[4][4], const bool do_keys, cons
}
else {
i = nu->pntsu * nu->pntsv;
- for (bp = nu->bp; i--; bp++)
+ for (bp = nu->bp; i--; bp++) {
mul_m4_v3(mat, bp->vec);
+ bp->radius *= unit_scale;
+ }
}
}
@@ -4422,9 +4448,6 @@ void BKE_curve_material_index_remove(Curve *cu, int index)
for (nu = cu->nurb.first; nu; nu = nu->next) {
if (nu->mat_nr && nu->mat_nr >= index) {
nu->mat_nr--;
- if (curvetype == OB_CURVE) {
- nu->charidx--;
- }
}
}
}
@@ -4446,9 +4469,6 @@ void BKE_curve_material_index_clear(Curve *cu)
for (nu = cu->nurb.first; nu; nu = nu->next) {
nu->mat_nr = 0;
- if (curvetype == OB_CURVE) {
- nu->charidx = 0;
- }
}
}
}
@@ -4475,9 +4495,6 @@ int BKE_curve_material_index_validate(Curve *cu)
for (nu = cu->nurb.first; nu; nu = nu->next) {
if (nu->mat_nr > max_idx) {
nu->mat_nr = 0;
- if (curvetype == OB_CURVE) {
- nu->charidx = 0;
- }
is_valid = false;
}
}
@@ -4492,6 +4509,54 @@ int BKE_curve_material_index_validate(Curve *cu)
}
}
+void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int remap_len)
+{
+ const int curvetype = BKE_curve_type_get(cu);
+ const short remap_len_short = (short)remap_len;
+
+#define MAT_NR_REMAP(n) \
+ if (n < remap_len_short) { \
+ BLI_assert(n >= 0 && remap[n] < remap_len_short); \
+ n = remap[n]; \
+ } ((void)0)
+
+ if (curvetype == OB_FONT) {
+ struct CharInfo *strinfo;
+ int charinfo_len, i;
+
+ if (cu->editfont) {
+ EditFont *ef = cu->editfont;
+ strinfo = ef->textbufinfo;
+ charinfo_len = ef->len;
+ }
+ else {
+ strinfo = cu->strinfo;
+ charinfo_len = cu->len_wchar;
+ }
+
+ for (i = 0; i <= charinfo_len; i++) {
+ if (strinfo[i].mat_nr > 0) {
+ strinfo[i].mat_nr -= 1;
+ MAT_NR_REMAP(strinfo[i].mat_nr);
+ strinfo[i].mat_nr += 1;
+ }
+ }
+ }
+ else {
+ Nurb *nu;
+ ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+
+ if (nurbs) {
+ for (nu = nurbs->first; nu; nu = nu->next) {
+ MAT_NR_REMAP(nu->mat_nr);
+ }
+ }
+ }
+
+#undef MAT_NR_REMAP
+
+}
+
void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *tb, struct rctf *r_rect)
{
r_rect->xmin = cu->xof + tb->x;
@@ -4500,3 +4565,27 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *t
r_rect->xmax = r_rect->xmin + tb->w;
r_rect->ymin = r_rect->ymax - tb->h;
}
+
+/* **** Depsgraph evaluation **** */
+
+void BKE_curve_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+ Curve *curve)
+{
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s on %s\n", __func__, curve->id.name);
+ }
+ if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_curve_texspace_calc(curve);
+ }
+}
+
+void BKE_curve_eval_path(EvaluationContext *UNUSED(eval_ctx),
+ Curve *curve)
+{
+ /* TODO(sergey): This will probably need to be a part of
+ * the modifier stack still.
+ */
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s on %s\n", __func__, curve->id.name);
+ }
+}
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 149dc7c101c..403e815ce5c 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -55,6 +55,7 @@
#include "BKE_customdata.h"
#include "BKE_customdata_file.h"
+#include "BKE_editstrands.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_mesh_mapping.h"
@@ -1091,7 +1092,7 @@ static void layerDefault_mcol(void *data, int count)
static void layerDefault_origindex(void *data, int count)
{
- fill_vn_i((int *)data, count, ORIGINDEX_NONE);
+ copy_vn_i((int *)data, count, ORIGINDEX_NONE);
}
static void layerInterp_bweight(
@@ -1324,6 +1325,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(short[2]), "vec2s", 1, NULL, NULL, NULL, NULL, NULL, NULL},
/* 42: CD_FACEMAP */
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_fmap, NULL},
+ /* 43: CD_MSURFACE_SAMPLE */
+ {sizeof(MSurfaceSample), "MSurfaceSample", 1, NULL, NULL, NULL, NULL, NULL, NULL},
};
/* note, numbers are from trunk and need updating for bmesh */
@@ -1341,6 +1344,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 35-36 */ "CDGridPaintMask", "CDMVertSkin",
/* 37-38 */ "CDFreestyleEdge", "CDFreestyleFace",
/* 39-42 */ "CDMLoopTangent", "CDTessLoopNormal", "CDCustomLoopNormal", "CDFaceMap",
+ /* 43 */ "CDMSurfaceSample",
};
@@ -1378,6 +1382,17 @@ const CustomDataMask CD_MASK_BMESH =
const CustomDataMask CD_MASK_FACECORNERS = /* XXX Not used anywhere! */
CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV |
CD_MASK_MLOOPCOL | CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT;
+const CustomDataMask CD_MASK_STRANDS =
+ CD_MASK_MVERT | CD_MASK_MEDGE |
+ CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MCOL |
+ CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS |
+ CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE |
+ CD_MASK_MSURFACE_SAMPLE;
+const CustomDataMask CD_MASK_STRANDS_BMESH =
+ CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT |
+ CD_MASK_PROP_STR | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_MDISPS |
+ CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE |
+ CD_MASK_MSURFACE_SAMPLE;
const CustomDataMask CD_MASK_EVERYTHING =
CD_MASK_MVERT | CD_MASK_MSTICKY /* DEPRECATED */ | CD_MASK_MDEFORMVERT | CD_MASK_MEDGE | CD_MASK_MFACE |
CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_NORMAL /* | CD_MASK_POLYINDEX */ | CD_MASK_PROP_FLT |
@@ -1389,7 +1404,7 @@ const CustomDataMask CD_MASK_EVERYTHING =
/* BMESH ONLY END */
CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN |
CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
- CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP;
+ CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP | CD_MASK_MSURFACE_SAMPLE;
static const LayerTypeInfo *layerType_getInfo(int type)
{
@@ -1554,7 +1569,7 @@ static void CustomData_external_free(CustomData *data)
void CustomData_reset(CustomData *data)
{
memset(data, 0, sizeof(*data));
- fill_vn_i(data->typemap, CD_NUMTYPES, -1);
+ copy_vn_i(data->typemap, CD_NUMTYPES, -1);
}
void CustomData_free(CustomData *data, int totelem)
@@ -1841,7 +1856,13 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ
newlayerdata = layerdata;
}
else if (size > 0) {
- newlayerdata = MEM_callocN(size, layerType_getName(type));
+ if (alloctype == CD_DUPLICATE && layerdata) {
+ newlayerdata = MEM_mallocN(size, layerType_getName(type));
+ }
+ else {
+ newlayerdata = MEM_callocN(size, layerType_getName(type));
+ }
+
if (!newlayerdata)
return NULL;
}
@@ -2300,7 +2321,7 @@ void CustomData_interp(const CustomData *source, CustomData *dest,
}
}
- if (count > SOURCE_BUF_SIZE) MEM_freeN(sources);
+ if (count > SOURCE_BUF_SIZE) MEM_freeN((void *)sources);
}
void CustomData_swap(struct CustomData *data, int index, const int *corner_indices)
@@ -2832,6 +2853,18 @@ void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n)
return POINTER_OFFSET(block, data->layers[n].offset);
}
+/*Bmesh Custom Data Functions. Should replace editmesh ones with these as well, due to more effecient memory alloc*/
+void *CustomData_bmesh_get_named(const CustomData *data, void *block, int type, const char *name)
+{
+ int layer_index;
+
+ /* get the layer index of the named layer of type */
+ layer_index = CustomData_get_named_layer_index(data, type, name);
+ if (layer_index == -1) return NULL;
+
+ return (char *)block + data->layers[layer_index].offset;
+}
+
bool CustomData_layer_has_math(const struct CustomData *data, int layer_n)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type);
@@ -3858,7 +3891,7 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap, const CustomDataTra
if (tmp_data_src) {
if (UNLIKELY(sources_num > tmp_buff_size)) {
tmp_buff_size = (size_t)sources_num;
- tmp_data_src = MEM_reallocN(tmp_data_src, sizeof(*tmp_data_src) * tmp_buff_size);
+ tmp_data_src = MEM_reallocN((void *)tmp_data_src, sizeof(*tmp_data_src) * tmp_buff_size);
}
for (j = 0; j < sources_num; j++) {
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 8f6d4385b55..da00aecf9c0 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -1157,12 +1157,20 @@ bool BKE_object_data_transfer_dm(
const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
if (!geom_map_init[VDATA]) {
- if ((map_vert_mode == MREMAP_MODE_TOPOLOGY) && (num_verts_dst != dm_src->getNumVerts(dm_src))) {
+ const int num_verts_src = dm_src->getNumVerts(dm_src);
+
+ if ((map_vert_mode == MREMAP_MODE_TOPOLOGY) && (num_verts_dst != num_verts_src)) {
BKE_report(reports, RPT_ERROR,
"Source and destination meshes do not have the same amount of vertices, "
"'Topology' mapping cannot be used in this case");
return changed;
}
+ if (ELEM(0, num_verts_dst, num_verts_src)) {
+ BKE_report(reports, RPT_ERROR,
+ "Source or destination meshes do not have any vertices, cannot transfer vertex data");
+ return changed;
+ }
+
BKE_mesh_remap_calc_verts_from_dm(
map_vert_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, dirty_nors_dst, dm_src, &geom_map[VDATA]);
@@ -1197,12 +1205,20 @@ bool BKE_object_data_transfer_dm(
const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
if (!geom_map_init[EDATA]) {
- if ((map_edge_mode == MREMAP_MODE_TOPOLOGY) && (num_edges_dst != dm_src->getNumEdges(dm_src))) {
+ const int num_edges_src = dm_src->getNumEdges(dm_src);
+
+ if ((map_edge_mode == MREMAP_MODE_TOPOLOGY) && (num_edges_dst != num_edges_src)) {
BKE_report(reports, RPT_ERROR,
"Source and destination meshes do not have the same amount of edges, "
"'Topology' mapping cannot be used in this case");
return changed;
}
+ if (ELEM(0, num_edges_dst, num_edges_src)) {
+ BKE_report(reports, RPT_ERROR,
+ "Source or destination meshes do not have any edges, cannot transfer edge data");
+ return changed;
+ }
+
BKE_mesh_remap_calc_edges_from_dm(
map_edge_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, edges_dst, num_edges_dst, dirty_nors_dst,
@@ -1248,12 +1264,20 @@ bool BKE_object_data_transfer_dm(
MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type);
if (!geom_map_init[LDATA]) {
- if ((map_loop_mode == MREMAP_MODE_TOPOLOGY) && (num_loops_dst != dm_src->getNumLoops(dm_src))) {
+ const int num_loops_src = dm_src->getNumLoops(dm_src);
+
+ if ((map_loop_mode == MREMAP_MODE_TOPOLOGY) && (num_loops_dst != num_loops_src)) {
BKE_report(reports, RPT_ERROR,
"Source and destination meshes do not have the same amount of face corners, "
"'Topology' mapping cannot be used in this case");
return changed;
}
+ if (ELEM(0, num_loops_dst, num_loops_src)) {
+ BKE_report(reports, RPT_ERROR,
+ "Source or destination meshes do not have any polygons, cannot transfer loop data");
+ return changed;
+ }
+
BKE_mesh_remap_calc_loops_from_dm(
map_loop_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, edges_dst, num_edges_dst,
@@ -1298,12 +1322,20 @@ bool BKE_object_data_transfer_dm(
CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
if (!geom_map_init[PDATA]) {
- if ((map_poly_mode == MREMAP_MODE_TOPOLOGY) && (num_polys_dst != dm_src->getNumPolys(dm_src))) {
+ const int num_polys_src = dm_src->getNumPolys(dm_src);
+
+ if ((map_poly_mode == MREMAP_MODE_TOPOLOGY) && (num_polys_dst != num_polys_src)) {
BKE_report(reports, RPT_ERROR,
"Source and destination meshes do not have the same amount of faces, "
"'Topology' mapping cannot be used in this case");
return changed;
}
+ if (ELEM(0, num_polys_dst, num_polys_src)) {
+ BKE_report(reports, RPT_ERROR,
+ "Source or destination meshes do not have any polygons, cannot transfer poly data");
+ return changed;
+ }
+
BKE_mesh_remap_calc_polys_from_dm(
map_poly_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, loops_dst, num_loops_dst,
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 0adea59c245..88885da474b 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -649,7 +649,7 @@ void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[
BLI_strncpy(prefix, name, sizeof(prefix));
/* first case; separator . - _ with extensions r R l L */
- if (is_char_sep(name[len - 2])) {
+ if ((len > 1) && is_char_sep(name[len - 2])) {
is_set = true;
switch (name[len - 1]) {
case 'l':
@@ -982,7 +982,7 @@ void BKE_defvert_extract_vgroup_to_vertweights(
}
}
else {
- fill_vn_fl(r_weights, invert_vgroup ? 1.0f : 0.0f, num_verts);
+ copy_vn_fl(r_weights, num_verts, invert_vgroup ? 1.0f : 0.0f);
}
}
@@ -1008,7 +1008,7 @@ void BKE_defvert_extract_vgroup_to_edgeweights(
MEM_freeN(tmp_weights);
}
else {
- fill_vn_fl(r_weights, 0.0f, num_edges);
+ copy_vn_fl(r_weights, num_edges, 0.0f);
}
}
@@ -1031,7 +1031,7 @@ void BKE_defvert_extract_vgroup_to_loopweights(
MEM_freeN(tmp_weights);
}
else {
- fill_vn_fl(r_weights, 0.0f, num_loops);
+ copy_vn_fl(r_weights, num_loops, 0.0f);
}
}
@@ -1060,7 +1060,7 @@ void BKE_defvert_extract_vgroup_to_polyweights(
MEM_freeN(tmp_weights);
}
else {
- fill_vn_fl(r_weights, 0.0f, num_polys);
+ copy_vn_fl(r_weights, num_polys, 0.0f);
}
}
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 00efc28988b..ffaafe94b96 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -45,6 +45,7 @@
#include "BLI_threads.h"
#include "DNA_anim_types.h"
+#include "DNA_cache_library_types.h"
#include "DNA_camera_types.h"
#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
@@ -88,16 +89,25 @@
#include "depsgraph_private.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_query.h"
+
+#ifdef WITH_LEGACY_DEPSGRAPH
+
static SpinLock threaded_update_lock;
void DAG_init(void)
{
BLI_spin_init(&threaded_update_lock);
+ DEG_register_node_types();
}
void DAG_exit(void)
{
BLI_spin_end(&threaded_update_lock);
+ DEG_free_node_types();
}
/* Queue and stack operations for dag traversal
@@ -484,7 +494,7 @@ static void dag_add_collision_field_relation(DagForest *dag, Scene *scene, Objec
}
}
-static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, Object *ob, int mask)
+static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Scene *scene, Object *ob, int mask)
{
bConstraint *con;
DagNode *node;
@@ -512,7 +522,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -574,9 +584,9 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if (mti->updateDepgraph) mti->updateDepgraph(md, dag, scene, ob, node);
+ if (mti->updateDepgraph) mti->updateDepgraph(md, dag, bmain, scene, ob, node);
}
}
if (ob->parent) {
@@ -620,8 +630,22 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
/* inverted relation, so addtoroot shouldn't be set to zero */
}
+ /* XXX Fake dependency: duplicator object becomes a child of group objects.
+ * This exploits the layer visibility mechanism, making the group objects update
+ * when the duplicator is visible (even if group objects are not visible themselves).
+ * It is not a true dependency, the duplicator does not in any way depend on group objects or data!
+ */
if (ob->transflag & OB_DUPLI) {
+ /* XXX In theory it would be possible to disable the visibility dependency when dupli groups are cached,
+ * since we use the results from the cache instead of the generated object data anyway.
+ * However, the caching system depends a lot on DNA objects currently and behaves unpredictably without this ...
+ */
+#if 0
+ bool is_cached = ob->cache_library && ob->cache_library->source_mode == CACHE_LIBRARY_SOURCE_CACHE;
+ if (!is_cached && (ob->transflag & OB_DUPLIGROUP) && ob->dup_group) {
+#else
if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) {
+#endif
GroupObject *go;
for (go = ob->dup_group->gobject.first; go; go = go->next) {
if (go->ob) {
@@ -793,7 +817,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
}
}
- effectors = pdInitEffectors(scene, ob, psys, part->effector_weights, false);
+ effectors = pdInitEffectors_ex(scene, ob, psys, ob->lay, part->effector_weights, false);
if (effectors) {
for (eff = effectors->first; eff; eff = eff->next) {
@@ -827,7 +851,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
/* object constraints */
for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -895,7 +919,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation");
}
-static void build_dag_group(DagForest *dag, DagNode *scenenode, Scene *scene, Group *group, short mask)
+static void build_dag_group(DagForest *dag, DagNode *scenenode, Main *bmain, Scene *scene, Group *group, short mask)
{
GroupObject *go;
@@ -905,9 +929,9 @@ static void build_dag_group(DagForest *dag, DagNode *scenenode, Scene *scene, Gr
group->id.flag |= LIB_DOIT;
for (go = group->gobject.first; go; go = go->next) {
- build_dag_object(dag, scenenode, scene, go->ob, mask);
+ build_dag_object(dag, scenenode, bmain, scene, go->ob, mask);
if (go->ob->dup_group)
- build_dag_group(dag, scenenode, scene, go->ob->dup_group, mask);
+ build_dag_group(dag, scenenode, bmain, scene, go->ob->dup_group, mask);
}
}
@@ -940,11 +964,11 @@ DagForest *build_dag(Main *bmain, Scene *sce, short mask)
for (base = sce->base.first; base; base = base->next) {
ob = base->object;
- build_dag_object(dag, scenenode, sce, ob, mask);
+ build_dag_object(dag, scenenode, bmain, sce, ob, mask);
if (ob->proxy)
- build_dag_object(dag, scenenode, sce, ob->proxy, mask);
+ build_dag_object(dag, scenenode, bmain, sce, ob->proxy, mask);
if (ob->dup_group)
- build_dag_group(dag, scenenode, sce, ob->dup_group, mask);
+ build_dag_group(dag, scenenode, bmain, sce, ob->dup_group, mask);
}
BKE_main_id_tag_idcode(bmain, ID_GR, false);
@@ -964,6 +988,10 @@ DagForest *build_dag(Main *bmain, Scene *sce, short mask)
/* also flush custom data mask */
((Object *)node->ob)->customdata_mask = node->customdata_mask;
+
+ if (node->parent == NULL) {
+ dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation");
+ }
}
}
/* now set relations equal, so that when only one parent changes, the correct recalcs are found */
@@ -1329,8 +1357,14 @@ static void (*EditorsUpdateSceneCb)(Main *bmain, Scene *scene, int updated) = NU
void DAG_editors_update_cb(void (*id_func)(Main *bmain, ID *id), void (*scene_func)(Main *bmain, Scene *scene, int updated))
{
- EditorsUpdateIDCb = id_func;
- EditorsUpdateSceneCb = scene_func;
+ if (DEG_depsgraph_use_legacy()) {
+ EditorsUpdateIDCb = id_func;
+ EditorsUpdateSceneCb = scene_func;
+ }
+ else {
+ /* New dependency graph. */
+ DEG_editors_set_update_cb(id_func, scene_func);
+ }
}
static void dag_editors_id_update(Main *bmain, ID *id)
@@ -1529,7 +1563,7 @@ static void dag_scene_build(Main *bmain, Scene *sce)
Base *base;
BLI_listbase_clear(&tempbase);
-
+
build_dag(bmain, sce, DAG_RL_ALL_BUT_DATA);
dag_check_cycle(sce->theDag);
@@ -1621,32 +1655,65 @@ static void dag_scene_build(Main *bmain, Scene *sce)
/* clear all dependency graphs */
void DAG_relations_tag_update(Main *bmain)
{
- Scene *sce;
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next)
- dag_scene_free(sce);
+ if (DEG_depsgraph_use_legacy()) {
+ Scene *sce;
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
+ dag_scene_free(sce);
+ }
+ }
+ else {
+ /* New dependency graph. */
+ DEG_relations_tag_update(bmain);
+ }
}
/* rebuild dependency graph only for a given scene */
void DAG_scene_relations_rebuild(Main *bmain, Scene *sce)
{
- dag_scene_free(sce);
- DAG_scene_relations_update(bmain, sce);
+ if (DEG_depsgraph_use_legacy()) {
+ dag_scene_free(sce);
+ DAG_scene_relations_update(bmain, sce);
+ }
+ else {
+ /* New dependency graph. */
+ DEG_scene_relations_rebuild(bmain, sce);
+ }
}
/* create dependency graph if it was cleared or didn't exist yet */
void DAG_scene_relations_update(Main *bmain, Scene *sce)
{
- if (!sce->theDag)
- dag_scene_build(bmain, sce);
+ if (DEG_depsgraph_use_legacy()) {
+ if (!sce->theDag)
+ dag_scene_build(bmain, sce);
+ }
+ else {
+ /* New dependency graph. */
+ DEG_scene_relations_update(bmain, sce);
+ }
+}
+
+void DAG_scene_relations_validate(Main *bmain, Scene *sce)
+{
+ if (!DEG_depsgraph_use_legacy()) {
+ DEG_debug_scene_relations_validate(bmain, sce);
+ }
}
void DAG_scene_free(Scene *sce)
{
- if (sce->theDag) {
- free_forest(sce->theDag);
- MEM_freeN(sce->theDag);
- sce->theDag = NULL;
+ if (DEG_depsgraph_use_legacy()) {
+ if (sce->theDag) {
+ free_forest(sce->theDag);
+ MEM_freeN(sce->theDag);
+ sce->theDag = NULL;
+ }
+ }
+ else {
+ if (sce->depsgraph) {
+ DEG_graph_free(sce->depsgraph);
+ sce->depsgraph = NULL;
+ }
}
}
@@ -1889,7 +1956,11 @@ void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const sho
DagAdjList *itA;
Object *ob;
int lasttime;
-
+
+ if (!DEG_depsgraph_use_legacy()) {
+ return;
+ }
+
if (sce->theDag == NULL) {
printf("DAG zero... not allowed to happen!\n");
DAG_scene_relations_update(bmain, sce);
@@ -2015,7 +2086,7 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob)
if (ob->constraints.first) {
bConstraint *con;
for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -2141,6 +2212,10 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob)
}
}
+ /* invalidate dupli cache */
+ if (ob->dup_cache)
+ ob->dup_cache->flag |= DUPCACHE_FLAG_DIRTY;
+
if (ob->recalc & OB_RECALC_OB)
lib_id_recalc_tag(bmain, &ob->id);
if (ob->recalc & OB_RECALC_DATA)
@@ -2229,6 +2304,90 @@ void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const b
}
}
+void DAG_scene_update_group_flags(Main *bmain,
+ Scene *scene,
+ Group *group,
+ unsigned int lay,
+ const bool do_time,
+ const bool do_invisible_flush)
+{
+ DagNode *root_node = scene->theDag->DagNode.first, *node;
+ GroupObject *go;
+ DagNodeQueue *queue;
+
+ /* Tag all possible objects for update. */
+ DAG_scene_update_flags(bmain, scene, lay, do_time, do_invisible_flush);
+
+ /* Initialize colors of nodes. */
+ for (node = root_node; node != NULL; node = node->next) {
+ node->color = DAG_WHITE;
+ node->scheduled = false;
+ }
+
+ /* Tag nodes which corresponds to objects which are to be updated. */
+ for (go = group->gobject.first; go != NULL; go = go->next) {
+ if (go->ob != NULL) {
+ node = dag_find_node(scene->theDag, go->ob);
+ if (node != NULL) {
+ node->scheduled = true;
+ }
+ }
+ }
+
+ /* Flush schedule flags to parent. */
+ queue = queue_create(DAGQUEUEALLOC);
+ for (node = root_node; node != NULL; node = node->next) {
+ if (node->color == DAG_WHITE) {
+ push_stack(queue, node);
+ node->color = DAG_GRAY;
+ while (queue->count) {
+ DagNode *current_node = get_top_node_queue(queue);
+ DagAdjList *itA;
+ bool skip = false;
+ /* Check if all child nodes were scheduled. */
+ for (itA = current_node->child; itA; itA = itA->next) {
+ if (itA->node->color == DAG_WHITE) {
+ itA->node->color = DAG_GRAY;
+ push_stack(queue, itA->node);
+ skip = true;
+ break;
+ }
+ }
+ /* Check if there are scheduled children and if so schedule
+ * current node as well since it's needed for chidlren.
+ */
+ if (!skip) {
+ current_node = pop_queue(queue);
+ if (current_node->type == ID_OB) {
+ for (itA = current_node->child; itA; itA = itA->next) {
+ if (itA->node->scheduled) {
+ current_node->scheduled = true;
+ break;
+ }
+ }
+ }
+ node->color = DAG_BLACK;
+ }
+ }
+ }
+ }
+ queue_delete(queue);
+
+ /* Clear recalc flags from objects which corresponds to nodes which are
+ * not needed for the interesting group update.
+ */
+ for (node = root_node; node != NULL; node = node->next) {
+ if (node->type == ID_OB) {
+ Object *object = node->ob;
+ if (!node->scheduled) {
+ object->recalc &= ~OB_RECALC_ALL;
+ }
+ }
+ node->color = DAG_WHITE;
+ node->scheduled = false;
+ }
+}
+
/* struct returned by DagSceneLayer */
typedef struct DagSceneLayer {
struct DagSceneLayer *next, *prev;
@@ -2300,7 +2459,7 @@ static void dag_current_scene_layers(Main *bmain, ListBase *lb)
}
}
-static void dag_group_on_visible_update(Group *group)
+static void dag_group_on_visible_update(Scene *scene, Group *group)
{
GroupObject *go;
@@ -2322,7 +2481,7 @@ static void dag_group_on_visible_update(Group *group)
}
if (go->ob->dup_group)
- dag_group_on_visible_update(go->ob->dup_group);
+ dag_group_on_visible_update(scene, go->ob->dup_group);
}
}
@@ -2330,7 +2489,13 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
{
ListBase listbase;
DagSceneLayer *dsl;
-
+
+ if (!DEG_depsgraph_use_legacy()) {
+ /* Inform new dependnecy graphs about visibility changes. */
+ DEG_on_visible_update(bmain, do_time);
+ return;
+ }
+
/* get list of visible scenes and layers */
dag_current_scene_layers(bmain, &listbase);
@@ -2357,7 +2522,8 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
oblay = (node) ? node->lay : ob->lay;
if ((oblay & lay) & ~scene->lay_updated) {
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
+ /* TODO(sergey): Why do we need armature here now but didn't need before? */
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE, OB_ARMATURE)) {
ob->recalc |= OB_RECALC_DATA;
lib_id_recalc_tag(bmain, &ob->id);
}
@@ -2375,7 +2541,7 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
lib_id_recalc_tag(bmain, &ob->id);
}
if (ob->dup_group)
- dag_group_on_visible_update(ob->dup_group);
+ dag_group_on_visible_update(scene, ob->dup_group);
}
}
@@ -2550,7 +2716,7 @@ static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id)
for (obt = bmain->object.first; obt; obt = obt->id.next) {
bConstraint *con;
for (con = obt->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER,
CONSTRAINT_TYPE_OBJECTSOLVER))
{
@@ -2600,6 +2766,21 @@ static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id)
}
}
}
+
+ /* set flags based on CacheLibrary */
+ if (idtype == ID_CL) {
+ for (obt = bmain->object.first; obt; obt = obt->id.next) {
+ if (!(ob && obt == ob) && ((ID *)obt->cache_library == id)) {
+ obt->flag |= (OB_RECALC_OB | OB_RECALC_DATA);
+ lib_id_recalc_tag(bmain, &obt->id);
+ lib_id_recalc_data_tag(bmain, &obt->id);
+
+ /* invalidate dupli cache */
+ if (obt->dup_cache)
+ obt->dup_cache->flag |= DUPCACHE_FLAG_DIRTY;
+ }
+ }
+ }
/* camera's matrix is used to orient reconstructed stuff,
* so it should happen tracking-related constraints recalculation
@@ -2623,7 +2804,12 @@ void DAG_ids_flush_tagged(Main *bmain)
ListBase *lbarray[MAX_LIBARRAY];
int a;
bool do_flush = false;
-
+
+ if (!DEG_depsgraph_use_legacy()) {
+ DEG_ids_flush_tagged(bmain);
+ return;
+ }
+
/* get list of visible scenes and layers */
dag_current_scene_layers(bmain, &listbase);
@@ -2667,6 +2853,11 @@ void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
int a;
bool updated = false;
+ if (!DEG_depsgraph_use_legacy()) {
+ DEG_ids_check_recalc(bmain, scene, time);
+ return;
+ }
+
/* loop over all ID types */
a = set_listbasepointers(bmain, lbarray);
@@ -2783,6 +2974,11 @@ void DAG_ids_clear_recalc(Main *bmain)
void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
{
+ if (!DEG_depsgraph_use_legacy()) {
+ DEG_id_tag_update_ex(bmain, id, flag);
+ return;
+ }
+
if (id == NULL) return;
if (G.debug & G_DEBUG_DEPSGRAPH) {
@@ -2934,7 +3130,7 @@ void DAG_pose_sort(Object *ob)
addtoroot = 0;
}
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -3174,6 +3370,10 @@ short DAG_get_eval_flags_for_object(Scene *scene, void *object)
{
DagNode *node;
+ if (!DEG_depsgraph_use_legacy()) {
+ return DEG_get_eval_flags_for_id(scene->depsgraph, (ID *)object);
+ }
+
if (scene->theDag == NULL) {
/* Happens when converting objects to mesh from a python script
* after modifying scene graph.
@@ -3212,3 +3412,286 @@ bool DAG_is_acyclic(Scene *scene)
{
return scene->theDag->is_acyclic;
}
+
+#else
+
+/* *********************************************************************
+ * Stubs to avoid linking issues and make sure legacy crap is not used *
+ * *********************************************************************
+ */
+
+DagNodeQueue *queue_create(int UNUSED(slots))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+void queue_raz(DagNodeQueue *UNUSED(queue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void queue_delete(DagNodeQueue *UNUSED(queue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void push_queue(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void push_stack(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+DagNode *pop_queue(DagNodeQueue *UNUSED(queue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagNode *get_top_node_queue(DagNodeQueue *UNUSED(queue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagForest *dag_init(void)
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagForest *build_dag(Main *UNUSED(bmain),
+ Scene *UNUSED(sce),
+ short UNUSED(mask))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+void free_forest(DagForest *UNUSED(Dag))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+DagNode *dag_find_node(DagForest *UNUSED(forest), void *UNUSED(fob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagNode *dag_add_node(DagForest *UNUSED(forest), void *UNUSED(fob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagNode *dag_get_node(DagForest *UNUSED(forest), void *UNUSED(fob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagNode *dag_get_sub_node(DagForest *UNUSED(forest), void *UNUSED(fob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+void dag_add_relation(DagForest *UNUSED(forest),
+ DagNode *UNUSED(fob1),
+ DagNode *UNUSED(fob2),
+ short UNUSED(rel),
+ const char *UNUSED(name))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+/* debug test functions */
+
+void graph_print_queue(DagNodeQueue *UNUSED(nqueue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void graph_print_queue_dist(DagNodeQueue *UNUSED(nqueue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void graph_print_adj_list(DagForest *UNUSED(dag))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void DAG_scene_flush_update(Main *UNUSED(bmain),
+ Scene *UNUSED(sce),
+ unsigned int UNUSED(lay),
+ const short UNUSED(time))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void DAG_scene_update_flags(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ unsigned int UNUSED(lay),
+ const bool UNUSED(do_time),
+ const bool UNUSED(do_invisible_flush))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+/* ******************* DAG FOR ARMATURE POSE ***************** */
+
+void DAG_pose_sort(Object *UNUSED(ob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+/* ************************ DAG FOR THREADED UPDATE ********************* */
+
+void DAG_threaded_update_begin(Scene *UNUSED(scene),
+ void (*func)(void *node, void *user_data),
+ void *UNUSED(user_data))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ (void)func;
+}
+
+void DAG_threaded_update_handle_node_updated(void *UNUSED(node_v),
+ void (*func)(void *node, void *user_data),
+ void *UNUSED(user_data))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ (void)func;
+}
+
+/* ************************ DAG querying ********************* */
+
+Object *DAG_get_node_object(void *UNUSED(node_v))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+const char *DAG_get_node_name(Scene *UNUSED(scene), void *UNUSED(node_v))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return "INVALID";
+}
+
+bool DAG_is_acyclic(Scene *UNUSED(scene))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return false;
+}
+
+/* ************************************
+ * This functions are to be supported *
+ * ************************************
+ */
+
+void DAG_init(void)
+{
+ DEG_register_node_types();
+}
+
+void DAG_exit(void)
+{
+ DEG_free_node_types();
+}
+
+/* ************************ API *********************** */
+
+void DAG_editors_update_cb(DEG_EditorUpdateIDCb id_func,
+ DEG_EditorUpdateSceneCb scene_func)
+{
+ DEG_editors_set_update_cb(id_func, scene_func);
+}
+
+/* Tag all relations for update. */
+void DAG_relations_tag_update(Main *bmain)
+{
+ DEG_relations_tag_update(bmain);
+}
+
+/* Rebuild dependency graph only for a given scene. */
+void DAG_scene_relations_rebuild(Main *bmain, Scene *scene)
+{
+ DEG_scene_relations_rebuild(bmain, scene);
+}
+
+/* Create dependency graph if it was cleared or didn't exist yet. */
+void DAG_scene_relations_update(Main *bmain, Scene *scene)
+{
+ DEG_scene_relations_update(bmain, scene);
+}
+
+void DAG_scene_relations_validate(Main *bmain, Scene *scene)
+{
+ DEG_debug_scene_relations_validate(bmain, scene);
+}
+
+void DAG_scene_free(Scene *scene)
+{
+ DEG_scene_graph_free(scene);
+}
+
+void DAG_on_visible_update(Main *bmain, const bool do_time)
+{
+ DEG_on_visible_update(bmain, do_time);
+}
+
+void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
+{
+ DEG_ids_check_recalc(bmain, scene, time);
+}
+
+void DAG_id_tag_update(ID *id, short flag)
+{
+ DEG_id_tag_update_ex(G.main, id, flag);
+}
+
+void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
+{
+ DEG_id_tag_update_ex(bmain, id, flag);
+}
+
+void DAG_id_type_tag(Main *bmain, short idtype)
+{
+ DEG_id_type_tag(bmain, idtype);
+}
+
+int DAG_id_type_tagged(Main *bmain, short idtype)
+{
+ return DEG_id_type_tagged(bmain, idtype);
+}
+
+void DAG_ids_clear_recalc(Main *bmain)
+{
+ DEG_ids_clear_recalc(bmain);
+}
+
+short DAG_get_eval_flags_for_object(Scene *scene, void *object)
+{
+ return DEG_get_eval_flags_for_id(scene->depsgraph, (ID *)object);
+}
+
+void DAG_ids_flush_tagged(Main *bmain)
+{
+ DEG_ids_flush_tagged(bmain);
+}
+
+/* ************************ DAG DEBUGGING ********************* */
+
+void DAG_print_dependencies(Main *UNUSED(bmain),
+ Scene *scene,
+ Object *UNUSED(ob))
+{
+ DEG_debug_graphviz(scene->depsgraph, stdout, "Depsgraph", false);
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index dd92a82bed2..336d2c1a59b 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -53,6 +53,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_object.h"
#include "BKE_mball.h"
+#include "BKE_mball_tessellate.h"
#include "BKE_curve.h"
#include "BKE_key.h"
#include "BKE_anim.h"
@@ -763,7 +764,7 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, Object *ob,
pretessellatePoint = NULL;
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!modifier_isEnabled(scene, md, required_mode))
continue;
@@ -832,7 +833,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
if (pretessellatePoint) {
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -933,7 +934,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
}
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
ModifierApplyFlag appf = app_flag;
md->scene = scene;
@@ -1164,7 +1165,7 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
orcodm = create_orco_dm(scene, ob);
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -1434,9 +1435,8 @@ static void calc_bevfac_mapping(Curve *cu, BevList *bl, Nurb *nu,
return;
}
- if (ELEM(cu->bevfac1_mapping,
- CU_BEVFAC_MAP_SEGMENT,
- CU_BEVFAC_MAP_SPLINE))
+ if (ELEM(cu->bevfac1_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE) ||
+ ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE))
{
for (i = 0; i < SEGMENTSU(nu); i++) {
total_length += bl->seglen[i];
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 762b24dfdf8..ce9e85c6813 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -527,7 +527,7 @@ static int subframe_updateObject(Scene *scene, Object *ob, int flags, int parent
/* also update constraint targets */
for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
if (cti && cti->get_constraint_targets) {
@@ -579,7 +579,7 @@ static void scene_setSubframe(Scene *scene, float subframe)
scene->r.subframe = subframe;
}
-static int surface_getBrushFlags(DynamicPaintSurface *surface, Scene *scene)
+static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scene)
{
Base *base = NULL;
GroupObject *go = NULL;
@@ -1447,7 +1447,7 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int for
MEM_freeN(temp_data);
}
-static void dynamicPaint_setInitialColor(Scene *scene, DynamicPaintSurface *surface)
+static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface *surface)
{
PaintSurfaceData *sData = surface->data;
PaintPoint *pPoint = (PaintPoint *)sData->type_data;
@@ -1595,7 +1595,7 @@ static void dynamicPaint_setInitialColor(Scene *scene, DynamicPaintSurface *surf
}
/* clears surface data back to zero */
-void dynamicPaint_clearSurface(Scene *scene, DynamicPaintSurface *surface)
+void dynamicPaint_clearSurface(const Scene *scene, DynamicPaintSurface *surface)
{
PaintSurfaceData *sData = surface->data;
if (sData && sData->type_data) {
@@ -1620,7 +1620,7 @@ void dynamicPaint_clearSurface(Scene *scene, DynamicPaintSurface *surface)
}
/* completely (re)initializes surface (only for point cache types)*/
-bool dynamicPaint_resetSurface(Scene *scene, DynamicPaintSurface *surface)
+bool dynamicPaint_resetSurface(const Scene *scene, DynamicPaintSurface *surface)
{
int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
/* free existing data */
@@ -1647,7 +1647,7 @@ bool dynamicPaint_resetSurface(Scene *scene, DynamicPaintSurface *surface)
}
/* make sure allocated surface size matches current requirements */
-static bool dynamicPaint_checkSurfaceData(Scene *scene, DynamicPaintSurface *surface)
+static bool dynamicPaint_checkSurfaceData(const Scene *scene, DynamicPaintSurface *surface)
{
if (!surface->data || ((dynamicPaint_surfaceNumOfPoints(surface) != surface->data->total_points))) {
return dynamicPaint_resetSurface(scene, surface);
@@ -2964,15 +2964,16 @@ static void mesh_faces_nearest_point_dp(void *userdata, int index, const float c
/**
* Mix color values to canvas point.
*
- * \param surface canvas surface
- * \param index surface point index
- * \param paintFlags paint object flags
- * \param paintColor,Alpha,Wetness to be mixed paint values
- * \param timescale value used to adjust time dependent
+ * \param surface: Canvas surface
+ * \param index: Surface point index
+ * \param paintFlags: paint object flags
+ * \param paintColor,paintAlpha,paintWetness: To be mixed paint values
+ * \param timescale: Value used to adjust time dependent
* operations when using substeps
*/
-static void dynamicPaint_mixPaintColors(DynamicPaintSurface *surface, int index, int paintFlags,
- const float paintColor[3], float *paintAlpha, float *paintWetness, float *timescale)
+static void dynamicPaint_mixPaintColors(
+ DynamicPaintSurface *surface, int index, int paintFlags,
+ const float paintColor[3], float *paintAlpha, float *paintWetness, float *timescale)
{
PaintPoint *pPoint = &((PaintPoint *)surface->data->type_data)[index];
@@ -4220,7 +4221,7 @@ static int dynamicPaint_prepareEffectStep(DynamicPaintSurface *surface, Scene *s
/* Init force data if required */
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
float vel[3] = {0};
- ListBase *effectors = pdInitEffectors(scene, ob, NULL, surface->effector_weights, true);
+ ListBase *effectors = pdInitEffectors(scene, ob, NULL, surface->effector_weights);
/* allocate memory for force data (dir vector + strength) */
*force = MEM_mallocN(sData->total_points * 4 * sizeof(float), "PaintEffectForces");
@@ -4696,7 +4697,7 @@ static int dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob
return ret;
}
-static int surface_needsVelocityData(DynamicPaintSurface *surface, Scene *scene)
+static int surface_needsVelocityData(DynamicPaintSurface *surface, const Scene *scene)
{
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP)
return 1;
@@ -4716,7 +4717,7 @@ static int surface_needsAccelerationData(DynamicPaintSurface *surface)
}
/* Prepare for surface step by creating PaintBakeNormal data */
-static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, Scene *scene, Object *ob)
+static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Scene *scene, Object *ob)
{
PaintSurfaceData *sData = surface->data;
PaintAdjData *adj_data = sData->adj_data;
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index 082edb01efd..fbce501f57f 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -521,8 +521,6 @@ static void emDM_drawMappedFaces(DerivedMesh *dm,
GLenum poly_prev = GL_ZERO;
GLenum shade_prev = GL_ZERO;
- (void)setMaterial; /* UNUSED */
-
/* currently unused -- each original face is handled separately */
(void)compareDrawOptions;
@@ -539,6 +537,8 @@ static void emDM_drawMappedFaces(DerivedMesh *dm,
}
if (bmdm->vertexCos) {
+ short prev_mat_nr = -1;
+
/* add direct access */
const float (*vertexCos)[3] = bmdm->vertexCos;
const float (*vertexNos)[3];
@@ -569,8 +569,14 @@ static void emDM_drawMappedFaces(DerivedMesh *dm,
setDrawOptions(userData, BM_elem_index_get(efa)));
if (draw_option != DM_DRAW_OPTION_SKIP) {
const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
- if (setMaterial)
- setMaterial(efa->mat_nr + 1, NULL);
+
+ if (efa->mat_nr != prev_mat_nr) {
+ if (setMaterial) {
+ setMaterial(efa->mat_nr + 1, NULL);
+ }
+ prev_mat_nr = efa->mat_nr;
+ }
+
if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */
if (poly_prev != GL_ZERO) glEnd();
@@ -645,6 +651,8 @@ static void emDM_drawMappedFaces(DerivedMesh *dm,
}
}
else {
+ short prev_mat_nr = -1;
+
BM_mesh_elem_index_ensure(bm, lnors ? BM_FACE | BM_LOOP : BM_FACE);
for (i = 0; i < tottri; i++) {
@@ -661,8 +669,12 @@ static void emDM_drawMappedFaces(DerivedMesh *dm,
if (draw_option != DM_DRAW_OPTION_SKIP) {
const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
- if (setMaterial)
- setMaterial(efa->mat_nr + 1, NULL);
+ if (efa->mat_nr != prev_mat_nr) {
+ if (setMaterial) {
+ setMaterial(efa->mat_nr + 1, NULL);
+ }
+ prev_mat_nr = efa->mat_nr;
+ }
if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */
@@ -985,7 +997,7 @@ static void emDM_drawMappedFacesTex(DerivedMesh *dm,
* ... because the material may use layer names to select different UV's
* see: [#34378]
*/
-static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const BMLoop *loop, const int index_in_face)
+static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const BMLoop *loop, const int index_in_face, const int face_index)
{
BMVert *eve = loop->v;
int i;
@@ -1028,7 +1040,7 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
glVertexAttrib4ubvARB(attribs->mcol[i].gl_index, col);
}
if (attribs->tottang) {
- int index = i * 4 + index_in_face;
+ int index = face_index * 4 + index_in_face;
const float *tang = (attribs->tang.array) ? attribs->tang.array[index] : zero;
glVertexAttrib4fvARB(attribs->tang.gl_index, tang);
}
@@ -1100,14 +1112,14 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm,
if (vertexCos) {
glNormal3fv(polyNos[BM_elem_index_get(efa)]);
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]);
}
}
else {
glNormal3fv(efa->no);
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
glVertex3fv(ltri[fi]->v->co);
}
}
@@ -1116,7 +1128,7 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm,
if (vertexCos) {
for (fi = 0; fi < 3; fi++) {
const int j = BM_elem_index_get(ltri[fi]->v);
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
else glNormal3fv(vertexNos[j]);
glVertex3fv(vertexCos[j]);
@@ -1124,7 +1136,7 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm,
}
else {
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
else glNormal3fv(ltri[fi]->v->no);
glVertex3fv(ltri[fi]->v->co);
@@ -1204,14 +1216,14 @@ static void emDM_drawMappedFacesMat(DerivedMesh *dm,
if (vertexCos) {
glNormal3fv(polyNos[BM_elem_index_get(efa)]);
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]);
}
}
else {
glNormal3fv(efa->no);
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
glVertex3fv(ltri[fi]->v->co);
}
}
@@ -1220,7 +1232,7 @@ static void emDM_drawMappedFacesMat(DerivedMesh *dm,
if (vertexCos) {
for (fi = 0; fi < 3; fi++) {
const int j = BM_elem_index_get(ltri[fi]->v);
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
else glNormal3fv(vertexNos[j]);
glVertex3fv(vertexCos[j]);
@@ -1228,7 +1240,7 @@ static void emDM_drawMappedFacesMat(DerivedMesh *dm,
}
else {
for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi);
+ emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i);
if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
else glNormal3fv(ltri[fi]->v->no);
glVertex3fv(ltri[fi]->v->co);
@@ -1968,7 +1980,7 @@ static void statvis_calc_thickness(
BLI_assert(min <= max);
- fill_vn_fl(face_dists, em->bm->totface, max);
+ copy_vn_fl(face_dists, em->bm->totface, max);
if (use_jit) {
int j;
@@ -2223,7 +2235,7 @@ static void statvis_calc_sharp(
(void)vertexCos; /* TODO */
- fill_vn_fl(vert_angles, em->bm->totvert, -M_PI);
+ copy_vn_fl(vert_angles, em->bm->totvert, -M_PI);
/* first assign float values to verts */
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
@@ -2253,7 +2265,7 @@ static void statvis_calc_sharp(
}
void BKE_editmesh_statvis_calc(BMEditMesh *em, DerivedMesh *dm,
- MeshStatVis *statvis)
+ const MeshStatVis *statvis)
{
EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
BLI_assert(dm == NULL || dm->type == DM_TYPE_EDITBMESH);
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 2247b91df1d..87a5c6f149f 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -246,3 +246,21 @@ void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype)
break;
}
}
+
+float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3]
+{
+ BMIter iter;
+ BMVert *eve;
+ float (*orco)[3];
+ int i;
+
+ orco = MEM_mallocN(em->bm->totvert * sizeof(*orco), __func__);
+
+ BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ copy_v3_v3(orco[i], eve->co);
+ }
+
+ *r_numVerts = em->bm->totvert;
+
+ return orco;
+}
diff --git a/source/blender/blenkernel/intern/editstrands.c b/source/blender/blenkernel/intern/editstrands.c
new file mode 100644
index 00000000000..fcf98dfc2ee
--- /dev/null
+++ b/source/blender/blenkernel/intern/editstrands.c
@@ -0,0 +1,272 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/editstrands.c
+ * \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_mempool.h"
+
+#include "DNA_cache_library_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_strands_types.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_cache_library.h"
+#include "BKE_customdata.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_editstrands.h"
+#include "BKE_effect.h"
+#include "BKE_mesh_sample.h"
+#include "BKE_particle.h"
+
+#include "BPH_strands.h"
+
+#include "intern/bmesh_strands_conv.h"
+
+/* mat can be used to transform the dm into another space,
+ * in case the edited object is not the active object:
+ * mat = inv(M_act) * M_edit
+ */
+BMEditStrands *BKE_editstrands_create(BMesh *bm, DerivedMesh *root_dm, float mat[4][4])
+{
+ BMEditStrands *es = MEM_callocN(sizeof(BMEditStrands), __func__);
+
+ es->bm = bm;
+ es->root_dm = CDDM_copy(root_dm);
+
+ if (mat) {
+ DerivedMesh *dm = es->root_dm;
+ MVert *mv = dm->getVertArray(dm);
+ int totvert = dm->getNumVerts(dm), i;
+ for (i = 0; i < totvert; ++i, ++mv) {
+ mul_m4_v3(mat, mv->co);
+ }
+ }
+
+ return es;
+}
+
+BMEditStrands *BKE_editstrands_copy(BMEditStrands *es)
+{
+ BMEditStrands *es_copy = MEM_callocN(sizeof(BMEditStrands), __func__);
+ *es_copy = *es;
+
+ es_copy->bm = BM_mesh_copy(es->bm);
+ es_copy->root_dm = CDDM_copy(es->root_dm);
+
+ return es_copy;
+}
+
+/**
+ * \brief Return the BMEditStrands for a given object
+ */
+BMEditStrands *BKE_editstrands_from_object(Object *ob)
+{
+ {
+ ParticleSystem *psys = psys_get_current(ob);
+ if (psys && psys->hairedit)
+ return psys->hairedit;
+ }
+
+ {
+ StrandsKeyCacheModifier *skmd;
+ if (BKE_cache_modifier_strands_key_get(ob, &skmd, NULL, NULL, NULL, NULL, NULL)) {
+ if (skmd->edit)
+ return skmd->edit;
+ }
+ }
+
+ return NULL;
+}
+
+void BKE_editstrands_update_linked_customdata(BMEditStrands *es)
+{
+ BMesh *bm = es->bm;
+
+ /* this is done for BMEditMesh, but should never exist for strands */
+ BLI_assert(!CustomData_has_layer(&bm->pdata, CD_MTEXPOLY));
+}
+
+/*does not free the BMEditStrands struct itself*/
+void BKE_editstrands_free(BMEditStrands *es)
+{
+ if (es->bm)
+ BM_mesh_free(es->bm);
+ if (es->root_dm)
+ es->root_dm->release(es->root_dm);
+}
+
+/* === constraints === */
+
+BMEditStrandsLocations BKE_editstrands_get_locations(BMEditStrands *edit)
+{
+ BMesh *bm = edit->bm;
+ BMEditStrandsLocations locs = MEM_mallocN(3*sizeof(float) * bm->totvert, "editstrands locations");
+
+ BMVert *v;
+ BMIter iter;
+ int i;
+
+ BM_ITER_MESH_INDEX(v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ copy_v3_v3(locs[i], v->co);
+ }
+
+ return locs;
+}
+
+void BKE_editstrands_free_locations(BMEditStrandsLocations locs)
+{
+ MEM_freeN(locs);
+}
+
+void BKE_editstrands_solve_constraints(Object *ob, BMEditStrands *es, BMEditStrandsLocations orig)
+{
+ BKE_editstrands_ensure(es);
+
+ BPH_strands_solve_constraints(ob, es, orig);
+}
+
+static void editstrands_calc_segment_lengths(BMesh *bm)
+{
+ BMVert *root;
+ BMIter iter;
+
+ BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) {
+ BMVert *v, *vprev = NULL;
+ BMIter iter_strand;
+ BM_ITER_STRANDS_ELEM(v, &iter_strand, root, BM_VERTS_OF_STRAND) {
+ if (vprev) {
+ float length = len_v3v3(v->co, vprev->co);
+ BM_elem_float_data_named_set(&bm->vdata, vprev, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH, length);
+ }
+ vprev = v;
+ }
+ if (vprev) {
+ /* set last to 0 */
+ BM_elem_float_data_named_set(&bm->vdata, vprev, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH, 0.0f);
+ }
+ }
+}
+
+void BKE_editstrands_ensure(BMEditStrands *es)
+{
+ BM_strands_cd_flag_ensure(es->bm, 0);
+
+ if (es->flag & BM_STRANDS_DIRTY_SEGLEN) {
+ editstrands_calc_segment_lengths(es->bm);
+
+ es->flag &= ~BM_STRANDS_DIRTY_SEGLEN;
+ }
+}
+
+
+/* === cache shape key conversion === */
+
+BMesh *BKE_cache_strands_to_bmesh(struct Strands *strands, struct Key *key, float mat[4][4], int act_key_nr, DerivedMesh *dm)
+{
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_STRANDS(strands);
+ BMesh *bm;
+
+ DM_ensure_tessface(dm);
+
+ bm = BM_mesh_create(&allocsize);
+ BM_strands_bm_from_strands(bm, strands, mat, key, dm, true, act_key_nr);
+ editstrands_calc_segment_lengths(bm);
+
+ return bm;
+}
+
+struct Strands *BKE_cache_strands_from_bmesh(BMEditStrands *edit, struct Key *key, float mat[4][4], DerivedMesh *dm)
+{
+ BMesh *bm = edit ? edit->bm : NULL;
+ Strands *strands = NULL;
+
+ if (bm && dm) {
+ BVHTreeFromMesh bvhtree = {NULL};
+
+ DM_ensure_tessface(dm);
+
+ bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6);
+
+ strands = BM_strands_bm_to_strands(bm, strands, mat, key, dm, &bvhtree);
+
+ free_bvhtree_from_mesh(&bvhtree);
+ }
+
+ return strands;
+}
+
+
+/* === particle conversion === */
+
+BMesh *BKE_particles_to_bmesh(Object *ob, ParticleSystem *psys)
+{
+ ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
+
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_PSYS(psys);
+ BMesh *bm;
+
+ bm = BM_mesh_create(&allocsize);
+
+ if (psmd && psmd->dm) {
+ DM_ensure_tessface(psmd->dm);
+
+ BM_strands_bm_from_psys(bm, ob, psys, psmd->dm, true, /*psys->shapenr*/ -1);
+
+ editstrands_calc_segment_lengths(bm);
+ }
+
+ return bm;
+}
+
+void BKE_particles_from_bmesh(Object *ob, ParticleSystem *psys)
+{
+ ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
+ BMesh *bm = psys->hairedit ? psys->hairedit->bm : NULL;
+
+ if (bm) {
+ if (psmd && psmd->dm) {
+ BVHTreeFromMesh bvhtree = {NULL};
+
+ DM_ensure_tessface(psmd->dm);
+
+ bvhtree_from_mesh_faces(&bvhtree, psmd->dm, 0.0, 2, 6);
+
+ BM_strands_bm_to_psys(bm, ob, psys, psmd->dm, &bvhtree);
+
+ free_bvhtree_from_mesh(&bvhtree);
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index a9bf499cd65..4842b40bf84 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -203,18 +203,17 @@ static void add_particles_to_effectors(ListBase **effectors, Scene *scene, Effec
}
/* returns ListBase handle with objects taking part in the effecting */
-ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src,
- EffectorWeights *weights, bool precalc)
+ListBase *pdInitEffectors_ex(Scene *scene, Object *ob_src, ParticleSystem *psys_src, int layers,
+ EffectorWeights *weights, bool precalc)
{
Base *base;
- unsigned int layer= ob_src->lay;
ListBase *effectors = NULL;
if (weights->group) {
GroupObject *go;
for (go= weights->group->gobject.first; go; go= go->next) {
- if ( (go->ob->lay & layer) ) {
+ if ( (go->ob->lay & layers) ) {
if ( go->ob->pd && go->ob->pd->forcefield )
add_object_to_effectors(&effectors, scene, weights, go->ob, ob_src);
@@ -229,9 +228,9 @@ ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src
}
else {
for (base = scene->base.first; base; base= base->next) {
- if ( (base->lay & layer) ) {
+ if ( (base->lay & layers) ) {
if ( base->object->pd && base->object->pd->forcefield )
- add_object_to_effectors(&effectors, scene, weights, base->object, ob_src);
+ add_object_to_effectors(&effectors, scene, weights, base->object, ob_src);
if ( base->object->particlesystem.first ) {
ParticleSystem *psys= base->object->particlesystem.first;
@@ -249,6 +248,12 @@ ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src
return effectors;
}
+ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src,
+ EffectorWeights *weights)
+{
+ return pdInitEffectors_ex(scene, ob_src, psys_src, ob_src->lay, weights, true);
+}
+
void pdEndEffectors(ListBase **effectors)
{
if (*effectors) {
@@ -1125,10 +1130,10 @@ static void debug_data_insert(SimDebugData *debug_data, SimDebugElement *elem)
BLI_ghash_insert(debug_data->gh, elem, elem);
}
-void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], float r, float g, float b, const char *category, unsigned int hash)
+void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3],
+ float r, float g, float b, const char *category, unsigned int hash)
{
unsigned int category_hash = BLI_ghashutil_strhash_p(category);
- SimDebugElement *elem;
if (!_sim_debug_data) {
if (G.debug & G_DEBUG_SIMDATA)
@@ -1137,6 +1142,16 @@ void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[
return;
}
+ BKE_sim_debug_data_add_element_ex(_sim_debug_data, type, v1, v2, r, g, b, category_hash, hash);
+}
+
+void BKE_sim_debug_data_add_element_ex(SimDebugData *debug_data, int type, const float v1[3], const float v2[3],
+ float r, float g, float b, unsigned int category_hash, unsigned int hash)
+{
+ SimDebugElement *elem;
+ if (!debug_data)
+ return;
+
elem = MEM_callocN(sizeof(SimDebugElement), "sim debug data element");
elem->type = type;
elem->category_hash = category_hash;
@@ -1147,17 +1162,22 @@ void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[
copy_v3_v3(elem->v1, v1);
copy_v3_v3(elem->v2, v2);
- debug_data_insert(_sim_debug_data, elem);
+ debug_data_insert(debug_data, elem);
}
void BKE_sim_debug_data_remove_element(unsigned int hash)
{
+ BKE_sim_debug_data_remove_element_ex(_sim_debug_data, hash);
+}
+
+void BKE_sim_debug_data_remove_element_ex(SimDebugData *debug_data, unsigned int hash)
+{
SimDebugElement dummy;
- if (!_sim_debug_data)
+ if (!debug_data)
return;
dummy.hash = hash;
- BLI_ghash_remove(_sim_debug_data->gh, &dummy, NULL, debug_element_free);
+ BLI_ghash_remove(debug_data->gh, &dummy, NULL, debug_element_free);
}
void BKE_sim_debug_data_clear(void)
@@ -1180,7 +1200,7 @@ void BKE_sim_debug_data_clear_category(const char *category)
GHashIterator iter;
BLI_ghashIterator_init(&iter, _sim_debug_data->gh);
while (!BLI_ghashIterator_done(&iter)) {
- SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
+ const SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
BLI_ghashIterator_step(&iter); /* removing invalidates the current iterator, so step before removing */
if (elem->category_hash == category_hash)
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 81321b9dbc2..6e58513e38e 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -46,6 +46,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_easing.h"
+#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BLF_translation.h"
@@ -69,6 +70,10 @@
#define SMALL -1.0e-10
#define SELECT 1
+#ifdef WITH_PYTHON
+static ThreadMutex python_driver_lock = BLI_MUTEX_INITIALIZER;
+#endif
+
/* ************************** Data-Level Functions ************************* */
/* ---------------------- Freeing --------------------------- */
@@ -309,19 +314,23 @@ int list_find_data_fcurves(ListBase *dst, ListBase *src, const char *dataPrefix,
return matches;
}
-FCurve *rna_get_fcurve(PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **adt, bAction **action, bool *r_driven)
+FCurve *rna_get_fcurve(PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **adt,
+ bAction **action, bool *r_driven, bool *r_special)
{
- return rna_get_fcurve_context_ui(NULL, ptr, prop, rnaindex, adt, action, r_driven);
+ return rna_get_fcurve_context_ui(NULL, ptr, prop, rnaindex, adt, action, r_driven, r_special);
}
-FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *prop, int rnaindex,
- AnimData **animdata, bAction **action, bool *r_driven)
+FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **animdata,
+ bAction **action, bool *r_driven, bool *r_special)
{
FCurve *fcu = NULL;
PointerRNA tptr = *ptr;
if (animdata) *animdata = NULL;
*r_driven = false;
+ *r_special = false;
+
+ if (action) *action = NULL;
/* there must be some RNA-pointer + property combon */
if (prop && tptr.id.data && RNA_property_animateable(&tptr, prop)) {
@@ -342,10 +351,15 @@ FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *pro
path = RNA_path_from_ID_to_property(&tptr, prop);
}
+ // XXX: the logic here is duplicated with a function up above
if (path) {
/* animation takes priority over drivers */
- if (adt->action && adt->action->curves.first)
+ if (adt->action && adt->action->curves.first) {
fcu = list_find_fcurve(&adt->action->curves, path, rnaindex);
+
+ if (fcu && action)
+ *action = adt->action;
+ }
/* if not animated, check if driven */
if (!fcu && (adt->drivers.first)) {
@@ -375,6 +389,32 @@ FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *pro
}
}
}
+
+ /* if we still haven't found anything, check whether it's a "special" property */
+ if ((fcu == NULL) && (adt && adt->nla_tracks.first)) {
+ NlaTrack *nlt;
+ const char *propname = RNA_property_identifier(prop);
+
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ NlaStrip *strip;
+
+ if (fcu)
+ break;
+
+ /* FIXME: need to do recursive search here for correctness,
+ * but this will do for most use cases (i.e. interactive editing),
+ * where nested strips can't be easily edited
+ */
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ fcu = list_find_fcurve(&strip->fcurves, propname, rnaindex);
+
+ if (fcu) {
+ *r_special = true;
+ break;
+ }
+ }
+ }
+ }
}
MEM_SAFE_FREE(path);
}
@@ -1496,7 +1536,7 @@ static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = {
};
/* Get driver variable typeinfo */
-static DriverVarTypeInfo *get_dvar_typeinfo(int type)
+static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
{
/* check if valid type */
if ((type >= 0) && (type < MAX_DVAR_TYPES))
@@ -1540,7 +1580,7 @@ void driver_free_variable(ChannelDriver *driver, DriverVar *dvar)
/* Change the type of driver variable */
void driver_change_variable_type(DriverVar *dvar, int type)
{
- DriverVarTypeInfo *dvti = get_dvar_typeinfo(type);
+ const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type);
/* sanity check */
if (ELEM(NULL, dvar, dvti))
@@ -1664,7 +1704,7 @@ ChannelDriver *fcurve_copy_driver(ChannelDriver *driver)
/* Evaluate a Driver Variable to get a value that contributes to the final */
float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
{
- DriverVarTypeInfo *dvti;
+ const DriverVarTypeInfo *dvti;
/* sanity check */
if (ELEM(NULL, driver, dvar))
@@ -1772,7 +1812,9 @@ static float evaluate_driver(ChannelDriver *driver, const float evaltime)
/* this evaluates the expression using Python, and returns its result:
* - on errors it reports, then returns 0.0f
*/
+ BLI_mutex_lock(&python_driver_lock);
driver->curval = BPY_driver_exec(driver, evaltime);
+ BLI_mutex_unlock(&python_driver_lock);
}
#else /* WITH_PYTHON*/
(void)evaltime;
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index af0db5e1c47..6e78d08b508 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -1040,7 +1040,7 @@ static void fmods_init_typeinfo(void)
/* This function should be used for getting the appropriate type-info when only
* a F-Curve modifier type is known
*/
-FModifierTypeInfo *get_fmodifier_typeinfo(int type)
+const FModifierTypeInfo *get_fmodifier_typeinfo(int type)
{
/* initialize the type-info list? */
if (FMI_INIT) {
@@ -1065,7 +1065,7 @@ FModifierTypeInfo *get_fmodifier_typeinfo(int type)
/* This function should always be used to get the appropriate type-info, as it
* has checks which prevent segfaults in some weird cases.
*/
-FModifierTypeInfo *fmodifier_get_typeinfo(FModifier *fcm)
+const FModifierTypeInfo *fmodifier_get_typeinfo(FModifier *fcm)
{
/* only return typeinfo for valid modifiers */
if (fcm)
@@ -1079,7 +1079,7 @@ FModifierTypeInfo *fmodifier_get_typeinfo(FModifier *fcm)
/* Add a new F-Curve Modifier to the given F-Curve of a certain type */
FModifier *add_fmodifier(ListBase *modifiers, int type)
{
- FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
+ const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
FModifier *fcm;
/* sanity checks */
@@ -1119,7 +1119,7 @@ FModifier *add_fmodifier(ListBase *modifiers, int type)
/* Make a copy of the specified F-Modifier */
FModifier *copy_fmodifier(FModifier *src)
{
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(src);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(src);
FModifier *dst;
/* sanity check */
@@ -1153,7 +1153,7 @@ void copy_fmodifiers(ListBase *dst, ListBase *src)
BLI_duplicatelist(dst, src);
for (fcm = dst->first, srcfcm = src->first; fcm && srcfcm; srcfcm = srcfcm->next, fcm = fcm->next) {
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
/* make a new copy of the F-Modifier's data */
fcm->data = MEM_dupallocN(fcm->data);
@@ -1167,7 +1167,7 @@ void copy_fmodifiers(ListBase *dst, ListBase *src)
/* Remove and free the given F-Modifier from the given stack */
bool remove_fmodifier(ListBase *modifiers, FModifier *fcm)
{
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
/* sanity check */
if (fcm == NULL)
@@ -1266,7 +1266,7 @@ bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype)
/* find the first mdifier fitting these criteria */
for (fcm = modifiers->first; fcm; fcm = fcm->next) {
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
short mOk = 1, aOk = 1; /* by default 1, so that when only one test, won't fail */
/* check if applicable ones are fullfilled */
@@ -1296,7 +1296,7 @@ FModifierStackStorage *evaluate_fmodifiers_storage_new(ListBase *modifiers)
}
for (fcm = modifiers->last; fcm; fcm = fcm->prev) {
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
if (fmi == NULL) {
continue;
@@ -1398,7 +1398,10 @@ float evaluate_time_fmodifiers(FModifierStackStorage *storage, ListBase *modifie
/* sanity checks */
if (ELEM(NULL, modifiers, modifiers->last))
return evaltime;
-
+
+ if (fcu->flag & FCURVE_MOD_OFF)
+ return evaltime;
+
/* Starting from the end of the stack, calculate the time effects of various stacked modifiers
* on the time the F-Curve should be evaluated at.
*
@@ -1410,7 +1413,7 @@ float evaluate_time_fmodifiers(FModifierStackStorage *storage, ListBase *modifie
* (such as multiple 'stepped' modifiers in sequence, causing different stepping rates)
*/
for (fcm = modifiers->last; fcm; fcm = fcm->prev) {
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
if (fmi == NULL)
continue;
@@ -1455,10 +1458,13 @@ void evaluate_value_fmodifiers(FModifierStackStorage *storage, ListBase *modifie
/* sanity checks */
if (ELEM(NULL, modifiers, modifiers->first))
return;
+
+ if (fcu->flag & FCURVE_MOD_OFF)
+ return;
/* evaluate modifiers */
for (fcm = modifiers->first; fcm; fcm = fcm->next) {
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
if (fmi == NULL)
continue;
diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c
index cc9ad63d451..f6c4263cff7 100644
--- a/source/blender/blenkernel/intern/freestyle.c
+++ b/source/blender/blenkernel/intern/freestyle.c
@@ -179,7 +179,7 @@ static FreestyleLineSet *alloc_lineset(void)
return (FreestyleLineSet *)MEM_callocN(sizeof(FreestyleLineSet), "Freestyle line set");
}
-FreestyleLineSet *BKE_freestyle_lineset_add(FreestyleConfig *config, const char *name)
+FreestyleLineSet *BKE_freestyle_lineset_add(struct Main *bmain, FreestyleConfig *config, const char *name)
{
int lineset_index = BLI_listbase_count(&config->linesets);
@@ -187,7 +187,7 @@ FreestyleLineSet *BKE_freestyle_lineset_add(FreestyleConfig *config, const char
BLI_addtail(&config->linesets, (void *)lineset);
BKE_freestyle_lineset_set_active_index(config, lineset_index);
- lineset->linestyle = BKE_linestyle_new("LineStyle", NULL);
+ lineset->linestyle = BKE_linestyle_new(bmain, "LineStyle");
lineset->flags |= FREESTYLE_LINESET_ENABLED;
lineset->selection = FREESTYLE_SEL_VISIBILITY | FREESTYLE_SEL_EDGE_TYPES | FREESTYLE_SEL_IMAGE_BORDER;
lineset->qi = FREESTYLE_QI_VISIBLE;
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index dd2155505fb..38a84296ca6 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -119,7 +119,7 @@ void BKE_gpencil_free(bGPdata *gpd)
/* free animation data */
if (gpd->adt) {
- BKE_free_animdata(&gpd->id);
+ BKE_animdata_free(&gpd->id);
gpd->adt = NULL;
}
}
@@ -129,11 +129,11 @@ void BKE_gpencil_free(bGPdata *gpd)
/* add a new gp-frame to the given layer */
bGPDframe *gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
{
- bGPDframe *gpf, *gf;
+ bGPDframe *gpf = NULL, *gf = NULL;
short state = 0;
/* error checking (neg frame only if they are not allowed in Blender!) */
- if ((gpl == NULL) || ((U.flag & USER_NONEGFRAMES) && (cframe <= 0)))
+ if (gpl == NULL)
return NULL;
/* allocate memory for this frame */
@@ -160,8 +160,14 @@ bGPDframe *gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
/* check whether frame was added successfully */
if (state == -1) {
+ printf("Error: Frame (%d) existed already for this layer. Using existing frame\n", cframe);
+
+ /* free the newly created one, and use the old one instead */
MEM_freeN(gpf);
- printf("Error: frame (%d) existed already for this layer\n", cframe);
+
+ /* return existing frame instead... */
+ BLI_assert(gf != NULL);
+ gpf = gf;
}
else if (state == 0) {
/* add to end then! */
@@ -388,8 +394,6 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, short addnew)
/* error checking */
if (gpl == NULL) return NULL;
- /* No reason to forbid negative frames when they are allowed in Blender! */
- if ((U.flag & USER_NONEGFRAMES) && cframe <= 0) cframe = 1;
/* check if there is already an active frame */
if (gpl->actframe) {
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
index ae3ab833a87..78f8a42ffe6 100644
--- a/source/blender/blenkernel/intern/group.c
+++ b/source/blender/blenkernel/intern/group.c
@@ -36,6 +36,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_cache_library_types.h"
#include "DNA_group_types.h"
#include "DNA_material_types.h"
#include "DNA_object_types.h"
@@ -45,7 +46,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-
+#include "BKE_cache_library.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_group.h"
@@ -318,7 +319,7 @@ bool BKE_group_is_animated(Group *group, Object *UNUSED(parent))
GroupObject *go;
#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */
- if (parent->nlastrips.first)
+ if (parent && parent->nlastrips.first)
return 1;
#endif
@@ -385,7 +386,7 @@ void BKE_group_handle_recalc_and_update(EvaluationContext *eval_ctx, Scene *scen
* but when its enabled at some point it will need to be changed so as not to update so much - campbell */
/* if animated group... */
- if (parent->nlastrips.first) {
+ if (parent && parent->nlastrips.first) {
int cfrao;
/* switch to local time */
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index 8bda957f187..daf39116d76 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -45,6 +45,7 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+#include "BLI_string.h"
#include "BKE_icons.h"
#include "BKE_global.h" /* only for G.background test */
@@ -53,6 +54,10 @@
#include "GPU_extensions.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_thumbs.h"
+
/* GLOBALS */
static GHash *gIcons = NULL;
@@ -61,6 +66,7 @@ static int gNextIconId = 1;
static int gFirstIconId = 1;
+static GHash *gCachedPreviews = NULL;
static void icon_free(void *val)
{
@@ -105,30 +111,50 @@ void BKE_icons_init(int first_dyn_id)
gFirstIconId = first_dyn_id;
if (!gIcons)
- gIcons = BLI_ghash_int_new("icons_init gh");
+ gIcons = BLI_ghash_int_new(__func__);
+
+ if (!gCachedPreviews) {
+ gCachedPreviews = BLI_ghash_str_new(__func__);
+ }
}
void BKE_icons_free(void)
{
- if (gIcons)
+ if (gIcons) {
BLI_ghash_free(gIcons, NULL, icon_free);
- gIcons = NULL;
+ gIcons = NULL;
+ }
+
+ if (gCachedPreviews) {
+ BLI_ghash_free(gCachedPreviews, MEM_freeN, BKE_previewimg_freefunc);
+ gCachedPreviews = NULL;
+ }
}
-PreviewImage *BKE_previewimg_create(void)
+static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
{
PreviewImage *prv_img = NULL;
int i;
- prv_img = MEM_callocN(sizeof(PreviewImage), "img_prv");
+ prv_img = MEM_mallocN(sizeof(PreviewImage) + deferred_data_size, "img_prv");
+ memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */
+
+ if (deferred_data_size) {
+ prv_img->use_deferred = true;
+ }
for (i = 0; i < NUM_ICON_SIZES; ++i) {
- prv_img->changed[i] = 1;
+ prv_img->flag[i] |= PRV_CHANGED;
prv_img->changed_timestamp[i] = 0;
}
return prv_img;
}
+PreviewImage *BKE_previewimg_create(void)
+{
+ return previewimg_create_ex(0);
+}
+
void BKE_previewimg_freefunc(void *link)
{
PreviewImage *prv = (PreviewImage *)link;
@@ -138,7 +164,6 @@ void BKE_previewimg_freefunc(void *link)
for (i = 0; i < NUM_ICON_SIZES; ++i) {
if (prv->rect[i]) {
MEM_freeN(prv->rect[i]);
- prv->rect[i] = NULL;
}
if (prv->gputexture[i])
GPU_texture_free(prv->gputexture[i]);
@@ -156,6 +181,26 @@ void BKE_previewimg_free(PreviewImage **prv)
}
}
+void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size)
+{
+ MEM_SAFE_FREE(prv->rect[size]);
+ if (prv->gputexture[size]) {
+ GPU_texture_free(prv->gputexture[size]);
+ }
+ prv->h[size] = prv->w[size] = 0;
+ prv->flag[size] |= PRV_CHANGED;
+ prv->flag[size] &= ~PRV_USER_EDITED;
+ prv->changed_timestamp[size] = 0;
+}
+
+void BKE_previewimg_clear(struct PreviewImage *prv)
+{
+ int i;
+ for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ BKE_previewimg_clear_single(prv, i);
+ }
+}
+
PreviewImage *BKE_previewimg_copy(PreviewImage *prv)
{
PreviewImage *prv_img = NULL;
@@ -167,79 +212,186 @@ PreviewImage *BKE_previewimg_copy(PreviewImage *prv)
if (prv->rect[i]) {
prv_img->rect[i] = MEM_dupallocN(prv->rect[i]);
}
- else {
- prv_img->rect[i] = NULL;
- }
prv_img->gputexture[i] = NULL;
}
}
return prv_img;
}
-void BKE_previewimg_free_id(ID *id)
+PreviewImage **BKE_previewimg_id_get_p(ID *id)
{
- if (GS(id->name) == ID_MA) {
- Material *mat = (Material *)id;
- BKE_previewimg_free(&mat->preview);
- }
- else if (GS(id->name) == ID_TE) {
- Tex *tex = (Tex *)id;
- BKE_previewimg_free(&tex->preview);
- }
- else if (GS(id->name) == ID_WO) {
- World *wo = (World *)id;
- BKE_previewimg_free(&wo->preview);
+ switch (GS(id->name)) {
+#define ID_PRV_CASE(id_code, id_struct) case id_code: { return &((id_struct *)id)->preview; }
+ ID_PRV_CASE(ID_MA, Material);
+ ID_PRV_CASE(ID_TE, Tex);
+ ID_PRV_CASE(ID_WO, World);
+ ID_PRV_CASE(ID_LA, Lamp);
+ ID_PRV_CASE(ID_IM, Image);
+ ID_PRV_CASE(ID_BR, Brush);
+#undef ID_PRV_CASE
}
- else if (GS(id->name) == ID_LA) {
- Lamp *la = (Lamp *)id;
- BKE_previewimg_free(&la->preview);
- }
- else if (GS(id->name) == ID_IM) {
- Image *img = (Image *)id;
- BKE_previewimg_free(&img->preview);
+
+ return NULL;
+}
+
+void BKE_previewimg_id_free(ID *id)
+{
+ PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
+ if (prv_p) {
+ BKE_previewimg_free(prv_p);
}
- else if (GS(id->name) == ID_BR) {
- Brush *br = (Brush *)id;
- BKE_previewimg_free(&br->preview);
+}
+
+PreviewImage *BKE_previewimg_id_ensure(ID *id)
+{
+ PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
+
+ if (prv_p) {
+ if (*prv_p == NULL) {
+ *prv_p = BKE_previewimg_create();
+ }
+ return *prv_p;
}
+
+ return NULL;
}
-PreviewImage *BKE_previewimg_get(ID *id)
+PreviewImage *BKE_previewimg_cached_get(const char *name)
{
- PreviewImage *prv_img = NULL;
+ return BLI_ghash_lookup(gCachedPreviews, name);
+}
- if (GS(id->name) == ID_MA) {
- Material *mat = (Material *)id;
- if (!mat->preview) mat->preview = BKE_previewimg_create();
- prv_img = mat->preview;
+/**
+ * Generate an empty PreviewImage, if not yet existing.
+ */
+PreviewImage *BKE_previewimg_cached_ensure(const char *name)
+{
+ PreviewImage *prv = NULL;
+ void **prv_p;
+
+ if (!BLI_ghash_ensure_p_ex(gCachedPreviews, name, &prv_p, (GHashKeyCopyFP)BLI_strdup)) {
+ *prv_p = BKE_previewimg_create();
}
- else if (GS(id->name) == ID_TE) {
- Tex *tex = (Tex *)id;
- if (!tex->preview) tex->preview = BKE_previewimg_create();
- prv_img = tex->preview;
+ prv = *prv_p;
+ BLI_assert(prv);
+
+ return prv;
+}
+
+/**
+ * Generate a PreviewImage from given file path, using thumbnails management, if not yet existing.
+ */
+PreviewImage *BKE_previewimg_cached_thumbnail_read(
+ const char *name, const char *path, const int source, bool force_update)
+{
+ PreviewImage *prv = NULL;
+ void **prv_p;
+
+ prv_p = BLI_ghash_lookup_p(gCachedPreviews, name);
+
+ if (prv_p) {
+ prv = *prv_p;
+ BLI_assert(prv);
}
- else if (GS(id->name) == ID_WO) {
- World *wo = (World *)id;
- if (!wo->preview) wo->preview = BKE_previewimg_create();
- prv_img = wo->preview;
+
+ if (prv && force_update) {
+ const char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
+ if (((int)prv_deferred_data[0] == source) && STREQ(&prv_deferred_data[1], path)) {
+ /* If same path, no need to re-allocate preview, just clear it up. */
+ BKE_previewimg_clear(prv);
+ }
+ else {
+ BKE_previewimg_free(&prv);
+ }
}
- else if (GS(id->name) == ID_LA) {
- Lamp *la = (Lamp *)id;
- if (!la->preview) la->preview = BKE_previewimg_create();
- prv_img = la->preview;
+
+ if (!prv) {
+ /* We pack needed data for lazy loading (source type, in a single char, and path). */
+ const size_t deferred_data_size = strlen(path) + 2;
+ char *deferred_data;
+
+ prv = previewimg_create_ex(deferred_data_size);
+ deferred_data = PRV_DEFERRED_DATA(prv);
+ deferred_data[0] = source;
+ memcpy(&deferred_data[1], path, deferred_data_size - 1);
+
+ force_update = true;
}
- else if (GS(id->name) == ID_IM) {
- Image *img = (Image *)id;
- if (!img->preview) img->preview = BKE_previewimg_create();
- prv_img = img->preview;
+
+ if (force_update) {
+ if (prv_p) {
+ *prv_p = prv;
+ }
+ else {
+ BLI_ghash_insert(gCachedPreviews, BLI_strdup(name), prv);
+ }
}
- else if (GS(id->name) == ID_BR) {
- Brush *br = (Brush *)id;
- if (!br->preview) br->preview = BKE_previewimg_create();
- prv_img = br->preview;
+
+ return prv;
+}
+
+void BKE_previewimg_cached_release(const char *name)
+{
+ PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN);
+
+ if (prv) {
+ if (prv->icon_id) {
+ BKE_icon_delete(prv->icon_id);
+ }
+ BKE_previewimg_freefunc(prv);
}
+}
- return prv_img;
+/** Handle deferred (lazy) loading/generation of preview image, if needed.
+ * For now, only used with file thumbnails. */
+void BKE_previewimg_ensure(PreviewImage *prv, const int size)
+{
+ if (prv->use_deferred) {
+ const bool do_icon = ((size == ICON_SIZE_ICON) && !prv->rect[ICON_SIZE_ICON]);
+ const bool do_preview = ((size == ICON_SIZE_PREVIEW) && !prv->rect[ICON_SIZE_PREVIEW]);
+
+ if (do_icon || do_preview) {
+ ImBuf *thumb;
+ char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
+ int source = prv_deferred_data[0];
+ char *path = &prv_deferred_data[1];
+ int icon_w, icon_h;
+
+ thumb = IMB_thumb_manage(path, THB_LARGE, source);
+
+ if (thumb) {
+ /* PreviewImage assumes premultiplied alhpa... */
+ IMB_premultiply_alpha(thumb);
+
+ if (do_preview) {
+ prv->w[ICON_SIZE_PREVIEW] = thumb->x;
+ prv->h[ICON_SIZE_PREVIEW] = thumb->y;
+ prv->rect[ICON_SIZE_PREVIEW] = MEM_dupallocN(thumb->rect);
+ prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED);
+ }
+ if (do_icon) {
+ if (thumb->x > thumb->y) {
+ icon_w = ICON_RENDER_DEFAULT_HEIGHT;
+ icon_h = (thumb->y * icon_w) / thumb->x + 1;
+ }
+ else if (thumb->x < thumb->y) {
+ icon_h = ICON_RENDER_DEFAULT_HEIGHT;
+ icon_w = (thumb->x * icon_h) / thumb->y + 1;
+ }
+ else {
+ icon_w = icon_h = ICON_RENDER_DEFAULT_HEIGHT;
+ }
+
+ IMB_scaleImBuf(thumb, icon_w, icon_h);
+ prv->w[ICON_SIZE_ICON] = icon_w;
+ prv->h[ICON_SIZE_ICON] = icon_h;
+ prv->rect[ICON_SIZE_ICON] = MEM_dupallocN(thumb->rect);
+ prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED);
+ }
+ IMB_freeImBuf(thumb);
+ }
+ }
+ }
}
void BKE_icon_changed(int id)
@@ -251,20 +403,20 @@ void BKE_icon_changed(int id)
icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(id));
if (icon) {
- PreviewImage *prv = BKE_previewimg_get((ID *)icon->obj);
+ PreviewImage *prv = BKE_previewimg_id_ensure((ID *)icon->obj);
/* all previews changed */
if (prv) {
int i;
for (i = 0; i < NUM_ICON_SIZES; ++i) {
- prv->changed[i] = 1;
+ prv->flag[i] |= PRV_CHANGED;
prv->changed_timestamp[i]++;
}
}
}
}
-int BKE_icon_getid(struct ID *id)
+int BKE_icon_id_ensure(struct ID *id)
{
Icon *new_icon = NULL;
@@ -277,11 +429,11 @@ int BKE_icon_getid(struct ID *id)
id->icon_id = get_next_free_id();
if (!id->icon_id) {
- printf("BKE_icon_getid: Internal error - not enough IDs\n");
+ printf("%s: Internal error - not enough IDs\n", __func__);
return 0;
}
- new_icon = MEM_callocN(sizeof(Icon), "texicon");
+ new_icon = MEM_mallocN(sizeof(Icon), __func__);
new_icon->obj = id;
new_icon->type = GS(id->name);
@@ -295,6 +447,40 @@ int BKE_icon_getid(struct ID *id)
return id->icon_id;
}
+/**
+ * Return icon id of given preview, or create new icon if not found.
+ */
+int BKE_icon_preview_ensure(PreviewImage *preview)
+{
+ Icon *new_icon = NULL;
+
+ if (!preview || G.background)
+ return 0;
+
+ if (preview->icon_id)
+ return preview->icon_id;
+
+ preview->icon_id = get_next_free_id();
+
+ if (!preview->icon_id) {
+ printf("%s: Internal error - not enough IDs\n", __func__);
+ return 0;
+ }
+
+ new_icon = MEM_mallocN(sizeof(Icon), __func__);
+
+ new_icon->obj = preview;
+ new_icon->type = 0; /* Special, tags as non-ID icon/preview. */
+
+ /* next two lines make sure image gets created */
+ new_icon->drawinfo = NULL;
+ new_icon->drawinfo_free = NULL;
+
+ BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(preview->icon_id), new_icon);
+
+ return preview->icon_id;
+}
+
Icon *BKE_icon_get(int icon_id)
{
Icon *icon = NULL;
@@ -302,7 +488,7 @@ Icon *BKE_icon_get(int icon_id)
icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id));
if (!icon) {
- printf("BKE_icon_get: Internal error, no icon for icon ID: %d\n", icon_id);
+ printf("%s: Internal error, no icon for icon ID: %d\n", __func__, icon_id);
return NULL;
}
@@ -311,23 +497,42 @@ Icon *BKE_icon_get(int icon_id)
void BKE_icon_set(int icon_id, struct Icon *icon)
{
- Icon *old_icon = NULL;
+ void **val_p;
- old_icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id));
-
- if (old_icon) {
- printf("BKE_icon_set: Internal error, icon already set: %d\n", icon_id);
+ if (BLI_ghash_ensure_p(gIcons, SET_INT_IN_POINTER(icon_id), &val_p)) {
+ printf("%s: Internal error, icon already set: %d\n", __func__, icon_id);
return;
}
- BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(icon_id), icon);
+ *val_p = icon;
}
-void BKE_icon_delete(struct ID *id)
+void BKE_icon_id_delete(struct ID *id)
{
-
if (!id->icon_id) return; /* no icon defined for library object */
BLI_ghash_remove(gIcons, SET_INT_IN_POINTER(id->icon_id), NULL, icon_free);
id->icon_id = 0;
}
+
+/**
+ * Remove icon and free data.
+ */
+void BKE_icon_delete(int icon_id)
+{
+ Icon *icon;
+
+ if (!icon_id) return; /* no icon defined for library object */
+
+ icon = BLI_ghash_popkey(gIcons, SET_INT_IN_POINTER(icon_id), NULL);
+
+ if (icon) {
+ if (icon->type) {
+ ((ID *)(icon->obj))->icon_id = 0;
+ }
+ else {
+ ((PreviewImage *)(icon->obj))->icon_id = 0;
+ }
+ icon_free(icon);
+ }
+}
diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c
index 1b7a03ec80e..47a4414f324 100644
--- a/source/blender/blenkernel/intern/idcode.c
+++ b/source/blender/blenkernel/intern/idcode.c
@@ -53,6 +53,7 @@ static IDType idtypes[] = {
{ ID_AC, "Action", "actions", IDTYPE_FLAGS_ISLINKABLE },
{ ID_AR, "Armature", "armatures", IDTYPE_FLAGS_ISLINKABLE },
{ ID_BR, "Brush", "brushes", IDTYPE_FLAGS_ISLINKABLE },
+ { ID_CL, "CacheLibrary", "cache_libraries", IDTYPE_FLAGS_ISLINKABLE },
{ ID_CA, "Camera", "cameras", IDTYPE_FLAGS_ISLINKABLE },
{ ID_CU, "Curve", "curves", IDTYPE_FLAGS_ISLINKABLE },
{ ID_GD, "GPencil", "grease_pencil", IDTYPE_FLAGS_ISLINKABLE }, /* rename gpencil */
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 9be09e99bcc..09934c872f7 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -75,6 +75,7 @@
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
+#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_node.h"
#include "BKE_sequencer.h" /* seq_foreground_frame_get() */
@@ -99,6 +100,12 @@
static SpinLock image_spin;
+/* prototypes */
+static size_t image_num_files(struct Image *ima);
+static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock);
+static void image_update_views_format(Image *ima, ImageUser *iuser);
+static void image_add_view(Image *ima, const char *viewname, const char *filepath);
+
/* max int, to indicate we don't store sequences in ibuf */
#define IMA_NO_INDEX 0x7FEFEFEF
@@ -257,6 +264,46 @@ static void image_free_cached_frames(Image *image)
}
}
+static void image_free_packedfiles(Image *ima)
+{
+ while (ima->packedfiles.last) {
+ ImagePackedFile *imapf = ima->packedfiles.last;
+ if (imapf->packedfile) {
+ freePackedFile(imapf->packedfile);
+ }
+ BLI_remlink(&ima->packedfiles, imapf);
+ MEM_freeN(imapf);
+ }
+}
+
+void BKE_image_free_packedfiles(Image *ima)
+{
+ image_free_packedfiles(ima);
+}
+
+static void image_free_views(Image *ima)
+{
+ BLI_freelistN(&ima->views);
+}
+
+void BKE_image_free_views(Image *image)
+{
+ image_free_views(image);
+}
+
+static void image_free_anims(Image *ima)
+{
+ while (ima->anims.last) {
+ ImageAnim *ia = ima->anims.last;
+ if (ia->anim) {
+ IMB_free_anim(ia->anim);
+ ia->anim = NULL;
+ }
+ BLI_remlink(&ima->anims, ia);
+ MEM_freeN(ia);
+ }
+}
+
/**
* Simply free the image data from memory,
* on display the image can load again (except for render buffers).
@@ -265,8 +312,7 @@ void BKE_image_free_buffers(Image *ima)
{
image_free_cached_frames(ima);
- if (ima->anim) IMB_free_anim(ima->anim);
- ima->anim = NULL;
+ image_free_anims(ima);
if (ima->rr) {
RE_FreeRenderResult(ima->rr);
@@ -290,11 +336,10 @@ void BKE_image_free(Image *ima)
int a;
BKE_image_free_buffers(ima);
- if (ima->packedfile) {
- freePackedFile(ima->packedfile);
- ima->packedfile = NULL;
- }
- BKE_icon_delete(&ima->id);
+
+ image_free_packedfiles(ima);
+
+ BKE_icon_id_delete(&ima->id);
ima->id.icon_id = 0;
BKE_previewimg_free(&ima->preview);
@@ -305,6 +350,9 @@ void BKE_image_free(Image *ima)
ima->renders[a] = NULL;
}
}
+
+ image_free_views(ima);
+ MEM_freeN(ima->stereo3d_format);
}
/* only image block itself */
@@ -328,7 +376,9 @@ static Image *image_alloc(Main *bmain, const char *name, short source, short typ
ima->flag |= IMA_VIEW_AS_RENDER;
BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings);
+ ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format");
}
+
return ima;
}
@@ -359,6 +409,22 @@ static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int frame)
}
}
+static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
+{
+ const ImagePackedFile *imapf_src;
+
+ BLI_listbase_clear(lb_dst);
+ for (imapf_src = lb_src->first; imapf_src; imapf_src = imapf_src->next) {
+ ImagePackedFile *imapf_dst = MEM_mallocN(sizeof(ImagePackedFile), "Image Packed Files (copy)");
+ BLI_strncpy(imapf_dst->filepath, imapf_src->filepath, sizeof(imapf_dst->filepath));
+
+ if (imapf_src->packedfile)
+ imapf_dst->packedfile = dupPackedFile(imapf_src->packedfile);
+
+ BLI_addtail(lb_dst, imapf_dst);
+ }
+}
+
/* empty image block, of similar type and filename */
Image *BKE_image_copy(Main *bmain, Image *ima)
{
@@ -381,8 +447,10 @@ Image *BKE_image_copy(Main *bmain, Image *ima)
BKE_color_managed_colorspace_settings_copy(&nima->colorspace_settings, &ima->colorspace_settings);
- if (ima->packedfile)
- nima->packedfile = dupPackedFile(ima->packedfile);
+ copy_image_packedfiles(&nima->packedfiles, &ima->packedfiles);
+
+ nima->stereo3d_format = MEM_dupallocN(ima->stereo3d_format);
+ BLI_duplicatelist(&nima->views, &ima->views);
if (ima->id.lib) {
BKE_id_lib_local_paths(bmain, ima->id.lib, &nima->id);
@@ -686,7 +754,9 @@ Image *BKE_image_load_exists_ex(const char *filepath, bool *r_exists)
BLI_path_abs(strtest, ID_BLEND_PATH(G.main, &ima->id));
if (BLI_path_cmp(strtest, str) == 0) {
- if (ima->anim == NULL || ima->id.us == 0) {
+ if ((BKE_image_has_anim(ima) == false) ||
+ (ima->id.us == 0))
+ {
ima->id.us++; /* officially should not, it doesn't link here! */
if (ima->ok == 0)
ima->ok = IMA_OK;
@@ -774,13 +844,14 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char
}
/* adds new image block, creates ImBuf and initializes color */
-Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4])
+Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4], const bool stereo3d)
{
/* on save, type is changed to FILE in editsima.c */
Image *ima = image_alloc(bmain, name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
if (ima) {
- ImBuf *ibuf;
+ size_t view_id;
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
/* BLI_strncpy(ima->name, name, FILE_MAX); */ /* don't do this, this writes in ain invalid filepath! */
ima->gen_x = width;
@@ -790,13 +861,21 @@ Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int hei
ima->gen_depth = depth;
copy_v4_v4(ima->gen_color, color);
- ibuf = add_ibuf_size(width, height, ima->name, depth, floatbuf, gen_type, color, &ima->colorspace_settings);
- image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ for (view_id = 0; view_id < 2; view_id++) {
+ ImBuf *ibuf;
+ ibuf = add_ibuf_size(width, height, ima->name, depth, floatbuf, gen_type, color, &ima->colorspace_settings);
+ image_assign_ibuf(ima, ibuf, stereo3d ? view_id : IMA_NO_INDEX, 0);
- /* image_assign_ibuf puts buffer to the cache, which increments user counter. */
- IMB_freeImBuf(ibuf);
+ /* image_assign_ibuf puts buffer to the cache, which increments user counter. */
+ IMB_freeImBuf(ibuf);
+ if (!stereo3d) break;
+
+ image_add_view(ima, names[view_id], "");
+ }
ima->ok = IMA_OK_LOADED;
+ if (stereo3d)
+ ima->flag |= IMA_IS_STEREO | IMA_IS_MULTIVIEW;
}
return ima;
@@ -805,12 +884,16 @@ Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int hei
/* Create an image image from ibuf. The refcount of ibuf is increased,
* caller should take care to drop its reference by calling
* IMB_freeImBuf if needed. */
-Image *BKE_image_add_from_imbuf(ImBuf *ibuf)
+Image *BKE_image_add_from_imbuf(ImBuf *ibuf, const char *name)
{
/* on save, type is changed to FILE in editsima.c */
Image *ima;
- ima = image_alloc(G.main, BLI_path_basename(ibuf->name), IMA_SRC_FILE, IMA_TYPE_IMAGE);
+ if (name == NULL) {
+ name = BLI_path_basename(ibuf->name);
+ }
+
+ ima = image_alloc(G.main, name, IMA_SRC_FILE, IMA_TYPE_IMAGE);
if (ima) {
BLI_strncpy(ima->name, ibuf->name, FILE_MAX);
@@ -821,18 +904,79 @@ Image *BKE_image_add_from_imbuf(ImBuf *ibuf)
return ima;
}
+/* packs rects from memory as PNG
+ * convert multiview images to R_IMF_VIEWS_INDIVIDUAL
+ */
+static void image_memorypack_multiview(Image *ima)
+{
+ ImageView *iv;
+ size_t i;
+
+ image_free_packedfiles(ima);
+
+ for (i = 0, iv = ima->views.first; iv; iv = iv->next, i++) {
+ ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, i, 0);
+
+ ibuf->ftype = PNG;
+ ibuf->planes = R_IMF_PLANES_RGBA;
+
+ /* if the image was a R_IMF_VIEWS_STEREO_3D we force _L, _R suffices */
+ if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
+ const char *suffix[2] = {STEREO_LEFT_SUFFIX, STEREO_RIGHT_SUFFIX};
+ BLI_path_suffix(iv->filepath, FILE_MAX, suffix[i], "");
+ }
+
+ IMB_saveiff(ibuf, iv->filepath, IB_rect | IB_mem);
+
+ if (ibuf->encodedbuffer == NULL) {
+ printf("memory save for pack error\n");
+ IMB_freeImBuf(ibuf);
+ image_free_packedfiles(ima);
+ return;
+ }
+ else {
+ ImagePackedFile *imapf;
+ PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
+
+ pf->data = ibuf->encodedbuffer;
+ pf->size = ibuf->encodedsize;
+
+ imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile");
+ BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath));
+ imapf->packedfile = pf;
+ BLI_addtail(&ima->packedfiles, imapf);
+
+ ibuf->encodedbuffer = NULL;
+ ibuf->encodedsize = 0;
+ ibuf->userflags &= ~IB_BITMAPDIRTY;
+ }
+ IMB_freeImBuf(ibuf);
+ }
+
+ if (ima->source == IMA_SRC_GENERATED) {
+ ima->source = IMA_SRC_FILE;
+ ima->type = IMA_TYPE_IMAGE;
+ }
+ ima->views_format = R_IMF_VIEWS_INDIVIDUAL;
+}
+
/* packs rect from memory as PNG */
void BKE_image_memorypack(Image *ima)
{
- ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+ ImBuf *ibuf;
- if (ibuf == NULL)
+ if ((ima->flag & IMA_IS_MULTIVIEW)) {
+ image_memorypack_multiview(ima);
return;
- if (ima->packedfile) {
- freePackedFile(ima->packedfile);
- ima->packedfile = NULL;
}
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+
+ if (ibuf == NULL)
+ return;
+
+ image_free_packedfiles(ima);
+
ibuf->ftype = PNG;
ibuf->planes = R_IMF_PLANES_RGBA;
@@ -841,11 +985,17 @@ void BKE_image_memorypack(Image *ima)
printf("memory save for pack error\n");
}
else {
+ ImagePackedFile *imapf;
PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
pf->data = ibuf->encodedbuffer;
pf->size = ibuf->encodedsize;
- ima->packedfile = pf;
+
+ imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile");
+ BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath));
+ imapf->packedfile = pf;
+ BLI_addtail(&ima->packedfiles, imapf);
+
ibuf->encodedbuffer = NULL;
ibuf->encodedsize = 0;
ibuf->userflags &= ~IB_BITMAPDIRTY;
@@ -859,6 +1009,53 @@ void BKE_image_memorypack(Image *ima)
IMB_freeImBuf(ibuf);
}
+void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
+{
+ const size_t totfiles = image_num_files(ima);
+
+ if (totfiles == 1) {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file");
+ BLI_addtail(&ima->packedfiles, imapf);
+ imapf->packedfile = newPackedFile(reports, ima->name, basepath);
+ if (imapf->packedfile) {
+ BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath));
+ }
+ else {
+ BLI_freelinkN(&ima->packedfiles, imapf);
+ }
+ }
+ else {
+ ImageView *iv;
+ for (iv = ima->views.first; iv; iv = iv->next) {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file");
+ BLI_addtail(&ima->packedfiles, imapf);
+
+ imapf->packedfile = newPackedFile(reports, iv->filepath, basepath);
+ if (imapf->packedfile) {
+ BLI_strncpy(imapf->filepath, iv->filepath, sizeof(imapf->filepath));
+ }
+ else {
+ BLI_freelinkN(&ima->packedfiles, imapf);
+ }
+ }
+ }
+}
+
+void BKE_image_packfiles_from_mem(ReportList *reports, Image *ima, char *data, const size_t data_len)
+{
+ const size_t totfiles = image_num_files(ima);
+
+ if (totfiles != 1) {
+ BKE_report(reports, RPT_ERROR, "Cannot pack multiview images from raw data currently...");
+ }
+ else {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), __func__);
+ BLI_addtail(&ima->packedfiles, imapf);
+ imapf->packedfile = newPackedFileMemory(data, data_len);
+ BLI_strncpy(imapf->filepath, ima->name, sizeof(imapf->filepath));
+ }
+}
+
void BKE_image_tag_time(Image *ima)
{
ima->lastused = PIL_check_seconds_timer_i();
@@ -1259,7 +1456,7 @@ char BKE_imtype_from_arg(const char *imtype_arg)
else return R_IMF_IMTYPE_INVALID;
}
-static bool image_path_ensure_ext(char *string, const char imtype, const ImageFormatData *im_format)
+static bool do_add_image_extension(char *string, const char imtype, const ImageFormatData *im_format)
{
const char *extension = NULL;
const char *extension_test;
@@ -1311,7 +1508,7 @@ static bool image_path_ensure_ext(char *string, const char imtype, const ImageFo
}
#endif
#ifdef WITH_OPENEXR
- else if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
+ else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) {
if (!BLI_testextensie(string, extension_test = ".exr"))
extension = extension_test;
}
@@ -1369,14 +1566,14 @@ static bool image_path_ensure_ext(char *string, const char imtype, const ImageFo
}
}
-bool BKE_image_path_ensure_ext_from_imformat(char *string, const ImageFormatData *im_format)
+int BKE_image_path_ensure_ext_from_imformat(char *string, const ImageFormatData *im_format)
{
- return image_path_ensure_ext(string, im_format->imtype, im_format);
+ return do_add_image_extension(string, im_format->imtype, im_format);
}
-bool BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype)
+int BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype)
{
- return image_path_ensure_ext(string, imtype, NULL);
+ return do_add_image_extension(string, imtype, NULL);
}
void BKE_imformat_defaults(ImageFormatData *im_format)
@@ -1861,28 +2058,65 @@ void BKE_image_stamp_buf(
#undef BUFF_MARGIN_Y
}
-void BKE_imbuf_stamp_info(Scene *scene, Object *camera, struct ImBuf *ibuf)
+void BKE_render_result_stamp_info(Scene *scene, Object *camera, struct RenderResult *rr)
{
- struct StampData stamp_data;
+ struct StampData *stamp_data;
+
+ if (!(scene && scene->r.stamp & R_STAMP_ALL))
+ return;
+
+ if (!rr->stamp_data) {
+ stamp_data = MEM_callocN(sizeof(StampData), "RenderResult.stamp_data");
+ }
+ else {
+ stamp_data = rr->stamp_data;
+ }
- if (!ibuf) return;
+ stampdata(scene, camera, stamp_data, 0);
- /* fill all the data values, no prefix */
- stampdata(scene, camera, &stamp_data, 0);
+ if (!rr->stamp_data) {
+ rr->stamp_data = stamp_data;
+ }
+}
- if (stamp_data.file[0]) IMB_metadata_change_field(ibuf, "File", stamp_data.file);
- if (stamp_data.note[0]) IMB_metadata_change_field(ibuf, "Note", stamp_data.note);
- if (stamp_data.date[0]) IMB_metadata_change_field(ibuf, "Date", stamp_data.date);
- if (stamp_data.marker[0]) IMB_metadata_change_field(ibuf, "Marker", stamp_data.marker);
- if (stamp_data.time[0]) IMB_metadata_change_field(ibuf, "Time", stamp_data.time);
- if (stamp_data.frame[0]) IMB_metadata_change_field(ibuf, "Frame", stamp_data.frame);
- if (stamp_data.camera[0]) IMB_metadata_change_field(ibuf, "Camera", stamp_data.camera);
- if (stamp_data.cameralens[0]) IMB_metadata_change_field(ibuf, "Lens", stamp_data.cameralens);
- if (stamp_data.scene[0]) IMB_metadata_change_field(ibuf, "Scene", stamp_data.scene);
- if (stamp_data.strip[0]) IMB_metadata_change_field(ibuf, "Strip", stamp_data.strip);
- if (stamp_data.rendertime[0]) IMB_metadata_change_field(ibuf, "RenderTime", stamp_data.rendertime);
+
+void BKE_imbuf_stamp_info(RenderResult *rr, struct ImBuf *ibuf)
+{
+ struct StampData *stamp_data = rr->stamp_data;
+
+ if (!ibuf || !stamp_data) return;
+
+ if (stamp_data->file[0]) IMB_metadata_change_field(ibuf, "File", stamp_data->file);
+ if (stamp_data->note[0]) IMB_metadata_change_field(ibuf, "Note", stamp_data->note);
+ if (stamp_data->date[0]) IMB_metadata_change_field(ibuf, "Date", stamp_data->date);
+ if (stamp_data->marker[0]) IMB_metadata_change_field(ibuf, "Marker", stamp_data->marker);
+ if (stamp_data->time[0]) IMB_metadata_change_field(ibuf, "Time", stamp_data->time);
+ if (stamp_data->frame[0]) IMB_metadata_change_field(ibuf, "Frame", stamp_data->frame);
+ if (stamp_data->camera[0]) IMB_metadata_change_field(ibuf, "Camera", stamp_data->camera);
+ if (stamp_data->cameralens[0]) IMB_metadata_change_field(ibuf, "Lens", stamp_data->cameralens);
+ if (stamp_data->scene[0]) IMB_metadata_change_field(ibuf, "Scene", stamp_data->scene);
+ if (stamp_data->strip[0]) IMB_metadata_change_field(ibuf, "Strip", stamp_data->strip);
+ if (stamp_data->rendertime[0]) IMB_metadata_change_field(ibuf, "RenderTime", stamp_data->rendertime);
}
+void BKE_stamp_info_callback(void *data, const struct StampData *stamp_data, StampCallback callback)
+{
+ if (!callback || !stamp_data) return;
+
+ if (stamp_data->file[0]) callback(data, "File", stamp_data->file);
+ if (stamp_data->note[0]) callback(data, "Note", stamp_data->note);
+ if (stamp_data->date[0]) callback(data, "Date", stamp_data->date);
+ if (stamp_data->marker[0]) callback(data, "Marker", stamp_data->marker);
+ if (stamp_data->time[0]) callback(data, "Time", stamp_data->time);
+ if (stamp_data->frame[0]) callback(data, "Frame", stamp_data->frame);
+ if (stamp_data->camera[0]) callback(data, "Camera", stamp_data->camera);
+ if (stamp_data->cameralens[0]) callback(data, "Lens", stamp_data->cameralens);
+ if (stamp_data->scene[0]) callback(data, "Scene", stamp_data->scene);
+ if (stamp_data->strip[0]) callback(data, "Strip", stamp_data->strip);
+ if (stamp_data->rendertime[0]) callback(data, "RenderTime", stamp_data->rendertime);
+}
+
+
bool BKE_imbuf_alpha_test(ImBuf *ibuf)
{
int tot;
@@ -1908,14 +2142,12 @@ bool BKE_imbuf_alpha_test(ImBuf *ibuf)
/* note: imf->planes is ignored here, its assumed the image channels
* are already set */
-int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
+void BKE_imbuf_write_prepare(ImBuf *ibuf, ImageFormatData *imf)
{
char imtype = imf->imtype;
char compress = imf->compress;
char quality = imf->quality;
- int ok;
-
if (imtype == R_IMF_IMTYPE_IRIS) {
ibuf->ftype = IMAGIC;
}
@@ -1952,7 +2184,7 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
}
#endif
#ifdef WITH_OPENEXR
- else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) {
+ else if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
ibuf->ftype = OPENEXR;
if (imf->depth == R_IMF_CHAN_DEPTH_16)
ibuf->ftype |= OPENEXR_HALF;
@@ -2036,6 +2268,13 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
if (quality < 10) quality = 90;
ibuf->ftype = JPG | quality;
}
+}
+
+int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
+{
+ int ok;
+
+ BKE_imbuf_write_prepare(ibuf, imf);
BLI_make_existing_file(name);
@@ -2070,18 +2309,18 @@ int BKE_imbuf_write_as(ImBuf *ibuf, const char *name, ImageFormatData *imf,
return ok;
}
-int BKE_imbuf_write_stamp(Scene *scene, struct Object *camera, ImBuf *ibuf, const char *name, struct ImageFormatData *imf)
+int BKE_imbuf_write_stamp(Scene *scene, struct RenderResult *rr, ImBuf *ibuf, const char *name, struct ImageFormatData *imf)
{
if (scene && scene->r.stamp & R_STAMP_ALL)
- BKE_imbuf_stamp_info(scene, camera, ibuf);
+ BKE_imbuf_stamp_info(rr, ibuf);
return BKE_imbuf_write(ibuf, name, imf);
}
-
-static void image_path_makepicstring(
+static void do_makepicstring(
char *string, const char *base, const char *relbase, int frame, const char imtype,
- const ImageFormatData *im_format, const short use_ext, const short use_frames)
+ const ImageFormatData *im_format, const short use_ext, const short use_frames,
+ const char *suffix)
{
if (string == NULL) return;
BLI_strncpy(string, base, FILE_MAX - 10); /* weak assumption */
@@ -2090,22 +2329,25 @@ static void image_path_makepicstring(
if (use_frames)
BLI_path_frame(string, frame, 4);
+ if (suffix)
+ BLI_path_suffix(string, FILE_MAX, suffix, "");
+
if (use_ext)
- image_path_ensure_ext(string, imtype, im_format);
+ do_add_image_extension(string, imtype, im_format);
}
void BKE_image_path_from_imformat(
char *string, const char *base, const char *relbase, int frame,
- const ImageFormatData *im_format, const bool use_ext, const bool use_frames)
+ const ImageFormatData *im_format, const bool use_ext, const bool use_frames, const char *suffix)
{
- image_path_makepicstring(string, base, relbase, frame, im_format->imtype, im_format, use_ext, use_frames);
+ do_makepicstring(string, base, relbase, frame, im_format->imtype, im_format, use_ext, use_frames, suffix);
}
void BKE_image_path_from_imtype(
char *string, const char *base, const char *relbase, int frame,
- const char imtype, const bool use_ext, const bool use_frames)
+ const char imtype, const bool use_ext, const bool use_frames, const char *view)
{
- image_path_makepicstring(string, base, relbase, frame, imtype, NULL, use_ext, use_frames);
+ do_makepicstring(string, base, relbase, frame, imtype, NULL, use_ext, use_frames, view);
}
struct anim *openanim_noload(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE])
@@ -2181,6 +2423,71 @@ Image *BKE_image_verify_viewer(int type, const char *name)
return ima;
}
+static void image_viewer_create_views(const RenderData *rd, Image *ima)
+{
+ if ((rd->scemode & R_MULTIVIEW) == 0) {
+ image_add_view(ima, "", "");
+ }
+ else {
+ SceneRenderView *srv;
+ for (srv = rd->views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv) == false)
+ continue;
+ image_add_view(ima, srv->name, "");
+ }
+ }
+}
+
+/* Reset the image cache and views when the Viewer Nodes views don't match the scene views */
+void BKE_image_verify_viewer_views(const RenderData *rd, Image *ima, ImageUser *iuser)
+{
+ bool do_reset;
+ const bool is_multiview = (rd->scemode & R_MULTIVIEW) != 0;
+
+ BLI_lock_thread(LOCK_DRAW_IMAGE);
+
+ if (BKE_scene_multiview_is_stereo3d(rd)) {
+ ima->flag |= IMA_IS_STEREO;
+ ima->flag |= IMA_IS_MULTIVIEW;
+ }
+ else {
+ ima->flag &= ~IMA_IS_STEREO;
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ iuser->flag &= ~IMA_SHOW_STEREO;
+ }
+
+ /* see if all scene render views are in the image view list */
+ do_reset = (BKE_scene_multiview_num_views_get(rd) != BLI_listbase_count(&ima->views));
+
+ /* multiview also needs to be sure all the views are synced */
+ if (is_multiview && !do_reset) {
+ SceneRenderView *srv;
+ ImageView *iv;
+
+ for (iv = ima->views.first; iv; iv = iv->next) {
+ srv = BLI_findstring(&rd->views, iv->name, offsetof(SceneRenderView, name));
+ if ((srv == NULL) || (BKE_scene_multiview_is_render_view_active(rd, srv) == false)) {
+ do_reset = true;
+ break;
+ }
+ }
+ }
+
+ if (do_reset) {
+ BLI_spin_lock(&image_spin);
+
+ image_free_cached_frames(ima);
+ BKE_image_free_views(ima);
+
+ /* add new views */
+ image_viewer_create_views(rd, ima);
+
+ BLI_spin_unlock(&image_spin);
+ }
+
+ BLI_unlock_thread(LOCK_DRAW_IMAGE);
+}
+
void BKE_image_walk_all_users(const Main *mainp, void *customdata,
void callback(Image *ima, ImageUser *iuser, void *customdata))
{
@@ -2238,6 +2545,33 @@ static void image_tag_frame_recalc(Image *ima, ImageUser *iuser, void *customdat
}
}
+static void image_init_imageuser(Image *ima, ImageUser *iuser)
+{
+ RenderResult *rr = ima->rr;
+
+ iuser->multi_index = 0;
+ iuser->layer = iuser->view = 0;
+ iuser->passtype = SCE_PASS_COMBINED;
+
+ if (rr) {
+ RenderLayer *rl = rr->layers.first;
+
+ if (rl) {
+ RenderPass *rp = rl->passes.first;
+
+ if (rp)
+ iuser->passtype = rp->passtype;
+ }
+
+ BKE_image_multilayer_index(rr, iuser);
+ }
+}
+
+void BKE_image_init_imageuser(Image *ima, ImageUser *iuser)
+{
+ image_init_imageuser(ima, iuser);
+}
+
void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
{
if (ima == NULL)
@@ -2248,8 +2582,13 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
switch (signal) {
case IMA_SIGNAL_FREE:
BKE_image_free_buffers(ima);
- if (iuser)
+
+ if (iuser) {
iuser->ok = 1;
+ if (iuser->scene) {
+ image_update_views_format(ima, iuser);
+ }
+ }
break;
case IMA_SIGNAL_SRC_CHANGE:
if (ima->type == IMA_TYPE_UV_TEST)
@@ -2301,23 +2640,41 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
case IMA_SIGNAL_RELOAD:
/* try to repack file */
- if (ima->packedfile) {
- PackedFile *pf;
- pf = newPackedFile(NULL, ima->name, ID_BLEND_PATH(G.main, &ima->id));
- if (pf) {
- freePackedFile(ima->packedfile);
- ima->packedfile = pf;
- BKE_image_free_buffers(ima);
+ if (BKE_image_has_packedfile(ima)) {
+ const size_t totfiles = image_num_files(ima);
+
+ if (totfiles != BLI_listbase_count_ex(&ima->packedfiles, totfiles + 1)) {
+ /* in case there are new available files to be loaded */
+ image_free_packedfiles(ima);
+ BKE_image_packfiles(NULL, ima, ID_BLEND_PATH(G.main, &ima->id));
}
else {
- printf("ERROR: Image not available. Keeping packed image\n");
+ ImagePackedFile *imapf;
+ for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) {
+ PackedFile *pf;
+ pf = newPackedFile(NULL, imapf->filepath, ID_BLEND_PATH(G.main, &ima->id));
+ if (pf) {
+ freePackedFile(imapf->packedfile);
+ imapf->packedfile = pf;
+ }
+ else {
+ printf("ERROR: Image \"%s\" not available. Keeping packed image\n", imapf->filepath);
+ }
+ }
}
+
+ if (BKE_image_has_packedfile(ima))
+ BKE_image_free_buffers(ima);
}
else
BKE_image_free_buffers(ima);
- if (iuser)
+ if (iuser) {
iuser->ok = 1;
+ if (iuser->scene) {
+ image_update_views_format(ima, iuser);
+ }
+ }
break;
case IMA_SIGNAL_USER_NEW_IMAGE:
@@ -2325,8 +2682,7 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
iuser->ok = 1;
if (ima->source == IMA_SRC_FILE || ima->source == IMA_SRC_SEQUENCE) {
if (ima->type == IMA_TYPE_MULTILAYER) {
- iuser->multi_index = 0;
- iuser->layer = iuser->pass = 0;
+ image_init_imageuser(ima, iuser);
}
}
}
@@ -2368,44 +2724,113 @@ RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser)
return NULL;
if (iuser) {
- short index = 0, rl_index = 0, rp_index;
+ short index = 0, rv_index, rl_index = 0;
+ bool is_stereo = (iuser->flag & IMA_SHOW_STEREO) && RE_RenderResult_is_stereo(rr);
+
+ rv_index = is_stereo ? iuser->multiview_eye : iuser->view;
+ if (RE_HasFakeLayer(rr)) rl_index += 1;
for (rl = rr->layers.first; rl; rl = rl->next, rl_index++) {
- rp_index = 0;
- for (rpass = rl->passes.first; rpass; rpass = rpass->next, index++, rp_index++)
- if (iuser->layer == rl_index && iuser->pass == rp_index)
+ for (rpass = rl->passes.first; rpass; rpass = rpass->next, index++) {
+ if (iuser->layer == rl_index &&
+ iuser->passtype == rpass->passtype &&
+ rv_index == rpass->view_id)
+ {
break;
+ }
+ }
if (rpass)
break;
}
-
- if (rpass)
- iuser->multi_index = index;
- else
- iuser->multi_index = 0;
+ iuser->multi_index = (rpass ? index : 0);
}
+
if (rpass == NULL) {
rl = rr->layers.first;
if (rl)
rpass = rl->passes.first;
+
+ if (rpass && iuser)
+ iuser->passtype = rpass->passtype;
}
return rpass;
}
+void BKE_image_multiview_index(Image *ima, ImageUser *iuser)
+{
+ if (iuser) {
+ bool is_stereo = (ima->flag & IMA_IS_STEREO) && (iuser->flag & IMA_SHOW_STEREO);
+ if (is_stereo) {
+ iuser->multi_index = iuser->multiview_eye;
+ }
+ else {
+ if ((iuser->view < 0) || (iuser->view >= BLI_listbase_count_ex(&ima->views, iuser->view + 1))) {
+ iuser->multi_index = iuser->view = 0;
+ }
+ else {
+ iuser->multi_index = iuser->view;
+ }
+ }
+ }
+}
+
+/* if layer or pass changes, we need an index for the imbufs list */
+/* note it is called for rendered results, but it doesnt use the index! */
+/* and because rendered results use fake layer/passes, don't correct for wrong indices here */
+bool BKE_image_is_multilayer(Image *ima)
+{
+ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE)) {
+ if (ima->type == IMA_TYPE_MULTILAYER) {
+ return true;
+ }
+ }
+ else if (ima->source == IMA_SRC_VIEWER) {
+ if (ima->type == IMA_TYPE_R_RESULT) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void image_init_multilayer_multiview_flag(Image *ima, RenderResult *rr)
+{
+ if (rr) {
+ if (RE_RenderResult_is_stereo(rr)) {
+ ima->flag |= IMA_IS_STEREO;
+ ima->flag |= IMA_IS_MULTIVIEW;
+ }
+ else {
+ ima->flag &= ~IMA_IS_STEREO;
+ if (BLI_listbase_count_ex(&rr->views, 2) > 1)
+ ima->flag |= IMA_IS_MULTIVIEW;
+ else
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ }
+ }
+ else {
+ ima->flag &= ~IMA_IS_STEREO;
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ }
+}
+
RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima)
{
+ RenderResult *rr = NULL;
if (ima->rr) {
- return ima->rr;
+ rr = ima->rr;
}
else if (ima->type == IMA_TYPE_R_RESULT) {
if (ima->render_slot == ima->last_render_slot)
- return RE_AcquireResultRead(RE_GetRender(scene->id.name));
+ rr = RE_AcquireResultRead(RE_GetRender(scene->id.name));
else
- return ima->renders[ima->render_slot];
+ rr = ima->renders[ima->render_slot];
+
+ /* set proper multiview flag */
+ image_init_multilayer_multiview_flag(ima, rr);
}
- else
- return NULL;
+
+ return rr;
}
void BKE_image_release_renderresult(Scene *scene, Image *ima)
@@ -2419,6 +2844,18 @@ void BKE_image_release_renderresult(Scene *scene, Image *ima)
}
}
+bool BKE_image_is_openexr(struct Image *ima)
+{
+#ifdef WITH_OPENEXR
+ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE)) {
+ return BLI_testextensie(ima->name, ".exr");
+ }
+#else
+ UNUSED_VARS(ima);
+#endif
+ return false;
+}
+
void BKE_image_backup_render(Scene *scene, Image *ima)
{
/* called right before rendering, ima->renders contains render
@@ -2439,8 +2876,155 @@ void BKE_image_backup_render(Scene *scene, Image *ima)
ima->last_render_slot = slot;
}
+/**************************** multiview save openexr *********************************/
+#ifdef WITH_OPENEXR
+static const char *image_get_view_cb(void *base, const size_t view_id)
+{
+ Image *ima = base;
+ ImageView *iv = BLI_findlink(&ima->views, view_id);
+ return iv ? iv->name : "";
+}
+#endif /* WITH_OPENEXR */
+
+#ifdef WITH_OPENEXR
+static ImBuf *image_get_buffer_cb(void *base, const size_t view_id)
+{
+ Image *ima = base;
+ ImageUser iuser = {0};
+
+ iuser.view = view_id;
+ iuser.ok = 1;
+
+ BKE_image_multiview_index(ima, &iuser);
+
+ return image_acquire_ibuf(ima, &iuser, NULL);
+}
+#endif /* WITH_OPENEXR */
+
+bool BKE_image_save_openexr_multiview(Image *ima, ImBuf *ibuf, const char *filepath, const int flags)
+{
+#ifdef WITH_OPENEXR
+ char name[FILE_MAX];
+ bool ok;
+
+ BLI_strncpy(name, filepath, sizeof(name));
+ BLI_path_abs(name, G.main->name);
+
+ ibuf->userdata = ima;
+ ok = IMB_exr_multiview_save(ibuf, name, flags, BLI_listbase_count(&ima->views), image_get_view_cb, image_get_buffer_cb);
+ ibuf->userdata = NULL;
+
+ return ok;
+#else
+ UNUSED_VARS(ima, ibuf, filepath, flags);
+ return false;
+#endif
+}
+
+/**************************** multiview load openexr *********************************/
+
+static void image_add_view(Image *ima, const char *viewname, const char *filepath)
+{
+ ImageView *iv;
+
+ iv = MEM_mallocN(sizeof(ImageView), "Viewer Image View");
+ BLI_strncpy(iv->name, viewname, sizeof(iv->name));
+ BLI_strncpy(iv->filepath, filepath, sizeof(iv->filepath));
+
+ /* For stereo drawing we need to ensure:
+ * STEREO_LEFT_NAME == STEREO_LEFT_ID and
+ * STEREO_RIGHT_NAME == STEREO_RIGHT_ID */
+
+ if (STREQ(viewname, STEREO_LEFT_NAME)) {
+ BLI_addhead(&ima->views, iv);
+ }
+ else if (STREQ(viewname, STEREO_RIGHT_NAME)) {
+ ImageView *left_iv = BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name));
+
+ if (left_iv == NULL) {
+ BLI_addhead(&ima->views, iv);
+ }
+ else {
+ BLI_insertlinkafter(&ima->views, left_iv, iv);
+ }
+ }
+ else {
+ BLI_addtail(&ima->views, iv);
+ }
+}
+
+#ifdef WITH_OPENEXR
+static void image_add_view_cb(void *base, const char *str)
+{
+ Image *ima = base;
+ image_add_view(ima, str, ima->name);
+}
+
+static void image_add_buffer_cb(void *base, const char *str, ImBuf *ibuf, const int frame)
+{
+ Image *ima = base;
+ size_t id;
+ bool predivide = (ima->alpha_mode == IMA_ALPHA_PREMUL);
+ const char *colorspace = ima->colorspace_settings.name;
+ const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
+
+ if (ibuf == NULL)
+ return;
+
+ id = BLI_findstringindex(&ima->views, str, offsetof(ImageView, name));
+
+ if (id == -1)
+ return;
+
+ if (ibuf->channels >= 3)
+ IMB_colormanagement_transform(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
+ colorspace, to_colorspace, predivide);
+
+ image_assign_ibuf(ima, ibuf, id, frame);
+ IMB_freeImBuf(ibuf);
+}
+#endif /* WITH_OPENEXR */
+
+#ifdef WITH_OPENEXR
+static void image_update_multiview_flags(Image *ima)
+{
+ if (BLI_listbase_count_ex(&ima->views, 2) > 1) {
+ ima->flag |= IMA_IS_MULTIVIEW;
+
+ if (BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name)) &&
+ BLI_findstring(&ima->views, STEREO_RIGHT_NAME, offsetof(ImageView, name)))
+ {
+ ima->flag |= IMA_IS_STEREO;
+ }
+ else {
+ ima->flag &= ~IMA_IS_STEREO;
+ }
+ }
+ else {
+ ima->flag &= ~IMA_IS_STEREO;
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ }
+}
+#endif /* WITH_OPENEXR */
+
/* after imbuf load, openexr type can return with a exrhandle open */
/* in that case we have to build a render-result */
+#ifdef WITH_OPENEXR
+static void image_create_multiview(Image *ima, ImBuf *ibuf, const int frame)
+{
+ image_free_views(ima);
+
+ IMB_exr_multiview_convert(ibuf->userdata, ima, image_add_view_cb, image_add_buffer_cb, frame);
+
+ image_update_multiview_flags(ima);
+
+ IMB_exr_close(ibuf->userdata);
+}
+#endif /* WITH_OPENEXR */
+
+/* after imbuf load, openexr type can return with a exrhandle open */
+/* in that case we have to build a render-result */
+#ifdef WITH_OPENEXR
static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
{
const char *colorspace = ima->colorspace_settings.name;
@@ -2448,21 +3032,23 @@ static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
ima->rr = RE_MultilayerConvert(ibuf->userdata, colorspace, predivide, ibuf->x, ibuf->y);
-#ifdef WITH_OPENEXR
IMB_exr_close(ibuf->userdata);
-#endif
ibuf->userdata = NULL;
if (ima->rr)
ima->rr->framenr = framenr;
+
+ /* set proper multiview flag */
+ image_init_multilayer_multiview_flag(ima, ima->rr);
}
+#endif /* WITH_OPENEXR */
/* common stuff to do with images after loading */
static void image_initialize_after_load(Image *ima, ImBuf *ibuf)
{
/* preview is NULL when it has never been used as an icon before */
if (G.background == 0 && ima->preview == NULL)
- BKE_icon_changed(BKE_icon_getid(&ima->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&ima->id));
/* fields */
if (ima->flag & IMA_FIELDS) {
@@ -2488,18 +3074,41 @@ static int imbuf_alpha_flags_for_image(Image *ima)
return flag;
}
-static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
+/* the number of files will vary according to the stereo format */
+static size_t image_num_files(Image *ima)
+{
+ const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
+
+ if (!is_multiview) {
+ return 1;
+ }
+ else if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
+ return 1;
+ }
+ /* R_IMF_VIEWS_INDIVIDUAL */
+ else {
+ return BLI_listbase_count(&ima->views);
+ }
+}
+
+static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, const size_t view_id, bool *r_assign)
{
struct ImBuf *ibuf;
char name[FILE_MAX];
int flag;
+ ImageUser iuser_t;
/* XXX temp stuff? */
if (ima->lastframe != frame)
ima->tpageflag |= IMA_TPAGE_REFRESH;
ima->lastframe = frame;
- BKE_image_user_file_path(iuser, ima, name);
+
+ if (iuser)
+ iuser_t = *iuser;
+
+ iuser_t.view = view_id;
+ BKE_image_user_file_path(&iuser_t, ima, name);
flag = IB_rect | IB_multilayer;
flag |= imbuf_alpha_flags_for_image(ima);
@@ -2520,25 +3129,78 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
#ifdef WITH_OPENEXR
/* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */
if (ibuf->ftype == OPENEXR && ibuf->userdata) {
- image_create_multilayer(ima, ibuf, frame);
- ima->type = IMA_TYPE_MULTILAYER;
- IMB_freeImBuf(ibuf);
- ibuf = NULL;
+ /* handle singlelayer multiview case assign ibuf based on available views */
+ if (IMB_exr_has_singlelayer_multiview(ibuf->userdata)) {
+ image_create_multiview(ima, ibuf, frame);
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+ else if (IMB_exr_has_multilayer(ibuf->userdata)) {
+ /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */
+ image_create_multilayer(ima, ibuf, frame);
+ ima->type = IMA_TYPE_MULTILAYER;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
}
else {
image_initialize_after_load(ima, ibuf);
- image_assign_ibuf(ima, ibuf, 0, frame);
+ *r_assign = true;
}
#else
image_initialize_after_load(ima, ibuf);
- image_assign_ibuf(ima, ibuf, 0, frame);
+ *r_assign = true;
#endif
}
- else
- ima->ok = 0;
- if (iuser)
- iuser->ok = ima->ok;
+ return ibuf;
+}
+
+static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
+{
+ struct ImBuf *ibuf = NULL;
+ const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
+ const size_t totfiles = image_num_files(ima);
+ bool assign = false;
+
+ if (!is_multiview) {
+ ibuf = load_sequence_single(ima, iuser, frame, 0, &assign);
+ if (assign) {
+ image_assign_ibuf(ima, ibuf, 0, frame);
+ }
+ }
+ else {
+ size_t i;
+ struct ImBuf **ibuf_arr;
+ const size_t totviews = BLI_listbase_count(&ima->views);
+
+ ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
+
+ for (i = 0; i < totfiles; i++)
+ ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i, &assign);
+
+ if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+
+ /* return the original requested ImBuf */
+ ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)];
+
+ if (assign) {
+ for (i = 0; i < totviews; i++) {
+ image_assign_ibuf(ima, ibuf_arr[i], i, frame);
+ }
+ }
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+
+ /* cleanup */
+ MEM_freeN(ibuf_arr);
+ }
return ibuf;
}
@@ -2595,46 +3257,52 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int f
return ibuf;
}
-
-static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
+static ImBuf *load_movie_single(Image *ima, ImageUser *iuser, int frame, const size_t view_id)
{
struct ImBuf *ibuf = NULL;
+ ImageAnim *ia;
- ima->lastframe = frame;
+ ia = BLI_findlink(&ima->anims, view_id);
- if (ima->anim == NULL) {
+ if (ia->anim == NULL) {
char str[FILE_MAX];
int flags = IB_rect;
+ ImageUser iuser_t;
+
if (ima->flag & IMA_DEINTERLACE) {
flags |= IB_animdeinterlace;
}
- BKE_image_user_file_path(iuser, ima, str);
+ if (iuser)
+ iuser_t = *iuser;
+
+ iuser_t.view = view_id;
+
+ BKE_image_user_file_path(&iuser_t, ima, str);
/* FIXME: make several stream accessible in image editor, too*/
- ima->anim = openanim(str, IB_rect, 0, ima->colorspace_settings.name);
+ ia->anim = openanim(str, flags, 0, ima->colorspace_settings.name);
/* let's initialize this user */
- if (ima->anim && iuser && iuser->frames == 0)
- iuser->frames = IMB_anim_get_duration(ima->anim,
+ if (ia->anim && iuser && iuser->frames == 0)
+ iuser->frames = IMB_anim_get_duration(ia->anim,
IMB_TC_RECORD_RUN);
}
- if (ima->anim) {
- int dur = IMB_anim_get_duration(ima->anim,
+ if (ia->anim) {
+ int dur = IMB_anim_get_duration(ia->anim,
IMB_TC_RECORD_RUN);
int fra = frame - 1;
if (fra < 0) fra = 0;
if (fra > (dur - 1)) fra = dur - 1;
ibuf = IMB_makeSingleUser(
- IMB_anim_absolute(ima->anim, fra,
+ IMB_anim_absolute(ia->anim, fra,
IMB_TC_RECORD_RUN,
IMB_PROXY_NONE));
if (ibuf) {
image_initialize_after_load(ima, ibuf);
- image_assign_ibuf(ima, ibuf, 0, frame);
}
else
ima->ok = 0;
@@ -2642,67 +3310,225 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
else
ima->ok = 0;
+ return ibuf;
+}
+
+static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
+{
+ struct ImBuf *ibuf = NULL;
+ const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
+ const size_t totfiles = image_num_files(ima);
+ size_t i;
+
+ if (totfiles != BLI_listbase_count_ex(&ima->anims, totfiles + 1)) {
+ image_free_anims(ima);
+
+ for (i = 0; i < totfiles; i++) {
+ /* allocate the ImageAnim */
+ ImageAnim *ia = MEM_callocN(sizeof(ImageAnim), "Image Anim");
+ BLI_addtail(&ima->anims, ia);
+ }
+ }
+
+ if (!is_multiview) {
+ ibuf = load_movie_single(ima, iuser, frame, 0);
+ image_assign_ibuf(ima, ibuf, 0, frame);
+ }
+ else {
+ struct ImBuf **ibuf_arr;
+ const size_t totviews = BLI_listbase_count(&ima->views);
+
+ ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views (movie) Imbufs");
+
+ for (i = 0; i < totfiles; i++) {
+ ibuf_arr[i] = load_movie_single(ima, iuser, frame, i);
+ }
+
+ if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i]) {
+ image_assign_ibuf(ima, ibuf_arr[i], i, frame);
+ }
+ else {
+ ima->ok = 0;
+ }
+ }
+
+ /* return the original requested ImBuf */
+ ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)];
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+
+ /* cleanup */
+ MEM_freeN(ibuf_arr);
+ }
+
if (iuser)
iuser->ok = ima->ok;
return ibuf;
}
-/* warning, 'iuser' can be NULL */
-static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
+static ImBuf *load_image_single(
+ Image *ima, ImageUser *iuser, int cfra,
+ const size_t view_id,
+ const bool has_packed,
+ bool *r_assign)
{
- struct ImBuf *ibuf;
- char str[FILE_MAX];
- int assign = 0, flag;
-
- /* always ensure clean ima */
- BKE_image_free_buffers(ima);
+ char filepath[FILE_MAX];
+ struct ImBuf *ibuf = NULL;
+ int flag;
/* is there a PackedFile with this image ? */
- if (ima->packedfile) {
+ if (has_packed) {
+ ImagePackedFile *imapf;
+
flag = IB_rect | IB_multilayer;
flag |= imbuf_alpha_flags_for_image(ima);
- ibuf = IMB_ibImageFromMemory((unsigned char *)ima->packedfile->data, ima->packedfile->size, flag,
- ima->colorspace_settings.name, "<packed data>");
+ imapf = BLI_findlink(&ima->packedfiles, view_id);
+ if (imapf->packedfile) {
+ ibuf = IMB_ibImageFromMemory(
+ (unsigned char *)imapf->packedfile->data, imapf->packedfile->size, flag,
+ ima->colorspace_settings.name, "<packed data>");
+ }
}
else {
+ ImageUser iuser_t;
+
flag = IB_rect | IB_multilayer | IB_metadata;
flag |= imbuf_alpha_flags_for_image(ima);
- /* get the right string */
+ /* get the correct filepath */
BKE_image_user_frame_calc(iuser, cfra, 0);
- BKE_image_user_file_path(iuser, ima, str);
+
+ if (iuser)
+ iuser_t = *iuser;
+ else
+ iuser_t.framenr = ima->lastframe;
+
+ iuser_t.view = view_id;
+
+ BKE_image_user_file_path(&iuser_t, ima, filepath);
/* read ibuf */
- ibuf = IMB_loadiffname(str, flag, ima->colorspace_settings.name);
+ ibuf = IMB_loadiffname(filepath, flag, ima->colorspace_settings.name);
}
if (ibuf) {
- /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */
+#ifdef WITH_OPENEXR
if (ibuf->ftype == OPENEXR && ibuf->userdata) {
- image_create_multilayer(ima, ibuf, cfra);
- ima->type = IMA_TYPE_MULTILAYER;
- IMB_freeImBuf(ibuf);
- ibuf = NULL;
+ if (IMB_exr_has_singlelayer_multiview(ibuf->userdata)) {
+ /* handle singlelayer multiview case assign ibuf based on available views */
+ image_create_multiview(ima, ibuf, cfra);
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+ else if (IMB_exr_has_multilayer(ibuf->userdata)) {
+ /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_acquire_ibuf */
+ image_create_multilayer(ima, ibuf, cfra);
+ ima->type = IMA_TYPE_MULTILAYER;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
}
else {
image_initialize_after_load(ima, ibuf);
- assign = 1;
+ *r_assign = true;
/* check if the image is a font image... */
detectBitmapFont(ibuf);
/* make packed file for autopack */
- if ((ima->packedfile == NULL) && (G.fileflags & G_AUTOPACK))
- ima->packedfile = newPackedFile(NULL, str, ID_BLEND_PATH(G.main, &ima->id));
+ if ((has_packed == false) && (G.fileflags & G_AUTOPACK)) {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Packefile");
+ BLI_addtail(&ima->packedfiles, imapf);
+
+ BLI_strncpy(imapf->filepath, filepath, sizeof(imapf->filepath));
+ imapf->packedfile = newPackedFile(NULL, filepath, ID_BLEND_PATH(G.main, &ima->id));
+ }
}
+#else
+ image_initialize_after_load(ima, ibuf);
+ *r_assign = true;
+#endif
}
- else
+ else {
ima->ok = 0;
+ }
- if (assign)
- image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ return ibuf;
+}
+
+/* warning, 'iuser' can be NULL
+ * note: Image->views was already populated (in image_update_views_format)
+ */
+static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
+{
+ struct ImBuf *ibuf = NULL;
+ bool assign = false;
+ const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
+ const size_t totfiles = image_num_files(ima);
+ bool has_packed = BKE_image_has_packedfile(ima);
+
+ /* always ensure clean ima */
+ BKE_image_free_buffers(ima);
+
+ /* this should never happen, but just playing safe */
+ if (has_packed) {
+ if (totfiles != BLI_listbase_count_ex(&ima->packedfiles, totfiles + 1)) {
+ image_free_packedfiles(ima);
+ has_packed = false;
+ }
+ }
+
+ if (!is_multiview) {
+ ibuf = load_image_single(ima, iuser, cfra, 0, has_packed, &assign);
+ if (assign) {
+ image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ }
+ }
+ else {
+ size_t i;
+ struct ImBuf **ibuf_arr;
+ const size_t totviews = BLI_listbase_count(&ima->views);
+ BLI_assert(totviews > 0);
+
+ ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
+
+ for (i = 0; i < totfiles; i++)
+ ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed, &assign);
+
+ if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+
+ /* return the original requested ImBuf */
+ i = iuser && iuser->multi_index < totviews ? iuser->multi_index : 0;
+ ibuf = ibuf_arr[i];
+
+ if (assign) {
+ for (i = 0; i < totviews; i++) {
+ image_assign_ibuf(ima, ibuf_arr[i], i, 0);
+ }
+ }
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+
+ /* cleanup */
+ MEM_freeN(ibuf_arr);
+ }
if (iuser)
iuser->ok = ima->ok;
@@ -2749,37 +3575,43 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser)
/* showing RGBA result itself (from compo/sequence) or
* like exr, using layers etc */
/* always returns a single ibuf, also during render progress */
-static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_r)
+static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_lock)
{
Render *re;
RenderResult rres;
+ RenderView *rv;
float *rectf, *rectz;
unsigned int *rect;
float dither;
- int channels, layer, pass;
+ int channels, layer, passtype;
ImBuf *ibuf;
int from_render = (ima->render_slot == ima->last_render_slot);
+ int actview;
bool byte_buffer_in_display_space = false;
if (!(iuser && iuser->scene))
return NULL;
/* if we the caller is not going to release the lock, don't give the image */
- if (!lock_r)
+ if (!r_lock)
return NULL;
re = RE_GetRender(iuser->scene->id.name);
channels = 4;
layer = iuser->layer;
- pass = iuser->pass;
+ passtype = iuser->passtype;
+ actview = iuser->view;
+
+ if ((ima->flag & IMA_IS_STEREO) && (iuser->flag & IMA_SHOW_STEREO))
+ actview = iuser->multiview_eye;
if (from_render) {
- RE_AcquireResultImage(re, &rres);
+ RE_AcquireResultImage(re, &rres, actview);
}
else if (ima->renders[ima->render_slot]) {
rres = *(ima->renders[ima->render_slot]);
- rres.have_combined = rres.rectf != NULL;
+ rres.have_combined = ((RenderView *)rres.views.first)->rectf != NULL;
}
else
memset(&rres, 0, sizeof(RenderResult));
@@ -2790,16 +3622,30 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
return NULL;
}
- /* release is done in BKE_image_release_ibuf using lock_r */
+ /* release is done in BKE_image_release_ibuf using r_lock */
if (from_render) {
BLI_lock_thread(LOCK_VIEWER);
- *lock_r = re;
+ *r_lock = re;
+ rv = NULL;
+ }
+ else {
+ rv = BLI_findlink(&rres.views, actview);
+ if (rv == NULL)
+ rv = rres.views.first;
}
/* this gives active layer, composite or sequence result */
- rect = (unsigned int *)rres.rect32;
- rectf = rres.rectf;
- rectz = rres.rectz;
+ if (rv == NULL) {
+ rect = (unsigned int *)rres.rect32;
+ rectf = rres.rectf;
+ rectz = rres.rectz;
+ }
+ else {
+ rect = (unsigned int *)rv->rect32;
+ rectf = rv->rectf;
+ rectz = rv->rectz;
+ }
+
dither = iuser->scene->r.dither_intensity;
/* combined layer gets added as first layer */
@@ -2819,24 +3665,27 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
if (rl) {
RenderPass *rpass;
- /* there's no combined pass, is in renderlayer itself */
- if (pass == 0) {
- rectf = rl->rectf;
- if (rectf == NULL) {
+ for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
+ if (passtype == rpass->passtype &&
+ actview == rpass->view_id)
+ {
+ break;
+ }
+ }
+
+ if (rpass) {
+ channels = rpass->channels;
+ rectf = rpass->rect;
+
+ if (!rectf) {
/* Happens when Save Buffers is enabled.
* Use display buffer stored in the render layer.
*/
rect = (unsigned int *) rl->display_buffer;
byte_buffer_in_display_space = true;
}
- }
- else {
- rpass = BLI_findlink(&rl->passes, pass - 1);
- if (rpass) {
- channels = rpass->channels;
- rectf = rpass->rect;
- dither = 0.0f; /* don't dither passes */
- }
+
+ dither = 0.0f; /* don't dither passes */
}
for (rpass = rl->passes.first; rpass; rpass = rpass->next)
@@ -2925,9 +3774,31 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
return ibuf;
}
+static size_t image_get_multiview_index(Image *ima, ImageUser *iuser)
+{
+ const bool is_multilayer = BKE_image_is_multilayer(ima);
+ const bool is_backdrop = (ima->source == IMA_SRC_VIEWER) && (ima->type == IMA_TYPE_COMPOSITE) && (iuser == NULL);
+ int index = BKE_image_is_animated(ima) ? 0 : IMA_NO_INDEX;
+
+ if (is_multilayer) {
+ return iuser ? iuser->multi_index : index;
+ }
+ else if (is_backdrop) {
+ if ((ima->flag & IMA_IS_STEREO)) {
+ /* backdrop hackaround (since there is no iuser */
+ return ima->eye;
+ }
+ }
+ else if ((ima->flag & IMA_IS_MULTIVIEW)) {
+ return iuser ? iuser->multi_index : index;
+ }
+
+ return index;
+}
+
static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame, int *r_index)
{
- int frame = 0, index = 0;
+ int frame = 0, index = image_get_multiview_index(ima, iuser);
/* see if we already have an appropriate ibuf, with image source and type */
if (ima->source == IMA_SRC_MOVIE) {
@@ -2939,7 +3810,6 @@ static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame
}
else if (ima->type == IMA_TYPE_MULTILAYER) {
frame = iuser ? iuser->framenr : ima->lastframe;
- index = iuser ? iuser->multi_index : IMA_NO_INDEX;
}
}
@@ -2956,12 +3826,12 @@ static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame
static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame, int *r_index)
{
ImBuf *ibuf = NULL;
- int frame = 0, index = 0;
+ int frame = 0, index = image_get_multiview_index(ima, iuser);
/* see if we already have an appropriate ibuf, with image source and type */
if (ima->source == IMA_SRC_MOVIE) {
frame = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
/* XXX temp stuff? */
if (ima->lastframe != frame)
ima->tpageflag |= IMA_TPAGE_REFRESH;
@@ -2970,7 +3840,7 @@ static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame,
else if (ima->source == IMA_SRC_SEQUENCE) {
if (ima->type == IMA_TYPE_IMAGE) {
frame = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
/* XXX temp stuff? */
if (ima->lastframe != frame) {
@@ -2990,18 +3860,17 @@ static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame,
}
else if (ima->type == IMA_TYPE_MULTILAYER) {
frame = iuser ? iuser->framenr : ima->lastframe;
- index = iuser ? iuser->multi_index : IMA_NO_INDEX;
ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
}
}
else if (ima->source == IMA_SRC_FILE) {
if (ima->type == IMA_TYPE_IMAGE)
- ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
else if (ima->type == IMA_TYPE_MULTILAYER)
- ibuf = image_get_cached_ibuf_for_index_frame(ima, iuser ? iuser->multi_index : IMA_NO_INDEX, 0);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
}
else if (ima->source == IMA_SRC_GENERATED) {
- ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
}
else if (ima->source == IMA_SRC_VIEWER) {
/* always verify entirely, not that this shouldn't happen
@@ -3037,13 +3906,13 @@ BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser)
*
* not thread-safe, so callee should worry about thread locks
*/
-static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
+static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
{
ImBuf *ibuf = NULL;
int frame = 0, index = 0;
- if (lock_r)
- *lock_r = NULL;
+ if (r_lock)
+ *r_lock = NULL;
/* quick reject tests */
if (!image_quick_test(ima, iuser))
@@ -3085,31 +3954,31 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
if (ima->gen_depth == 0) ima->gen_depth = 24;
ibuf = add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, ima->gen_depth, (ima->gen_flag & IMA_GEN_FLOAT) != 0, ima->gen_type,
ima->gen_color, &ima->colorspace_settings);
- image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ image_assign_ibuf(ima, ibuf, index, 0);
ima->ok = IMA_OK_LOADED;
}
else if (ima->source == IMA_SRC_VIEWER) {
if (ima->type == IMA_TYPE_R_RESULT) {
/* always verify entirely, and potentially
* returns pointer to release later */
- ibuf = image_get_render_result(ima, iuser, lock_r);
+ ibuf = image_get_render_result(ima, iuser, r_lock);
}
else if (ima->type == IMA_TYPE_COMPOSITE) {
/* requires lock/unlock, otherwise don't return image */
- if (lock_r) {
+ if (r_lock) {
/* unlock in BKE_image_release_ibuf */
BLI_lock_thread(LOCK_VIEWER);
- *lock_r = ima;
+ *r_lock = ima;
/* XXX anim play for viewer nodes not yet supported */
frame = 0; // XXX iuser ? iuser->framenr : 0;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
if (!ibuf) {
/* Composite Viewer, all handled in compositor */
/* fake ibuf, will be filled in compositor */
- ibuf = IMB_allocImBuf(256, 256, 32, IB_rect);
- image_assign_ibuf(ima, ibuf, 0, frame);
+ ibuf = IMB_allocImBuf(256, 256, 32, IB_rect | IB_rectfloat);
+ image_assign_ibuf(ima, ibuf, index, frame);
}
}
}
@@ -3133,13 +4002,13 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
*
* references the result, BKE_image_release_ibuf should be used to de-reference
*/
-ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
+ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
{
ImBuf *ibuf;
BLI_spin_lock(&image_spin);
- ibuf = image_acquire_ibuf(ima, iuser, lock_r);
+ ibuf = image_acquire_ibuf(ima, iuser, r_lock);
BLI_spin_unlock(&image_spin);
@@ -3409,7 +4278,13 @@ void BKE_image_update_frame(const Main *bmain, int cfra)
void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
{
- BLI_strncpy(filepath, ima->name, FILE_MAX);
+ if ((ima->flag & IMA_IS_MULTIVIEW) && (ima->rr == NULL)) {
+ ImageView *iv = BLI_findlink(&ima->views, iuser->view);
+ BLI_strncpy(filepath, iv->filepath, FILE_MAX);
+ }
+ else {
+ BLI_strncpy(filepath, ima->name, FILE_MAX);
+ }
if (ima->source == IMA_SRC_SEQUENCE) {
char head[FILE_MAX], tail[FILE_MAX];
@@ -3545,6 +4420,16 @@ int BKE_image_sequence_guess_offset(Image *image)
return atoi(num);
}
+bool BKE_image_has_anim(Image *ima)
+{
+ return (BLI_listbase_is_empty(&ima->anims) == false);
+}
+
+bool BKE_image_has_packedfile(Image *ima)
+{
+ return (BLI_listbase_is_empty(&ima->packedfiles) == false);
+}
+
/**
* Checks the image buffer changes (not keyframed values)
*
@@ -3675,3 +4560,88 @@ ImBuf *BKE_image_get_first_ibuf(Image *image)
return ibuf;
}
+
+static void image_update_views_format(Image *ima, ImageUser *iuser)
+{
+ SceneRenderView *srv;
+ ImageView *iv;
+ Scene *scene = iuser->scene;
+ const bool is_multiview = ((scene->r.scemode & R_MULTIVIEW) != 0) &&
+ ((ima->flag & IMA_USE_VIEWS) != 0);
+
+ /* reset the image views */
+ BKE_image_free_views(ima);
+
+ if (!is_multiview) {
+ goto monoview;
+ }
+ else if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
+ size_t i;
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+
+ ima->flag |= IMA_IS_MULTIVIEW;
+ ima->flag |= IMA_IS_STEREO;
+
+ for (i = 0; i < 2; i++) {
+ image_add_view(ima, names[i], ima->name);
+ }
+ return;
+ }
+ else {
+ /* R_IMF_VIEWS_INDIVIDUAL */
+ char prefix[FILE_MAX] = {'\0'};
+ char *name = ima->name;
+ char *ext = NULL;
+
+ BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext);
+
+ if (prefix[0] == '\0') {
+ goto monoview;
+ }
+
+ /* create all the image views */
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
+ char filepath[FILE_MAX];
+ BLI_snprintf(filepath, sizeof(filepath), "%s%s%s", prefix, srv->suffix, ext);
+ image_add_view(ima, srv->name, filepath);
+ }
+ }
+
+ /* check if the files are all available */
+ iv = ima->views.last;
+ while (iv) {
+ int file;
+ char str[FILE_MAX];
+
+ BLI_strncpy(str, iv->filepath, sizeof(str));
+ BLI_path_abs(str, G.main->name);
+
+ /* exists? */
+ file = BLI_open(str, O_BINARY | O_RDONLY, 0);
+ if (file == -1) {
+ ImageView *iv_del = iv;
+ iv = iv->prev;
+ BLI_remlink(&ima->views, iv_del);
+ MEM_freeN(iv_del);
+ }
+ else {
+ iv = iv->prev;
+ close(file);
+ }
+ }
+
+ /* all good */
+ if (BLI_listbase_count_ex(&ima->views, 2) > 1) {
+ ima->flag |= IMA_IS_MULTIVIEW;
+ if (BKE_scene_multiview_is_stereo3d(&scene->r))
+ ima->flag |= IMA_IS_STEREO;
+ }
+ else {
+monoview:
+ ima->flag &= ~IMA_IS_STEREO;
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ BKE_image_free_views(ima);
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 09ce9484a69..6d37f3ae006 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -1712,7 +1712,7 @@ void do_versions_ipos_to_animato(Main *main)
/* check if object has any animation data */
if (ob->nlastrips.first) {
/* Add AnimData block */
- BKE_id_add_animdata(id);
+ BKE_animdata_add_id(id);
/* IPO first to take into any non-NLA'd Object Animation */
if (ob->ipo) {
@@ -1735,7 +1735,7 @@ void do_versions_ipos_to_animato(Main *main)
}
else if ((ob->ipo) || (ob->action)) {
/* Add AnimData block */
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
/* Action first - so that Action name get conserved */
if (ob->action) {
@@ -1776,7 +1776,7 @@ void do_versions_ipos_to_animato(Main *main)
/* check PoseChannels for constraints with local data */
if (ob->pose) {
/* Verify if there's AnimData block */
- BKE_id_add_animdata(id);
+ BKE_animdata_add_id(id);
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
@@ -1802,7 +1802,7 @@ void do_versions_ipos_to_animato(Main *main)
*/
if (con->ipo) {
/* Verify if there's AnimData block, just in case */
- BKE_id_add_animdata(id);
+ BKE_animdata_add_id(id);
/* although this was the constraint's local IPO, we still need to provide con
* so that drivers can be added properly...
@@ -1819,7 +1819,7 @@ void do_versions_ipos_to_animato(Main *main)
/* check constraint channels - we need to remove them anyway... */
if (ob->constraintChannels.first) {
/* Verify if there's AnimData block */
- BKE_id_add_animdata(id);
+ BKE_animdata_add_id(id);
for (conchan = ob->constraintChannels.first; conchan; conchan = conchann) {
/* get pointer to next Constraint Channel */
@@ -1857,7 +1857,7 @@ void do_versions_ipos_to_animato(Main *main)
*/
if (key->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
/* Convert Shapekey data... */
ipo_to_animdata(id, key->ipo, NULL, NULL, NULL);
@@ -1879,7 +1879,7 @@ void do_versions_ipos_to_animato(Main *main)
/* we're only interested in the IPO */
if (ma->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
/* Convert Material data... */
ipo_to_animdata(id, ma->ipo, NULL, NULL, NULL);
@@ -1901,7 +1901,7 @@ void do_versions_ipos_to_animato(Main *main)
/* we're only interested in the IPO */
if (wo->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
/* Convert World data... */
ipo_to_animdata(id, wo->ipo, NULL, NULL, NULL);
@@ -1921,7 +1921,7 @@ void do_versions_ipos_to_animato(Main *main)
if (ed && ed->seqbasep) {
Sequence *seq;
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
SEQ_BEGIN(ed, seq)
{
@@ -1977,7 +1977,7 @@ void do_versions_ipos_to_animato(Main *main)
/* we're only interested in the IPO */
if (te->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
/* Convert Texture data... */
ipo_to_animdata(id, te->ipo, NULL, NULL, NULL);
@@ -1999,7 +1999,7 @@ void do_versions_ipos_to_animato(Main *main)
/* we're only interested in the IPO */
if (ca->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
/* Convert Camera data... */
ipo_to_animdata(id, ca->ipo, NULL, NULL, NULL);
@@ -2021,7 +2021,7 @@ void do_versions_ipos_to_animato(Main *main)
/* we're only interested in the IPO */
if (la->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
/* Convert Lamp data... */
ipo_to_animdata(id, la->ipo, NULL, NULL, NULL);
@@ -2043,7 +2043,7 @@ void do_versions_ipos_to_animato(Main *main)
/* we're only interested in the IPO */
if (cu->ipo) {
/* Add AnimData block */
- AnimData *adt = BKE_id_add_animdata(id);
+ AnimData *adt = BKE_animdata_add_id(id);
/* Convert Curve data... */
ipo_to_animdata(id, cu->ipo, NULL, NULL, NULL);
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index f598be0298a..092dd90041f 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -52,12 +52,14 @@
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
+#include "DNA_strands_types.h"
#include "DNA_texture_types.h"
#include "BKE_animsys.h"
#include "BKE_curve.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
+#include "BKE_pointcache.h"
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
@@ -65,25 +67,26 @@
#include "BKE_particle.h"
#include "BKE_editmesh.h"
#include "BKE_scene.h"
+#include "BKE_strands.h"
#include "RNA_access.h"
#include "RE_render_ext.h"
-#define KEY_MODE_DUMMY 0 /* use where mode isn't checked for */
-#define KEY_MODE_BPOINT 1
-#define KEY_MODE_BEZTRIPLE 2
-
/* old defines from DNA_ipo_types.h for data-type, stored in DNA - don't modify! */
#define IPO_FLOAT 4
#define IPO_BEZTRIPLE 100
#define IPO_BPOINT 101
+#define KEY_MODE_DUMMY 0 /* use where mode isn't checked for */
+#define KEY_MODE_BPOINT 1
+#define KEY_MODE_BEZTRIPLE 2
+
void BKE_key_free(Key *key)
{
KeyBlock *kb;
- BKE_free_animdata((ID *)key);
+ BKE_animdata_free((ID *)key);
while ((kb = BLI_pophead(&key->block))) {
if (kb->data)
@@ -103,78 +106,82 @@ void BKE_key_free_nolib(Key *key)
}
}
-Key *BKE_key_add(ID *id) /* common function */
+static void key_set_elemstr(short fromtype, char *r_elemstr, int *r_elemsize)
{
- Key *key;
- char *el;
-
- key = BKE_libblock_alloc(G.main, ID_KE, "Key");
-
- key->type = KEY_NORMAL;
- BKE_key_set_from_id(key, id);
-
- key->uidgen = 1;
-
/* XXX the code here uses some defines which will soon be deprecated... */
- switch (GS(id->name)) {
- case ID_ME:
- el = key->elemstr;
-
- el[0] = 3;
- el[1] = IPO_FLOAT;
- el[2] = 0;
-
- key->elemsize = 12;
-
+ char elemtype = IPO_FLOAT;
+ char numelem = 0;
+ int elemsize = 0;
+
+ switch (fromtype) {
+ case KEY_OWNER_MESH:
+ numelem = 3;
+ elemtype = IPO_FLOAT;
+ elemsize = 12;
break;
- case ID_LT:
- el = key->elemstr;
-
- el[0] = 3;
- el[1] = IPO_FLOAT;
- el[2] = 0;
-
- key->elemsize = 12;
-
+ case KEY_OWNER_LATTICE:
+ numelem = 3;
+ elemtype = IPO_FLOAT;
+ elemsize = 12;
break;
- case ID_CU:
- el = key->elemstr;
-
- el[0] = 4;
- el[1] = IPO_BPOINT;
- el[2] = 0;
-
- key->elemsize = 16;
-
+ case KEY_OWNER_CURVE:
+ numelem = 4;
+ elemtype = IPO_BPOINT;
+ elemsize = 16;
+ break;
+ case KEY_OWNER_PARTICLES:
+ numelem = 3;
+ elemtype = IPO_FLOAT;
+ elemsize = 12;
+ break;
+ case KEY_OWNER_CACHELIB:
+ numelem = 3;
+ elemtype = IPO_FLOAT;
+ elemsize = 12;
break;
}
- return key;
+ r_elemstr[0] = numelem;
+ r_elemstr[1] = elemtype;
+ r_elemstr[2] = 0;
+ *r_elemsize = elemsize;
}
-Key *BKE_key_add_particles(Object *ob, ParticleSystem *psys) /* particles are "special" */
+Key *BKE_key_add_ex(ID *from, int fromtype, int fromindex) /* common function */
{
Key *key;
- char *el;
key = BKE_libblock_alloc(G.main, ID_KE, "Key");
key->type = KEY_NORMAL;
- BKE_key_set_from_particles(key, ob, psys);
-
+ key->from = from;
+ key->fromtype = fromtype;
+ key->fromindex = fromindex;
+
key->uidgen = 1;
- el = key->elemstr;
-
- el[0] = 3;
- el[1] = IPO_FLOAT;
- el[2] = 0;
-
- key->elemsize = 12;
+ key_set_elemstr(fromtype, key->elemstr, &key->elemsize);
return key;
}
+Key *BKE_key_add(ID *id)
+{
+ int fromtype = 0;
+ switch (GS(id->name)) {
+ case ID_ME: fromtype = KEY_OWNER_MESH; break;
+ case ID_CU: fromtype = KEY_OWNER_CURVE; break;
+ case ID_LT: fromtype = KEY_OWNER_LATTICE; break;
+ default: BLI_assert(false); break; /* other fromtypes should use the _ex version for specifying the type */
+ }
+ return BKE_key_add_ex(id, fromtype, -1);
+}
+
+Key *BKE_key_add_particles(Object *ob, ParticleSystem *psys) /* particles are "special" */
+{
+ return BKE_key_add_ex((ID *)ob, KEY_OWNER_PARTICLES, BLI_findindex(&ob->particlesystem, psys));
+}
+
Key *BKE_key_copy(Key *key)
{
Key *keyn;
@@ -284,11 +291,11 @@ void BKE_key_set_from_id(Key *key, ID *id)
if (key) {
key->from = id;
switch (GS(id->name)) {
- case ID_ME: key->from_extra.type = KEY_OWNER_MESH; break;
- case ID_CU: key->from_extra.type = KEY_OWNER_CURVE; break;
- case ID_LT: key->from_extra.type = KEY_OWNER_LATTICE; break;
+ case ID_ME: key->fromtype = KEY_OWNER_MESH; break;
+ case ID_CU: key->fromtype = KEY_OWNER_CURVE; break;
+ case ID_LT: key->fromtype = KEY_OWNER_LATTICE; break;
}
- key->from_extra.index = -1;
+ key->fromindex = -1;
}
}
@@ -296,8 +303,8 @@ void BKE_key_set_from_particles(Key *key, Object *ob, ParticleSystem *psys)
{
if (key) {
key->from = (ID *)ob;
- key->from_extra.type = KEY_OWNER_PARTICLES;
- key->from_extra.index = BLI_findindex(&ob->particlesystem, psys);
+ key->fromtype = KEY_OWNER_PARTICLES;
+ key->fromindex = BLI_findindex(&ob->particlesystem, psys);
}
}
@@ -565,7 +572,7 @@ static char *key_block_get_data(Key *key, KeyBlock *actkb, KeyBlock *kb, char **
if (kb == actkb) {
/* this hack makes it possible to edit shape keys in
* edit mode with shape keys blending applied */
- if (key->from_extra.type == KEY_OWNER_MESH) {
+ if (key->from && key->fromtype == KEY_OWNER_MESH) {
Mesh *me;
BMVert *eve;
BMIter iter;
@@ -597,7 +604,11 @@ static char *key_block_get_data(Key *key, KeyBlock *actkb, KeyBlock *kb, char **
/* currently only the first value of 'ofs' may be set. */
static bool key_pointer_size(const Key *key, const int mode, int *poinsize, int *ofs)
{
- switch (key->from_extra.type) {
+ /* some types allow NULL for key->from */
+ if (!key->from && !ELEM(key->fromtype, KEY_OWNER_CACHELIB))
+ return false;
+
+ switch (key->fromtype) {
case KEY_OWNER_MESH:
*ofs = sizeof(float) * 3;
*poinsize = *ofs;
@@ -620,12 +631,15 @@ static bool key_pointer_size(const Key *key, const int mode, int *poinsize, int
*ofs = sizeof(float) * 3;
*poinsize = *ofs;
break;
-
+ case KEY_OWNER_CACHELIB:
+ *ofs = sizeof(float) * 3;
+ *poinsize = *ofs;
+ break;
+
default:
BLI_assert(!"invalid 'key->from' ID type");
return false;
}
-
return true;
}
@@ -747,6 +761,87 @@ static void cp_key(const int start, int end, const int tot, char *poin, Key *key
if (freekref) MEM_freeN(freekref);
}
+static void cp_key_strands(const int start, int end, const int tot, char *poin, Key *key, KeyBlock *actkb, KeyBlock *kb, float *weights, const int mode)
+{
+ float ktot = 0.0, kd = 0.0;
+ int elemsize, poinsize = 0, a, ofs, flagflo = 0;
+ char *k1, *freek1;
+
+ /* currently always 0, in future key_pointer_size may assign */
+ ofs = 0;
+
+ if (!key_pointer_size(key, mode, &poinsize, &ofs))
+ return;
+
+ if (end > tot) end = tot;
+
+ if (tot != kb->totelem) {
+ ktot = 0.0;
+ flagflo = 1;
+ if (kb->totelem) {
+ kd = kb->totelem / (float)tot;
+ }
+ else {
+ return;
+ }
+ }
+
+ k1 = key_block_get_data(key, actkb, kb, &freek1);
+
+ /* this exception is needed curves with multiple splines */
+ if (start != 0) {
+
+ poin += poinsize * start;
+
+ if (flagflo) {
+ ktot += start * kd;
+ a = (int)floor(ktot);
+ if (a) {
+ ktot -= a;
+ k1 += a * key->elemsize;
+ }
+ }
+ else {
+ k1 += start * key->elemsize;
+ }
+ }
+
+ /* just do it here, not above! */
+ elemsize = key->elemsize;
+ if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3;
+
+ for (a = start; a < end; a++) {
+ if (weights) {
+ if (*weights != 0.0f)
+ madd_v3_v3fl((float *)poin, (float *)k1, *weights);
+ weights++;
+ }
+ else {
+ add_v3_v3((float *)poin, (float *)k1);
+ }
+
+ poin += ofs;
+
+ /* are we going to be nasty? */
+ if (flagflo) {
+ ktot += kd;
+ while (ktot >= 1.0f) {
+ ktot -= 1.0f;
+ k1 += elemsize;
+ }
+ }
+ else {
+ k1 += elemsize;
+ }
+
+ if (mode == KEY_MODE_BEZTRIPLE) {
+ a += 2;
+ }
+ }
+
+ if (freek1) MEM_freeN(freek1);
+}
+
static void cp_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock *kb, const int start, int end, char *out, const int tot)
{
Nurb *nu;
@@ -781,7 +876,8 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba
{
KeyBlock *kb;
int *ofsp, ofs[3], elemsize, b;
- char *cp, *poin, *reffrom, *from, elemstr[8];
+ char *poin, *reffrom, *from;
+ char elemstr[8];
int poinsize, keyblock_index;
/* currently always 0, in future key_pointer_size may assign */
@@ -812,23 +908,25 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba
/* only with value, and no difference allowed */
if (!(kb->flag & KEYBLOCK_MUTE) && icuval != 0.0f && kb->totelem == tot) {
- KeyBlock *refb;
float weight, *weights = per_keyblock_weights ? per_keyblock_weights[keyblock_index] : NULL;
char *freefrom = NULL, *freereffrom = NULL;
- /* reference now can be any block */
- refb = BLI_findlink(&key->block, kb->relative);
- if (refb == NULL) continue;
-
poin = basispoin;
from = key_block_get_data(key, actkb, kb, &freefrom);
- reffrom = key_block_get_data(key, actkb, refb, &freereffrom);
+ {
+ /* reference now can be any block */
+ KeyBlock *refb = BLI_findlink(&key->block, kb->relative);
+ if (refb == NULL) continue;
+
+ reffrom = key_block_get_data(key, actkb, refb, &freereffrom);
+ }
poin += start * poinsize;
reffrom += key->elemsize * start; // key elemsize yes!
from += key->elemsize * start;
for (b = start; b < end; b++) {
+ char *cp;
weight = weights ? (*weights * icuval) : icuval;
@@ -877,6 +975,57 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba
}
}
+void BKE_key_evaluate_strands_relative(const int start, int end, const int tot, char *basispoin, Key *key, KeyBlock *actkb,
+ float **per_keyblock_weights, const int mode)
+{
+ KeyBlock *kb;
+ int ofs, elemsize, b;
+ char *poin, *from;
+ int poinsize, keyblock_index;
+
+ if (!key_pointer_size(key, mode, &poinsize, &ofs))
+ return;
+
+ if (end > tot) end = tot;
+
+ /* just here, not above! */
+ elemsize = key->elemsize;
+ if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3;
+
+ for (kb = key->block.first, keyblock_index = 0; kb; kb = kb->next, keyblock_index++) {
+ if (kb != key->refkey) {
+ float icuval = kb->curval;
+
+ /* only with value, and no difference allowed */
+ if (!(kb->flag & KEYBLOCK_MUTE) && icuval != 0.0f && kb->totelem == tot) {
+ float weight, *weights = per_keyblock_weights ? per_keyblock_weights[keyblock_index] : NULL;
+ char *freefrom = NULL;
+
+ poin = basispoin;
+ from = key_block_get_data(key, actkb, kb, &freefrom);
+
+ poin += start * poinsize;
+ from += key->elemsize * start;
+
+ for (b = start; b < end; b++) {
+ float delta[3];
+
+ weight = weights ? (*weights * icuval) : icuval;
+
+ sub_v3_v3v3(delta, (float *)from, (float *)poin);
+ madd_v3_v3fl((float *)poin, delta, weight);
+
+ poin += ofs;
+ from += elemsize;
+ if (mode == KEY_MODE_BEZTRIPLE) b += 2;
+ if (weights) weights++;
+ }
+
+ if (freefrom) MEM_freeN(freefrom);
+ }
+ }
+ }
+}
static void do_key(const int start, int end, const int tot, char *poin, Key *key, KeyBlock *actkb, KeyBlock **k, float *t, const int mode)
{
@@ -1053,6 +1202,200 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key
k1 += elemsize;
}
}
+ else {
+ k1 += elemsize;
+ }
+ }
+ if (flagdo & 2) {
+ if (flagflo & 2) {
+ k2tot += k2d;
+ while (k2tot >= 1.0f) {
+ k2tot -= 1.0f;
+ k2 += elemsize;
+ }
+ }
+ else {
+ k2 += elemsize;
+ }
+ }
+ if (flagdo & 4) {
+ if (flagflo & 4) {
+ k3tot += k3d;
+ while (k3tot >= 1.0f) {
+ k3tot -= 1.0f;
+ k3 += elemsize;
+ }
+ }
+ else {
+ k3 += elemsize;
+ }
+ }
+ if (flagdo & 8) {
+ if (flagflo & 8) {
+ k4tot += k4d;
+ while (k4tot >= 1.0f) {
+ k4tot -= 1.0f;
+ k4 += elemsize;
+ }
+ }
+ else {
+ k4 += elemsize;
+ }
+ }
+
+ if (mode == KEY_MODE_BEZTRIPLE) a += 2;
+ }
+
+ if (freek1) MEM_freeN(freek1);
+ if (freek2) MEM_freeN(freek2);
+ if (freek3) MEM_freeN(freek3);
+ if (freek4) MEM_freeN(freek4);
+}
+
+static void do_key_strands(const int start, int end, const int tot, char *poin, Key *key, KeyBlock *actkb, KeyBlock **k, float *t, const int mode)
+{
+ float k1tot = 0.0, k2tot = 0.0, k3tot = 0.0, k4tot = 0.0;
+ float k1d = 0.0, k2d = 0.0, k3d = 0.0, k4d = 0.0;
+ int a, ofs;
+ int flagdo = 15, flagflo = 0, elemsize, poinsize = 0;
+ char *k1, *k2, *k3, *k4, *freek1, *freek2, *freek3, *freek4;
+
+ /* currently always 0, in future key_pointer_size may assign */
+ if (!key_pointer_size(key, mode, &poinsize, &ofs))
+ return;
+
+ if (end > tot) end = tot;
+
+ k1 = key_block_get_data(key, actkb, k[0], &freek1);
+ k2 = key_block_get_data(key, actkb, k[1], &freek2);
+ k3 = key_block_get_data(key, actkb, k[2], &freek3);
+ k4 = key_block_get_data(key, actkb, k[3], &freek4);
+
+ /* test for more or less points (per key!) */
+ if (tot != k[0]->totelem) {
+ k1tot = 0.0;
+ flagflo |= 1;
+ if (k[0]->totelem) {
+ k1d = k[0]->totelem / (float)tot;
+ }
+ else {
+ flagdo -= 1;
+ }
+ }
+ if (tot != k[1]->totelem) {
+ k2tot = 0.0;
+ flagflo |= 2;
+ if (k[0]->totelem) {
+ k2d = k[1]->totelem / (float)tot;
+ }
+ else {
+ flagdo -= 2;
+ }
+ }
+ if (tot != k[2]->totelem) {
+ k3tot = 0.0;
+ flagflo |= 4;
+ if (k[0]->totelem) {
+ k3d = k[2]->totelem / (float)tot;
+ }
+ else {
+ flagdo -= 4;
+ }
+ }
+ if (tot != k[3]->totelem) {
+ k4tot = 0.0;
+ flagflo |= 8;
+ if (k[0]->totelem) {
+ k4d = k[3]->totelem / (float)tot;
+ }
+ else {
+ flagdo -= 8;
+ }
+ }
+
+ /* this exception is needed for curves with multiple splines */
+ if (start != 0) {
+
+ poin += poinsize * start;
+
+ if (flagdo & 1) {
+ if (flagflo & 1) {
+ k1tot += start * k1d;
+ a = (int)floor(k1tot);
+ if (a) {
+ k1tot -= a;
+ k1 += a * key->elemsize;
+ }
+ }
+ else {
+ k1 += start * key->elemsize;
+ }
+ }
+ if (flagdo & 2) {
+ if (flagflo & 2) {
+ k2tot += start * k2d;
+ a = (int)floor(k2tot);
+ if (a) {
+ k2tot -= a;
+ k2 += a * key->elemsize;
+ }
+ }
+ else {
+ k2 += start * key->elemsize;
+ }
+ }
+ if (flagdo & 4) {
+ if (flagflo & 4) {
+ k3tot += start * k3d;
+ a = (int)floor(k3tot);
+ if (a) {
+ k3tot -= a;
+ k3 += a * key->elemsize;
+ }
+ }
+ else {
+ k3 += start * key->elemsize;
+ }
+ }
+ if (flagdo & 8) {
+ if (flagflo & 8) {
+ k4tot += start * k4d;
+ a = (int)floor(k4tot);
+ if (a) {
+ k4tot -= a;
+ k4 += a * key->elemsize;
+ }
+ }
+ else {
+ k4 += start * key->elemsize;
+ }
+ }
+
+ }
+
+ /* only here, not above! */
+ elemsize = key->elemsize;
+ if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3;
+
+ for (a = start; a < end; a++) {
+
+ zero_v3((float *)poin);
+ madd_v3_v3fl((float *)poin, (float *)k1, t[0]);
+ madd_v3_v3fl((float *)poin, (float *)k2, t[1]);
+ madd_v3_v3fl((float *)poin, (float *)k3, t[2]);
+ madd_v3_v3fl((float *)poin, (float *)k4, t[3]);
+
+ poin += ofs;
+
+ /* lets do it the difficult way: when keys have a different size */
+ if (flagdo & 1) {
+ if (flagflo & 1) {
+ k1tot += k1d;
+ while (k1tot >= 1.0f) {
+ k1tot -= 1.0f;
+ k1 += elemsize;
+ }
+ }
else k1 += elemsize;
}
if (flagdo & 2) {
@@ -1173,6 +1516,21 @@ static float *get_object_weights_array(Object *ob, char *vgroup, WeightsArrayCac
return NULL;
}
+static float *get_weights_array_strands(Strands *strands, const char *UNUSED(vgroup), bool is_refkey, WeightsArrayCache *UNUSED(cache))
+{
+ int totvert = strands->totverts;
+
+ if (is_refkey) {
+ /* for the refkey, return zero weights, so the refkey actually uses the unmodified data */
+ float *weights = MEM_callocN(totvert * sizeof(float), "weights");
+ return weights;
+ }
+ else {
+ /* TODO no vgroup support for strands yet */
+ return NULL;
+ }
+}
+
float **BKE_keyblock_get_per_block_object_weights(Object *ob, Key *key, WeightsArrayCache *cache)
{
KeyBlock *keyblock;
@@ -1280,6 +1638,26 @@ float **BKE_keyblock_get_per_block_particle_weights(Object *ob, ParticleSystem *
return per_keyblock_weights;
}
+float **BKE_keyblock_strands_get_per_block_weights(Strands *strands, Key *key, WeightsArrayCache *cache)
+{
+ KeyBlock *keyblock;
+ float **per_keyblock_weights;
+ int keyblock_index;
+
+ per_keyblock_weights =
+ MEM_mallocN(sizeof(*per_keyblock_weights) * key->totkey,
+ "per keyblock weights");
+
+ for (keyblock = key->block.first, keyblock_index = 0;
+ keyblock;
+ keyblock = keyblock->next, keyblock_index++)
+ {
+ per_keyblock_weights[keyblock_index] = get_weights_array_strands(strands, keyblock->vgroup, keyblock == key->refkey, cache);
+ }
+
+ return per_keyblock_weights;
+}
+
void BKE_keyblock_free_per_block_weights(Key *key, float **per_keyblock_weights, WeightsArrayCache *cache)
{
int a;
@@ -1554,10 +1932,114 @@ float *BKE_key_evaluate_object(Object *ob, int *r_totelem)
return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0);
}
+static void do_strands_key(Strands *strands, Key *key, KeyBlock *actkb, char *out, const int tot)
+{
+ KeyBlock *k[4];
+ float t[4];
+ int flag = 0;
+
+ if (key->type == KEY_RELATIVE) {
+ WeightsArrayCache cache = {0, NULL};
+ float **per_keyblock_weights ;
+ per_keyblock_weights = BKE_keyblock_strands_get_per_block_weights(strands, key, &cache);
+ BKE_key_evaluate_strands_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY);
+ BKE_keyblock_free_per_block_weights(key, per_keyblock_weights, &cache);
+ }
+ else {
+ const float ctime_scaled = key->ctime / 100.0f;
+
+ flag = setkeys(ctime_scaled, &key->block, k, t, 0);
+
+ if (flag == 0) {
+ do_key_strands(0, tot, tot, (char *)out, key, actkb, k, t, KEY_MODE_DUMMY);
+ }
+ else {
+ cp_key_strands(0, tot, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY);
+ }
+ }
+}
+
+float *BKE_key_evaluate_strands_ex(Strands *strands, Key *key, KeyBlock *actkb, bool lock_shape, int *r_totelem, float *arr, size_t arr_size)
+{
+ char *out;
+ int tot = 0, size = 0;
+
+ if (key == NULL || BLI_listbase_is_empty(&key->block))
+ return NULL;
+
+ /* compute size of output array */
+ tot = strands->totverts;
+ size = tot * 3 * sizeof(float);
+ /* if nothing to interpolate, cancel */
+ if (tot == 0 || size == 0)
+ return NULL;
+
+ /* allocate array */
+ if (arr == NULL) {
+ out = MEM_callocN(size, "BKE_key_evaluate_strands out");
+ }
+ else {
+ if (arr_size != size) {
+ return NULL;
+ }
+
+ out = (char *)arr;
+ }
+
+ if (lock_shape && actkb) {
+ /* shape locked, copy the locked shape instead of blending */
+ float *weights;
+
+ if (actkb->flag & KEYBLOCK_MUTE)
+ actkb = key->refkey;
+
+ /* XXX weights not supported for strands yet */
+ weights = get_weights_array_strands(strands, actkb->vgroup, actkb == key->refkey, NULL);
+
+ cp_key_strands(0, tot, tot, out, key, actkb, actkb, weights, 0);
+
+ if (weights)
+ MEM_freeN(weights);
+ }
+ else {
+ do_strands_key(strands, key, actkb, out, tot);
+ }
+
+ if (r_totelem) {
+ *r_totelem = tot;
+ }
+ return (float *)out;
+}
+
+float *BKE_key_evaluate_strands(Strands *strands, Key *key, KeyBlock *actkb, bool lock_shape, int *r_totelem, bool use_motion)
+{
+ size_t size = sizeof(float) * 3 * strands->totverts;
+ float *data = MEM_mallocN(size, "strands shape key data");
+ float *result;
+ float *fp;
+ int i;
+
+ if (use_motion && strands->state) {
+ for (i = 0, fp = data; i < strands->totverts; ++i, fp += 3)
+ copy_v3_v3(fp, strands->state[i].co);
+ }
+ else {
+ for (i = 0, fp = data; i < strands->totverts; ++i, fp += 3)
+ copy_v3_v3(fp, strands->verts[i].co);
+ }
+
+ result = BKE_key_evaluate_strands_ex(strands, key, actkb, lock_shape, r_totelem, data, size);
+ if (result != data)
+ MEM_freeN(data);
+
+ return result;
+}
+
/* returns key coordinates when key applied, NULL otherwise */
float *BKE_key_evaluate_particles_ex(Object *ob, ParticleSystem *psys, float cfra, int *r_totelem,
float *arr, size_t arr_size)
{
+ const bool use_editmode = (ob->mode & OB_MODE_PARTICLE_EDIT) && psys == psys_get_current(ob) && (psys->edit || psys->pointcache->edit) && !psys->renderdata;
Key *key = psys->key;
KeyBlock *actkb = BKE_keyblock_from_particles(psys);
char *out;
@@ -1592,7 +2074,21 @@ float *BKE_key_evaluate_particles_ex(Object *ob, ParticleSystem *psys, float cfr
/* prevent python from screwing this up? anyhoo, the from pointer could be dropped */
BKE_key_set_from_particles(key, ob, psys);
- if (ob->shapeflag & OB_SHAPE_LOCK) {
+ if (use_editmode) {
+ /* in edit mode, only evaluate the active shape */
+ KeyBlock *kb = BLI_findlink(&key->block, psys->shapenr - 1);
+
+ if (kb && (kb->flag & KEYBLOCK_MUTE))
+ kb = key->refkey;
+
+ if (kb == NULL) {
+ kb = key->block.first;
+ psys->shapenr = 1;
+ }
+
+ cp_key(0, tot, tot, out, key, actkb, kb, NULL, 0);
+ }
+ else if (ob->shapeflag & OB_SHAPE_LOCK) {
/* shape locked, copy the locked shape instead of blending */
KeyBlock *kb = BLI_findlink(&key->block, psys->shapenr - 1);
float *weights;
@@ -1626,25 +2122,37 @@ float *BKE_key_evaluate_particles(Object *ob, ParticleSystem *psys, float cfra,
return BKE_key_evaluate_particles_ex(ob, psys, cfra, r_totelem, NULL, 0);
}
-Key *BKE_key_from_object(Object *ob)
+Key **BKE_key_from_object_p(Object *ob)
{
- if (ob == NULL) return NULL;
-
+ if (ob == NULL)
+ return NULL;
+
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
- return me->key;
+ return &me->key;
}
else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
Curve *cu = ob->data;
- return cu->key;
+ return &cu->key;
}
else if (ob->type == OB_LATTICE) {
Lattice *lt = ob->data;
- return lt->key;
+ return &lt->key;
}
return NULL;
}
+Key *BKE_key_from_object(Object *ob)
+{
+ Key **key_p;
+ key_p = BKE_key_from_object_p(ob);
+ if (key_p) {
+ return *key_p;
+ }
+
+ return NULL;
+}
+
KeyBlock *BKE_keyblock_add(Key *key, const char *name)
{
KeyBlock *kb;
@@ -2019,6 +2527,72 @@ void BKE_keyblock_convert_to_mesh(KeyBlock *kb, Mesh *me)
}
}
+/************************* Strands ************************/
+void BKE_keyblock_update_from_strands(Strands *strands, KeyBlock *kb, bool use_motion)
+{
+ float (*fp)[3];
+ int a, tot;
+
+ BLI_assert(strands->totverts == kb->totelem);
+
+ tot = strands->totverts;
+ if (tot == 0) return;
+
+ fp = kb->data;
+ /* use vertex locations as fallback, so we always get a valid shape */
+ if (use_motion && strands->state) {
+ StrandsMotionState *state = strands->state;
+ for (a = 0; a < tot; a++, fp++, state++) {
+ copy_v3_v3(*fp, state->co);
+ }
+ }
+ else {
+ StrandsVertex *vert = strands->verts;
+ for (a = 0; a < tot; a++, fp++, vert++) {
+ copy_v3_v3(*fp, vert->co);
+ }
+ }
+}
+
+void BKE_keyblock_convert_from_strands(Strands *strands, Key *key, KeyBlock *kb, bool use_motion)
+{
+ int tot = strands->totverts;
+
+ if (strands->totverts == 0) return;
+
+ MEM_SAFE_FREE(kb->data);
+
+ kb->data = MEM_mallocN(key->elemsize * tot, __func__);
+ kb->totelem = tot;
+
+ BKE_keyblock_update_from_strands(strands, kb, use_motion);
+}
+
+void BKE_keyblock_convert_to_strands(KeyBlock *kb, Strands *strands, bool use_motion)
+{
+ const float (*fp)[3];
+ int a, tot;
+
+ fp = kb->data;
+
+ tot = min_ii(kb->totelem, strands->totverts);
+
+ if (use_motion) {
+ if (strands->state) {
+ StrandsMotionState *state = strands->state;
+ for (a = 0; a < tot; a++, fp++, state++) {
+ copy_v3_v3(state->co, *fp);
+ }
+ }
+ }
+ else {
+ StrandsVertex *vert = strands->verts;
+ for (a = 0; a < tot; a++, fp++, vert++) {
+ copy_v3_v3(vert->co, *fp);
+ }
+ }
+}
+
/************************* raw coords ************************/
void BKE_keyblock_update_from_vertcos(Object *ob, KeyBlock *kb, float (*vertCos)[3])
{
@@ -2256,11 +2830,10 @@ void BKE_keyblock_convert_from_hair_keys(struct Object *UNUSED(ob), struct Parti
* \param org_index if < 0, current object's active shape will be used as skey to move.
* \return true if something was done, else false.
*/
-bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
+bool BKE_keyblock_move_ex(Key *key, int *shapenr, int org_index, int new_index)
{
- Key *key = BKE_key_from_object(ob);
KeyBlock *kb;
- const int act_index = ob->shapenr - 1;
+ const int act_index = *shapenr - 1;
const int totkey = key->totkey;
int i;
bool rev, in_range = false;
@@ -2320,13 +2893,13 @@ bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
/* Need to update active shape number if it's affected, same principle as for relative indices above. */
if (org_index == act_index) {
- ob->shapenr = new_index + 1;
+ *shapenr = new_index + 1;
}
else if (act_index < org_index && act_index >= new_index) {
- ob->shapenr++;
+ (*shapenr)++;
}
else if (act_index > org_index && act_index <= new_index) {
- ob->shapenr--;
+ (*shapenr)--;
}
/* First key is always refkey, matches interface and BKE_key_sort */
@@ -2335,6 +2908,14 @@ bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
return true;
}
+bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
+{
+ int shapenr;
+ bool result = BKE_keyblock_move_ex(BKE_key_from_object(ob), &shapenr, org_index, new_index);
+ ob->shapenr = shapenr;
+ return result;
+}
+
/**
* Check if given keyblock (as index) is used as basis by others in given key.
*/
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index 93b9c22566d..44e35c645de 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -221,7 +221,7 @@ void BKE_lamp_free(Lamp *la)
if (mtex) MEM_freeN(mtex);
}
- BKE_free_animdata((ID *)la);
+ BKE_animdata_free((ID *)la);
curvemapping_free(la->curfalloff);
@@ -232,7 +232,7 @@ void BKE_lamp_free(Lamp *la)
}
BKE_previewimg_free(&la->preview);
- BKE_icon_delete(&la->id);
+ BKE_icon_id_delete(&la->id);
la->id.icon_id = 0;
}
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 13f6e1b87b2..582c164a776 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -53,6 +53,7 @@
#include "BKE_anim.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_global.h"
#include "BKE_key.h"
@@ -307,7 +308,7 @@ void BKE_lattice_free(Lattice *lt)
/* free animation data */
if (lt->adt) {
- BKE_free_animdata(&lt->id);
+ BKE_animdata_free(&lt->id);
lt->adt = NULL;
}
}
@@ -725,8 +726,9 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3],
return false;
}
-void curve_deform_verts(Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3],
- int numVerts, const char *vgroup, short defaxis)
+void curve_deform_verts(
+ Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3],
+ int numVerts, const char *vgroup, short defaxis)
{
Curve *cu;
int a;
@@ -1068,7 +1070,7 @@ void BKE_lattice_modifiers_calc(Scene *scene, Object *ob)
}
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -1205,3 +1207,10 @@ void BKE_lattice_translate(Lattice *lt, float offset[3], bool do_keys)
}
}
+/* **** Depsgraph evaluation **** */
+
+void BKE_lattice_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+ Lattice *UNUSED(latt))
+{
+}
+
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index fa4f9c6ed52..c850216f5ef 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -45,6 +45,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
+#include "DNA_cache_library_types.h"
#include "DNA_camera_types.h"
#include "DNA_group_types.h"
#include "DNA_gpencil_types.h"
@@ -79,6 +80,7 @@
#include "BKE_armature.h"
#include "BKE_bpath.h"
#include "BKE_brush.h"
+#include "BKE_cache_library.h"
#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_curve.h"
@@ -107,6 +109,7 @@
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_packedFile.h"
+#include "BKE_pointcache.h"
#include "BKE_speaker.h"
#include "BKE_sound.h"
#include "BKE_screen.h"
@@ -115,6 +118,8 @@
#include "BKE_texture.h"
#include "BKE_world.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#ifdef WITH_PYTHON
@@ -291,7 +296,7 @@ bool id_make_local(ID *id, bool test)
/**
* Invokes the appropriate copy method for the block and returns the result in
- * newid, unless test. Returns true iff the block can be copied.
+ * newid, unless test. Returns true if the block can be copied.
*/
bool id_copy(ID *id, ID **newid, bool test)
{
@@ -384,7 +389,7 @@ bool id_copy(ID *id, ID **newid, bool test)
if (!test) *newid = (ID *)BKE_mask_copy((Mask *)id);
return true;
case ID_LS:
- if (!test) *newid = (ID *)BKE_linestyle_copy((FreestyleLineStyle *)id);
+ if (!test) *newid = (ID *)BKE_linestyle_copy(G.main, (FreestyleLineStyle *)id);
return true;
}
@@ -409,6 +414,10 @@ bool id_unlink(ID *id, int test)
if (test) return true;
BKE_object_unlink((Object *)id);
break;
+ case ID_CL:
+ if (test) return true;
+ BKE_cache_library_unlink((CacheLibrary *)id);
+ break;
}
if (id->us == 0) {
@@ -432,7 +441,7 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
if (RNA_property_editable(ptr, prop)) {
if (id_copy(id, &newid, false) && newid) {
/* copy animation actions too */
- BKE_copy_animdata_id_action(id);
+ BKE_animdata_copy_id_action(id);
/* us is 1 by convention, but RNA_property_pointer_set
* will also increment it, so set it to zero */
newid->us = 0;
@@ -521,6 +530,8 @@ ListBase *which_libbase(Main *mainlib, short type)
return &(mainlib->palettes);
case ID_PC:
return &(mainlib->paintcurves);
+ case ID_CL:
+ return &(mainlib->cache_library);
}
return NULL;
}
@@ -610,13 +621,14 @@ int set_listbasepointers(Main *main, ListBase **lb)
lb[a++] = &(main->speaker);
lb[a++] = &(main->world);
+ lb[a++] = &(main->movieclip);
lb[a++] = &(main->screen);
lb[a++] = &(main->object);
lb[a++] = &(main->linestyle); /* referenced by scenes */
lb[a++] = &(main->scene);
lb[a++] = &(main->library);
+ lb[a++] = &(main->cache_library);
lb[a++] = &(main->wm);
- lb[a++] = &(main->movieclip);
lb[a++] = &(main->mask);
lb[a] = NULL;
@@ -747,6 +759,9 @@ static ID *alloc_libblock_notest(short type)
case ID_PC:
id = MEM_callocN(sizeof(PaintCurve), "Paint Curve");
break;
+ case ID_CL:
+ id = MEM_callocN(sizeof(CacheLibrary), "Cache Library");
+ break;
}
return id;
}
@@ -785,7 +800,7 @@ static void id_copy_animdata(ID *id, const bool do_action)
if (adt) {
IdAdtTemplate *iat = (IdAdtTemplate *)id;
- iat->adt = BKE_copy_animdata(iat->adt, do_action); /* could be set to false, need to investigate */
+ iat->adt = BKE_animdata_copy(iat->adt, do_action); /* could be set to false, need to investigate */
}
}
@@ -865,18 +880,24 @@ static void BKE_library_free(Library *lib)
static void (*free_windowmanager_cb)(bContext *, wmWindowManager *) = NULL;
-void set_free_windowmanager_cb(void (*func)(bContext *C, wmWindowManager *) )
+void BKE_library_callback_free_window_manager_set(void (*func)(bContext *C, wmWindowManager *) )
{
free_windowmanager_cb = func;
}
static void (*free_notifier_reference_cb)(const void *) = NULL;
-void set_free_notifier_reference_cb(void (*func)(const void *) )
+void BKE_library_callback_free_notifier_reference_set(void (*func)(const void *) )
{
free_notifier_reference_cb = func;
}
+static void (*free_editor_id_reference_cb)(const ID *) = NULL;
+
+void BKE_library_callback_free_editor_id_reference_set(void (*func)(const ID *))
+{
+ free_editor_id_reference_cb = func;
+}
static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
{
@@ -1029,13 +1050,21 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user)
case ID_PC:
BKE_paint_curve_free((PaintCurve *)id);
break;
+ case ID_CL:
+ BKE_cache_library_free((CacheLibrary *)id);
+ break;
}
/* avoid notifying on removed data */
BKE_main_lock(bmain);
- if (free_notifier_reference_cb)
+ if (free_notifier_reference_cb) {
free_notifier_reference_cb(id);
+ }
+
+ if (free_editor_id_reference_cb) {
+ free_editor_id_reference_cb(id);
+ }
BLI_remlink(lb, id);
@@ -1070,8 +1099,7 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
Main *BKE_main_new(void)
{
Main *bmain = MEM_callocN(sizeof(Main), "new main");
- bmain->eval_ctx = MEM_callocN(sizeof(EvaluationContext),
- "EvaluationContext");
+ bmain->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_VIEWPORT);
bmain->lock = MEM_mallocN(sizeof(SpinLock), "main lock");
BLI_spin_init((SpinLock *)bmain->lock);
return bmain;
@@ -1138,7 +1166,7 @@ void BKE_main_free(Main *mainvar)
BLI_spin_end((SpinLock *)mainvar->lock);
MEM_freeN(mainvar->lock);
- MEM_freeN(mainvar->eval_ctx);
+ DEG_evaluation_context_free(mainvar->eval_ctx);
MEM_freeN(mainvar);
}
@@ -1404,16 +1432,11 @@ void id_clear_lib_data(Main *bmain, ID *id)
/* internal bNodeTree blocks inside ID types below
* also stores id->lib, make sure this stays in sync.
*/
- switch (GS(id->name)) {
- case ID_SCE: ntree = ((Scene *)id)->nodetree; break;
- case ID_MA: ntree = ((Material *)id)->nodetree; break;
- case ID_LA: ntree = ((Lamp *)id)->nodetree; break;
- case ID_WO: ntree = ((World *)id)->nodetree; break;
- case ID_TE: ntree = ((Tex *)id)->nodetree; break;
- case ID_LS: ntree = ((FreestyleLineStyle *)id)->nodetree; break;
- }
- if (ntree)
+ ntree = ntreeFromID(id);
+
+ if (ntree) {
ntree->id.lib = NULL;
+ }
}
/* next to indirect usage in read/writefile also in editobject.c scene.c */
@@ -1603,7 +1626,7 @@ void rename_id(ID *id, const char *name)
void name_uiprefix_id(char *name, const ID *id)
{
name[0] = id->lib ? 'L' : ' ';
- name[1] = id->flag & LIB_FAKEUSER ? 'F' : (id->us == 0) ? '0' : ' ';
+ name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' ');
name[2] = ' ';
strcpy(name + 3, id->name + 2);
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index b97bf0ed9b0..40db411ef4c 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -107,14 +107,11 @@ static void default_linestyle_settings(FreestyleLineStyle *linestyle)
linestyle->caps = LS_CAPS_BUTT;
}
-FreestyleLineStyle *BKE_linestyle_new(const char *name, struct Main *main)
+FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name)
{
FreestyleLineStyle *linestyle;
- if (!main)
- main = G.main;
-
- linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(main, ID_LS, name);
+ linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(bmain, ID_LS, name);
default_linestyle_settings(linestyle);
@@ -138,7 +135,7 @@ void BKE_linestyle_free(FreestyleLineStyle *linestyle)
MEM_freeN(linestyle->nodetree);
}
- BKE_free_animdata(&linestyle->id);
+ BKE_animdata_free(&linestyle->id);
while ((m = (LineStyleModifier *)linestyle->color_modifiers.first))
BKE_linestyle_color_modifier_remove(linestyle, m);
while ((m = (LineStyleModifier *)linestyle->alpha_modifiers.first))
@@ -149,13 +146,13 @@ void BKE_linestyle_free(FreestyleLineStyle *linestyle)
BKE_linestyle_geometry_modifier_remove(linestyle, m);
}
-FreestyleLineStyle *BKE_linestyle_copy(FreestyleLineStyle *linestyle)
+FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *linestyle)
{
FreestyleLineStyle *new_linestyle;
LineStyleModifier *m;
int a;
- new_linestyle = BKE_linestyle_new(linestyle->id.name + 2, NULL);
+ new_linestyle = BKE_linestyle_new(bmain, linestyle->id.name + 2);
BKE_linestyle_free(new_linestyle);
for (a = 0; a < MAX_MTEX; a++) {
diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c
index 387d093051e..13ec970c65c 100644
--- a/source/blender/blenkernel/intern/mask_rasterize.c
+++ b/source/blender/blenkernel/intern/mask_rasterize.c
@@ -1360,6 +1360,9 @@ float BKE_maskrasterize_handle_sample(MaskRasterHandle *mr_handle, const float x
case PROP_SHARP:
value_layer = value_layer * value_layer;
break;
+ case PROP_INVSQUARE:
+ value_layer = value_layer * (2.0f - value_layer);
+ break;
case PROP_LIN:
default:
/* nothing */
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 9b682f101ad..283c7a6fc88 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -53,6 +53,7 @@
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLI_string.h"
+#include "BLI_array_utils.h"
#include "BKE_animsys.h"
#include "BKE_displist.h"
@@ -66,6 +67,8 @@
#include "BKE_scene.h"
#include "BKE_node.h"
#include "BKE_curve.h"
+#include "BKE_editmesh.h"
+#include "BKE_font.h"
#include "GPU_material.h"
@@ -99,11 +102,11 @@ void BKE_material_free_ex(Material *ma, bool do_id_user)
if (ma->ramp_col) MEM_freeN(ma->ramp_col);
if (ma->ramp_spec) MEM_freeN(ma->ramp_spec);
- BKE_free_animdata((ID *)ma);
+ BKE_animdata_free((ID *)ma);
if (ma->preview)
BKE_previewimg_free(&ma->preview);
- BKE_icon_delete((struct ID *)ma);
+ BKE_icon_id_delete((struct ID *)ma);
ma->id.icon_id = 0;
/* is no lib link block, but material extension */
@@ -806,9 +809,13 @@ void assign_material_id(ID *id, Material *ma, short act)
if (act > MAXMAT) return;
if (act < 1) act = 1;
+ /* this is needed for Python overrides,
+ * we just have to take care that the UI can't do this */
+#if 0
/* prevent crashing when using accidentally */
BLI_assert(id->lib == NULL);
if (id->lib) return;
+#endif
/* test arraylens */
@@ -918,6 +925,35 @@ void assign_material(Object *ob, Material *ma, short act, int assign_type)
test_object_materials(G.main, ob->data);
}
+
+void BKE_material_remap_object(Object *ob, const unsigned int *remap)
+{
+ Material ***matar = give_matarar(ob);
+ const short *totcol_p = give_totcolp(ob);
+
+ BLI_array_permute(ob->mat, ob->totcol, remap);
+
+ if (ob->matbits) {
+ BLI_array_permute(ob->matbits, ob->totcol, remap);
+ }
+
+ if (matar) {
+ BLI_array_permute(*matar, *totcol_p, remap);
+ }
+
+ if (ob->type == OB_MESH) {
+ BKE_mesh_material_remap(ob->data, remap, ob->totcol);
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ BKE_curve_material_remap(ob->data, remap, ob->totcol);
+ }
+ else {
+ /* add support for this object data! */
+ BLI_assert(matar == NULL);
+ }
+}
+
+
/* XXX - this calls many more update calls per object then are needed, could be optimized */
void assign_matarar(struct Object *ob, struct Material ***matar, short totcol)
{
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index ce20636233a..c09cd1aabdc 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -39,6 +39,7 @@
#include <stdlib.h>
#include <ctype.h>
#include <float.h>
+
#include "MEM_guardedalloc.h"
#include "DNA_material_types.h"
@@ -46,7 +47,6 @@
#include "DNA_meta_types.h"
#include "DNA_scene_types.h"
-
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -54,7 +54,6 @@
#include "BKE_global.h"
#include "BKE_main.h"
-/* #include "BKE_object.h" */
#include "BKE_animsys.h"
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
@@ -65,119 +64,6 @@
#include "BKE_object.h"
#include "BKE_material.h"
-/* Data types */
-
-typedef struct vertex { /* surface vertex */
- float co[3]; /* position and surface normal */
- float no[3];
-} VERTEX;
-
-typedef struct vertices { /* list of vertices in polygonization */
- int count, max; /* # vertices, max # allowed */
- VERTEX *ptr; /* dynamically allocated */
-} VERTICES;
-
-typedef struct corner { /* corner of a cube */
- int i, j, k; /* (i, j, k) is index within lattice */
- float co[3], value; /* location and function value */
- struct corner *next;
-} CORNER;
-
-typedef struct cube { /* partitioning cell (cube) */
- int i, j, k; /* lattice location of cube */
- CORNER *corners[8]; /* eight corners */
-} CUBE;
-
-typedef struct cubes { /* linked list of cubes acting as stack */
- CUBE cube; /* a single cube */
- struct cubes *next; /* remaining elements */
-} CUBES;
-
-typedef struct centerlist { /* list of cube locations */
- int i, j, k; /* cube location */
- struct centerlist *next; /* remaining elements */
-} CENTERLIST;
-
-typedef struct edgelist { /* list of edges */
- int i1, j1, k1, i2, j2, k2; /* edge corner ids */
- int vid; /* vertex id */
- struct edgelist *next; /* remaining elements */
-} EDGELIST;
-
-typedef struct intlist { /* list of integers */
- int i; /* an integer */
- struct intlist *next; /* remaining elements */
-} INTLIST;
-
-typedef struct intlists { /* list of list of integers */
- INTLIST *list; /* a list of integers */
- struct intlists *next; /* remaining elements */
-} INTLISTS;
-
-/* dividing scene using octal tree makes polygonisation faster */
-typedef struct ml_pointer {
- struct ml_pointer *next, *prev;
- struct MetaElem *ml;
-} ml_pointer;
-
-typedef struct octal_node {
- struct octal_node *nodes[8];/* children of current node */
- struct octal_node *parent; /* parent of current node */
- struct ListBase elems; /* ListBase of MetaElem pointers (ml_pointer) */
- float x_min, y_min, z_min; /* 1st border point */
- float x_max, y_max, z_max; /* 7th border point */
- float x, y, z; /* center of node */
- int pos, neg; /* number of positive and negative MetaElements in the node */
- int count; /* number of MetaElems, which belongs to the node */
-} octal_node;
-
-typedef struct octal_tree {
- struct octal_node *first; /* first node */
- int pos, neg; /* number of positive and negative MetaElements in the scene */
- short depth; /* number of scene subdivision */
-} octal_tree;
-
-struct pgn_elements {
- struct pgn_elements *next, *prev;
- char *data;
-};
-
-typedef struct process { /* parameters, function, storage */
- /* ** old G_mb contents ** */
- float thresh;
- int totelem;
- MetaElem **mainb;
- octal_tree *metaball_tree;
-
- /* ** old process contents ** */
-
- /* what happens here? floats, I think. */
- /* float (*function)(void); */ /* implicit surface function */
- float (*function)(struct process *, float, float, float);
- float size, delta; /* cube size, normal delta */
- int bounds; /* cube range within lattice */
- CUBES *cubes; /* active cubes */
- VERTICES vertices; /* surface vertices */
- CENTERLIST **centers; /* cube center hash table */
- CORNER **corners; /* corner value hash table */
- EDGELIST **edges; /* edge and vertex id hash table */
-
- /* Runtime things */
- int *indices;
- int totindex, curindex;
-
- int pgn_offset;
- struct pgn_elements *pgn_current;
- ListBase pgn_list;
-} PROCESS;
-
-/* Forward declarations */
-static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2, MetaBall *mb);
-static int setcenter(PROCESS *process, CENTERLIST *table[], const int i, const int j, const int k);
-static CORNER *setcorner(PROCESS *process, int i, int j, int k);
-static void converge(PROCESS *process, const float p1[3], const float p2[3], float v1, float v2,
- float p[3], MetaBall *mb, int f);
-
/* Functions */
void BKE_mball_unlink(MetaBall *mb)
@@ -197,7 +83,7 @@ void BKE_mball_free(MetaBall *mb)
BKE_mball_unlink(mb);
if (mb->adt) {
- BKE_free_animdata((ID *)mb);
+ BKE_animdata_free((ID *)mb);
mb->adt = NULL;
}
if (mb->mat) MEM_freeN(mb->mat);
@@ -558,1817 +444,6 @@ Object *BKE_mball_basis_find(Scene *scene, Object *basis)
return basis;
}
-
-/* ******************** ARITH ************************* */
-
-/* BASED AT CODE (but mostly rewritten) :
- * C code from the article
- * "An Implicit Surface Polygonizer"
- * by Jules Bloomenthal, jbloom@beauty.gmu.edu
- * in "Graphics Gems IV", Academic Press, 1994
- *
- * Authored by Jules Bloomenthal, Xerox PARC.
- * Copyright (c) Xerox Corporation, 1991. All rights reserved.
- * Permission is granted to reproduce, use and distribute this code for
- * any and all purposes, provided that this notice appears in all copies. */
-
-#define RES 12 /* # converge iterations */
-
-#define L 0 /* left direction: -x, -i */
-#define R 1 /* right direction: +x, +i */
-#define B 2 /* bottom direction: -y, -j */
-#define T 3 /* top direction: +y, +j */
-#define N 4 /* near direction: -z, -k */
-#define F 5 /* far direction: +z, +k */
-#define LBN 0 /* left bottom near corner */
-#define LBF 1 /* left bottom far corner */
-#define LTN 2 /* left top near corner */
-#define LTF 3 /* left top far corner */
-#define RBN 4 /* right bottom near corner */
-#define RBF 5 /* right bottom far corner */
-#define RTN 6 /* right top near corner */
-#define RTF 7 /* right top far corner */
-
-/* the LBN corner of cube (i, j, k), corresponds with location
- * (i-0.5)*size, (j-0.5)*size, (k-0.5)*size) */
-
-#define HASHBIT (5)
-#define HASHSIZE (size_t)(1 << (3 * HASHBIT)) /*! < hash table size (32768) */
-
-#define HASH(i, j, k) ((((( (i) & 31) << 5) | ( (j) & 31)) << 5) | ( (k) & 31) )
-
-#define MB_BIT(i, bit) (((i) >> (bit)) & 1)
-#define FLIP(i, bit) ((i) ^ 1 << (bit)) /* flip the given bit of i */
-
-
-/* **************** POLYGONIZATION ************************ */
-
-static void calc_mballco(MetaElem *ml, float vec[3])
-{
- if (ml->mat) {
- mul_m4_v3((float (*)[4])ml->mat, vec);
- }
-}
-
-static float densfunc(MetaElem *ball, float x, float y, float z)
-{
- float dist2;
- float dvec[3] = {x, y, z};
-
- mul_m4_v3((float (*)[4])ball->imat, dvec);
-
- switch (ball->type) {
- case MB_BALL:
- /* do nothing */
- break;
- case MB_TUBE:
- if (dvec[0] > ball->expx) dvec[0] -= ball->expx;
- else if (dvec[0] < -ball->expx) dvec[0] += ball->expx;
- else dvec[0] = 0.0;
- break;
- case MB_PLANE:
- if (dvec[0] > ball->expx) dvec[0] -= ball->expx;
- else if (dvec[0] < -ball->expx) dvec[0] += ball->expx;
- else dvec[0] = 0.0;
- if (dvec[1] > ball->expy) dvec[1] -= ball->expy;
- else if (dvec[1] < -ball->expy) dvec[1] += ball->expy;
- else dvec[1] = 0.0;
- break;
- case MB_ELIPSOID:
- dvec[0] /= ball->expx;
- dvec[1] /= ball->expy;
- dvec[2] /= ball->expz;
- break;
- case MB_CUBE:
- if (dvec[0] > ball->expx) dvec[0] -= ball->expx;
- else if (dvec[0] < -ball->expx) dvec[0] += ball->expx;
- else dvec[0] = 0.0;
-
- if (dvec[1] > ball->expy) dvec[1] -= ball->expy;
- else if (dvec[1] < -ball->expy) dvec[1] += ball->expy;
- else dvec[1] = 0.0;
-
- if (dvec[2] > ball->expz) dvec[2] -= ball->expz;
- else if (dvec[2] < -ball->expz) dvec[2] += ball->expz;
- else dvec[2] = 0.0;
- break;
-
- /* *** deprecated, could be removed?, do-versioned at least *** */
- case MB_TUBEX:
- if (dvec[0] > ball->len) dvec[0] -= ball->len;
- else if (dvec[0] < -ball->len) dvec[0] += ball->len;
- else dvec[0] = 0.0;
- break;
- case MB_TUBEY:
- if (dvec[1] > ball->len) dvec[1] -= ball->len;
- else if (dvec[1] < -ball->len) dvec[1] += ball->len;
- else dvec[1] = 0.0;
- break;
- case MB_TUBEZ:
- if (dvec[2] > ball->len) dvec[2] -= ball->len;
- else if (dvec[2] < -ball->len) dvec[2] += ball->len;
- else dvec[2] = 0.0;
- break;
- /* *** end deprecated *** */
- }
-
- dist2 = 1.0f - (len_squared_v3(dvec) / ball->rad2);
-
- if ((ball->flag & MB_NEGATIVE) == 0) {
- return (dist2 < 0.0f) ? -0.5f : (ball->s * dist2 * dist2 * dist2) - 0.5f;
- }
- else {
- return (dist2 < 0.0f) ? 0.5f : 0.5f - (ball->s * dist2 * dist2 * dist2);
- }
-}
-
-static octal_node *find_metaball_octal_node(octal_node *node, float x, float y, float z, short depth)
-{
- if (!depth) return node;
-
- if (z < node->z) {
- if (y < node->y) {
- if (x < node->x) {
- if (node->nodes[0])
- return find_metaball_octal_node(node->nodes[0], x, y, z, depth--);
- else
- return node;
- }
- else {
- if (node->nodes[1])
- return find_metaball_octal_node(node->nodes[1], x, y, z, depth--);
- else
- return node;
- }
- }
- else {
- if (x < node->x) {
- if (node->nodes[3])
- return find_metaball_octal_node(node->nodes[3], x, y, z, depth--);
- else
- return node;
- }
- else {
- if (node->nodes[2])
- return find_metaball_octal_node(node->nodes[2], x, y, z, depth--);
- else
- return node;
- }
- }
- }
- else {
- if (y < node->y) {
- if (x < node->x) {
- if (node->nodes[4])
- return find_metaball_octal_node(node->nodes[4], x, y, z, depth--);
- else
- return node;
- }
- else {
- if (node->nodes[5])
- return find_metaball_octal_node(node->nodes[5], x, y, z, depth--);
- else
- return node;
- }
- }
- else {
- if (x < node->x) {
- if (node->nodes[7])
- return find_metaball_octal_node(node->nodes[7], x, y, z, depth--);
- else
- return node;
- }
- else {
- if (node->nodes[6])
- return find_metaball_octal_node(node->nodes[6], x, y, z, depth--);
- else
- return node;
- }
- }
- }
-
- /* all cases accounted for */
- BLI_assert(0);
-}
-
-static float metaball(PROCESS *process, float x, float y, float z)
-/* float x, y, z; */
-{
- octal_tree *metaball_tree = process->metaball_tree;
- struct octal_node *node;
- struct ml_pointer *ml_p;
- float dens = 0;
- int a;
-
- if (process->totelem > 1) {
- node = find_metaball_octal_node(metaball_tree->first, x, y, z, metaball_tree->depth);
- if (node) {
- for (ml_p = node->elems.first; ml_p; ml_p = ml_p->next) {
- dens += densfunc(ml_p->ml, x, y, z);
- }
-
- dens += -0.5f * (metaball_tree->pos - node->pos);
- dens += 0.5f * (metaball_tree->neg - node->neg);
- }
- else {
- for (a = 0; a < process->totelem; a++) {
- dens += densfunc(process->mainb[a], x, y, z);
- }
- }
- }
- else {
- dens += densfunc(process->mainb[0], x, y, z);
- }
-
- return process->thresh - dens;
-}
-
-/* ******************************************** */
-
-static void accum_mballfaces(PROCESS *process, int i1, int i2, int i3, int i4)
-{
- int *newi, *cur;
- /* static int i = 0; I would like to delete altogether, but I don't dare to, yet */
-
- if (process->totindex == process->curindex) {
- process->totindex += 256;
- newi = MEM_mallocN(4 * sizeof(int) * process->totindex, "vertindex");
-
- if (process->indices) {
- memcpy(newi, process->indices, 4 * sizeof(int) * (process->totindex - 256));
- MEM_freeN(process->indices);
- }
- process->indices = newi;
- }
-
- cur = process->indices + 4 * process->curindex;
-
- /* displists now support array drawing, we treat tri's as fake quad */
-
- cur[0] = i1;
- cur[1] = i2;
- cur[2] = i3;
- if (i4 == 0)
- cur[3] = i3;
- else
- cur[3] = i4;
-
- process->curindex++;
-
-}
-
-/* ******************* MEMORY MANAGEMENT *********************** */
-static void *new_pgn_element(PROCESS *process, int size)
-{
- /* during polygonize 1000s of elements are allocated
- * and never freed in between. Freeing only done at the end.
- */
- int blocksize = 16384;
- void *adr;
-
- if (size > 10000 || size == 0) {
- printf("incorrect use of new_pgn_element\n");
- }
- else if (size == -1) {
- struct pgn_elements *cur = process->pgn_list.first;
- while (cur) {
- MEM_freeN(cur->data);
- cur = cur->next;
- }
- BLI_freelistN(&process->pgn_list);
-
- return NULL;
- }
-
- size = 4 * ( (size + 3) / 4);
-
- if (process->pgn_current) {
- if (size + process->pgn_offset < blocksize) {
- adr = (void *) (process->pgn_current->data + process->pgn_offset);
- process->pgn_offset += size;
- return adr;
- }
- }
-
- process->pgn_current = MEM_callocN(sizeof(struct pgn_elements), "newpgn");
- process->pgn_current->data = MEM_callocN(blocksize, "newpgn");
- BLI_addtail(&process->pgn_list, process->pgn_current);
-
- process->pgn_offset = size;
- return process->pgn_current->data;
-}
-
-static void freepolygonize(PROCESS *process)
-{
- MEM_freeN(process->corners);
- MEM_freeN(process->edges);
- MEM_freeN(process->centers);
-
- new_pgn_element(process, -1);
-
- if (process->vertices.ptr) {
- MEM_freeN(process->vertices.ptr);
- }
-}
-
-/**** Cubical Polygonization (optional) ****/
-
-#define LB 0 /* left bottom edge */
-#define LT 1 /* left top edge */
-#define LN 2 /* left near edge */
-#define LF 3 /* left far edge */
-#define RB 4 /* right bottom edge */
-#define RT 5 /* right top edge */
-#define RN 6 /* right near edge */
-#define RF 7 /* right far edge */
-#define BN 8 /* bottom near edge */
-#define BF 9 /* bottom far edge */
-#define TN 10 /* top near edge */
-#define TF 11 /* top far edge */
-
-static INTLISTS *cubetable[256];
-
-/* edge: LB, LT, LN, LF, RB, RT, RN, RF, BN, BF, TN, TF */
-static int corner1[12] = {
- LBN, LTN, LBN, LBF, RBN, RTN, RBN, RBF, LBN, LBF, LTN, LTF
-};
-static int corner2[12] = {
- LBF, LTF, LTN, LTF, RBF, RTF, RTN, RTF, RBN, RBF, RTN, RTF
-};
-static int leftface[12] = {
- B, L, L, F, R, T, N, R, N, B, T, F
-};
-/* face on left when going corner1 to corner2 */
-static int rightface[12] = {
- L, T, N, L, B, R, R, F, B, F, N, T
-};
-/* face on right when going corner1 to corner2 */
-
-
-/* docube: triangulate the cube directly, without decomposition */
-
-static void docube(PROCESS *process, CUBE *cube, MetaBall *mb)
-{
- INTLISTS *polys;
- CORNER *c1, *c2;
- int i, index = 0, count, indexar[8];
-
- for (i = 0; i < 8; i++) {
- if (cube->corners[i]->value > 0.0f) {
- index += (1 << i);
- }
- }
-
- for (polys = cubetable[index]; polys; polys = polys->next) {
- INTLIST *edges;
-
- count = 0;
-
- for (edges = polys->list; edges; edges = edges->next) {
- c1 = cube->corners[corner1[edges->i]];
- c2 = cube->corners[corner2[edges->i]];
-
- indexar[count] = vertid(process, c1, c2, mb);
- count++;
- }
- if (count > 2) {
- switch (count) {
- case 3:
- accum_mballfaces(process, indexar[2], indexar[1], indexar[0], 0);
- break;
- case 4:
- if (indexar[0] == 0) accum_mballfaces(process, indexar[0], indexar[3], indexar[2], indexar[1]);
- else accum_mballfaces(process, indexar[3], indexar[2], indexar[1], indexar[0]);
- break;
- case 5:
- if (indexar[0] == 0) accum_mballfaces(process, indexar[0], indexar[3], indexar[2], indexar[1]);
- else accum_mballfaces(process, indexar[3], indexar[2], indexar[1], indexar[0]);
-
- accum_mballfaces(process, indexar[4], indexar[3], indexar[0], 0);
- break;
- case 6:
- if (indexar[0] == 0) {
- accum_mballfaces(process, indexar[0], indexar[3], indexar[2], indexar[1]);
- accum_mballfaces(process, indexar[0], indexar[5], indexar[4], indexar[3]);
- }
- else {
- accum_mballfaces(process, indexar[3], indexar[2], indexar[1], indexar[0]);
- accum_mballfaces(process, indexar[5], indexar[4], indexar[3], indexar[0]);
- }
- break;
- case 7:
- if (indexar[0] == 0) {
- accum_mballfaces(process, indexar[0], indexar[3], indexar[2], indexar[1]);
- accum_mballfaces(process, indexar[0], indexar[5], indexar[4], indexar[3]);
- }
- else {
- accum_mballfaces(process, indexar[3], indexar[2], indexar[1], indexar[0]);
- accum_mballfaces(process, indexar[5], indexar[4], indexar[3], indexar[0]);
- }
-
- accum_mballfaces(process, indexar[6], indexar[5], indexar[0], 0);
-
- break;
- }
- }
- }
-}
-
-
-/* testface: given cube at lattice (i, j, k), and four corners of face,
- * if surface crosses face, compute other four corners of adjacent cube
- * and add new cube to cube stack */
-
-static void testface(PROCESS *process, int i, int j, int k, CUBE *old, int bit, int c1, int c2, int c3, int c4)
-{
- CUBE newc;
- CUBES *oldcubes = process->cubes;
- CORNER *corn1, *corn2, *corn3, *corn4;
- int n, pos;
-
- corn1 = old->corners[c1];
- corn2 = old->corners[c2];
- corn3 = old->corners[c3];
- corn4 = old->corners[c4];
-
- pos = corn1->value > 0.0f ? 1 : 0;
-
- /* test if no surface crossing */
- if ( (corn2->value > 0) == pos && (corn3->value > 0) == pos && (corn4->value > 0) == pos) return;
- /* test if cube out of bounds */
- /*if ( abs(i) > p->bounds || abs(j) > p->bounds || abs(k) > p->bounds) return;*/
- /* test if already visited (always as last) */
- if (setcenter(process, process->centers, i, j, k)) {
- return;
- }
-
- /* create new cube and add cube to top of stack: */
- process->cubes = (CUBES *) new_pgn_element(process, sizeof(CUBES));
- process->cubes->next = oldcubes;
-
- newc.i = i;
- newc.j = j;
- newc.k = k;
- for (n = 0; n < 8; n++) newc.corners[n] = NULL;
-
- newc.corners[FLIP(c1, bit)] = corn1;
- newc.corners[FLIP(c2, bit)] = corn2;
- newc.corners[FLIP(c3, bit)] = corn3;
- newc.corners[FLIP(c4, bit)] = corn4;
-
- if (newc.corners[0] == NULL) newc.corners[0] = setcorner(process, i, j, k);
- if (newc.corners[1] == NULL) newc.corners[1] = setcorner(process, i, j, k + 1);
- if (newc.corners[2] == NULL) newc.corners[2] = setcorner(process, i, j + 1, k);
- if (newc.corners[3] == NULL) newc.corners[3] = setcorner(process, i, j + 1, k + 1);
- if (newc.corners[4] == NULL) newc.corners[4] = setcorner(process, i + 1, j, k);
- if (newc.corners[5] == NULL) newc.corners[5] = setcorner(process, i + 1, j, k + 1);
- if (newc.corners[6] == NULL) newc.corners[6] = setcorner(process, i + 1, j + 1, k);
- if (newc.corners[7] == NULL) newc.corners[7] = setcorner(process, i + 1, j + 1, k + 1);
-
- process->cubes->cube = newc;
-}
-
-/* setcorner: return corner with the given lattice location
- * set (and cache) its function value */
-
-static CORNER *setcorner(PROCESS *process, int i, int j, int k)
-{
- /* for speed, do corner value caching here */
- CORNER *c;
- int index;
-
- /* does corner exist? */
- index = HASH(i, j, k);
- c = process->corners[index];
-
- for (; c != NULL; c = c->next) {
- if (c->i == i && c->j == j && c->k == k) {
- return c;
- }
- }
-
- c = (CORNER *) new_pgn_element(process, sizeof(CORNER));
-
- c->i = i;
- c->co[0] = ((float)i - 0.5f) * process->size;
- c->j = j;
- c->co[1] = ((float)j - 0.5f) * process->size;
- c->k = k;
- c->co[2] = ((float)k - 0.5f) * process->size;
- c->value = process->function(process, c->co[0], c->co[1], c->co[2]);
-
- c->next = process->corners[index];
- process->corners[index] = c;
-
- return c;
-}
-
-
-/* nextcwedge: return next clockwise edge from given edge around given face */
-
-static int nextcwedge(int edge, int face)
-{
- switch (edge) {
- case LB:
- return (face == L) ? LF : BN;
- case LT:
- return (face == L) ? LN : TF;
- case LN:
- return (face == L) ? LB : TN;
- case LF:
- return (face == L) ? LT : BF;
- case RB:
- return (face == R) ? RN : BF;
- case RT:
- return (face == R) ? RF : TN;
- case RN:
- return (face == R) ? RT : BN;
- case RF:
- return (face == R) ? RB : TF;
- case BN:
- return (face == B) ? RB : LN;
- case BF:
- return (face == B) ? LB : RF;
- case TN:
- return (face == T) ? LT : RN;
- case TF:
- return (face == T) ? RT : LF;
- }
- return 0;
-}
-
-
-/* otherface: return face adjoining edge that is not the given face */
-
-static int otherface(int edge, int face)
-{
- int other = leftface[edge];
- return face == other ? rightface[edge] : other;
-}
-
-
-/* makecubetable: create the 256 entry table for cubical polygonization */
-
-static void makecubetable(void)
-{
- static bool is_done = false;
- int i, e, c, done[12], pos[8];
-
- if (is_done) return;
- is_done = true;
-
- for (i = 0; i < 256; i++) {
- for (e = 0; e < 12; e++) done[e] = 0;
- for (c = 0; c < 8; c++) pos[c] = MB_BIT(i, c);
- for (e = 0; e < 12; e++)
- if (!done[e] && (pos[corner1[e]] != pos[corner2[e]])) {
- INTLIST *ints = NULL;
- INTLISTS *lists = (INTLISTS *) MEM_callocN(sizeof(INTLISTS), "mball_intlist");
- int start = e, edge = e;
-
- /* get face that is to right of edge from pos to neg corner: */
- int face = pos[corner1[e]] ? rightface[e] : leftface[e];
-
- while (1) {
- edge = nextcwedge(edge, face);
- done[edge] = 1;
- if (pos[corner1[edge]] != pos[corner2[edge]]) {
- INTLIST *tmp = ints;
-
- ints = (INTLIST *) MEM_callocN(sizeof(INTLIST), "mball_intlist");
- ints->i = edge;
- ints->next = tmp; /* add edge to head of list */
-
- if (edge == start) break;
- face = otherface(edge, face);
- }
- }
- lists->list = ints; /* add ints to head of table entry */
- lists->next = cubetable[i];
- cubetable[i] = lists;
- }
- }
-}
-
-void BKE_mball_cubeTable_free(void)
-{
- int i;
- INTLISTS *lists, *nlists;
- INTLIST *ints, *nints;
-
- for (i = 0; i < 256; i++) {
- lists = cubetable[i];
- while (lists) {
- nlists = lists->next;
-
- ints = lists->list;
- while (ints) {
- nints = ints->next;
- MEM_freeN(ints);
- ints = nints;
- }
-
- MEM_freeN(lists);
- lists = nlists;
- }
- cubetable[i] = NULL;
- }
-}
-
-/**** Storage ****/
-
-/* setcenter: set (i, j, k) entry of table[]
- * return 1 if already set; otherwise, set and return 0 */
-
-static int setcenter(PROCESS *process, CENTERLIST *table[], const int i, const int j, const int k)
-{
- int index;
- CENTERLIST *newc, *l, *q;
-
- index = HASH(i, j, k);
- q = table[index];
-
- for (l = q; l != NULL; l = l->next) {
- if (l->i == i && l->j == j && l->k == k) return 1;
- }
-
- newc = (CENTERLIST *) new_pgn_element(process, sizeof(CENTERLIST));
- newc->i = i;
- newc->j = j;
- newc->k = k;
- newc->next = q;
- table[index] = newc;
-
- return 0;
-}
-
-
-/* setedge: set vertex id for edge */
-
-static void setedge(PROCESS *process,
- EDGELIST *table[],
- int i1, int j1,
- int k1, int i2,
- int j2, int k2,
- int vid)
-{
- unsigned int index;
- EDGELIST *newe;
-
- if (i1 > i2 || (i1 == i2 && (j1 > j2 || (j1 == j2 && k1 > k2)))) {
- int t = i1;
- i1 = i2;
- i2 = t;
- t = j1;
- j1 = j2;
- j2 = t;
- t = k1;
- k1 = k2;
- k2 = t;
- }
- index = HASH(i1, j1, k1) + HASH(i2, j2, k2);
- newe = (EDGELIST *) new_pgn_element(process, sizeof(EDGELIST));
- newe->i1 = i1;
- newe->j1 = j1;
- newe->k1 = k1;
- newe->i2 = i2;
- newe->j2 = j2;
- newe->k2 = k2;
- newe->vid = vid;
- newe->next = table[index];
- table[index] = newe;
-}
-
-
-/* getedge: return vertex id for edge; return -1 if not set */
-
-static int getedge(EDGELIST *table[],
- int i1, int j1, int k1,
- int i2, int j2, int k2)
-{
- EDGELIST *q;
-
- if (i1 > i2 || (i1 == i2 && (j1 > j2 || (j1 == j2 && k1 > k2)))) {
- int t = i1;
- i1 = i2;
- i2 = t;
- t = j1;
- j1 = j2;
- j2 = t;
- t = k1;
- k1 = k2;
- k2 = t;
- }
- q = table[HASH(i1, j1, k1) + HASH(i2, j2, k2)];
- for (; q != NULL; q = q->next) {
- if (q->i1 == i1 && q->j1 == j1 && q->k1 == k1 &&
- q->i2 == i2 && q->j2 == j2 && q->k2 == k2)
- {
- return q->vid;
- }
- }
- return -1;
-}
-
-
-/**** Vertices ****/
-
-#undef R
-
-
-
-/* vertid: return index for vertex on edge:
- * c1->value and c2->value are presumed of different sign
- * return saved index if any; else compute vertex and save */
-
-/* addtovertices: add v to sequence of vertices */
-
-static void addtovertices(VERTICES *vertices, VERTEX v)
-{
- if (vertices->count == vertices->max) {
- int i;
- VERTEX *newv;
- vertices->max = vertices->count == 0 ? 10 : 2 * vertices->count;
- newv = (VERTEX *) MEM_callocN(vertices->max * sizeof(VERTEX), "addtovertices");
-
- for (i = 0; i < vertices->count; i++) newv[i] = vertices->ptr[i];
-
- if (vertices->ptr != NULL) MEM_freeN(vertices->ptr);
- vertices->ptr = newv;
- }
- vertices->ptr[vertices->count++] = v;
-}
-
-/* vnormal: compute unit length surface normal at point */
-
-static void vnormal(PROCESS *process, const float point[3], float r_no[3])
-{
- const float delta = 0.2f * process->delta;
- const float f = process->function(process, point[0], point[1], point[2]);
-
- r_no[0] = process->function(process, point[0] + delta, point[1], point[2]) - f;
- r_no[1] = process->function(process, point[0], point[1] + delta, point[2]) - f;
- r_no[2] = process->function(process, point[0], point[1], point[2] + delta) - f;
-
-#if 1
- normalize_v3(r_no);
-#else
- f = normalize_v3(r_no);
-
- if (0) {
- float tvec[3];
-
- delta *= 2.0f;
-
- f = process->function(process, point[0], point[1], point[2]);
-
- tvec[0] = process->function(process, point[0] + delta, point[1], point[2]) - f;
- tvec[1] = process->function(process, point[0], point[1] + delta, point[2]) - f;
- tvec[2] = process->function(process, point[0], point[1], point[2] + delta) - f;
-
- if (normalize_v3(tvec) != 0.0f) {
- add_v3_v3(r_no, tvec);
- normalize_v3(r_no);
- }
- }
-#endif
-}
-
-
-static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2, MetaBall *mb)
-{
- VERTEX v;
- int vid = getedge(process->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k);
-
- if (vid != -1) {
- return vid; /* previously computed */
- }
-
- converge(process, c1->co, c2->co, c1->value, c2->value, v.co, mb, 1); /* position */
- vnormal(process, v.co, v.no);
-
- addtovertices(&process->vertices, v); /* save vertex */
- vid = process->vertices.count - 1;
- setedge(process, process->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid);
-
- return vid;
-}
-
-
-/* converge: from two points of differing sign, converge to zero crossing */
-/* watch it: p1 and p2 are used to calculate */
-static void converge(PROCESS *process, const float p1[3], const float p2[3], float v1, float v2,
- float p[3], MetaBall *mb, int f)
-{
- int i = 0;
- float pos[3], neg[3];
- float positive = 0.0f, negative = 0.0f;
- float dvec[3];
-
- if (v1 < 0) {
- copy_v3_v3(pos, p2);
- copy_v3_v3(neg, p1);
- positive = v2;
- negative = v1;
- }
- else {
- copy_v3_v3(pos, p1);
- copy_v3_v3(neg, p2);
- positive = v1;
- negative = v2;
- }
-
- sub_v3_v3v3(dvec, pos, neg);
-
-/* Approximation by linear interpolation is faster then binary subdivision,
- * but it results sometimes (mb->thresh < 0.2) into the strange results */
- if ((mb->thresh > 0.2f) && (f == 1)) {
- if ((dvec[1] == 0.0f) && (dvec[2] == 0.0f)) {
- p[0] = neg[0] - negative * dvec[0] / (positive - negative);
- p[1] = neg[1];
- p[2] = neg[2];
- return;
- }
- if ((dvec[0] == 0.0f) && (dvec[2] == 0.0f)) {
- p[0] = neg[0];
- p[1] = neg[1] - negative * dvec[1] / (positive - negative);
- p[2] = neg[2];
- return;
- }
- if ((dvec[0] == 0.0f) && (dvec[1] == 0.0f)) {
- p[0] = neg[0];
- p[1] = neg[1];
- p[2] = neg[2] - negative * dvec[2] / (positive - negative);
- return;
- }
- }
-
- if ((dvec[1] == 0.0f) && (dvec[2] == 0.0f)) {
- p[1] = neg[1];
- p[2] = neg[2];
- while (1) {
- if (i++ == RES) return;
- p[0] = 0.5f * (pos[0] + neg[0]);
- if ((process->function(process, p[0], p[1], p[2])) > 0.0f) pos[0] = p[0];
- else neg[0] = p[0];
- }
- }
-
- if ((dvec[0] == 0.0f) && (dvec[2] == 0.0f)) {
- p[0] = neg[0];
- p[2] = neg[2];
- while (1) {
- if (i++ == RES) return;
- p[1] = 0.5f * (pos[1] + neg[1]);
- if ((process->function(process, p[0], p[1], p[2])) > 0.0f) pos[1] = p[1];
- else neg[1] = p[1];
- }
- }
-
- if ((dvec[0] == 0.0f) && (dvec[1] == 0.0f)) {
- p[0] = neg[0];
- p[1] = neg[1];
- while (1) {
- if (i++ == RES) return;
- p[2] = 0.5f * (pos[2] + neg[2]);
- if ((process->function(process, p[0], p[1], p[2])) > 0.0f) pos[2] = p[2];
- else neg[2] = p[2];
- }
- }
-
- /* This is necessary to find start point */
- while (1) {
- mid_v3_v3v3(&p[0], pos, neg);
-
- if (i++ == RES) {
- return;
- }
-
- if ((process->function(process, p[0], p[1], p[2])) > 0.0f) {
- copy_v3_v3(pos, &p[0]);
- }
- else {
- copy_v3_v3(neg, &p[0]);
- }
- }
-}
-
-/* ************************************** */
-static void add_cube(PROCESS *process, int i, int j, int k, int count)
-{
- CUBES *ncube;
- int n;
- int a, b, c;
-
- /* hmmm, not only one, but eight cube will be added on the stack
- * ... */
- for (a = i - 1; a < i + count; a++)
- for (b = j - 1; b < j + count; b++)
- for (c = k - 1; c < k + count; c++) {
- /* test if cube has been found before */
- if (setcenter(process, process->centers, a, b, c) == 0) {
- /* push cube on stack: */
- ncube = (CUBES *) new_pgn_element(process, sizeof(CUBES));
- ncube->next = process->cubes;
- process->cubes = ncube;
-
- ncube->cube.i = a;
- ncube->cube.j = b;
- ncube->cube.k = c;
-
- /* set corners of initial cube: */
- for (n = 0; n < 8; n++)
- ncube->cube.corners[n] = setcorner(process, a + MB_BIT(n, 2), b + MB_BIT(n, 1), c + MB_BIT(n, 0));
- }
- }
-}
-
-
-static void find_first_points(PROCESS *process, MetaBall *mb, int a)
-{
- MetaElem *ml;
- float f;
-
- ml = process->mainb[a];
- f = 1.0f - (mb->thresh / ml->s);
-
- /* Skip, when Stiffness of MetaElement is too small ... MetaElement can't be
- * visible alone ... but still can influence others MetaElements :-) */
- if (f > 0.0f) {
- float IN[3] = {0.0f}, OUT[3] = {0.0f}, in[3] = {0.0f}, out[3];
- int i, j, k, c_i, c_j, c_k;
- int index[3] = {1, 0, -1};
- float in_v /*, out_v*/;
- float workp[3];
- float dvec[3];
- float tmp_v, workp_v, max_len_sq, nx, ny, nz, max_dim;
-
- calc_mballco(ml, in);
- in_v = process->function(process, in[0], in[1], in[2]);
-
- for (i = 0; i < 3; i++) {
- switch (ml->type) {
- case MB_BALL:
- OUT[0] = out[0] = IN[0] + index[i] * ml->rad;
- break;
- case MB_TUBE:
- case MB_PLANE:
- case MB_ELIPSOID:
- case MB_CUBE:
- OUT[0] = out[0] = IN[0] + index[i] * (ml->expx + ml->rad);
- break;
- }
-
- for (j = 0; j < 3; j++) {
- switch (ml->type) {
- case MB_BALL:
- OUT[1] = out[1] = IN[1] + index[j] * ml->rad;
- break;
- case MB_TUBE:
- case MB_PLANE:
- case MB_ELIPSOID:
- case MB_CUBE:
- OUT[1] = out[1] = IN[1] + index[j] * (ml->expy + ml->rad);
- break;
- }
-
- for (k = 0; k < 3; k++) {
- out[0] = OUT[0];
- out[1] = OUT[1];
- switch (ml->type) {
- case MB_BALL:
- case MB_TUBE:
- case MB_PLANE:
- out[2] = IN[2] + index[k] * ml->rad;
- break;
- case MB_ELIPSOID:
- case MB_CUBE:
- out[2] = IN[2] + index[k] * (ml->expz + ml->rad);
- break;
- }
-
- calc_mballco(ml, out);
-
- /*out_v = process->function(out[0], out[1], out[2]);*/ /*UNUSED*/
-
- /* find "first points" on Implicit Surface of MetaElemnt ml */
- copy_v3_v3(workp, in);
- workp_v = in_v;
- max_len_sq = len_squared_v3v3(out, in);
-
- nx = fabsf((out[0] - in[0]) / process->size);
- ny = fabsf((out[1] - in[1]) / process->size);
- nz = fabsf((out[2] - in[2]) / process->size);
-
- max_dim = max_fff(nx, ny, nz);
- if (max_dim != 0.0f) {
- float len_sq = 0.0f;
-
- dvec[0] = (out[0] - in[0]) / max_dim;
- dvec[1] = (out[1] - in[1]) / max_dim;
- dvec[2] = (out[2] - in[2]) / max_dim;
-
- while (len_sq <= max_len_sq) {
- add_v3_v3(workp, dvec);
-
- /* compute value of implicite function */
- tmp_v = process->function(process, workp[0], workp[1], workp[2]);
- /* add cube to the stack, when value of implicite function crosses zero value */
- if ((tmp_v < 0.0f && workp_v >= 0.0f) || (tmp_v > 0.0f && workp_v <= 0.0f)) {
-
- /* indexes of CUBE, which includes "first point" */
- c_i = (int)floor(workp[0] / process->size);
- c_j = (int)floor(workp[1] / process->size);
- c_k = (int)floor(workp[2] / process->size);
-
- /* add CUBE (with indexes c_i, c_j, c_k) to the stack,
- * this cube includes found point of Implicit Surface */
- if ((ml->flag & MB_NEGATIVE) == 0) {
- add_cube(process, c_i, c_j, c_k, 1);
- }
- else {
- add_cube(process, c_i, c_j, c_k, 2);
- }
- }
- len_sq = len_squared_v3v3(workp, in);
- workp_v = tmp_v;
-
- }
- }
- }
- }
- }
- }
-}
-
-static void polygonize(PROCESS *process, MetaBall *mb)
-{
- CUBE c;
- int a;
-
- process->vertices.count = process->vertices.max = 0;
- process->vertices.ptr = NULL;
-
- /* allocate hash tables and build cube polygon table: */
- process->centers = MEM_callocN(HASHSIZE * sizeof(CENTERLIST *), "mbproc->centers");
- process->corners = MEM_callocN(HASHSIZE * sizeof(CORNER *), "mbproc->corners");
- process->edges = MEM_callocN(2 * HASHSIZE * sizeof(EDGELIST *), "mbproc->edges");
- makecubetable();
-
- for (a = 0; a < process->totelem; a++) {
-
- /* try to find 8 points on the surface for each MetaElem */
- find_first_points(process, mb, a);
- }
-
- /* polygonize all MetaElems of current MetaBall */
- while (process->cubes != NULL) { /* process active cubes till none left */
- c = process->cubes->cube;
-
- /* polygonize the cube directly: */
- docube(process, &c, mb);
-
- /* pop current cube from stack */
- process->cubes = process->cubes->next;
-
- /* test six face directions, maybe add to stack: */
- testface(process, c.i - 1, c.j, c.k, &c, 2, LBN, LBF, LTN, LTF);
- testface(process, c.i + 1, c.j, c.k, &c, 2, RBN, RBF, RTN, RTF);
- testface(process, c.i, c.j - 1, c.k, &c, 1, LBN, LBF, RBN, RBF);
- testface(process, c.i, c.j + 1, c.k, &c, 1, LTN, LTF, RTN, RTF);
- testface(process, c.i, c.j, c.k - 1, &c, 0, LBN, LTN, RBN, RTN);
- testface(process, c.i, c.j, c.k + 1, &c, 0, LBF, LTF, RBF, RTF);
- }
-}
-
-static float init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob) /* return totsize */
-{
- Scene *sce_iter = scene;
- Base *base;
- Object *bob;
- MetaBall *mb;
- MetaElem *ml;
- float size, totsize, obinv[4][4], obmat[4][4], vec[3];
- //float max = 0.0f;
- int a, obnr, zero_size = 0;
- char obname[MAX_ID_NAME];
- SceneBaseIter iter;
-
- copy_m4_m4(obmat, ob->obmat); /* to cope with duplicators from BKE_scene_base_iter_next */
- invert_m4_m4(obinv, ob->obmat);
- a = 0;
-
- BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
-
- /* make main array */
- BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL);
- while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &bob)) {
-
- if (bob->type == OB_MBALL) {
- zero_size = 0;
- ml = NULL;
-
- if (bob == ob && (base->flag & OB_FROMDUPLI) == 0) {
- mb = ob->data;
-
- if (mb->editelems) ml = mb->editelems->first;
- else ml = mb->elems.first;
- }
- else {
- char name[MAX_ID_NAME];
- int nr;
-
- BLI_split_name_num(name, &nr, bob->id.name + 2, '.');
- if (STREQ(obname, name)) {
- mb = bob->data;
-
- if (mb->editelems) ml = mb->editelems->first;
- else ml = mb->elems.first;
- }
- }
-
- /* when metaball object has zero scale, then MetaElem to this MetaBall
- * will not be put to mainb array */
- if (has_zero_axis_m4(bob->obmat)) {
- zero_size = 1;
- }
- else if (bob->parent) {
- struct Object *pob = bob->parent;
- while (pob) {
- if (has_zero_axis_m4(pob->obmat)) {
- zero_size = 1;
- break;
- }
- pob = pob->parent;
- }
- }
-
- if (zero_size) {
- unsigned int ml_count = 0;
- while (ml) {
- ml_count++;
- ml = ml->next;
- }
- process->totelem -= ml_count;
- }
- else {
- while (ml) {
- if (!(ml->flag & MB_HIDE)) {
- int i;
- float temp1[4][4], temp2[4][4], temp3[4][4];
- float (*mat)[4] = NULL, (*imat)[4] = NULL;
- float max_x, max_y, max_z, min_x, min_y, min_z;
- float expx, expy, expz;
-
- max_x = max_y = max_z = -3.4e38;
- min_x = min_y = min_z = 3.4e38;
-
- /* too big stiffness seems only ugly due to linear interpolation
- * no need to have possibility for too big stiffness */
- if (ml->s > 10.0f) ml->s = 10.0f;
-
- /* Rotation of MetaElem is stored in quat */
- quat_to_mat4(temp3, ml->quat);
-
- /* Translation of MetaElem */
- unit_m4(temp2);
- temp2[3][0] = ml->x;
- temp2[3][1] = ml->y;
- temp2[3][2] = ml->z;
-
- mul_m4_m4m4(temp1, temp2, temp3);
-
- /* make a copy because of duplicates */
- process->mainb[a] = new_pgn_element(process, sizeof(MetaElem));
- *(process->mainb[a]) = *ml;
- process->mainb[a]->bb = new_pgn_element(process, sizeof(BoundBox));
-
- mat = new_pgn_element(process, 4 * 4 * sizeof(float));
- imat = new_pgn_element(process, 4 * 4 * sizeof(float));
-
- /* mat is the matrix to transform from mball into the basis-mball */
- invert_m4_m4(obinv, obmat);
- mul_m4_m4m4(temp2, obinv, bob->obmat);
- /* MetaBall transformation */
- mul_m4_m4m4(mat, temp2, temp1);
-
- invert_m4_m4(imat, mat);
-
- process->mainb[a]->rad2 = ml->rad * ml->rad;
-
- process->mainb[a]->mat = (float *) mat;
- process->mainb[a]->imat = (float *) imat;
-
- if (!MB_TYPE_SIZE_SQUARED(ml->type)) {
- expx = ml->expx;
- expy = ml->expy;
- expz = ml->expz;
- }
- else {
- expx = ml->expx * ml->expx;
- expy = ml->expy * ml->expy;
- expz = ml->expz * ml->expz;
- }
-
- /* untransformed Bounding Box of MetaElem */
- /* TODO, its possible the elem type has been changed and the exp* values can use a fallback */
- copy_v3_fl3(process->mainb[a]->bb->vec[0], -expx, -expy, -expz); /* 0 */
- copy_v3_fl3(process->mainb[a]->bb->vec[1], +expx, -expy, -expz); /* 1 */
- copy_v3_fl3(process->mainb[a]->bb->vec[2], +expx, +expy, -expz); /* 2 */
- copy_v3_fl3(process->mainb[a]->bb->vec[3], -expx, +expy, -expz); /* 3 */
- copy_v3_fl3(process->mainb[a]->bb->vec[4], -expx, -expy, +expz); /* 4 */
- copy_v3_fl3(process->mainb[a]->bb->vec[5], +expx, -expy, +expz); /* 5 */
- copy_v3_fl3(process->mainb[a]->bb->vec[6], +expx, +expy, +expz); /* 6 */
- copy_v3_fl3(process->mainb[a]->bb->vec[7], -expx, +expy, +expz); /* 7 */
-
- /* transformation of Metalem bb */
- for (i = 0; i < 8; i++)
- mul_m4_v3((float (*)[4])mat, process->mainb[a]->bb->vec[i]);
-
- /* find max and min of transformed bb */
- for (i = 0; i < 8; i++) {
- /* find maximums */
- if (process->mainb[a]->bb->vec[i][0] > max_x) max_x = process->mainb[a]->bb->vec[i][0];
- if (process->mainb[a]->bb->vec[i][1] > max_y) max_y = process->mainb[a]->bb->vec[i][1];
- if (process->mainb[a]->bb->vec[i][2] > max_z) max_z = process->mainb[a]->bb->vec[i][2];
- /* find minimums */
- if (process->mainb[a]->bb->vec[i][0] < min_x) min_x = process->mainb[a]->bb->vec[i][0];
- if (process->mainb[a]->bb->vec[i][1] < min_y) min_y = process->mainb[a]->bb->vec[i][1];
- if (process->mainb[a]->bb->vec[i][2] < min_z) min_z = process->mainb[a]->bb->vec[i][2];
- }
-
- /* create "new" bb, only point 0 and 6, which are
- * necessary for octal tree filling */
- process->mainb[a]->bb->vec[0][0] = min_x - ml->rad;
- process->mainb[a]->bb->vec[0][1] = min_y - ml->rad;
- process->mainb[a]->bb->vec[0][2] = min_z - ml->rad;
-
- process->mainb[a]->bb->vec[6][0] = max_x + ml->rad;
- process->mainb[a]->bb->vec[6][1] = max_y + ml->rad;
- process->mainb[a]->bb->vec[6][2] = max_z + ml->rad;
-
- a++;
- }
- ml = ml->next;
- }
- }
- }
- }
-
-
- /* totsize (= 'manhattan' radius) */
- totsize = 0.0;
- for (a = 0; a < process->totelem; a++) {
-
- vec[0] = process->mainb[a]->x + process->mainb[a]->rad + process->mainb[a]->expx;
- vec[1] = process->mainb[a]->y + process->mainb[a]->rad + process->mainb[a]->expy;
- vec[2] = process->mainb[a]->z + process->mainb[a]->rad + process->mainb[a]->expz;
-
- calc_mballco(process->mainb[a], vec);
-
- size = fabsf(vec[0]);
- if (size > totsize) totsize = size;
- size = fabsf(vec[1]);
- if (size > totsize) totsize = size;
- size = fabsf(vec[2]);
- if (size > totsize) totsize = size;
-
- vec[0] = process->mainb[a]->x - process->mainb[a]->rad;
- vec[1] = process->mainb[a]->y - process->mainb[a]->rad;
- vec[2] = process->mainb[a]->z - process->mainb[a]->rad;
-
- calc_mballco(process->mainb[a], vec);
-
- size = fabsf(vec[0]);
- if (size > totsize) totsize = size;
- size = fabsf(vec[1]);
- if (size > totsize) totsize = size;
- size = fabsf(vec[2]);
- if (size > totsize) totsize = size;
- }
-
- for (a = 0; a < process->totelem; a++) {
- process->thresh += densfunc(process->mainb[a], 2.0f * totsize, 2.0f * totsize, 2.0f * totsize);
- }
-
- return totsize;
-}
-
-/* if MetaElem lies in node, then node includes MetaElem pointer (ml_p)
- * pointing at MetaElem (ml)
- */
-static void fill_metaball_octal_node(octal_node *node, MetaElem *ml, short i)
-{
- ml_pointer *ml_p;
-
- ml_p = MEM_mallocN(sizeof(ml_pointer), "ml_pointer");
- ml_p->ml = ml;
- BLI_addtail(&(node->nodes[i]->elems), ml_p);
- node->count++;
-
- if ((ml->flag & MB_NEGATIVE) == 0) {
- node->nodes[i]->pos++;
- }
- else {
- node->nodes[i]->neg++;
- }
-}
-
-/* Node is subdivided as is illustrated on the following figure:
- *
- * +------+------+
- * / / /|
- * +------+------+ |
- * / / /| +
- * +------+------+ |/|
- * | | | + |
- * | | |/| +
- * +------+------+ |/
- * | | | +
- * | | |/
- * +------+------+
- *
- */
-static void subdivide_metaball_octal_node(octal_node *node, float size_x, float size_y, float size_z, short depth)
-{
- MetaElem *ml;
- ml_pointer *ml_p;
- float x, y, z;
- int a, i;
-
- /* create new nodes */
- for (a = 0; a < 8; a++) {
- node->nodes[a] = MEM_mallocN(sizeof(octal_node), "octal_node");
- for (i = 0; i < 8; i++)
- node->nodes[a]->nodes[i] = NULL;
- node->nodes[a]->parent = node;
- BLI_listbase_clear(&node->nodes[a]->elems);
- node->nodes[a]->count = 0;
- node->nodes[a]->neg = 0;
- node->nodes[a]->pos = 0;
- }
-
- size_x /= 2;
- size_y /= 2;
- size_z /= 2;
-
- /* center of node */
- node->x = x = node->x_min + size_x;
- node->y = y = node->y_min + size_y;
- node->z = z = node->z_min + size_z;
-
- /* setting up of border points of new nodes */
- node->nodes[0]->x_min = node->x_min;
- node->nodes[0]->y_min = node->y_min;
- node->nodes[0]->z_min = node->z_min;
- node->nodes[0]->x = node->nodes[0]->x_min + size_x / 2;
- node->nodes[0]->y = node->nodes[0]->y_min + size_y / 2;
- node->nodes[0]->z = node->nodes[0]->z_min + size_z / 2;
-
- node->nodes[1]->x_min = x;
- node->nodes[1]->y_min = node->y_min;
- node->nodes[1]->z_min = node->z_min;
- node->nodes[1]->x = node->nodes[1]->x_min + size_x / 2;
- node->nodes[1]->y = node->nodes[1]->y_min + size_y / 2;
- node->nodes[1]->z = node->nodes[1]->z_min + size_z / 2;
-
- node->nodes[2]->x_min = x;
- node->nodes[2]->y_min = y;
- node->nodes[2]->z_min = node->z_min;
- node->nodes[2]->x = node->nodes[2]->x_min + size_x / 2;
- node->nodes[2]->y = node->nodes[2]->y_min + size_y / 2;
- node->nodes[2]->z = node->nodes[2]->z_min + size_z / 2;
-
- node->nodes[3]->x_min = node->x_min;
- node->nodes[3]->y_min = y;
- node->nodes[3]->z_min = node->z_min;
- node->nodes[3]->x = node->nodes[3]->x_min + size_x / 2;
- node->nodes[3]->y = node->nodes[3]->y_min + size_y / 2;
- node->nodes[3]->z = node->nodes[3]->z_min + size_z / 2;
-
- node->nodes[4]->x_min = node->x_min;
- node->nodes[4]->y_min = node->y_min;
- node->nodes[4]->z_min = z;
- node->nodes[4]->x = node->nodes[4]->x_min + size_x / 2;
- node->nodes[4]->y = node->nodes[4]->y_min + size_y / 2;
- node->nodes[4]->z = node->nodes[4]->z_min + size_z / 2;
-
- node->nodes[5]->x_min = x;
- node->nodes[5]->y_min = node->y_min;
- node->nodes[5]->z_min = z;
- node->nodes[5]->x = node->nodes[5]->x_min + size_x / 2;
- node->nodes[5]->y = node->nodes[5]->y_min + size_y / 2;
- node->nodes[5]->z = node->nodes[5]->z_min + size_z / 2;
-
- node->nodes[6]->x_min = x;
- node->nodes[6]->y_min = y;
- node->nodes[6]->z_min = z;
- node->nodes[6]->x = node->nodes[6]->x_min + size_x / 2;
- node->nodes[6]->y = node->nodes[6]->y_min + size_y / 2;
- node->nodes[6]->z = node->nodes[6]->z_min + size_z / 2;
-
- node->nodes[7]->x_min = node->x_min;
- node->nodes[7]->y_min = y;
- node->nodes[7]->z_min = z;
- node->nodes[7]->x = node->nodes[7]->x_min + size_x / 2;
- node->nodes[7]->y = node->nodes[7]->y_min + size_y / 2;
- node->nodes[7]->z = node->nodes[7]->z_min + size_z / 2;
-
- ml_p = node->elems.first;
-
- /* setting up references of MetaElems for new nodes */
- while (ml_p) {
- ml = ml_p->ml;
- if (ml->bb->vec[0][2] < z) {
- if (ml->bb->vec[0][1] < y) {
- /* vec[0][0] lies in first octant */
- if (ml->bb->vec[0][0] < x) {
- /* ml belongs to the (0)1st node */
- fill_metaball_octal_node(node, ml, 0);
-
- /* ml belongs to the (3)4th node */
- if (ml->bb->vec[6][1] >= y) {
- fill_metaball_octal_node(node, ml, 3);
-
- /* ml belongs to the (7)8th node */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 7);
- }
- }
-
- /* ml belongs to the (1)2nd node */
- if (ml->bb->vec[6][0] >= x) {
- fill_metaball_octal_node(node, ml, 1);
-
- /* ml belongs to the (5)6th node */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 5);
- }
- }
-
- /* ml belongs to the (2)3th node */
- if ((ml->bb->vec[6][0] >= x) && (ml->bb->vec[6][1] >= y)) {
- fill_metaball_octal_node(node, ml, 2);
-
- /* ml belong to the (6)7th node */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 6);
- }
-
- }
-
- /* ml belongs to the (4)5th node too */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 4);
- }
-
-
-
- }
- /* vec[0][0] is in the (1)second octant */
- else {
- /* ml belong to the (1)2nd node */
- fill_metaball_octal_node(node, ml, 1);
-
- /* ml belongs to the (2)3th node */
- if (ml->bb->vec[6][1] >= y) {
- fill_metaball_octal_node(node, ml, 2);
-
- /* ml belongs to the (6)7th node */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 6);
- }
-
- }
-
- /* ml belongs to the (5)6th node */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 5);
- }
- }
- }
- else {
- /* vec[0][0] is in the (3)4th octant */
- if (ml->bb->vec[0][0] < x) {
- /* ml belongs to the (3)4nd node */
- fill_metaball_octal_node(node, ml, 3);
-
- /* ml belongs to the (7)8th node */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 7);
- }
-
-
- /* ml belongs to the (2)3th node */
- if (ml->bb->vec[6][0] >= x) {
- fill_metaball_octal_node(node, ml, 2);
-
- /* ml belongs to the (6)7th node */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 6);
- }
- }
- }
-
- }
-
- /* vec[0][0] is in the (2)3th octant */
- if ((ml->bb->vec[0][0] >= x) && (ml->bb->vec[0][1] >= y)) {
- /* ml belongs to the (2)3th node */
- fill_metaball_octal_node(node, ml, 2);
-
- /* ml belongs to the (6)7th node */
- if (ml->bb->vec[6][2] >= z) {
- fill_metaball_octal_node(node, ml, 6);
- }
- }
- }
- else {
- if (ml->bb->vec[0][1] < y) {
- /* vec[0][0] lies in (4)5th octant */
- if (ml->bb->vec[0][0] < x) {
- /* ml belongs to the (4)5th node */
- fill_metaball_octal_node(node, ml, 4);
-
- if (ml->bb->vec[6][0] >= x) {
- fill_metaball_octal_node(node, ml, 5);
- }
-
- if (ml->bb->vec[6][1] >= y) {
- fill_metaball_octal_node(node, ml, 7);
- }
-
- if ((ml->bb->vec[6][0] >= x) && (ml->bb->vec[6][1] >= y)) {
- fill_metaball_octal_node(node, ml, 6);
- }
- }
- /* vec[0][0] lies in (5)6th octant */
- else {
- fill_metaball_octal_node(node, ml, 5);
-
- if (ml->bb->vec[6][1] >= y) {
- fill_metaball_octal_node(node, ml, 6);
- }
- }
- }
- else {
- /* vec[0][0] lies in (7)8th octant */
- if (ml->bb->vec[0][0] < x) {
- fill_metaball_octal_node(node, ml, 7);
-
- if (ml->bb->vec[6][0] >= x) {
- fill_metaball_octal_node(node, ml, 6);
- }
- }
-
- }
-
- /* vec[0][0] lies in (6)7th octant */
- if ((ml->bb->vec[0][0] >= x) && (ml->bb->vec[0][1] >= y)) {
- fill_metaball_octal_node(node, ml, 6);
- }
- }
- ml_p = ml_p->next;
- }
-
- /* free references of MetaElems for curent node (it is not needed anymore) */
- BLI_freelistN(&node->elems);
-
- depth--;
-
- if (depth > 0) {
- for (a = 0; a < 8; a++) {
- if (node->nodes[a]->count > 0) /* if node is not empty, then it is subdivided */
- subdivide_metaball_octal_node(node->nodes[a], size_x, size_y, size_z, depth);
- }
- }
-}
-
-/* free all octal nodes recursively */
-static void free_metaball_octal_node(octal_node *node)
-{
- int a;
- for (a = 0; a < 8; a++) {
- if (node->nodes[a] != NULL) free_metaball_octal_node(node->nodes[a]);
- }
- BLI_freelistN(&node->elems);
- MEM_freeN(node);
-}
-
-/* If scene include more than one MetaElem, then octree is used */
-static void init_metaball_octal_tree(PROCESS *process, int depth)
-{
- struct octal_node *node;
- ml_pointer *ml_p;
- float size[3];
- int a;
-
- process->metaball_tree = MEM_mallocN(sizeof(octal_tree), "metaball_octal_tree");
- process->metaball_tree->first = node = MEM_mallocN(sizeof(octal_node), "metaball_octal_node");
- /* maximal depth of octree */
- process->metaball_tree->depth = depth;
-
- process->metaball_tree->neg = node->neg = 0;
- process->metaball_tree->pos = node->pos = 0;
-
- BLI_listbase_clear(&node->elems);
- node->count = 0;
-
- for (a = 0; a < 8; a++)
- node->nodes[a] = NULL;
-
- node->x_min = node->y_min = node->z_min = FLT_MAX;
- node->x_max = node->y_max = node->z_max = -FLT_MAX;
-
- /* size of octal tree scene */
- for (a = 0; a < process->totelem; a++) {
- if (process->mainb[a]->bb->vec[0][0] < node->x_min) node->x_min = process->mainb[a]->bb->vec[0][0];
- if (process->mainb[a]->bb->vec[0][1] < node->y_min) node->y_min = process->mainb[a]->bb->vec[0][1];
- if (process->mainb[a]->bb->vec[0][2] < node->z_min) node->z_min = process->mainb[a]->bb->vec[0][2];
-
- if (process->mainb[a]->bb->vec[6][0] > node->x_max) node->x_max = process->mainb[a]->bb->vec[6][0];
- if (process->mainb[a]->bb->vec[6][1] > node->y_max) node->y_max = process->mainb[a]->bb->vec[6][1];
- if (process->mainb[a]->bb->vec[6][2] > node->z_max) node->z_max = process->mainb[a]->bb->vec[6][2];
-
- ml_p = MEM_mallocN(sizeof(ml_pointer), "ml_pointer");
- ml_p->ml = process->mainb[a];
- BLI_addtail(&node->elems, ml_p);
-
- if ((process->mainb[a]->flag & MB_NEGATIVE) == 0) {
- /* number of positive MetaElem in scene */
- process->metaball_tree->pos++;
- }
- else {
- /* number of negative MetaElem in scene */
- process->metaball_tree->neg++;
- }
- }
-
- /* size of first node */
- size[0] = node->x_max - node->x_min;
- size[1] = node->y_max - node->y_min;
- size[2] = node->z_max - node->z_min;
-
- /* first node is subdivided recursively */
- subdivide_metaball_octal_node(node, size[0], size[1], size[2], process->metaball_tree->depth);
-}
-
-static void mball_count(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *basis)
-{
- Scene *sce_iter = scene;
- Base *base;
- Object *ob, *bob = basis;
- MetaElem *ml = NULL;
- int basisnr, obnr;
- char basisname[MAX_ID_NAME], obname[MAX_ID_NAME];
- SceneBaseIter iter;
-
- BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.');
- process->totelem = 0;
-
- BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL);
- while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &ob)) {
- if (ob->type == OB_MBALL) {
- if (ob == bob) {
- MetaBall *mb = ob->data;
-
- /* if bob object is in edit mode, then dynamic list of all MetaElems
- * is stored in editelems */
- if (mb->editelems) ml = mb->editelems->first;
- /* if bob object is in object mode */
- else ml = mb->elems.first;
- }
- else {
- BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
-
- /* object ob has to be in same "group" ... it means, that it has to have
- * same base of its name */
- if (STREQ(obname, basisname)) {
- MetaBall *mb = ob->data;
-
- /* if object is in edit mode, then dynamic list of all MetaElems
- * is stored in editelems */
- if (mb->editelems) ml = mb->editelems->first;
- /* if bob object is in object mode */
- else ml = mb->elems.first;
- }
- }
-
- for ( ; ml; ml = ml->next) {
- if (!(ml->flag & MB_HIDE)) {
- process->totelem++;
- }
- }
- }
- }
-}
-
-void BKE_mball_polygonize(EvaluationContext *eval_ctx, Scene *scene, Object *ob, ListBase *dispbase)
-{
- MetaBall *mb;
- DispList *dl;
- int a, nr_cubes;
- float *co, *no, totsize, width;
- PROCESS process = {0};
-
- mb = ob->data;
-
- mball_count(eval_ctx, &process, scene, ob);
-
- if (process.totelem == 0) return;
- if ((eval_ctx->mode != DAG_EVAL_RENDER) && (mb->flag == MB_UPDATE_NEVER)) return;
- if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) return;
-
- process.thresh = mb->thresh;
-
- /* total number of MetaElems (totelem) is precomputed in find_basis_mball() function */
- process.mainb = MEM_mallocN(sizeof(void *) * process.totelem, "mainb");
-
- /* initialize all mainb (MetaElems) */
- totsize = init_meta(eval_ctx, &process, scene, ob);
-
- /* if scene includes more than one MetaElem, then octal tree optimization is used */
- if ((process.totelem > 1) && (process.totelem <= 64)) init_metaball_octal_tree(&process, 1);
- if ((process.totelem > 64) && (process.totelem <= 128)) init_metaball_octal_tree(&process, 2);
- if ((process.totelem > 128) && (process.totelem <= 512)) init_metaball_octal_tree(&process, 3);
- if ((process.totelem > 512) && (process.totelem <= 1024)) init_metaball_octal_tree(&process, 4);
- if (process.totelem > 1024) init_metaball_octal_tree(&process, 5);
-
- /* don't polygonize metaballs with too high resolution (base mball to small)
- * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */
- if (process.metaball_tree) {
- if (ob->size[0] <= 0.00001f * (process.metaball_tree->first->x_max - process.metaball_tree->first->x_min) ||
- ob->size[1] <= 0.00001f * (process.metaball_tree->first->y_max - process.metaball_tree->first->y_min) ||
- ob->size[2] <= 0.00001f * (process.metaball_tree->first->z_max - process.metaball_tree->first->z_min))
- {
- new_pgn_element(&process, -1); /* free values created by init_meta */
-
- MEM_freeN(process.mainb);
-
- /* free tree */
- free_metaball_octal_node(process.metaball_tree->first);
- MEM_freeN(process.metaball_tree);
-
- return;
- }
- }
-
- /* width is size per polygonize cube */
- if (eval_ctx->mode == DAG_EVAL_RENDER) {
- width = mb->rendersize;
- }
- else {
- width = mb->wiresize;
- if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_HALFRES) {
- width *= 2;
- }
- }
- /* nr_cubes is just for safety, minimum is totsize */
- nr_cubes = (int)(0.5f + totsize / width);
-
- /* init process */
- process.function = metaball;
- process.size = width;
- process.bounds = nr_cubes;
- process.cubes = NULL;
- process.delta = width / (float)(RES * RES);
-
- polygonize(&process, mb);
-
- MEM_freeN(process.mainb);
-
- /* free octal tree */
- if (process.totelem > 1) {
- free_metaball_octal_node(process.metaball_tree->first);
- MEM_freeN(process.metaball_tree);
- process.metaball_tree = NULL;
- }
-
- if (process.curindex) {
- VERTEX *ptr = process.vertices.ptr;
-
- dl = MEM_callocN(sizeof(DispList), "mbaldisp");
- BLI_addtail(dispbase, dl);
- dl->type = DL_INDEX4;
- dl->nr = process.vertices.count;
- dl->parts = process.curindex;
-
- dl->index = process.indices;
- process.indices = NULL;
-
- a = process.vertices.count;
- dl->verts = co = MEM_mallocN(sizeof(float[3]) * a, "mballverts");
- dl->nors = no = MEM_mallocN(sizeof(float[3]) * a, "mballnors");
-
- for (a = 0; a < process.vertices.count; ptr++, a++, no += 3, co += 3) {
- copy_v3_v3(co, ptr->co);
- copy_v3_v3(no, ptr->no);
- }
- }
-
- freepolygonize(&process);
-}
-
bool BKE_mball_minmax_ex(MetaBall *mb, float min[3], float max[3],
float obmat[4][4], const short flag)
{
@@ -2511,3 +586,9 @@ void BKE_mball_select_swap(struct MetaBall *mb)
}
}
+/* **** Depsgraph evaluation **** */
+
+void BKE_mball_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+ MetaBall *UNUSED(mball))
+{
+}
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
new file mode 100644
index 00000000000..e8418e876bb
--- /dev/null
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -0,0 +1,1325 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Jiri Hnidek <jiri.hnidek@vslib.cz>.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/mball_tessellate.c
+ * \ingroup bke
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_object_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "BLI_memarena.h"
+
+#include "BKE_global.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_scene.h"
+#include "BKE_displist.h"
+#include "BKE_mball_tessellate.h" /* own include */
+
+#include "BLI_strict_flags.h"
+
+/* experimental (faster) normal calculation */
+// #define USE_ACCUM_NORMAL
+
+/* Data types */
+
+typedef struct corner { /* corner of a cube */
+ int i, j, k; /* (i, j, k) is index within lattice */
+ float co[3], value; /* location and function value */
+ struct corner *next;
+} CORNER;
+
+typedef struct cube { /* partitioning cell (cube) */
+ int i, j, k; /* lattice location of cube */
+ CORNER *corners[8]; /* eight corners */
+} CUBE;
+
+typedef struct cubes { /* linked list of cubes acting as stack */
+ CUBE cube; /* a single cube */
+ struct cubes *next; /* remaining elements */
+} CUBES;
+
+typedef struct centerlist { /* list of cube locations */
+ int i, j, k; /* cube location */
+ struct centerlist *next; /* remaining elements */
+} CENTERLIST;
+
+typedef struct edgelist { /* list of edges */
+ int i1, j1, k1, i2, j2, k2; /* edge corner ids */
+ int vid; /* vertex id */
+ struct edgelist *next; /* remaining elements */
+} EDGELIST;
+
+typedef struct intlist { /* list of integers */
+ int i; /* an integer */
+ struct intlist *next; /* remaining elements */
+} INTLIST;
+
+typedef struct intlists { /* list of list of integers */
+ INTLIST *list; /* a list of integers */
+ struct intlists *next; /* remaining elements */
+} INTLISTS;
+
+typedef struct Box { /* an AABB with pointer to metalelem */
+ float min[3], max[3];
+ const MetaElem *ml;
+} Box;
+
+typedef struct MetaballBVHNode { /* BVH node */
+ Box bb[2]; /* AABB of children */
+ struct MetaballBVHNode *child[2];
+} MetaballBVHNode;
+
+typedef struct process { /* parameters, storage */
+ float thresh, size; /* mball threshold, single cube size */
+ float delta; /* small delta for calculating normals */
+ unsigned int converge_res; /* converge procedure resolution (more = slower) */
+
+ MetaElem **mainb; /* array of all metaelems */
+ unsigned int totelem, mem; /* number of metaelems */
+
+ MetaballBVHNode metaball_bvh; /* The simplest bvh */
+ Box allbb; /* Bounding box of all metaelems */
+
+ MetaballBVHNode **bvh_queue; /* Queue used during bvh traversal */
+ unsigned int bvh_queue_size;
+
+ CUBES *cubes; /* stack of cubes waiting for polygonization */
+ CENTERLIST **centers; /* cube center hash table */
+ CORNER **corners; /* corner value hash table */
+ EDGELIST **edges; /* edge and vertex id hash table */
+
+ int (*indices)[4]; /* output indices */
+ unsigned int totindex; /* size of memory allocated for indices */
+ unsigned int curindex; /* number of currently added indices */
+
+ float (*co)[3], (*no)[3]; /* surface vertices - positions and normals */
+ unsigned int totvertex; /* memory size */
+ unsigned int curvertex; /* currently added vertices */
+
+ /* memory allocation from common pool */
+ MemArena *pgn_elements;
+} PROCESS;
+
+/* Forward declarations */
+static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2);
+static void add_cube(PROCESS *process, int i, int j, int k);
+static void make_face(PROCESS *process, int i1, int i2, int i3, int i4);
+static void converge(PROCESS *process, const CORNER *c1, const CORNER *c2, float r_p[3]);
+
+/* ******************* SIMPLE BVH ********************* */
+
+static void make_box_union(const BoundBox *a, const Box *b, Box *r_out)
+{
+ r_out->min[0] = min_ff(a->vec[0][0], b->min[0]);
+ r_out->min[1] = min_ff(a->vec[0][1], b->min[1]);
+ r_out->min[2] = min_ff(a->vec[0][2], b->min[2]);
+
+ r_out->max[0] = max_ff(a->vec[6][0], b->max[0]);
+ r_out->max[1] = max_ff(a->vec[6][1], b->max[1]);
+ r_out->max[2] = max_ff(a->vec[6][2], b->max[2]);
+}
+
+static void make_box_from_metaelem(Box *r, const MetaElem *ml)
+{
+ copy_v3_v3(r->max, ml->bb->vec[6]);
+ copy_v3_v3(r->min, ml->bb->vec[0]);
+ r->ml = ml;
+}
+
+/**
+ * Partitions part of mainb array [start, end) along axis s. Returns i,
+ * where centroids of elements in the [start, i) segment lie "on the right side" of div,
+ * and elements in the [i, end) segment lie "on the left"
+ */
+static unsigned int partition_mainb(MetaElem **mainb, unsigned int start, unsigned int end, unsigned int s, float div)
+{
+ unsigned int i = start, j = end - 1;
+ div *= 2.0f;
+
+ while (1) {
+ while (i < j && div > (mainb[i]->bb->vec[6][s] + mainb[i]->bb->vec[0][s])) i++;
+ while (j > i && div < (mainb[j]->bb->vec[6][s] + mainb[j]->bb->vec[0][s])) j--;
+
+ if (i >= j)
+ break;
+
+ SWAP(MetaElem *, mainb[i], mainb[j]);
+ i++;
+ j--;
+ }
+
+ if (i == start) {
+ i++;
+ }
+
+ return i;
+}
+
+/**
+ * Recursively builds a BVH, dividing elements along the middle of the longest axis of allbox.
+ */
+static void build_bvh_spatial(
+ PROCESS *process, MetaballBVHNode *node,
+ unsigned int start, unsigned int end, const Box *allbox)
+{
+ unsigned int part, j, s;
+ float dim[3], div;
+
+ /* Maximum bvh queue size is number of nodes which are made, equals calls to this function. */
+ process->bvh_queue_size++;
+
+ dim[0] = allbox->max[0] - allbox->min[0];
+ dim[1] = allbox->max[1] - allbox->min[1];
+ dim[2] = allbox->max[2] - allbox->min[2];
+
+ s = 0;
+ if (dim[1] > dim[0] && dim[1] > dim[2]) s = 1;
+ else if (dim[2] > dim[1] && dim[2] > dim[0]) s = 2;
+
+ div = allbox->min[s] + (dim[s] / 2.0f);
+
+ part = partition_mainb(process->mainb, start, end, s, div);
+
+ make_box_from_metaelem(&node->bb[0], process->mainb[start]);
+ node->child[0] = NULL;
+
+ if (part > start + 1) {
+ for (j = start; j < part; j++) {
+ make_box_union(process->mainb[j]->bb, &node->bb[0], &node->bb[0]);
+ }
+
+ node->child[0] = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaballBVHNode));
+ build_bvh_spatial(process, node->child[0], start, part, &node->bb[0]);
+ }
+
+ node->child[1] = NULL;
+ if (part < end) {
+ make_box_from_metaelem(&node->bb[1], process->mainb[part]);
+
+ if (part < end - 1) {
+ for (j = part; j < end; j++) {
+ make_box_union(process->mainb[j]->bb, &node->bb[1], &node->bb[1]);
+ }
+
+ node->child[1] = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaballBVHNode));
+ build_bvh_spatial(process, node->child[1], part, end, &node->bb[1]);
+ }
+ }
+ else {
+ INIT_MINMAX(node->bb[1].min, node->bb[1].max);
+ }
+}
+
+/* ******************** ARITH ************************* */
+
+/**
+ * BASED AT CODE (but mostly rewritten) :
+ * C code from the article
+ * "An Implicit Surface Polygonizer"
+ * by Jules Bloomenthal, jbloom@beauty.gmu.edu
+ * in "Graphics Gems IV", Academic Press, 1994
+ *
+ * Authored by Jules Bloomenthal, Xerox PARC.
+ * Copyright (c) Xerox Corporation, 1991. All rights reserved.
+ * Permission is granted to reproduce, use and distribute this code for
+ * any and all purposes, provided that this notice appears in all copies.
+ */
+
+#define L 0 /* left direction: -x, -i */
+#define R 1 /* right direction: +x, +i */
+#define B 2 /* bottom direction: -y, -j */
+#define T 3 /* top direction: +y, +j */
+#define N 4 /* near direction: -z, -k */
+#define F 5 /* far direction: +z, +k */
+#define LBN 0 /* left bottom near corner */
+#define LBF 1 /* left bottom far corner */
+#define LTN 2 /* left top near corner */
+#define LTF 3 /* left top far corner */
+#define RBN 4 /* right bottom near corner */
+#define RBF 5 /* right bottom far corner */
+#define RTN 6 /* right top near corner */
+#define RTF 7 /* right top far corner */
+
+/**
+ * the LBN corner of cube (i, j, k), corresponds with location
+ * (i-0.5)*size, (j-0.5)*size, (k-0.5)*size)
+ */
+
+#define HASHBIT (5)
+#define HASHSIZE (size_t)(1 << (3 * HASHBIT)) /*! < hash table size (32768) */
+
+#define HASH(i, j, k) ((((( (i) & 31) << 5) | ( (j) & 31)) << 5) | ( (k) & 31) )
+
+#define MB_BIT(i, bit) (((i) >> (bit)) & 1)
+// #define FLIP(i, bit) ((i) ^ 1 << (bit)) /* flip the given bit of i */
+
+/* ******************** DENSITY COPMPUTATION ********************* */
+
+/**
+ * Computes density from given metaball at given position.
+ * Metaball equation is: ``(1 - r^2 / R^2)^3 * s``
+ *
+ * r = distance from center
+ * R = metaball radius
+ * s - metaball stiffness
+ */
+static float densfunc(const MetaElem *ball, float x, float y, float z)
+{
+ float dist2;
+ float dvec[3] = {x, y, z};
+
+ mul_m4_v3((float (*)[4])ball->imat, dvec);
+
+ switch (ball->type) {
+ case MB_BALL:
+ /* do nothing */
+ break;
+ case MB_CUBE:
+ if (dvec[2] > ball->expz) dvec[2] -= ball->expz;
+ else if (dvec[2] < -ball->expz) dvec[2] += ball->expz;
+ else dvec[2] = 0.0;
+ /* fall through */
+ case MB_PLANE:
+ if (dvec[1] > ball->expy) dvec[1] -= ball->expy;
+ else if (dvec[1] < -ball->expy) dvec[1] += ball->expy;
+ else dvec[1] = 0.0;
+ /* fall through */
+ case MB_TUBE:
+ if (dvec[0] > ball->expx) dvec[0] -= ball->expx;
+ else if (dvec[0] < -ball->expx) dvec[0] += ball->expx;
+ else dvec[0] = 0.0;
+ break;
+ case MB_ELIPSOID:
+ dvec[0] /= ball->expx;
+ dvec[1] /= ball->expy;
+ dvec[2] /= ball->expz;
+ break;
+
+ /* *** deprecated, could be removed?, do-versioned at least *** */
+ case MB_TUBEX:
+ if (dvec[0] > ball->len) dvec[0] -= ball->len;
+ else if (dvec[0] < -ball->len) dvec[0] += ball->len;
+ else dvec[0] = 0.0;
+ break;
+ case MB_TUBEY:
+ if (dvec[1] > ball->len) dvec[1] -= ball->len;
+ else if (dvec[1] < -ball->len) dvec[1] += ball->len;
+ else dvec[1] = 0.0;
+ break;
+ case MB_TUBEZ:
+ if (dvec[2] > ball->len) dvec[2] -= ball->len;
+ else if (dvec[2] < -ball->len) dvec[2] += ball->len;
+ else dvec[2] = 0.0;
+ break;
+ /* *** end deprecated *** */
+ }
+
+ /* ball->rad2 is inverse of squared rad */
+ dist2 = 1.0f - (len_squared_v3(dvec) * ball->rad2);
+
+ /* ball->s is negative if metaball is negative */
+ return (dist2 < 0.0f) ? 0.0f : (ball->s * dist2 * dist2 * dist2);
+}
+
+/**
+ * Computes density at given position form all metaballs which contain this point in their box.
+ * Traverses BVH using a queue.
+ */
+static float metaball(PROCESS *process, float x, float y, float z)
+{
+ int i;
+ float dens = 0.0f;
+ unsigned int front = 0, back = 0;
+ MetaballBVHNode *node;
+
+ process->bvh_queue[front++] = &process->metaball_bvh;
+
+ while (front != back) {
+ node = process->bvh_queue[back++];
+
+ for (i = 0; i < 2; i++) {
+ if ((node->bb[i].min[0] <= x) && (node->bb[i].max[0] >= x) &&
+ (node->bb[i].min[1] <= y) && (node->bb[i].max[1] >= y) &&
+ (node->bb[i].min[2] <= z) && (node->bb[i].max[2] >= z))
+ {
+ if (node->child[i]) process->bvh_queue[front++] = node->child[i];
+ else dens += densfunc(node->bb[i].ml, x, y, z);
+ }
+ }
+ }
+
+ return process->thresh - dens;
+}
+
+/**
+ * Adds face to indices, expands memory if needed.
+ */
+static void make_face(PROCESS *process, int i1, int i2, int i3, int i4)
+{
+ int *cur;
+
+#ifdef USE_ACCUM_NORMAL
+ float n[3];
+#endif
+
+ if (UNLIKELY(process->totindex == process->curindex)) {
+ process->totindex += 4096;
+ process->indices = MEM_reallocN(process->indices, sizeof(int[4]) * process->totindex);
+ }
+
+ cur = process->indices[process->curindex++];
+
+ /* displists now support array drawing, we treat tri's as fake quad */
+
+ cur[0] = i1;
+ cur[1] = i2;
+ cur[2] = i3;
+
+ if (i4 == 0) {
+ cur[3] = i3;
+ }
+ else {
+ cur[3] = i4;
+ }
+
+#ifdef USE_ACCUM_NORMAL
+ if (i4 == 0) {
+ normal_tri_v3(n, process->co[i1], process->co[i2], process->co[i3]);
+ accumulate_vertex_normals(
+ process->no[i1], process->no[i2], process->no[i3], NULL, n,
+ process->co[i1], process->co[i2], process->co[i3], NULL);
+ }
+ else {
+ normal_quad_v3(n, process->co[i1], process->co[i2], process->co[i3], process->co[i4]);
+ accumulate_vertex_normals(
+ process->no[i1], process->no[i2], process->no[i3], process->no[i4], n,
+ process->co[i1], process->co[i2], process->co[i3], process->co[i4]);
+ }
+#endif
+
+}
+
+/* Frees allocated memory */
+static void freepolygonize(PROCESS *process)
+{
+ if (process->corners) MEM_freeN(process->corners);
+ if (process->edges) MEM_freeN(process->edges);
+ if (process->centers) MEM_freeN(process->centers);
+ if (process->mainb) MEM_freeN(process->mainb);
+ if (process->bvh_queue) MEM_freeN(process->bvh_queue);
+ if (process->pgn_elements) BLI_memarena_free(process->pgn_elements);
+}
+
+/* **************** POLYGONIZATION ************************ */
+
+/**** Cubical Polygonization (optional) ****/
+
+#define LB 0 /* left bottom edge */
+#define LT 1 /* left top edge */
+#define LN 2 /* left near edge */
+#define LF 3 /* left far edge */
+#define RB 4 /* right bottom edge */
+#define RT 5 /* right top edge */
+#define RN 6 /* right near edge */
+#define RF 7 /* right far edge */
+#define BN 8 /* bottom near edge */
+#define BF 9 /* bottom far edge */
+#define TN 10 /* top near edge */
+#define TF 11 /* top far edge */
+
+static INTLISTS *cubetable[256];
+static char faces[256];
+
+/* edge: LB, LT, LN, LF, RB, RT, RN, RF, BN, BF, TN, TF */
+static int corner1[12] = {
+ LBN, LTN, LBN, LBF, RBN, RTN, RBN, RBF, LBN, LBF, LTN, LTF
+};
+static int corner2[12] = {
+ LBF, LTF, LTN, LTF, RBF, RTF, RTN, RTF, RBN, RBF, RTN, RTF
+};
+static int leftface[12] = {
+ B, L, L, F, R, T, N, R, N, B, T, F
+};
+/* face on left when going corner1 to corner2 */
+static int rightface[12] = {
+ L, T, N, L, B, R, R, F, B, F, N, T
+};
+/* face on right when going corner1 to corner2 */
+
+/**
+ * triangulate the cube directly, without decomposition
+ */
+static void docube(PROCESS *process, CUBE *cube)
+{
+ INTLISTS *polys;
+ CORNER *c1, *c2;
+ int i, index = 0, count, indexar[8];
+
+ /* Determine which case cube falls into. */
+ for (i = 0; i < 8; i++) {
+ if (cube->corners[i]->value > 0.0f) {
+ index += (1 << i);
+ }
+ }
+
+ /* Using faces[] table, adds neighbouring cube if surface intersects face in this direction. */
+ if (MB_BIT(faces[index], 0)) add_cube(process, cube->i - 1, cube->j, cube->k);
+ if (MB_BIT(faces[index], 1)) add_cube(process, cube->i + 1, cube->j, cube->k);
+ if (MB_BIT(faces[index], 2)) add_cube(process, cube->i, cube->j - 1, cube->k);
+ if (MB_BIT(faces[index], 3)) add_cube(process, cube->i, cube->j + 1, cube->k);
+ if (MB_BIT(faces[index], 4)) add_cube(process, cube->i, cube->j, cube->k - 1);
+ if (MB_BIT(faces[index], 5)) add_cube(process, cube->i, cube->j, cube->k + 1);
+
+ /* Using cubetable[], determines polygons for output. */
+ for (polys = cubetable[index]; polys; polys = polys->next) {
+ INTLIST *edges;
+
+ count = 0;
+ /* Sets needed vertex id's lying on the edges. */
+ for (edges = polys->list; edges; edges = edges->next) {
+ c1 = cube->corners[corner1[edges->i]];
+ c2 = cube->corners[corner2[edges->i]];
+
+ indexar[count] = vertid(process, c1, c2);
+ count++;
+ }
+
+ /* Adds faces to output. */
+ if (count > 2) {
+ switch (count) {
+ case 3:
+ make_face(process, indexar[2], indexar[1], indexar[0], 0);
+ break;
+ case 4:
+ if (indexar[0] == 0) make_face(process, indexar[0], indexar[3], indexar[2], indexar[1]);
+ else make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]);
+ break;
+ case 5:
+ if (indexar[0] == 0) make_face(process, indexar[0], indexar[3], indexar[2], indexar[1]);
+ else make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]);
+
+ make_face(process, indexar[4], indexar[3], indexar[0], 0);
+ break;
+ case 6:
+ if (indexar[0] == 0) {
+ make_face(process, indexar[0], indexar[3], indexar[2], indexar[1]);
+ make_face(process, indexar[0], indexar[5], indexar[4], indexar[3]);
+ }
+ else {
+ make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]);
+ make_face(process, indexar[5], indexar[4], indexar[3], indexar[0]);
+ }
+ break;
+ case 7:
+ if (indexar[0] == 0) {
+ make_face(process, indexar[0], indexar[3], indexar[2], indexar[1]);
+ make_face(process, indexar[0], indexar[5], indexar[4], indexar[3]);
+ }
+ else {
+ make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]);
+ make_face(process, indexar[5], indexar[4], indexar[3], indexar[0]);
+ }
+
+ make_face(process, indexar[6], indexar[5], indexar[0], 0);
+
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * return corner with the given lattice location
+ * set (and cache) its function value
+ */
+static CORNER *setcorner(PROCESS *process, int i, int j, int k)
+{
+ /* for speed, do corner value caching here */
+ CORNER *c;
+ int index;
+
+ /* does corner exist? */
+ index = HASH(i, j, k);
+ c = process->corners[index];
+
+ for (; c != NULL; c = c->next) {
+ if (c->i == i && c->j == j && c->k == k) {
+ return c;
+ }
+ }
+
+ c = BLI_memarena_alloc(process->pgn_elements, sizeof(CORNER));
+
+ c->i = i;
+ c->co[0] = ((float)i - 0.5f) * process->size;
+ c->j = j;
+ c->co[1] = ((float)j - 0.5f) * process->size;
+ c->k = k;
+ c->co[2] = ((float)k - 0.5f) * process->size;
+
+ c->value = metaball(process, c->co[0], c->co[1], c->co[2]);
+
+ c->next = process->corners[index];
+ process->corners[index] = c;
+
+ return c;
+}
+
+/**
+ * return next clockwise edge from given edge around given face
+ */
+static int nextcwedge(int edge, int face)
+{
+ switch (edge) {
+ case LB:
+ return (face == L) ? LF : BN;
+ case LT:
+ return (face == L) ? LN : TF;
+ case LN:
+ return (face == L) ? LB : TN;
+ case LF:
+ return (face == L) ? LT : BF;
+ case RB:
+ return (face == R) ? RN : BF;
+ case RT:
+ return (face == R) ? RF : TN;
+ case RN:
+ return (face == R) ? RT : BN;
+ case RF:
+ return (face == R) ? RB : TF;
+ case BN:
+ return (face == B) ? RB : LN;
+ case BF:
+ return (face == B) ? LB : RF;
+ case TN:
+ return (face == T) ? LT : RN;
+ case TF:
+ return (face == T) ? RT : LF;
+ }
+ return 0;
+}
+
+/**
+ * \return the face adjoining edge that is not the given face
+ */
+static int otherface(int edge, int face)
+{
+ int other = leftface[edge];
+ return face == other ? rightface[edge] : other;
+}
+
+/**
+ * create the 256 entry table for cubical polygonization
+ */
+static void makecubetable(void)
+{
+ static bool is_done = false;
+ int i, e, c, done[12], pos[8];
+
+ if (is_done) return;
+ is_done = true;
+
+ for (i = 0; i < 256; i++) {
+ for (e = 0; e < 12; e++) done[e] = 0;
+ for (c = 0; c < 8; c++) pos[c] = MB_BIT(i, c);
+ for (e = 0; e < 12; e++)
+ if (!done[e] && (pos[corner1[e]] != pos[corner2[e]])) {
+ INTLIST *ints = NULL;
+ INTLISTS *lists = MEM_callocN(sizeof(INTLISTS), "mball_intlist");
+ int start = e, edge = e;
+
+ /* get face that is to right of edge from pos to neg corner: */
+ int face = pos[corner1[e]] ? rightface[e] : leftface[e];
+
+ while (1) {
+ edge = nextcwedge(edge, face);
+ done[edge] = 1;
+ if (pos[corner1[edge]] != pos[corner2[edge]]) {
+ INTLIST *tmp = ints;
+
+ ints = MEM_callocN(sizeof(INTLIST), "mball_intlist");
+ ints->i = edge;
+ ints->next = tmp; /* add edge to head of list */
+
+ if (edge == start) break;
+ face = otherface(edge, face);
+ }
+ }
+ lists->list = ints; /* add ints to head of table entry */
+ lists->next = cubetable[i];
+ cubetable[i] = lists;
+ }
+ }
+
+ for (i = 0; i < 256; i++) {
+ INTLISTS *polys;
+ faces[i] = 0;
+ for (polys = cubetable[i]; polys; polys = polys->next) {
+ INTLIST *edges;
+
+ for (edges = polys->list; edges; edges = edges->next) {
+ if (edges->i == LB || edges->i == LT || edges->i == LN || edges->i == LF) faces[i] |= 1 << L;
+ if (edges->i == RB || edges->i == RT || edges->i == RN || edges->i == RF) faces[i] |= 1 << R;
+ if (edges->i == LB || edges->i == RB || edges->i == BN || edges->i == BF) faces[i] |= 1 << B;
+ if (edges->i == LT || edges->i == RT || edges->i == TN || edges->i == TF) faces[i] |= 1 << T;
+ if (edges->i == LN || edges->i == RN || edges->i == BN || edges->i == TN) faces[i] |= 1 << N;
+ if (edges->i == LF || edges->i == RF || edges->i == BF || edges->i == TF) faces[i] |= 1 << F;
+ }
+ }
+ }
+}
+
+void BKE_mball_cubeTable_free(void)
+{
+ int i;
+ INTLISTS *lists, *nlists;
+ INTLIST *ints, *nints;
+
+ for (i = 0; i < 256; i++) {
+ lists = cubetable[i];
+ while (lists) {
+ nlists = lists->next;
+
+ ints = lists->list;
+ while (ints) {
+ nints = ints->next;
+ MEM_freeN(ints);
+ ints = nints;
+ }
+
+ MEM_freeN(lists);
+ lists = nlists;
+ }
+ cubetable[i] = NULL;
+ }
+}
+
+/**** Storage ****/
+
+/**
+ * Inserts cube at lattice i, j, k into hash table, marking it as "done"
+ */
+static int setcenter(PROCESS *process, CENTERLIST *table[], const int i, const int j, const int k)
+{
+ int index;
+ CENTERLIST *newc, *l, *q;
+
+ index = HASH(i, j, k);
+ q = table[index];
+
+ for (l = q; l != NULL; l = l->next) {
+ if (l->i == i && l->j == j && l->k == k) return 1;
+ }
+
+ newc = BLI_memarena_alloc(process->pgn_elements, sizeof(CENTERLIST));
+ newc->i = i;
+ newc->j = j;
+ newc->k = k;
+ newc->next = q;
+ table[index] = newc;
+
+ return 0;
+}
+
+/**
+ * Sets vid of vertex lying on given edge.
+ */
+static void setedge(
+ PROCESS *process,
+ int i1, int j1, int k1,
+ int i2, int j2, int k2,
+ int vid)
+{
+ int index;
+ EDGELIST *newe;
+
+ if (i1 > i2 || (i1 == i2 && (j1 > j2 || (j1 == j2 && k1 > k2)))) {
+ int t = i1;
+ i1 = i2;
+ i2 = t;
+ t = j1;
+ j1 = j2;
+ j2 = t;
+ t = k1;
+ k1 = k2;
+ k2 = t;
+ }
+ index = HASH(i1, j1, k1) + HASH(i2, j2, k2);
+ newe = BLI_memarena_alloc(process->pgn_elements, sizeof(EDGELIST));
+
+ newe->i1 = i1;
+ newe->j1 = j1;
+ newe->k1 = k1;
+ newe->i2 = i2;
+ newe->j2 = j2;
+ newe->k2 = k2;
+ newe->vid = vid;
+ newe->next = process->edges[index];
+ process->edges[index] = newe;
+}
+
+/**
+ * \return vertex id for edge; return -1 if not set
+ */
+static int getedge(EDGELIST *table[],
+ int i1, int j1, int k1,
+ int i2, int j2, int k2)
+{
+ EDGELIST *q;
+
+ if (i1 > i2 || (i1 == i2 && (j1 > j2 || (j1 == j2 && k1 > k2)))) {
+ int t = i1;
+ i1 = i2;
+ i2 = t;
+ t = j1;
+ j1 = j2;
+ j2 = t;
+ t = k1;
+ k1 = k2;
+ k2 = t;
+ }
+ q = table[HASH(i1, j1, k1) + HASH(i2, j2, k2)];
+ for (; q != NULL; q = q->next) {
+ if (q->i1 == i1 && q->j1 == j1 && q->k1 == k1 &&
+ q->i2 == i2 && q->j2 == j2 && q->k2 == k2)
+ {
+ return q->vid;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Adds a vertex, expands memory if needed.
+ */
+static void addtovertices(PROCESS *process, const float v[3], const float no[3])
+{
+ if (process->curvertex == process->totvertex) {
+ process->totvertex += 4096;
+ process->co = MEM_reallocN(process->co, process->totvertex * sizeof(float[3]));
+ process->no = MEM_reallocN(process->no, process->totvertex * sizeof(float[3]));
+ }
+
+ copy_v3_v3(process->co[process->curvertex], v);
+ copy_v3_v3(process->no[process->curvertex], no);
+
+ process->curvertex++;
+}
+
+#ifndef USE_ACCUM_NORMAL
+/**
+ * Computes normal from density field at given point.
+ *
+ * \note Doesn't do normalization!
+ */
+static void vnormal(PROCESS *process, const float point[3], float r_no[3])
+{
+ const float delta = process->delta;
+ const float f = metaball(process, point[0], point[1], point[2]);
+
+ r_no[0] = metaball(process, point[0] + delta, point[1], point[2]) - f;
+ r_no[1] = metaball(process, point[0], point[1] + delta, point[2]) - f;
+ r_no[2] = metaball(process, point[0], point[1], point[2] + delta) - f;
+
+#if 0
+ f = normalize_v3(r_no);
+
+ if (0) {
+ float tvec[3];
+
+ delta *= 2.0f;
+
+ f = process->function(process, point[0], point[1], point[2]);
+
+ tvec[0] = process->function(process, point[0] + delta, point[1], point[2]) - f;
+ tvec[1] = process->function(process, point[0], point[1] + delta, point[2]) - f;
+ tvec[2] = process->function(process, point[0], point[1], point[2] + delta) - f;
+
+ if (normalize_v3(tvec) != 0.0f) {
+ add_v3_v3(r_no, tvec);
+ normalize_v3(r_no);
+ }
+ }
+#endif
+}
+#endif /* USE_ACCUM_NORMAL */
+
+/**
+ * \return the id of vertex between two corners.
+ *
+ * If it wasn't previously computed, does #converge() and adds vertex to process.
+ */
+static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2)
+{
+ float v[3], no[3];
+ int vid = getedge(process->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k);
+
+ if (vid != -1) return vid; /* previously computed */
+
+ converge(process, c1, c2, v); /* position */
+
+#ifdef USE_ACCUM_NORMAL
+ zero_v3(no);
+#else
+ vnormal(process, v, no);
+#endif
+
+ addtovertices(process, v, no); /* save vertex */
+ vid = (int)process->curvertex - 1;
+ setedge(process, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid);
+
+ return vid;
+}
+
+/**
+ * Given two corners, computes approximation of surface intersection point between them.
+ * In case of small threshold, do bisection.
+ */
+static void converge(PROCESS *process, const CORNER *c1, const CORNER *c2, float r_p[3])
+{
+ float tmp, dens;
+ unsigned int i;
+ float c1_value, c1_co[3];
+ float c2_value, c2_co[3];
+
+ if (c1->value < c2->value) {
+ c1_value = c2->value;
+ copy_v3_v3(c1_co, c2->co);
+ c2_value = c1->value;
+ copy_v3_v3(c2_co, c1->co);
+ }
+ else {
+ c1_value = c1->value;
+ copy_v3_v3(c1_co, c1->co);
+ c2_value = c2->value;
+ copy_v3_v3(c2_co, c2->co);
+ }
+
+
+ for (i = 0; i < process->converge_res; i++) {
+ interp_v3_v3v3(r_p, c1_co, c2_co, 0.5f);
+ dens = metaball(process, r_p[0], r_p[1], r_p[2]);
+
+ if (dens > 0.0f) {
+ c1_value = dens;
+ copy_v3_v3(c1_co, r_p);
+ }
+ else {
+ c2_value = dens;
+ copy_v3_v3(c2_co, r_p);
+ }
+ }
+
+ tmp = -c1_value / (c2_value - c1_value);
+ interp_v3_v3v3(r_p, c1_co, c2_co, tmp);
+}
+
+/**
+ * Adds cube at given lattice position to cube stack of process.
+ */
+static void add_cube(PROCESS *process, int i, int j, int k)
+{
+ CUBES *ncube;
+ int n;
+
+ /* test if cube has been found before */
+ if (setcenter(process, process->centers, i, j, k) == 0) {
+ /* push cube on stack: */
+ ncube = BLI_memarena_alloc(process->pgn_elements, sizeof(CUBES));
+ ncube->next = process->cubes;
+ process->cubes = ncube;
+
+ ncube->cube.i = i;
+ ncube->cube.j = j;
+ ncube->cube.k = k;
+
+ /* set corners of initial cube: */
+ for (n = 0; n < 8; n++)
+ ncube->cube.corners[n] = setcorner(process, i + MB_BIT(n, 2), j + MB_BIT(n, 1), k + MB_BIT(n, 0));
+ }
+}
+
+static void next_lattice(int r[3], const float pos[3], const float size)
+{
+ r[0] = (int)ceil((pos[0] / size) + 0.5f);
+ r[1] = (int)ceil((pos[1] / size) + 0.5f);
+ r[2] = (int)ceil((pos[2] / size) + 0.5f);
+}
+static void prev_lattice(int r[3], const float pos[3], const float size)
+{
+ next_lattice(r, pos, size);
+ r[0]--; r[1]--; r[2]--;
+}
+static void closest_latice(int r[3], const float pos[3], const float size)
+{
+ r[0] = (int)floorf(pos[0] / size + 1.0f);
+ r[1] = (int)floorf(pos[1] / size + 1.0f);
+ r[2] = (int)floorf(pos[2] / size + 1.0f);
+}
+
+/**
+ * Find at most 26 cubes to start polygonization from.
+ */
+static void find_first_points(PROCESS *process, const unsigned int em)
+{
+ const MetaElem *ml;
+ int center[3], lbn[3], rtf[3], it[3], dir[3], add[3];
+ float tmp[3], a, b;
+
+ ml = process->mainb[em];
+
+ mid_v3_v3v3(tmp, ml->bb->vec[0], ml->bb->vec[6]);
+ closest_latice(center, tmp, process->size);
+ prev_lattice(lbn, ml->bb->vec[0], process->size);
+ next_lattice(rtf, ml->bb->vec[6], process->size);
+
+ for (dir[0] = -1; dir[0] <= 1; dir[0]++) {
+ for (dir[1] = -1; dir[1] <= 1; dir[1]++) {
+ for (dir[2] = -1; dir[2] <= 1; dir[2]++) {
+ if (dir[0] == 0 && dir[1] == 0 && dir[2] == 0) {
+ continue;
+ }
+
+ copy_v3_v3_int(it, center);
+
+ b = setcorner(process, it[0], it[1], it[2])->value;
+ do {
+ it[0] += dir[0];
+ it[1] += dir[1];
+ it[2] += dir[2];
+ a = b;
+ b = setcorner(process, it[0], it[1], it[2])->value;
+
+ if (a * b < 0.0f) {
+ add[0] = it[0] - dir[0];
+ add[1] = it[1] - dir[1];
+ add[2] = it[2] - dir[2];
+ DO_MIN(it, add);
+ add_cube(process, add[0], add[1], add[2]);
+ break;
+ }
+ } while ((it[0] > lbn[0]) && (it[1] > lbn[1]) && (it[2] > lbn[2]) &&
+ (it[0] < rtf[0]) && (it[1] < rtf[1]) && (it[2] < rtf[2]));
+ }
+ }
+ }
+}
+
+/**
+ * The main polygonization proc.
+ * Allocates memory, makes cubetable,
+ * finds starting surface points
+ * and processes cubes on the stack until none left.
+ */
+static void polygonize(PROCESS *process)
+{
+ CUBE c;
+ unsigned int i;
+
+ process->centers = MEM_callocN(HASHSIZE * sizeof(CENTERLIST *), "mbproc->centers");
+ process->corners = MEM_callocN(HASHSIZE * sizeof(CORNER *), "mbproc->corners");
+ process->edges = MEM_callocN(2 * HASHSIZE * sizeof(EDGELIST *), "mbproc->edges");
+ process->bvh_queue = MEM_callocN(sizeof(MetaballBVHNode *) * process->bvh_queue_size, "Metaball BVH Queue");
+
+ makecubetable();
+
+ for (i = 0; i < process->totelem; i++) {
+ find_first_points(process, i);
+ }
+
+ while (process->cubes != NULL) {
+ c = process->cubes->cube;
+ process->cubes = process->cubes->next;
+
+ docube(process, &c);
+ }
+}
+
+/**
+ * Iterates over ALL objects in the scene and all of its sets, including
+ * making all duplis(not only metas). Copies metas to mainb array.
+ * Computes bounding boxes for building BVH. */
+static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob)
+{
+ Scene *sce_iter = scene;
+ Base *base;
+ Object *bob;
+ MetaBall *mb;
+ const MetaElem *ml;
+ float obinv[4][4], obmat[4][4];
+ unsigned int i;
+ int obnr, zero_size = 0;
+ char obname[MAX_ID_NAME];
+ SceneBaseIter iter;
+
+ copy_m4_m4(obmat, ob->obmat); /* to cope with duplicators from BKE_scene_base_iter_next */
+ invert_m4_m4(obinv, ob->obmat);
+
+ BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
+
+ /* make main array */
+ BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL);
+ while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &bob)) {
+ if (bob->type == OB_MBALL) {
+ zero_size = 0;
+ ml = NULL;
+
+ if (bob == ob && (base->flag & OB_FROMDUPLI) == 0) {
+ mb = ob->data;
+
+ if (mb->editelems) ml = mb->editelems->first;
+ else ml = mb->elems.first;
+ }
+ else {
+ char name[MAX_ID_NAME];
+ int nr;
+
+ BLI_split_name_num(name, &nr, bob->id.name + 2, '.');
+ if (STREQ(obname, name)) {
+ mb = bob->data;
+
+ if (mb->editelems) ml = mb->editelems->first;
+ else ml = mb->elems.first;
+ }
+ }
+
+ /* when metaball object has zero scale, then MetaElem to this MetaBall
+ * will not be put to mainb array */
+ if (has_zero_axis_m4(bob->obmat)) {
+ zero_size = 1;
+ }
+ else if (bob->parent) {
+ struct Object *pob = bob->parent;
+ while (pob) {
+ if (has_zero_axis_m4(pob->obmat)) {
+ zero_size = 1;
+ break;
+ }
+ pob = pob->parent;
+ }
+ }
+
+ if (zero_size) {
+ while (ml) {
+ ml = ml->next;
+ }
+ }
+ else {
+ while (ml) {
+ if (!(ml->flag & MB_HIDE)) {
+ float pos[4][4], rot[4][4];
+ float expx, expy, expz;
+ float tempmin[3], tempmax[3];
+
+ MetaElem *new_ml;
+
+ /* make a copy because of duplicates */
+ new_ml = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaElem));
+ *(new_ml) = *ml;
+ new_ml->bb = BLI_memarena_alloc(process->pgn_elements, sizeof(BoundBox));
+ new_ml->mat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float));
+ new_ml->imat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float));
+
+ /* too big stiffness seems only ugly due to linear interpolation
+ * no need to have possibility for too big stiffness */
+ if (ml->s > 10.0f) new_ml->s = 10.0f;
+ else new_ml->s = ml->s;
+
+ /* if metaball is negative, set stiffness negative */
+ if (new_ml->flag & MB_NEGATIVE) new_ml->s = -new_ml->s;
+
+ /* Translation of MetaElem */
+ unit_m4(pos);
+ pos[3][0] = ml->x;
+ pos[3][1] = ml->y;
+ pos[3][2] = ml->z;
+
+ /* Rotation of MetaElem is stored in quat */
+ quat_to_mat4(rot, ml->quat);
+
+ /* basis object space -> world -> ml object space -> position -> rotation -> ml local space */
+ mul_m4_series((float(*)[4])new_ml->mat, obinv, bob->obmat, pos, rot);
+ /* ml local space -> basis object space */
+ invert_m4_m4((float(*)[4])new_ml->imat, (float(*)[4])new_ml->mat);
+
+ /* rad2 is inverse of squared radius */
+ new_ml->rad2 = 1 / (ml->rad * ml->rad);
+
+ /* initial dimensions = radius */
+ expx = ml->rad;
+ expy = ml->rad;
+ expz = ml->rad;
+
+ switch (ml->type) {
+ case MB_BALL:
+ break;
+ case MB_CUBE: /* cube is "expanded" by expz, expy and expx */
+ expz += ml->expz;
+ /* fall through */
+ case MB_PLANE: /* plane is "expanded" by expy and expx */
+ expy += ml->expy;
+ /* fall through */
+ case MB_TUBE: /* tube is "expanded" by expx */
+ expx += ml->expx;
+ break;
+ case MB_ELIPSOID: /* ellipsoid is "stretched" by exp* */
+ expx *= ml->expx;
+ expy *= ml->expy;
+ expz *= ml->expz;
+ break;
+ }
+
+ /* untransformed Bounding Box of MetaElem */
+ /* TODO, its possible the elem type has been changed and the exp* values can use a fallback */
+ copy_v3_fl3(new_ml->bb->vec[0], -expx, -expy, -expz); /* 0 */
+ copy_v3_fl3(new_ml->bb->vec[1], +expx, -expy, -expz); /* 1 */
+ copy_v3_fl3(new_ml->bb->vec[2], +expx, +expy, -expz); /* 2 */
+ copy_v3_fl3(new_ml->bb->vec[3], -expx, +expy, -expz); /* 3 */
+ copy_v3_fl3(new_ml->bb->vec[4], -expx, -expy, +expz); /* 4 */
+ copy_v3_fl3(new_ml->bb->vec[5], +expx, -expy, +expz); /* 5 */
+ copy_v3_fl3(new_ml->bb->vec[6], +expx, +expy, +expz); /* 6 */
+ copy_v3_fl3(new_ml->bb->vec[7], -expx, +expy, +expz); /* 7 */
+
+ /* transformation of Metalem bb */
+ for (i = 0; i < 8; i++)
+ mul_m4_v3((float(*)[4])new_ml->mat, new_ml->bb->vec[i]);
+
+ /* find max and min of transformed bb */
+ INIT_MINMAX(tempmin, tempmax);
+ for (i = 0; i < 8; i++) {
+ DO_MINMAX(new_ml->bb->vec[i], tempmin, tempmax);
+ }
+
+ /* set only point 0 and 6 - AABB of Metaelem */
+ copy_v3_v3(new_ml->bb->vec[0], tempmin);
+ copy_v3_v3(new_ml->bb->vec[6], tempmax);
+
+ /* add new_ml to mainb[] */
+ if (UNLIKELY(process->totelem == process->mem)) {
+ process->mem = process->mem * 2 + 10;
+ process->mainb = MEM_reallocN(process->mainb, sizeof(MetaElem *) * process->mem);
+ }
+ process->mainb[process->totelem++] = new_ml;
+ }
+ ml = ml->next;
+ }
+ }
+ }
+ }
+
+ /* compute AABB of all Metaelems */
+ if (process->totelem > 0) {
+ copy_v3_v3(process->allbb.min, process->mainb[0]->bb->vec[0]);
+ copy_v3_v3(process->allbb.max, process->mainb[0]->bb->vec[6]);
+ for (i = 1; i < process->totelem; i++)
+ make_box_union(process->mainb[i]->bb, &process->allbb, &process->allbb);
+ }
+}
+
+void BKE_mball_polygonize(EvaluationContext *eval_ctx, Scene *scene, Object *ob, ListBase *dispbase)
+{
+ MetaBall *mb;
+ DispList *dl;
+ unsigned int a;
+ PROCESS process = {0};
+
+ mb = ob->data;
+
+ process.thresh = mb->thresh;
+
+ if (process.thresh < 0.001f) process.converge_res = 16;
+ else if (process.thresh < 0.01f) process.converge_res = 8;
+ else if (process.thresh < 0.1f) process.converge_res = 4;
+ else process.converge_res = 2;
+
+ if ((eval_ctx->mode != DAG_EVAL_RENDER) && (mb->flag == MB_UPDATE_NEVER)) return;
+ if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) return;
+
+ if (eval_ctx->mode == DAG_EVAL_RENDER) {
+ process.size = mb->rendersize;
+ }
+ else {
+ process.size = mb->wiresize;
+ if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_HALFRES) {
+ process.size *= 2.0f;
+ }
+ }
+
+ process.delta = process.size * 0.001f;
+
+ process.pgn_elements = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "Metaball memarena");
+
+ /* initialize all mainb (MetaElems) */
+ init_meta(eval_ctx, &process, scene, ob);
+
+ if (process.totelem > 0) {
+ build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb);
+
+ /* don't polygonize metaballs with too high resolution (base mball to small)
+ * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */
+ if (ob->size[0] > 0.00001f * (process.allbb.max[0] - process.allbb.min[0]) ||
+ ob->size[1] > 0.00001f * (process.allbb.max[1] - process.allbb.min[1]) ||
+ ob->size[2] > 0.00001f * (process.allbb.max[2] - process.allbb.min[2]))
+ {
+ polygonize(&process);
+
+ /* add resulting surface to displist */
+ if (process.curindex) {
+ dl = MEM_callocN(sizeof(DispList), "mballdisp");
+ BLI_addtail(dispbase, dl);
+ dl->type = DL_INDEX4;
+ dl->nr = (int)process.curvertex;
+ dl->parts = (int)process.curindex;
+
+ dl->index = (int *)process.indices;
+
+ for (a = 0; a < process.curvertex; a++) {
+ normalize_v3(process.no[a]);
+ }
+
+ dl->verts = (float *)process.co;
+ dl->nors = (float *)process.no;
+ }
+ }
+ }
+
+ freepolygonize(&process);
+}
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 419f907d786..c8223657a05 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -61,6 +61,7 @@
#include "BKE_object.h"
#include "BKE_editmesh.h"
+#include "DEG_depsgraph.h"
enum {
MESHCMP_DVERT_WEIGHTMISMATCH = 1,
@@ -463,7 +464,7 @@ void BKE_mesh_free(Mesh *me, int unlink)
CustomData_free(&me->pdata, me->totpoly);
if (me->adt) {
- BKE_free_animdata(&me->id);
+ BKE_animdata_free(&me->id);
me->adt = NULL;
}
@@ -1265,7 +1266,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase,
dl = dispbase->first;
while (dl) {
- int smooth = dl->rt & CU_SMOOTH ? 1 : 0;
+ const bool is_smooth = (dl->rt & CU_SMOOTH) != 0;
if (dl->type == DL_SEGM) {
startvert = vertcount;
@@ -1344,7 +1345,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase,
}
}
- if (smooth) mpoly->flag |= ME_SMOOTH;
+ if (is_smooth) mpoly->flag |= ME_SMOOTH;
mpoly++;
mloop += 3;
index += 3;
@@ -1423,7 +1424,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase,
}
}
- if (smooth) mpoly->flag |= ME_SMOOTH;
+ if (is_smooth) mpoly->flag |= ME_SMOOTH;
mpoly++;
mloop += 4;
@@ -1773,6 +1774,36 @@ void BKE_mesh_material_index_clear(Mesh *me)
}
}
+void BKE_mesh_material_remap(Mesh *me, const unsigned int *remap, unsigned int remap_len)
+{
+ const short remap_len_short = (short)remap_len;
+
+#define MAT_NR_REMAP(n) \
+ if (n < remap_len_short) { \
+ BLI_assert(n >= 0 && remap[n] < remap_len_short); \
+ n = remap[n]; \
+ } ((void)0)
+
+ if (me->edit_btmesh) {
+ BMEditMesh *em = me->edit_btmesh;
+ BMIter iter;
+ BMFace *efa;
+
+ BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ MAT_NR_REMAP(efa->mat_nr);
+ }
+ }
+ else {
+ int i;
+ for (i = 0; i < me->totpoly; i++) {
+ MAT_NR_REMAP(me->mpoly[i].mat_nr);
+ }
+ }
+
+#undef MAT_NR_REMAP
+
+}
+
void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth)
{
Mesh *me = meshOb->data;
@@ -1805,7 +1836,7 @@ void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth)
* Return a newly MEM_malloc'd array of all the mesh vertex locations
* \note \a r_numVerts may be NULL
*/
-float (*BKE_mesh_vertexCos_get(Mesh *me, int *r_numVerts))[3]
+float (*BKE_mesh_vertexCos_get(const Mesh *me, int *r_numVerts))[3]
{
int i, numVerts = me->totvert;
float (*cos)[3] = MEM_mallocN(sizeof(*cos) * numVerts, "vertexcos1");
@@ -1821,8 +1852,9 @@ float (*BKE_mesh_vertexCos_get(Mesh *me, int *r_numVerts))[3]
* Find the index of the loop in 'poly' which references vertex,
* returns -1 if not found
*/
-int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart,
- unsigned vert)
+int poly_find_loop_from_vert(
+ const MPoly *poly, const MLoop *loopstart,
+ unsigned vert)
{
int j;
for (j = 0; j < poly->totloop; j++, loopstart++) {
@@ -1838,20 +1870,22 @@ int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart,
* vertex. Returns the index of the loop matching vertex, or -1 if the
* vertex is not in \a poly
*/
-int poly_get_adj_loops_from_vert(unsigned r_adj[3], const MPoly *poly,
- const MLoop *mloop, unsigned vert)
+int poly_get_adj_loops_from_vert(
+ unsigned r_adj[2], const MPoly *poly,
+ const MLoop *mloop, unsigned vert)
{
int corner = poly_find_loop_from_vert(poly,
&mloop[poly->loopstart],
vert);
if (corner != -1) {
+#if 0 /* unused - this loop */
const MLoop *ml = &mloop[poly->loopstart + corner];
+#endif
/* vertex was found */
r_adj[0] = ME_POLY_LOOP_PREV(mloop, poly, corner)->v;
- r_adj[1] = ml->v;
- r_adj[2] = ME_POLY_LOOP_NEXT(mloop, poly, corner)->v;
+ r_adj[1] = ME_POLY_LOOP_NEXT(mloop, poly, corner)->v;
}
return corner;
@@ -1887,6 +1921,7 @@ void BKE_mesh_transform(Mesh *me, float mat[4][4], bool do_keys)
{
int i;
MVert *mvert = me->mvert;
+ float (*lnors)[3] = CustomData_get_layer(&me->ldata, CD_NORMAL);
for (i = 0; i < me->totvert; i++, mvert++)
mul_m4_v3(mat, mvert->co);
@@ -1901,7 +1936,17 @@ void BKE_mesh_transform(Mesh *me, float mat[4][4], bool do_keys)
}
}
- /* don't update normals, caller can do this explicitly */
+ /* don't update normals, caller can do this explicitly.
+ * We do update loop normals though, those may not be auto-generated (see e.g. STL import script)! */
+ if (lnors) {
+ float m3[3][3];
+
+ copy_m3_m4(m3, mat);
+ normalize_m3(m3);
+ for (i = 0; i < me->totloop; i++, lnors++) {
+ mul_m3_v3(m3, *lnors);
+ }
+ }
}
void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys)
@@ -2124,6 +2169,146 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type)
(me->mselect[me->totselect - 1].type == type));
}
+void BKE_mesh_calc_normals_split(Mesh *mesh)
+{
+ float (*r_loopnors)[3];
+ float (*polynors)[3];
+ short (*clnors)[2] = NULL;
+ bool free_polynors = false;
+
+ if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
+ r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
+ memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop);
+ }
+ else {
+ r_loopnors = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop);
+ CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+
+ /* may be NULL */
+ clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
+
+ if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
+ /* This assume that layer is always up to date, not sure this is the case (esp. in Edit mode?)... */
+ polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ free_polynors = false;
+ }
+ else {
+ polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__);
+ BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly,
+ polynors, false);
+ free_polynors = true;
+ }
+
+ BKE_mesh_normals_loop_split(
+ mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge,
+ mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly,
+ (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, NULL, clnors, NULL);
+
+ if (free_polynors) {
+ MEM_freeN(polynors);
+ }
+}
+
+/* Spli faces based on the edge angle.
+ * Matches behavior of face splitting in render engines.
+ */
+void BKE_mesh_split_faces(Mesh *mesh)
+{
+ const int num_verts = mesh->totvert;
+ const int num_edges = mesh->totedge;
+ const int num_polys = mesh->totpoly;
+ MVert *mvert = mesh->mvert;
+ MEdge *medge = mesh->medge;
+ MLoop *mloop = mesh->mloop;
+ MPoly *mpoly = mesh->mpoly;
+ float (*lnors)[3];
+ int poly, num_new_verts = 0;
+ if ((mesh->flag & ME_AUTOSMOOTH) == 0) {
+ return;
+ }
+ BKE_mesh_tessface_clear(mesh);
+ /* Compute loop normals if needed. */
+ if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
+ BKE_mesh_calc_normals_split(mesh);
+ }
+ lnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
+ /* Count. */
+ for (poly = 0; poly < num_polys; poly++) {
+ MPoly *mp = &mpoly[poly];
+ int loop;
+ for (loop = 0; loop < mp->totloop; loop++) {
+ MLoop *ml = &mloop[mp->loopstart + loop];
+ MVert *mv = &mvert[ml->v];
+ float vn[3];
+ normal_short_to_float_v3(vn, mv->no);
+ if (!equals_v3v3(vn, lnors[mp->loopstart + loop])) {
+ num_new_verts++;
+ }
+ }
+ }
+ if (num_new_verts == 0) {
+ /* No new vertices are to be added, can do early exit. */
+ return;
+ }
+ /* Actual split. */
+ mesh->totvert += num_new_verts;
+ mesh->totedge += 2 * num_new_verts;
+ mvert = mesh->mvert = MEM_reallocN(mesh->mvert,
+ sizeof(MVert) * mesh->totvert);
+ medge = mesh->medge = MEM_reallocN(mesh->medge,
+ sizeof(MEdge) * mesh->totedge);
+ CustomData_set_layer(&mesh->vdata, CD_MVERT, mesh->mvert);
+ CustomData_set_layer(&mesh->edata, CD_MEDGE, mesh->medge);
+ num_new_verts = 0;
+ for (poly = 0; poly < num_polys; poly++) {
+ MPoly *mp = &mpoly[poly];
+ int loop;
+ for (loop = 0; loop < mp->totloop; loop++) {
+ int poly_loop = mp->loopstart + loop;
+ MLoop *ml = &mloop[poly_loop];
+ MVert *mv = &mvert[ml->v];
+ float vn[3];
+ normal_short_to_float_v3(vn, mv->no);
+ if (!equals_v3v3(vn, lnors[mp->loopstart + loop])) {
+ int poly_loop_prev = mp->loopstart + (loop + mp->totloop - 1) % mp->totloop;
+ MLoop *ml_prev = &mloop[poly_loop_prev];
+ int new_edge_prev, new_edge;
+ /* Cretae new vertex. */
+ int new_vert = num_verts + num_new_verts;
+ CustomData_copy_data(&mesh->vdata, &mesh->vdata,
+ ml->v, new_vert, 1);
+ normal_float_to_short_v3(mvert[new_vert].no,
+ lnors[poly_loop]);
+ /* Create new edges. */
+ new_edge_prev = num_edges + 2 * num_new_verts;
+ new_edge = num_edges + 2 * num_new_verts + 1;
+ CustomData_copy_data(&mesh->edata, &mesh->edata,
+ ml_prev->e, new_edge_prev, 1);
+ CustomData_copy_data(&mesh->edata, &mesh->edata,
+ ml->e, new_edge, 1);
+ if (medge[new_edge_prev].v1 == ml->v) {
+ medge[new_edge_prev].v1 = new_vert;
+ }
+ else {
+ medge[new_edge_prev].v2 = new_vert;
+ }
+ if (medge[new_edge].v1 == ml->v) {
+ medge[new_edge].v1 = new_vert;
+ }
+ else {
+ medge[new_edge].v2 = new_vert;
+ }
+
+ ml->v = new_vert;
+ ml_prev->e = new_edge_prev;
+ ml->e = new_edge;
+ num_new_verts++;
+ }
+ }
+ }
+}
+
/* settings: 1 - preview, 2 - render */
Mesh *BKE_mesh_new_from_object(
Main *bmain, Scene *sce, Object *ob,
@@ -2213,8 +2398,8 @@ Mesh *BKE_mesh_new_from_object(
* only contains for_render flag. As soon as CoW is
* implemented, this is to be rethinked.
*/
- EvaluationContext eval_ctx = {0};
- eval_ctx.mode = DAG_EVAL_RENDER;
+ EvaluationContext eval_ctx;
+ DEG_evaluation_context_init(&eval_ctx, DAG_EVAL_RENDER);
BKE_displist_make_mball_forRender(&eval_ctx, sce, ob, &disp);
BKE_mesh_from_metaball(&disp, tmpmesh);
BKE_displist_free(&disp);
@@ -2339,3 +2524,75 @@ Mesh *BKE_mesh_new_from_object(
return tmpmesh;
}
+/* settings: 1 - preview, 2 - render */
+Mesh *BKE_mesh_new_from_dupli_data(
+ Main *bmain, DupliObjectData *data,
+ bool calc_tessface, bool calc_undeformed)
+{
+ Object *ob = data->ob;
+ DerivedMesh *dm = data->dm;
+ CustomDataMask mask;
+
+ Mesh *tmpmesh;
+
+ if (!ob || !dm)
+ return NULL;
+
+ mask = CD_MASK_MESH; /* this seems more suitable, exporter,
+ * for example, needs CD_MASK_MDEFORMVERT */
+ if (calc_undeformed)
+ mask |= CD_MASK_ORCO;
+
+ tmpmesh = BKE_mesh_add(bmain, "Mesh");
+ DM_to_mesh(dm, tmpmesh, ob, mask, true);
+
+ /* BKE_mesh_add/copy gives us a user count we don't need */
+ tmpmesh->id.us--;
+
+ /* Copy materials to new mesh */
+ switch (ob->type) {
+ case OB_MESH: {
+ Mesh *origmesh = ob->data;
+ int i;
+
+ tmpmesh->flag = origmesh->flag;
+ tmpmesh->mat = MEM_dupallocN(origmesh->mat);
+ tmpmesh->totcol = origmesh->totcol;
+ tmpmesh->smoothresh = origmesh->smoothresh;
+ if (origmesh->mat) {
+ for (i = origmesh->totcol; i-- > 0; ) {
+ /* are we an object material or data based? */
+ tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : origmesh->mat[i];
+
+ if (tmpmesh->mat[i]) {
+ tmpmesh->mat[i]->id.us++;
+ }
+ }
+ }
+ break;
+ }
+ } /* end copy materials */
+
+ if (calc_tessface) {
+ /* cycles and exporters rely on this still */
+ BKE_mesh_tessface_ensure(tmpmesh);
+ }
+
+ /* make sure materials get updated in objects */
+ test_object_materials(bmain, &tmpmesh->id);
+
+ return tmpmesh;
+}
+
+/* **** Depsgraph evaluation **** */
+
+void BKE_mesh_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+ Mesh *mesh)
+{
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s on %s\n", __func__, mesh->id.name);
+ }
+ if (mesh->bb == NULL || (mesh->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_mesh_texspace_calc(mesh);
+ }
+}
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 40a09eba658..d17ca751c5e 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -226,7 +226,7 @@ void BKE_mesh_calc_normals_poly(MVert *mverts, int numVerts, MLoop *mloop, MPoly
MPoly *mp;
if (only_face_normals) {
- BLI_assert(pnors != NULL);
+ BLI_assert((pnors != NULL) || (numPolys == 0));
#pragma omp parallel for if (numPolys > BKE_MESH_OMP_LIMIT)
for (i = 0; i < numPolys; i++) {
@@ -252,12 +252,12 @@ void BKE_mesh_calc_normals_poly(MVert *mverts, int numVerts, MLoop *mloop, MPoly
}
}
- /* following Mesh convention; we use vertex coordinate itself for normal in this case */
for (i = 0; i < numVerts; i++) {
MVert *mv = &mverts[i];
float *no = tnorms[i];
if (UNLIKELY(normalize_v3(no) == 0.0f)) {
+ /* following Mesh convention; we use vertex coordinate itself for normal in this case */
normalize_v3_v3(no, mv->co);
}
@@ -372,6 +372,10 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, const float lnor[3],
/* If vec_ref or vec_other are too much aligned with lnor, we can't build lnor space,
* tag it as invalid and abort. */
lnor_space->ref_alpha = lnor_space->ref_beta = 0.0f;
+
+ if (edge_vectors) {
+ BLI_stack_clear(edge_vectors);
+ }
return;
}
@@ -387,7 +391,9 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, const float lnor[3],
BLI_stack_discard(edge_vectors);
nbr++;
}
- BLI_assert(nbr > 2); /* This piece of code shall only be called for more than one loop... */
+ /* Note: In theory, this could be 'nbr > 2', but there is one case where we only have two edges for
+ * two loops: a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.). */
+ BLI_assert(nbr >= 2); /* This piece of code shall only be called for more than one loop... */
lnor_space->ref_alpha = alpha / (float)nbr;
}
else {
@@ -1347,6 +1353,10 @@ static void mesh_normals_loop_custom_set(
const int nidx = lidx;
float *nor = custom_loopnors[nidx];
+ if (is_zero_v3(nor)) {
+ nor = lnors[nidx];
+ }
+
if (!org_nor) {
org_nor = nor;
}
@@ -1406,6 +1416,10 @@ static void mesh_normals_loop_custom_set(
const int nidx = use_vertices ? (int)mloops[lidx].v : lidx;
float *nor = custom_loopnors[nidx];
+ if (is_zero_v3(nor)) {
+ nor = lnors[nidx];
+ }
+
nbr_nors++;
add_v3_v3(avg_nor, nor);
BLI_SMALLSTACK_PUSH(clnors_data, (short *)r_clnors_data[lidx]);
@@ -2243,12 +2257,15 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData
/**
* Recreate tessellation.
*
- * \param do_face_nor_copy controls whether the normals from the poly are copied to the tessellated faces.
+ * \param do_face_nor_copy: Controls whether the normals from the poly are copied to the tessellated faces.
*
* \return number of tessellation faces.
*/
-int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomData *pdata,
- MVert *mvert, int totface, int totloop, int totpoly, const bool do_face_nor_cpy)
+int BKE_mesh_recalc_tessellation(
+ CustomData *fdata, CustomData *ldata, CustomData *pdata,
+ MVert *mvert,
+ int totface, int totloop, int totpoly,
+ const bool do_face_nor_copy)
{
/* use this to avoid locking pthread for _every_ polygon
* and calling the fill function */
@@ -2458,7 +2475,7 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomDat
CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface);
CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
- if (do_face_nor_cpy) {
+ if (do_face_nor_copy) {
/* If polys have a normals layer, copying that to faces can help
* avoid the need to recalculate normals later */
if (CustomData_has_layer(pdata, CD_NORMAL)) {
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index 8d9fbe46f19..8b41aded3d9 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -30,7 +30,9 @@
#include "MEM_guardedalloc.h"
#include "DNA_meshdata_types.h"
+#include "DNA_vec_types.h"
+#include "BLI_buffer.h"
#include "BLI_utildefines.h"
#include "BLI_bitmap.h"
#include "BLI_math.h"
@@ -52,8 +54,10 @@
/* this replaces the non bmesh function (in trunk) which takes MTFace's, if we ever need it back we could
* but for now this replaces it because its unused. */
-UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv,
- unsigned int totpoly, unsigned int totvert, int selected, float *limit)
+UvVertMap *BKE_mesh_uv_vert_map_create(
+ struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv,
+ unsigned int totpoly, unsigned int totvert,
+ const float limit[2], const bool selected, const bool use_winding)
{
UvVertMap *vmap;
UvMapVert *buf;
@@ -61,6 +65,9 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop,
unsigned int a;
int i, totuv, nverts;
+ bool *winding;
+ BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, 32);
+
totuv = 0;
/* generate UvMapVert array */
@@ -72,7 +79,9 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop,
if (totuv == 0)
return NULL;
+ winding = MEM_callocN(sizeof(*winding) * totpoly, "winding");
vmap = (UvVertMap *)MEM_callocN(sizeof(*vmap), "UvVertMap");
+
if (!vmap)
return NULL;
@@ -87,6 +96,8 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop,
mp = mpoly;
for (a = 0; a < totpoly; a++, mp++) {
if (!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) {
+ float (*tf_uv)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, mp->totloop);
+
nverts = mp->totloop;
for (i = 0; i < nverts; i++) {
@@ -95,8 +106,15 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop,
buf->separate = 0;
buf->next = vmap->vert[mloop[mp->loopstart + i].v];
vmap->vert[mloop[mp->loopstart + i].v] = buf;
+
+ copy_v2_v2(tf_uv[i], mloopuv[mpoly[a].loopstart + i].uv);
buf++;
}
+
+ if (use_winding)
+ winding[a] = cross_poly_v2((const float (*)[2])tf_uv, (unsigned int)nverts) > 0;
+ else
+ winding[a] = 0;
}
}
@@ -123,7 +141,9 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop,
sub_v2_v2v2(uvdiff, uv2, uv);
- if (fabsf(uv[0] - uv2[0]) < limit[0] && fabsf(uv[1] - uv2[1]) < limit[1]) {
+ if (fabsf(uv[0] - uv2[0]) < limit[0] && fabsf(uv[1] - uv2[1]) < limit[1] &&
+ winding[iterv->f] == winding[v->f])
+ {
if (lastv) lastv->next = next;
else vlist = next;
iterv->next = newvlist;
@@ -141,6 +161,9 @@ UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop,
vmap->vert[a] = newvlist;
}
+ MEM_freeN(winding);
+ BLI_buffer_free(&tf_uv_buf);
+
return vmap;
}
@@ -159,8 +182,6 @@ void BKE_mesh_uv_vert_map_free(UvVertMap *vmap)
}
/**
-
-
* Generates a map where the key is the vertex and the value is a list
* of polys or loops that use that vertex as a corner. The lists are allocated
* from one memory pool.
@@ -233,9 +254,10 @@ void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map, int **r_mem,
mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, true);
}
-/* Generates a map where the key is the vertex and the value is a list
- * of edges that use that vertex as an endpoint. The lists are allocated
- * from one memory pool. */
+/**
+ * Generates a map where the key is the vertex and the value is a list of edges that use that vertex as an endpoint.
+ * The lists are allocated from one memory pool.
+ */
void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map, int **r_mem,
const MEdge *medge, int totvert, int totedge)
{
@@ -275,6 +297,10 @@ void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map, int **r_mem,
*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.
+ */
void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map, int **r_mem,
const MEdge *UNUSED(medge), const int totedge,
const MPoly *mpoly, const int totpoly,
@@ -382,7 +408,8 @@ void BKE_mesh_origindex_map_create(MeshElemMap **r_map, int **r_mem,
* Used currently for UVs and 'smooth groups'.
* \{ */
-/** Callback deciding whether the given poly/loop/edge define an island boundary or not.
+/**
+ * Callback deciding whether the given poly/loop/edge define an island boundary or not.
*/
typedef bool (*MeshRemap_CheckIslandBoundary)(
const struct MPoly *mpoly, const struct MLoop *mloop, const struct MEdge *medge,
@@ -565,8 +592,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)
{
/* 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));
@@ -663,7 +689,6 @@ void BKE_mesh_loop_islands_add(
const size_t curr_num_islands = (size_t)island_store->islands_num;
int i = item_num;
- island_store->items_to_islands_num = item_num;
while (i--) {
island_store->items_to_islands[items_indices[i]] = curr_island_idx;
}
@@ -698,17 +723,21 @@ void BKE_mesh_loop_islands_add(
* not sure we want that at all!
*/
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 *UNUSED(ml), const MEdge *me, const int UNUSED(nbr_egde_users))
{
/* Edge is UV boundary if tagged as seam. */
return (me->flag & ME_SEAM) != 0;
}
/**
- * \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...
+ * 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(
MVert *UNUSED(verts), const int UNUSED(totvert),
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index aca72614094..0ed10687fae 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -707,7 +707,7 @@ void BKE_mesh_remap_calc_edges_from_dm(
BLI_space_transform_apply_normal(space_transform, v2_no);
}
- fill_vn_fl(weights, (int)numedges_src, 0.0f);
+ copy_vn_fl(weights, (int)numedges_src, 0.0f);
/* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast),
* with lower/upper bounds. */
@@ -977,6 +977,8 @@ void BKE_mesh_remap_calc_loops_from_dm(
float (*poly_nors_dst)[3] = NULL;
float (*loop_nors_dst)[3] = NULL;
+ float (*poly_cents_src)[3] = NULL;
+
MeshElemMap *vert_to_loop_map_src = NULL;
int *vert_to_loop_map_src_buff = NULL;
MeshElemMap *vert_to_poly_map_src = NULL;
@@ -1012,6 +1014,8 @@ void BKE_mesh_remap_calc_loops_from_dm(
int *indices_interp = NULL;
float *weights_interp = NULL;
+ MLoop *ml_src, *ml_dst;
+ MPoly *mp_src, *mp_dst;
int tindex, pidx_dst, lidx_dst, plidx_dst, pidx_src, lidx_src, plidx_src;
IslandResult **islands_res;
@@ -1089,11 +1093,13 @@ void BKE_mesh_remap_calc_loops_from_dm(
edges_src, num_edges_src, polys_src, num_polys_src, loops_src, num_loops_src);
if (use_from_vert) {
loop_to_poly_map_src = MEM_mallocN(sizeof(*loop_to_poly_map_src) * (size_t)num_loops_src, __func__);
- for (pidx_src = 0; pidx_src < num_polys_src; pidx_src++) {
- MPoly *mp = &polys_src[pidx_src];
- for (plidx_src = 0, lidx_src = mp->loopstart; plidx_src < mp->totloop; plidx_src++, lidx_src++) {
+ poly_cents_src = MEM_mallocN(sizeof(*poly_cents_src) * (size_t)num_polys_src, __func__);
+ for (pidx_src = 0, mp_src = polys_src; pidx_src < num_polys_src; pidx_src++, mp_src++) {
+ ml_src = &loops_src[mp_src->loopstart];
+ for (plidx_src = 0, lidx_src = mp_src->loopstart; plidx_src < mp_src->totloop; plidx_src++, lidx_src++) {
loop_to_poly_map_src[lidx_src] = pidx_src;
}
+ BKE_mesh_calc_poly_center(mp_src, ml_src, verts_src, poly_cents_src[pidx_src]);
}
}
@@ -1155,10 +1161,13 @@ void BKE_mesh_remap_calc_loops_from_dm(
int num_verts_active = 0;
BLI_BITMAP_SET_ALL(verts_active, false, (size_t)num_verts_src);
for (i = 0; i < isld->count; i++) {
- MPoly *mp_src = &polys_src[isld->indices[i]];
+ mp_src = &polys_src[isld->indices[i]];
for (lidx_src = mp_src->loopstart; lidx_src < mp_src->loopstart + mp_src->totloop; lidx_src++) {
- BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v);
- num_verts_active++;
+ const unsigned int vidx_src = loops_src[lidx_src].v;
+ if (!BLI_BITMAP_TEST(verts_active, vidx_src)) {
+ BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v);
+ num_verts_active++;
+ }
}
}
/* verts 'ownership' is transfered to treedata here, which will handle its freeing. */
@@ -1199,13 +1208,13 @@ void BKE_mesh_remap_calc_loops_from_dm(
int num_faces_active = 0;
BLI_BITMAP_SET_ALL(faces_active, false, (size_t)num_faces_src);
for (i = 0; i < num_faces_src; i++) {
- MPoly *mp_src = &polys_src[tessface_to_poly_map_src[i]];
+ mp_src = &polys_src[tessface_to_poly_map_src[i]];
if (island_store.items_to_islands[mp_src->loopstart] == tindex) {
BLI_BITMAP_ENABLE(faces_active, i);
num_faces_active++;
}
}
- /* verts 'ownership' is transfered to treedata here, which will handle its freeing. */
+ /* verts and faces 'ownership' is transfered to treedata here, which will handle its freeing. */
bvhtree_from_mesh_faces_ex(
&treedata[tindex], verts_src, verts_allocated_src,
faces_src, num_faces_src, faces_allocated_src,
@@ -1233,10 +1242,14 @@ void BKE_mesh_remap_calc_loops_from_dm(
islands_res[tindex] = MEM_mallocN(sizeof(**islands_res) * islands_res_buff_size, __func__);
}
- for (pidx_dst = 0; pidx_dst < numpolys_dst; pidx_dst++) {
- MPoly *mp_dst = &polys_dst[pidx_dst];
+ for (pidx_dst = 0, mp_dst = polys_dst; pidx_dst < numpolys_dst; pidx_dst++, mp_dst++) {
float (*pnor_dst)[3] = &poly_nors_dst[pidx_dst];
+ /* Only in use_from_vert case, we may need polys' centers as fallback in case we cannot decide which
+ * corner to use from normals only. */
+ float pcent_dst[3];
+ bool pcent_dst_valid = false;
+
if ((size_t)mp_dst->totloop > islands_res_buff_size) {
islands_res_buff_size = (size_t)mp_dst->totloop;
for (tindex = 0; tindex < num_trees; tindex++) {
@@ -1246,8 +1259,8 @@ void BKE_mesh_remap_calc_loops_from_dm(
for (tindex = 0; tindex < num_trees; tindex++) {
BVHTreeFromMesh *tdata = &treedata[tindex];
- MLoop *ml_dst = &loops_dst[mp_dst->loopstart];
+ ml_dst = &loops_dst[mp_dst->loopstart];
for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++, ml_dst++) {
if (use_from_vert) {
float tmp_co[3];
@@ -1263,6 +1276,7 @@ void BKE_mesh_remap_calc_loops_from_dm(
float (*nor_dst)[3];
float (*nors_src)[3];
float best_nor_dot = -2.0f;
+ float best_sqdist_fallback = FLT_MAX;
int best_index_src = -1;
if (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) {
@@ -1279,16 +1293,50 @@ void BKE_mesh_remap_calc_loops_from_dm(
for (i = vert_to_refelem_map_src[nearest.index].count; i--;) {
const int index_src = vert_to_refelem_map_src[nearest.index].indices[i];
const float dot = dot_v3v3(nors_src[index_src], *nor_dst);
- if (dot > best_nor_dot) {
- best_nor_dot = dot;
- best_index_src = index_src;
+
+ pidx_src = (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ?
+ loop_to_poly_map_src[index_src] : index_src;
+ /* WARNING! This is not the *real* lidx_src in case of POLYNOR, we only use it
+ * to check we stay on current island (all loops from a given poly are
+ * on same island!). */
+ lidx_src = (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ?
+ index_src : polys_src[pidx_src].loopstart;
+
+ /* A same vert may be at the boundary of several islands! Hence, we have to ensure
+ * poly/loop we are currently considering *belongs* to current island! */
+ if (use_islands && island_store.items_to_islands[lidx_src] != tindex) {
+ continue;
+ }
+
+ if (dot > best_nor_dot - 1e-6f) {
+ /* We need something as fallback decision in case dest normal matches several
+ * source normals (see T44522), using distance between polys' centers here. */
+ float *pcent_src;
+ float sqdist;
+
+ mp_src = &polys_src[pidx_src];
+ ml_src = &loops_src[mp_src->loopstart];
+
+ if (!pcent_dst_valid) {
+ BKE_mesh_calc_poly_center(
+ mp_dst, &loops_dst[mp_dst->loopstart], verts_dst, pcent_dst);
+ pcent_dst_valid = true;
+ }
+ pcent_src = poly_cents_src[pidx_src];
+ sqdist = len_squared_v3v3(pcent_dst, pcent_src);
+
+ if ((dot > best_nor_dot + 1e-6f) || (sqdist < best_sqdist_fallback)) {
+ best_nor_dot = dot;
+ best_sqdist_fallback = sqdist;
+ best_index_src = index_src;
+ }
}
}
if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) {
/* Our best_index_src is a poly one for now!
* Have to find its loop matching our closest vertex. */
- MPoly *mp_src = &polys_src[best_index_src];
- MLoop *ml_src = &loops_src[mp_src->loopstart];
+ mp_src = &polys_src[best_index_src];
+ ml_src = &loops_src[mp_src->loopstart];
for (plidx_src = 0; plidx_src < mp_src->totloop; plidx_src++, ml_src++) {
if ((int)ml_src->v == nearest.index) {
best_index_src = plidx_src + mp_src->loopstart;
@@ -1296,7 +1344,8 @@ void BKE_mesh_remap_calc_loops_from_dm(
}
}
}
- islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / (hit_dist * best_nor_dot)) : 1e18f;
+ best_nor_dot = (best_nor_dot + 1.0f) * 0.5f;
+ islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / hit_dist * best_nor_dot) : 1e18f;
islands_res[tindex][plidx_dst].hit_dist = hit_dist;
islands_res[tindex][plidx_dst].index_src = best_index_src;
}
@@ -1488,12 +1537,11 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (last_valid_pidx_isld_src != -1) {
/* Find a new valid loop in that new poly (nearest one for now).
* Note we could be much more subtle here, again that's for later... */
- MPoly *mp_src;
- MLoop *ml_src, *ml_dst = &loops_dst[lidx_dst];
int j;
float best_dist_sq = FLT_MAX;
float tmp_co[3];
+ ml_dst = &loops_dst[lidx_dst];
copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
/* We do our transform here, since we may do several raycast/nearest queries. */
@@ -1532,10 +1580,10 @@ void BKE_mesh_remap_calc_loops_from_dm(
/* Else, we use source poly, indices stored in islands_res are those of polygons. */
pidx_src = isld_res->index_src;
if (pidx_src >= 0) {
- MPoly *mp_src = &polys_src[pidx_src];
float *hit_co = isld_res->hit_point;
int best_loop_index_src;
+ mp_src = &polys_src[pidx_src];
/* If prev and curr poly are the same, no need to do anything more!!! */
if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) {
int pidx_isld_src, pidx_isld_src_prev;
@@ -1575,11 +1623,11 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (last_valid_pidx_isld_src != -1) {
/* Find a new valid loop in that new poly (nearest point on poly for now).
* Note we could be much more subtle here, again that's for later... */
- MLoop *ml_dst = &loops_dst[lidx_dst];
float best_dist_sq = FLT_MAX;
float tmp_co[3];
int j;
+ ml_dst = &loops_dst[lidx_dst];
copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
/* We do our transform here, since we may do several raycast/nearest queries. */
@@ -1710,6 +1758,9 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (loop_to_poly_map_src) {
MEM_freeN(loop_to_poly_map_src);
}
+ if (poly_cents_src) {
+ MEM_freeN(poly_cents_src);
+ }
if (vcos_interp) {
MEM_freeN(vcos_interp);
}
@@ -1865,7 +1916,7 @@ void BKE_mesh_remap_calc_polys_from_dm(
BLI_space_transform_apply_normal(space_transform, tmp_no);
}
- fill_vn_fl(weights, (int)numpolys_src, 0.0f);
+ copy_vn_fl(weights, (int)numpolys_src, 0.0f);
if (UNLIKELY((size_t)mp->totloop > tmp_poly_size)) {
tmp_poly_size = (size_t)mp->totloop;
diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c
new file mode 100644
index 00000000000..b1a89ec64fc
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_sample.c
@@ -0,0 +1,381 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/mesh_sample.c
+ * \ingroup bke
+ *
+ * Sample a mesh surface or volume and evaluate samples on deformed meshes.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_rand.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_mesh_sample.h"
+#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
+
+#include "BLI_strict_flags.h"
+
+/* ==== Evaluate ==== */
+
+bool BKE_mesh_sample_eval(DerivedMesh *dm, const MSurfaceSample *sample, float loc[3], float nor[3], float tang[3])
+{
+ MVert *mverts = dm->getVertArray(dm);
+ unsigned int totverts = (unsigned int)dm->getNumVerts(dm);
+ MVert *v1, *v2, *v3;
+
+ zero_v3(loc);
+ zero_v3(nor);
+ zero_v3(tang);
+
+ if (sample->orig_verts[0] >= totverts ||
+ sample->orig_verts[1] >= totverts ||
+ sample->orig_verts[2] >= totverts)
+ return false;
+
+ v1 = &mverts[sample->orig_verts[0]];
+ v2 = &mverts[sample->orig_verts[1]];
+ v3 = &mverts[sample->orig_verts[2]];
+
+ { /* location */
+ madd_v3_v3fl(loc, v1->co, sample->orig_weights[0]);
+ madd_v3_v3fl(loc, v2->co, sample->orig_weights[1]);
+ madd_v3_v3fl(loc, v3->co, sample->orig_weights[2]);
+ }
+
+ { /* normal */
+ float vnor[3];
+
+ normal_short_to_float_v3(vnor, v1->no);
+ madd_v3_v3fl(nor, vnor, sample->orig_weights[0]);
+ normal_short_to_float_v3(vnor, v2->no);
+ madd_v3_v3fl(nor, vnor, sample->orig_weights[1]);
+ normal_short_to_float_v3(vnor, v3->no);
+ madd_v3_v3fl(nor, vnor, sample->orig_weights[2]);
+
+ normalize_v3(nor);
+ }
+
+ { /* tangent */
+ float edge[3];
+
+ /* XXX simply using the v1-v2 edge as a tangent vector for now ...
+ * Eventually mikktspace generated tangents (CD_TANGENT tessface layer)
+ * should be used for consistency, but requires well-defined tessface
+ * indices for the mesh surface samples.
+ */
+
+ sub_v3_v3v3(edge, v2->co, v1->co);
+ /* make edge orthogonal to nor */
+ madd_v3_v3fl(edge, nor, -dot_v3v3(edge, nor));
+ normalize_v3_v3(tang, edge);
+ }
+
+ return true;
+}
+
+bool BKE_mesh_sample_shapekey(Key *key, KeyBlock *kb, const MSurfaceSample *sample, float loc[3])
+{
+ float *v1, *v2, *v3;
+
+ (void)key; /* Unused in release builds. */
+
+ BLI_assert(key->elemsize == 3 * sizeof(float));
+ BLI_assert(sample->orig_verts[0] < (unsigned int)kb->totelem);
+ BLI_assert(sample->orig_verts[1] < (unsigned int)kb->totelem);
+ BLI_assert(sample->orig_verts[2] < (unsigned int)kb->totelem);
+
+ v1 = (float *)kb->data + sample->orig_verts[0] * 3;
+ v2 = (float *)kb->data + sample->orig_verts[1] * 3;
+ v3 = (float *)kb->data + sample->orig_verts[2] * 3;
+
+ zero_v3(loc);
+ madd_v3_v3fl(loc, v1, sample->orig_weights[0]);
+ madd_v3_v3fl(loc, v2, sample->orig_weights[1]);
+ madd_v3_v3fl(loc, v3, sample->orig_weights[2]);
+
+ /* TODO use optional vgroup weights to determine if a shapeky actually affects the sample */
+ return true;
+}
+
+
+/* ==== Sampling Utilities ==== */
+
+BLI_INLINE void mesh_sample_weights_from_loc(MSurfaceSample *sample, DerivedMesh *dm, int face_index, const float loc[3])
+{
+ MFace *face = &dm->getTessFaceArray(dm)[face_index];
+ unsigned int index[4] = { face->v1, face->v2, face->v3, face->v4 };
+ MVert *mverts = dm->getVertArray(dm);
+
+ float *v1 = mverts[face->v1].co;
+ float *v2 = mverts[face->v2].co;
+ float *v3 = mverts[face->v3].co;
+ float *v4 = face->v4 ? mverts[face->v4].co : NULL;
+ float w[4];
+ int tri[3];
+
+ interp_weights_face_v3_index(tri, w, v1, v2, v3, v4, loc);
+
+ sample->orig_verts[0] = index[tri[0]];
+ sample->orig_verts[1] = index[tri[1]];
+ sample->orig_verts[2] = index[tri[2]];
+ sample->orig_weights[0] = w[tri[0]];
+ sample->orig_weights[1] = w[tri[1]];
+ sample->orig_weights[2] = w[tri[2]];
+}
+
+/* ==== Sampling ==== */
+
+static bool mesh_sample_store_array_sample(void *vdata, int capacity, int index, const MSurfaceSample *sample)
+{
+ MSurfaceSample *data = vdata;
+ if (index >= capacity)
+ return false;
+
+ data[index] = *sample;
+ return true;
+}
+
+void BKE_mesh_sample_storage_single(MSurfaceSampleStorage *storage, MSurfaceSample *sample)
+{
+ /* handled as just a special array case with capacity = 1 */
+ storage->store_sample = mesh_sample_store_array_sample;
+ storage->capacity = 1;
+ storage->data = sample;
+ storage->free_data = false;
+}
+
+void BKE_mesh_sample_storage_array(MSurfaceSampleStorage *storage, MSurfaceSample *samples, int capacity)
+{
+ storage->store_sample = mesh_sample_store_array_sample;
+ storage->capacity = capacity;
+ storage->data = samples;
+ storage->free_data = false;
+}
+
+void BKE_mesh_sample_storage_release(MSurfaceSampleStorage *storage)
+{
+ if (storage->free_data)
+ MEM_freeN(storage->data);
+}
+
+
+int BKE_mesh_sample_generate_random(MSurfaceSampleStorage *dst, DerivedMesh *dm, unsigned int seed, int totsample)
+{
+ MFace *mfaces;
+ int totfaces;
+ RNG *rng;
+ MFace *mface;
+ float a, b;
+ int i, stored = 0;
+
+ rng = BLI_rng_new(seed);
+
+ DM_ensure_tessface(dm);
+ mfaces = dm->getTessFaceArray(dm);
+ totfaces = dm->getNumTessFaces(dm);
+
+ for (i = 0; i < totsample; ++i) {
+ MSurfaceSample sample = {{0}};
+
+ mface = &mfaces[BLI_rng_get_int(rng) % totfaces];
+
+ if (mface->v4 && BLI_rng_get_int(rng) % 2 == 0) {
+ sample.orig_verts[0] = mface->v3;
+ sample.orig_verts[1] = mface->v4;
+ sample.orig_verts[2] = mface->v1;
+ }
+ else {
+ sample.orig_verts[0] = mface->v1;
+ sample.orig_verts[1] = mface->v2;
+ sample.orig_verts[2] = mface->v3;
+ }
+
+ a = BLI_rng_get_float(rng);
+ b = BLI_rng_get_float(rng);
+ if (a + b > 1.0f) {
+ a = 1.0f - a;
+ b = 1.0f - b;
+ }
+ sample.orig_weights[0] = 1.0f - (a + b);
+ sample.orig_weights[1] = a;
+ sample.orig_weights[2] = b;
+
+ if (dst->store_sample(dst->data, dst->capacity, i, &sample))
+ ++stored;
+ else
+ break;
+ }
+
+ BLI_rng_free(rng);
+
+ return stored;
+}
+
+
+static bool sample_bvh_raycast(MSurfaceSample *sample, DerivedMesh *dm, BVHTreeFromMesh *bvhdata, const float ray_start[3], const float ray_end[3])
+{
+ BVHTreeRayHit hit;
+ float ray_normal[3], dist;
+
+ sub_v3_v3v3(ray_normal, ray_end, ray_start);
+ dist = normalize_v3(ray_normal);
+
+ hit.index = -1;
+ hit.dist = dist;
+
+ if (BLI_bvhtree_ray_cast(bvhdata->tree, ray_start, ray_normal, 0.0f,
+ &hit, bvhdata->raycast_callback, bvhdata) >= 0) {
+
+ mesh_sample_weights_from_loc(sample, dm, hit.index, hit.co);
+
+ return true;
+ }
+ else
+ return false;
+}
+
+int BKE_mesh_sample_generate_raycast(MSurfaceSampleStorage *dst, DerivedMesh *dm, MeshSampleRayCallback ray_cb, void *userdata, int totsample)
+{
+ BVHTreeFromMesh bvhdata;
+ float ray_start[3], ray_end[3];
+ int i, stored = 0;
+
+ DM_ensure_tessface(dm);
+
+ memset(&bvhdata, 0, sizeof(BVHTreeFromMesh));
+ bvhtree_from_mesh_faces(&bvhdata, dm, 0.0f, 4, 6);
+
+ if (bvhdata.tree) {
+ for (i = 0; i < totsample; ++i) {
+ if (ray_cb(userdata, ray_start, ray_end)) {
+ MSurfaceSample sample;
+ if (sample_bvh_raycast(&sample, dm, &bvhdata, ray_start, ray_end)) {
+ if (dst->store_sample(dst->data, dst->capacity, i, &sample))
+ ++stored;
+ else
+ break;
+ }
+ }
+ }
+ }
+
+ free_bvhtree_from_mesh(&bvhdata);
+
+ return stored;
+}
+
+/* ==== Utilities ==== */
+
+#include "DNA_particle_types.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_particle.h"
+
+bool BKE_mesh_sample_from_particle(MSurfaceSample *sample, ParticleSystem *psys, DerivedMesh *dm, ParticleData *pa)
+{
+ MVert *mverts;
+ MFace *mface;
+ float mapfw[4];
+ int mapindex;
+ float *co1 = NULL, *co2 = NULL, *co3 = NULL, *co4 = NULL;
+ float vec[3];
+ float w[4];
+
+ if (!psys_get_index_on_dm(psys, dm, pa, &mapindex, mapfw))
+ return false;
+
+ mface = dm->getTessFaceData(dm, mapindex, CD_MFACE);
+ mverts = dm->getVertDataArray(dm, CD_MVERT);
+
+ co1 = mverts[mface->v1].co;
+ co2 = mverts[mface->v2].co;
+ co3 = mverts[mface->v3].co;
+
+ if (mface->v4) {
+ co4 = mverts[mface->v4].co;
+
+ interp_v3_v3v3v3v3(vec, co1, co2, co3, co4, mapfw);
+ }
+ else {
+ interp_v3_v3v3v3(vec, co1, co2, co3, mapfw);
+ }
+
+ /* test both triangles of the face */
+ interp_weights_face_v3(w, co1, co2, co3, NULL, vec);
+ if (w[0] <= 1.0f && w[1] <= 1.0f && w[2] <= 1.0f) {
+ sample->orig_verts[0] = mface->v1;
+ sample->orig_verts[1] = mface->v2;
+ sample->orig_verts[2] = mface->v3;
+
+ copy_v3_v3(sample->orig_weights, w);
+ return true;
+ }
+ else if (mface->v4) {
+ interp_weights_face_v3(w, co3, co4, co1, NULL, vec);
+ sample->orig_verts[0] = mface->v3;
+ sample->orig_verts[1] = mface->v4;
+ sample->orig_verts[2] = mface->v1;
+
+ copy_v3_v3(sample->orig_weights, w);
+ return true;
+ }
+ else
+ return false;
+}
+
+bool BKE_mesh_sample_to_particle(MSurfaceSample *sample, ParticleSystem *UNUSED(psys), DerivedMesh *dm, BVHTreeFromMesh *bvhtree, ParticleData *pa)
+{
+ BVHTreeNearest nearest;
+ float vec[3], nor[3], tang[3];
+
+ BKE_mesh_sample_eval(dm, sample, vec, nor, tang);
+
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ BLI_bvhtree_find_nearest(bvhtree->tree, vec, &nearest, bvhtree->nearest_callback, bvhtree);
+ if (nearest.index >= 0) {
+ MFace *mface = dm->getTessFaceData(dm, nearest.index, CD_MFACE);
+ MVert *mverts = dm->getVertDataArray(dm, CD_MVERT);
+
+ float *co1 = mverts[mface->v1].co;
+ float *co2 = mverts[mface->v2].co;
+ float *co3 = mverts[mface->v3].co;
+ float *co4 = mface->v4 ? mverts[mface->v4].co : NULL;
+
+ pa->num = nearest.index;
+ pa->num_dmcache = DMCACHE_NOTFOUND;
+
+ interp_weights_face_v3(pa->fuv, co1, co2, co3, co4, vec);
+ pa->foffset = 0.0f; /* XXX any sensible way to reconstruct this? */
+
+ return true;
+ }
+ else
+ return false;
+}
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 7de993e1099..f758bcdf2f5 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -1475,8 +1475,9 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool update, const bool select)
int j, v_prev = (l + (mp->totloop - 1))->v;
for (j = 0; j < mp->totloop; j++, l++) {
if (v_prev != l->v) {
- if (!BLI_edgehash_haskey(eh, v_prev, l->v)) {
- BLI_edgehash_insert(eh, v_prev, l->v, NULL);
+ void **val_p;
+ if (!BLI_edgehash_ensure_p(eh, v_prev, l->v, &val_p)) {
+ *val_p = NULL;
}
}
v_prev = l->v;
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 42247d866e4..4d007e12ef5 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -57,6 +57,7 @@
#include "BLF_translation.h"
#include "BKE_appdir.h"
+#include "BKE_cache_library.h"
#include "BKE_key.h"
#include "BKE_multires.h"
#include "BKE_DerivedMesh.h"
@@ -68,7 +69,7 @@
#include "MOD_modifiertypes.h"
-static ModifierTypeInfo *modifier_types[NUM_MODIFIER_TYPES] = {NULL};
+static ModifierTypeInfo *cache_modifier_types[NUM_MODIFIER_TYPES] = {NULL};
static VirtualModifierData virtualModifierCommonData;
void BKE_modifier_init(void)
@@ -76,7 +77,7 @@ void BKE_modifier_init(void)
ModifierData *md;
/* Initialize modifier types */
- modifier_type_init(modifier_types); /* MOD_utils.c */
+ modifier_type_init(cache_modifier_types); /* MOD_utils.c */
/* Initialize global cmmon storage used for virtual modifier list */
md = modifier_new(eModifierType_Armature);
@@ -99,13 +100,15 @@ void BKE_modifier_init(void)
virtualModifierCommonData.cmd.modifier.mode |= eModifierMode_Virtual;
virtualModifierCommonData.lmd.modifier.mode |= eModifierMode_Virtual;
virtualModifierCommonData.smd.modifier.mode |= eModifierMode_Virtual;
+
+ BKE_cache_modifier_init();
}
-ModifierTypeInfo *modifierType_getInfo(ModifierType type)
+const ModifierTypeInfo *modifierType_getInfo(ModifierType type)
{
/* type unsigned, no need to check < 0 */
- if (type < NUM_MODIFIER_TYPES && modifier_types[type]->name[0] != '\0') {
- return modifier_types[type];
+ if (type < NUM_MODIFIER_TYPES && cache_modifier_types[type]->name[0] != '\0') {
+ return cache_modifier_types[type];
}
else {
return NULL;
@@ -116,7 +119,7 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type)
ModifierData *modifier_new(int type)
{
- ModifierTypeInfo *mti = modifierType_getInfo(type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(type);
ModifierData *md = MEM_callocN(mti->structSize, mti->structName);
/* note, this name must be made unique later */
@@ -135,7 +138,7 @@ ModifierData *modifier_new(int type)
void modifier_free(ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti->freeData) mti->freeData(md);
if (md->error) MEM_freeN(md->error);
@@ -146,7 +149,7 @@ void modifier_free(ModifierData *md)
bool modifier_unique_name(ListBase *modifiers, ModifierData *md)
{
if (modifiers && md) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
return BLI_uniquename(modifiers, md, DATA_(mti->name), '.', offsetof(ModifierData, name), sizeof(md->name));
}
@@ -155,14 +158,14 @@ bool modifier_unique_name(ListBase *modifiers, ModifierData *md)
bool modifier_dependsOnTime(ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
return mti->dependsOnTime && mti->dependsOnTime(md);
}
bool modifier_supportsMapping(ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
return (mti->type == eModifierTypeType_OnlyDeform ||
(mti->flags & eModifierTypeFlag_SupportsMapping));
@@ -170,7 +173,7 @@ bool modifier_supportsMapping(ModifierData *md)
bool modifier_isPreview(ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
/* Constructive modifiers are highly likely to also modify data like vgroups or vcol! */
if (!((mti->flags & eModifierTypeFlag_UsesPreview) || (mti->type == eModifierTypeType_Constructive))) {
@@ -221,7 +224,7 @@ void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk,
ModifierData *md = ob->modifiers.first;
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti->foreachObjectLink)
mti->foreachObjectLink(md, ob, walk, userData);
@@ -233,7 +236,7 @@ void modifiers_foreachIDLink(Object *ob, IDWalkFunc walk, void *userData)
ModifierData *md = ob->modifiers.first;
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti->foreachIDLink) mti->foreachIDLink(md, ob, walk, userData);
else if (mti->foreachObjectLink) {
@@ -249,7 +252,7 @@ void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData)
ModifierData *md = ob->modifiers.first;
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti->foreachTexLink)
mti->foreachTexLink(md, ob, walk, userData);
@@ -261,7 +264,7 @@ void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData)
*/
void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md_src->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md_src->type);
const size_t data_size = sizeof(ModifierData);
const char *md_src_data = ((const char *)md_src) + data_size;
char *md_dst_data = ((char *)md_dst) + data_size;
@@ -271,7 +274,7 @@ void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst)
void modifier_copyData(ModifierData *md, ModifierData *target)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
target->mode = md->mode;
@@ -282,7 +285,7 @@ void modifier_copyData(ModifierData *md, ModifierData *target)
bool modifier_supportsCage(struct Scene *scene, ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -293,7 +296,7 @@ bool modifier_supportsCage(struct Scene *scene, ModifierData *md)
bool modifier_couldBeCage(struct Scene *scene, ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -305,13 +308,13 @@ bool modifier_couldBeCage(struct Scene *scene, ModifierData *md)
bool modifier_isSameTopology(ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
return ELEM(mti->type, eModifierTypeType_OnlyDeform, eModifierTypeType_NonGeometrical);
}
bool modifier_isNonGeometrical(ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
return (mti->type == eModifierTypeType_NonGeometrical);
}
@@ -353,7 +356,7 @@ int modifiers_getCageIndex(struct Scene *scene, Object *ob, int *r_lastPossibleC
/* Find the last modifier acting on the cage. */
for (i = 0; md; i++, md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
bool supports_mapping;
md->scene = scene;
@@ -411,7 +414,7 @@ bool modifiers_isParticleEnabled(Object *ob)
bool modifier_isEnabled(struct Scene *scene, ModifierData *md, int required_mode)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -432,7 +435,7 @@ CDMaskLink *modifiers_calcDataMasks(struct Scene *scene, Object *ob, ModifierDat
/* build a list of modifier data requirements in reverse order */
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
curr = MEM_callocN(sizeof(CDMaskLink), "CDMaskLink");
@@ -626,7 +629,7 @@ bool modifiers_usesArmature(Object *ob, bArmature *arm)
bool modifier_isCorrectableDeformed(ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
return (mti->deformMatricesEM != NULL);
}
@@ -736,7 +739,7 @@ struct DerivedMesh *modwrap_applyModifier(
struct DerivedMesh *dm,
ModifierApplyFlag flag)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
@@ -751,7 +754,7 @@ struct DerivedMesh *modwrap_applyModifierEM(
DerivedMesh *dm,
ModifierApplyFlag flag)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
@@ -766,7 +769,7 @@ void modwrap_deformVerts(
float (*vertexCos)[3], int numVerts,
ModifierApplyFlag flag)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
BLI_assert(!dm || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
@@ -780,7 +783,7 @@ void modwrap_deformVertsEM(
struct BMEditMesh *em, DerivedMesh *dm,
float (*vertexCos)[3], int numVerts)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
BLI_assert(!dm || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c
index 645567eea67..18f3db6bd15 100644
--- a/source/blender/blenkernel/intern/modifiers_bmesh.c
+++ b/source/blender/blenkernel/intern/modifiers_bmesh.c
@@ -37,8 +37,9 @@
#include "BKE_editmesh.h"
/* Static function for alloc */
-static BMFace *bm_face_create_from_mpoly(MPoly *mp, MLoop *ml,
- BMesh *bm, BMVert **vtable, BMEdge **etable)
+static BMFace *bm_face_create_from_mpoly(
+ MPoly *mp, MLoop *ml,
+ BMesh *bm, BMVert **vtable, BMEdge **etable)
{
BMVert **verts = BLI_array_alloca(verts, mp->totloop);
BMEdge **edges = BLI_array_alloca(edges, mp->totloop);
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 73f75f4f96d..f063933f3f9 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -1129,15 +1129,15 @@ void BKE_movieclip_get_aspect(MovieClip *clip, float *aspx, float *aspy)
}
/* get segments of cached frames. useful for debugging cache policies */
-void BKE_movieclip_get_cache_segments(MovieClip *clip, MovieClipUser *user, int *totseg_r, int **points_r)
+void BKE_movieclip_get_cache_segments(MovieClip *clip, MovieClipUser *user, int *r_totseg, int **r_points)
{
- *totseg_r = 0;
- *points_r = NULL;
+ *r_totseg = 0;
+ *r_points = NULL;
if (clip->cache) {
int proxy = rendersize_to_proxy(user, clip->flag);
- IMB_moviecache_get_cache_segments(clip->cache->moviecache, proxy, user->render_flag, totseg_r, points_r);
+ IMB_moviecache_get_cache_segments(clip->cache->moviecache, proxy, user->render_flag, r_totseg, r_points);
}
}
@@ -1168,7 +1168,7 @@ static void free_buffers(MovieClip *clip)
clip->anim = NULL;
}
- BKE_free_animdata((ID *) clip);
+ BKE_animdata_free((ID *) clip);
}
void BKE_movieclip_clear_cache(MovieClip *clip)
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 220d0f7c604..0c984c38b8e 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -280,7 +280,7 @@ static MDisps *multires_mdisps_initialize_hidden(Mesh *me, int level)
DerivedMesh *get_multires_dm(Scene *scene, MultiresModifierData *mmd, Object *ob)
{
ModifierData *md = (ModifierData *)mmd;
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
DerivedMesh *tdm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
DerivedMesh *dm;
@@ -340,13 +340,13 @@ static int multires_get_level(Object *ob, MultiresModifierData *mmd,
bool render, bool ignore_simplify)
{
if (render)
- return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->renderlvl) : mmd->renderlvl;
+ return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->renderlvl, true) : mmd->renderlvl;
else if (ob->mode == OB_MODE_SCULPT)
return mmd->sculptlvl;
else if (ignore_simplify)
return mmd->lvl;
else
- return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->lvl) : mmd->lvl;
+ return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->lvl, false) : mmd->lvl;
}
void multires_set_tot_level(Object *ob, MultiresModifierData *mmd, int lvl)
@@ -429,7 +429,7 @@ int multiresModifier_reshape(Scene *scene, MultiresModifierData *mmd, Object *ds
int multiresModifier_reshapeFromDeformMod(Scene *scene, MultiresModifierData *mmd,
Object *ob, ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
DerivedMesh *dm, *ndm;
int numVerts, result;
float (*deformedVerts)[3];
@@ -882,18 +882,20 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
{
Mesh *me = ob->data;
MDisps *mdisps;
- int lvl = mmd->totlvl;
+ const int lvl = mmd->totlvl;
if ((totlvl > multires_max_levels) || (me->totpoly == 0))
return;
+ BLI_assert(totlvl > lvl);
+
multires_force_update(ob);
mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
if (!mdisps)
mdisps = multires_mdisps_initialize_hidden(me, totlvl);
- if (mdisps->disps && !updateblock && totlvl > 1) {
+ if (mdisps->disps && !updateblock && lvl != 0) {
/* upsample */
DerivedMesh *lowdm, *cddm, *highdm;
CCGElem **highGridData, **lowGridData, **subGridData;
@@ -910,6 +912,7 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
/* create multires DM from original mesh at low level */
lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple, has_mask);
+ BLI_assert(lowdm != cddm);
cddm->release(cddm);
/* copy subsurf grids and replace them with low displaced grids */
@@ -2137,27 +2140,38 @@ void multires_load_old(Object *ob, Mesh *me)
me->mr = NULL;
}
-/* If 'ob' and 'to_ob' both have multires modifiers, synchronize them
- * such that 'ob' has the same total number of levels as 'to_ob'. */
-static void multires_sync_levels(Scene *scene, Object *ob, Object *to_ob)
+/* If 'ob_src' and 'ob_dst' both have multires modifiers, synchronize them
+ * such that 'ob_dst' has the same total number of levels as 'ob_src'. */
+void multiresModifier_sync_levels_ex(Object *ob_dst, MultiresModifierData *mmd_src, MultiresModifierData *mmd_dst)
{
- MultiresModifierData *mmd = get_multires_modifier(scene, ob, 1);
- MultiresModifierData *to_mmd = get_multires_modifier(scene, to_ob, 1);
+ if (mmd_src->totlvl == mmd_dst->totlvl) {
+ return;
+ }
+
+ if (mmd_src->totlvl > mmd_dst->totlvl) {
+ multires_subdivide(mmd_dst, ob_dst, mmd_src->totlvl, false, mmd_dst->simple);
+ }
+ else {
+ multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl);
+ }
+}
- if (!mmd) {
+static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst)
+{
+ MultiresModifierData *mmd_src = get_multires_modifier(scene, ob_src, true);
+ MultiresModifierData *mmd_dst = get_multires_modifier(scene, ob_dst, true);
+
+ if (!mmd_src) {
/* object could have MDISP even when there is no multires modifier
* this could lead to troubles due to i've got no idea how mdisp could be
* upsampled correct without modifier data.
* just remove mdisps if no multires present (nazgul) */
- multires_customdata_delete(ob->data);
+ multires_customdata_delete(ob_src->data);
}
- if (mmd && to_mmd) {
- if (mmd->totlvl > to_mmd->totlvl)
- multires_del_higher(mmd, ob, to_mmd->totlvl);
- else
- multires_subdivide(mmd, ob, to_mmd->totlvl, 0, mmd->simple);
+ if (mmd_src && mmd_dst) {
+ multiresModifier_sync_levels_ex(ob_dst, mmd_src, mmd_dst);
}
}
@@ -2276,7 +2290,7 @@ void multiresModifier_scale_disp(Scene *scene, Object *ob)
void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob)
{
float smat[3][3], tmat[3][3], mat[3][3];
- multires_sync_levels(scene, ob, to_ob);
+ multires_sync_levels(scene, to_ob, ob);
/* construct scale matrix for displacement */
BKE_object_scale_to_mat3(to_ob, tmat);
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 9a04312aaab..1ad6446eb05 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -535,9 +535,14 @@ float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
/* if the active-strip info has been stored already, access this, otherwise look this up
* and store for (very probable) future usage
*/
+ if (adt->act_track == NULL) {
+ if (adt->actstrip)
+ adt->act_track = BKE_nlatrack_find_tweaked(adt);
+ else
+ adt->act_track = BKE_nlatrack_find_active(&adt->nla_tracks);
+ }
if (adt->actstrip == NULL) {
- NlaTrack *nlt = BKE_nlatrack_find_active(&adt->nla_tracks);
- adt->actstrip = BKE_nlastrip_find_active(nlt);
+ adt->actstrip = BKE_nlastrip_find_active(adt->act_track);
}
strip = adt->actstrip;
@@ -926,6 +931,39 @@ NlaTrack *BKE_nlatrack_find_active(ListBase *tracks)
return NULL;
}
+/* Get the NLA Track that the active action/action strip comes from,
+ * since this info is not stored in AnimData. It also isn't as simple
+ * as just using the active track, since multiple tracks may have been
+ * entered at the same time.
+ */
+NlaTrack *BKE_nlatrack_find_tweaked(AnimData *adt)
+{
+ NlaTrack *nlt;
+
+ /* sanity check */
+ if (adt == NULL)
+ return NULL;
+
+ /* Since the track itself gets disabled, we want the first disabled... */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ if (nlt->flag & (NLATRACK_ACTIVE | NLATRACK_DISABLED)) {
+ /* For good measure, make sure that strip actually exists there */
+ if (BLI_findindex(&nlt->strips, adt->actstrip) != -1) {
+ return nlt;
+ }
+ else if (G.debug & G_DEBUG) {
+ printf("%s: Active strip (%p, %s) not in NLA track found (%p, %s)\n",
+ __func__,
+ adt->actstrip, (adt->actstrip) ? adt->actstrip->name : "<None>",
+ nlt, nlt->name);
+ }
+ }
+ }
+
+ /* Not found! */
+ return NULL;
+}
+
/* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
* that has this status in its AnimData block.
*/
@@ -1584,6 +1622,12 @@ bool BKE_nla_action_stash(AnimData *adt)
nlt = add_nlatrack(adt, prev_track);
BLI_assert(nlt != NULL);
+ /* we need to ensure that if there wasn't any previous instance, it must go to tbe bottom of the stack */
+ if (prev_track == NULL) {
+ BLI_remlink(&adt->nla_tracks, nlt);
+ BLI_addhead(&adt->nla_tracks, nlt);
+ }
+
BLI_strncpy(nlt->name, STASH_TRACK_NAME, sizeof(nlt->name));
BLI_uniquename(&adt->nla_tracks, nlt, STASH_TRACK_NAME, '.', offsetof(NlaTrack, name), sizeof(nlt->name));
@@ -1605,6 +1649,12 @@ bool BKE_nla_action_stash(AnimData *adt)
nlt->flag = (NLATRACK_MUTED | NLATRACK_PROTECTED);
strip->flag &= ~(NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE);
+ /* also mark the strip for auto syncing the length, so that the strips accurately
+ * reflect the length of the action
+ * XXX: we could do with some extra flags here to prevent repeats/scaling options from working!
+ */
+ strip->flag |= NLASTRIP_FLAG_SYNC_LENGTH;
+
/* succeeded */
return true;
}
@@ -1756,6 +1806,7 @@ bool BKE_nla_tweakmode_enter(AnimData *adt)
*/
adt->tmpact = adt->action;
adt->action = activeStrip->act;
+ adt->act_track = activeTrack;
adt->actstrip = activeStrip;
id_us_plus(&activeStrip->act->id);
adt->flag |= ADT_NLA_EDIT_ON;
@@ -1815,6 +1866,7 @@ void BKE_nla_tweakmode_exit(AnimData *adt)
if (adt->action) adt->action->id.us--;
adt->action = adt->tmpact;
adt->tmpact = NULL;
+ adt->act_track = NULL;
adt->actstrip = NULL;
adt->flag &= ~ADT_NLA_EDIT_ON;
}
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index c7010e42aac..9e159fa5852 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -303,7 +303,7 @@ bNodeTreeType *ntreeTypeFind(const char *idname)
void ntreeTypeAdd(bNodeTreeType *nt)
{
- BLI_ghash_insert(nodetreetypes_hash, (void *)nt->idname, nt);
+ BLI_ghash_insert(nodetreetypes_hash, nt->idname, nt);
/* XXX pass Main to register function? */
update_typeinfo(G.main, NULL, nt, NULL, NULL, false);
}
@@ -317,7 +317,7 @@ static void ntree_free_type(void *treetype_v)
MEM_freeN(treetype);
}
-void ntreeTypeFreeLink(bNodeTreeType *nt)
+void ntreeTypeFreeLink(const bNodeTreeType *nt)
{
BLI_ghash_remove(nodetreetypes_hash, nt->idname, NULL, ntree_free_type);
}
@@ -378,7 +378,7 @@ void nodeRegisterType(bNodeType *nt)
BLI_assert(nt->idname[0] != '\0');
BLI_assert(nt->poll != NULL);
- BLI_ghash_insert(nodetypes_hash, (void *)nt->idname, nt);
+ BLI_ghash_insert(nodetypes_hash, nt->idname, nt);
/* XXX pass Main to register function? */
update_typeinfo(G.main, NULL, NULL, nt, NULL, false);
}
@@ -1109,7 +1109,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
* copying for internal use (threads for eg), where you wont want it to modify the
* scene data.
*/
-static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_id_user, bool do_make_extern, bool copy_previews)
+static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool skip_database, bool do_id_user, bool do_make_extern, bool copy_previews)
{
bNodeTree *newtree;
bNode *node /*, *nnode */ /* UNUSED */, *last;
@@ -1119,7 +1119,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_
if (ntree == NULL) return NULL;
/* is ntree part of library? */
- if (bmain && BLI_findindex(&bmain->nodetree, ntree) >= 0) {
+ if (bmain && !skip_database && BLI_findindex(&bmain->nodetree, ntree) >= 0) {
newtree = BKE_libblock_copy(&ntree->id);
}
else {
@@ -1211,7 +1211,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_
bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, Main *bmain, const bool do_id_user)
{
- return ntreeCopyTree_internal(ntree, bmain, do_id_user, true, true);
+ return ntreeCopyTree_internal(ntree, bmain, false, do_id_user, true, true);
}
bNodeTree *ntreeCopyTree(bNodeTree *ntree)
{
@@ -1418,7 +1418,7 @@ static void node_preview_sync(bNodePreview *to, bNodePreview *from)
if (to->rect && from->rect) {
int xsize = to->xsize;
int ysize = to->ysize;
- memcpy(to->rect, from->rect, 4 * xsize + xsize * ysize * sizeof(char) * 4);
+ memcpy(to->rect, from->rect, xsize * ysize * sizeof(char) * 4);
}
}
@@ -1733,7 +1733,7 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user)
/* unregister associated RNA types */
ntreeInterfaceTypeFree(ntree);
- BKE_free_animdata((ID *)ntree);
+ BKE_animdata_free((ID *)ntree);
id_us_min((ID *)ntree->gpd);
@@ -1980,7 +1980,7 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
/* Make full copy.
* Note: previews are not copied here.
*/
- ltree = ntreeCopyTree_internal(ntree, NULL, false, false, false);
+ ltree = ntreeCopyTree_internal(ntree, G.main, true, false, false, false);
ltree->flag |= NTREE_IS_LOCALIZED;
for (node = ltree->nodes.first; node; node = node->next) {
@@ -3082,10 +3082,14 @@ void nodeSynchronizeID(bNode *node, bool copy_to_id)
bNodeSocket *sock;
Material *ma = (Material *)node->id;
int a;
+ short check_flags = SOCK_UNAVAIL;
+
+ if (!copy_to_id)
+ check_flags |= SOCK_HIDDEN;
/* hrmf, case in loop isn't super fast, but we don't edit 100s of material at same time either! */
for (a = 0, sock = node->inputs.first; sock; sock = sock->next, a++) {
- if (!nodeSocketIsHidden(sock)) {
+ if (!(sock->flag & check_flags)) {
if (copy_to_id) {
switch (a) {
case MAT_IN_COLOR:
@@ -3475,6 +3479,7 @@ static void registerCompositNodes(void)
register_node_type_cmp_bokehimage();
register_node_type_cmp_bokehblur();
register_node_type_cmp_switch();
+ register_node_type_cmp_switch_view();
register_node_type_cmp_pixelate();
register_node_type_cmp_mask();
@@ -3568,6 +3573,7 @@ static void registerShaderNodes(void)
register_node_type_sh_tex_magic();
register_node_type_sh_tex_checker();
register_node_type_sh_tex_brick();
+ register_node_type_sh_tex_pointdensity();
}
static void registerTextureNodes(void)
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index b3bc9f222e9..04bdfe3b58e 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -38,6 +38,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
+#include "DNA_cache_library_types.h"
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_group_types.h"
@@ -76,6 +77,7 @@
#include "BKE_armature.h"
#include "BKE_action.h"
#include "BKE_bullet.h"
+#include "BKE_cache_library.h"
#include "BKE_deform.h"
#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
@@ -97,6 +99,7 @@
#include "BKE_editmesh.h"
#include "BKE_mball.h"
#include "BKE_modifier.h"
+#include "BKE_multires.h"
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
@@ -108,6 +111,7 @@
#include "BKE_sca.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
+#include "BKE_smoke.h"
#include "BKE_speaker.h"
#include "BKE_softbody.h"
#include "BKE_subsurf.h"
@@ -236,7 +240,7 @@ void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd)
bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type)
{
- ModifierTypeInfo *mti;
+ const ModifierTypeInfo *mti;
mti = modifierType_getInfo(modifier_type);
@@ -249,7 +253,7 @@ bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type)
return true;
}
-void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src)
+void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src)
{
ModifierData *md;
BKE_object_free_modifiers(ob_dst);
@@ -265,8 +269,6 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src)
if (ELEM(md->type,
eModifierType_Hook,
- eModifierType_Softbody,
- eModifierType_ParticleInstance,
eModifierType_Collision))
{
continue;
@@ -274,21 +276,31 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src)
if (!BKE_object_support_modifier_type_check(ob_dst, md->type))
continue;
-
- if (md->type == eModifierType_Skin) {
- /* ensure skin-node customdata exists */
- BKE_mesh_ensure_skin_customdata(ob_dst->data);
+
+ switch (md->type) {
+ case eModifierType_Softbody:
+ BKE_object_copy_softbody(ob_dst, ob_src);
+ break;
+ case eModifierType_Skin:
+ /* ensure skin-node customdata exists */
+ BKE_mesh_ensure_skin_customdata(ob_dst->data);
+ break;
}
nmd = modifier_new(md->type);
BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
+
+ if (md->type == eModifierType_Multires) {
+ /* Has to be done after mod creation, but *before* we actually copy its settings! */
+ multiresModifier_sync_levels_ex(ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
+ }
+
modifier_copyData(md, nmd);
BLI_addtail(&ob_dst->modifiers, nmd);
modifier_unique_name(&ob_dst->modifiers, nmd);
}
BKE_object_copy_particlesystems(ob_dst, ob_src);
- BKE_object_copy_softbody(ob_dst, ob_src);
/* TODO: smoke?, cloth? */
}
@@ -318,9 +330,12 @@ void BKE_object_free_derived_caches(Object *ob)
}
if (ob->derivedFinal) {
- ob->derivedFinal->needsFree = 1;
- ob->derivedFinal->release(ob->derivedFinal);
- ob->derivedFinal = NULL;
+ /* dupli cache owns the derivedFinal, is freed by duplicator object */
+ if (!(ob->transflag & OB_IS_DUPLI_CACHE)) {
+ ob->derivedFinal->needsFree = 1;
+ ob->derivedFinal->release(ob->derivedFinal);
+ ob->derivedFinal = NULL;
+ }
}
if (ob->derivedDeform) {
ob->derivedDeform->needsFree = 1;
@@ -329,9 +344,11 @@ void BKE_object_free_derived_caches(Object *ob)
}
BKE_object_free_curve_cache(ob);
+
+ BKE_object_dupli_cache_clear(ob);
}
-void BKE_object_free_caches(Object *object)
+void BKE_object_free_caches(Object *object, bool free_smoke_sim)
{
ModifierData *md;
short update_flag = 0;
@@ -344,7 +361,7 @@ void BKE_object_free_caches(Object *object)
psys = psys->next)
{
psys_free_path_cache(psys, psys->edit);
- update_flag |= PSYS_RECALC;
+ update_flag |= PSYS_RECALC_REDO;
}
}
@@ -356,9 +373,32 @@ void BKE_object_free_caches(Object *object)
psmd->dm->needsFree = 1;
psmd->dm->release(psmd->dm);
psmd->dm = NULL;
+ psmd->flag |= eParticleSystemFlag_file_loaded;
update_flag |= OB_RECALC_DATA;
}
}
+ else if (md->type == eModifierType_Smoke) {
+ if (free_smoke_sim) {
+ SmokeModifierData *smd = (SmokeModifierData *) md;
+ SmokeDomainSettings *sds = smd->domain;
+ if (sds != NULL) {
+ bool use_sim = sds->point_cache[0] == NULL;
+ PointCache *cache;
+ /* We only reset cache if all the point caches are baked to file. */
+ for (cache = sds->ptcaches[0].first;
+ cache != NULL && use_sim == false;
+ cache = cache->next)
+ {
+ use_sim |= ((cache->flag & (PTCACHE_BAKED|PTCACHE_DISK_CACHE)) != (PTCACHE_BAKED|PTCACHE_DISK_CACHE));
+ }
+ if (!use_sim) {
+ smokeModifier_reset(smd);
+ smokeModifier_reset_turbulence(smd);
+ update_flag |= OB_RECALC_DATA;
+ }
+ }
+ }
+ }
}
/* Tag object for update, so once memory critical operation is over and
@@ -410,7 +450,7 @@ void BKE_object_free_ex(Object *ob, bool do_id_user)
ob->iuser = NULL;
if (ob->bb) MEM_freeN(ob->bb);
ob->bb = NULL;
- if (ob->adt) BKE_free_animdata((ID *)ob);
+ if (ob->adt) BKE_animdata_free((ID *)ob);
if (ob->poselib) ob->poselib->id.us--;
if (ob->gpd) ((ID *)ob->gpd)->us--;
if (ob->defbase.first)
@@ -438,7 +478,7 @@ void BKE_object_free_ex(Object *ob, bool do_id_user)
if (ob->bsoft) bsbFree(ob->bsoft);
if (ob->gpulamp.first) GPU_lamp_free(ob);
- BKE_free_sculptsession(ob);
+ BKE_sculptsession_free(ob);
if (ob->pc_ids.first) BLI_freelistN(&ob->pc_ids);
@@ -451,6 +491,8 @@ void BKE_object_free_ex(Object *ob, bool do_id_user)
free_path(ob->curve_cache->path);
MEM_freeN(ob->curve_cache);
}
+
+ BKE_object_dupli_cache_free(ob);
}
void BKE_object_free(Object *ob)
@@ -469,6 +511,15 @@ static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Objec
}
}
+static void unlink_object__unlinkCacheModifierLinks(void *userData, CacheLibrary *UNUSED(cachelib), CacheModifier *UNUSED(md), ID **idpoin)
+{
+ Object *unlinkOb = userData;
+
+ if (*idpoin == (ID *)unlinkOb) {
+ *idpoin = NULL;
+ }
+}
+
void BKE_object_unlink(Object *ob)
{
Main *bmain = G.main;
@@ -490,6 +541,7 @@ void BKE_object_unlink(Object *ob)
ARegion *ar;
RegionView3D *rv3d;
LodLevel *lod;
+ CacheLibrary *cachelib;
int a, found;
unlink_controllers(&ob->controllers);
@@ -535,7 +587,7 @@ void BKE_object_unlink(Object *ob)
bPoseChannel *pchan;
for (pchan = obt->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -566,7 +618,7 @@ void BKE_object_unlink(Object *ob)
sca_remove_ob_poin(obt, ob);
for (con = obt->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -677,6 +729,10 @@ void BKE_object_unlink(Object *ob)
lod->source = NULL;
}
+ /* dupli cache is cleared entirely if the object in question is duplified to keep it simple */
+ if (BKE_object_dupli_cache_contains(obt, ob))
+ BKE_object_dupli_cache_clear(obt);
+
obt = obt->id.next;
}
@@ -812,34 +868,11 @@ void BKE_object_unlink(Object *ob)
}
}
}
- else if (sl->spacetype == SPACE_OUTLINER) {
- SpaceOops *so = (SpaceOops *)sl;
-
- if (so->treestore) {
- TreeStoreElem *tselem;
- BLI_mempool_iter iter;
- BLI_mempool_iternew(so->treestore, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- if (tselem->id == (ID *)ob) tselem->id = NULL;
- }
- }
- }
- else if (sl->spacetype == SPACE_BUTS) {
- SpaceButs *sbuts = (SpaceButs *)sl;
-
- if (sbuts->pinid == (ID *)ob) {
- sbuts->flag &= ~SB_PIN_CONTEXT;
- sbuts->pinid = NULL;
- }
- }
- else if (sl->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)sl;
-
- if (snode->from == (ID *)ob) {
- snode->flag &= ~SNODE_PIN;
- snode->from = NULL;
- }
+#if 0
+ else if (ELEM(sl->spacetype, SPACE_OUTLINER, SPACE_BUTS, SPACE_NODE)) {
+ /* now handled by WM_main_remove_editor_id_reference */
}
+#endif
}
sa = sa->next;
@@ -862,6 +895,15 @@ void BKE_object_unlink(Object *ob)
}
camera = camera->id.next;
}
+
+ /* cache libraries */
+ for (cachelib = bmain->cache_library.first; cachelib; cachelib = cachelib->id.next) {
+ CacheModifier *md;
+
+ for (md = cachelib->modifiers.first; md; md = md->next) {
+ BKE_cache_modifier_foreachIDLink(cachelib, md, unlink_object__unlinkCacheModifierLinks, ob);
+ }
+ }
}
/* actual check for internal data, not context or flags */
@@ -942,26 +984,6 @@ bool BKE_object_exists_check(Object *obtest)
/* *************************************************** */
-void *BKE_object_obdata_add_from_type(Main *bmain, int type)
-{
- switch (type) {
- case OB_MESH: return BKE_mesh_add(bmain, "Mesh");
- case OB_CURVE: return BKE_curve_add(bmain, "Curve", OB_CURVE);
- case OB_SURF: return BKE_curve_add(bmain, "Surf", OB_SURF);
- case OB_FONT: return BKE_curve_add(bmain, "Text", OB_FONT);
- case OB_MBALL: return BKE_mball_add(bmain, "Meta");
- case OB_CAMERA: return BKE_camera_add(bmain, "Camera");
- case OB_LAMP: return BKE_lamp_add(bmain, "Lamp");
- case OB_LATTICE: return BKE_lattice_add(bmain, "Lattice");
- case OB_ARMATURE: return BKE_armature_add(bmain, "Armature");
- case OB_SPEAKER: return BKE_speaker_add(bmain, "Speaker");
- case OB_EMPTY: return NULL;
- default:
- printf("BKE_object_obdata_add_from_type: Internal error, bad type: %d\n", type);
- return NULL;
- }
-}
-
static const char *get_obdata_defname(int type)
{
switch (type) {
@@ -982,6 +1004,30 @@ static const char *get_obdata_defname(int type)
}
}
+void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
+{
+ if (name == NULL) {
+ name = get_obdata_defname(type);
+ }
+
+ switch (type) {
+ case OB_MESH: return BKE_mesh_add(bmain, name);
+ case OB_CURVE: return BKE_curve_add(bmain, name, OB_CURVE);
+ case OB_SURF: return BKE_curve_add(bmain, name, OB_SURF);
+ case OB_FONT: return BKE_curve_add(bmain, name, OB_FONT);
+ case OB_MBALL: return BKE_mball_add(bmain, name);
+ case OB_CAMERA: return BKE_camera_add(bmain, name);
+ case OB_LAMP: return BKE_lamp_add(bmain, name);
+ case OB_LATTICE: return BKE_lattice_add(bmain, name);
+ case OB_ARMATURE: return BKE_armature_add(bmain, name);
+ case OB_SPEAKER: return BKE_speaker_add(bmain, name);
+ case OB_EMPTY: return NULL;
+ default:
+ printf("%s: Internal error, bad type: %d\n", __func__, type);
+ return NULL;
+ }
+}
+
/* more general add: creates minimum required data, but without vertices etc. */
Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
{
@@ -1052,7 +1098,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
ob->jump_speed = 10.0f;
ob->fall_speed = 55.0f;
ob->col_group = 0x01;
- ob->col_mask = 0xff;
+ ob->col_mask = 0xffff;
/* NT fluid sim defaults */
ob->fluidsimSettings = NULL;
@@ -1067,16 +1113,16 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
/* general add: to scene, with layer from area and default name */
/* creates minimum required data, but without vertices etc. */
-Object *BKE_object_add(Main *bmain, Scene *scene, int type)
+Object *BKE_object_add(
+ Main *bmain, Scene *scene,
+ int type, const char *name)
{
Object *ob;
Base *base;
- char name[MAX_ID_NAME];
- BLI_strncpy(name, get_obdata_defname(type), sizeof(name));
ob = BKE_object_add_only_object(bmain, type, name);
- ob->data = BKE_object_obdata_add_from_type(bmain, type);
+ ob->data = BKE_object_obdata_add_from_type(bmain, type, name);
ob->lay = scene->lay;
@@ -1102,10 +1148,12 @@ void BKE_object_lod_add(Object *ob)
BLI_addtail(&ob->lodlevels, base);
base->flags = OB_LOD_USE_MESH | OB_LOD_USE_MAT;
base->source = ob;
+ base->obhysteresis = 10;
last = ob->currentlod = base;
}
lod->distance = last->distance + 25.0f;
+ lod->obhysteresis = 10;
lod->flags = OB_LOD_USE_MESH | OB_LOD_USE_MAT;
BLI_addtail(&ob->lodlevels, lod);
@@ -1221,7 +1269,7 @@ struct Object *BKE_object_lod_matob_get(Object *ob, Scene *scene)
#endif /* WITH_GAMEENGINE */
-SoftBody *copy_softbody(SoftBody *sb, bool copy_caches)
+SoftBody *copy_softbody(const SoftBody *sb, bool copy_caches)
{
SoftBody *sbn;
@@ -1323,6 +1371,7 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys)
psysn->pathcache = NULL;
psysn->childcache = NULL;
psysn->edit = NULL;
+ psysn->hairedit = NULL;
psysn->pdd = NULL;
psysn->effectors = NULL;
psysn->tree = NULL;
@@ -1334,36 +1383,30 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys)
psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, false);
- /* XXX - from reading existing code this seems correct but intended usage of
- * pointcache should /w cloth should be added in 'ParticleSystem' - campbell */
- if (psysn->clmd) {
- psysn->clmd->point_cache = psysn->pointcache;
- }
-
id_us_plus((ID *)psysn->part);
id_us_plus((ID *)psysn->key);
return psysn;
}
-void BKE_object_copy_particlesystems(Object *obn, Object *ob)
+void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src)
{
ParticleSystem *psys, *npsys;
ModifierData *md;
- if (obn->type != OB_MESH) {
+ if (ob_dst->type != OB_MESH) {
/* currently only mesh objects can have soft body */
return;
}
- BLI_listbase_clear(&obn->particlesystem);
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ BLI_listbase_clear(&ob_dst->particlesystem);
+ for (psys = ob_src->particlesystem.first; psys; psys = psys->next) {
npsys = BKE_object_copy_particlesystem(psys);
- BLI_addtail(&obn->particlesystem, npsys);
+ BLI_addtail(&ob_dst->particlesystem, npsys);
/* need to update particle modifiers too */
- for (md = obn->modifiers.first; md; md = md->next) {
+ for (md = ob_dst->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_ParticleSystem) {
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
if (psmd->psys == psys)
@@ -1391,10 +1434,12 @@ void BKE_object_copy_particlesystems(Object *obn, Object *ob)
}
}
-void BKE_object_copy_softbody(Object *obn, Object *ob)
+void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src)
{
- if (ob->soft)
- obn->soft = copy_softbody(ob->soft, false);
+ if (ob_src->soft) {
+ ob_dst->softflag = ob_src->softflag;
+ ob_dst->soft = copy_softbody(ob_src->soft, false);
+ }
}
static void copy_object_pose(Object *obn, Object *ob)
@@ -1411,7 +1456,7 @@ static void copy_object_pose(Object *obn, Object *ob)
chan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE);
for (con = chan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -1533,6 +1578,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
id_us_plus((ID *)obn->data);
id_us_plus((ID *)obn->gpd);
id_lib_extern((ID *)obn->dup_group);
+ id_lib_extern((ID *)obn->cache_library);
for (a = 0; a < obn->totcol; a++) id_us_plus((ID *)obn->mat[a]);
@@ -1564,6 +1610,8 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
/* Copy runtime surve data. */
obn->curve_cache = NULL;
+ obn->dup_cache = NULL;
+
if (ob->id.lib) {
BKE_id_lib_local_paths(bmain, ob->id.lib, &obn->id);
}
@@ -1595,6 +1643,7 @@ static void extern_local_object(Object *ob)
id_lib_extern((ID *)ob->data);
id_lib_extern((ID *)ob->dup_group);
+ id_lib_extern((ID *)ob->cache_library);
id_lib_extern((ID *)ob->poselib);
id_lib_extern((ID *)ob->gpd);
@@ -1713,7 +1762,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
/* add new animdata block */
if (!ob->adt)
- ob->adt = BKE_id_add_animdata(&ob->id);
+ ob->adt = BKE_animdata_add_id(&ob->id);
/* make a copy of all the drivers (for now), then correct any links that need fixing */
free_fcurves(&ob->adt->drivers);
@@ -1775,8 +1824,7 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
mul_m4_m4m4(ob->obmat, gob->obmat, target->obmat);
if (gob->dup_group) { /* should always be true */
float tvec[3];
- copy_v3_v3(tvec, gob->dup_group->dupli_ofs);
- mul_mat3_m4_v3(ob->obmat, tvec);
+ mul_v3_mat3_m4v3(tvec, ob->obmat, gob->dup_group->dupli_ofs);
sub_v3_v3(ob->obmat[3], tvec);
}
BKE_object_apply_mat4(ob, ob->obmat, false, true);
@@ -2071,14 +2119,12 @@ void BKE_object_to_mat4(Object *ob, float mat[4][4])
add_v3_v3v3(mat[3], ob->loc, ob->dloc);
}
-static void ob_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4]);
-
void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4])
{
if (ob->parent) {
float par_imat[4][4];
- ob_get_parent_matrix(NULL, ob, ob->parent, par_imat);
+ BKE_object_get_parent_matrix(NULL, ob, ob->parent, par_imat);
invert_m4(par_imat);
mul_m4_m4m4(mat, par_imat, ob->obmat);
}
@@ -2098,7 +2144,7 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
unit_m4(mat);
cu = par->data;
- if (ELEM(NULL, par->curve_cache, par->curve_cache->path, par->curve_cache->path->data)) /* only happens on reload file, but violates depsgraph still... fix! */
+ if (par->curve_cache == NULL) /* only happens on reload file, but violates depsgraph still... fix! */
BKE_displist_make_curveTypes(scene, par, 0);
if (par->curve_cache->path == NULL) return;
@@ -2133,7 +2179,7 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
}
/* vec: 4 items! */
- if (where_on_path(par, ctime, vec, dir, cu->flag & CU_FOLLOW ? quat : NULL, &radius, NULL)) {
+ if (where_on_path(par, ctime, vec, dir, (cu->flag & CU_FOLLOW) ? quat : NULL, &radius, NULL)) {
if (cu->flag & CU_FOLLOW) {
#if 0
@@ -2227,7 +2273,7 @@ static void give_parvert(Object *par, int nr, float vec[3])
md != NULL;
md = md->next)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
/* TODO(sergey): Check for disabled modifiers. */
if (mti->type != eModifierTypeType_OnlyDeform && md->next != NULL) {
use_special_ss_case = false;
@@ -2370,7 +2416,8 @@ static void ob_parvert3(Object *ob, Object *par, float mat[4][4])
}
}
-static void ob_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4])
+
+void BKE_object_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4])
{
float tmat[4][4];
float vec[3];
@@ -2427,7 +2474,7 @@ static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[4
if (ob->partype & PARSLOW) copy_m4_m4(slowmat, obmat);
- ob_get_parent_matrix(scene, ob, par, totmat);
+ BKE_object_get_parent_matrix(scene, ob, par, totmat);
/* total */
mul_m4_m4m4(tmat, totmat, ob->parentinv);
@@ -2585,7 +2632,7 @@ void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, c
if (use_parent && ob->parent) {
float rmat[4][4], diff_mat[4][4], imat[4][4], parent_mat[4][4];
- ob_get_parent_matrix(NULL, ob, ob->parent, parent_mat);
+ BKE_object_get_parent_matrix(NULL, ob, ob->parent, parent_mat);
mul_m4_m4m4(diff_mat, parent_mat, ob->parentinv);
invert_m4_m4(imat, diff_mat);
@@ -2854,7 +2901,15 @@ bool BKE_object_minmax_dupli(Scene *scene, Object *ob, float r_min[3], float r_m
/* pass */
}
else {
- BoundBox *bb = BKE_object_boundbox_get(dob->ob);
+ BoundBox *bb = NULL;
+ if (ob->dup_cache) {
+ DupliObjectData *dob_data = BKE_dupli_cache_find_data(ob->dup_cache, dob->ob);
+ if (dob_data && dob_data->dm) {
+ bb = &dob_data->bb;
+ }
+ }
+ if (!bb)
+ bb = BKE_object_boundbox_get(dob->ob);
if (bb) {
int i;
@@ -3021,8 +3076,12 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
{
if (ob->recalc & OB_RECALC_ALL) {
/* speed optimization for animation lookups */
- if (ob->pose)
+ if (ob->pose) {
BKE_pose_channels_hash_make(ob->pose);
+ if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
+ BKE_pose_update_constraint_flags(ob->pose);
+ }
+ }
if (ob->recalc & OB_RECALC_DATA) {
if (ob->type == OB_ARMATURE) {
@@ -3048,8 +3107,9 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
// 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;
- invert_m4_m4(obg->imat, obg->obmat);
- mul_m4_m4m4(ob->obmat, obg->imat, ob->proxy_from->obmat);
+ float imat[4][4];
+ invert_m4_m4(imat, obg->obmat);
+ mul_m4_m4m4(ob->obmat, imat, ob->proxy_from->obmat);
if (obg->dup_group) { /* should always be true */
add_v3_v3(ob->obmat[3], obg->dup_group->dupli_ofs);
}
@@ -3062,153 +3122,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
}
if (ob->recalc & OB_RECALC_DATA) {
- ID *data_id = (ID *)ob->data;
- AnimData *adt = BKE_animdata_from_id(data_id);
- Key *key;
- ParticleSystem *psys;
-
- if (G.debug & G_DEBUG_DEPSGRAPH)
- printf("recalcdata %s\n", ob->id.name + 2);
-
- if (adt) {
- /* evaluate drivers - datalevel */
- /* XXX: for mesh types, should we push this to derivedmesh instead? */
- BKE_animsys_evaluate_animdata(scene, data_id, adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- key = BKE_key_from_object(ob);
- if (key && key->block.first) {
- if (!(ob->shapeflag & OB_SHAPE_LOCK))
- BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS);
- }
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- key = psys->key;
- if (key && key->block.first) {
- BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS);
- }
- }
-
- /* includes all keys and modifiers */
- switch (ob->type) {
- case OB_MESH:
- {
- BMEditMesh *em = (ob == scene->obedit) ? BKE_editmesh_from_object(ob) : NULL;
- uint64_t data_mask = scene->customdata_mask | CD_MASK_BAREMESH;
-#ifdef WITH_FREESTYLE
- /* make sure Freestyle edge/face marks appear in DM for render (see T40315) */
- if (eval_ctx->mode != DAG_EVAL_VIEWPORT) {
- data_mask |= CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE;
- }
-#endif
- if (em) {
- makeDerivedMesh(scene, ob, em, data_mask, 0); /* was CD_MASK_BAREMESH */
- }
- else {
- makeDerivedMesh(scene, ob, NULL, data_mask, 0);
- }
- break;
- }
- case OB_ARMATURE:
- if (ob->id.lib && 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);
- }
- }
- else {
- BKE_pose_where_is(scene, ob);
- }
- break;
-
- case OB_MBALL:
- BKE_displist_make_mball(eval_ctx, scene, ob);
- break;
-
- case OB_CURVE:
- case OB_SURF:
- case OB_FONT:
- BKE_displist_make_curveTypes(scene, ob, 0);
- break;
-
- case OB_LATTICE:
- BKE_lattice_modifiers_calc(scene, ob);
- break;
-
- case OB_EMPTY:
- if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data)
- if (BKE_image_is_animated(ob->data))
- BKE_image_user_check_frame_calc(ob->iuser, (int)ctime, 0);
- break;
- }
-
- /* related materials */
- /* XXX: without depsgraph tagging, this will always need to be run, which will be slow!
- * However, not doing anything (or trying to hack around this lack) is not an option
- * anymore, especially due to Cycles [#31834]
- */
- if (ob->totcol) {
- int a;
-
- for (a = 1; a <= ob->totcol; a++) {
- Material *ma = give_current_material(ob, a);
-
- if (ma) {
- /* recursively update drivers for this material */
- material_drivers_update(scene, ma, ctime);
- }
- }
- }
- else if (ob->type == OB_LAMP)
- lamp_drivers_update(scene, ob->data, ctime);
-
- /* particles */
- if (ob != scene->obedit && ob->particlesystem.first) {
- ParticleSystem *tpsys, *psys;
- DerivedMesh *dm;
- ob->transflag &= ~OB_DUPLIPARTS;
-
- psys = ob->particlesystem.first;
- while (psys) {
- /* ensure this update always happens even if psys is disabled */
- if (psys->recalc & PSYS_RECALC_TYPE) {
- psys_changed_type(ob, psys);
- }
-
- if (psys_check_enabled(ob, psys)) {
- /* check use of dupli objects here */
- if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) &&
- ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) ||
- (psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group)))
- {
- ob->transflag |= OB_DUPLIPARTS;
- }
-
- particle_system_update(scene, ob, psys);
- psys = psys->next;
- }
- else if (psys->flag & PSYS_DELETE) {
- tpsys = psys->next;
- BLI_remlink(&ob->particlesystem, psys);
- psys_free(ob, psys);
- psys = tpsys;
- }
- else
- psys = psys->next;
- }
-
- if (eval_ctx->mode == DAG_EVAL_RENDER && ob->transflag & OB_DUPLIPARTS) {
- /* this is to make sure we get render level duplis in groups:
- * the derivedmesh must be created before init_render_mesh,
- * since object_duplilist does dupliparticles before that */
- dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
- dm->release(dm);
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next)
- psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
- }
- }
-
- /* quick cache removed */
+ BKE_object_handle_data_update(eval_ctx, scene, ob);
}
ob->recalc &= ~OB_RECALC_ALL;
@@ -3253,7 +3167,7 @@ void BKE_object_sculpt_modifiers_changed(Object *ob)
ss->pbvh = NULL;
}
- BKE_free_sculptsession_deformMats(ob->sculpt);
+ BKE_sculptsession_free_deformMats(ob->sculpt);
}
else {
PBVHNode **nodes;
@@ -3516,7 +3430,7 @@ static KeyBlock *insert_curvekey(Object *ob, const char *name, const bool from_m
return kb;
}
-KeyBlock *BKE_object_insert_shape_key(Object *ob, const char *name, const bool from_mix)
+KeyBlock *BKE_object_shapekey_insert(Object *ob, const char *name, const bool from_mix)
{
switch (ob->type) {
case OB_MESH:
@@ -3532,6 +3446,85 @@ KeyBlock *BKE_object_insert_shape_key(Object *ob, const char *name, const bool f
}
+bool BKE_object_shapekey_free(Main *bmain, Object *ob)
+{
+ Key **key_p, *key;
+
+ key_p = BKE_key_from_object_p(ob);
+ if (ELEM(NULL, key_p, *key_p)) {
+ return false;
+ }
+
+ key = *key_p;
+ *key_p = NULL;
+
+ BKE_libblock_free_us(bmain, key);
+
+ return false;
+}
+
+bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb)
+{
+ KeyBlock *rkb;
+ Key *key = BKE_key_from_object(ob);
+ short kb_index;
+
+ if (key == NULL) {
+ return false;
+ }
+
+ kb_index = BLI_findindex(&key->block, kb);
+ BLI_assert(kb_index != -1);
+
+ for (rkb = key->block.first; rkb; rkb = rkb->next) {
+ if (rkb->relative == kb_index) {
+ /* remap to the 'Basis' */
+ rkb->relative = 0;
+ }
+ else if (rkb->relative >= kb_index) {
+ /* Fix positional shift of the keys when kb is deleted from the list */
+ rkb->relative -= 1;
+ }
+ }
+
+ BLI_remlink(&key->block, kb);
+ key->totkey--;
+ if (key->refkey == kb) {
+ key->refkey = key->block.first;
+
+ if (key->refkey) {
+ /* apply new basis key on original data */
+ switch (ob->type) {
+ case OB_MESH:
+ BKE_keyblock_convert_to_mesh(key->refkey, ob->data);
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ BKE_keyblock_convert_to_curve(key->refkey, ob->data, BKE_curve_nurbs_get(ob->data));
+ break;
+ case OB_LATTICE:
+ BKE_keyblock_convert_to_lattice(key->refkey, ob->data);
+ break;
+ }
+ }
+ }
+
+ if (kb->data) {
+ MEM_freeN(kb->data);
+ }
+ MEM_freeN(kb);
+
+ if (ob->shapenr > 1) {
+ ob->shapenr--;
+ }
+
+ if (key->totkey == 0) {
+ BKE_object_shapekey_free(bmain, ob);
+ }
+
+ return true;
+}
+
bool BKE_object_flag_test_recursive(const Object *ob, short flag)
{
if (ob->flag & flag) {
@@ -3683,7 +3676,7 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob)
md && (flag != (eModifierMode_Render | eModifierMode_Realtime));
md = md->next)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
bool can_deform = mti->type == eModifierTypeType_OnlyDeform ||
is_modifier_animated;
@@ -3740,7 +3733,7 @@ void BKE_object_relink(Object *ob)
modifiers_foreachIDLink(ob, copy_object__forwardModifierLinks, NULL);
if (ob->adt)
- BKE_relink_animdata(ob->adt);
+ BKE_animdata_relink(ob->adt);
if (ob->rigidbody_constraint)
BKE_rigidbody_relink_constraint(ob->rigidbody_constraint);
@@ -4053,3 +4046,51 @@ KDTree *BKE_object_as_kdtree(Object *ob, int *r_tot)
*r_tot = tot;
return tree;
}
+
+bool BKE_object_modifier_use_time(Object *ob, ModifierData *md)
+{
+ if (modifier_dependsOnTime(md)) {
+ return true;
+ }
+
+ /* Check whether modifier is animated. */
+ /* TODO: this should be handled as part of build_animdata() -- Aligorith */
+ if (ob->adt) {
+ AnimData *adt = ob->adt;
+ FCurve *fcu;
+
+ char pattern[MAX_NAME + 10];
+ /* TODO(sergey): Escape modifier name. */
+ BLI_snprintf(pattern, sizeof(pattern), "modifiers[%s", md->name);
+
+ /* action - check for F-Curves with paths containing 'modifiers[' */
+ if (adt->action) {
+ for (fcu = (FCurve *)adt->action->curves.first;
+ fcu != NULL;
+ fcu = (FCurve *)fcu->next)
+ {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+ }
+
+ /* This here allows modifier properties to get driven and still update properly
+ *
+ * Workaround to get [#26764] (e.g. subsurf levels not updating when animated/driven)
+ * working, without the updating problems ([#28525] [#28690] [#28774] [#28777]) caused
+ * by the RNA updates cache introduced in r.38649
+ */
+ for (fcu = (FCurve *)adt->drivers.first;
+ fcu != NULL;
+ fcu = (FCurve *)fcu->next)
+ {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+
+ /* XXX: also, should check NLA strips, though for now assume that nobody uses
+ * that and we can omit that for performance reasons... */
+ }
+
+ return false;
+}
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index e46929dde4a..f6e939a103e 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -163,7 +163,7 @@ MDeformVert *BKE_object_defgroup_data_create(ID *id)
/**
* Remove all verts (or only selected ones) from given vgroup. Work in Object and Edit modes.
*
- * \param allverts If true, remove all vertices, else only selected ones.
+ * \param use_selection: Only operate on selection.
* \return True if any vertex was removed, false otherwise.
*/
bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_selection)
@@ -241,7 +241,7 @@ bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_sele
/**
* Remove all verts (or only selected ones) from all vgroups. Work in Object and Edit modes.
*
- * \param allverts If true, remove all vertices, else only selected ones.
+ * \param use_selection: Only operate on selection.
* \return True if any vertex was removed, false otherwise.
*/
bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection)
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index c77f65f69e1..fd0d0daf7e4 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -35,11 +35,16 @@
#include "MEM_guardedalloc.h"
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_math.h"
#include "BLI_rand.h"
+#include "BLI_task.h"
#include "DNA_anim_types.h"
#include "DNA_group_types.h"
@@ -48,6 +53,7 @@
#include "DNA_vfont_types.h"
#include "BKE_animsys.h"
+#include "BKE_cache_library.h"
#include "BKE_DerivedMesh.h"
#include "BKE_depsgraph.h"
#include "BKE_font.h"
@@ -56,15 +62,18 @@
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_sample.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
#include "BKE_editmesh.h"
#include "BKE_anim.h"
-
+#include "BKE_strands.h"
#include "BLI_strict_flags.h"
+#include "BLF_translation.h"
+
/* Dupli-Geometry */
typedef struct DupliContext {
@@ -96,7 +105,7 @@ typedef struct DupliGenerator {
static const DupliGenerator *get_dupli_generator(const DupliContext *ctx);
/* create initial context for root object */
-static void init_context(DupliContext *r_ctx, EvaluationContext *eval_ctx, Scene *scene, Object *ob, float space_mat[4][4], bool update)
+static void init_context_ex(DupliContext *r_ctx, EvaluationContext *eval_ctx, Scene *scene, Object *ob, float space_mat[4][4], const DupliGenerator *gen, bool update)
{
r_ctx->eval_ctx = eval_ctx;
r_ctx->scene = scene;
@@ -110,14 +119,19 @@ static void init_context(DupliContext *r_ctx, EvaluationContext *eval_ctx, Scene
copy_m4_m4(r_ctx->space_mat, space_mat);
else
unit_m4(r_ctx->space_mat);
- r_ctx->lay = ob->lay;
+ r_ctx->lay = ob ? ob->lay : 0;
r_ctx->level = 0;
- r_ctx->gen = get_dupli_generator(r_ctx);
+ r_ctx->gen = gen ? gen : get_dupli_generator(r_ctx);
r_ctx->duplilist = NULL;
}
+static void init_context(DupliContext *r_ctx, EvaluationContext *eval_ctx, Scene *scene, Object *ob, bool update)
+{
+ init_context_ex(r_ctx, eval_ctx, scene, ob, NULL, NULL, update);
+}
+
/* create sub-context for recursive duplis */
static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index, bool animated)
{
@@ -126,7 +140,7 @@ static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Obj
r_ctx->animated |= animated; /* object animation makes all children animated */
/* XXX annoying, previously was done by passing an ID* argument, this at least is more explicit */
- if (ctx->gen->type == OB_DUPLIGROUP)
+ if (ctx->gen->type == OB_DUPLIGROUP && ctx->object)
r_ctx->group = ctx->object->dup_group;
r_ctx->object = ob;
@@ -219,7 +233,10 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild
{
Object *parent = ctx->object;
Object *obedit = ctx->scene->obedit;
-
+
+ if (!parent)
+ return;
+
if (ctx->group) {
unsigned int lay = ctx->group->layer;
GroupObject *go;
@@ -255,69 +272,84 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild
/*---- Implementations ----*/
-/* OB_DUPLIGROUP */
-static void make_duplis_group(const DupliContext *ctx)
+/* Intern function for creating instances of group content
+ * with or without a parent (parent == NULL is allowed!)
+ * Note: some of the group animation update functions use the parent object,
+ * but this is old NLA code that is currently disabled and might be removed entirely.
+ */
+static void make_duplis_group_intern(const DupliContext *ctx, Group *group, Object *parent)
{
- bool for_render = (ctx->eval_ctx->mode == DAG_EVAL_RENDER);
- Object *ob = ctx->object;
- Group *group;
+ const bool for_render = (ctx->eval_ctx->mode == DAG_EVAL_RENDER);
+
GroupObject *go;
float group_mat[4][4];
int id;
- bool animated, hide;
-
- if (ob->dup_group == NULL) return;
- group = ob->dup_group;
-
- /* combine group offset and obmat */
+ bool animated;
+
unit_m4(group_mat);
sub_v3_v3(group_mat[3], group->dupli_ofs);
- mul_m4_m4m4(group_mat, ob->obmat, group_mat);
- /* don't access 'ob->obmat' from now on. */
-
+
+ if (parent) {
+ /* combine group offset and obmat */
+ mul_m4_m4m4(group_mat, parent->obmat, group_mat);
+ /* don't access 'parent->obmat' from now on. */
+ }
+
/* handles animated groups */
-
+
/* we need to check update for objects that are not in scene... */
if (ctx->do_update) {
/* note: update is optional because we don't always need object
* transformations to be correct. Also fixes bug [#29616]. */
- BKE_group_handle_recalc_and_update(ctx->eval_ctx, ctx->scene, ob, group);
+ BKE_group_handle_recalc_and_update(ctx->eval_ctx, ctx->scene, parent, group);
}
-
- animated = BKE_group_is_animated(group, ob);
-
+
+ animated = BKE_group_is_animated(group, parent);
+
for (go = group->gobject.first, id = 0; go; go = go->next, id++) {
+ float mat[4][4];
+ bool hide;
+
/* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */
- if (go->ob != ob) {
- float mat[4][4];
-
- /* Special case for instancing dupli-groups, see: T40051
- * this object may be instanced via dupli-verts/faces, in this case we don't want to render
- * (blender convention), but _do_ show in the viewport.
- *
- * Regular objects work fine but not if we're instancing dupli-groups,
- * because the rules for rendering aren't applied to objects they instance.
- * We could recursively pass down the 'hide' flag instead, but that seems unnecessary.
- */
- if (for_render && go->ob->parent && go->ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES)) {
- continue;
- }
-
- /* group dupli offset, should apply after everything else */
- mul_m4_m4m4(mat, group_mat, go->ob->obmat);
-
- /* check the group instance and object layers match, also that the object visible flags are ok. */
- hide = (go->ob->lay & group->layer) == 0 ||
- (for_render ? go->ob->restrictflag & OB_RESTRICT_RENDER : go->ob->restrictflag & OB_RESTRICT_VIEW);
-
- make_dupli(ctx, go->ob, mat, id, animated, hide);
-
- /* recursion */
- make_recursive_duplis(ctx, go->ob, group_mat, id, animated);
+ if (go->ob == parent)
+ continue;
+
+ /* Special case for instancing dupli-groups, see: T40051
+ * this object may be instanced via dupli-verts/faces, in this case we don't want to render
+ * (blender convention), but _do_ show in the viewport.
+ *
+ * Regular objects work fine but not if we're instancing dupli-groups,
+ * because the rules for rendering aren't applied to objects they instance.
+ * We could recursively pass down the 'hide' flag instead, but that seems unnecessary.
+ */
+ if (for_render && go->ob->parent && go->ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES)) {
+ continue;
}
+
+ /* group dupli offset, should apply after everything else */
+ mul_m4_m4m4(mat, group_mat, go->ob->obmat);
+
+ /* check the group instance and object layers match, also that the object visible flags are ok. */
+ hide = (go->ob->lay & group->layer) == 0 ||
+ (for_render ? go->ob->restrictflag & OB_RESTRICT_RENDER : go->ob->restrictflag & OB_RESTRICT_VIEW);
+
+ make_dupli(ctx, go->ob, mat, id, animated, hide);
+
+ /* recursion */
+ make_recursive_duplis(ctx, go->ob, group_mat, id, animated);
}
}
+/* OB_DUPLIGROUP */
+static void make_duplis_group(const DupliContext *ctx)
+{
+ Object *ob = ctx->object;
+ if (!ob || !ob->dup_group)
+ return;
+
+ make_duplis_group_intern(ctx, ob->dup_group, ob);
+}
+
const DupliGenerator gen_dupli_group = {
OB_DUPLIGROUP, /* type */
make_duplis_group /* make_duplis */
@@ -331,8 +363,9 @@ static void make_duplis_frames(const DupliContext *ctx)
extern int enable_cu_speed; /* object.c */
Object copyob;
int cfrao = scene->r.cfra;
- int dupend = ob->dupend;
+ if (!ob)
+ return;
/* dupliframes not supported inside groups */
if (ctx->group)
return;
@@ -341,7 +374,7 @@ static void make_duplis_frames(const DupliContext *ctx)
*/
if (ob->parent == NULL && BLI_listbase_is_empty(&ob->constraints) && ob->adt == NULL)
return;
-
+
/* make a copy of the object's original data (before any dupli-data overwrites it)
* as we'll need this to keep track of unkeyed data
* - this doesn't take into account other data that can be reached from the object,
@@ -356,7 +389,7 @@ static void make_duplis_frames(const DupliContext *ctx)
* updates, as this is not a permanent change to the object */
ob->id.flag |= LIB_ANIM_NO_RECALC;
- for (scene->r.cfra = ob->dupsta; scene->r.cfra <= dupend; scene->r.cfra++) {
+ for (scene->r.cfra = ob->dupsta; scene->r.cfra <= ob->dupend; scene->r.cfra++) {
int ok = 1;
/* - dupoff = how often a frames within the range shouldn't be made into duplis
@@ -512,6 +545,9 @@ static void make_duplis_verts(const DupliContext *ctx)
Object *parent = ctx->object;
bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
VertexDupliData vdd;
+
+ if (!parent)
+ return;
vdd.ctx = ctx;
vdd.use_rotation = parent->transflag & OB_DUPLIROT;
@@ -592,6 +628,8 @@ static void make_duplis_font(const DupliContext *ctx)
const wchar_t *text = NULL;
bool text_free = false;
+ if (!par)
+ return;
/* font dupliverts not supported inside groups */
if (ctx->group)
return;
@@ -779,6 +817,9 @@ static void make_duplis_faces(const DupliContext *ctx)
bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
FaceDupliData fdd;
+ if (!parent)
+ return;
+
fdd.use_scale = ((parent->transflag & OB_DUPLIFACES_SCALE) != 0);
/* gather mesh info */
@@ -842,7 +883,8 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
int no_draw_flag = PARS_UNEXIST;
- if (psys == NULL) return;
+ if (!psys)
+ return;
part = psys->part;
@@ -983,7 +1025,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
/* for groups, pick the object based on settings */
if (part->draw & PART_DRAW_RAND_GR)
- b = BLI_rand() % totgroup;
+ b = (int)(psys_frand(psys, (unsigned int)(a + 974)) * (float)totgroup) % totgroup;
else
b = a % totgroup;
@@ -1123,6 +1165,9 @@ static void make_duplis_particles(const DupliContext *ctx)
ParticleSystem *psys;
int psysid;
+ if (!ctx->object)
+ return;
+
/* particle system take up one level in id, the particles another */
for (psys = ctx->object->particlesystem.first, psysid = 0; psys; psys = psys->next, psysid++) {
/* particles create one more level for persistent psys index */
@@ -1142,8 +1187,13 @@ const DupliGenerator gen_dupli_particles = {
/* select dupli generator from given context */
static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
{
- int transflag = ctx->object->transflag;
- int restrictflag = ctx->object->restrictflag;
+ int transflag, restrictflag;
+
+ if (!ctx->object)
+ return NULL;
+
+ transflag = ctx->object->transflag;
+ restrictflag = ctx->object->restrictflag;
if ((transflag & OB_DUPLI) == 0)
return NULL;
@@ -1183,15 +1233,36 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
/* Returns a list of DupliObject */
ListBase *object_duplilist_ex(EvaluationContext *eval_ctx, Scene *scene, Object *ob, bool update)
{
- ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist");
- DupliContext ctx;
- init_context(&ctx, eval_ctx, scene, ob, NULL, update);
- if (ctx.gen) {
- ctx.duplilist = duplilist;
- ctx.gen->make_duplis(&ctx);
+ if (update) {
+ BKE_object_dupli_cache_update(scene, ob, eval_ctx, (float)scene->r.cfra + scene->r.subframe);
+ }
+
+ if (ob->dup_cache && (ob->dup_cache->result != CACHE_READ_SAMPLE_INVALID)) {
+ /* Note: duplis in the cache don't have the main duplicator obmat applied.
+ * duplilist also should return a full copy of duplis, so we copy
+ * the cached list and apply the obmat to each.
+ */
+ ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist");
+ DupliObject *dob;
+
+ BLI_duplicatelist(duplilist, &ob->dup_cache->duplilist);
+
+ for (dob = duplilist->first; dob; dob = dob->next) {
+ mul_m4_m4m4(dob->mat, ob->obmat, dob->mat);
+ }
+
+ return duplilist;
+ }
+ else {
+ ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist");
+ DupliContext ctx;
+ init_context(&ctx, eval_ctx, scene, ob, update);
+ if (ctx.gen) {
+ ctx.duplilist = duplilist;
+ ctx.gen->make_duplis(&ctx);
+ }
+ return duplilist;
}
-
- return duplilist;
}
/* note: previously updating was always done, this is why it defaults to be on
@@ -1201,6 +1272,24 @@ ListBase *object_duplilist(EvaluationContext *eval_ctx, Scene *sce, Object *ob)
return object_duplilist_ex(eval_ctx, sce, ob, true);
}
+ListBase *group_duplilist_ex(EvaluationContext *eval_ctx, Scene *scene, Group *group, bool update)
+{
+ ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist");
+ DupliContext ctx;
+
+ init_context_ex(&ctx, eval_ctx, scene, NULL, NULL, &gen_dupli_group, update);
+ ctx.duplilist = duplilist;
+
+ make_duplis_group_intern(&ctx, group, NULL);
+
+ return duplilist;
+}
+
+ListBase *group_duplilist(EvaluationContext *eval_ctx, Scene *scene, Group *group)
+{
+ return group_duplilist_ex(eval_ctx, scene, group, true);
+}
+
void free_object_duplilist(ListBase *lb)
{
BLI_freelistN(lb);
@@ -1237,7 +1326,559 @@ int count_duplilist(Object *ob)
return 1;
}
-DupliApplyData *duplilist_apply(Object *ob, ListBase *duplilist)
+/* ------------------------------------------------------------------------- */
+
+static void dupli_cache_calc_boundbox(DupliObjectData *data)
+{
+ DupliObjectDataStrands *link;
+ float min[3], max[3];
+ bool has_data = false;
+
+ INIT_MINMAX(min, max);
+ if (data->dm) {
+ data->dm->getMinMax(data->dm, min, max);
+ has_data = true;
+ }
+ for (link = data->strands.first; link; link = link->next) {
+ if (link->strands) {
+ BKE_strands_get_minmax(link->strands, min, max, true);
+ has_data = true;
+ }
+ if (link->strands_children) {
+ BKE_strands_children_get_minmax(link->strands_children, min, max);
+ has_data = true;
+ }
+ }
+
+ if (!has_data) {
+ zero_v3(min);
+ zero_v3(max);
+ }
+
+ BKE_boundbox_init_from_minmax(&data->bb, min, max);
+}
+
+static bool UNUSED_FUNCTION(dupli_object_data_strands_unique_name)(ListBase *lb, DupliObjectDataStrands *link)
+{
+ if (lb && link) {
+ return BLI_uniquename(lb, link, DATA_("Strands"), '.', offsetof(DupliObjectDataStrands, name), sizeof(link->name));
+ }
+ return false;
+}
+
+void BKE_dupli_object_data_init(DupliObjectData *data, Object *ob)
+{
+ data->ob = ob;
+
+ data->dm = NULL;
+ BLI_listbase_clear(&data->strands);
+
+ memset(&data->bb, 0, sizeof(data->bb));
+ dupli_cache_calc_boundbox(data);
+}
+
+void BKE_dupli_object_data_clear(DupliObjectData *data)
+{
+ DupliObjectDataStrands *link;
+
+ if (data->dm) {
+ /* we lock DMs in the cache to prevent freeing outside,
+ * now allow releasing again
+ */
+ data->dm->needsFree = true;
+ data->dm->release(data->dm);
+ }
+
+ for (link = data->strands.first; link; link = link->next) {
+ if (link->strands)
+ BKE_strands_free(link->strands);
+ if (link->strands_children)
+ BKE_strands_children_free(link->strands_children);
+ }
+ BLI_freelistN(&data->strands);
+}
+
+void BKE_dupli_object_data_set_mesh(DupliObjectData *data, DerivedMesh *dm)
+{
+ if (data->dm) {
+ /* we lock DMs in the cache to prevent freeing outside,
+ * now allow releasing again
+ */
+ data->dm->needsFree = true;
+ data->dm->release(data->dm);
+ }
+
+ data->dm = dm;
+ /* we own this dm now and need to protect it until we free it ourselves */
+ dm->needsFree = false;
+
+ dupli_cache_calc_boundbox(data);
+}
+
+void BKE_dupli_object_data_add_strands(DupliObjectData *data, const char *name, Strands *strands)
+{
+ DupliObjectDataStrands *link = NULL;
+ for (link = data->strands.first; link; link = link->next) {
+ if (STREQ(link->name, name))
+ break;
+ }
+
+ if (!link) {
+ link = MEM_callocN(sizeof(DupliObjectDataStrands), "strands link");
+ BLI_strncpy(link->name, name, sizeof(link->name));
+ link->strands = strands;
+
+ BLI_addtail(&data->strands, link);
+ }
+ else {
+ if (link->strands && link->strands != strands)
+ BKE_strands_free(link->strands);
+ link->strands = strands;
+ }
+
+ dupli_cache_calc_boundbox(data);
+}
+
+void BKE_dupli_object_data_add_strands_children(DupliObjectData *data, const char *name, StrandsChildren *children)
+{
+ DupliObjectDataStrands *link = NULL;
+ for (link = data->strands.first; link; link = link->next) {
+ if (STREQ(link->name, name))
+ break;
+ }
+
+ if (!link) {
+ link = MEM_callocN(sizeof(DupliObjectDataStrands), "strands link");
+ BLI_strncpy(link->name, name, sizeof(link->name));
+ link->strands_children = children;
+
+ BLI_addtail(&data->strands, link);
+ }
+ else {
+ if (link->strands_children && link->strands_children != children)
+ BKE_strands_children_free(link->strands_children);
+ link->strands_children = children;
+ }
+
+ dupli_cache_calc_boundbox(data);
+}
+
+void BKE_dupli_object_data_find_strands(DupliObjectData *data, const char *name, Strands **r_strands, StrandsChildren **r_children)
+{
+ DupliObjectDataStrands *link;
+ for (link = data->strands.first; link; link = link->next) {
+ if (STREQ(link->name, name)) {
+ if (r_strands) *r_strands = link->strands;
+ if (r_children) *r_children = link->strands_children;
+ return;
+ }
+ }
+
+ if (r_strands) *r_strands = NULL;
+ if (r_children) *r_children = NULL;
+}
+
+bool BKE_dupli_object_data_acquire_strands(DupliObjectData *data, Strands *strands)
+{
+ DupliObjectDataStrands *link, *link_next;
+ bool found = false;
+
+ if (!data || !strands)
+ return false;
+
+ for (link = data->strands.first; link; link = link_next) {
+ link_next = link->next;
+ if (link->strands == strands) {
+ link->strands = NULL;
+ found = true;
+ }
+ }
+ return found;
+}
+
+bool BKE_dupli_object_data_acquire_strands_children(DupliObjectData *data, StrandsChildren *children)
+{
+ DupliObjectDataStrands *link, *link_next;
+ bool found = false;
+
+ if (!data || !children)
+ return false;
+
+ for (link = data->strands.first; link; link = link_next) {
+ link_next = link->next;
+ if (link->strands_children == children) {
+ link->strands_children = NULL;
+ found = true;
+ }
+ }
+ return found;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void dupli_object_data_free(DupliObjectData *data)
+{
+ BKE_dupli_object_data_clear(data);
+ MEM_freeN(data);
+}
+
+static void dupli_object_free(DupliObject *dob)
+{
+ MEM_freeN(dob);
+}
+
+DupliCache *BKE_dupli_cache_new(void)
+{
+ DupliCache *dupcache = MEM_callocN(sizeof(DupliCache), "dupli object cache");
+
+ dupcache->ghash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "dupli object data hash");
+
+ return dupcache;
+}
+
+void BKE_dupli_cache_free(DupliCache *dupcache)
+{
+ BKE_dupli_cache_clear(dupcache);
+
+ BLI_ghash_free(dupcache->ghash, NULL, (GHashValFreeFP)dupli_object_data_free);
+ MEM_freeN(dupcache);
+}
+
+void BKE_dupli_cache_clear(DupliCache *dupcache)
+{
+ DupliObject *dob, *dob_next;
+ for (dob = dupcache->duplilist.first; dob; dob = dob_next) {
+ dob_next = dob->next;
+
+ dupli_object_free(dob);
+ }
+ BLI_listbase_clear(&dupcache->duplilist);
+
+ BLI_ghash_clear(dupcache->ghash, NULL, (GHashValFreeFP)dupli_object_data_free);
+}
+
+void BKE_dupli_cache_clear_instances(DupliCache *dupcache)
+{
+ DupliObject *dob, *dob_next;
+ for (dob = dupcache->duplilist.first; dob; dob = dob_next) {
+ dob_next = dob->next;
+
+ dupli_object_free(dob);
+ }
+ BLI_listbase_clear(&dupcache->duplilist);
+}
+
+static DupliObjectData *dupli_cache_add_object_data(DupliCache *dupcache, Object *ob)
+{
+ DupliObjectData *data = MEM_callocN(sizeof(DupliObjectData), "dupli object data");
+
+ data->ob = ob;
+ BLI_ghash_insert(dupcache->ghash, data->ob, data);
+ return data;
+}
+
+static DupliObject *dupli_cache_add_object(DupliCache *dupcache)
+{
+ DupliObject *dob = MEM_callocN(sizeof(DupliObject), "dupli object");
+
+ unit_m4(dob->mat);
+
+ BLI_addtail(&dupcache->duplilist, dob);
+ return dob;
+}
+
+static int count_hair_verts(ParticleSystem *psys)
+{
+ int numverts = 0;
+ int p;
+ for (p = 0; p < psys->totpart; ++p) {
+ numverts += psys->particles[p].totkey;
+ }
+ return numverts;
+}
+
+static void dupli_strands_data_update(CacheLibrary *cachelib, DupliObjectData *data,
+ DupliObject *dob, bool calc_strands_base) {
+ ParticleSystem *psys;
+ for (psys = dob->ob->particlesystem.first; psys; psys = psys->next) {
+ if (cachelib->data_types & CACHE_TYPE_HAIR) {
+ if (psys->part && psys->part->type == PART_HAIR) {
+ int numstrands = psys->totpart;
+ int numverts = count_hair_verts(psys);
+ ParticleData *pa;
+ HairKey *hkey;
+ int p, k;
+
+ Strands *strands = BKE_strands_new(numstrands, numverts);
+ StrandsCurve *scurve = strands->curves;
+ StrandsVertex *svert = strands->verts;
+
+ for (p = 0, pa = psys->particles; p < psys->totpart; ++p, ++pa) {
+ float hairmat[4][4];
+ psys_mat_hair_to_object(dob->ob, data->dm, psys->part->from, pa, hairmat);
+
+ scurve->numverts = pa->totkey;
+ copy_m3_m4(scurve->root_matrix, hairmat);
+ BKE_mesh_sample_from_particle(&scurve->msurf, psys, data->dm, pa);
+
+ for (k = 0, hkey = pa->hair; k < pa->totkey; ++k, ++hkey) {
+ copy_v3_v3(svert->co, hkey->co);
+ if (calc_strands_base)
+ copy_v3_v3(svert->base, hkey->co);
+ svert->time = hkey->time;
+ svert->weight = hkey->weight;
+ ++svert;
+ }
+ ++scurve;
+ }
+
+ BKE_dupli_object_data_add_strands(data, psys->name, strands);
+ }
+ }
+ }
+}
+
+typedef struct DupliObjectDataFromGroupState {
+ EvaluationContext *eval_ctx;
+ Scene *scene;
+ CacheLibrary *cachelib;
+ bool calc_strands_base;
+} DupliObjectDataFromGroupState;
+
+typedef struct DupliObjectDataFromGroupTask {
+ DupliObject *dob;
+ DupliObjectData *data;
+} DupliObjectDataFromGroupTask;
+
+static void dupli_object_data_from_group_func(TaskPool *pool, void *taskdata, int UNUSED(threadid))
+{
+ DupliObjectDataFromGroupState *state = (DupliObjectDataFromGroupState *)BLI_task_pool_userdata(pool);
+ DupliObjectDataFromGroupTask *task = (DupliObjectDataFromGroupTask *)taskdata;
+ Object *object = task->dob->ob;
+ DerivedMesh *dm;
+
+ if (state->eval_ctx->mode == DAG_EVAL_RENDER) {
+ dm = mesh_create_derived_render(state->scene, object, CD_MASK_BAREMESH);
+ }
+ else {
+ dm = mesh_create_derived_view(state->scene, object, CD_MASK_BAREMESH);
+ }
+
+ if (dm != NULL) {
+ BKE_dupli_object_data_set_mesh(task->data, dm);
+ }
+
+ dupli_strands_data_update(state->cachelib, task->data, task->dob, state->calc_strands_base);
+}
+
+void BKE_dupli_cache_from_group(Scene *scene, Group *group, CacheLibrary *cachelib, DupliCache *dupcache, EvaluationContext *eval_ctx, bool calc_strands_base)
+{
+ DupliObject *dob;
+ TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool;
+ DupliObjectDataFromGroupState state;
+
+ BKE_dupli_cache_clear(dupcache);
+
+ if (!(group && cachelib))
+ return;
+
+ {
+ /* copy duplilist to the cache */
+ ListBase *duplilist = group_duplilist(eval_ctx, scene, group);
+ dupcache->duplilist = *duplilist;
+ MEM_freeN(duplilist);
+ }
+
+ state.eval_ctx = eval_ctx;
+ state.scene = scene;
+ state.cachelib = cachelib;
+ state.calc_strands_base = calc_strands_base;
+ task_pool = BLI_task_pool_create(task_scheduler, &state);
+
+ /* tag objects for which to store data */
+ BKE_cache_library_tag_used_objects(cachelib);
+
+ for (dob = dupcache->duplilist.first; dob; dob = dob->next) {
+ DupliObjectData *data = BKE_dupli_cache_find_data(dupcache, dob->ob);
+ if (!data) {
+ bool strands_handled = false;
+ data = dupli_cache_add_object_data(dupcache, dob->ob);
+
+ /* generate data only for filtered objects */
+ if (dob->ob->id.flag & LIB_DOIT) {
+ if (cachelib->data_types & CACHE_TYPE_DERIVED_MESH) {
+ if (dob->ob->type == OB_MESH) {
+ /* TODO(sergey): Consider using memory pool instead. */
+ DupliObjectDataFromGroupTask *task = MEM_mallocN(sizeof(DupliObjectDataFromGroupTask),
+ "dupcache task");
+ task->dob = dob;
+ task->data = data;
+ BLI_task_pool_push(task_pool, dupli_object_data_from_group_func, task, true, TASK_PRIORITY_LOW);
+ /* Task is getting care of strands as well. */
+ strands_handled = true;
+ }
+ }
+ if (!strands_handled) {
+ dupli_strands_data_update(cachelib, data, dob, calc_strands_base);
+ }
+ }
+ }
+ }
+
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void BKE_object_dupli_cache_update(Scene *scene, Object *ob, EvaluationContext *eval_ctx, float frame)
+{
+ bool use_render = (eval_ctx->mode == DAG_EVAL_RENDER);
+ bool is_dupligroup = (ob->transflag & OB_DUPLIGROUP) && ob->dup_group;
+ bool is_cached = ob->cache_library && (ob->cache_library->source_mode == CACHE_LIBRARY_SOURCE_CACHE || ob->cache_library->display_mode == CACHE_LIBRARY_DISPLAY_RESULT);
+ bool do_modifiers = ob->cache_library && ob->cache_library->display_mode == CACHE_LIBRARY_DISPLAY_MODIFIERS;
+
+ /* cache is a group duplicator feature only */
+ if (is_dupligroup && is_cached) {
+
+ if (ob->dup_cache && !(ob->dup_cache->flag & DUPCACHE_FLAG_DIRTY)) {
+ /* skip if cache is valid */
+ }
+ else {
+ if (G.debug & G_DEBUG)
+ printf("Update dupli cache for object '%s'\n", ob->id.name+2);
+
+ if (ob->dup_cache) {
+ BKE_dupli_cache_clear(ob->dup_cache);
+ }
+ else {
+ ob->dup_cache = BKE_dupli_cache_new();
+ }
+
+ /* skip reading when the cachelib is baking, avoids unnecessary memory allocation */
+ if (!(ob->cache_library->flag & CACHE_LIBRARY_BAKING)) {
+ bool do_strands_motion, do_strands_children;
+ CacheLibrary *cachelib = ob->cache_library;
+ CacheProcessData process_data;
+
+ BKE_cache_library_get_read_flags(ob->cache_library, use_render, true, &do_strands_motion, &do_strands_children);
+
+ /* TODO at this point we could apply animation offset */
+ BKE_cache_read_dupli_cache(ob->cache_library, ob->dup_cache, scene, ob->dup_group, frame, use_render, true);
+
+ process_data.lay = ob->lay;
+ copy_m4_m4(process_data.mat, ob->obmat);
+ process_data.dupcache = ob->dup_cache;
+
+ BKE_cache_process_dupli_cache(cachelib, &process_data, scene, ob->dup_group, (float)scene->r.cfra, frame, do_modifiers, do_strands_children, do_strands_motion);
+ }
+
+ ob->dup_cache->flag &= ~DUPCACHE_FLAG_DIRTY;
+ ob->dup_cache->cfra = frame;
+ }
+
+ }
+ else {
+ if (ob->dup_cache) {
+ BKE_dupli_cache_free(ob->dup_cache);
+ ob->dup_cache = NULL;
+ }
+ }
+}
+
+void BKE_object_dupli_cache_clear(Object *ob)
+{
+ if (ob->dup_cache) {
+ BKE_dupli_cache_clear(ob->dup_cache);
+ }
+}
+
+void BKE_object_dupli_cache_free(Object *ob)
+{
+ if (ob->dup_cache) {
+ BKE_dupli_cache_free(ob->dup_cache);
+ ob->dup_cache = NULL;
+ }
+}
+
+bool BKE_object_dupli_cache_contains(Object *ob, Object *other)
+{
+ if (ob->dup_cache) {
+ DupliObject *dob;
+ for (dob = ob->dup_cache->duplilist.first; dob; dob = dob->next) {
+ if (dob->ob == other)
+ return true;
+ }
+ }
+ return false;
+}
+
+
+DupliObjectData *BKE_dupli_cache_find_data(DupliCache *dupcache, Object *ob)
+{
+ DupliObjectData *data = BLI_ghash_lookup(dupcache->ghash, ob);
+ return data;
+}
+
+DupliObjectData *BKE_dupli_cache_add_object(DupliCache *dupcache, Object *ob)
+{
+ DupliObjectData *data = BKE_dupli_cache_find_data(dupcache, ob);
+ if (!data) {
+ data = dupli_cache_add_object_data(dupcache, ob);
+ }
+ return data;
+}
+
+DupliObject *BKE_dupli_cache_add_instance(DupliCache *dupcache, float obmat[4][4], DupliObjectData *data)
+{
+ DupliObject *dob = dupli_cache_add_object(dupcache);
+
+ /* data must have been created correctly */
+ BLI_assert(BLI_ghash_lookup(dupcache->ghash, data->ob) != NULL);
+
+ dob->ob = data->ob;
+ copy_m4_m4(dob->mat, obmat);
+
+ dob->data = data;
+
+ return dob;
+}
+
+/* ------------------------------------------------------------------------- */
+
+typedef struct DupliCacheIterator {
+ int unused;
+} DupliCacheIterator;
+
+DupliCacheIterator *BKE_dupli_cache_iter_new(struct DupliCache *dupcache)
+{
+ return (DupliCacheIterator *)BLI_ghashIterator_new(dupcache->ghash);
+}
+
+void BKE_dupli_cache_iter_free(DupliCacheIterator *iter)
+{
+ BLI_ghashIterator_free((GHashIterator *)iter);
+}
+
+bool BKE_dupli_cache_iter_valid(DupliCacheIterator *iter)
+{
+ return !BLI_ghashIterator_done((GHashIterator *)iter);
+}
+
+void BKE_dupli_cache_iter_next(DupliCacheIterator *iter)
+{
+ BLI_ghashIterator_step((GHashIterator *)iter);
+}
+
+DupliObjectData *BKE_dupli_cache_iter_get(DupliCacheIterator *iter)
+{
+ return BLI_ghashIterator_getValue((GHashIterator *)iter);
+}
+
+/* ------------------------------------------------------------------------- */
+
+DupliApplyData *duplilist_apply(Object *ob, Scene *scene, ListBase *duplilist)
{
DupliApplyData *apply_data = NULL;
int num_objects = BLI_listbase_count(duplilist);
@@ -1253,6 +1894,13 @@ DupliApplyData *duplilist_apply(Object *ob, ListBase *duplilist)
for (dob = duplilist->first, i = 0; dob; dob = dob->next, ++i) {
/* copy obmat from duplis */
copy_m4_m4(apply_data->extra[i].obmat, dob->ob->obmat);
+
+ /* make sure derivedmesh is calculated once, before drawing */
+ if (scene && !(dob->ob->transflag & OB_DUPLICALCDERIVED) && dob->ob->type == OB_MESH) {
+ mesh_get_derived_final(scene, dob->ob, scene->customdata_mask);
+ dob->ob->transflag |= OB_DUPLICALCDERIVED;
+ }
+
copy_m4_m4(dob->ob->obmat, dob->mat);
/* copy layers from the main duplicator object */
@@ -1273,6 +1921,7 @@ void duplilist_restore(ListBase *duplilist, DupliApplyData *apply_data)
*/
for (dob = duplilist->last, i = apply_data->num_objects - 1; dob; dob = dob->prev, --i) {
copy_m4_m4(dob->ob->obmat, apply_data->extra[i].obmat);
+ dob->ob->transflag &= ~OB_DUPLICALCDERIVED;
dob->ob->lay = apply_data->extra[i].lay;
}
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
new file mode 100644
index 00000000000..6752beb6d3b
--- /dev/null
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -0,0 +1,355 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 20014 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/object_update.c
+ * \ingroup bke
+ */
+
+#include "DNA_anim_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_group_types.h"
+#include "DNA_key_types.h"
+#include "DNA_material_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_threads.h"
+
+#include "BKE_global.h"
+#include "BKE_armature.h"
+#include "BKE_action.h"
+#include "BKE_constraint.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_animsys.h"
+#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_key.h"
+#include "BKE_lamp.h"
+#include "BKE_lattice.h"
+#include "BKE_editmesh.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_scene.h"
+#include "BKE_material.h"
+#include "BKE_image.h"
+
+#include "DEG_depsgraph.h"
+
+#ifdef WITH_LEGACY_DEPSGRAPH
+# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf
+#else
+# define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
+#endif
+
+static ThreadMutex material_lock = BLI_MUTEX_INITIALIZER;
+
+void BKE_object_eval_local_transform(EvaluationContext *UNUSED(eval_ctx),
+ Scene *UNUSED(scene),
+ Object *ob)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+
+ /* calculate local matrix */
+ BKE_object_to_mat4(ob, ob->obmat);
+}
+
+/* Evaluate parent */
+/* NOTE: based on solve_parenting(), but with the cruft stripped out */
+void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob)
+{
+ Object *par = ob->parent;
+
+ float totmat[4][4];
+ float tmat[4][4];
+ float locmat[4][4];
+
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+
+ /* get local matrix (but don't calculate it, as that was done already!) */
+ // XXX: redundant?
+ copy_m4_m4(locmat, ob->obmat);
+
+ /* get parent effect matrix */
+ BKE_object_get_parent_matrix(scene, ob, par, totmat);
+
+ /* total */
+ mul_m4_m4m4(tmat, totmat, ob->parentinv);
+ mul_m4_m4m4(ob->obmat, tmat, locmat);
+
+ /* origin, for help line */
+ if ((ob->partype & PARTYPE) == PARSKEL) {
+ copy_v3_v3(ob->orig, par->obmat[3]);
+ }
+ else {
+ copy_v3_v3(ob->orig, totmat[3]);
+ }
+}
+
+void BKE_object_eval_constraints(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob)
+{
+ bConstraintOb *cob;
+ float ctime = BKE_scene_frame_get(scene);
+
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+
+ /* evaluate constraints stack */
+ /* TODO: split this into:
+ * - pre (i.e. BKE_constraints_make_evalob, per-constraint (i.e.
+ * - inner body of BKE_constraints_solve),
+ * - post (i.e. BKE_constraints_clear_evalob)
+ *
+ * Not sure why, this is from Joshua - sergey
+ *
+ */
+ cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+ BKE_constraints_solve(&ob->constraints, cob, ctime);
+ BKE_constraints_clear_evalob(cob);
+}
+
+void BKE_object_eval_done(EvaluationContext *UNUSED(eval_ctx), Object *ob)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+
+ /* Set negative scale flag in object. */
+ if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE;
+ else ob->transflag &= ~OB_NEG_SCALE;
+}
+
+void BKE_object_eval_modifier(struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *ob,
+ struct ModifierData *md)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+ (void) eval_ctx; /* Ignored. */
+ (void) scene; /* Ignored. */
+ (void) ob; /* Ignored. */
+ (void) md; /* Ignored. */
+}
+
+void BKE_object_handle_data_update(EvaluationContext *eval_ctx,
+ Scene *scene,
+ Object *ob)
+{
+ ID *data_id = (ID *)ob->data;
+ AnimData *adt = BKE_animdata_from_id(data_id);
+ Key *key;
+ ParticleSystem *psys;
+ float ctime = BKE_scene_frame_get(scene);
+
+ if (G.debug & G_DEBUG_DEPSGRAPH)
+ printf("recalcdata %s\n", ob->id.name + 2);
+
+ /* TODO(sergey): Only used by legacy depsgraph. */
+ if (adt) {
+ /* evaluate drivers - datalevel */
+ /* XXX: for mesh types, should we push this to derivedmesh instead? */
+ BKE_animsys_evaluate_animdata(scene, data_id, adt, ctime, ADT_RECALC_DRIVERS);
+ }
+
+ /* TODO(sergey): Only used by legacy depsgraph. */
+ key = BKE_key_from_object(ob);
+ if (key && key->block.first) {
+ if (!(ob->shapeflag & OB_SHAPE_LOCK))
+ BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS);
+ }
+ for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ key = psys->key;
+ if (key && key->block.first) {
+ BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS);
+ }
+ }
+
+ /* includes all keys and modifiers */
+ switch (ob->type) {
+ case OB_MESH:
+ {
+ BMEditMesh *em = (ob == scene->obedit) ? BKE_editmesh_from_object(ob) : NULL;
+ uint64_t data_mask = scene->customdata_mask | CD_MASK_BAREMESH;
+#ifdef WITH_FREESTYLE
+ /* make sure Freestyle edge/face marks appear in DM for render (see T40315) */
+ if (eval_ctx->mode != DAG_EVAL_VIEWPORT) {
+ data_mask |= CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE;
+ }
+#endif
+ if (em) {
+ makeDerivedMesh(scene, ob, em, data_mask, 0); /* was CD_MASK_BAREMESH */
+ }
+ else {
+ makeDerivedMesh(scene, ob, NULL, data_mask, 0);
+ }
+ break;
+ }
+ case OB_ARMATURE:
+ if (ob->id.lib && 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);
+ }
+ }
+ else {
+ BKE_pose_where_is(scene, ob);
+ }
+ break;
+
+ case OB_MBALL:
+ BKE_displist_make_mball(eval_ctx, scene, ob);
+ break;
+
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_FONT:
+ BKE_displist_make_curveTypes(scene, ob, 0);
+ break;
+
+ case OB_LATTICE:
+ BKE_lattice_modifiers_calc(scene, ob);
+ break;
+
+ case OB_EMPTY:
+ if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data)
+ if (BKE_image_is_animated(ob->data))
+ BKE_image_user_check_frame_calc(ob->iuser, (int)ctime, 0);
+ break;
+ }
+
+ /* related materials */
+ /* XXX: without depsgraph tagging, this will always need to be run, which will be slow!
+ * However, not doing anything (or trying to hack around this lack) is not an option
+ * anymore, especially due to Cycles [#31834]
+ */
+ if (ob->totcol) {
+ int a;
+ if (ob->totcol != 0) {
+ BLI_mutex_lock(&material_lock);
+ for (a = 1; a <= ob->totcol; a++) {
+ Material *ma = give_current_material(ob, a);
+ if (ma) {
+ /* recursively update drivers for this material */
+ material_drivers_update(scene, ma, ctime);
+ }
+ }
+ BLI_mutex_unlock(&material_lock);
+ }
+ }
+ else if (ob->type == OB_LAMP)
+ lamp_drivers_update(scene, ob->data, ctime);
+
+ /* particles */
+ if (ob != scene->obedit && ob->particlesystem.first) {
+ ParticleSystem *tpsys, *psys;
+ DerivedMesh *dm;
+ ob->transflag &= ~OB_DUPLIPARTS;
+ psys = ob->particlesystem.first;
+ while (psys) {
+ /* ensure this update always happens even if psys is disabled */
+ if (psys->recalc & PSYS_RECALC_TYPE) {
+ psys_changed_type(ob, psys);
+ }
+
+ if (psys_check_enabled(ob, psys)) {
+ /* check use of dupli objects here */
+ if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) &&
+ ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) ||
+ (psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group)))
+ {
+ ob->transflag |= OB_DUPLIPARTS;
+ }
+
+ particle_system_update(scene, ob, psys);
+ psys = psys->next;
+ }
+ else if (psys->flag & PSYS_DELETE) {
+ tpsys = psys->next;
+ BLI_remlink(&ob->particlesystem, psys);
+ psys_free(ob, psys);
+ psys = tpsys;
+ }
+ else
+ psys = psys->next;
+ }
+
+ if (eval_ctx->mode == DAG_EVAL_RENDER && ob->transflag & OB_DUPLIPARTS) {
+ /* this is to make sure we get render level duplis in groups:
+ * the derivedmesh must be created before init_render_mesh,
+ * since object_duplilist does dupliparticles before that */
+ dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
+ dm->release(dm);
+
+ for (psys = ob->particlesystem.first; psys; psys = psys->next)
+ psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
+ }
+ }
+
+ /* quick cache removed */
+}
+
+void BKE_object_eval_uber_transform(EvaluationContext *UNUSED(eval_ctx),
+ Scene *UNUSED(scene),
+ Object *ob)
+{
+ /* TODO(sergey): Currently it's a duplicate of logic in BKE_object_handle_update_ex(). */
+ // XXX: it's almost redundant now...
+
+ /* Handle proxy copy for target, */
+ if (ob->id.lib && ob->proxy_from) {
+ if (ob->proxy_from->proxy_group) {
+ /* Transform proxy into group space. */
+ Object *obg = ob->proxy_from->proxy_group;
+ float imat[4][4];
+ invert_m4_m4(imat, obg->obmat);
+ mul_m4_m4m4(ob->obmat, imat, ob->proxy_from->obmat);
+ /* Should always be true. */
+ if (obg->dup_group) {
+ add_v3_v3(ob->obmat[3], obg->dup_group->dupli_ofs);
+ }
+ }
+ else
+ copy_m4_m4(ob->obmat, ob->proxy_from->obmat);
+ }
+
+ ob->recalc &= ~(OB_RECALC_OB | OB_RECALC_TIME);
+ if (ob->data == NULL) {
+ ob->recalc &= ~OB_RECALC_DATA;
+ }
+}
+
+void BKE_object_eval_uber_data(EvaluationContext *eval_ctx,
+ Scene *scene,
+ Object *ob)
+{
+ DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
+ BLI_assert(ob->type != OB_ARMATURE);
+ BKE_object_handle_data_update(eval_ctx, scene, ob);
+
+ ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME);
+}
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 12e82d3a34f..1a178fb2bdf 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -494,7 +494,7 @@ void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j)
BLI_rw_mutex_unlock(&oc->oceanmutex);
}
-void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount)
+void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount)
{
int i, j;
@@ -732,14 +732,14 @@ static void set_height_normalize_factor(struct Ocean *oc)
oc->normalize_factor = 1.0;
- BKE_simulate_ocean(oc, 0.0, 1.0, 0);
+ BKE_ocean_simulate(oc, 0.0, 1.0, 0);
BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
for (i = 0; i < oc->_M; ++i) {
for (j = 0; j < oc->_N; ++j) {
- if (max_h < fabsf(oc->_disp_y[i * oc->_N + j])) {
- max_h = fabsf(oc->_disp_y[i * oc->_N + j]);
+ if (max_h < fabs(oc->_disp_y[i * oc->_N + j])) {
+ max_h = fabs(oc->_disp_y[i * oc->_N + j]);
}
}
}
@@ -754,7 +754,7 @@ static void set_height_normalize_factor(struct Ocean *oc)
oc->normalize_factor = res;
}
-struct Ocean *BKE_add_ocean(void)
+struct Ocean *BKE_ocean_add(void)
{
Ocean *oc = MEM_callocN(sizeof(Ocean), "ocean sim data");
@@ -763,7 +763,7 @@ struct Ocean *BKE_add_ocean(void)
return oc;
}
-void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp,
+void BKE_ocean_init(struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp,
float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals,
short do_jacobian, int seed)
{
@@ -900,7 +900,7 @@ void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V,
BLI_rng_free(rng);
}
-void BKE_free_ocean_data(struct Ocean *oc)
+void BKE_ocean_free_data(struct Ocean *oc)
{
if (!oc) return;
@@ -962,11 +962,11 @@ void BKE_free_ocean_data(struct Ocean *oc)
BLI_rw_mutex_unlock(&oc->oceanmutex);
}
-void BKE_free_ocean(struct Ocean *oc)
+void BKE_ocean_free(struct Ocean *oc)
{
if (!oc) return;
- BKE_free_ocean_data(oc);
+ BKE_ocean_free_data(oc);
BLI_rw_mutex_end(&oc->oceanmutex);
MEM_freeN(oc);
@@ -1002,7 +1002,7 @@ static void cache_filename(char *string, const char *path, const char *relbase,
BLI_join_dirfile(cachepath, sizeof(cachepath), path, fname);
- BKE_image_path_from_imtype(string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true);
+ BKE_image_path_from_imtype(string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true, "");
}
/* silly functions but useful to inline when the args do a lot of indirections */
@@ -1021,7 +1021,7 @@ MINLINE void value_to_rgba_unit_alpha(float r_rgba[4], const float value)
r_rgba[3] = 1.0f;
}
-void BKE_free_ocean_cache(struct OceanCache *och)
+void BKE_ocean_free_cache(struct OceanCache *och)
{
int i, f = 0;
@@ -1111,7 +1111,7 @@ void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, in
}
}
-struct OceanCache *BKE_init_ocean_cache(const char *bakepath, const char *relbase, int start, int end, float wave_scale,
+struct OceanCache *BKE_ocean_init_cache(const char *bakepath, const char *relbase, int start, int end, float wave_scale,
float chop_amount, float foam_coverage, float foam_fade, int resolution)
{
OceanCache *och = MEM_callocN(sizeof(OceanCache), "ocean cache data");
@@ -1138,7 +1138,7 @@ struct OceanCache *BKE_init_ocean_cache(const char *bakepath, const char *relbas
return och;
}
-void BKE_simulate_ocean_cache(struct OceanCache *och, int frame)
+void BKE_ocean_simulate_cache(struct OceanCache *och, int frame)
{
char string[FILE_MAX];
int f = frame;
@@ -1182,7 +1182,7 @@ void BKE_simulate_ocean_cache(struct OceanCache *och, int frame)
}
-void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel),
+void BKE_ocean_bake(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel),
void *update_cb_data)
{
/* note: some of these values remain uninitialized unless certain options
@@ -1221,7 +1221,7 @@ void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(v
ibuf_disp = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat);
ibuf_normal = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat);
- BKE_simulate_ocean(o, och->time[i], och->wave_scale, och->chop_amount);
+ BKE_ocean_simulate(o, och->time[i], och->wave_scale, och->chop_amount);
/* add new foam */
for (y = 0; y < res_y; y++) {
@@ -1371,29 +1371,29 @@ void BKE_ocean_eval_ij(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr)
{
}
-void BKE_simulate_ocean(struct Ocean *UNUSED(o), float UNUSED(t), float UNUSED(scale), float UNUSED(chop_amount))
+void BKE_ocean_simulate(struct Ocean *UNUSED(o), float UNUSED(t), float UNUSED(scale), float UNUSED(chop_amount))
{
}
-struct Ocean *BKE_add_ocean(void)
+struct Ocean *BKE_ocean_add(void)
{
Ocean *oc = MEM_callocN(sizeof(Ocean), "ocean sim data");
return oc;
}
-void BKE_init_ocean(struct Ocean *UNUSED(o), int UNUSED(M), int UNUSED(N), float UNUSED(Lx), float UNUSED(Lz),
+void BKE_ocean_init(struct Ocean *UNUSED(o), int UNUSED(M), int UNUSED(N), float UNUSED(Lx), float UNUSED(Lz),
float UNUSED(V), float UNUSED(l), float UNUSED(A), float UNUSED(w), float UNUSED(damp),
float UNUSED(alignment), float UNUSED(depth), float UNUSED(time), short UNUSED(do_height_field),
short UNUSED(do_chop), short UNUSED(do_normals), short UNUSED(do_jacobian), int UNUSED(seed))
{
}
-void BKE_free_ocean_data(struct Ocean *UNUSED(oc))
+void BKE_ocean_free_data(struct Ocean *UNUSED(oc))
{
}
-void BKE_free_ocean(struct Ocean *oc)
+void BKE_ocean_free(struct Ocean *oc)
{
if (!oc) return;
MEM_freeN(oc);
@@ -1403,7 +1403,7 @@ void BKE_free_ocean(struct Ocean *oc)
/* ********* Baking/Caching ********* */
-void BKE_free_ocean_cache(struct OceanCache *och)
+void BKE_ocean_free_cache(struct OceanCache *och)
{
if (!och) return;
@@ -1420,7 +1420,7 @@ void BKE_ocean_cache_eval_ij(struct OceanCache *UNUSED(och), struct OceanResult
{
}
-OceanCache *BKE_init_ocean_cache(const char *UNUSED(bakepath), const char *UNUSED(relbase), int UNUSED(start),
+OceanCache *BKE_ocean_init_cache(const char *UNUSED(bakepath), const char *UNUSED(relbase), int UNUSED(start),
int UNUSED(end), float UNUSED(wave_scale), float UNUSED(chop_amount),
float UNUSED(foam_coverage), float UNUSED(foam_fade), int UNUSED(resolution))
{
@@ -1429,11 +1429,11 @@ OceanCache *BKE_init_ocean_cache(const char *UNUSED(bakepath), const char *UNUSE
return och;
}
-void BKE_simulate_ocean_cache(struct OceanCache *UNUSED(och), int UNUSED(frame))
+void BKE_ocean_simulate_cache(struct OceanCache *UNUSED(och), int UNUSED(frame))
{
}
-void BKE_bake_ocean(struct Ocean *UNUSED(o), struct OceanCache *UNUSED(och),
+void BKE_ocean_bake(struct Ocean *UNUSED(o), struct OceanCache *UNUSED(och),
void (*update_cb)(void *, float progress, int *cancel), void *UNUSED(update_cb_data))
{
/* unused */
diff --git a/source/blender/blenkernel/intern/treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c
index 866502c4ae1..f31ba34a984 100644
--- a/source/blender/blenkernel/intern/treehash.c
+++ b/source/blender/blenkernel/intern/outliner_treehash.c
@@ -20,7 +20,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file treehash.c
+/** \file outliner_treehash.c
* \ingroup bke
*
* Tree hash for the outliner space.
@@ -28,7 +28,7 @@
#include <stdlib.h>
-#include "BKE_treehash.h"
+#include "BKE_outliner_treehash.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -38,8 +38,7 @@
#include "MEM_guardedalloc.h"
-typedef struct TseGroup
-{
+typedef struct TseGroup {
TreeStoreElem **elems;
int size;
int allocated;
@@ -103,12 +102,15 @@ static void fill_treehash(void *treehash, BLI_mempool *treestore)
TreeStoreElem *tselem;
BLI_mempool_iter iter;
BLI_mempool_iternew(treestore, &iter);
+
+ BLI_assert(treehash);
+
while ((tselem = BLI_mempool_iterstep(&iter))) {
- BKE_treehash_add_element(treehash, tselem);
+ BKE_outliner_treehash_add_element(treehash, tselem);
}
}
-void *BKE_treehash_create_from_treestore(BLI_mempool *treestore)
+void *BKE_outliner_treehash_create_from_treestore(BLI_mempool *treestore)
{
GHash *treehash = BLI_ghash_new_ex(tse_hash, tse_cmp, "treehash", BLI_mempool_count(treestore));
fill_treehash(treehash, treestore);
@@ -120,35 +122,46 @@ static void free_treehash_group(void *key)
tse_group_free(key);
}
-void *BKE_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore)
+void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore)
{
+ BLI_assert(treehash);
+
BLI_ghash_clear_ex(treehash, NULL, free_treehash_group, BLI_mempool_count(treestore));
fill_treehash(treehash, treestore);
return treehash;
}
-void BKE_treehash_add_element(void *treehash, TreeStoreElem *elem)
+void BKE_outliner_treehash_add_element(void *treehash, TreeStoreElem *elem)
{
- TseGroup *group = BLI_ghash_lookup(treehash, elem);
- if (!group) {
- group = tse_group_create();
- BLI_ghash_insert(treehash, elem, group);
+ TseGroup *group;
+ void **val_p;
+
+ if (!BLI_ghash_ensure_p(treehash, elem, &val_p)) {
+ *val_p = tse_group_create();
}
+ group = *val_p;
tse_group_add(group, elem);
}
-static TseGroup *BKE_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id)
+static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id)
{
TreeStoreElem tse_template;
tse_template.type = type;
tse_template.nr = type ? nr : 0; // we're picky! :)
tse_template.id = id;
+
+ BLI_assert(th);
+
return BLI_ghash_lookup(th, &tse_template);
}
-TreeStoreElem *BKE_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id)
+TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id)
{
- TseGroup *group = BKE_treehash_lookup_group(treehash, type, nr, id);
+ TseGroup *group;
+
+ BLI_assert(treehash);
+
+ group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id);
if (group) {
int i;
for (i = 0; i < group->size; i++) {
@@ -160,13 +173,19 @@ TreeStoreElem *BKE_treehash_lookup_unused(void *treehash, short type, short nr,
return NULL;
}
-TreeStoreElem *BKE_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id)
+TreeStoreElem *BKE_outliner_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id)
{
- TseGroup *group = BKE_treehash_lookup_group(treehash, type, nr, id);
+ TseGroup *group;
+
+ BLI_assert(treehash);
+
+ group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id);
return group ? group->elems[0] : NULL;
}
-void BKE_treehash_free(void *treehash)
+void BKE_outliner_treehash_free(void *treehash)
{
+ BLI_assert(treehash);
+
BLI_ghash_free(treehash, NULL, free_treehash_group);
}
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 8d56b1247fe..800df252c69 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -128,8 +128,8 @@ int countPackedFiles(Main *bmain)
/* let's check if there are packed files... */
for (ima = bmain->image.first; ima; ima = ima->id.next)
- if (ima->packedfile)
- count++;
+ if (BKE_image_has_packedfile(ima))
+ count ++;
for (vf = bmain->vfont.first; vf; vf = vf->id.next)
if (vf->packedfile)
@@ -224,7 +224,7 @@ PackedFile *newPackedFile(ReportList *reports, const char *filename, const char
}
/* no libraries for now */
-void packAll(Main *bmain, ReportList *reports)
+void packAll(Main *bmain, ReportList *reports, bool verbose)
{
Image *ima;
VFont *vfont;
@@ -232,12 +232,12 @@ void packAll(Main *bmain, ReportList *reports)
int tot = 0;
for (ima = bmain->image.first; ima; ima = ima->id.next) {
- if (ima->packedfile == NULL && ima->id.lib == NULL) {
+ if (BKE_image_has_packedfile(ima) == false && ima->id.lib == NULL) {
if (ima->source == IMA_SRC_FILE) {
- ima->packedfile = newPackedFile(reports, ima->name, ID_BLEND_PATH(bmain, &ima->id));
+ BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
tot ++;
}
- else if (BKE_image_is_animated(ima)) {
+ else if (BKE_image_is_animated(ima) && verbose) {
BKE_reportf(reports, RPT_WARNING, "Image '%s' skipped, movies and image sequences not supported",
ima->id.name + 2);
}
@@ -258,10 +258,10 @@ void packAll(Main *bmain, ReportList *reports)
}
}
- if (tot == 0)
- BKE_report(reports, RPT_INFO, "No new files have been packed");
- else
+ if (tot > 0)
BKE_reportf(reports, RPT_INFO, "Packed %d files", tot);
+ else if (verbose)
+ BKE_report(reports, RPT_INFO, "No new files have been packed");
}
@@ -478,7 +478,7 @@ char *unpackFile(ReportList *reports, const char *abs_name, const char *local_na
}
static void unpack_generate_paths(
- const char *name, ID *id, char *abspath_r, char *relpath_r, size_t abspathlen, size_t relpathlen)
+ const char *name, ID *id, char *r_abspath, char *r_relpath, size_t abspathlen, size_t relpathlen)
{
char tempname[FILE_MAX];
char tempdir[FILE_MAXDIR];
@@ -500,19 +500,19 @@ static void unpack_generate_paths(
switch (GS(id->name)) {
case ID_VF:
- BLI_snprintf(relpath_r, relpathlen, "//fonts/%s", tempname);
+ BLI_snprintf(r_relpath, relpathlen, "//fonts/%s", tempname);
break;
case ID_SO:
- BLI_snprintf(relpath_r, relpathlen, "//sounds/%s", tempname);
+ BLI_snprintf(r_relpath, relpathlen, "//sounds/%s", tempname);
break;
case ID_IM:
- BLI_snprintf(relpath_r, relpathlen, "//textures/%s", tempname);
+ BLI_snprintf(r_relpath, relpathlen, "//textures/%s", tempname);
break;
}
{
- size_t len = BLI_strncpy_rlen(abspath_r, tempdir, abspathlen);
- BLI_strncpy(abspath_r + len, tempname, abspathlen - len);
+ size_t len = BLI_strncpy_rlen(r_abspath, tempdir, abspathlen);
+ BLI_strncpy(r_abspath + len, tempname, abspathlen - len);
}
}
@@ -553,7 +553,7 @@ int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how)
freePackedFile(sound->packedfile);
sound->packedfile = NULL;
- sound_load(bmain, sound);
+ BKE_sound_load(bmain, sound);
ret_value = RET_OK;
}
@@ -564,23 +564,47 @@ int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how)
int unpackImage(ReportList *reports, Image *ima, int how)
{
- char localname[FILE_MAX], absname[FILE_MAX];
- char *newname;
int ret_value = RET_ERROR;
-
+
if (ima != NULL && ima->name[0]) {
- unpack_generate_paths(ima->name, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname));
- newname = unpackFile(reports, absname, localname, ima->packedfile, how);
- if (newname != NULL) {
- ret_value = RET_OK;
- freePackedFile(ima->packedfile);
- ima->packedfile = NULL;
- BLI_strncpy(ima->name, newname, sizeof(ima->name));
- MEM_freeN(newname);
- BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
+ while (ima->packedfiles.last) {
+ char localname[FILE_MAX], absname[FILE_MAX];
+ char *newname;
+ ImagePackedFile *imapf = ima->packedfiles.last;
+
+ unpack_generate_paths(imapf->filepath, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname));
+ newname = unpackFile(reports, absname, localname, imapf->packedfile, how);
+
+ if (newname != NULL) {
+ ImageView *iv;
+
+ ret_value = ret_value == RET_ERROR ? RET_ERROR : RET_OK;
+ freePackedFile(imapf->packedfile);
+ imapf->packedfile = NULL;
+
+ /* update the new corresponding view filepath */
+ iv = BLI_findstring(&ima->views, imapf->filepath, offsetof(ImageView, filepath));
+ if (iv) {
+ BLI_strncpy(iv->filepath, newname, sizeof(imapf->filepath));
+ }
+
+ /* keep the new name in the image for non-pack specific reasons */
+ BLI_strncpy(ima->name, newname, sizeof(imapf->filepath));
+ MEM_freeN(newname);
+ }
+ else {
+ ret_value = RET_ERROR;
+ }
+
+ BLI_remlink(&ima->packedfiles, imapf);
+ MEM_freeN(imapf);
}
}
-
+
+ if (ret_value == RET_OK) {
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
+ }
+
return(ret_value);
}
@@ -636,7 +660,7 @@ void unpackAll(Main *bmain, ReportList *reports, int how)
bSound *sound;
for (ima = bmain->image.first; ima; ima = ima->id.next)
- if (ima->packedfile)
+ if (BKE_image_has_packedfile(ima))
unpackImage(reports, ima, how);
for (vf = bmain->vfont.first; vf; vf = vf->id.next)
@@ -655,7 +679,7 @@ bool BKE_pack_check(ID *id)
case ID_IM:
{
Image *ima = (Image *)id;
- return ima->packedfile != NULL;
+ return BKE_image_has_packedfile(ima);
}
case ID_VF:
{
@@ -683,7 +707,7 @@ void BKE_unpack_id(Main *bmain, ID *id, ReportList *reports, int how)
case ID_IM:
{
Image *ima = (Image *)id;
- if (ima->packedfile) {
+ if (BKE_image_has_packedfile(ima)) {
unpackImage(reports, ima, how);
}
break;
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 431eec0d220..0bda740af53 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -313,25 +313,33 @@ void BKE_paint_curve_set(Brush *br, PaintCurve *pc)
}
}
+void BKE_paint_curve_clamp_endpoint_add_index(PaintCurve *pc, const int add_index)
+{
+ pc->add_index = (add_index || pc->tot_points == 1) ? (add_index + 1) : 0;
+}
+
/* remove colour from palette. Must be certain color is inside the palette! */
void BKE_palette_color_remove(Palette *palette, PaletteColor *color)
{
- if (color) {
- int numcolors = BLI_listbase_count(&palette->colors);
- if ((numcolors == palette->active_color + 1) && (numcolors != 1))
- palette->active_color--;
-
- BLI_remlink(&palette->colors, color);
- BLI_addhead(&palette->deleted, color);
+ if (BLI_listbase_count_ex(&palette->colors, palette->active_color) == palette->active_color) {
+ palette->active_color--;
}
+
+ BLI_remlink(&palette->colors, color);
+
+ if (palette->active_color < 0 && !BLI_listbase_is_empty(&palette->colors)) {
+ palette->active_color = 0;
+ }
+
+ MEM_freeN(color);
}
-void BKE_palette_cleanup(Palette *palette)
+void BKE_palette_clear(Palette *palette)
{
- BLI_freelistN(&palette->deleted);
+ BLI_freelistN(&palette->colors);
+ palette->active_color = 0;
}
-
Palette *BKE_palette_add(Main *bmain, const char *name)
{
Palette *palette;
@@ -353,7 +361,6 @@ PaletteColor *BKE_palette_color_add(Palette *palette)
{
PaletteColor *color = MEM_callocN(sizeof(*color), "Pallete Color");
BLI_addtail(&palette->colors, color);
- palette->active_color = BLI_listbase_count(&palette->colors) - 1;
return color;
}
@@ -512,7 +519,7 @@ float paint_grid_paint_mask(const GridPaintMask *gpm, unsigned level,
/* threshold to move before updating the brush rotation */
#define RAKE_THRESHHOLD 20
-static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, float rotation)
+void paint_update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, float rotation)
{
if (brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)
ups->brush_rotation = rotation;
@@ -520,7 +527,6 @@ static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush,
ups->brush_rotation = 0.0f;
if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)
- /* here, translation contains the mouse coordinates. */
ups->brush_rotation_sec = rotation;
else
ups->brush_rotation_sec = 0.0f;
@@ -529,7 +535,6 @@ static void update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush,
void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, const float mouse_pos[2])
{
if ((brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
- const float u = 0.5f;
const float r = RAKE_THRESHHOLD;
float rotation;
@@ -539,17 +544,16 @@ void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, cons
if (len_squared_v2(dpos) >= r * r) {
rotation = atan2f(dpos[0], dpos[1]);
- interp_v2_v2v2(ups->last_rake, ups->last_rake,
- mouse_pos, u);
+ copy_v2_v2(ups->last_rake, mouse_pos);
ups->last_rake_angle = rotation;
- update_brush_rake_rotation(ups, brush, rotation);
+ paint_update_brush_rake_rotation(ups, brush, rotation);
}
/* make sure we reset here to the last rotation to avoid accumulating
* values in case a random rotation is also added */
else {
- update_brush_rake_rotation(ups, brush, ups->last_rake_angle);
+ paint_update_brush_rake_rotation(ups, brush, ups->last_rake_angle);
}
}
else {
@@ -557,15 +561,11 @@ void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, cons
}
}
-void BKE_free_sculptsession_deformMats(SculptSession *ss)
+void BKE_sculptsession_free_deformMats(SculptSession *ss)
{
- if (ss->orig_cos) MEM_freeN(ss->orig_cos);
- if (ss->deform_cos) MEM_freeN(ss->deform_cos);
- if (ss->deform_imats) MEM_freeN(ss->deform_imats);
-
- ss->orig_cos = NULL;
- ss->deform_cos = NULL;
- ss->deform_imats = NULL;
+ MEM_SAFE_FREE(ss->orig_cos);
+ MEM_SAFE_FREE(ss->deform_cos);
+ MEM_SAFE_FREE(ss->deform_imats);
}
/* Write out the sculpt dynamic-topology BMesh to the Mesh */
@@ -624,7 +624,7 @@ void BKE_sculptsession_bm_to_me_for_render(Object *object)
}
}
-void BKE_free_sculptsession(Object *ob)
+void BKE_sculptsession_free(Object *ob)
{
if (ob && ob->sculpt) {
SculptSession *ss = ob->sculpt;
@@ -718,7 +718,7 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
/* exception for shape keys because we can edit those */
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
if (ELEM(md->type, eModifierType_ShapeKey, eModifierType_Multires)) continue;
@@ -765,7 +765,12 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
}
/* BMESH ONLY --- at some point we should move sculpt code to use polygons only - but for now it needs tessfaces */
- BKE_mesh_tessface_ensure(me);
+ if (ss->bm) {
+ BKE_mesh_tessface_clear(me);
+ }
+ else {
+ BKE_mesh_tessface_ensure(me);
+ }
if (!mmd) ss->kb = BKE_keyblock_from_object(ob);
else ss->kb = NULL;
@@ -780,7 +785,6 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
ss->mvert = NULL;
ss->mpoly = NULL;
ss->mloop = NULL;
- ss->face_normals = NULL;
}
else {
ss->totvert = me->totvert;
@@ -788,7 +792,6 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
ss->mvert = me->mvert;
ss->mpoly = me->mpoly;
ss->mloop = me->mloop;
- ss->face_normals = NULL;
ss->multires = NULL;
ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
}
@@ -802,7 +805,7 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
if (!ss->orig_cos) {
int a;
- BKE_free_sculptsession_deformMats(ss);
+ BKE_sculptsession_free_deformMats(ss);
ss->orig_cos = (ss->kb) ? BKE_keyblock_convert_to_vertcos(ob, ss->kb) : BKE_mesh_vertexCos_get(me, NULL);
@@ -815,7 +818,7 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
}
}
else {
- BKE_free_sculptsession_deformMats(ss);
+ BKE_sculptsession_free_deformMats(ss);
}
if (ss->kb != NULL && ss->deform_cos == NULL) {
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index f081c964bdd..a928ed69b9e 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -65,6 +65,7 @@
#include "BKE_boids.h"
#include "BKE_cloth.h"
#include "BKE_colortools.h"
+#include "BKE_editstrands.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_group.h"
@@ -103,6 +104,8 @@ void psys_init_rng(void)
static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx,
ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex);
+static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSettings *part, ParticleData *par,
+ int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra);
extern void do_child_modifiers(ParticleSimulationData *sim,
ParticleTexture *ptex, const float par_co[3], const float par_vel[3], const float par_rot[4], const float par_orco[3],
ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t);
@@ -405,7 +408,7 @@ void BKE_particlesettings_free(ParticleSettings *part)
{
MTex *mtex;
int a;
- BKE_free_animdata(&part->id);
+ BKE_animdata_free(&part->id);
if (part->clumpcurve)
curvemapping_free(part->clumpcurve);
@@ -576,6 +579,11 @@ void psys_free(Object *ob, ParticleSystem *psys)
if (psys->edit && psys->free_edit)
psys->free_edit(psys->edit);
+ if (psys->hairedit) {
+ BKE_editstrands_free(psys->hairedit);
+ MEM_freeN(psys->hairedit);
+ psys->hairedit = NULL;
+ }
if (psys->child) {
MEM_freeN(psys->child);
@@ -1173,6 +1181,11 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_
return 1;
}
+int psys_get_index_on_dm(ParticleSystem *psys, DerivedMesh *dm, ParticleData *pa, int *mapindex, float mapfw[4])
+{
+ return psys_map_index_on_dm(dm, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, mapindex, mapfw);
+}
+
/* interprets particle data to get a point on a mesh in object space */
void psys_particle_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache,
const float fw[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
@@ -1599,9 +1612,11 @@ float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup)
}
void psys_find_parents(ParticleSimulationData *sim)
{
+ ParticleSystem *psys = sim->psys;
ParticleSettings *part = sim->psys->part;
KDTree *tree;
ChildParticle *cpa;
+ ParticleTexture ptex;
int p, totparent, totchild = sim->psys->totchild;
float co[3], orco[3];
int from = PART_FROM_FACE;
@@ -1619,7 +1634,13 @@ void psys_find_parents(ParticleSimulationData *sim)
for (p = 0, cpa = sim->psys->child; p < totparent; p++, cpa++) {
psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco, 0);
- BLI_kdtree_insert(tree, p, orco);
+
+ /* Check if particle doesn't exist because of texture influence. Insert only existing particles into kdtree. */
+ get_cpa_texture(sim->psmd->dm, psys, part, psys->particles + cpa->pa[0], p, cpa->num, cpa->fuv, orco, &ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
+
+ if (ptex.exist >= psys_frand(psys, p + 24)) {
+ BLI_kdtree_insert(tree, p, orco);
+ }
}
BLI_kdtree_balance(tree);
@@ -1646,7 +1667,7 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi
if (psys_in_edit_mode(scene, psys)) {
ParticleEditSettings *pset = &scene->toolsettings->particle;
- if (psys->renderdata == 0 && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
+ if ((psys->renderdata == 0 && G.is_rendering == 0) && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
totchild = 0;
segments = 1 << pset->draw_step;
@@ -1662,7 +1683,7 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi
between = 1;
}
- if (psys->renderdata)
+ if (psys->renderdata || G.is_rendering)
segments = 1 << part->ren_step;
else {
totchild = (int)((float)totchild * (float)part->disp / 100.0f);
@@ -1747,9 +1768,9 @@ static void psys_calc_child_parent_weights(ParticleTask *task, struct ChildParti
}
/* modify weights to create parting */
- if (p_fac > 0.f) {
+ if (p_fac > 0.f && key[0]->segments != -1) {
for (w = 0; w < 4; w++) {
- if (w && weight[w] > 0.f) {
+ if (w && weight[w] > 0.f && key[w]->segments != -1) {
float d;
if (part->flag & PART_CHILD_LONG_HAIR) {
/* For long hair use tip distance/root distance as parting factor instead of root to tip angle. */
@@ -1941,17 +1962,28 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
ParticleCacheKey *par = NULL;
float par_co[3];
float par_orco[3];
-
+
if (ctx->totparent) {
if (i >= ctx->totparent) {
pa = &psys->particles[cpa->parent];
/* this is now threadsafe, virtual parents are calculated before rest of children */
+ BLI_assert(cpa->parent < psys->totchildcache);
par = cache[cpa->parent];
}
}
else if (cpa->parent >= 0) {
pa = &psys->particles[cpa->parent];
par = pcache[cpa->parent];
+
+ /* If particle is unexisting, try to pick a viable parent from particles used for interpolation. */
+ for (k = 0; k < 4 && pa && (pa->flag & PARS_UNEXIST); k++) {
+ if (cpa->pa[k] >= 0) {
+ pa = &psys->particles[cpa->pa[k]];
+ par = pcache[cpa->pa[k]];
+ }
+ }
+
+ if (pa->flag & PARS_UNEXIST) pa = NULL;
}
if (pa) {
@@ -1983,6 +2015,7 @@ static void exec_child_path_cache(TaskPool *UNUSED(pool), void *taskdata, int UN
cpa = psys->child + task->begin;
for (i = task->begin; i < task->end; ++i, ++cpa) {
+ BLI_assert(i < psys->totchildcache);
psys_thread_create_path(task, cpa, cache[i], i);
}
}
@@ -2021,7 +2054,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupd
/* cache parent paths */
ctx.parent_pass = 1;
- psys_tasks_create(&ctx, totparent, &tasks_parent, &numtasks_parent);
+ psys_tasks_create(&ctx, 0, totparent, &tasks_parent, &numtasks_parent);
for (i = 0; i < numtasks_parent; ++i) {
ParticleTask *task = &tasks_parent[i];
@@ -2032,7 +2065,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupd
/* cache child paths */
ctx.parent_pass = 0;
- psys_tasks_create(&ctx, totchild, &tasks_child, &numtasks_child);
+ psys_tasks_create(&ctx, totparent, totchild, &tasks_child, &numtasks_child);
for (i = 0; i < numtasks_child; ++i) {
ParticleTask *task = &tasks_child[i];
@@ -2116,7 +2149,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
float prev_tangent[3] = {0.0f, 0.0f, 0.0f}, hairmat[4][4];
float rotmat[3][3];
int k;
- int segments = (int)pow(2.0, (double)(psys->renderdata ? part->ren_step : part->draw_step));
+ int segments = (int)pow(2.0, (double)((psys->renderdata || G.is_rendering) ? part->ren_step : part->draw_step));
int totpart = psys->totpart;
float length, vec[3];
float *vg_effector = NULL;
@@ -2646,6 +2679,25 @@ void psys_mat_hair_to_global(Object *ob, DerivedMesh *dm, short from, ParticleDa
mul_m4_m4m4(hairmat, ob->obmat, facemat);
}
+void psys_child_mat_to_object(Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, ChildParticle *cpa, float hairmat[4][4])
+{
+ const bool between = (psys->part->childtype == PART_CHILD_FACES);
+ float co[3];
+
+ if (between) {
+ ParticleData *pa = &psys->particles[cpa->pa[0]];
+ psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, NULL, NULL, NULL, NULL, NULL);
+ psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, hairmat);
+ }
+ else {
+ ParticleData *pa = &psys->particles[cpa->parent];
+ psys_particle_on_emitter(psmd, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, NULL, NULL, NULL, NULL, NULL);
+ psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, hairmat);
+ }
+
+ copy_v3_v3(hairmat[3], co);
+}
+
/************************************************/
/* ParticleSettings handling */
/************************************************/
@@ -2734,7 +2786,7 @@ void object_remove_particle_system(Scene *UNUSED(scene), Object *ob)
if (ob->particlesystem.first)
((ParticleSystem *) ob->particlesystem.first)->flag |= PSYS_CURRENT;
else
- ob->mode &= ~OB_MODE_PARTICLE_EDIT;
+ ob->mode &= ~(OB_MODE_PARTICLE_EDIT | OB_MODE_HAIR_EDIT);
DAG_relations_tag_update(G.main);
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -3011,6 +3063,11 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, co
pvalue = texture_value_blend(def, pvalue, value, texfac, blend); \
} (void)0
+#define SET_PARTICLE_TEXTURE_RGB(type, prgb, texfac) \
+ if ((event & mtex->mapto) & type) { \
+ texture_rgb_blend(prgb, rgba, prgb, value, texfac, blend); \
+ } (void)0
+
#define CLAMP_PARTICLE_TEXTURE_POS(type, pvalue) \
if (event & type) { \
if (pvalue < 0.0f) \
@@ -3023,6 +3080,11 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, co
CLAMP(pvalue, -1.0f, 1.0f); \
} (void)0
+#define CLAMP_PARTICLE_TEXTURE_RGB(type, prgb) \
+ if (event & type) { \
+ CLAMP3(prgb, 0.0f, 1.0f); \
+ } (void)0
+
/* actual usable texco mode for particles */
BLI_INLINE int particle_texco(ParticleSettings *part, MTex *mtex)
{
@@ -3042,6 +3104,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti
ptex->ivel = ptex->life = ptex->exist = ptex->size = ptex->damp =
ptex->gravity = ptex->field = ptex->time = ptex->clump = ptex->kink_freq = ptex->kink_amp =
ptex->effector = ptex->rough1 = ptex->rough2 = ptex->roughe = 1.0f;
+ ptex->color[0] = ptex->color[1] = ptex->color[2] = 1.0f;
ptex->length = 1.0f - part->randlength * psys_frand(psys, child_index + 26);
ptex->length *= part->clength_thres < psys_frand(psys, child_index + 27) ? part->clength : 1.0f;
@@ -3087,6 +3150,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti
SET_PARTICLE_TEXTURE(PAMAP_KINK_AMP, ptex->kink_amp, mtex->kinkampfac);
SET_PARTICLE_TEXTURE(PAMAP_KINK_FREQ, ptex->kink_freq, mtex->kinkfac);
SET_PARTICLE_TEXTURE(PAMAP_DENS, ptex->exist, mtex->padensfac);
+ SET_PARTICLE_TEXTURE_RGB(PAMAP_COLOR, ptex->color, mtex->pacolfac);
}
}
@@ -3096,6 +3160,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_KINK_FREQ, ptex->kink_freq);
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_ROUGH, ptex->rough1);
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_DENS, ptex->exist);
+ CLAMP_PARTICLE_TEXTURE_RGB(PAMAP_COLOR, ptex->color);
}
bool particle_mtex_eval(ParticleSimulationData *sim, MTex *mtex, ParticleData *pa, float cfra, float *value, float rgba[4])
@@ -3167,6 +3232,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
ptex->ivel = ptex->life = ptex->exist = ptex->size = ptex->damp =
ptex->gravity = ptex->field = ptex->length = ptex->clump = ptex->kink_freq = ptex->kink_amp =
ptex->effector = ptex->rough1 = ptex->rough2 = ptex->roughe = 1.0f;
+ ptex->color[0] = ptex->color[1] = ptex->color[2] = 1.0f;
ptex->time = (float)(pa - sim->psys->particles) / (float)sim->psys->totpart;
@@ -3196,6 +3262,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
SET_PARTICLE_TEXTURE(PAMAP_GRAVITY, ptex->gravity, mtex->gravityfac);
SET_PARTICLE_TEXTURE(PAMAP_DAMP, ptex->damp, mtex->dampfac);
SET_PARTICLE_TEXTURE(PAMAP_LENGTH, ptex->length, mtex->lengthfac);
+ SET_PARTICLE_TEXTURE_RGB(PAMAP_COLOR, ptex->color, mtex->pacolfac);
}
}
@@ -3208,6 +3275,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
CLAMP_PARTICLE_TEXTURE_POSNEG(PAMAP_GRAVITY, ptex->gravity);
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_DAMP, ptex->damp);
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_LENGTH, ptex->length);
+ CLAMP_PARTICLE_TEXTURE_RGB(PAMAP_COLOR, ptex->color);
}
/* specialized texture eval for shapekey influences */
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 5ce1aea9ed7..13bb7c65025 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -333,7 +333,7 @@ static void init_mv_jit(float *jit, int num, int seed2, float amount)
rng = BLI_rng_new(31415926 + num + seed2);
x= 0;
- num2 = 2 * num;
+ num2 = 2 * num;
for (i=0; i<num2; i+=2) {
jit[i] = x + amount*rad1*(0.5f - BLI_rng_get_float(rng));
@@ -468,10 +468,9 @@ static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, i
psys_uv_to_w(1.0f / 3.0f, 1.0f / 3.0f, mface->v4, pa->fuv);
}
else {
- ctx->jitoff[i] = fmod(ctx->jitoff[i],(float)ctx->jitlevel);
- if (!isnan(ctx->jitoff[i])) {
- psys_uv_to_w(ctx->jit[2*(int)ctx->jitoff[i]], ctx->jit[2*(int)ctx->jitoff[i]+1], mface->v4, pa->fuv);
- ctx->jitoff[i]++;
+ float offset = fmod(ctx->jitoff[i] + (float)p, (float)ctx->jitlevel);
+ if (!isnan(offset)) {
+ psys_uv_to_w(ctx->jit[2*(int)offset], ctx->jit[2*(int)offset+1], mface->v4, pa->fuv);
}
}
break;
@@ -492,7 +491,7 @@ static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, i
static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, int p) {
ParticleThreadContext *ctx= thread->ctx;
DerivedMesh *dm= ctx->dm;
- float *v1, *v2, *v3, *v4, nor[3], co1[3], co2[3];
+ float *v1, *v2, *v3, *v4, nor[3], co[3];
float cur_d, min_d, randu, randv;
int distr= ctx->distr;
int i, intersect, tot;
@@ -513,10 +512,9 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
psys_uv_to_w(1.0f / 3.0f, 1.0f / 3.0f, mface->v4, pa->fuv);
}
else {
- ctx->jitoff[i] = fmod(ctx->jitoff[i],(float)ctx->jitlevel);
- if (!isnan(ctx->jitoff[i])) {
- psys_uv_to_w(ctx->jit[2*(int)ctx->jitoff[i]], ctx->jit[2*(int)ctx->jitoff[i]+1], mface->v4, pa->fuv);
- ctx->jitoff[i]++;
+ float offset = fmod(ctx->jitoff[i] + (float)p, (float)ctx->jitlevel);
+ if (!isnan(offset)) {
+ psys_uv_to_w(ctx->jit[2*(int)offset], ctx->jit[2*(int)offset+1], mface->v4, pa->fuv);
}
}
break;
@@ -533,14 +531,12 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
/* experimental */
tot=dm->getNumTessFaces(dm);
- psys_interpolate_face(mvert,mface,0,0,pa->fuv,co1,nor,0,0,0,0);
+ psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0,0);
normalize_v3(nor);
- mul_v3_fl(nor,-100.0);
+ negate_v3(nor);
- add_v3_v3v3(co2,co1,nor);
-
- min_d=2.0;
+ min_d=FLT_MAX;
intersect=0;
for (i=0,mface=dm->getTessFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++) {
@@ -550,20 +546,20 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
v2=mvert[mface->v2].co;
v3=mvert[mface->v3].co;
- if (isect_line_tri_v3(co1, co2, v2, v3, v1, &cur_d, 0)) {
+ if (isect_ray_tri_v3(co, nor, v2, v3, v1, &cur_d, 0)) {
if (cur_d<min_d) {
min_d=cur_d;
- pa->foffset=cur_d*50.0f; /* to the middle of volume */
+ pa->foffset=cur_d*0.5f; /* to the middle of volume */
intersect=1;
}
}
if (mface->v4) {
v4=mvert[mface->v4].co;
- if (isect_line_tri_v3(co1, co2, v4, v1, v3, &cur_d, 0)) {
+ if (isect_ray_tri_v3(co, nor, v4, v1, v3, &cur_d, 0)) {
if (cur_d<min_d) {
min_d=cur_d;
- pa->foffset=cur_d*50.0f; /* to the middle of volume */
+ pa->foffset=cur_d*0.5f; /* to the middle of volume */
intersect=1;
}
}
@@ -671,6 +667,8 @@ static void exec_distribute_parent(TaskPool *UNUSED(pool), void *taskdata, int U
ParticleSystem *psys= task->ctx->sim.psys;
ParticleData *pa;
int p;
+
+ BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->begin);
pa= psys->particles + task->begin;
switch (psys->part->from) {
@@ -1124,7 +1122,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
task_pool = BLI_task_pool_create(task_scheduler, &ctx);
totpart = (from == PART_FROM_CHILD ? sim->psys->totchild : sim->psys->totpart);
- psys_tasks_create(&ctx, totpart, &tasks, &numtasks);
+ psys_tasks_create(&ctx, 0, totpart, &tasks, &numtasks);
for (i = 0; i < numtasks; ++i) {
ParticleTask *task = &tasks[i];
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 7148f5e79a8..68dda2611fd 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -91,6 +91,7 @@
#include "BKE_modifier.h"
#include "BKE_scene.h"
#include "BKE_bvhutils.h"
+#include "BKE_depsgraph.h"
#include "PIL_time.h"
@@ -298,7 +299,7 @@ int psys_get_child_number(Scene *scene, ParticleSystem *psys)
else
nbr= psys->part->child_nbr;
- return get_render_child_particle_number(&scene->r, nbr);
+ return get_render_child_particle_number(&scene->r, nbr, psys->renderdata != NULL);
}
int psys_get_tot_child(Scene *scene, ParticleSystem *psys)
@@ -449,24 +450,24 @@ BLI_INLINE int ceil_ii(int a, int b)
return (a + b - 1) / b;
}
-void psys_tasks_create(ParticleThreadContext *ctx, int totpart, ParticleTask **r_tasks, int *r_numtasks)
+void psys_tasks_create(ParticleThreadContext *ctx, int startpart, int endpart, ParticleTask **r_tasks, int *r_numtasks)
{
ParticleTask *tasks;
- int numtasks = ceil_ii(totpart, MAX_PARTICLES_PER_TASK);
- float particles_per_task = (float)totpart / (float)numtasks, p, pnext;
+ int numtasks = ceil_ii((endpart - startpart), MAX_PARTICLES_PER_TASK);
+ float particles_per_task = (float)(endpart - startpart) / (float)numtasks, p, pnext;
int i;
tasks = MEM_callocN(sizeof(ParticleTask) * numtasks, "ParticleThread");
*r_numtasks = numtasks;
*r_tasks = tasks;
- p = 0.0f;
+ p = (float)startpart;
for (i = 0; i < numtasks; i++, p = pnext) {
pnext = p + particles_per_task;
tasks[i].ctx = ctx;
tasks[i].begin = (int)p;
- tasks[i].end = min_ii((int)pnext, totpart);
+ tasks[i].end = min_ii((int)pnext, endpart);
}
}
@@ -560,17 +561,24 @@ static void initialize_all_particles(ParticleSimulationData *sim)
ParticleSystem *psys = sim->psys;
PARTICLE_P;
+ LOOP_PARTICLES {
+ initialize_particle(sim, pa);
+ }
+}
+
+static void free_unexisting_particles(ParticleSimulationData *sim)
+{
+ ParticleSystem *psys = sim->psys;
+ PARTICLE_P;
+
psys->totunexist = 0;
LOOP_PARTICLES {
- if ((pa->flag & PARS_UNEXIST)==0)
- initialize_particle(sim, pa);
-
- if (pa->flag & PARS_UNEXIST)
+ if (pa->flag & PARS_UNEXIST) {
psys->totunexist++;
+ }
}
- /* Free unexisting particles. */
if (psys->totpart && psys->totunexist == psys->totpart) {
if (psys->particles->boid)
MEM_freeN(psys->particles->boid);
@@ -1178,7 +1186,7 @@ void psys_make_temp_pointcache(Object *ob, ParticleSystem *psys)
PTCacheID pid;
BKE_ptcache_id_from_particles(&pid, ob, psys);
cache->flag &= ~PTCACHE_DISK_CACHE;
- BKE_ptcache_disk_to_mem(&pid);
+ BKE_ptcache_disk_to_mem(&pid, false);
cache->flag |= PTCACHE_DISK_CACHE;
}
}
@@ -1268,7 +1276,7 @@ static void psys_update_effectors(ParticleSimulationData *sim)
{
pdEndEffectors(&sim->psys->effectors);
sim->psys->effectors = pdInitEffectors(sim->scene, sim->ob, sim->psys,
- sim->psys->part->effector_weights, true);
+ sim->psys->part->effector_weights);
precalc_guides(sim, sim->psys->effectors);
}
@@ -4087,6 +4095,7 @@ static void system_step(ParticleSimulationData *sim, float cfra)
initialize_all_particles(sim);
/* reset only just created particles (on startframe all particles are recreated) */
reset_all_particles(sim, 0.0, cfra, oldtotpart);
+ free_unexisting_particles(sim);
if (psys->fluid_springs) {
MEM_freeN(psys->fluid_springs);
@@ -4433,6 +4442,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
{
PARTICLE_P;
float disp = psys_get_current_display_percentage(psys);
+ bool free_unexisting = false;
/* Particles without dynamics haven't been reset yet because they don't use pointcache */
if (psys->recalc & PSYS_RECALC_RESET)
@@ -4442,6 +4452,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
free_keyed_keys(psys);
distribute_particles(&sim, part->from);
initialize_all_particles(&sim);
+ free_unexisting = true;
/* flag for possible explode modifiers after this system */
sim.psmd->flag |= eParticleSystemFlag_Pars;
@@ -4460,6 +4471,10 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
pa->flag &= ~PARS_NO_DISP;
}
+ /* free unexisting after reseting particles */
+ if (free_unexisting)
+ free_unexisting_particles(&sim);
+
if (part->phystype == PART_PHYS_KEYED) {
psys_count_keyed_targets(&sim);
set_keyed_keys(&sim);
@@ -4492,3 +4507,13 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
invert_m4_m4(psys->imat, ob->obmat);
}
+/* **** Depsgraph evaluation **** */
+
+void BKE_particle_system_eval(EvaluationContext *UNUSED(eval_ctx),
+ Object *ob,
+ ParticleSystem *psys)
+{
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s on %s:%s\n", __func__, ob->id.name, psys->name);
+ }
+}
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 5e07437d426..95d8e37d1c7 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -232,16 +232,11 @@ static int partition_indices_material(PBVH *bvh, int lo, int hi)
void pbvh_grow_nodes(PBVH *bvh, int totnode)
{
- if (totnode > bvh->node_mem_count) {
- PBVHNode *prev = bvh->nodes;
- bvh->node_mem_count *= 1.33;
+ if (UNLIKELY(totnode > bvh->node_mem_count)) {
+ bvh->node_mem_count = bvh->node_mem_count + (bvh->node_mem_count / 3);
if (bvh->node_mem_count < totnode)
bvh->node_mem_count = totnode;
- bvh->nodes = MEM_mallocN(sizeof(PBVHNode) * bvh->node_mem_count,
- "bvh nodes");
- memcpy(bvh->nodes, prev, bvh->totnode * sizeof(PBVHNode));
- memset(bvh->nodes + bvh->totnode, 0, (bvh->node_mem_count - bvh->totnode) * sizeof(PBVHNode));
- MEM_freeN(prev);
+ bvh->nodes = MEM_recallocN(bvh->nodes, sizeof(PBVHNode) * bvh->node_mem_count);
}
bvh->totnode = totnode;
@@ -575,7 +570,7 @@ void BKE_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts, int totface, int
}
/* Do a full rebuild with on Grids data structure */
-void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj,
+void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids,
int totgrid, CCGKey *key, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
{
BBC *prim_bbc = NULL;
@@ -585,7 +580,6 @@ void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj,
bvh->type = PBVH_GRIDS;
bvh->grids = grids;
- bvh->gridadj = gridadj;
bvh->gridfaces = gridfaces;
bvh->grid_flag_mats = flagmats;
bvh->totgrid = totgrid;
@@ -699,16 +693,16 @@ static void pbvh_iter_end(PBVHIter *iter)
static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, int revisiting)
{
- if (iter->stacksize == iter->stackspace) {
- PBVHStack *newstack;
-
+ if (UNLIKELY(iter->stacksize == iter->stackspace)) {
iter->stackspace *= 2;
- newstack = MEM_callocN(sizeof(PBVHStack) * iter->stackspace, "PBVHStack");
- memcpy(newstack, iter->stack, sizeof(PBVHStack) * iter->stacksize);
- if (iter->stackspace > STACK_FIXED_DEPTH)
- MEM_freeN(iter->stack);
- iter->stack = newstack;
+ if (iter->stackspace != STACK_FIXED_DEPTH) {
+ iter->stack = MEM_reallocN(iter->stack, sizeof(PBVHStack) * iter->stackspace);
+ }
+ else {
+ iter->stack = MEM_mallocN(sizeof(PBVHStack) * iter->stackspace, "PBVHStack");
+ memcpy(iter->stack, iter->stackfixed, sizeof(PBVHStack) * iter->stacksize);
+ }
}
iter->stack[iter->stacksize].node = node;
@@ -800,7 +794,7 @@ void BKE_pbvh_search_gather(PBVH *bvh,
while ((node = pbvh_iter_next(&iter))) {
if (node->flag & PBVH_Leaf) {
- if (tot == space) {
+ if (UNLIKELY(tot == space)) {
/* resize array if needed */
space = (tot == 0) ? 32 : space * 2;
array = MEM_recallocN_id(array, sizeof(PBVHNode *) * space, __func__);
@@ -948,6 +942,7 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes,
int n;
if (bvh->type == PBVH_BMESH) {
+ BLI_assert(face_nors == NULL);
pbvh_bmesh_normals_update(nodes, totnode);
return;
}
@@ -1285,6 +1280,16 @@ PBVHType BKE_pbvh_type(const PBVH *bvh)
return bvh->type;
}
+bool BKE_pbvh_has_faces(const PBVH *bvh)
+{
+ if (bvh->type == PBVH_BMESH) {
+ return (bvh->bm->totface != 0);
+ }
+ else {
+ return (bvh->totprim != 0);
+ }
+}
+
void BKE_pbvh_bounding_box(const PBVH *bvh, float min[3], float max[3])
{
if (bvh->totnode) {
@@ -1377,7 +1382,7 @@ void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *to
}
}
-void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, CCGElem ***griddata, DMGridAdjacency **gridadj)
+void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, CCGElem ***griddata)
{
switch (bvh->type) {
case PBVH_GRIDS:
@@ -1386,7 +1391,6 @@ void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int
if (maxgrid) *maxgrid = bvh->totgrid;
if (gridsize) *gridsize = bvh->gridkey.grid_size;
if (griddata) *griddata = bvh->grids;
- if (gridadj) *gridadj = bvh->gridadj;
break;
case PBVH_FACES:
case PBVH_BMESH:
@@ -1395,7 +1399,6 @@ void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int
if (maxgrid) *maxgrid = 0;
if (gridsize) *gridsize = 0;
if (griddata) *griddata = NULL;
- if (gridadj) *gridadj = NULL;
break;
}
}
@@ -1424,6 +1427,15 @@ void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *pro
}
}
+void BKE_pbvh_node_get_bm_orco_data(
+ PBVHNode *node,
+ int (**r_orco_tris)[3], int *r_orco_tris_num, float (**r_orco_coords)[3])
+{
+ *r_orco_tris = node->bm_ortri;
+ *r_orco_tris_num = node->bm_tot_ortri;
+ *r_orco_coords = node->bm_orco;
+}
+
/********************************* Raycast ***********************************/
typedef struct {
@@ -1597,7 +1609,9 @@ bool BKE_pbvh_node_raycast(
return hit;
}
-void BKE_pbvh_raycast_project_ray_root (PBVH *bvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3])
+void BKE_pbvh_raycast_project_ray_root(
+ PBVH *bvh, bool original,
+ float ray_start[3], float ray_end[3], float ray_normal[3])
{
if (bvh->nodes) {
float rootmin_start, rootmin_end;
@@ -1770,13 +1784,12 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3],
pbvh_draw_BB(bvh);
}
-void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, void **gridfaces,
+void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces,
DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
{
int a;
bvh->grids = grids;
- bvh->gridadj = gridadj;
bvh->gridfaces = gridfaces;
if (flagmats != bvh->grid_flag_mats || bvh->grid_hidden != grid_hidden) {
@@ -1955,7 +1968,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node,
vi->fno = NULL;
vi->mvert = NULL;
- BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids, NULL);
+ BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids);
BKE_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert);
BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &verts);
vi->key = &bvh->gridkey;
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 01bca44d3b6..9f092bd651f 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -29,6 +29,7 @@
#include "BLI_ghash.h"
#include "BLI_heap.h"
#include "BLI_math.h"
+#include "BLI_memarena.h"
#include "BKE_ccg.h"
#include "BKE_DerivedMesh.h"
@@ -41,6 +42,27 @@
#include <assert.h>
+/* Avoid skinny faces */
+#define USE_EDGEQUEUE_EVEN_SUBDIV
+#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
+# include "BKE_global.h"
+#endif
+
+/* Support for only operating on front-faces */
+#define USE_EDGEQUEUE_FRONTFACE
+
+/* don't add edges into the queue multiple times */
+#define USE_EDGEQUEUE_TAG
+/**
+ * Ensure we don't have dirty tags for the edge queue, and that they are left cleared.
+ * (slow, even for debug mode, so leave disabled for now).
+ */
+#if defined(USE_EDGEQUEUE_TAG) && 0
+# if !defined(NDEBUG)
+# define USE_EDGEQUEUE_TAG_VERIFY
+# endif
+#endif
+
// #define USE_VERIFY
#ifdef USE_VERIFY
@@ -107,7 +129,7 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index, const int cd_ver
}
/* Recursively split the node if it exceeds the leaf_limit */
-static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index)
+static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_index)
{
GSet *empty, *other;
GSetIterator gs_iter;
@@ -129,7 +151,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index)
BB_reset(&cb);
GSET_ITER (gs_iter, n->bm_faces) {
const BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- const BBC *bbc = BLI_ghash_lookup(prim_bbc, f);
+ const BBC *bbc = &bbc_array[BM_elem_index_get(f)];
BB_expand(&cb, bbc->bcentroid);
}
@@ -157,7 +179,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index)
/* Partition the parent node's faces between the two children */
GSET_ITER (gs_iter, n->bm_faces) {
BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- const BBC *bbc = BLI_ghash_lookup(prim_bbc, f);
+ const BBC *bbc = &bbc_array[BM_elem_index_get(f)];
if (bbc->bcentroid[axis] < mid)
BLI_gset_insert(c1->bm_faces, f);
@@ -221,8 +243,8 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index)
/* Recurse */
c1 = c2 = NULL;
- pbvh_bmesh_node_split(bvh, prim_bbc, children);
- pbvh_bmesh_node_split(bvh, prim_bbc, children + 1);
+ pbvh_bmesh_node_split(bvh, bbc_array, children);
+ pbvh_bmesh_node_split(bvh, bbc_array, children + 1);
/* Array maybe reallocated, update current node pointer */
n = &bvh->nodes[node_index];
@@ -237,7 +259,6 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index)
/* Recursively split the node if it exceeds the leaf_limit */
static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
{
- GHash *prim_bbc;
GSet *bm_faces;
int bm_faces_size;
GSetIterator gs_iter;
@@ -252,8 +273,7 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
}
/* For each BMFace, store the AABB and AABB centroid */
- prim_bbc = BLI_ghash_ptr_new_ex("prim_bbc", bm_faces_size);
- bbc_array = MEM_callocN(sizeof(BBC) * bm_faces_size, "BBC");
+ bbc_array = MEM_mallocN(sizeof(BBC) * bm_faces_size, "BBC");
GSET_ITER_INDEX (gs_iter, bm_faces, i) {
BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
@@ -268,12 +288,14 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
} while ((l_iter = l_iter->next) != l_first);
BBC_update_centroid(bbc);
- BLI_ghash_insert(prim_bbc, f, bbc);
+ /* so we can do direct lookups on 'bbc_array' */
+ BM_elem_index_set(f, i); /* set_dirty! */
}
+ /* likely this is already dirty */
+ bvh->bm->elem_index_dirty |= BM_FACE;
- pbvh_bmesh_node_split(bvh, prim_bbc, node_index);
+ pbvh_bmesh_node_split(bvh, bbc_array, node_index);
- BLI_ghash_free(prim_bbc, NULL, NULL);
MEM_freeN(bbc_array);
return true;
@@ -321,15 +343,21 @@ static PBVHNode *pbvh_bmesh_node_lookup(PBVH *bvh, void *key)
static BMVert *pbvh_bmesh_vert_create(
PBVH *bvh, int node_index,
- const float co[3],
- const BMVert *example,
+ const float co[3], const float no[3],
const int cd_vert_mask_offset)
{
- BMVert *v = BM_vert_create(bvh->bm, co, example, BM_CREATE_NOP);
PBVHNode *node = &bvh->nodes[node_index];
+ BMVert *v;
BLI_assert((bvh->totnode == 1 || node_index) && node_index <= bvh->totnode);
+ /* avoid initializing customdata because its quite involved */
+ v = BM_vert_create(bvh->bm, co, NULL, BM_CREATE_SKIP_CD);
+ CustomData_bmesh_set_default(&bvh->bm->vdata, &v->head.data);
+
+ /* This value is logged below */
+ copy_v3_v3(v->no, no);
+
BLI_gset_insert(node->bm_unique_verts, v);
BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, node_index);
@@ -352,7 +380,7 @@ static BMFace *pbvh_bmesh_face_create(
/* ensure we never add existing face */
BLI_assert(BM_face_exists(v_tri, 3, NULL) == false);
- f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
+ f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NO_DOUBLE);
f->head.hflag = f_example->head.hflag;
BLI_gset_insert(node->bm_faces, f);
@@ -369,6 +397,7 @@ static BMFace *pbvh_bmesh_face_create(
}
/* Return the number of faces in 'node' that use vertex 'v' */
+#if 0
static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
{
BMIter bm_iter;
@@ -376,12 +405,33 @@ static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
int count = 0;
BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- PBVHNode *f_node;
+ PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
+ if (f_node == node) {
+ count++;
+ }
+ }
- f_node = pbvh_bmesh_node_lookup(bvh, f);
+ return count;
+}
+#endif
+
+#define pbvh_bmesh_node_vert_use_count_is_equal(bvh, node, v, n) \
+ (pbvh_bmesh_node_vert_use_count_ex(bvh, node, v, (n) + 1) == n)
- if (f_node == node)
+static int pbvh_bmesh_node_vert_use_count_ex(PBVH *bvh, PBVHNode *node, BMVert *v, const int count_max)
+{
+ BMIter bm_iter;
+ BMFace *f;
+ int count = 0;
+
+ BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
+ PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
+ if (f_node == node) {
count++;
+ if (count == count_max) {
+ break;
+ }
+ }
}
return count;
@@ -484,13 +534,13 @@ static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f)
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
v = l_iter->v;
- if (pbvh_bmesh_node_vert_use_count(bvh, f_node, v) == 1) {
+ if (pbvh_bmesh_node_vert_use_count_is_equal(bvh, f_node, v, 1)) {
if (BLI_gset_haskey(f_node->bm_unique_verts, v)) {
/* Find a different node that uses 'v' */
PBVHNode *new_node;
new_node = pbvh_bmesh_vert_other_node_find(bvh, v);
- BLI_assert(new_node || BM_vert_face_count(v) == 1);
+ BLI_assert(new_node || BM_vert_face_count_is_equal(v, 1));
if (new_node) {
pbvh_bmesh_vert_ownership_transfer(bvh, new_node, v);
@@ -548,6 +598,15 @@ typedef struct {
const float *center;
float radius_squared;
float limit_len_squared;
+#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
+ float limit_len;
+#endif
+
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ const float *view_normal;
+ unsigned int use_view_normal : 1;
+#endif
+
} EdgeQueue;
typedef struct {
@@ -559,6 +618,44 @@ typedef struct {
int cd_face_node_offset;
} EdgeQueueContext;
+/* only tag'd edges are in the queue */
+#ifdef USE_EDGEQUEUE_TAG
+# define EDGE_QUEUE_TEST(e) (BM_elem_flag_test((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG))
+# define EDGE_QUEUE_ENABLE(e) BM_elem_flag_enable((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG)
+# define EDGE_QUEUE_DISABLE(e) BM_elem_flag_disable((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG)
+#endif
+
+#ifdef USE_EDGEQUEUE_TAG_VERIFY
+/* simply check no edges are tagged
+ * (it's a requirement that edges enter and leave a clean tag state) */
+static void pbvh_bmesh_edge_tag_verify(PBVH *bvh)
+{
+ int n;
+
+ for (n = 0; n < bvh->totnode; n++) {
+ PBVHNode *node = &bvh->nodes[n];
+ GSetIterator gs_iter;
+ if (node->bm_faces) {
+ GSET_ITER (gs_iter, node->bm_faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ BMEdge *e_tri[3];
+ BMLoop *l_iter;
+
+ BLI_assert(f->len == 3);
+ l_iter = BM_FACE_FIRST_LOOP(f);
+ e_tri[0] = l_iter->e; l_iter = l_iter->next;
+ e_tri[1] = l_iter->e; l_iter = l_iter->next;
+ e_tri[2] = l_iter->e;
+
+ BLI_assert((EDGE_QUEUE_TEST(e_tri[0]) == false) &&
+ (EDGE_QUEUE_TEST(e_tri[1]) == false) &&
+ (EDGE_QUEUE_TEST(e_tri[2]) == false));
+ }
+ }
+ }
+}
+#endif
+
static bool edge_queue_tri_in_sphere(const EdgeQueue *q, BMFace *f)
{
BMVert *v_tri[3];
@@ -580,8 +677,9 @@ static bool check_mask(EdgeQueueContext *eq_ctx, BMVert *v)
return (BM_ELEM_CD_GET_FLOAT(v, eq_ctx->cd_vert_mask_offset) < 1.0f);
}
-static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e,
- float priority)
+static void edge_queue_insert(
+ EdgeQueueContext *eq_ctx, BMEdge *e,
+ float priority)
{
BMVert **pair;
@@ -600,28 +698,120 @@ static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e,
pair[0] = e->v1;
pair[1] = e->v2;
BLI_heap_insert(eq_ctx->q->heap, priority, pair);
+#ifdef USE_EDGEQUEUE_TAG
+ BLI_assert(EDGE_QUEUE_TEST(e) == false);
+ EDGE_QUEUE_ENABLE(e);
+#endif
}
}
-static void long_edge_queue_edge_add(EdgeQueueContext *eq_ctx,
- BMEdge *e)
+static void long_edge_queue_edge_add(
+ EdgeQueueContext *eq_ctx,
+ BMEdge *e)
{
- const float len_sq = BM_edge_calc_length_squared(e);
- if (len_sq > eq_ctx->q->limit_len_squared)
- edge_queue_insert(eq_ctx, e, -len_sq);
+#ifdef USE_EDGEQUEUE_TAG
+ if (EDGE_QUEUE_TEST(e) == false)
+#endif
+ {
+ const float len_sq = BM_edge_calc_length_squared(e);
+ if (len_sq > eq_ctx->q->limit_len_squared) {
+ edge_queue_insert(eq_ctx, e, -len_sq);
+ }
+ }
}
-static void short_edge_queue_edge_add(EdgeQueueContext *eq_ctx,
- BMEdge *e)
+#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
+static void long_edge_queue_edge_add_recursive(
+ EdgeQueueContext *eq_ctx,
+ BMLoop *l_edge, BMLoop *l_end,
+ const float len_sq, float limit_len)
{
- const float len_sq = BM_edge_calc_length_squared(e);
- if (len_sq < eq_ctx->q->limit_len_squared)
- edge_queue_insert(eq_ctx, e, len_sq);
+ BLI_assert(len_sq > SQUARE(limit_len));
+
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ if (eq_ctx->q->use_view_normal) {
+ if (dot_v3v3(l_edge->f->no, eq_ctx->q->view_normal) < 0.0f) {
+ return;
+ }
+ }
+#endif
+
+#ifdef USE_EDGEQUEUE_TAG
+ if (EDGE_QUEUE_TEST(l_edge->e) == false)
+#endif
+ {
+ edge_queue_insert(eq_ctx, l_edge->e, -len_sq);
+ }
+
+ /* temp support previous behavior! */
+ if (UNLIKELY(G.debug_value == 1234)) {
+ return;
+ }
+
+ if ((l_edge->radial_next != l_edge)) {
+ /* how much longer we need to be to consider for subdividing
+ * (avoids subdividing faces which are only *slightly* skinny) */
+#define EVEN_EDGELEN_THRESHOLD 1.2f
+ /* how much the limit increases per recursion
+ * (avoids performing subdvisions too far away) */
+#define EVEN_GENERATION_SCALE 1.6f
+
+ const float len_sq_cmp = len_sq * EVEN_EDGELEN_THRESHOLD;
+ float limit_len_sq;
+ BMLoop *l_iter;
+
+ limit_len *= EVEN_GENERATION_SCALE;
+ limit_len_sq = SQUARE(limit_len);
+
+ l_iter = l_edge;
+ do {
+ float len_sq_other;
+ BMLoop *l_adjacent[2] = {l_iter->next, l_iter->prev};
+ int i;
+ for (i = 0; i < ARRAY_SIZE(l_adjacent); i++) {
+ len_sq_other = BM_edge_calc_length_squared(l_adjacent[i]->e);
+ if (len_sq_other > max_ff(len_sq_cmp, limit_len_sq)) {
+// edge_queue_insert(eq_ctx, l_adjacent[i]->e, -len_sq_other);
+ long_edge_queue_edge_add_recursive(
+ eq_ctx, l_adjacent[i]->radial_next, l_adjacent[i],
+ len_sq_other, limit_len);
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != l_end);
+
+#undef EVEN_EDGELEN_THRESHOLD
+#undef EVEN_GENERATION_SCALE
+ }
}
+#endif /* USE_EDGEQUEUE_EVEN_SUBDIV */
-static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx,
- BMFace *f)
+static void short_edge_queue_edge_add(
+ EdgeQueueContext *eq_ctx,
+ BMEdge *e)
{
+#ifdef USE_EDGEQUEUE_TAG
+ if (EDGE_QUEUE_TEST(e) == false)
+#endif
+ {
+ const float len_sq = BM_edge_calc_length_squared(e);
+ if (len_sq < eq_ctx->q->limit_len_squared) {
+ edge_queue_insert(eq_ctx, e, len_sq);
+ }
+ }
+}
+
+static void long_edge_queue_face_add(
+ EdgeQueueContext *eq_ctx,
+ BMFace *f)
+{
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ if (eq_ctx->q->use_view_normal) {
+ if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) {
+ return;
+ }
+ }
+#endif
+
if (edge_queue_tri_in_sphere(eq_ctx->q, f)) {
BMLoop *l_iter;
BMLoop *l_first;
@@ -629,14 +819,34 @@ static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx,
/* Check each edge of the face */
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- long_edge_queue_edge_add(eq_ctx, l_iter->e);
+ {
+#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
+ const float len_sq = BM_edge_calc_length_squared(l_iter->e);
+ if (len_sq > eq_ctx->q->limit_len_squared) {
+ long_edge_queue_edge_add_recursive(
+ eq_ctx, l_iter->radial_next, l_iter,
+ len_sq, eq_ctx->q->limit_len);
+ }
+#else
+ long_edge_queue_edge_add(eq_ctx, l_iter->e);
+#endif
+ }
} while ((l_iter = l_iter->next) != l_first);
}
}
-static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx,
- BMFace *f)
+static void short_edge_queue_face_add(
+ EdgeQueueContext *eq_ctx,
+ BMFace *f)
{
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ if (eq_ctx->q->use_view_normal) {
+ if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) {
+ return;
+ }
+ }
+#endif
+
if (edge_queue_tri_in_sphere(eq_ctx->q, f)) {
BMLoop *l_iter;
BMLoop *l_first;
@@ -658,9 +868,10 @@ static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx,
*
* The highest priority (lowest number) is given to the longest edge.
*/
-static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
- PBVH *bvh, const float center[3],
- float radius)
+static void long_edge_queue_create(
+ EdgeQueueContext *eq_ctx,
+ PBVH *bvh, const float center[3], const float view_normal[3],
+ float radius)
{
int n;
@@ -668,6 +879,21 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
eq_ctx->q->center = center;
eq_ctx->q->radius_squared = radius * radius;
eq_ctx->q->limit_len_squared = bvh->bm_max_edge_len * bvh->bm_max_edge_len;
+#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
+ eq_ctx->q->limit_len = bvh->bm_max_edge_len;
+#endif
+
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ eq_ctx->q->view_normal = view_normal;
+ eq_ctx->q->use_view_normal = (view_normal != NULL);
+#else
+ UNUSED_VARS(view_normal);
+#endif
+
+#ifdef USE_EDGEQUEUE_TAG_VERIFY
+ pbvh_bmesh_edge_tag_verify(bvh);
+#endif
+
for (n = 0; n < bvh->totnode; n++) {
PBVHNode *node = &bvh->nodes[n];
@@ -698,9 +924,10 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
*
* The highest priority (lowest number) is given to the shortest edge.
*/
-static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
- PBVH *bvh, const float center[3],
- float radius)
+static void short_edge_queue_create(
+ EdgeQueueContext *eq_ctx,
+ PBVH *bvh, const float center[3], const float view_normal[3],
+ float radius)
{
int n;
@@ -708,6 +935,16 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
eq_ctx->q->center = center;
eq_ctx->q->radius_squared = radius * radius;
eq_ctx->q->limit_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
+#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
+ eq_ctx->q->limit_len = bvh->bm_min_edge_len;
+#endif
+
+#ifdef USE_EDGEQUEUE_FRONTFACE
+ eq_ctx->q->view_normal = view_normal;
+ eq_ctx->q->use_view_normal = (view_normal != NULL);
+#else
+ UNUSED_VARS(view_normal);
+#endif
for (n = 0; n < bvh->totnode; n++) {
PBVHNode *node = &bvh->nodes[n];
@@ -738,21 +975,24 @@ static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3])
e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE);
}
-static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh,
- BMEdge *e, BLI_Buffer *edge_loops)
+static void pbvh_bmesh_split_edge(
+ EdgeQueueContext *eq_ctx, PBVH *bvh,
+ BMEdge *e, BLI_Buffer *edge_loops)
{
BMVert *v_new;
- float mid[3];
+ float co_mid[3], no_mid[3];
int i, node_index;
/* Get all faces adjacent to the edge */
pbvh_bmesh_edge_loops(edge_loops, e);
/* Create a new vertex in current node at the edge's midpoint */
- mid_v3_v3v3(mid, e->v1->co, e->v2->co);
+ mid_v3_v3v3(co_mid, e->v1->co, e->v2->co);
+ mid_v3_v3v3(no_mid, e->v1->no, e->v2->no);
+ normalize_v3(no_mid);
node_index = BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset);
- v_new = pbvh_bmesh_vert_create(bvh, node_index, mid, e->v1, eq_ctx->cd_vert_mask_offset);
+ v_new = pbvh_bmesh_vert_create(bvh, node_index, co_mid, no_mid, eq_ctx->cd_vert_mask_offset);
/* update paint mask */
if (eq_ctx->cd_vert_mask_offset != -1) {
@@ -788,6 +1028,32 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh,
if (ni != node_index && i == 0)
pbvh_bmesh_vert_ownership_transfer(bvh, &bvh->nodes[ni], v_new);
+ /**
+ * The 2 new faces created and assigned to ``f_new`` have their
+ * verts & edges shuffled around.
+ *
+ * - faces wind anticlockwise in this example.
+ * - original edge is ``(v1, v2)``
+ * - oroginal face is ``(v1, v2, v3)``
+ *
+ * <pre>
+ * + v3(v_opp)
+ * /|\
+ * / | \
+ * / | \
+ * e4/ | \ e3
+ * / |e5 \
+ * / | \
+ * / e1 | e2 \
+ * +-------+-------+
+ * v1 v4(v_new) v2
+ * (first) (second)
+ * </pre>
+ *
+ * - f_new (first): ``v_tri=(v1, v4, v3), e_tri=(e1, e5, e4)``
+ * - f_new (second): ``v_tri=(v4, v2, v3), e_tri=(e2, e3, e5)``
+ */
+
/* Create two new faces */
v_tri[0] = v1;
v_tri[1] = v_new;
@@ -810,13 +1076,11 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh,
BM_face_kill(bvh->bm, f_adj);
/* Ensure new vertex is in the node */
- if (!BLI_gset_haskey(bvh->nodes[ni].bm_unique_verts, v_new) &&
- !BLI_gset_haskey(bvh->nodes[ni].bm_other_verts, v_new))
- {
- BLI_gset_insert(bvh->nodes[ni].bm_other_verts, v_new);
+ if (!BLI_gset_haskey(bvh->nodes[ni].bm_unique_verts, v_new)) {
+ BLI_gset_add(bvh->nodes[ni].bm_other_verts, v_new);
}
- if (BM_vert_edge_count(v_opp) >= 9) {
+ if (BM_vert_edge_count_is_over(v_opp, 8)) {
BMIter bm_iter;
BMEdge *e2;
@@ -829,8 +1093,9 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh,
BM_edge_kill(bvh->bm, e);
}
-static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, PBVH *bvh,
- BLI_Buffer *edge_loops)
+static bool pbvh_bmesh_subdivide_long_edges(
+ EdgeQueueContext *eq_ctx, PBVH *bvh,
+ BLI_Buffer *edge_loops)
{
bool any_subdivided = false;
@@ -842,13 +1107,22 @@ static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, PBVH *bvh,
BLI_mempool_free(eq_ctx->pool, pair);
pair = NULL;
- if (len_squared_v3v3(v1->co, v2->co) <= eq_ctx->q->limit_len_squared)
- continue;
-
/* Check that the edge still exists */
if (!(e = BM_edge_exists(v1, v2))) {
continue;
}
+#ifdef USE_EDGEQUEUE_TAG
+ EDGE_QUEUE_DISABLE(e);
+#endif
+
+ /* At the moment edges never get shorter (subdiv will make new edges)
+ * unlike collapse where edges can become longer. */
+#if 0
+ if (len_squared_v3v3(v1->co, v2->co) <= eq_ctx->q->limit_len_squared)
+ continue;
+#else
+ BLI_assert(len_squared_v3v3(v1->co, v2->co) > eq_ctx->q->limit_len_squared);
+#endif
/* Check that the edge's vertices are still in the PBVH. It's
* possible that an edge collapse has deleted adjacent faces
@@ -865,6 +1139,10 @@ static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, PBVH *bvh,
pbvh_bmesh_split_edge(eq_ctx, bvh, e, edge_loops);
}
+#ifdef USE_EDGEQUEUE_TAG_VERIFY
+ pbvh_bmesh_edge_tag_verify(bvh);
+#endif
+
return any_subdivided;
}
@@ -945,10 +1223,8 @@ static void pbvh_bmesh_collapse_edge(
pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f);
/* Ensure that v_conn is in the new face's node */
- if (!BLI_gset_haskey(n->bm_unique_verts, v_conn) &&
- !BLI_gset_haskey(n->bm_other_verts, v_conn))
- {
- BLI_gset_insert(n->bm_other_verts, v_conn);
+ if (!BLI_gset_haskey(n->bm_unique_verts, v_conn)) {
+ BLI_gset_add(n->bm_other_verts, v_conn);
}
}
@@ -970,18 +1246,6 @@ static void pbvh_bmesh_collapse_edge(
v_tri[1] = l_iter->v; e_tri[1] = l_iter->e; l_iter = l_iter->next;
v_tri[2] = l_iter->v; e_tri[2] = l_iter->e;
- /* Check if any of the face's vertices are now unused, if so
- * remove them from the PBVH */
- for (j = 0; j < 3; j++) {
- if (v_tri[j] != v_del && BM_vert_face_count(v_tri[j]) == 1) {
- BLI_gset_insert(deleted_verts, v_tri[j]);
- pbvh_bmesh_vert_remove(bvh, v_tri[j]);
- }
- else {
- v_tri[j] = NULL;
- }
- }
-
/* Remove the face */
pbvh_bmesh_face_remove(bvh, f_del);
BM_face_kill(bvh->bm, f_del);
@@ -993,9 +1257,13 @@ static void pbvh_bmesh_collapse_edge(
BM_edge_kill(bvh->bm, e_tri[j]);
}
- /* Delete unused vertices */
+ /* Check if any of the face's vertices are now unused, if so
+ * remove them from the PBVH */
for (j = 0; j < 3; j++) {
- if (v_tri[j]) {
+ if ((v_tri[j] != v_del) && (v_tri[j]->e == NULL)) {
+ BLI_gset_insert(deleted_verts, v_tri[j]);
+ pbvh_bmesh_vert_remove(bvh, v_tri[j]);
+
BM_log_vert_removed(bvh->bm_log, v_tri[j], eq_ctx->cd_vert_mask_offset);
BM_vert_kill(bvh->bm, v_tri[j]);
}
@@ -1007,10 +1275,12 @@ static void pbvh_bmesh_collapse_edge(
if (!BLI_gset_haskey(deleted_verts, v_conn)) {
BM_log_vert_before_modified(bvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset);
mid_v3_v3v3(v_conn->co, v_conn->co, v_del->co);
+ add_v3_v3(v_conn->no, v_del->no);
+ normalize_v3(v_conn->no);
}
/* Delete v_del */
- BLI_assert(BM_vert_face_count(v_del) == 0);
+ BLI_assert(!BM_vert_face_check(v_del));
BLI_gset_insert(deleted_verts, v_del);
BM_log_vert_removed(bvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset);
BM_vert_kill(bvh->bm, v_del);
@@ -1042,13 +1312,16 @@ static bool pbvh_bmesh_collapse_short_edges(
continue;
}
- if (len_squared_v3v3(v1->co, v2->co) >= min_len_squared)
- continue;
-
/* Check that the edge still exists */
if (!(e = BM_edge_exists(v1, v2))) {
continue;
}
+#ifdef USE_EDGEQUEUE_TAG
+ EDGE_QUEUE_DISABLE(e);
+#endif
+
+ if (len_squared_v3v3(v1->co, v2->co) >= min_len_squared)
+ continue;
/* Check that the edge's vertices are still in the PBVH. It's
* possible that an edge collapse has deleted adjacent faces
@@ -1074,9 +1347,10 @@ static bool pbvh_bmesh_collapse_short_edges(
/************************* Called from pbvh.c *************************/
-bool pbvh_bmesh_node_raycast(PBVHNode *node, const float ray_start[3],
- const float ray_normal[3], float *dist,
- bool use_original)
+bool pbvh_bmesh_node_raycast(
+ PBVHNode *node, const float ray_start[3],
+ const float ray_normal[3], float *dist,
+ bool use_original)
{
bool hit = false;
@@ -1189,36 +1463,225 @@ void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode)
}
}
-/***************************** Public API *****************************/
+typedef struct FastNodeBuildInfo {
+ int totface; /* number of faces */
+ int start; /* start of faces in array */
+ struct FastNodeBuildInfo *child1;
+ struct FastNodeBuildInfo *child2;
+} FastNodeBuildInfo;
-static void pbvh_bmesh_node_layers_reset(PBVH *bvh)
+/* Recursively split the node if it exceeds the leaf_limit. This function is multithreadabe since each invocation applies
+ * to a sub part of the arrays */
+static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, MemArena *arena)
{
BMFace *f;
- BMVert *v;
- BMIter iter;
- BMesh *bm = bvh->bm;
- int cd_vert_node_offset = bvh->cd_vert_node_offset;
- int cd_face_node_offset = bvh->cd_face_node_offset;
+ BB cb;
+ BBC *bbc;
+ float mid;
+ int axis, i;
+ int end;
+ FastNodeBuildInfo *child1, *child2;
+ int num_child1, num_child2;
+ BMFace *tmp;
- /* clear the elements of the node information */
- BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
- BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
+ if (node->totface <= bvh->leaf_limit) {
+ return;
}
- BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) {
- BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
+ /* Calculate bounding box around primitive centroids */
+ BB_reset(&cb);
+ for (i = 0; i < node->totface; i++) {
+ f = nodeinfo[i + node->start];
+ bbc = &bbc_array[BM_elem_index_get(f)];
+
+ BB_expand(&cb, bbc->bcentroid);
+ }
+
+ /* initialize the children */
+
+ /* Find widest axis and its midpoint */
+ axis = BB_widest_axis(&cb);
+ mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f;
+
+ num_child1 = 0, num_child2 = 0;
+
+ /* split vertices along the middle line */
+ end = node->start + node->totface;
+ for (i = node->start; i < end - num_child2; i++) {
+ f = nodeinfo[i];
+ bbc = &bbc_array[BM_elem_index_get(f)];
+
+ if (bbc->bcentroid[axis] > mid) {
+ int i_iter = end - num_child2 - 1;
+ int candidate = -1;
+ /* found a face that should be part of another node, look for a face to substitute with */
+
+ for (;i_iter > i; i_iter--) {
+ BMFace *f_iter = nodeinfo[i_iter];
+ const BBC *bbc_iter = &bbc_array[BM_elem_index_get(f_iter)];
+ if (bbc_iter->bcentroid[axis] <= mid) {
+ candidate = i_iter;
+ break;
+ }
+ else {
+ num_child2++;
+ }
+ }
+
+ if (candidate != -1) {
+ tmp = nodeinfo[i];
+ nodeinfo[i] = nodeinfo[candidate];
+ nodeinfo[candidate] = tmp;
+ /* increase both counts */
+ num_child1++;
+ num_child2++;
+ }
+ else {
+ /* not finding candidate means second half of array part is full of
+ * second node parts, just increase the number of child nodes for it */
+ num_child2++;
+ }
+ }
+ else {
+ num_child1++;
+ }
+ }
+
+ /* ensure at least one child in each node */
+ if (num_child2 == 0) {
+ num_child2++;
+ num_child1--;
+ }
+ else if (num_child1 == 0) {
+ num_child1++;
+ num_child2--;
+ }
+
+ /* at this point, faces should have been split along the array range sequentially,
+ * each sequential part belonging to one node only */
+ BLI_assert((num_child1 + num_child2) == node->totface);
+
+ node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo));
+ node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo));
+
+ child1->totface = num_child1;
+ child1->start = node->start;
+ child2->totface = num_child2;
+ child2->start = node->start + num_child1;
+ child1->child1 = child1->child2 = child2->child1 = child2->child2 = NULL;
+
+ pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child1, arena);
+ pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child2, arena);
+
+ return;
+}
+
+static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, int node_index)
+{
+ PBVHNode *n = bvh->nodes + node_index;
+ /* two cases, node does not have children or does have children */
+ if (node->child1) {
+ int children_offset = bvh->totnode;
+
+ n->children_offset = children_offset;
+ pbvh_grow_nodes(bvh, bvh->totnode + 2);
+ pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, node->child1, children_offset);
+ pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, node->child2, children_offset + 1);
+
+ n = &bvh->nodes[node_index];
+
+ /* Update bounding box */
+ BB_reset(&n->vb);
+ BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset].vb);
+ BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset + 1].vb);
+ n->orig_vb = n->vb;
+ }
+ else {
+ /* node does not have children so it's a leaf node, populate with faces and tag accordingly
+ * this is an expensive part but it's not so easily threadable due to vertex node indices */
+ const int cd_vert_node_offset = bvh->cd_vert_node_offset;
+ const int cd_face_node_offset = bvh->cd_face_node_offset;
+
+ bool has_visible = false;
+ int i, end;
+ BMFace *f;
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ BMVert *v;
+ BBC *bbc;
+
+ n->flag = PBVH_Leaf;
+ n->bm_faces = BLI_gset_ptr_new_ex("bm_faces", node->totface);
+
+ /* Create vert hash sets */
+ n->bm_unique_verts = BLI_gset_ptr_new("bm_unique_verts");
+ n->bm_other_verts = BLI_gset_ptr_new("bm_other_verts");
+
+ BB_reset(&n->vb);
+
+ end = node->start + node->totface;
+
+ for (i = node->start; i < end; i++) {
+ f = nodeinfo[i];
+ bbc = &bbc_array[BM_elem_index_get(f)];
+
+ /* Update ownership of faces */
+ BLI_gset_insert(n->bm_faces, f);
+ BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
+
+ /* Update vertices */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ v = l_iter->v;
+ if (!BLI_gset_haskey(n->bm_unique_verts, v)) {
+ if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
+ BLI_gset_add(n->bm_other_verts, v);
+ }
+ else {
+ BLI_gset_insert(n->bm_unique_verts, v);
+ BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index);
+ }
+ }
+ /* Update node bounding box */
+ } while ((l_iter = l_iter->next) != l_first);
+
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN))
+ has_visible = true;
+
+ BB_expand_with_bb(&n->vb, (BB *)bbc);
+ }
+
+ BLI_assert(n->vb.bmin[0] <= n->vb.bmax[0] &&
+ n->vb.bmin[1] <= n->vb.bmax[1] &&
+ n->vb.bmin[2] <= n->vb.bmax[2]);
+
+ n->orig_vb = n->vb;
+
+ /* Build GPU buffers for new node and update vertex normals */
+ BKE_pbvh_node_mark_rebuild_draw(n);
+
+ BKE_pbvh_node_fully_hidden_set(n, !has_visible);
+ n->flag |= PBVH_UpdateNormals;
}
}
+/***************************** Public API *****************************/
+
/* Build a PBVH from a BMesh */
-void BKE_pbvh_build_bmesh(PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log,
- const int cd_vert_node_offset, const int cd_face_node_offset)
+void BKE_pbvh_build_bmesh(
+ PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log,
+ const int cd_vert_node_offset, const int cd_face_node_offset)
{
BMIter iter;
BMFace *f;
- PBVHNode *n;
- int node_index = 0;
+ BMVert *v;
+ int i;
+ /* bounding box array of all faces, no need to recalculate every time */
+ BBC *bbc_array;
+ BMFace **nodeinfo;
+ FastNodeBuildInfo rootnode = {0};
+ MemArena *arena;
bvh->cd_vert_node_offset = cd_vert_node_offset;
bvh->cd_face_node_offset = cd_face_node_offset;
@@ -1235,26 +1698,61 @@ void BKE_pbvh_build_bmesh(PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log,
if (smooth_shading)
bvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING;
- pbvh_bmesh_node_layers_reset(bvh);
+ /* calculate all bounding boxes once for all faces */
+ bbc_array = MEM_mallocN(sizeof(BBC) * bm->totface, "BBC");
+ nodeinfo = MEM_mallocN(sizeof(*nodeinfo) * bm->totface, "nodeinfo");
+ arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "fast PBVH node storage");
+
+ BM_ITER_MESH_INDEX(f, &iter, bm, BM_FACES_OF_MESH, i) {
+ BBC *bbc = &bbc_array[i];
+ BMLoop *l_iter;
+ BMLoop *l_first;
+
+ BB_reset((BB *)bbc);
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BB_expand((BB *)bbc, l_iter->v->co);
+ } while ((l_iter = l_iter->next) != l_first);
+ BBC_update_centroid(bbc);
+
+ /* so we can do direct lookups on 'bbc_array' */
+ BM_elem_index_set(f, i); /* set_dirty! */
+ nodeinfo[i] = f;
+ BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
+ }
+
+ BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
+ }
+
+ /* likely this is already dirty */
+ bm->elem_index_dirty |= BM_FACE;
+
+ /* setup root node */
+ rootnode.totface = bm->totface;
+
+ /* start recursion, assign faces to nodes accordingly */
+ pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, &rootnode, arena);
+
+ /* we now have all faces assigned to a node, next we need to assign those to the gsets of the nodes */
/* Start with all faces in the root node */
- n = bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode");
+ bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode");
bvh->totnode = 1;
- n->flag = PBVH_Leaf;
- n->bm_faces = BLI_gset_ptr_new_ex("bm_faces", bvh->bm->totface);
- BM_ITER_MESH (f, &iter, bvh->bm, BM_FACES_OF_MESH) {
- BLI_gset_insert(n->bm_faces, f);
- }
- /* Recursively split the node until it is under the limit; if no
- * splitting occurs then finalize the existing leaf node */
- if (!pbvh_bmesh_node_limit_ensure(bvh, node_index))
- pbvh_bmesh_node_finalize(bvh, 0, cd_vert_node_offset, cd_face_node_offset);
+ /* take root node and visit and populate children recursively */
+ pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, &rootnode, 0);
+
+ BLI_memarena_free(arena);
+ MEM_freeN(bbc_array);
+ MEM_freeN(nodeinfo);
}
/* Collapse short edges, subdivide long edges */
-bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode,
- const float center[3], float radius)
+bool BKE_pbvh_bmesh_update_topology(
+ PBVH *bvh, PBVHTopologyUpdateMode mode,
+ const float center[3], const float view_normal[3],
+ float radius)
{
/* 2 is enough for edge faces - manifold edge */
BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2);
@@ -1266,12 +1764,16 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode,
bool modified = false;
int n;
+ if (view_normal) {
+ BLI_assert(len_squared_v3(view_normal) != 0.0f);
+ }
+
if (mode & PBVH_Collapse) {
EdgeQueue q;
BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP);
EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset};
- short_edge_queue_create(&eq_ctx, bvh, center, radius);
+ short_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius);
modified |= !BLI_heap_is_empty(q.heap);
pbvh_bmesh_collapse_short_edges(&eq_ctx, bvh,
&deleted_faces);
@@ -1284,7 +1786,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode,
BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP);
EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset};
- long_edge_queue_create(&eq_ctx, bvh, center, radius);
+ long_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius);
modified |= !BLI_heap_is_empty(q.heap);
pbvh_bmesh_subdivide_long_edges(&eq_ctx, bvh, &edge_loops);
BLI_heap_free(q.heap, NULL);
@@ -1641,7 +2143,7 @@ static void pbvh_bmesh_verify(PBVH *bvh)
GSET_ITER (gs_iter, n->bm_other_verts) {
BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
- BLI_assert(BM_vert_face_count(v) > 0);
+ BLI_assert(!BM_vert_face_check(v));
BLI_assert(BLI_gset_haskey(verts_all, v));
}
}
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 6b3ef8eb5da..7daccb47c92 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -139,7 +139,6 @@ struct PBVH {
/* Grid Data */
CCGKey gridkey;
CCGElem **grids;
- DMGridAdjacency *gridadj;
void **gridfaces;
const DMFlagMat *grid_flag_mats;
int totgrid;
@@ -175,9 +174,10 @@ void BB_expand_with_bb(BB *bb, BB *bb2);
void BBC_update_centroid(BBC *bbc);
int BB_widest_axis(const BB *bb);
void pbvh_grow_nodes(PBVH *bvh, int totnode);
-bool ray_face_intersection(const float ray_start[3], const float ray_normal[3],
- const float *t0, const float *t1, const float *t2,
- const float *t3, float *fdist);
+bool ray_face_intersection(
+ const float ray_start[3], const float ray_normal[3],
+ const float *t0, const float *t1, const float *t2,
+ const float *t3, float *fdist);
void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag);
/* pbvh_bmesh.c */
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index e6d41063262..4711a5900f0 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -84,8 +84,12 @@
#endif
#ifdef WITH_LZO
-#include "minilzo.h"
-#define LZO_HEAP_ALLOC(var,size) \
+# ifdef WITH_SYSTEM_LZO
+# include <lzo/lzo1x.h>
+# else
+# include "minilzo.h"
+# endif
+# define LZO_HEAP_ALLOC(var,size) \
lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ]
#endif
@@ -2533,7 +2537,7 @@ int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra)
*/
/* Clears & resets */
-void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
+void BKE_ptcache_id_clear_ex(PTCacheID *pid, int mode, unsigned int cfra, bool allow_file_delete)
{
unsigned int len; /* store the length of the string */
unsigned int sta, end;
@@ -2591,8 +2595,10 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */
if (mode == PTCACHE_CLEAR_ALL) {
pid->cache->last_exact = MIN2(pid->cache->startframe, 0);
- BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
- BLI_delete(path_full, false, false);
+ if (allow_file_delete) {
+ BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
+ BLI_delete(path_full, false, false);
+ }
}
else {
/* read the number of the file */
@@ -2607,8 +2613,10 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
(mode == PTCACHE_CLEAR_AFTER && frame > cfra))
{
- BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
- BLI_delete(path_full, false, false);
+ if (allow_file_delete) {
+ BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
+ BLI_delete(path_full, false, false);
+ }
if (pid->cache->cached_frames && frame >=sta && frame <= end)
pid->cache->cached_frames[frame-sta] = 0;
}
@@ -2661,8 +2669,10 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
case PTCACHE_CLEAR_FRAME:
if (pid->cache->flag & PTCACHE_DISK_CACHE) {
if (BKE_ptcache_id_exist(pid, cfra)) {
- ptcache_filename(pid, filename, cfra, 1, 1); /* no path */
- BLI_delete(filename, false, false);
+ if (allow_file_delete) {
+ ptcache_filename(pid, filename, cfra, 1, 1); /* no path */
+ BLI_delete(filename, false, false);
+ }
}
}
else {
@@ -2684,6 +2694,13 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
BKE_ptcache_update_info(pid);
}
+
+/* Clears & resets */
+void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
+{
+ BKE_ptcache_id_clear_ex(pid, mode, cfra, false);
+}
+
int BKE_ptcache_id_exist(PTCacheID *pid, int cfra)
{
if (!pid->cache)
@@ -2955,49 +2972,6 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
return reset;
}
-/* Use this when quitting blender, with unsaved files */
-void BKE_ptcache_remove(void)
-{
- char path[MAX_PTCACHE_PATH];
- char path_full[MAX_PTCACHE_PATH];
- int rmdir = 1;
-
- ptcache_path(NULL, path);
-
- if (BLI_exists(path)) {
- /* The pointcache dir exists? - remove all pointcache */
-
- DIR *dir;
- struct dirent *de;
-
- dir = opendir(path);
- if (dir==NULL)
- return;
-
- while ((de = readdir(dir)) != NULL) {
- if (FILENAME_IS_CURRPAR(de->d_name)) {
- /* do nothing */
- }
- else if (strstr(de->d_name, PTCACHE_EXT)) { /* do we have the right extension?*/
- BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
- BLI_delete(path_full, false, false);
- }
- else {
- rmdir = 0; /* unknown file, don't remove the dir */
- }
- }
-
- closedir(dir);
- }
- else {
- rmdir = 0; /* path dosnt exist */
- }
-
- if (rmdir) {
- BLI_delete(path, true, false);
- }
-}
-
/* Point Cache handling */
PointCache *BKE_ptcache_add(ListBase *ptcaches)
@@ -3089,7 +3063,7 @@ static PointCache *ptcache_copy(PointCache *cache, bool copy_data)
}
/* returns first point cache */
-PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, ListBase *ptcaches_old, bool copy_data)
+PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcaches_old, bool copy_data)
{
PointCache *cache = ptcaches_old->first;
@@ -3350,7 +3324,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
}
}
- BLI_end_threads(&threads);
+ BLI_end_threads(&threads);
}
/* clear baking flag */
if (pid) {
@@ -3408,21 +3382,24 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
/* TODO: call redraw all windows somehow */
}
/* Helpers */
-void BKE_ptcache_disk_to_mem(PTCacheID *pid)
+void BKE_ptcache_disk_to_mem(PTCacheID *pid, bool clear)
{
PointCache *cache = pid->cache;
PTCacheMem *pm = NULL;
- int baked = cache->flag & PTCACHE_BAKED;
int cfra, sfra = cache->startframe, efra = cache->endframe;
- /* Remove possible bake flag to allow clear */
- cache->flag &= ~PTCACHE_BAKED;
-
- /* PTCACHE_DISK_CACHE flag was cleared already */
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
-
- /* restore possible bake flag */
- cache->flag |= baked;
+ if (clear) {
+ int baked = cache->flag & PTCACHE_BAKED;
+
+ /* Remove possible bake flag to allow clear */
+ cache->flag &= ~PTCACHE_BAKED;
+
+ /* PTCACHE_DISK_CACHE flag was cleared already */
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
+
+ /* restore possible bake flag */
+ cache->flag |= baked;
+ }
for (cfra=sfra; cfra <= efra; cfra++) {
pm = ptcache_disk_frame_to_mem(pid, cfra);
@@ -3431,20 +3408,23 @@ void BKE_ptcache_disk_to_mem(PTCacheID *pid)
BLI_addtail(&pid->cache->mem_cache, pm);
}
}
-void BKE_ptcache_mem_to_disk(PTCacheID *pid)
+void BKE_ptcache_mem_to_disk(PTCacheID *pid, bool clear)
{
PointCache *cache = pid->cache;
PTCacheMem *pm = cache->mem_cache.first;
- int baked = cache->flag & PTCACHE_BAKED;
-
- /* Remove possible bake flag to allow clear */
- cache->flag &= ~PTCACHE_BAKED;
-
- /* PTCACHE_DISK_CACHE flag was set already */
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
- /* restore possible bake flag */
- cache->flag |= baked;
+ if (clear) {
+ int baked = cache->flag & PTCACHE_BAKED;
+
+ /* Remove possible bake flag to allow clear */
+ cache->flag &= ~PTCACHE_BAKED;
+
+ /* PTCACHE_DISK_CACHE flag was set already */
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
+
+ /* restore possible bake flag */
+ cache->flag |= baked;
+ }
for (; pm; pm=pm->next) {
if (ptcache_mem_frame_to_disk(pid, pm)==0) {
@@ -3475,9 +3455,9 @@ void BKE_ptcache_toggle_disk_cache(PTCacheID *pid)
}
if (cache->flag & PTCACHE_DISK_CACHE)
- BKE_ptcache_mem_to_disk(pid);
+ BKE_ptcache_mem_to_disk(pid, true);
else
- BKE_ptcache_disk_to_mem(pid);
+ BKE_ptcache_disk_to_mem(pid, true);
cache->flag ^= PTCACHE_DISK_CACHE;
BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index aaf54b82f32..b4218378eb8 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -54,6 +54,7 @@
#include "DNA_scene_types.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_depsgraph.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_library.h"
@@ -61,6 +62,7 @@
#include "BKE_object.h"
#include "BKE_pointcache.h"
#include "BKE_rigidbody.h"
+#include "BKE_scene.h"
#ifdef WITH_BULLET
@@ -1236,7 +1238,7 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
ListBase *effectors;
/* get effectors present in the group specified by effector_weights */
- effectors = pdInitEffectors(scene, ob, NULL, effector_weights, true);
+ effectors = pdInitEffectors(scene, ob, NULL, effector_weights);
if (effectors) {
float eff_force[3] = {0.0f, 0.0f, 0.0f};
float eff_loc[3], eff_vel[3];
@@ -1610,3 +1612,51 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) {}
#endif
#endif /* WITH_BULLET */
+
+/* -------------------- */
+/* Depsgraph evaluation */
+
+void BKE_rigidbody_rebuild_sim(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene)
+{
+ float ctime = BKE_scene_frame_get(scene);
+
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s at %f\n", __func__, ctime);
+ }
+
+ /* rebuild sim data (i.e. after resetting to start of timeline) */
+ if (BKE_scene_check_rigidbody_active(scene)) {
+ BKE_rigidbody_rebuild_world(scene, ctime);
+ }
+}
+
+void BKE_rigidbody_eval_simulation(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene)
+{
+ float ctime = BKE_scene_frame_get(scene);
+
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s at %f\n", __func__, ctime);
+ }
+
+ /* evaluate rigidbody sim */
+ if (BKE_scene_check_rigidbody_active(scene)) {
+ BKE_rigidbody_do_simulation(scene, ctime);
+ }
+}
+
+void BKE_rigidbody_object_sync_transforms(EvaluationContext *UNUSED(eval_ctx),
+ Scene *scene,
+ Object *ob)
+{
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+ float ctime = BKE_scene_frame_get(scene);
+
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("%s on %s\n", __func__, ob->id.name);
+ }
+
+ /* read values pushed into RBO from sim/cache... */
+ BKE_rigidbody_sync_transforms(rbw, ob, ctime);
+}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 32d568f5729..b6fede75d96 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -64,6 +64,7 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_armature.h"
+#include "BKE_cache_library.h"
#include "BKE_colortools.h"
#include "BKE_depsgraph.h"
#include "BKE_editmesh.h"
@@ -75,6 +76,7 @@
#include "BKE_idprop.h"
#include "BKE_image.h"
#include "BKE_library.h"
+#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_mask.h"
#include "BKE_node.h"
@@ -82,16 +84,20 @@
#include "BKE_paint.h"
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
+#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "BKE_sound.h"
#include "BKE_unit.h"
#include "BKE_world.h"
+#include "DEG_depsgraph.h"
+
#include "RE_engine.h"
#include "PIL_time.h"
#include "IMB_colormanagement.h"
+#include "IMB_imbuf.h"
#include "bmesh.h"
@@ -153,18 +159,21 @@ Scene *BKE_scene_copy(Scene *sce, int type)
{
Scene *scen;
SceneRenderLayer *srl, *new_srl;
+ FreestyleLineSet *lineset;
ToolSettings *ts;
Base *base, *obase;
if (type == SCE_COPY_EMPTY) {
- ListBase lb;
+ ListBase rl, rv;
/* XXX. main should become an arg */
scen = BKE_scene_add(G.main, sce->id.name + 2);
- lb = scen->r.layers;
+ rl = scen->r.layers;
+ rv = scen->r.views;
scen->r = sce->r;
- scen->r.layers = lb;
+ scen->r.layers = rl;
scen->r.actlay = 0;
+ scen->r.views = rv;
scen->unit = sce->unit;
scen->physics_settings = sce->physics_settings;
scen->gm = sce->gm;
@@ -187,6 +196,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
scen->ed = NULL;
scen->theDag = NULL;
+ scen->depsgraph = NULL;
scen->obedit = NULL;
scen->stats = NULL;
scen->fps_info = NULL;
@@ -197,6 +207,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
BLI_duplicatelist(&(scen->markers), &(sce->markers));
BLI_duplicatelist(&(scen->transform_spaces), &(sce->transform_spaces));
BLI_duplicatelist(&(scen->r.layers), &(sce->r.layers));
+ BLI_duplicatelist(&(scen->r.views), &(sce->r.views));
BKE_keyingsets_copy(&(scen->keyingsets), &(sce->keyingsets));
if (sce->nodetree) {
@@ -224,7 +235,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
sizeof(scen->sequencer_colorspace_settings.name));
/* copy action and remove animation used by sequencer */
- BKE_copy_animdata_id_action(&scen->id);
+ BKE_animdata_copy_id_action(&scen->id);
if (type != SCE_COPY_FULL)
remove_sequencer_fcurves(scen);
@@ -233,6 +244,14 @@ Scene *BKE_scene_copy(Scene *sce, int type)
new_srl = scen->r.layers.first;
for (srl = sce->r.layers.first; srl; srl = srl->next) {
BKE_freestyle_config_copy(&new_srl->freestyleConfig, &srl->freestyleConfig);
+ if (type == SCE_COPY_FULL) {
+ for (lineset = new_srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
+ if (lineset->linestyle) {
+ id_us_plus((ID *)lineset->linestyle);
+ lineset->linestyle = BKE_linestyle_copy(G.main, lineset->linestyle);
+ }
+ }
+ }
new_srl = new_srl->next;
}
}
@@ -293,14 +312,14 @@ Scene *BKE_scene_copy(Scene *sce, int type)
}
/* before scene copy */
- sound_create_scene(scen);
+ BKE_sound_create_scene(scen);
/* world */
if (type == SCE_COPY_FULL) {
if (scen->world) {
id_us_plus((ID *)scen->world);
scen->world = BKE_world_copy(scen->world);
- BKE_copy_animdata_id_action((ID *)scen->world);
+ BKE_animdata_copy_id_action((ID *)scen->world);
}
if (sce->ed) {
@@ -361,7 +380,7 @@ void BKE_scene_free(Scene *sce)
BLI_freelistN(&sce->base);
BKE_sequencer_editing_free(sce);
- BKE_free_animdata((ID *)sce);
+ BKE_animdata_free((ID *)sce);
BKE_keyingsets_free(&sce->keyingsets);
if (sce->rigidbody_world)
@@ -390,6 +409,7 @@ void BKE_scene_free(Scene *sce)
BLI_freelistN(&sce->markers);
BLI_freelistN(&sce->transform_spaces);
BLI_freelistN(&sce->r.layers);
+ BLI_freelistN(&sce->r.views);
if (sce->toolsettings) {
if (sce->toolsettings->vpaint) {
@@ -415,6 +435,8 @@ void BKE_scene_free(Scene *sce)
}
DAG_scene_free(sce);
+ if (sce->depsgraph)
+ DEG_graph_free(sce->depsgraph);
if (sce->nodetree) {
ntreeFreeTree(sce->nodetree);
@@ -426,7 +448,7 @@ void BKE_scene_free(Scene *sce)
if (sce->fps_info)
MEM_freeN(sce->fps_info);
- sound_destroy_scene(sce);
+ BKE_sound_destroy_scene(sce);
BKE_color_managed_view_settings_free(&sce->view_settings);
}
@@ -437,6 +459,7 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
ParticleEditSettings *pset;
int a;
const char *colorspace_name;
+ SceneRenderView *srv;
sce = BKE_libblock_alloc(bmain, ID_SCE, name);
sce->lay = sce->layact = 1;
@@ -628,7 +651,16 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
/* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */
BKE_scene_add_render_layer(sce, NULL);
-
+
+ /* multiview - stereo */
+ BKE_scene_add_render_view(sce, STEREO_LEFT_NAME);
+ srv = sce->r.views.first;
+ BLI_strncpy(srv->suffix, STEREO_LEFT_SUFFIX, sizeof(srv->suffix));
+
+ BKE_scene_add_render_view(sce, STEREO_RIGHT_NAME);
+ srv = sce->r.views.last;
+ BLI_strncpy(srv->suffix, STEREO_RIGHT_SUFFIX, sizeof(srv->suffix));
+
/* game data */
sce->gm.stereoflag = STEREO_NOSTEREO;
sce->gm.stereomode = STEREO_ANAGLYPH;
@@ -665,7 +697,7 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
sce->gm.recastData.cellsize = 0.3f;
sce->gm.recastData.cellheight = 0.2f;
- sce->gm.recastData.agentmaxslope = M_PI / 2;
+ sce->gm.recastData.agentmaxslope = M_PI_4;
sce->gm.recastData.agentmaxclimb = 0.9f;
sce->gm.recastData.agentheight = 2.0f;
sce->gm.recastData.agentradius = 0.6f;
@@ -677,9 +709,12 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
sce->gm.recastData.detailsampledist = 6.0f;
sce->gm.recastData.detailsamplemaxerror = 1.0f;
+ sce->gm.lodflag = SCE_LOD_USE_HYST;
+ sce->gm.scehysteresis = 10;
+
sce->gm.exitkey = 218; // Blender key code for ESC
- sound_create_scene(sce);
+ BKE_sound_create_scene(sce);
/* color management */
colorspace_name = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_SEQUENCER);
@@ -698,6 +733,19 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
return sce;
}
+Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name)
+{
+ Base *base;
+
+ for (base = scene->base.first; base; base = base->next) {
+ if (STREQ(base->object->id.name + 2, name)) {
+ break;
+ }
+ }
+
+ return base;
+}
+
Base *BKE_scene_base_find(Scene *scene, Object *ob)
{
return BLI_findptr(&scene->base, ob, offsetof(Base, object));
@@ -767,33 +815,6 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name)
return NULL;
}
-static void scene_unlink_space_node(SpaceNode *snode, Scene *sce)
-{
- if (snode->id == &sce->id) {
- /* nasty DNA logic for SpaceNode:
- * ideally should be handled by editor code, but would be bad level call
- */
- bNodeTreePath *path, *path_next;
- for (path = snode->treepath.first; path; path = path_next) {
- path_next = path->next;
- MEM_freeN(path);
- }
- BLI_listbase_clear(&snode->treepath);
-
- snode->id = NULL;
- snode->from = NULL;
- snode->nodetree = NULL;
- snode->edittree = NULL;
- }
-}
-
-static void scene_unlink_space_buts(SpaceButs *sbuts, Scene *sce)
-{
- if (sbuts->pinid == &sce->id) {
- sbuts->pinid = NULL;
- }
-}
-
void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce)
{
Scene *sce1;
@@ -818,24 +839,11 @@ void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce)
/* all screens */
for (screen = bmain->screen.first; screen; screen = screen->id.next) {
- ScrArea *area;
-
- if (screen->scene == sce)
+ if (screen->scene == sce) {
screen->scene = newsce;
-
- for (area = screen->areabase.first; area; area = area->next) {
- SpaceLink *space_link;
- for (space_link = area->spacedata.first; space_link; space_link = space_link->next) {
- switch (space_link->spacetype) {
- case SPACE_NODE:
- scene_unlink_space_node((SpaceNode *)space_link, sce);
- break;
- case SPACE_BUTS:
- scene_unlink_space_buts((SpaceButs *)space_link, sce);
- break;
- }
- }
}
+
+ /* editors are handled by WM_main_remove_editor_id_reference */
}
BKE_libblock_free(bmain, sce);
@@ -1140,13 +1148,13 @@ bool BKE_scene_validate_setscene(Main *bmain, Scene *sce)
/* This function is needed to cope with fractional frames - including two Blender rendering features
* mblur (motion blur that renders 'subframes' and blurs them together), and fields rendering.
*/
-float BKE_scene_frame_get(Scene *scene)
+float BKE_scene_frame_get(const Scene *scene)
{
return BKE_scene_frame_get_from_ctime(scene, scene->r.cfra);
}
/* This function is used to obtain arbitrary fractional frames */
-float BKE_scene_frame_get_from_ctime(Scene *scene, const float frame)
+float BKE_scene_frame_get_from_ctime(const Scene *scene, const float frame)
{
float ctime = frame;
ctime += scene->r.subframe;
@@ -1165,6 +1173,7 @@ void BKE_scene_frame_set(struct Scene *scene, double cfra)
scene->r.cfra = (int)intpart;
}
+#ifdef WITH_LEGACY_DEPSGRAPH
/* drivers support/hacks
* - this method is called from scene_update_tagged_recursive(), so gets included in viewport + render
* - these are always run since the depsgraph can't handle non-object data
@@ -1265,6 +1274,7 @@ static void scene_depsgraph_hack(EvaluationContext *eval_ctx, Scene *scene, Scen
}
}
}
+#endif /* WITH_LEGACY_DEPSGRAPH */
/* That's like really a bummer, because currently animation data for armatures
* might want to use pose, and pose might be missing on the object.
@@ -1294,6 +1304,7 @@ static void scene_armature_depsgraph_workaround(Main *bmain)
}
#endif
+#ifdef WITH_LEGACY_DEPSGRAPH
static void scene_rebuild_rbw_recursive(Scene *scene, float ctime)
{
if (scene->set)
@@ -1311,12 +1322,18 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
if (BKE_scene_check_rigidbody_active(scene))
BKE_rigidbody_do_simulation(scene, ctime);
}
+#endif
/* Used to visualize CPU threads activity during threaded object update,
* would pollute STDERR with whole bunch of timing information which then
* could be parsed and nicely visualized.
*/
-#undef DETAILED_ANALYSIS_OUTPUT
+#ifdef WITH_LEGACY_DEPSGRAPH
+# undef DETAILED_ANALYSIS_OUTPUT
+#else
+/* ALWAYS KEEY DISABLED! */
+# undef DETAILED_ANALYSIS_OUTPUT
+#endif
/* Mballs evaluation uses BKE_scene_base_iter_next which calls
* duplilist for all objects in the scene. This leads to conflict
@@ -1328,6 +1345,7 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
*/
#define MBALL_SINGLETHREAD_HACK
+#ifdef WITH_LEGACY_DEPSGRAPH
typedef struct StatisicsEntry {
struct StatisicsEntry *next, *prev;
Object *object;
@@ -1342,13 +1360,13 @@ typedef struct ThreadedObjectUpdateState {
Scene *scene_parent;
double base_time;
- /* Execution statistics */
- ListBase statistics[BLENDER_MAX_THREADS];
- bool has_updated_objects;
-
#ifdef MBALL_SINGLETHREAD_HACK
bool has_mballs;
#endif
+
+ /* Execution statistics */
+ bool has_updated_objects;
+ ListBase *statistics;
} ThreadedObjectUpdateState;
static void scene_update_object_add_task(void *node, void *user_data);
@@ -1417,6 +1435,8 @@ static void scene_update_object_func(TaskPool *pool, void *taskdata, int threadi
if (add_to_stats) {
StatisicsEntry *entry;
+ BLI_assert(threadid < BLI_pool_get_num_threads(pool));
+
entry = MEM_mallocN(sizeof(StatisicsEntry), "update thread statistics");
entry->object = object;
entry->start_time = start_time;
@@ -1446,6 +1466,7 @@ static void scene_update_object_add_task(void *node, void *user_data)
static void print_threads_statistics(ThreadedObjectUpdateState *state)
{
int i, tot_thread;
+ double finish_time;
if ((G.debug & G_DEBUG_DEPSGRAPH) == 0) {
return;
@@ -1471,6 +1492,7 @@ static void print_threads_statistics(ThreadedObjectUpdateState *state)
}
}
#else
+ finish_time = PIL_check_seconds_timer();
tot_thread = BLI_system_thread_count();
for (i = 0; i < tot_thread; i++) {
@@ -1500,6 +1522,9 @@ static void print_threads_statistics(ThreadedObjectUpdateState *state)
BLI_freelistN(&state->statistics[i]);
}
+ if (state->has_updated_objects) {
+ printf("Scene update in %f sec\n", finish_time - state->base_time);
+ }
#endif
}
@@ -1545,7 +1570,9 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene
/* Those are only needed when blender is run with --debug argument. */
if (G.debug & G_DEBUG_DEPSGRAPH) {
- memset(state.statistics, 0, sizeof(state.statistics));
+ const int tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
+ state.statistics = MEM_callocN(tot_thread * sizeof(*state.statistics),
+ "scene update objects stats");
state.has_updated_objects = false;
state.base_time = PIL_check_seconds_timer();
}
@@ -1555,6 +1582,9 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene
#endif
task_pool = BLI_task_pool_create(task_scheduler, &state);
+ if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
+ BLI_pool_set_num_threads(task_pool, 1);
+ }
DAG_threaded_update_begin(scene, scene_update_object_add_task, task_pool);
BLI_task_pool_work_and_wait(task_pool);
@@ -1562,6 +1592,7 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene
if (G.debug & G_DEBUG_DEPSGRAPH) {
print_threads_statistics(&state);
+ MEM_freeN(state.statistics);
}
/* We do single thread pass to update all the objects which are in cyclic dependency.
@@ -1607,6 +1638,7 @@ static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bma
BKE_mask_update_scene(bmain, scene);
}
+#endif /* WITH_LEGACY_DEPSGRAPH */
static bool check_rendered_viewport_visible(Main *bmain)
{
@@ -1658,13 +1690,26 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene)
{
Scene *sce_iter;
-
+#ifdef WITH_LEGACY_DEPSGRAPH
+ bool use_new_eval = !DEG_depsgraph_use_legacy();
+#endif
+
/* keep this first */
BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_PRE);
/* (re-)build dependency graph if needed */
- for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set)
+ for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) {
DAG_scene_relations_update(bmain, sce_iter);
+ /* Uncomment this to check if graph was properly tagged for update. */
+#if 0
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (use_new_eval)
+#endif
+ {
+ DAG_scene_relations_validate(bmain, sce_iter);
+ }
+#endif
+ }
/* flush editing data if needed */
prepare_mesh_for_viewport_render(bmain, scene);
@@ -1685,9 +1730,19 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
*
* in the future this should handle updates for all datablocks, not
* only objects and scenes. - brecht */
- scene_update_tagged_recursive(eval_ctx, bmain, scene, scene);
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (use_new_eval) {
+ DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene);
+ }
+ else {
+ scene_update_tagged_recursive(eval_ctx, bmain, scene, scene);
+ }
+#else
+ DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene);
+#endif
+
/* update sound system animation (TODO, move to depsgraph) */
- sound_update_scene(bmain, scene);
+ BKE_sound_update_scene(bmain, scene);
/* extra call here to recalc scene animation (for sequencer) */
{
@@ -1703,7 +1758,8 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
* Need to do this so changing material settings from the graph/dopesheet
* will update stuff in the viewport.
*/
- if (DAG_id_type_tagged(bmain, ID_MA)) {
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval && DAG_id_type_tagged(bmain, ID_MA)) {
Material *material;
float ctime = BKE_scene_frame_get(scene);
@@ -1718,7 +1774,7 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
}
/* Also do the same for node trees. */
- if (DAG_id_type_tagged(bmain, ID_NT)) {
+ if (!use_new_eval && DAG_id_type_tagged(bmain, ID_NT)) {
float ctime = BKE_scene_frame_get(scene);
FOREACH_NODETREE(bmain, ntree, id)
@@ -1729,9 +1785,12 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
}
FOREACH_NODETREE_END
}
+#endif
/* notify editors and python about recalc */
BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_POST);
+
+ /* Inform editors about possible changes. */
DAG_ids_check_recalc(bmain, scene, false);
/* clear recalc flags */
@@ -1751,6 +1810,12 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
#ifdef DETAILED_ANALYSIS_OUTPUT
double start_time = PIL_check_seconds_timer();
#endif
+#ifdef WITH_LEGACY_DEPSGRAPH
+ bool use_new_eval = !DEG_depsgraph_use_legacy();
+#else
+ /* TODO(sergey): Pass to evaluation routines instead of storing layer in the graph? */
+ (void) do_invisible_flush;
+#endif
/* keep this first */
BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
@@ -1760,28 +1825,39 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
* call this at the start so modifiers with textures don't lag 1 frame */
BKE_image_update_frame(bmain, sce->r.cfra);
+#ifdef WITH_LEGACY_DEPSGRAPH
/* rebuild rigid body worlds before doing the actual frame update
* this needs to be done on start frame but animation playback usually starts one frame later
* we need to do it here to avoid rebuilding the world on every simulation change, which can be very expensive
*/
- scene_rebuild_rbw_recursive(sce, ctime);
-
- sound_set_cfra(sce->r.cfra);
+ if (!use_new_eval) {
+ scene_rebuild_rbw_recursive(sce, ctime);
+ }
+#endif
+
+ BKE_sound_set_cfra(sce->r.cfra);
/* clear animation overrides */
/* XXX TODO... */
+ /* tag cached objects */
+ BKE_cache_library_dag_recalc_tag(eval_ctx, bmain);
+
for (sce_iter = sce; sce_iter; sce_iter = sce_iter->set)
DAG_scene_relations_update(bmain, sce_iter);
- /* flush recalc flags to dependencies, if we were only changing a frame
- * this would not be necessary, but if a user or a script has modified
- * some datablock before BKE_scene_update_tagged was called, we need the flush */
- DAG_ids_flush_tagged(bmain);
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval) {
+ /* flush recalc flags to dependencies, if we were only changing a frame
+ * this would not be necessary, but if a user or a script has modified
+ * some datablock before BKE_scene_update_tagged was called, we need the flush */
+ DAG_ids_flush_tagged(bmain);
- /* Following 2 functions are recursive
- * so don't call within 'scene_update_tagged_recursive' */
- DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still
+ /* Following 2 functions are recursive
+ * so don't call within 'scene_update_tagged_recursive' */
+ DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still
+ }
+#endif
BKE_mask_evaluate_all_masks(bmain, ctime, true);
@@ -1795,8 +1871,12 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
* can be overridden by settings from Scene, which owns the Texture through a hierarchy
* such as Scene->World->MTex/Texture) can still get correctly overridden.
*/
- BKE_animsys_evaluate_all_animation(bmain, sce, ctime);
- /*...done with recursive funcs */
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval) {
+ BKE_animsys_evaluate_all_animation(bmain, sce, ctime);
+ /*...done with recursive funcs */
+ }
+#endif
/* clear "LIB_DOIT" flag from all materials, to prevent infinite recursion problems later
* when trying to find materials with drivers that need evaluating [#32017]
@@ -1806,19 +1886,38 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
/* run rigidbody sim */
/* NOTE: current position is so that rigidbody sim affects other objects, might change in the future */
- scene_do_rb_simulation_recursive(sce, ctime);
-
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval) {
+ scene_do_rb_simulation_recursive(sce, ctime);
+ }
+#endif
+
/* BKE_object_handle_update() on all objects, groups and sets */
- scene_update_tagged_recursive(eval_ctx, bmain, sce, sce);
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (use_new_eval) {
+ DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay);
+ }
+ else {
+ scene_update_tagged_recursive(eval_ctx, bmain, sce, sce);
+ }
+#else
+ DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay);
+#endif
+
/* update sound system animation (TODO, move to depsgraph) */
- sound_update_scene(bmain, sce);
+ BKE_sound_update_scene(bmain, sce);
- scene_depsgraph_hack(eval_ctx, sce, sce);
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval) {
+ scene_depsgraph_hack(eval_ctx, sce, sce);
+ }
+#endif
/* notify editors and python about recalc */
BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_POST);
BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_POST);
+ /* Inform editors about possible changes. */
DAG_ids_check_recalc(bmain, sce, true);
/* clear recalc flags */
@@ -1829,6 +1928,45 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
#endif
}
+void BKE_scene_update_group_for_newframe(EvaluationContext *eval_ctx,
+ Main *bmain,
+ Scene *scene,
+ Group *group,
+ unsigned int lay)
+{
+ float ctime = BKE_scene_frame_get(scene);
+ Scene *sce_iter;
+
+ /* Step 1: Preparation, same as in regular frame update. */
+ BKE_image_update_frame(bmain, scene->r.cfra);
+ scene_rebuild_rbw_recursive(scene, ctime);
+ BKE_cache_library_dag_recalc_tag(eval_ctx, bmain);
+ for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) {
+ DAG_scene_relations_update(bmain, sce_iter);
+ }
+
+ /* Step 2: Tag objects which we need to update. */
+ DAG_ids_flush_tagged(bmain);
+ DAG_scene_update_group_flags(bmain, scene, group, lay, true, false);
+
+ /* Step 3: Update animation. */
+#ifdef POSE_ANIMATION_WORKAROUND
+ scene_armature_depsgraph_workaround(bmain);
+#endif
+ BKE_animsys_evaluate_all_animation(bmain, scene, ctime);
+
+ /* Step 4: Actual evaluation. */
+ BKE_main_id_tag_idcode(bmain, ID_MA, false);
+ BKE_main_id_tag_idcode(bmain, ID_LA, false);
+ scene_do_rb_simulation_recursive(scene, ctime);
+ scene_update_tagged_recursive(eval_ctx, bmain, scene, scene);
+ scene_depsgraph_hack(eval_ctx, scene, scene);
+
+ /* Step 5: Cleanup after evaluaiton. */
+ DAG_ids_check_recalc(bmain, scene, true);
+ DAG_ids_clear_recalc(bmain);
+}
+
/* return default layer, also used to patch old files */
SceneRenderLayer *BKE_scene_add_render_layer(Scene *sce, const char *name)
{
@@ -1889,25 +2027,71 @@ bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer *
return true;
}
+/* return default view */
+SceneRenderView *BKE_scene_add_render_view(Scene *sce, const char *name)
+{
+ SceneRenderView *srv;
+
+ if (!name)
+ name = DATA_("RenderView");
+
+ srv = MEM_callocN(sizeof(SceneRenderView), "new render view");
+ BLI_strncpy(srv->name, name, sizeof(srv->name));
+ BLI_uniquename(&sce->r.views, srv, DATA_("RenderView"), '.', offsetof(SceneRenderView, name), sizeof(srv->name));
+ BLI_addtail(&sce->r.views, srv);
+
+ return srv;
+}
+
+bool BKE_scene_remove_render_view(Scene *scene, SceneRenderView *srv)
+{
+ const int act = BLI_findindex(&scene->r.views, srv);
+
+ if (act == -1) {
+ return false;
+ }
+ else if (scene->r.views.first == scene->r.views.last) {
+ /* ensure 1 view is kept */
+ return false;
+ }
+
+ BLI_remlink(&scene->r.views, srv);
+ MEM_freeN(srv);
+
+ scene->r.actview = 0;
+
+ return true;
+}
+
/* render simplification */
-int get_render_subsurf_level(RenderData *r, int lvl)
+int get_render_subsurf_level(const RenderData *r, int lvl, bool for_render)
{
- if (r->mode & R_SIMPLIFY)
- return min_ii(r->simplify_subsurf, lvl);
- else
+ if (r->mode & R_SIMPLIFY) {
+ if (for_render)
+ return min_ii(r->simplify_subsurf_render, lvl);
+ else
+ return min_ii(r->simplify_subsurf, lvl);
+ }
+ else {
return lvl;
+ }
}
-int get_render_child_particle_number(RenderData *r, int num)
+int get_render_child_particle_number(const RenderData *r, int num, bool for_render)
{
- if (r->mode & R_SIMPLIFY)
- return (int)(r->simplify_particles * num);
- else
+ if (r->mode & R_SIMPLIFY) {
+ if (for_render)
+ return (int)(r->simplify_particles_render * num);
+ else
+ return (int)(r->simplify_particles * num);
+ }
+ else {
return num;
+ }
}
-int get_render_shadow_samples(RenderData *r, int samples)
+int get_render_shadow_samples(const RenderData *r, int samples)
{
if ((r->mode & R_SIMPLIFY) && samples > 0)
return min_ii(r->simplify_shadowsamples, samples);
@@ -1915,7 +2099,7 @@ int get_render_shadow_samples(RenderData *r, int samples)
return samples;
}
-float get_render_aosss_error(RenderData *r, float error)
+float get_render_aosss_error(const RenderData *r, float error)
{
if (r->mode & R_SIMPLIFY)
return ((1.0f - r->simplify_aosss) * 10.0f + 1.0f) * error;
@@ -1947,18 +2131,24 @@ Base *_setlooper_base_step(Scene **sce_iter, Base *base)
return NULL;
}
-bool BKE_scene_use_new_shading_nodes(Scene *scene)
+bool BKE_scene_use_new_shading_nodes(const Scene *scene)
{
- RenderEngineType *type = RE_engines_find(scene->r.engine);
+ const RenderEngineType *type = RE_engines_find(scene->r.engine);
return (type && type->flag & RE_USE_SHADING_NODES);
}
-bool BKE_scene_uses_blender_internal(struct Scene *scene)
+bool BKE_scene_use_shading_nodes_custom(Scene *scene)
+{
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+ return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM);
+}
+
+bool BKE_scene_uses_blender_internal(const Scene *scene)
{
return STREQ(scene->r.engine, RE_engine_id_BLENDER_RENDER);
}
-bool BKE_scene_uses_blender_game(struct Scene *scene)
+bool BKE_scene_uses_blender_game(const Scene *scene)
{
return STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME);
}
@@ -2059,3 +2249,283 @@ double BKE_scene_unit_scale(const UnitSettings *unit, const int unit_type, doubl
return value;
}
}
+
+/******************** multiview *************************/
+
+size_t BKE_scene_multiview_num_views_get(const RenderData *rd)
+{
+ SceneRenderView *srv;
+ size_t totviews = 0;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return 1;
+
+ if (rd->views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
+ srv = BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name));
+ if ((srv && srv->viewflag & SCE_VIEW_DISABLE) == 0) {
+ totviews++;
+ }
+
+ srv = BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name));
+ if ((srv && srv->viewflag & SCE_VIEW_DISABLE) == 0) {
+ totviews++;
+ }
+ }
+ else {
+ for (srv = rd->views.first; srv; srv = srv->next) {
+ if ((srv->viewflag & SCE_VIEW_DISABLE) == 0) {
+ totviews++;
+ }
+ }
+ }
+ return totviews;
+}
+
+bool BKE_scene_multiview_is_stereo3d(const RenderData *rd)
+{
+ SceneRenderView *srv[2];
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return false;
+
+ srv[0] = (SceneRenderView *)BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name));
+ srv[1] = (SceneRenderView *)BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name));
+
+ return (srv[0] && ((srv[0]->viewflag & SCE_VIEW_DISABLE) == 0) &&
+ srv[1] && ((srv[1]->viewflag & SCE_VIEW_DISABLE) == 0));
+}
+
+/* return whether to render this SceneRenderView */
+bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv)
+{
+ if (srv == NULL)
+ return false;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return false;
+
+ if ((srv->viewflag & SCE_VIEW_DISABLE))
+ return false;
+
+ if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW)
+ return true;
+
+ /* SCE_VIEWS_SETUP_BASIC */
+ if (STREQ(srv->name, STEREO_LEFT_NAME) ||
+ STREQ(srv->name, STEREO_RIGHT_NAME))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+/* return true if viewname is the first or if the name is NULL or not found */
+bool BKE_scene_multiview_is_render_view_first(const RenderData *rd, const char *viewname)
+{
+ SceneRenderView *srv;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return true;
+
+ if ((!viewname) || (!viewname[0]))
+ return true;
+
+ for (srv = rd->views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ return STREQ(viewname, srv->name);
+ }
+ }
+
+ return true;
+}
+
+/* return true if viewname is the last or if the name is NULL or not found */
+bool BKE_scene_multiview_is_render_view_last(const RenderData *rd, const char *viewname)
+{
+ SceneRenderView *srv;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return true;
+
+ if ((!viewname) || (!viewname[0]))
+ return true;
+
+ for (srv = rd->views.last; srv; srv = srv->prev) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ return STREQ(viewname, srv->name);
+ }
+ }
+
+ return true;
+}
+
+SceneRenderView *BKE_scene_multiview_render_view_findindex(const RenderData *rd, const int view_id)
+{
+ SceneRenderView *srv;
+ size_t nr;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return NULL;
+
+ nr = 0;
+ for (srv = rd->views.first, nr = 0; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ if (nr++ == view_id)
+ return srv;
+ }
+ }
+ return srv;
+}
+
+const char *BKE_scene_multiview_render_view_name_get(const RenderData *rd, const int view_id)
+{
+ SceneRenderView *srv = BKE_scene_multiview_render_view_findindex(rd, view_id);
+
+ if (srv)
+ return srv->name;
+ else
+ return "";
+}
+
+size_t BKE_scene_multiview_view_id_get(const RenderData *rd, const char *viewname)
+{
+ SceneRenderView *srv;
+ size_t nr;
+
+ if ((!rd) || ((rd->scemode & R_MULTIVIEW) == 0))
+ return 0;
+
+ if ((!viewname) || (!viewname[0]))
+ return 0;
+
+ nr = 0;
+ for (srv = rd->views.first, nr = 0; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ if (STREQ(viewname, srv->name)) {
+ return nr;
+ }
+ else {
+ nr += 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void BKE_scene_multiview_filepath_get(
+ SceneRenderView *srv, const char *filepath,
+ char *r_filepath)
+{
+ BLI_strncpy(r_filepath, filepath, FILE_MAX);
+ BLI_path_suffix(r_filepath, FILE_MAX, srv->suffix, "");
+}
+
+/**
+ * When multiview is not used the filepath is as usual (e.g., ``Image.jpg``).
+ * When multiview is on, even if only one view is enabled the view is incorporated
+ * into the file name (e.g., ``Image_L.jpg``). That allows for the user to re-render
+ * individual views.
+ */
+void BKE_scene_multiview_view_filepath_get(
+ const RenderData *rd, const char *filepath, const char *viewname,
+ char *r_filepath)
+{
+ SceneRenderView *srv;
+ char suffix[FILE_MAX];
+
+ srv = BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name));
+ if (srv)
+ BLI_strncpy(suffix, srv->suffix, sizeof(suffix));
+ else
+ BLI_strncpy(suffix, viewname, sizeof(suffix));
+
+ BLI_strncpy(r_filepath, filepath, FILE_MAX);
+ BLI_path_suffix(r_filepath, FILE_MAX, suffix, "");
+}
+
+const char *BKE_scene_multiview_view_suffix_get(const RenderData *rd, const char *viewname)
+{
+ SceneRenderView *srv;
+
+ if ((viewname == NULL) || (viewname[0] == '\0'))
+ return viewname;
+
+ srv = BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name));
+ if (srv)
+ return srv->suffix;
+ else
+ return viewname;
+}
+
+const char *BKE_scene_multiview_view_id_suffix_get(const RenderData *rd, const size_t view_id)
+{
+ if ((rd->scemode & R_MULTIVIEW) == 0) {
+ return "";
+ }
+ else {
+ const char *viewname = BKE_scene_multiview_render_view_name_get(rd, view_id);
+ return BKE_scene_multiview_view_suffix_get(rd, viewname);
+ }
+}
+
+void BKE_scene_multiview_view_prefix_get(Scene *scene, const char *name, char *rprefix, char **rext)
+{
+ SceneRenderView *srv;
+ size_t index_act;
+ char *suf_act;
+ const char delims[] = {'.', '\0'};
+
+ rprefix[0] = '\0';
+
+ /* begin of extension */
+ index_act = BLI_str_rpartition(name, delims, rext, &suf_act);
+ BLI_assert(index_act > 0);
+
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
+ size_t len = strlen(srv->suffix);
+ if (STREQLEN(*rext - len, srv->suffix, len)) {
+ BLI_strncpy(rprefix, name, strlen(name) - strlen(*rext) - len + 1);
+ break;
+ }
+ }
+ }
+}
+
+void BKE_scene_multiview_videos_dimensions_get(
+ const RenderData *rd, const size_t width, const size_t height,
+ size_t *r_width, size_t *r_height)
+{
+ if ((rd->scemode & R_MULTIVIEW) &&
+ rd->im_format.views_format == R_IMF_VIEWS_STEREO_3D)
+ {
+ IMB_stereo3d_write_dimensions(
+ rd->im_format.stereo3d_format.display_mode,
+ (rd->im_format.stereo3d_format.flag & S3D_SQUEEZED_FRAME) != 0,
+ width, height,
+ r_width, r_height);
+ }
+ else {
+ *r_width = width;
+ *r_height = height;
+ }
+}
+
+size_t BKE_scene_multiview_num_videos_get(const RenderData *rd)
+{
+ if (BKE_imtype_is_movie(rd->im_format.imtype) == false)
+ return 0;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return 1;
+
+ if (rd->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
+ return 1;
+ }
+ else {
+ /* R_IMF_VIEWS_INDIVIDUAL */
+ return BKE_scene_multiview_num_views_get(rd);
+ }
+}
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index ebbfc3d2a40..83aac79ae0b 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -276,6 +276,19 @@ void BKE_spacedata_draw_locks(int set)
}
}
+static void (*spacedata_id_unref_cb)(struct SpaceLink *sl, const struct ID *id) = NULL;
+
+void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *))
+{
+ spacedata_id_unref_cb = func;
+}
+
+void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id)
+{
+ if (spacedata_id_unref_cb) {
+ spacedata_id_unref_cb(sl, id);
+ }
+}
/* not region itself */
void BKE_area_region_free(SpaceType *st, ARegion *ar)
@@ -416,6 +429,23 @@ ARegion *BKE_area_find_region_active_win(ScrArea *sa)
return NULL;
}
+ARegion *BKE_area_find_region_xy(ScrArea *sa, const int regiontype, int x, int y)
+{
+ ARegion *ar_found = NULL;
+ if (sa) {
+ ARegion *ar;
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if ((regiontype == RGN_TYPE_ANY) || (ar->regiontype == regiontype)) {
+ if (BLI_rcti_isect_pt(&ar->winrct, x, y)) {
+ ar_found = ar;
+ break;
+ }
+ }
+ }
+ }
+ return ar_found;
+}
+
/**
* \note, ideally we can get the area from the context,
* there are a few places however where this isn't practical.
@@ -499,6 +529,23 @@ unsigned int BKE_screen_view3d_layer_active(const struct View3D *v3d, const stru
return BKE_screen_view3d_layer_active_ex(v3d, scene, true);
}
+/**
+ * Accumulate all visible layers on this screen.
+ */
+unsigned int BKE_screen_view3d_layer_all(const bScreen *sc)
+{
+ const ScrArea *sa;
+ unsigned int lay = 0;
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = sa->spacedata.first;
+ lay |= v3d->lay;
+ }
+ }
+
+ return lay;
+}
+
void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
{
int bit;
@@ -521,8 +568,8 @@ void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
if ((v3d->lay & v3d->layact) == 0) {
for (bit = 0; bit < 32; bit++) {
- if (v3d->lay & (1 << bit)) {
- v3d->layact = 1 << bit;
+ if (v3d->lay & (1u << bit)) {
+ v3d->layact = (1u << bit);
break;
}
}
diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c
index 05d6bf136a4..69ba7618981 100644
--- a/source/blender/blenkernel/intern/seqcache.c
+++ b/source/blender/blenkernel/intern/seqcache.c
@@ -35,6 +35,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_sequence_types.h"
+#include "DNA_scene_types.h"
#include "IMB_moviecache.h"
#include "IMB_imbuf.h"
@@ -43,6 +44,7 @@
#include "BLI_listbase.h"
#include "BKE_sequencer.h"
+#include "BKE_scene.h"
typedef struct SeqCacheKey {
struct Sequence *seq;
@@ -79,7 +81,9 @@ static bool seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
(a->bmain != b->bmain) ||
(a->scene != b->scene) ||
(a->motion_blur_shutter != b->motion_blur_shutter) ||
- (a->motion_blur_samples != b->motion_blur_samples));
+ (a->motion_blur_samples != b->motion_blur_samples) ||
+ (a->scene->r.views_format != b->scene->r.views_format) ||
+ (a->view_id != b->view_id));
}
static unsigned int seq_hash_render_data(const SeqRenderData *a)
@@ -91,6 +95,7 @@ static unsigned int seq_hash_render_data(const SeqRenderData *a)
rval ^= ((intptr_t) a->scene) << 6;
rval ^= (int)(a->motion_blur_shutter * 100.0f) << 10;
rval ^= a->motion_blur_samples << 24;
+ rval ^= ((a->scene->r.views_format * 2) + a->view_id) << 32;
return rval;
}
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 6157d63047e..a8787d44914 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -52,9 +52,6 @@
#include "RNA_access.h"
-/* TODO(sergey): Could be considered a bad level call, but
- * need this for gaussian table.
- */
#include "RE_pipeline.h"
static void slice_get_byte_buffers(const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2,
diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c
index b78529f51b4..f543a9f4c65 100644
--- a/source/blender/blenkernel/intern/seqmodifier.c
+++ b/source/blender/blenkernel/intern/seqmodifier.c
@@ -77,9 +77,9 @@ typedef struct ModifierThread {
} ModifierThread;
-static ImBuf *modifier_mask_get(SequenceModifierData *smd, const SeqRenderData *context, int cfra, bool make_float)
+static ImBuf *modifier_mask_get(SequenceModifierData *smd, const SeqRenderData *context, int cfra, int fra_offset, bool make_float)
{
- return BKE_sequencer_render_mask_input(context, smd->mask_input_type, smd->mask_sequence, smd->mask_id, cfra, make_float);
+ return BKE_sequencer_render_mask_input(context, smd->mask_input_type, smd->mask_sequence, smd->mask_id, cfra, fra_offset, make_float);
}
static void modifier_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
@@ -531,15 +531,11 @@ static void maskmodifier_apply_threaded(int width, int height, unsigned char *re
}
}
-static void maskmodifier_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
+static void maskmodifier_apply(struct SequenceModifierData *UNUSED(smd), ImBuf *ibuf, ImBuf *mask)
{
- BrightContrastModifierData *bcmd = (BrightContrastModifierData *) smd;
- BrightContrastThreadData data;
-
- data.bright = bcmd->bright;
- data.contrast = bcmd->contrast;
+ // SequencerMaskModifierData *bcmd = (SequencerMaskModifierData *)smd;
- modifier_apply_threaded(ibuf, mask, maskmodifier_apply_threaded, &data);
+ modifier_apply_threaded(ibuf, mask, maskmodifier_apply_threaded, NULL);
}
static SequenceModifierTypeInfo seqModifier_Mask = {
@@ -567,7 +563,7 @@ static void sequence_modifier_type_info_init(void)
#undef INIT_TYPE
}
-SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type)
+const SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type)
{
if (!modifierTypesInit) {
sequence_modifier_type_info_init();
@@ -580,7 +576,7 @@ SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type)
SequenceModifierData *BKE_sequence_modifier_new(Sequence *seq, const char *name, int type)
{
SequenceModifierData *smd;
- SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(type);
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(type);
smd = MEM_callocN(smti->struct_size, "sequence modifier");
@@ -627,7 +623,7 @@ void BKE_sequence_modifier_clear(Sequence *seq)
void BKE_sequence_modifier_free(SequenceModifierData *smd)
{
- SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
if (smti && smti->free_data) {
smti->free_data(smd);
@@ -638,7 +634,7 @@ void BKE_sequence_modifier_free(SequenceModifierData *smd)
void BKE_sequence_modifier_unique_name(Sequence *seq, SequenceModifierData *smd)
{
- SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
BLI_uniquename(&seq->modifiers, smd, CTX_DATA_(BLF_I18NCONTEXT_ID_SEQUENCE, smti->name), '.',
offsetof(SequenceModifierData, name), sizeof(smd->name));
@@ -660,7 +656,7 @@ ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context, Sequence
}
for (smd = seq->modifiers.first; smd; smd = smd->next) {
- SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
/* could happen if modifier is being removed or not exists in current version of blender */
if (!smti)
@@ -671,7 +667,7 @@ ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context, Sequence
continue;
if (smti->apply) {
- ImBuf *mask = modifier_mask_get(smd, context, cfra, ibuf->rect_float != NULL);
+ ImBuf *mask = modifier_mask_get(smd, context, cfra, seq->start, ibuf->rect_float != NULL);
if (processed_ibuf == ibuf)
processed_ibuf = IMB_dupImBuf(ibuf);
@@ -696,7 +692,7 @@ void BKE_sequence_modifier_list_copy(Sequence *seqn, Sequence *seq)
for (smd = seq->modifiers.first; smd; smd = smd->next) {
SequenceModifierData *smdn;
- SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
smdn = MEM_dupallocN(smd);
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index ee41c2b3208..1cff097df5e 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -53,6 +53,12 @@
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#ifdef WIN32
+# include "BLI_winstuff.h"
+#else
+# include <unistd.h>
+#endif
+
#include "BLF_translation.h"
#include "BKE_animsys.h"
@@ -66,6 +72,7 @@
#include "BKE_scene.h"
#include "BKE_mask.h"
#include "BKE_library.h"
+#include "BKE_idprop.h"
#include "RNA_access.h"
@@ -88,6 +95,8 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq
static ImBuf *seq_render_strip(const SeqRenderData *context, Sequence *seq, float cfra);
static void seq_free_animdata(Scene *scene, Sequence *seq);
static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr, bool make_float);
+static size_t seq_num_files(Scene *scene, char views_format, const bool is_multiview);
+static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const size_t view_id);
/* **** XXX ******** */
#define SELECT 1
@@ -180,10 +189,7 @@ static void BKE_sequence_free_ex(Scene *scene, Sequence *seq, const bool do_cach
if (seq->strip)
seq_free_strip(seq->strip);
- if (seq->anim) {
- IMB_free_anim(seq->anim);
- seq->anim = NULL;
- }
+ BKE_sequence_free_anim(seq);
if (seq->type & SEQ_TYPE_EFFECT) {
struct SeqEffectHandle sh = BKE_sequence_get_effect(seq);
@@ -195,6 +201,10 @@ static void BKE_sequence_free_ex(Scene *scene, Sequence *seq, const bool do_cach
((ID *)seq->sound)->us--;
}
+ if (seq->stereo3d_format) {
+ MEM_freeN(seq->stereo3d_format);
+ }
+
/* clipboard has no scene and will never have a sound handle or be active
* same goes to sequences copy for proxy rebuild job
*/
@@ -205,11 +215,16 @@ static void BKE_sequence_free_ex(Scene *scene, Sequence *seq, const bool do_cach
ed->act_seq = NULL;
if (seq->scene_sound && ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE))
- sound_remove_scene_sound(scene, seq->scene_sound);
+ BKE_sound_remove_scene_sound(scene, seq->scene_sound);
seq_free_animdata(scene, seq);
}
+ if (seq->prop) {
+ IDP_FreeProperty(seq->prop);
+ MEM_freeN(seq->prop);
+ }
+
/* free modifiers */
BKE_sequence_modifier_clear(seq);
@@ -234,6 +249,22 @@ void BKE_sequence_free(Scene *scene, Sequence *seq)
BKE_sequence_free_ex(scene, seq, true);
}
+/* Function to free imbuf and anim data on changes */
+void BKE_sequence_free_anim(Sequence *seq)
+{
+ while (seq->anims.last) {
+ StripAnim *sanim = seq->anims.last;
+
+ if (sanim->anim) {
+ IMB_free_anim(sanim->anim);
+ sanim->anim = NULL;
+ }
+
+ BLI_freelinkN(&seq->anims, sanim);
+ }
+ BLI_listbase_clear(&seq->anims);
+}
+
/* cache must be freed before calling this function
* since it leaves the seqbase in an invalid state */
static void seq_free_sequence_recurse(Scene *scene, Sequence *seq)
@@ -316,7 +347,7 @@ static void seqclipboard_ptr_restore(Main *bmain, ID **id_pt)
{
id_restore = BLI_findstring(lb, ((bSound *)ID_PT)->name, offsetof(bSound, name));
if (id_restore == NULL) {
- id_restore = sound_new_file(bmain, ((bSound *)ID_PT)->name);
+ id_restore = BKE_sound_new_file(bmain, ((bSound *)ID_PT)->name);
(ID_PT)->newid = id_restore; /* reuse next time */
}
break;
@@ -531,6 +562,7 @@ void BKE_sequencer_new_render_data(
r_context->motion_blur_shutter = 0;
r_context->skip_cache = false;
r_context->is_proxy_render = false;
+ r_context->view_id = 0;
}
/* ************************* iterator ************************** */
@@ -652,7 +684,7 @@ static void seq_update_sound_bounds_recursive_rec(Scene *scene, Sequence *metase
if (seq->start + seq->len - seq->endofs > end)
endofs = seq->start + seq->len - end;
- sound_move_scene_sound(scene, seq->scene_sound, seq->start + startofs,
+ BKE_sound_move_scene_sound(scene, seq->scene_sound, seq->start + startofs,
seq->start + seq->len - endofs, startofs + seq->anim_startofs);
}
}
@@ -765,10 +797,17 @@ void BKE_sequence_calc(Scene *scene, Sequence *seq)
}
}
+static void seq_multiview_name(Scene *scene, const size_t view_id, const char *prefix,
+ const char *ext, char *r_path, size_t r_size)
+{
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
+ BLI_snprintf(r_path, r_size, "%s%s%s", prefix, suffix, ext);
+}
+
/* note: caller should run BKE_sequence_calc(scene, seq) after */
void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_range)
{
- char str[FILE_MAX];
+ char path[FILE_MAX];
int prev_startdisp = 0, prev_enddisp = 0;
/* note: don't rename the strip, will break animation curves */
@@ -801,22 +840,67 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r
break;
}
case SEQ_TYPE_MOVIE:
- BLI_join_dirfile(str, sizeof(str), seq->strip->dir,
+ {
+ StripAnim *sanim;
+ bool is_multiview_loaded = false;
+ const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
+ (scene->r.scemode & R_MULTIVIEW) != 0;
+
+ BLI_join_dirfile(path, sizeof(path), seq->strip->dir,
seq->strip->stripdata->name);
- BLI_path_abs(str, G.main->name);
+ BLI_path_abs(path, G.main->name);
+
+ BKE_sequence_free_anim(seq);
+
+ if (is_multiview && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ char prefix[FILE_MAX];
+ char *ext = NULL;
+ size_t totfiles = seq_num_files(scene, seq->views_format, true);
+ int i = 0;
+
+ BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
+
+ if (prefix[0] != '\0') {
+ for (i = 0; i < totfiles; i++) {
+ struct anim *anim;
+ char str[FILE_MAX];
- if (seq->anim) IMB_free_anim(seq->anim);
+ seq_multiview_name(scene, i, prefix, ext, str, FILE_MAX);
+ anim = openanim(str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
- seq->anim = openanim(str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
+ if (anim) {
+ seq_anim_add_suffix(scene, anim, i);
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = anim;
+ }
+ }
+ is_multiview_loaded = true;
+ }
+ }
+
+ if (is_multiview_loaded == false) {
+ struct anim *anim;
+ anim = openanim(path, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ if (anim) {
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = anim;
+ }
+ }
- if (!seq->anim) {
+ /* use the first video as reference for everything */
+ sanim = seq->anims.first;
+
+ if ((!sanim) || (!sanim->anim)) {
return;
}
- seq->len = IMB_anim_get_duration(seq->anim, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN);
-
- seq->anim_preseek = IMB_anim_get_preseek(seq->anim);
+ seq->len = IMB_anim_get_duration(sanim->anim, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN);
+
+ seq->anim_preseek = IMB_anim_get_preseek(sanim->anim);
seq->len -= seq->anim_startofs;
seq->len -= seq->anim_endofs;
@@ -824,6 +908,7 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r
seq->len = 0;
}
break;
+ }
case SEQ_TYPE_MOVIECLIP:
if (seq->clip == NULL)
return;
@@ -1103,30 +1188,25 @@ static void make_black_ibuf(ImBuf *ibuf)
}
}
-static void multibuf(ImBuf *ibuf, float fmul)
+static void multibuf(ImBuf *ibuf, const float fmul)
{
char *rt;
float *rt_float;
- int a, mul, icol;
+ int a;
- mul = (int)(256.0f * fmul);
rt = (char *)ibuf->rect;
rt_float = ibuf->rect_float;
if (rt) {
+ const int imul = (int)(256.0f * fmul);
a = ibuf->x * ibuf->y;
while (a--) {
+ rt[0] = min_ii((imul * rt[0]) >> 8, 255);
+ rt[1] = min_ii((imul * rt[1]) >> 8, 255);
+ rt[2] = min_ii((imul * rt[2]) >> 8, 255);
+ rt[3] = min_ii((imul * rt[3]) >> 8, 255);
- icol = (mul * rt[0]) >> 8;
- if (icol > 254) rt[0] = 255; else rt[0] = icol;
- icol = (mul * rt[1]) >> 8;
- if (icol > 254) rt[1] = 255; else rt[1] = icol;
- icol = (mul * rt[2]) >> 8;
- if (icol > 254) rt[2] = 255; else rt[2] = icol;
- icol = (mul * rt[3]) >> 8;
- if (icol > 254) rt[3] = 255; else rt[3] = icol;
-
rt += 4;
}
}
@@ -1318,6 +1398,7 @@ typedef struct SeqIndexBuildContext {
int size_flags;
int quality;
bool overwrite;
+ size_t view_id;
Main *bmain;
Scene *scene;
@@ -1357,54 +1438,164 @@ static double seq_rendersize_to_scale_factor(int size)
return 0.25;
}
-static void seq_open_anim_file(Sequence *seq, bool openfile)
+/* the number of files will vary according to the stereo format */
+static size_t seq_num_files(Scene *scene, char views_format, const bool is_multiview)
+{
+ if (!is_multiview) {
+ return 1;
+ }
+ else if (views_format == R_IMF_VIEWS_STEREO_3D) {
+ return 1;
+ }
+ /* R_IMF_VIEWS_INDIVIDUAL */
+ else {
+ return BKE_scene_multiview_num_views_get(&scene->r);
+ }
+}
+
+static void seq_proxy_index_dir_set(struct anim *anim, const char *base_dir)
{
+ char dir[FILE_MAX];
+ char fname[FILE_MAXFILE];
+
+ IMB_anim_get_fname(anim, fname, FILE_MAXFILE);
+ BLI_strncpy(dir, base_dir, sizeof(dir));
+ BLI_path_append(dir, sizeof(dir), fname);
+ IMB_anim_set_index_dir(anim, dir);
+}
+
+static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
+{
+ char dir[FILE_MAX];
char name[FILE_MAX];
StripProxy *proxy;
+ bool use_proxy;
+ bool is_multiview_loaded = false;
+ Editing *ed = scene->ed;
+ const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 && (scene->r.scemode & R_MULTIVIEW) != 0;
- if (seq->anim != NULL) {
+ if ((seq->anims.first != NULL) && (((StripAnim *)seq->anims.first)->anim != NULL)) {
return;
}
+ /* reset all the previously created anims */
+ BKE_sequence_free_anim(seq);
+
BLI_join_dirfile(name, sizeof(name),
seq->strip->dir, seq->strip->stripdata->name);
BLI_path_abs(name, G.main->name);
-
- if (openfile) {
- seq->anim = openanim(name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
- }
- else {
- seq->anim = openanim_noload(name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
- }
- if (seq->anim == NULL) {
- return;
+ proxy = seq->strip->proxy;
+
+ use_proxy = proxy && ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) != 0 ||
+ (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE));
+
+ if (use_proxy) {
+ if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
+ if (ed->proxy_dir[0] == 0)
+ BLI_strncpy(dir, "//BL_proxy", sizeof(dir));
+ else
+ BLI_strncpy(dir, ed->proxy_dir, sizeof(dir));
+ }
+ else {
+ BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
+ }
+ BLI_path_abs(dir, G.main->name);
}
- proxy = seq->strip->proxy;
+ if (is_multiview && seq->views_format == R_IMF_VIEWS_INDIVIDUAL) {
+ size_t totfiles = seq_num_files(scene, seq->views_format, true);
+ char prefix[FILE_MAX];
+ char *ext = NULL;
+ int i;
- if (proxy == NULL) {
- return;
+ BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext);
+
+ if (prefix[0] != '\0') {
+ for (i = 0; i < totfiles; i++) {
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
+ char str[FILE_MAX];
+ StripAnim *sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+
+ BLI_addtail(&seq->anims, sanim);
+
+ BLI_snprintf(str, sizeof(str), "%s%s%s", prefix, suffix, ext);
+
+ if (openfile) {
+ sanim->anim = openanim(
+ str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+ else {
+ sanim->anim = openanim_noload(
+ str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+
+ if (sanim->anim) {
+#if 0
+ seq_anim_add_suffix(scene, sanim->anim, i);
+#else
+ /* we already have the suffix */
+ IMB_suffix_anim(sanim->anim, suffix);
+#endif
+ }
+ else {
+ if (openfile) {
+ sanim->anim = openanim(
+ name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+ else {
+ sanim->anim = openanim_noload(
+ name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+
+ /* no individual view files - monoscopic, stereo 3d or exr multiview */
+ totfiles = 1;
+ }
+
+ if (sanim->anim && use_proxy) {
+ seq_proxy_index_dir_set(sanim->anim, dir);
+ }
+ }
+ is_multiview_loaded = true;
+ }
}
- if (seq->flag & SEQ_USE_PROXY_CUSTOM_DIR) {
- char dir[FILE_MAX];
- BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
- BLI_path_abs(dir, G.main->name);
+ if (is_multiview_loaded == false) {
+ StripAnim *sanim;
+
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
- IMB_anim_set_index_dir(seq->anim, dir);
+ if (openfile) {
+ sanim->anim = openanim(
+ name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+ else {
+ sanim->anim = openanim_noload(
+ name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+
+ if (sanim->anim && use_proxy) {
+ seq_proxy_index_dir_set(sanim->anim, dir);
+ }
}
}
-
-static bool seq_proxy_get_fname(Sequence *seq, int cfra, int render_size, char *name)
+static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render_size, char *name, const size_t view_id)
{
int frameno;
char dir[PROXY_MAXFILE];
+ StripAnim *sanim;
+ char suffix[24] = {'\0'};
- if (!seq->strip->proxy) {
+ StripProxy *proxy = seq->strip->proxy;
+ if (!proxy) {
return false;
}
@@ -1416,8 +1607,32 @@ static bool seq_proxy_get_fname(Sequence *seq, int cfra, int render_size, char *
* have both, a directory full of jpeg files and proxy avis, so
* sorry folks, please rebuild your proxies... */
- if (seq->flag & (SEQ_USE_PROXY_CUSTOM_DIR | SEQ_USE_PROXY_CUSTOM_FILE)) {
+ sanim = BLI_findlink(&seq->anims, view_id);
+
+ if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
+ char fname[FILE_MAXFILE];
+ if (ed->proxy_dir[0] == 0)
+ BLI_strncpy(dir, "//BL_proxy", sizeof(dir));
+ else
+ BLI_strncpy(dir, ed->proxy_dir, sizeof(dir));
+
+ if (sanim && sanim->anim) {
+ IMB_anim_get_fname(sanim->anim, fname, FILE_MAXFILE);
+ }
+ else if (seq->type == SEQ_TYPE_IMAGE) {
+ fname[0] = 0;
+ }
+ BLI_path_append(dir, sizeof(dir), fname);
+ BLI_path_abs(name, G.main->name);
+ }
+ else if ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE)) {
+ BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
+ }
+ else if (sanim && sanim->anim && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR)) {
+ char fname[FILE_MAXFILE];
BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
+ IMB_anim_get_fname(sanim->anim, fname, FILE_MAXFILE);
+ BLI_path_append(dir, sizeof(dir), fname);
}
else if (seq->type == SEQ_TYPE_IMAGE) {
BLI_snprintf(dir, PROXY_MAXFILE, "%s/BL_proxy", seq->strip->dir);
@@ -1426,10 +1641,16 @@ static bool seq_proxy_get_fname(Sequence *seq, int cfra, int render_size, char *
return false;
}
- if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) {
+ if (view_id > 0)
+ BLI_snprintf(suffix, sizeof(suffix), "_%zu", view_id);
+
+ if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE && sanim && sanim->anim &&
+ ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE)
+ {
BLI_join_dirfile(name, PROXY_MAXFILE,
- dir, seq->strip->proxy->file);
+ dir, proxy->file);
BLI_path_abs(name, G.main->name);
+ BLI_snprintf(name, PROXY_MAXFILE, "%s_%s", name, suffix);
return true;
}
@@ -1437,13 +1658,13 @@ static bool seq_proxy_get_fname(Sequence *seq, int cfra, int render_size, char *
/* generate a separate proxy directory for each preview size */
if (seq->type == SEQ_TYPE_IMAGE) {
- BLI_snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy", dir, render_size,
- BKE_sequencer_give_stripelem(seq, cfra)->name);
+ BLI_snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy%s", dir, render_size,
+ BKE_sequencer_give_stripelem(seq, cfra)->name, suffix);
frameno = 1;
}
else {
frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs;
- BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####", dir, render_size);
+ BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, render_size, suffix);
}
BLI_path_abs(name, G.main->name);
@@ -1460,45 +1681,48 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size);
int size_flags;
int render_size = context->preview_render_size;
+ StripProxy *proxy = seq->strip->proxy;
+ Editing *ed = context->scene->ed;
+ StripAnim *sanim;
+
+ if (!(seq->flag & SEQ_USE_PROXY)) {
+ return NULL;
+ }
/* dirty hack to distinguish 100% render size from PROXY_100 */
if (render_size == 99) {
render_size = 100;
}
- if (!(seq->flag & SEQ_USE_PROXY)) {
- return NULL;
- }
-
- size_flags = seq->strip->proxy->build_size_flags;
+ size_flags = proxy->build_size_flags;
/* only use proxies, if they are enabled (even if present!) */
if (psize == IMB_PROXY_NONE || ((size_flags & psize) != psize)) {
return NULL;
}
- if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) {
+ if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
int frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs;
- if (seq->strip->proxy->anim == NULL) {
- if (seq_proxy_get_fname(seq, cfra, render_size, name) == 0) {
+ if (proxy->anim == NULL) {
+ if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) {
return NULL;
}
- seq->strip->proxy->anim = openanim(name, IB_rect, 0,
- seq->strip->colorspace_settings.name);
+ proxy->anim = openanim(name, IB_rect, 0, seq->strip->colorspace_settings.name);
}
- if (seq->strip->proxy->anim == NULL) {
+ if (proxy->anim == NULL) {
return NULL;
}
- seq_open_anim_file(seq, true);
+ seq_open_anim_file(context->scene, seq, true);
+ sanim = seq->anims.first;
- frameno = IMB_anim_index_get_frame_index(seq->anim, seq->strip->proxy->tc, frameno);
+ frameno = IMB_anim_index_get_frame_index(sanim ? sanim->anim : NULL, seq->strip->proxy->tc, frameno);
- return IMB_anim_absolute(seq->strip->proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
+ return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
}
- if (seq_proxy_get_fname(seq, cfra, render_size, name) == 0) {
+ if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) {
return NULL;
}
@@ -1523,8 +1747,9 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i
int rectx, recty;
int ok;
ImBuf *ibuf_tmp, *ibuf;
+ Editing *ed = context->scene->ed;
- if (!seq_proxy_get_fname(seq, cfra, proxy_render_size, name)) {
+ if (!seq_proxy_get_fname(ed, seq, cfra, proxy_render_size, name, context->view_id)) {
return;
}
@@ -1539,6 +1764,7 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i
if (ibuf_tmp->x != rectx || ibuf_tmp->y != recty) {
ibuf = IMB_dupImBuf(ibuf_tmp);
+ IMB_metadata_copy(ibuf, ibuf_tmp);
IMB_freeImBuf(ibuf_tmp);
IMB_scalefastImBuf(ibuf, (short)rectx, (short)recty);
}
@@ -1565,44 +1791,133 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i
IMB_freeImBuf(ibuf);
}
-SeqIndexBuildContext *BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *seq, struct GSet *file_list)
+/* 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 size_t view_id)
+{
+ if ((scene->r.scemode & R_MULTIVIEW) == 0)
+ return false;
+
+ if ((seq->type == SEQ_TYPE_IMAGE) && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ static char prefix[FILE_MAX];
+ static char *ext = NULL;
+ char str[FILE_MAX];
+
+ if (view_id == 0) {
+ char path[FILE_MAX];
+ BLI_join_dirfile(path, sizeof(path), seq->strip->dir,
+ seq->strip->stripdata->name);
+ BLI_path_abs(path, G.main->name);
+ BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
+ }
+ else {
+ prefix[0] = '\0';
+ }
+
+ if (prefix[0] == '\0')
+ return view_id != 0;
+
+ seq_multiview_name(scene, view_id, prefix, ext, str, FILE_MAX);
+
+ if (BLI_access(str, R_OK) == 0)
+ return false;
+ else
+ return view_id != 0;
+ }
+ return false;
+}
+
+/** This returns the maximum possible number of required contexts
+*/
+static size_t seq_proxy_context_count(Sequence *seq, Scene *scene)
+{
+ size_t num_views = 1;
+
+ if ((scene->r.scemode & R_MULTIVIEW) == 0)
+ return 1;
+
+ switch (seq->type) {
+ case SEQ_TYPE_MOVIE:
+ {
+ num_views = BLI_listbase_count(&seq->anims);
+ break;
+ }
+ case SEQ_TYPE_IMAGE:
+ {
+ switch (seq->views_format) {
+ case R_IMF_VIEWS_INDIVIDUAL:
+ num_views = BKE_scene_multiview_num_views_get(&scene->r);
+ break;
+ case R_IMF_VIEWS_STEREO_3D:
+ num_views = 2;
+ break;
+ case R_IMF_VIEWS_MULTIVIEW:
+ /* not supported at the moment */
+ /* pass through */
+ default:
+ num_views = 1;
+ }
+ break;
+ }
+ }
+
+ return num_views;
+}
+
+void BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *seq, struct GSet *file_list, ListBase *queue)
{
SeqIndexBuildContext *context;
Sequence *nseq;
+ LinkData *link;
+ size_t i;
+ size_t num_files;
if (!seq->strip || !seq->strip->proxy) {
- return NULL;
+ return;
}
if (!(seq->flag & SEQ_USE_PROXY)) {
- return NULL;
+ return;
}
- context = MEM_callocN(sizeof(SeqIndexBuildContext), "seq proxy rebuild context");
+ num_files = seq_proxy_context_count(seq, scene);
+
+ for (i = 0; i < num_files; i++) {
+ if (seq_proxy_multiview_context_invalid(seq, scene, i))
+ continue;
+
+ context = MEM_callocN(sizeof(SeqIndexBuildContext), "seq proxy rebuild context");
+
+ nseq = BKE_sequence_dupli_recursive(scene, scene, seq, 0);
+
+ context->tc_flags = nseq->strip->proxy->build_tc_flags;
+ context->size_flags = nseq->strip->proxy->build_size_flags;
+ context->quality = nseq->strip->proxy->quality;
+ context->overwrite = (nseq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0;
- nseq = BKE_sequence_dupli_recursive(scene, scene, seq, 0);
+ context->bmain = bmain;
+ context->scene = scene;
+ context->orig_seq = seq;
+ context->seq = nseq;
- context->tc_flags = nseq->strip->proxy->build_tc_flags;
- context->size_flags = nseq->strip->proxy->build_size_flags;
- context->quality = nseq->strip->proxy->quality;
- context->overwrite = (nseq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0;
+ context->view_id = i; /* only for images */
- context->bmain = bmain;
- context->scene = scene;
- context->orig_seq = seq;
- context->seq = nseq;
+ link = BLI_genericNodeN(context);
+ BLI_addtail(queue, link);
- if (nseq->type == SEQ_TYPE_MOVIE) {
- seq_open_anim_file(nseq, true);
+ if (nseq->type == SEQ_TYPE_MOVIE) {
+ StripAnim *sanim;
- if (nseq->anim) {
- context->index_context = IMB_anim_index_rebuild_context(nseq->anim,
- context->tc_flags, context->size_flags, context->quality,
- context->overwrite, file_list);
+ seq_open_anim_file(scene, nseq, true);
+ sanim = BLI_findlink(&nseq->anims, i);
+
+ if (sanim->anim) {
+ context->index_context = IMB_anim_index_rebuild_context(sanim->anim,
+ context->tc_flags, context->size_flags, context->quality,
+ context->overwrite, file_list);
+ }
}
}
-
- return context;
}
void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, short *do_update, float *progress)
@@ -1627,7 +1942,7 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho
}
/* that's why it is called custom... */
- if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) {
+ if (seq->strip->proxy && seq->strip->proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
return;
}
@@ -1641,6 +1956,7 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho
render_context.skip_cache = true;
render_context.is_proxy_render = true;
+ render_context.view_id = context->view_id;
for (cfra = seq->startdisp + seq->startstill; cfra < seq->enddisp - seq->endstill; cfra++) {
if (context->size_flags & IMB_PROXY_25) {
@@ -1667,8 +1983,14 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho
void BKE_sequencer_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop)
{
if (context->index_context) {
- IMB_close_anim_proxies(context->seq->anim);
- IMB_close_anim_proxies(context->orig_seq->anim);
+ StripAnim *sanim;
+
+ for (sanim = context->seq->anims.first; sanim; sanim = sanim->next)
+ IMB_close_anim_proxies(sanim->anim);
+
+ for (sanim = context->orig_seq->anims.first; sanim; sanim = sanim->next)
+ IMB_close_anim_proxies(sanim->anim);
+
IMB_anim_index_rebuild_finish(context->index_context, stop);
}
@@ -1947,7 +2269,10 @@ static void *color_balance_do_thread(void *thread_data_v)
return NULL;
}
-ImBuf *BKE_sequencer_render_mask_input(const SeqRenderData *context, int mask_input_type, Sequence *mask_sequence, Mask *mask_id, int cfra, bool make_float)
+/* cfra is offset by fra_offset only in case we are using a real mask. */
+ImBuf *BKE_sequencer_render_mask_input(
+ const SeqRenderData *context, int mask_input_type, Sequence *mask_sequence, Mask *mask_id,
+ int cfra, int fra_offset, bool make_float)
{
ImBuf *mask_input = NULL;
@@ -1966,7 +2291,7 @@ ImBuf *BKE_sequencer_render_mask_input(const SeqRenderData *context, int mask_in
}
}
else if (mask_input_type == SEQUENCE_MASK_INPUT_ID) {
- mask_input = seq_render_mask(context, mask_id, cfra, make_float);
+ mask_input = seq_render_mask(context, mask_id, cfra - fra_offset, make_float);
}
return mask_input;
@@ -2126,6 +2451,7 @@ static ImBuf *input_preprocess(const SeqRenderData *context, Sequence *seq, floa
IMB_rectcpy(i, ibuf, t.xofs, t.yofs, c.left, c.bottom, sx, sy);
sequencer_imbuf_assign_spaces(scene, i);
+ IMB_metadata_copy(i, ibuf);
IMB_freeImBuf(ibuf);
ibuf = i;
@@ -2179,6 +2505,7 @@ static ImBuf *input_preprocess(const SeqRenderData *context, Sequence *seq, floa
ImBuf *ibuf_new = BKE_sequence_modifier_apply_stack(context, seq, ibuf, cfra);
if (ibuf_new != ibuf) {
+ IMB_metadata_copy(ibuf_new, ibuf);
IMB_freeImBuf(ibuf);
ibuf = ibuf_new;
}
@@ -2201,6 +2528,7 @@ static ImBuf *copy_from_ibuf_still(const SeqRenderData *context, Sequence *seq,
if (ibuf) {
rval = IMB_dupImBuf(ibuf);
+ IMB_metadata_copy(rval, ibuf);
IMB_freeImBuf(ibuf);
}
@@ -2214,9 +2542,11 @@ static void copy_to_ibuf_still(const SeqRenderData *context, Sequence *seq, floa
/* we have to store a copy, since the passed ibuf
* could be preprocessed afterwards (thereby silently
* changing the cached image... */
- ibuf = IMB_dupImBuf(ibuf);
+ ImBuf *oibuf = ibuf;
+ ibuf = IMB_dupImBuf(oibuf);
if (ibuf) {
+ IMB_metadata_copy(ibuf, oibuf);
sequencer_imbuf_assign_spaces(context->scene, ibuf);
}
@@ -2412,6 +2742,237 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, Sequenc
return out;
}
+static ImBuf *seq_render_image_strip(const SeqRenderData *context, Sequence *seq, float nr, float cfra)
+{
+ ImBuf *ibuf = NULL;
+ char name[FILE_MAX];
+ bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
+ (context->scene->r.scemode & R_MULTIVIEW) != 0;
+ StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra);
+ int flag;
+
+ if (s_elem) {
+ BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name);
+ BLI_path_abs(name, G.main->name);
+ }
+
+ flag = IB_rect | IB_metadata;
+ if (seq->alpha_mode == SEQ_ALPHA_PREMUL)
+ flag |= IB_alphamode_premul;
+
+ if (!s_elem) {
+ /* don't do anything */
+ }
+ else if (is_multiview) {
+ size_t totfiles = seq_num_files(context->scene, seq->views_format, true);
+ size_t totviews;
+ struct ImBuf **ibufs_arr;
+ char prefix[FILE_MAX];
+ char *ext = NULL;
+ int i;
+
+ if (totfiles > 1) {
+ BKE_scene_multiview_view_prefix_get(context->scene, name, prefix, &ext);
+ if (prefix[0] == '\0') {
+ goto monoview_image;
+ }
+ }
+ else {
+ prefix[0] = '\0';
+ }
+
+ totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
+ ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
+
+ for (i = 0; i < totfiles; i++) {
+
+ if (prefix[0] == '\0') {
+ ibufs_arr[i] = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name);
+ }
+ else {
+ char str[FILE_MAX];
+ seq_multiview_name(context->scene, i, prefix, ext, str, FILE_MAX);
+ ibufs_arr[i] = IMB_loadiffname(str, flag, seq->strip->colorspace_settings.name);
+ }
+
+ if (ibufs_arr[i]) {
+ /* we don't need both (speed reasons)! */
+ if (ibufs_arr[i]->rect_float && ibufs_arr[i]->rect)
+ imb_freerectImBuf(ibufs_arr[i]);
+ }
+ }
+
+ if (seq->views_format == R_IMF_VIEWS_STEREO_3D && ibufs_arr[0])
+ IMB_ImBufFromStereo3d(seq->stereo3d_format, ibufs_arr[0], &ibufs_arr[0], &ibufs_arr[1]);
+
+ for (i = 0; i < totviews; i++) {
+ if (ibufs_arr[i]) {
+ SeqRenderData localcontext = *context;
+ localcontext.view_id = i;
+
+ /* all sequencer color is done in SRGB space, linear gives odd crossfades */
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[i], false);
+
+ if (i != context->view_id) {
+ copy_to_ibuf_still(&localcontext, seq, nr, ibufs_arr[i]);
+ BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibufs_arr[i]);
+ }
+ }
+ }
+
+ /* return the original requested ImBuf */
+ ibuf = ibufs_arr[context->view_id];
+ if (ibuf) {
+ s_elem->orig_width = ibufs_arr[0]->x;
+ s_elem->orig_height = ibufs_arr[0]->y;
+ }
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibufs_arr[i] != ibuf) {
+ IMB_freeImBuf(ibufs_arr[i]);
+ }
+ }
+
+ MEM_freeN(ibufs_arr);
+ }
+ else {
+monoview_image:
+ if ((ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name))) {
+ /* we don't need both (speed reasons)! */
+ if (ibuf->rect_float && ibuf->rect)
+ imb_freerectImBuf(ibuf);
+
+ /* all sequencer color is done in SRGB space, linear gives odd crossfades */
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
+
+ s_elem->orig_width = ibuf->x;
+ s_elem->orig_height = ibuf->y;
+ }
+ }
+
+ return ibuf;
+}
+
+static ImBuf *seq_render_movie_strip(const SeqRenderData *context, Sequence *seq, float nr, float cfra)
+{
+ ImBuf *ibuf = NULL;
+ StripAnim *sanim;
+ bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
+ (context->scene->r.scemode & R_MULTIVIEW) != 0;
+
+ /* load all the videos */
+ seq_open_anim_file(context->scene, seq, false);
+
+ if (is_multiview) {
+ ImBuf **ibuf_arr;
+ size_t totviews;
+ size_t totfiles = seq_num_files(context->scene, seq->views_format, true);
+ int i;
+
+ if (totfiles != BLI_listbase_count_ex(&seq->anims, totfiles + 1))
+ goto monoview_movie;
+
+ totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
+ ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
+
+ for (i = 0, sanim = seq->anims.first; sanim; sanim = sanim->next, i++) {
+ if (sanim->anim) {
+ IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size);
+ IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
+
+ ibuf_arr[i] = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ proxy_size);
+
+ /* fetching for requested proxy size failed, try fetching the original instead */
+ if (!ibuf_arr[i] && proxy_size != IMB_PROXY_NONE) {
+ ibuf_arr[i] = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ IMB_PROXY_NONE);
+ }
+ if (ibuf_arr[i]) {
+ /* we don't need both (speed reasons)! */
+ if (ibuf_arr[i]->rect_float && ibuf_arr[i]->rect)
+ imb_freerectImBuf(ibuf_arr[i]);
+ }
+ }
+ }
+
+ if (seq->views_format == R_IMF_VIEWS_STEREO_3D) {
+ if (ibuf_arr[0]) {
+ IMB_ImBufFromStereo3d(seq->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+ }
+ else {
+ /* probably proxy hasn't been created yet */
+ MEM_freeN(ibuf_arr);
+ return NULL;
+ }
+ }
+
+ for (i = 0; i < totviews; i++) {
+ SeqRenderData localcontext = *context;
+ localcontext.view_id = i;
+
+ if (ibuf_arr[i]) {
+ /* all sequencer color is done in SRGB space, linear gives odd crossfades */
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf_arr[i], false);
+ }
+ if (i != context->view_id) {
+ copy_to_ibuf_still(&localcontext, seq, nr, ibuf_arr[i]);
+ BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf_arr[i]);
+ }
+ }
+
+ /* return the original requested ImBuf */
+ ibuf = ibuf_arr[context->view_id];
+ if (ibuf) {
+ seq->strip->stripdata->orig_width = ibuf->x;
+ seq->strip->stripdata->orig_height = ibuf->y;
+ }
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+
+ MEM_freeN(ibuf_arr);
+ }
+ else {
+monoview_movie:
+ sanim = seq->anims.first;
+ if (sanim && sanim->anim) {
+ IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size);
+ IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
+
+ ibuf = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ proxy_size);
+
+ /* fetching for requested proxy size failed, try fetching the original instead */
+ if (!ibuf && proxy_size != IMB_PROXY_NONE) {
+ ibuf = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ IMB_PROXY_NONE);
+ }
+ if (ibuf) {
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
+
+ /* we don't need both (speed reasons)! */
+ if (ibuf->rect_float && ibuf->rect) {
+ imb_freerectImBuf(ibuf);
+ }
+
+ seq->strip->stripdata->orig_width = ibuf->x;
+ seq->strip->stripdata->orig_height = ibuf->y;
+ }
+ }
+ }
+ return ibuf;
+}
+
static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, Sequence *seq, float nr)
{
ImBuf *ibuf = NULL;
@@ -2543,7 +3104,7 @@ static ImBuf *seq_render_mask_strip(const SeqRenderData *context, Sequence *seq,
return seq_render_mask(context, seq->mask, nr, make_float);
}
-static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq, float nr)
+static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq, float nr, float cfra)
{
ImBuf *ibuf = NULL;
float frame;
@@ -2641,6 +3202,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
char err_out[256] = "unknown";
int width = (scene->r.xsch * scene->r.size) / 100;
int height = (scene->r.ysch * scene->r.size) / 100;
+ const char *viewname = BKE_scene_multiview_render_view_name_get(&scene->r, context->view_id);
/* for old scened this can be uninitialized,
* should probably be added to do_versions at some point if the functionality stays */
@@ -2652,14 +3214,18 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
ibuf = sequencer_view3d_cb(scene, camera, width, height, IB_rect,
context->scene->r.seq_prev_type,
(context->scene->r.seq_flag & R_SEQ_SOLID_TEX) != 0,
- use_gpencil, true, scene->r.alphamode, err_out);
+ use_gpencil, true, scene->r.alphamode, viewname, err_out);
if (ibuf == NULL) {
fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out);
}
}
else {
Render *re = RE_GetRender(scene->id.name);
- RenderResult rres;
+ size_t totviews = BKE_scene_multiview_num_views_get(&scene->r);
+ int i;
+ ImBuf **ibufs_arr;
+
+ ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
/* XXX: this if can be removed when sequence preview rendering uses the job system
*
@@ -2679,27 +3245,51 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
/* restore previous state after it was toggled on & off by RE_BlenderFrame */
G.is_rendering = is_rendering;
}
-
- RE_AcquireResultImage(re, &rres);
-
- if (rres.rectf) {
- ibuf = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat);
- memcpy(ibuf->rect_float, rres.rectf, 4 * sizeof(float) * rres.rectx * rres.recty);
- if (rres.rectz) {
- addzbuffloatImBuf(ibuf);
- memcpy(ibuf->zbuf_float, rres.rectz, sizeof(float) * rres.rectx * rres.recty);
+
+ for (i = 0; i < totviews; i++) {
+ SeqRenderData localcontext = *context;
+ RenderResult rres;
+
+ localcontext.view_id = i;
+
+ RE_AcquireResultImage(re, &rres, i);
+
+ if (rres.rectf) {
+ ibufs_arr[i] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat);
+ memcpy(ibufs_arr[i]->rect_float, rres.rectf, 4 * sizeof(float) * rres.rectx * rres.recty);
+
+ if (rres.rectz) {
+ addzbuffloatImBuf(ibufs_arr[i]);
+ memcpy(ibufs_arr[i]->zbuf_float, rres.rectz, sizeof(float) * rres.rectx * rres.recty);
+ }
+
+ /* float buffers in the sequencer are not linear */
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[i], false);
+ }
+ else if (rres.rect32) {
+ ibufs_arr[i] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect);
+ memcpy(ibufs_arr[i]->rect, rres.rect32, 4 * rres.rectx * rres.recty);
}
- /* float buffers in the sequencer are not linear */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
+ if (i != context->view_id) {
+ copy_to_ibuf_still(&localcontext, seq, nr, ibufs_arr[i]);
+ BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibufs_arr[i]);
+ }
+
+ RE_ReleaseResultImage(re);
}
- else if (rres.rect32) {
- ibuf = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect);
- memcpy(ibuf->rect, rres.rect32, 4 * rres.rectx * rres.recty);
+
+ /* return the original requested ImBuf */
+ ibuf = ibufs_arr[context->view_id];
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibufs_arr[i] != ibuf) {
+ IMB_freeImBuf(ibufs_arr[i]);
+ }
}
-
- RE_ReleaseResultImage(re);
-
+ MEM_freeN(ibufs_arr);
+
// BIF_end_render_callbacks();
}
@@ -2760,7 +3350,6 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s
float nr = give_stripelem_index(seq, cfra);
int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT : seq->type;
bool use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra);
- char name[FILE_MAX];
switch (type) {
case SEQ_TYPE_META:
@@ -2779,7 +3368,7 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s
}
else {
/* scene can be NULL after deletions */
- ibuf = seq_render_scene_strip(context, seq, nr);
+ ibuf = seq_render_scene_strip(context, seq, nr, cfra);
/* Scene strips update all animation, so we need to restore original state.*/
BKE_animsys_evaluate_all_animation(context->bmain, context->scene, cfra);
@@ -2824,68 +3413,14 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s
case SEQ_TYPE_IMAGE:
{
- StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra);
- int flag;
-
- if (s_elem) {
- BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name);
- BLI_path_abs(name, G.main->name);
- }
-
- flag = IB_rect;
- if (seq->alpha_mode == SEQ_ALPHA_PREMUL)
- flag |= IB_alphamode_premul;
-
- if (s_elem && (ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name))) {
- /* we don't need both (speed reasons)! */
- if (ibuf->rect_float && ibuf->rect)
- imb_freerectImBuf(ibuf);
-
- /* all sequencer color is done in SRGB space, linear gives odd crossfades */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
-
- copy_to_ibuf_still(context, seq, nr, ibuf);
-
- s_elem->orig_width = ibuf->x;
- s_elem->orig_height = ibuf->y;
- }
+ ibuf = seq_render_image_strip(context, seq, nr, cfra);
+ copy_to_ibuf_still(context, seq, nr, ibuf);
break;
}
case SEQ_TYPE_MOVIE:
{
- seq_open_anim_file(seq, false);
-
- if (seq->anim) {
- IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size);
- IMB_anim_set_preseek(seq->anim, seq->anim_preseek);
-
- ibuf = IMB_anim_absolute(seq->anim, nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
- proxy_size);
-
- /* fetching for requested proxy size failed, try fetching the original instead
- if (!ibuf && proxy_size != IMB_PROXY_NONE) {
- IMB_Proxy_Size proxy_sizes = IMB_anim_proxy_get_existing(seq->anim);
- while (!(proxy_size & proxy_sizes) && proxy_size > 0) {
- proxy_size >>= 1;
- }
- ibuf = IMB_anim_absolute(seq->anim, nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
- proxy_size);
- }*/
- if (ibuf) {
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
-
- /* we don't need both (speed reasons)! */
- if (ibuf->rect_float && ibuf->rect) {
- imb_freerectImBuf(ibuf);
- }
-
- seq->strip->stripdata->orig_width = ibuf->x;
- seq->strip->stripdata->orig_height = ibuf->y;
- }
- }
+ ibuf = seq_render_movie_strip(context, seq, nr, cfra);
copy_to_ibuf_still(context, seq, nr, ibuf);
break;
}
@@ -3111,6 +3646,8 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq
out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
+ IMB_metadata_copy(out, ibuf2);
+
IMB_freeImBuf(ibuf1);
IMB_freeImBuf(ibuf2);
}
@@ -3381,16 +3918,6 @@ ImBuf *BKE_sequencer_give_ibuf_threaded(const SeqRenderData *context, float cfra
return e ? e->ibuf : NULL;
}
-/* Functions to free imbuf and anim data on changes */
-
-static void free_anim_seq(Sequence *seq)
-{
- if (seq->anim) {
- IMB_free_anim(seq->anim);
- seq->anim = NULL;
- }
-}
-
/* check whether sequence cur depends on seq */
bool BKE_sequence_check_depend(Sequence *seq, Sequence *cur)
{
@@ -3442,15 +3969,11 @@ static void sequence_invalidate_cache(Scene *scene, Sequence *seq, bool invalida
/* invalidate cache for current sequence */
if (invalidate_self) {
- if (seq->anim) {
- /* Animation structure holds some buffers inside,
- * so for proper cache invalidation we need to
- * re-open the animation.
- */
- IMB_free_anim(seq->anim);
- seq->anim = NULL;
- }
-
+ /* Animation structure holds some buffers inside,
+ * so for proper cache invalidation we need to
+ * re-open the animation.
+ */
+ BKE_sequence_free_anim(seq);
BKE_sequencer_cache_cleanup_sequence(seq);
}
@@ -3497,7 +4020,7 @@ void BKE_sequencer_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
if (seq->strip) {
if (seq->type == SEQ_TYPE_MOVIE) {
- free_anim_seq(seq);
+ BKE_sequence_free_anim(seq);
}
if (seq->type == SEQ_TYPE_SPEED) {
BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
@@ -3544,7 +4067,7 @@ static bool update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *cha
if (free_imbuf) {
if (ibuf_change) {
if (seq->type == SEQ_TYPE_MOVIE)
- free_anim_seq(seq);
+ BKE_sequence_free_anim(seq);
if (seq->type == SEQ_TYPE_SPEED) {
BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
}
@@ -3796,10 +4319,10 @@ void BKE_sequence_sound_init(Scene *scene, Sequence *seq)
}
else {
if (seq->sound) {
- seq->scene_sound = sound_add_scene_sound_defaults(scene, seq);
+ seq->scene_sound = BKE_sound_add_scene_sound_defaults(scene, seq);
}
if (seq->scene) {
- seq->scene_sound = sound_scene_add_scene_sound_defaults(scene, seq);
+ seq->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene, seq);
}
}
}
@@ -4011,11 +4534,11 @@ void BKE_sequencer_update_sound_bounds(Scene *scene, Sequence *seq)
/* We have to take into account start frame of the sequence's scene! */
int startofs = seq->startofs + seq->anim_startofs + seq->scene->r.sfra;
- sound_move_scene_sound(scene, seq->scene_sound, seq->startdisp, seq->enddisp, startofs);
+ BKE_sound_move_scene_sound(scene, seq->scene_sound, seq->startdisp, seq->enddisp, startofs);
}
}
else {
- sound_move_scene_sound_defaults(scene, seq);
+ BKE_sound_move_scene_sound_defaults(scene, seq);
}
/* mute is set in seq_update_muting_recursive */
}
@@ -4040,7 +4563,7 @@ static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, i
}
else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
if (seq->scene_sound) {
- sound_mute_scene_sound(seq->scene_sound, seqmute);
+ BKE_sound_mute_scene_sound(seq->scene_sound, seqmute);
}
}
}
@@ -4069,7 +4592,7 @@ static void seq_update_sound_recursive(Scene *scene, ListBase *seqbasep, bSound
}
else if (seq->type == SEQ_TYPE_SOUND_RAM) {
if (seq->scene_sound && sound == seq->sound) {
- sound_update_scene_sound(seq->scene_sound, sound);
+ BKE_sound_update_scene_sound(seq->scene_sound, sound);
}
}
}
@@ -4184,7 +4707,7 @@ static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char
char name_esc[SEQ_NAME_MAXSTR * 2];
BLI_strescape(name_esc, name, sizeof(name_esc));
- return BLI_snprintf(str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc);
+ return BLI_snprintf_rlen(str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc);
}
/* XXX - hackish function needed for transforming strips! TODO - have some better solution */
@@ -4402,7 +4925,7 @@ static void seq_load_apply(Scene *scene, Sequence *seq, SeqLoadInfo *seq_load)
if (seq_load->flag & SEQ_LOAD_SOUND_CACHE) {
if (seq->sound)
- sound_cache(seq->sound);
+ BKE_sound_cache(seq->sound);
}
seq_load->tot_success++;
@@ -4432,6 +4955,8 @@ Sequence *BKE_sequence_alloc(ListBase *lb, int cfra, int machine)
seq->pitch = 1.0f;
seq->scene_sound = NULL;
+ seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format");
+
return seq;
}
@@ -4489,6 +5014,12 @@ Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoad
strip->stripdata = MEM_callocN(seq->len * sizeof(StripElem), "stripelem");
BLI_strncpy(strip->dir, seq_load->path, sizeof(strip->dir));
+ if (seq_load->stereo3d_format)
+ *seq->stereo3d_format = *seq_load->stereo3d_format;
+
+ seq->views_format = seq_load->views_format;
+ seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
+
seq_load_apply(scene, seq, seq_load);
return seq;
@@ -4508,9 +5039,9 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
AUD_SoundInfo info;
- sound = sound_new_file(bmain, seq_load->path); /* handles relative paths */
+ sound = BKE_sound_new_file(bmain, seq_load->path); /* handles relative paths */
- if (sound == NULL || sound->playback_handle == NULL) {
+ if (sound->playback_handle == NULL) {
#if 0
if (op)
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
@@ -4522,7 +5053,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
info = AUD_getInfo(sound->playback_handle);
if (info.specs.channels == AUD_CHANNELS_INVALID) {
- sound_delete(bmain, sound);
+ BKE_sound_delete(bmain, sound);
#if 0
if (op)
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
@@ -4547,7 +5078,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
- seq->scene_sound = sound_add_scene_sound(scene, seq, seq_load->start_frame, seq_load->start_frame + seq->len, 0);
+ seq->scene_sound = BKE_sound_add_scene_sound(scene, seq, seq_load->start_frame, seq_load->start_frame + seq->len, 0);
BKE_sequence_calc_disp(scene, seq);
@@ -4568,6 +5099,12 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
}
#endif // WITH_AUDASPACE
+static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const size_t view_id)
+{
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
+ IMB_suffix_anim(anim, suffix);
+}
+
Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
{
Scene *scene = CTX_data_scene(C); /* only for sound */
@@ -4577,29 +5114,84 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad
Strip *strip;
StripElem *se;
char colorspace[64] = "\0"; /* MAX_COLORSPACE_NAME */
-
- struct anim *an;
+ bool is_multiview_loaded = false;
+ const bool is_multiview = (seq_load->flag & SEQ_USE_VIEWS) != 0;
+ size_t totfiles = seq_num_files(scene, seq_load->views_format, is_multiview);
+ struct anim **anim_arr;
+ int i;
BLI_strncpy(path, seq_load->path, sizeof(path));
BLI_path_abs(path, G.main->name);
- an = openanim(path, IB_rect, 0, colorspace);
+ anim_arr = MEM_callocN(sizeof(struct anim *) * totfiles, "Video files");
- if (an == NULL)
- return NULL;
+ if (is_multiview && (seq_load->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ char prefix[FILE_MAX];
+ char *ext = NULL;
+ size_t j = 0;
+
+ BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
+
+ if (prefix[0] != '\0') {
+ for (i = 0; i < totfiles; i++) {
+ char str[FILE_MAX];
+
+ seq_multiview_name(scene, i, prefix, ext, str, FILE_MAX);
+ anim_arr[j] = openanim(str, IB_rect, 0, colorspace);
+
+ if (anim_arr[j]) {
+ seq_anim_add_suffix(scene, anim_arr[j], i);
+ j++;
+ }
+ }
+
+ if (j == 0) {
+ MEM_freeN(anim_arr);
+ return NULL;
+ }
+ is_multiview_loaded = true;
+ }
+ }
+
+ if (is_multiview_loaded == false) {
+ anim_arr[0] = openanim(path, IB_rect, 0, colorspace);
+
+ if (anim_arr[0] == NULL) {
+ MEM_freeN(anim_arr);
+ return NULL;
+ }
+ }
seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel);
+
+ /* multiview settings */
+ if (seq_load->stereo3d_format) {
+ *seq->stereo3d_format = *seq_load->stereo3d_format;
+ seq->views_format = seq_load->views_format;
+ }
+ seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
+
seq->type = SEQ_TYPE_MOVIE;
seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
- seq->anim = an;
- seq->anim_preseek = IMB_anim_get_preseek(an);
+ for (i = 0; i < totfiles; i++) {
+ if (anim_arr[i]) {
+ StripAnim *sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = anim_arr[i];
+ }
+ else {
+ break;
+ }
+ }
+
+ seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]);
BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2);
BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
/* basic defaults */
seq->strip = strip = MEM_callocN(sizeof(Strip), "strip");
- seq->len = IMB_anim_get_duration(an, IMB_TC_RECORD_RUN);
+ seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN);
strip->us = 1;
BLI_strncpy(seq->strip->colorspace_settings.name, colorspace, sizeof(seq->strip->colorspace_settings.name));
@@ -4627,6 +5219,7 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad
/* can be NULL */
seq_load_apply(scene, seq, seq_load);
+ MEM_freeN(anim_arr);
return seq;
}
@@ -4638,6 +5231,8 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
seq->tmp = seqn;
seqn->strip = MEM_dupallocN(seq->strip);
+ seqn->stereo3d_format = MEM_dupallocN(seq->stereo3d_format);
+
/* XXX: add F-Curve duplication stuff? */
if (seq->strip->crop) {
@@ -4653,6 +5248,10 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
seqn->strip->proxy->anim = NULL;
}
+ if (seq->prop) {
+ seqn->prop = IDP_CopyProperty(seq->prop);
+ }
+
if (seqn->modifiers.first) {
BLI_listbase_clear(&seqn->modifiers);
@@ -4669,7 +5268,7 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
else if (seq->type == SEQ_TYPE_SCENE) {
seqn->strip->stripdata = NULL;
if (seq->scene_sound)
- seqn->scene_sound = sound_scene_add_scene_sound_defaults(sce_audio, seqn);
+ seqn->scene_sound = BKE_sound_scene_add_scene_sound_defaults(sce_audio, seqn);
}
else if (seq->type == SEQ_TYPE_MOVIECLIP) {
/* avoid assert */
@@ -4680,13 +5279,13 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
else if (seq->type == SEQ_TYPE_MOVIE) {
seqn->strip->stripdata =
MEM_dupallocN(seq->strip->stripdata);
- seqn->anim = NULL;
+ BLI_listbase_clear(&seqn->anims);
}
else if (seq->type == SEQ_TYPE_SOUND_RAM) {
seqn->strip->stripdata =
MEM_dupallocN(seq->strip->stripdata);
if (seq->scene_sound)
- seqn->scene_sound = sound_add_scene_sound_defaults(sce_audio, seqn);
+ seqn->scene_sound = BKE_sound_add_scene_sound_defaults(sce_audio, seqn);
id_us_plus((ID *)seqn->sound);
}
@@ -4695,10 +5294,6 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
MEM_dupallocN(seq->strip->stripdata);
}
else if (seq->type >= SEQ_TYPE_EFFECT) {
- if (seq->seq1 && seq->seq1->tmp) seqn->seq1 = seq->seq1->tmp;
- if (seq->seq2 && seq->seq2->tmp) seqn->seq2 = seq->seq2->tmp;
- if (seq->seq3 && seq->seq3->tmp) seqn->seq3 = seq->seq3->tmp;
-
if (seq->type & SEQ_TYPE_EFFECT) {
struct SeqEffectHandle sh;
sh = BKE_sequence_get_effect(seq);
@@ -4723,6 +5318,28 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
return seqn;
}
+static void seq_new_fix_links_recursive(Sequence *seq)
+{
+ SequenceModifierData *smd;
+
+ if (seq->type >= SEQ_TYPE_EFFECT) {
+ if (seq->seq1 && seq->seq1->tmp) seq->seq1 = seq->seq1->tmp;
+ if (seq->seq2 && seq->seq2->tmp) seq->seq2 = seq->seq2->tmp;
+ if (seq->seq3 && seq->seq3->tmp) seq->seq3 = seq->seq3->tmp;
+ }
+ else if (seq->type == SEQ_TYPE_META) {
+ Sequence *seqn;
+ for (seqn = seq->seqbase.first; seqn; seqn = seqn->next) {
+ seq_new_fix_links_recursive(seqn);
+ }
+ }
+
+ for (smd = seq->modifiers.first; smd; smd = smd->next) {
+ if (smd->mask_sequence && smd->mask_sequence->tmp)
+ smd->mask_sequence = smd->mask_sequence->tmp;
+ }
+}
+
Sequence *BKE_sequence_dupli_recursive(Scene *scene, Scene *scene_to, Sequence *seq, int dupe_flag)
{
Sequence *seqn = seq_dupli(scene, scene_to, seq, dupe_flag);
@@ -4735,6 +5352,9 @@ Sequence *BKE_sequence_dupli_recursive(Scene *scene, Scene *scene_to, Sequence *
}
}
}
+
+ seq_new_fix_links_recursive(seqn);
+
return seqn;
}
@@ -4773,6 +5393,11 @@ void BKE_sequence_base_dupli_recursive(
}
}
}
+
+ /* fix modifier linking */
+ for (seq = nseqbase->first; seq; seq = seq->next) {
+ seq_new_fix_links_recursive(seq);
+ }
}
/* called on draw, needs to be fast,
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index a34aa5009e6..6a0af3ed118 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -66,6 +66,7 @@
#include "BKE_bvhutils.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_collision.h"
+#include "BKE_colortools.h"
#include "BKE_constraint.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
@@ -152,7 +153,7 @@ struct SmokeModifierData;
#else /* WITH_SMOKE */
/* Stubs to use when smoke is disabled */
-struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), int UNUSED(amplify), int UNUSED(noisetype), const char *UNUSED(noisefile_path), int UNUSED(use_fire), int UNUSED(use_colors)) { return NULL; }
+struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), int UNUSED(amplify), int UNUSED(noisetype), const char *UNUSED(noisefile_path), int UNUSED(use_fire), int UNUSED(use_colors), int UNUSED(use_sim)) { return NULL; }
//struct FLUID_3D *smoke_init(int *UNUSED(res), float *UNUSED(dx), float *UNUSED(dtdef), int UNUSED(use_heat), int UNUSED(use_fire), int UNUSED(use_colors)) { return NULL; }
void smoke_free(struct FLUID_3D *UNUSED(fluid)) {}
float *smoke_get_density(struct FLUID_3D *UNUSED(fluid)) { return NULL; }
@@ -195,6 +196,8 @@ void smoke_reallocate_highres_fluid(SmokeDomainSettings *sds, float dx, int res[
{
int use_fire = (sds->active_fields & (SM_ACTIVE_HEAT | SM_ACTIVE_FIRE));
int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
+ int use_sim = !((sds->point_cache[0] != NULL) &&
+ (sds->point_cache[0]->flag & (PTCACHE_BAKED|PTCACHE_DISK_CACHE)) == (PTCACHE_BAKED|PTCACHE_DISK_CACHE));
if (free_old && sds->wt)
smoke_turbulence_free(sds->wt);
@@ -206,7 +209,7 @@ void smoke_reallocate_highres_fluid(SmokeDomainSettings *sds, float dx, int res[
/* smoke_turbulence_init uses non-threadsafe functions from fftw3 lib (like fftw_plan & co). */
BLI_lock_thread(LOCK_FFTW);
- sds->wt = smoke_turbulence_init(res, sds->amplify + 1, sds->noise, BKE_tempdir_session(), use_fire, use_colors);
+ sds->wt = smoke_turbulence_init(res, sds->amplify + 1, sds->noise, BKE_tempdir_session(), use_fire, use_colors, use_sim);
BLI_unlock_thread(LOCK_FFTW);
@@ -266,7 +269,7 @@ static void smoke_set_domain_from_derivedmesh(SmokeDomainSettings *sds, Object *
}
/* apply object scale */
for (i = 0; i < 3; i++) {
- size[i] = fabs(size[i] * ob->size[i]);
+ size[i] = fabsf(size[i] * ob->size[i]);
}
copy_v3_v3(sds->global_size, size);
copy_v3_v3(sds->dp0, min);
@@ -563,6 +566,8 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOWBIG;
smd->domain->effector_weights = BKE_add_effector_weights(NULL);
+
+ smd->domain->display_thickness = 1.0f;
}
else if (smd->type & MOD_SMOKE_TYPE_FLOW)
{
@@ -730,7 +735,8 @@ static void obstacles_from_derivedmesh(Object *coll_ob, SmokeDomainSettings *sds
BVHTreeFromMesh treeData = {NULL};
int numverts, i, z;
- float surface_distance = 0.6;
+ /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */
+ const float surface_distance = 0.867f;
float *vert_vel = NULL;
int has_velocity = 0;
@@ -970,7 +976,7 @@ static bool subframe_updateObject(Scene *scene, Object *ob, int update_mesh, int
/* also update constraint targets */
for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
if (cti && cti->get_constraint_targets) {
@@ -1025,6 +1031,7 @@ typedef struct EmissionMap {
float *velocity;
int min[3], max[3], res[3];
int hmin[3], hmax[3], hres[3];
+ float *color;
int total_cells, valid;
} EmissionMap;
@@ -1069,7 +1076,7 @@ static void clampBoundsInDomain(SmokeDomainSettings *sds, int min[3], int max[3]
}
}
-static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul)
+static void em_allocateData(EmissionMap *em, bool use_velocity, bool use_color, int hires_mul)
{
int i, res[3];
@@ -1085,6 +1092,8 @@ static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul)
em->influence = MEM_callocN(sizeof(float) * em->total_cells, "smoke_flow_influence");
if (use_velocity)
em->velocity = MEM_callocN(sizeof(float) * em->total_cells * 3, "smoke_flow_velocity");
+ if (use_color)
+ em->color = MEM_callocN(sizeof(float) * em->total_cells * 3, "smoke_flow_color");
/* allocate high resolution map if required */
if (hires_mul > 1) {
@@ -1109,6 +1118,8 @@ static void em_freeData(EmissionMap *em)
MEM_freeN(em->influence_high);
if (em->velocity)
MEM_freeN(em->velocity);
+ if (em->color)
+ MEM_freeN(em->color);
}
static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_multiplier, int additive, float sample_size)
@@ -1131,7 +1142,7 @@ static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_mult
}
}
/* allocate output map */
- em_allocateData(output, (em1.velocity || em2->velocity), hires_multiplier);
+ em_allocateData(output, (em1.velocity || em2->velocity), (em1.color || em2->color), hires_multiplier);
/* base resolution inputs */
for (x = output->min[0]; x < output->max[0]; x++)
@@ -1150,6 +1161,9 @@ static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_mult
if (output->velocity && em1.velocity) {
copy_v3_v3(&output->velocity[index_out * 3], &em1.velocity[index_in * 3]);
}
+ if (output->color && em1.color) {
+ copy_v3_v3(&output->color[index_out * 3], &em1.color[index_in * 3]);
+ }
}
/* apply second input if in range */
@@ -1171,6 +1185,13 @@ static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_mult
output->velocity[index_out * 3 + 1] = ADD_IF_LOWER(output->velocity[index_out * 3 + 1], em2->velocity[index_in * 3 + 1]);
output->velocity[index_out * 3 + 2] = ADD_IF_LOWER(output->velocity[index_out * 3 + 2], em2->velocity[index_in * 3 + 2]);
}
+ if (output->color && em2->color) {
+ /* mix by influence */
+ float f1 = output->influence[index_out];
+ float f2 = em2->influence[index_in];
+ float f = f1 + f2 > 0.0f ? f1 / (f1 + f2) : 0.5f;
+ interp_v3_v3v3(&output->color[index_out * 3], &output->color[index_out * 3], &em2->color[index_in * 3], f);
+ }
}
} // low res loop
@@ -1222,6 +1243,7 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
ParticleSystem *psys = sfs->psys;
float *particle_pos;
float *particle_vel;
+ float *particle_texcol;
int totpart = psys->totpart, totchild;
int p = 0;
int valid_particles = 0;
@@ -1238,6 +1260,12 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
sim.ob = flow_ob;
sim.psys = psys;
+ /* prepare curvemapping tables */
+ if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve)
+ curvemapping_changed_all(psys->part->clumpcurve);
+ if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve)
+ curvemapping_changed_all(psys->part->roughcurve);
+
/* initialize particle cache */
if (psys->part->type == PART_HAIR) {
// TODO: PART_HAIR not supported whatsoever
@@ -1262,6 +1290,11 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
bounds_margin = (int)ceil(solid + smooth);
}
+ if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_TEXCOLOR)
+ particle_texcol = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles");
+ else
+ particle_texcol = NULL;
+
/* calculate local position for each particle */
for (p = 0; p < totpart + totchild; p++)
{
@@ -1295,6 +1328,16 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
BLI_kdtree_insert(tree, valid_particles, pos);
}
+ if (particle_texcol) {
+ if (p < totpart) {
+ ParticleTexture ptex;
+ psys_get_texture(&sim, &psys->particles[p], &ptex, PAMAP_COLOR, state.time);
+ copy_v3_v3(&particle_texcol[valid_particles * 3], ptex.color);
+ }
+ else
+ zero_v3(&particle_texcol[valid_particles * 3]);
+ }
+
/* calculate emission map bounds */
em_boundInsert(em, pos);
valid_particles++;
@@ -1302,7 +1345,7 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
/* set emission map */
clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, bounds_margin, dt);
- em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier);
+ em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, sfs->flags & MOD_SMOKE_FLOW_USE_PART_TEXCOLOR, hires_multiplier);
if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) {
for (p = 0; p < valid_particles; p++)
@@ -1334,6 +1377,9 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
{
VECADDFAC(&em->velocity[index * 3], &em->velocity[index * 3], &particle_vel[p * 3], sfs->vel_multi);
}
+ if (particle_texcol && em->color) {
+ copy_v3_v3(&em->color[index * 3], &particle_texcol[p * 3]);
+ }
} // particles loop
}
else if (valid_particles > 0) { // MOD_SMOKE_FLOW_USE_PART_SIZE
@@ -1383,6 +1429,9 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
{
VECADDFAC(&em->velocity[index * 3], &em->velocity[index * 3], &particle_vel[nearest.index * 3], sfs->vel_multi);
}
+ if (particle_texcol && em->color) {
+ copy_v3_v3(&em->color[index * 3], &particle_texcol[nearest.index * 3]);
+ }
}
}
@@ -1420,6 +1469,8 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
MEM_freeN(particle_pos);
if (particle_vel)
MEM_freeN(particle_vel);
+ if (particle_texcol)
+ MEM_freeN(particle_texcol);
}
}
@@ -1633,7 +1684,7 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo
/* set emission map */
clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, (int)ceil(sfs->surface_distance), dt);
- em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier);
+ em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, false, hires_multiplier);
/* setup loop bounds */
for (i = 0; i < 3; i++) {
@@ -1975,7 +2026,7 @@ BLI_INLINE void apply_outflow_fields(int index, float *density, float *heat, flo
}
}
-BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value, int index, float *density, float *heat, float *fuel, float *react, float *color_r, float *color_g, float *color_b)
+BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value, const float *color_value, int index, float *density, float *heat, float *fuel, float *react, float *color_r, float *color_g, float *color_b)
{
int absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE);
float dens_old = density[index];
@@ -2012,9 +2063,10 @@ BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value
/* set color */
if (color_r && dens_flow) {
float total_dens = density[index] / (dens_old + dens_flow);
- color_r[index] = (color_r[index] + sfs->color[0] * dens_flow) * total_dens;
- color_g[index] = (color_g[index] + sfs->color[1] * dens_flow) * total_dens;
- color_b[index] = (color_b[index] + sfs->color[2] * dens_flow) * total_dens;
+ const float *color = (color_value ? color_value : sfs->color);
+ color_r[index] = (color_r[index] + color[0] * dens_flow) * total_dens;
+ color_g[index] = (color_g[index] + color[1] * dens_flow) * total_dens;
+ color_b[index] = (color_b[index] + color[2] * dens_flow) * total_dens;
}
/* set fire reaction coordinate */
@@ -2161,7 +2213,10 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
}
/* activate color field if flows add smoke with varying colors */
if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE && sfs->density) {
- if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
+ if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_TEXCOLOR) {
+ active_fields |= SM_ACTIVE_COLORS;
+ }
+ else if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
copy_v3_v3(sds->active_color, sfs->color);
active_fields |= SM_ACTIVE_COLOR_SET;
}
@@ -2242,6 +2297,7 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
float *velocity_map = em->velocity;
float *emission_map = em->influence;
float *emission_map_high = em->influence_high;
+ float *color_map = em->color;
int ii, jj, kk, gx, gy, gz, ex, ey, ez, dx, dy, dz, block_size;
size_t e_index, d_index, index_big;
@@ -2269,7 +2325,7 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
apply_outflow_fields(d_index, density, heat, fuel, react, color_r, color_g, color_b);
}
else { // inflow
- apply_inflow_fields(sfs, emission_map[e_index], d_index, density, heat, fuel, react, color_r, color_g, color_b);
+ apply_inflow_fields(sfs, emission_map[e_index], color_map ? &color_map[e_index * 3] : NULL, d_index, density, heat, fuel, react, color_r, color_g, color_b);
/* initial velocity */
if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
@@ -2283,6 +2339,7 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
if (bigdensity) {
// neighbor cell emission densities (for high resolution smoke smooth interpolation)
float c000, c001, c010, c011, c100, c101, c110, c111;
+ float col000[3], col001[3], col010[3], col011[3], col100[3], col101[3], col110[3], col111[3];
smoke_turbulence_get_res(sds->wt, bigres);
block_size = sds->amplify + 1; // high res block size
@@ -2297,14 +2354,67 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
c110 = (ez > 0) ? emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez - 1)] : 0;
c111 = emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez)]; // this cell
+ if (color_map) {
+ static const float Z[3] = {0.0f, 0.0f, 0.0f};
+
+ copy_v3_v3(col000, (ex > 0 && ey > 0 && ez > 0) ? &color_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez - 1) * 3] : Z);
+ copy_v3_v3(col001, (ex > 0 && ey > 0) ? &color_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez) * 3] : Z);
+ copy_v3_v3(col010, (ex > 0 && ez > 0) ? &color_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez - 1) * 3] : Z);
+ copy_v3_v3(col011, (ex > 0) ? &color_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez) * 3] : Z);
+
+ copy_v3_v3(col100, (ey > 0 && ez > 0) ? &color_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez - 1) * 3] : Z);
+ copy_v3_v3(col101, (ey > 0) ? &color_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez) * 3] : Z);
+ copy_v3_v3(col110, (ez > 0) ? &color_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez - 1) * 3] : Z);
+ copy_v3_v3(col111, &color_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez) * 3]); // this cell
+ }
+ else {
+ zero_v3(col000);
+ zero_v3(col001);
+ zero_v3(col010);
+ zero_v3(col011);
+ zero_v3(col100);
+ zero_v3(col101);
+ zero_v3(col110);
+ zero_v3(col111);
+ }
+
for (ii = 0; ii < block_size; ii++)
for (jj = 0; jj < block_size; jj++)
for (kk = 0; kk < block_size; kk++)
{
- float fx, fy, fz, interpolated_value;
+ float col[3], interpolated_value, *interpolated_color;
int shift_x = 0, shift_y = 0, shift_z = 0;
+ float w[2][2][2];
+ bool do_interpolation = ((!((sds->highres_sampling == SM_HRES_FULLSAMPLE) && emission_map_high) &&
+ !(sds->highres_sampling == SM_HRES_NEAREST)) ||
+ color_map);
+
+ /* weights are used for both density and color,
+ * so calculate them once in advance
+ */
+ if (do_interpolation) {
+ /* get relative block position
+ * for interpolation smoothing */
+ float fx = (float)ii / block_size + 0.5f / block_size;
+ float fy = (float)jj / block_size + 0.5f / block_size;
+ float fz = (float)kk / block_size + 0.5f / block_size;
+ float mx = 1.0f - fx;
+ float my = 1.0f - fy;
+ float mz = 1.0f - fz;
+
+ w[0][0][0] = mx * my * mz;
+ w[1][0][0] = fx * my * mz;
+ w[0][1][0] = mx * fy * mz;
+ w[1][1][0] = fx * fy * mz;
+ w[0][0][1] = mx * my * fz;
+ w[1][0][1] = fx * my * fz;
+ w[0][1][1] = mx * fy * fz;
+ w[1][1][1] = fx * fy * fz;
+ }
+ else
+ memset(w, 0, sizeof(float) * 8);
/* Use full sample emission map if enabled and available */
if ((sds->highres_sampling == SM_HRES_FULLSAMPLE) && emission_map_high) {
@@ -2318,22 +2428,17 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
/* Fall back to interpolated */
else
{
- /* get relative block position
- * for interpolation smoothing */
- fx = (float)ii / block_size + 0.5f / block_size;
- fy = (float)jj / block_size + 0.5f / block_size;
- fz = (float)kk / block_size + 0.5f / block_size;
/* calculate trilinear interpolation */
- interpolated_value = c000 * (1 - fx) * (1 - fy) * (1 - fz) +
- c100 * fx * (1 - fy) * (1 - fz) +
- c010 * (1 - fx) * fy * (1 - fz) +
- c001 * (1 - fx) * (1 - fy) * fz +
- c101 * fx * (1 - fy) * fz +
- c011 * (1 - fx) * fy * fz +
- c110 * fx * fy * (1 - fz) +
- c111 * fx * fy * fz;
-
+ interpolated_value = 0.0f;
+ interpolated_value += c000 * w[0][0][0];
+ interpolated_value += c100 * w[1][0][0];
+ interpolated_value += c010 * w[0][1][0];
+ interpolated_value += c110 * w[1][1][0];
+ interpolated_value += c001 * w[0][0][1];
+ interpolated_value += c101 * w[1][0][1];
+ interpolated_value += c011 * w[0][1][1];
+ interpolated_value += c111 * w[1][1][1];
/* add some contrast / sharpness
* depending on hi-res block size */
@@ -2347,6 +2452,48 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
shift_y = (dy < 1) ? 0 : block_size / 2;
shift_z = (dz < 1) ? 0 : block_size / 2;
}
+
+ if (color_map) {
+ float wcol[2][2][2], totw, invtotw;
+
+ /* colors are zero (black) in zero-emission cells,
+ * so use weighted average based on density to avoid artifacts!
+ */
+ wcol[0][0][0] = w[0][0][0] * c000;
+ wcol[1][0][0] = w[1][0][0] * c100;
+ wcol[0][1][0] = w[0][1][0] * c010;
+ wcol[1][1][0] = w[1][1][0] * c110;
+ wcol[0][0][1] = w[0][0][1] * c001;
+ wcol[1][0][1] = w[1][0][1] * c101;
+ wcol[0][1][1] = w[0][1][1] * c011;
+ wcol[1][1][1] = w[1][1][1] * c111;
+
+ totw = wcol[0][0][0] + wcol[1][0][0] + wcol[0][1][0] + wcol[1][1][0] +
+ wcol[0][0][1] + wcol[1][0][1] + wcol[0][1][1] + wcol[1][1][1];
+ invtotw = totw > 0.0f ? 1.0f/totw : 0.0f;
+ wcol[0][0][0] *= invtotw;
+ wcol[1][0][0] *= invtotw;
+ wcol[0][1][0] *= invtotw;
+ wcol[1][1][0] *= invtotw;
+ wcol[0][0][1] *= invtotw;
+ wcol[1][0][1] *= invtotw;
+ wcol[0][1][1] *= invtotw;
+ wcol[1][1][1] *= invtotw;
+
+ zero_v3(col);
+ madd_v3_v3fl(col, col000, wcol[0][0][0]);
+ madd_v3_v3fl(col, col100, wcol[1][0][0]);
+ madd_v3_v3fl(col, col010, wcol[0][1][0]);
+ madd_v3_v3fl(col, col110, wcol[1][1][0]);
+ madd_v3_v3fl(col, col001, wcol[0][0][1]);
+ madd_v3_v3fl(col, col101, wcol[1][0][1]);
+ madd_v3_v3fl(col, col011, wcol[0][1][1]);
+ madd_v3_v3fl(col, col111, wcol[1][1][1]);
+
+ interpolated_color = col;
+ }
+ else
+ interpolated_color = NULL;
/* get shifted index for current high resolution block */
index_big = smoke_get_index(block_size * dx + ii - shift_x, bigres[0], block_size * dy + jj - shift_y, bigres[1], block_size * dz + kk - shift_z);
@@ -2357,7 +2504,7 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
}
}
else { // inflow
- apply_inflow_fields(sfs, interpolated_value, index_big, bigdensity, NULL, bigfuel, bigreact, bigcolor_r, bigcolor_g, bigcolor_b);
+ apply_inflow_fields(sfs, interpolated_value, interpolated_color, index_big, bigdensity, NULL, bigfuel, bigreact, bigcolor_r, bigcolor_g, bigcolor_b);
}
} // hires loop
} // bigdensity
@@ -2381,7 +2528,7 @@ static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds,
ListBase *effectors;
/* make sure smoke flow influence is 0.0f */
sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
- effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights, true);
+ effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights);
if (effectors)
{
@@ -2663,7 +2810,7 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
int startframe, endframe, framenr;
float timescale;
- framenr = scene->r.cfra;
+ framenr = scene->r.cfra - sds->point_cache_offset;
//printf("time: %d\n", scene->r.cfra);
@@ -2744,6 +2891,7 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
if (sds->wt)
{
+ smoke_ensure_simulation(sds->fluid, sds->wt);
smoke_turbulence_step(sds->wt, sds->fluid);
}
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 06d0627fd2c..dc5b77a1bf4 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -522,10 +522,8 @@ static void ccd_mesh_update(Object *ob, ccd_Mesh *pccd_M)
mima->maxz = max_ff(mima->maxz, v[2] + hull);
}
-
- mima++;
- mface++;
-
+ mima++;
+ mface++;
}
return;
}
@@ -707,7 +705,7 @@ static void add_2nd_order_roller(Object *ob, float UNUSED(stiffness), int *count
}
}
if ((bs2->v2 !=notthis)&&(bs2->v2 > v0)) {
- (*counter)++;/*hit */
+ (*counter)++; /* hit */
if (addsprings) {
bs3->v1= v0;
bs3->v2= bs2->v2;
@@ -1037,6 +1035,7 @@ static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), unsigned int U
ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
ob = BLI_ghashIterator_getKey (ihash);
+ {
/* only with deflecting set */
if (ob->pd && ob->pd->deflect) {
#if 0 /* UNUSED */
@@ -1078,6 +1077,7 @@ static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), unsigned int U
}
} /* if (ob->pd && ob->pd->deflect) */
BLI_ghashIterator_step(ihash);
+ }
} /* while () */
BLI_ghashIterator_free(ihash);
return deflected;
@@ -1116,6 +1116,7 @@ static int sb_detect_face_pointCached(float face_v1[3], float face_v2[3], float
ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
ob = BLI_ghashIterator_getKey (ihash);
+ {
/* only with deflecting set */
if (ob->pd && ob->pd->deflect) {
MVert *mvert= NULL;
@@ -1179,6 +1180,7 @@ static int sb_detect_face_pointCached(float face_v1[3], float face_v2[3], float
} /* if (mvert) */
} /* if (ob->pd && ob->pd->deflect) */
BLI_ghashIterator_step(ihash);
+ }
} /* while () */
BLI_ghashIterator_free(ihash);
return deflected;
@@ -1208,6 +1210,7 @@ static int sb_detect_face_collisionCached(float face_v1[3], float face_v2[3], fl
ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
ob = BLI_ghashIterator_getKey (ihash);
+ {
/* only with deflecting set */
if (ob->pd && ob->pd->deflect) {
MFace *mface= NULL;
@@ -1317,6 +1320,7 @@ static int sb_detect_face_collisionCached(float face_v1[3], float face_v2[3], fl
}/* while a */
} /* if (ob->pd && ob->pd->deflect) */
BLI_ghashIterator_step(ihash);
+ }
} /* while () */
BLI_ghashIterator_free(ihash);
return deflected;
@@ -1436,6 +1440,7 @@ static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], fl
ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
ob = BLI_ghashIterator_getKey (ihash);
+ {
/* only with deflecting set */
if (ob->pd && ob->pd->deflect) {
MFace *mface= NULL;
@@ -1557,6 +1562,7 @@ static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], fl
}/* while a */
} /* if (ob->pd && ob->pd->deflect) */
BLI_ghashIterator_step(ihash);
+ }
} /* while () */
BLI_ghashIterator_free(ihash);
return deflected;
@@ -1641,7 +1647,7 @@ static void scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow)
SoftBody *sb = ob->soft;
ListBase *do_effector = NULL;
- do_effector = pdInitEffectors(scene, ob, NULL, sb->effector_weights, true);
+ do_effector = pdInitEffectors(scene, ob, NULL, sb->effector_weights);
_scan_for_ext_spring_forces(scene, ob, timenow, 0, sb->totspring, do_effector);
pdEndEffectors(&do_effector);
}
@@ -1661,7 +1667,7 @@ static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow,
int i, totthread, left, dec;
int lowsprings =100; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */
- do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights, true);
+ do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights);
/* figure the number of threads while preventing pretty pointless threading overhead */
totthread= BKE_scene_num_threads(scene);
@@ -1764,6 +1770,7 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3],
ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
ob = BLI_ghashIterator_getKey (ihash);
+ {
/* only with deflecting set */
if (ob->pd && ob->pd->deflect) {
MFace *mface= NULL;
@@ -1801,7 +1808,7 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3],
else {
/*aye that should be cached*/
printf("missing cache error\n");
- BLI_ghashIterator_step(ihash);
+ BLI_ghashIterator_step(ihash);
continue;
}
@@ -1919,16 +1926,16 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3],
if (facedist > outerfacethickness*ff)
force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness);
*damp=ob->pd->pdef_sbdamp;
- if (facedist > 0.0f) {
- *damp *= (1.0f - facedist/outerfacethickness);
- Vec3PlusStVec(outerforceaccu, force_mag_norm, d_nvect);
- deflected = 3;
+ if (facedist > 0.0f) {
+ *damp *= (1.0f - facedist/outerfacethickness);
+ Vec3PlusStVec(outerforceaccu, force_mag_norm, d_nvect);
+ deflected = 3;
- }
- else {
- Vec3PlusStVec(innerforceaccu, force_mag_norm, d_nvect);
- if (deflected < 2) deflected = 2;
- }
+ }
+ else {
+ Vec3PlusStVec(innerforceaccu, force_mag_norm, d_nvect);
+ if (deflected < 2) deflected = 2;
+ }
if ((mprevvert) && (*damp > 0.0f)) {
choose_winner(ve, opco, nv1, nv3, nv4, vv1, vv3, vv4);
@@ -1999,6 +2006,7 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3],
}/* while a */
} /* if (ob->pd && ob->pd->deflect) */
BLI_ghashIterator_step(ihash);
+ }
} /* while () */
if (deflected == 1) { // no face but 'outer' edge cylinder sees vert
@@ -2337,14 +2345,14 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
float kd = 1.0f;
if (sb_deflect_face(ob, bp->pos, facenormal, defforce, &cf, timenow, vel, &intrusion)) {
- if (intrusion < 0.0f) {
- sb->scratch->flag |= SBF_DOFUZZY;
- bp->loc_flag |= SBF_DOFUZZY;
- bp->choke = sb->choke*0.01f;
- }
+ if (intrusion < 0.0f) {
+ sb->scratch->flag |= SBF_DOFUZZY;
+ bp->loc_flag |= SBF_DOFUZZY;
+ bp->choke = sb->choke*0.01f;
+ }
- sub_v3_v3v3(cfforce, bp->vec, vel);
- Vec3PlusStVec(bp->force, -cf*50.0f, cfforce);
+ sub_v3_v3v3(cfforce, bp->vec, vel);
+ Vec3PlusStVec(bp->force, -cf*50.0f, cfforce);
Vec3PlusStVec(bp->force, kd, defforce);
}
@@ -2467,7 +2475,7 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl
sb_sfesf_threads_run(scene, ob, timenow, sb->totspring, NULL);
/* after spring scan because it uses Effoctors too */
- do_effector= pdInitEffectors(scene, ob, NULL, sb->effector_weights, true);
+ do_effector= pdInitEffectors(scene, ob, NULL, sb->effector_weights);
if (do_deflector) {
float defforce[3];
@@ -2542,7 +2550,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
if (do_springcollision || do_aero) scan_for_ext_spring_forces(scene, ob, timenow);
/* after spring scan because it uses Effoctors too */
- do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights, true);
+ do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights);
if (do_deflector) {
float defforce[3];
@@ -3486,7 +3494,7 @@ static void makelatticesprings(Lattice *lt, BodySpring *bs, int dostiff, Object
bs->v1 = bpc;
bs->v2 = bpc+dw+dv-1;
bs->springtype=SB_BEND;
- bs->len= globallen((bp+dw+dv-1)->vec, bp->vec, ob);
+ bs->len= globallen((bp+dw+dv-1)->vec, bp->vec, ob);
bs++;
}
}
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 6acd7276a33..81cc55f754d 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -64,9 +64,9 @@
static int sound_cfra;
#endif
-bSound *sound_new_file(struct Main *bmain, const char *filename)
+bSound *BKE_sound_new_file(struct Main *bmain, const char *filename)
{
- bSound *sound = NULL;
+ bSound *sound;
char str[FILE_MAX];
const char *path;
@@ -87,12 +87,7 @@ bSound *sound_new_file(struct Main *bmain, const char *filename)
BLI_strncpy(sound->name, filename, FILE_MAX);
/* sound->type = SOUND_TYPE_FILE; */ /* XXX unused currently */
- sound_load(bmain, sound);
-
- if (!sound->playback_handle) {
- BKE_libblock_free(bmain, sound);
- sound = NULL;
- }
+ BKE_sound_load(bmain, sound);
return sound;
}
@@ -116,7 +111,7 @@ void BKE_sound_free(bSound *sound)
sound->cache = NULL;
}
- sound_free_waveform(sound);
+ BKE_sound_free_waveform(sound);
if (sound->spinlock) {
BLI_spin_end(sound->spinlock);
@@ -141,18 +136,18 @@ static void sound_sync_callback(void *data, int mode, float time)
while (scene) {
if (scene->audio.flag & AUDIO_SYNC) {
if (mode)
- sound_play_scene(scene);
+ BKE_sound_play_scene(scene);
else
- sound_stop_scene(scene);
- if (scene->sound_scene_handle)
- AUD_seek(scene->sound_scene_handle, time);
+ BKE_sound_stop_scene(scene);
+ if (scene->playback_handle)
+ AUD_seek(scene->playback_handle, time);
}
scene = scene->id.next;
}
}
#endif
-int sound_define_from_str(const char *str)
+int BKE_sound_define_from_str(const char *str)
{
if (BLI_strcaseeq(str, "NULL"))
return AUD_NULL_DEVICE;
@@ -166,18 +161,18 @@ int sound_define_from_str(const char *str)
return -1;
}
-void sound_force_device(int device)
+void BKE_sound_force_device(int device)
{
force_device = device;
}
-void sound_init_once(void)
+void BKE_sound_init_once(void)
{
AUD_initOnce();
- atexit(sound_exit_once);
+ atexit(BKE_sound_exit_once);
}
-void sound_init(struct Main *bmain)
+void BKE_sound_init(struct Main *bmain)
{
AUD_DeviceSpecs specs;
int device, buffersize;
@@ -206,10 +201,10 @@ void sound_init(struct Main *bmain)
if (!AUD_init(device, specs, buffersize))
AUD_init(AUD_NULL_DEVICE, specs, buffersize);
- sound_init_main(bmain);
+ BKE_sound_init_main(bmain);
}
-void sound_init_main(struct Main *bmain)
+void BKE_sound_init_main(struct Main *bmain)
{
#ifdef WITH_JACK
AUD_setSyncCallback(sound_sync_callback, bmain);
@@ -218,12 +213,12 @@ void sound_init_main(struct Main *bmain)
#endif
}
-void sound_exit(void)
+void BKE_sound_exit(void)
{
AUD_exit();
}
-void sound_exit_once(void)
+void BKE_sound_exit_once(void)
{
AUD_exit();
AUD_exitOnce();
@@ -231,7 +226,7 @@ void sound_exit_once(void)
/* XXX unused currently */
#if 0
-bSound *sound_new_buffer(struct Main *bmain, bSound *source)
+bSound *BKE_sound_new_buffer(struct Main *bmain, bSound *source)
{
bSound *sound = NULL;
@@ -246,16 +241,10 @@ bSound *sound_new_buffer(struct Main *bmain, bSound *source)
sound_load(bmain, sound);
- if (!sound->playback_handle)
- {
- BKE_libblock_free(bmain, sound);
- sound = NULL;
- }
-
return sound;
}
-bSound *sound_new_limiter(struct Main *bmain, bSound *source, float start, float end)
+bSound *BKE_sound_new_limiter(struct Main *bmain, bSound *source, float start, float end)
{
bSound *sound = NULL;
@@ -272,17 +261,11 @@ bSound *sound_new_limiter(struct Main *bmain, bSound *source, float start, float
sound_load(bmain, sound);
- if (!sound->playback_handle)
- {
- BKE_libblock_free(bmain, sound);
- sound = NULL;
- }
-
return sound;
}
#endif
-void sound_delete(struct Main *bmain, bSound *sound)
+void BKE_sound_delete(struct Main *bmain, bSound *sound)
{
if (sound) {
BKE_sound_free(sound);
@@ -291,7 +274,7 @@ void sound_delete(struct Main *bmain, bSound *sound)
}
}
-void sound_cache(bSound *sound)
+void BKE_sound_cache(bSound *sound)
{
sound->flags |= SOUND_FLAGS_CACHING;
if (sound->cache)
@@ -304,7 +287,7 @@ void sound_cache(bSound *sound)
sound->playback_handle = sound->handle;
}
-void sound_delete_cache(bSound *sound)
+void BKE_sound_delete_cache(bSound *sound)
{
sound->flags &= ~SOUND_FLAGS_CACHING;
if (sound->cache) {
@@ -314,7 +297,7 @@ void sound_delete_cache(bSound *sound)
}
}
-void sound_load(struct Main *bmain, bSound *sound)
+void BKE_sound_load(struct Main *bmain, bSound *sound)
{
if (sound) {
if (sound->cache) {
@@ -328,7 +311,7 @@ void sound_load(struct Main *bmain, bSound *sound)
sound->playback_handle = NULL;
}
- sound_free_waveform(sound);
+ BKE_sound_free_waveform(sound);
/* XXX unused currently */
#if 0
@@ -382,16 +365,16 @@ void sound_load(struct Main *bmain, bSound *sound)
else
sound->playback_handle = sound->handle;
- sound_update_sequencer(bmain, sound);
+ BKE_sound_update_sequencer(bmain, sound);
}
}
-AUD_Device *sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume)
+AUD_Device *BKE_sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume)
{
return AUD_openMixdownDevice(specs, scene->sound_scene, volume, start / FPS);
}
-void sound_create_scene(struct Scene *scene)
+void BKE_sound_create_scene(struct Scene *scene)
{
/* should be done in version patch, but this gets called before */
if (scene->r.frs_sec_base == 0)
@@ -400,15 +383,15 @@ void sound_create_scene(struct Scene *scene)
scene->sound_scene = AUD_createSequencer(FPS, scene->audio.flag & AUDIO_MUTE);
AUD_updateSequencerData(scene->sound_scene, scene->audio.speed_of_sound,
scene->audio.doppler_factor, scene->audio.distance_model);
- scene->sound_scene_handle = NULL;
+ scene->playback_handle = NULL;
scene->sound_scrub_handle = NULL;
scene->speaker_handles = NULL;
}
-void sound_destroy_scene(struct Scene *scene)
+void BKE_sound_destroy_scene(struct Scene *scene)
{
- if (scene->sound_scene_handle)
- AUD_stop(scene->sound_scene_handle);
+ if (scene->playback_handle)
+ AUD_stop(scene->playback_handle);
if (scene->sound_scrub_handle)
AUD_stop(scene->sound_scrub_handle);
if (scene->sound_scene)
@@ -417,13 +400,13 @@ void sound_destroy_scene(struct Scene *scene)
AUD_destroySet(scene->speaker_handles);
}
-void sound_mute_scene(struct Scene *scene, int muted)
+void BKE_sound_mute_scene(struct Scene *scene, int muted)
{
if (scene->sound_scene)
AUD_setSequencerMuted(scene->sound_scene, muted);
}
-void sound_update_fps(struct Scene *scene)
+void BKE_sound_update_fps(struct Scene *scene)
{
if (scene->sound_scene)
AUD_setSequencerFPS(scene->sound_scene, FPS);
@@ -431,13 +414,13 @@ void sound_update_fps(struct Scene *scene)
BKE_sequencer_refresh_sound_length(scene);
}
-void sound_update_scene_listener(struct Scene *scene)
+void BKE_sound_update_scene_listener(struct Scene *scene)
{
AUD_updateSequencerData(scene->sound_scene, scene->audio.speed_of_sound,
scene->audio.doppler_factor, scene->audio.distance_model);
}
-void *sound_scene_add_scene_sound(struct Scene *scene, struct Sequence *sequence,
+void *BKE_sound_scene_add_scene_sound(struct Scene *scene, struct Sequence *sequence,
int startframe, int endframe, int frameskip)
{
if (scene != sequence->scene) {
@@ -448,14 +431,14 @@ void *sound_scene_add_scene_sound(struct Scene *scene, struct Sequence *sequence
return NULL;
}
-void *sound_scene_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence)
+void *BKE_sound_scene_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence)
{
- return sound_scene_add_scene_sound(scene, sequence,
+ return BKE_sound_scene_add_scene_sound(scene, sequence,
sequence->startdisp, sequence->enddisp,
sequence->startofs + sequence->anim_startofs);
}
-void *sound_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip)
+void *BKE_sound_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip)
{
const double fps = FPS;
void *handle = AUD_addSequence(scene->sound_scene, sequence->sound->playback_handle,
@@ -467,70 +450,70 @@ void *sound_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int
return handle;
}
-void *sound_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence)
+void *BKE_sound_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence)
{
- return sound_add_scene_sound(scene, sequence,
+ return BKE_sound_add_scene_sound(scene, sequence,
sequence->startdisp, sequence->enddisp,
sequence->startofs + sequence->anim_startofs);
}
-void sound_remove_scene_sound(struct Scene *scene, void *handle)
+void BKE_sound_remove_scene_sound(struct Scene *scene, void *handle)
{
AUD_removeSequence(scene->sound_scene, handle);
}
-void sound_mute_scene_sound(void *handle, char mute)
+void BKE_sound_mute_scene_sound(void *handle, char mute)
{
AUD_muteSequence(handle, mute);
}
-void sound_move_scene_sound(struct Scene *scene, void *handle, int startframe, int endframe, int frameskip)
+void BKE_sound_move_scene_sound(struct Scene *scene, void *handle, int startframe, int endframe, int frameskip)
{
const double fps = FPS;
AUD_moveSequence(handle, startframe / fps, endframe / fps, frameskip / fps);
}
-void sound_move_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence)
+void BKE_sound_move_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence)
{
if (sequence->scene_sound) {
- sound_move_scene_sound(scene, sequence->scene_sound,
+ BKE_sound_move_scene_sound(scene, sequence->scene_sound,
sequence->startdisp, sequence->enddisp,
sequence->startofs + sequence->anim_startofs);
}
}
-void sound_update_scene_sound(void *handle, bSound *sound)
+void BKE_sound_update_scene_sound(void *handle, bSound *sound)
{
AUD_updateSequenceSound(handle, sound->playback_handle);
}
-void sound_set_cfra(int cfra)
+void BKE_sound_set_cfra(int cfra)
{
sound_cfra = cfra;
}
-void sound_set_scene_volume(struct Scene *scene, float volume)
+void BKE_sound_set_scene_volume(struct Scene *scene, float volume)
{
AUD_setSequencerAnimData(scene->sound_scene, AUD_AP_VOLUME, CFRA, &volume,
(scene->audio.flag & AUDIO_VOLUME_ANIMATED) != 0);
}
-void sound_set_scene_sound_volume(void *handle, float volume, char animated)
+void BKE_sound_set_scene_sound_volume(void *handle, float volume, char animated)
{
AUD_setSequenceAnimData(handle, AUD_AP_VOLUME, sound_cfra, &volume, animated);
}
-void sound_set_scene_sound_pitch(void *handle, float pitch, char animated)
+void BKE_sound_set_scene_sound_pitch(void *handle, float pitch, char animated)
{
AUD_setSequenceAnimData(handle, AUD_AP_PITCH, sound_cfra, &pitch, animated);
}
-void sound_set_scene_sound_pan(void *handle, float pan, char animated)
+void BKE_sound_set_scene_sound_pan(void *handle, float pan, char animated)
{
AUD_setSequenceAnimData(handle, AUD_AP_PANNING, sound_cfra, &pan, animated);
}
-void sound_update_sequencer(struct Main *main, bSound *sound)
+void BKE_sound_update_sequencer(struct Main *main, bSound *sound)
{
struct Scene *scene;
@@ -541,36 +524,36 @@ void sound_update_sequencer(struct Main *main, bSound *sound)
static void sound_start_play_scene(struct Scene *scene)
{
- if (scene->sound_scene_handle)
- AUD_stop(scene->sound_scene_handle);
+ if (scene->playback_handle)
+ AUD_stop(scene->playback_handle);
AUD_setSequencerDeviceSpecs(scene->sound_scene);
- if ((scene->sound_scene_handle = AUD_play(scene->sound_scene, 1)))
- AUD_setLoop(scene->sound_scene_handle, -1);
+ if ((scene->playback_handle = AUD_play(scene->sound_scene, 1)))
+ AUD_setLoop(scene->playback_handle, -1);
}
-void sound_play_scene(struct Scene *scene)
+void BKE_sound_play_scene(struct Scene *scene)
{
AUD_Status status;
const float cur_time = (float)((double)CFRA / FPS);
AUD_lock();
- status = scene->sound_scene_handle ? AUD_getStatus(scene->sound_scene_handle) : AUD_STATUS_INVALID;
+ status = scene->playback_handle ? AUD_getStatus(scene->playback_handle) : AUD_STATUS_INVALID;
if (status == AUD_STATUS_INVALID) {
sound_start_play_scene(scene);
- if (!scene->sound_scene_handle) {
+ if (!scene->playback_handle) {
AUD_unlock();
return;
}
}
if (status != AUD_STATUS_PLAYING) {
- AUD_seek(scene->sound_scene_handle, cur_time);
- AUD_resume(scene->sound_scene_handle);
+ AUD_seek(scene->playback_handle, cur_time);
+ AUD_resume(scene->playback_handle);
}
if (scene->audio.flag & AUDIO_SYNC)
@@ -579,17 +562,17 @@ void sound_play_scene(struct Scene *scene)
AUD_unlock();
}
-void sound_stop_scene(struct Scene *scene)
+void BKE_sound_stop_scene(struct Scene *scene)
{
- if (scene->sound_scene_handle) {
- AUD_pause(scene->sound_scene_handle);
+ if (scene->playback_handle) {
+ AUD_pause(scene->playback_handle);
if (scene->audio.flag & AUDIO_SYNC)
AUD_stopPlayback();
}
}
-void sound_seek_scene(struct Main *bmain, struct Scene *scene)
+void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene)
{
AUD_Status status;
bScreen *screen;
@@ -600,17 +583,17 @@ void sound_seek_scene(struct Main *bmain, struct Scene *scene)
AUD_lock();
- status = scene->sound_scene_handle ? AUD_getStatus(scene->sound_scene_handle) : AUD_STATUS_INVALID;
+ status = scene->playback_handle ? AUD_getStatus(scene->playback_handle) : AUD_STATUS_INVALID;
if (status == AUD_STATUS_INVALID) {
sound_start_play_scene(scene);
- if (!scene->sound_scene_handle) {
+ if (!scene->playback_handle) {
AUD_unlock();
return;
}
- AUD_pause(scene->sound_scene_handle);
+ AUD_pause(scene->playback_handle);
}
animation_playing = 0;
@@ -623,13 +606,13 @@ void sound_seek_scene(struct Main *bmain, struct Scene *scene)
if ((scene->audio.flag & AUDIO_SCRUB) && !animation_playing) {
if (scene->audio.flag & AUDIO_SYNC) {
- AUD_seek(scene->sound_scene_handle, cur_time);
- AUD_seekSequencer(scene->sound_scene_handle, cur_time);
+ AUD_seek(scene->playback_handle, cur_time);
+ AUD_seekSequencer(scene->playback_handle, cur_time);
}
else {
- AUD_seek(scene->sound_scene_handle, cur_time);
+ AUD_seek(scene->playback_handle, cur_time);
}
- AUD_resume(scene->sound_scene_handle);
+ AUD_resume(scene->playback_handle);
if (scene->sound_scrub_handle && AUD_getStatus(scene->sound_scrub_handle) != AUD_STATUS_INVALID) {
AUD_seek(scene->sound_scrub_handle, 0);
}
@@ -637,16 +620,16 @@ void sound_seek_scene(struct Main *bmain, struct Scene *scene)
if (scene->sound_scrub_handle) {
AUD_stop(scene->sound_scrub_handle);
}
- scene->sound_scrub_handle = AUD_pauseAfter(scene->sound_scene_handle, one_frame);
+ scene->sound_scrub_handle = AUD_pauseAfter(scene->playback_handle, one_frame);
}
}
else {
if (scene->audio.flag & AUDIO_SYNC) {
- AUD_seekSequencer(scene->sound_scene_handle, cur_time);
+ AUD_seekSequencer(scene->playback_handle, cur_time);
}
else {
if (status == AUD_STATUS_PLAYING) {
- AUD_seek(scene->sound_scene_handle, cur_time);
+ AUD_seek(scene->playback_handle, cur_time);
}
}
}
@@ -654,18 +637,18 @@ void sound_seek_scene(struct Main *bmain, struct Scene *scene)
AUD_unlock();
}
-float sound_sync_scene(struct Scene *scene)
+float BKE_sound_sync_scene(struct Scene *scene)
{
- if (scene->sound_scene_handle) {
+ if (scene->playback_handle) {
if (scene->audio.flag & AUDIO_SYNC)
- return AUD_getSequencerPosition(scene->sound_scene_handle);
+ return AUD_getSequencerPosition(scene->playback_handle);
else
- return AUD_getPosition(scene->sound_scene_handle);
+ return AUD_getPosition(scene->playback_handle);
}
return NAN_FLT;
}
-int sound_scene_playing(struct Scene *scene)
+int BKE_sound_scene_playing(struct Scene *scene)
{
if (scene->audio.flag & AUDIO_SYNC)
return AUD_doesPlayback();
@@ -673,7 +656,7 @@ int sound_scene_playing(struct Scene *scene)
return -1;
}
-void sound_free_waveform(bSound *sound)
+void BKE_sound_free_waveform(bSound *sound)
{
SoundWaveform *waveform = sound->waveform;
if (waveform) {
@@ -686,7 +669,7 @@ void sound_free_waveform(bSound *sound)
sound->waveform = NULL;
}
-void sound_read_waveform(bSound *sound, short *stop)
+void BKE_sound_read_waveform(bSound *sound, short *stop)
{
AUD_SoundInfo info = AUD_getInfo(sound->playback_handle);
SoundWaveform *waveform = MEM_mallocN(sizeof(SoundWaveform), "SoundWaveform");
@@ -717,7 +700,7 @@ void sound_read_waveform(bSound *sound, short *stop)
return;
}
- sound_free_waveform(sound);
+ BKE_sound_free_waveform(sound);
BLI_spin_lock(sound->spinlock);
sound->waveform = waveform;
@@ -725,7 +708,7 @@ void sound_read_waveform(bSound *sound, short *stop)
BLI_spin_unlock(sound->spinlock);
}
-void sound_update_scene(Main *bmain, struct Scene *scene)
+void BKE_sound_update_scene(Main *bmain, struct Scene *scene)
{
Object *ob;
Base *base;
@@ -806,20 +789,20 @@ void sound_update_scene(Main *bmain, struct Scene *scene)
scene->speaker_handles = new_set;
}
-void *sound_get_factory(void *sound)
+void *BKE_sound_get_factory(void *sound)
{
return ((bSound *)sound)->playback_handle;
}
/* stupid wrapper because AUD_C-API.h includes Python.h which makesrna doesn't like */
-float sound_get_length(bSound *sound)
+float BKE_sound_get_length(bSound *sound)
{
AUD_SoundInfo info = AUD_getInfo(sound->playback_handle);
return info.length;
}
-bool sound_is_jack_supported(void)
+bool BKE_sound_is_jack_supported(void)
{
return (bool)AUD_isJackSupported();
}
@@ -828,47 +811,47 @@ bool sound_is_jack_supported(void)
#include "BLI_utildefines.h"
-int sound_define_from_str(const char *UNUSED(str)) { return -1; }
-void sound_force_device(int UNUSED(device)) {}
-void sound_init_once(void) {}
-void sound_init(struct Main *UNUSED(bmain)) {}
-void sound_exit(void) {}
-void sound_exit_once(void) {}
-void sound_cache(struct bSound *UNUSED(sound)) {}
-void sound_delete_cache(struct bSound *UNUSED(sound)) {}
-void sound_load(struct Main *UNUSED(bmain), struct bSound *UNUSED(sound)) {}
-void sound_create_scene(struct Scene *UNUSED(scene)) {}
-void sound_destroy_scene(struct Scene *UNUSED(scene)) {}
-void sound_mute_scene(struct Scene *UNUSED(scene), int UNUSED(muted)) {}
-void *sound_scene_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence),
- int UNUSED(startframe), int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; }
-void *sound_scene_add_scene_sound_defaults(struct Scene *UNUSED(scene),
- struct Sequence *UNUSED(sequence)) { return NULL; }
-void *sound_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence), int UNUSED(startframe),
- int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; }
-void *sound_add_scene_sound_defaults(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence)) { return NULL; }
-void sound_remove_scene_sound(struct Scene *UNUSED(scene), void *UNUSED(handle)) {}
-void sound_mute_scene_sound(void *UNUSED(handle), char UNUSED(mute)) {}
-void sound_move_scene_sound(struct Scene *UNUSED(scene), void *UNUSED(handle), int UNUSED(startframe),
- int UNUSED(endframe), int UNUSED(frameskip)) {}
-void sound_move_scene_sound_defaults(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence)) {}
-void sound_play_scene(struct Scene *UNUSED(scene)) {}
-void sound_stop_scene(struct Scene *UNUSED(scene)) {}
-void sound_seek_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene)) {}
-float sound_sync_scene(struct Scene *UNUSED(scene)) { return NAN_FLT; }
-int sound_scene_playing(struct Scene *UNUSED(scene)) { return -1; }
-void sound_read_waveform(struct bSound *sound, short *stop) { UNUSED_VARS(sound, stop); }
-void sound_init_main(struct Main *UNUSED(bmain)) {}
-void sound_set_cfra(int UNUSED(cfra)) {}
-void sound_update_sequencer(struct Main *UNUSED(main), struct bSound *UNUSED(sound)) {}
-void sound_update_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene)) {}
-void sound_update_scene_sound(void *UNUSED(handle), struct bSound *UNUSED(sound)) {}
-void sound_update_scene_listener(struct Scene *UNUSED(scene)) {}
-void sound_update_fps(struct Scene *UNUSED(scene)) {}
-void sound_set_scene_sound_volume(void *UNUSED(handle), float UNUSED(volume), char UNUSED(animated)) {}
-void sound_set_scene_sound_pan(void *UNUSED(handle), float UNUSED(pan), char UNUSED(animated)) {}
-void sound_set_scene_volume(struct Scene *UNUSED(scene), float UNUSED(volume)) {}
-void sound_set_scene_sound_pitch(void *UNUSED(handle), float UNUSED(pitch), char UNUSED(animated)) {}
-float sound_get_length(struct bSound *UNUSED(sound)) { return 0; }
-bool sound_is_jack_supported(void) { return false; }
+int BKE_sound_define_from_str(const char *UNUSED(str)) { return -1; }
+void BKE_sound_force_device(int UNUSED(device)) {}
+void BKE_sound_init_once(void) {}
+void BKE_sound_init(struct Main *UNUSED(bmain)) {}
+void BKE_sound_exit(void) {}
+void BKE_sound_exit_once(void) {}
+void BKE_sound_cache(struct bSound *UNUSED(sound)) {}
+void BKE_sound_delete_cache(struct bSound *UNUSED(sound)) {}
+void BKE_sound_load(struct Main *UNUSED(bmain), struct bSound *UNUSED(sound)) {}
+void BKE_sound_create_scene(struct Scene *UNUSED(scene)) {}
+void BKE_sound_destroy_scene(struct Scene *UNUSED(scene)) {}
+void BKE_sound_mute_scene(struct Scene *UNUSED(scene), int UNUSED(muted)) {}
+void *BKE_sound_scene_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence),
+ int UNUSED(startframe), int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; }
+void *BKE_sound_scene_add_scene_sound_defaults(struct Scene *UNUSED(scene),
+ struct Sequence *UNUSED(sequence)) { return NULL; }
+void *BKE_sound_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence), int UNUSED(startframe),
+ int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; }
+void *BKE_sound_add_scene_sound_defaults(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence)) { return NULL; }
+void BKE_sound_remove_scene_sound(struct Scene *UNUSED(scene), void *UNUSED(handle)) {}
+void BKE_sound_mute_scene_sound(void *UNUSED(handle), char UNUSED(mute)) {}
+void BKE_sound_move_scene_sound(struct Scene *UNUSED(scene), void *UNUSED(handle), int UNUSED(startframe),
+ int UNUSED(endframe), int UNUSED(frameskip)) {}
+void BKE_sound_move_scene_sound_defaults(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence)) {}
+void BKE_sound_play_scene(struct Scene *UNUSED(scene)) {}
+void BKE_sound_stop_scene(struct Scene *UNUSED(scene)) {}
+void BKE_sound_seek_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene)) {}
+float BKE_sound_sync_scene(struct Scene *UNUSED(scene)) { return NAN_FLT; }
+int BKE_sound_scene_playing(struct Scene *UNUSED(scene)) { return -1; }
+void BKE_sound_read_waveform(struct bSound *sound, short *stop) { UNUSED_VARS(sound, stop); }
+void BKE_sound_init_main(struct Main *UNUSED(bmain)) {}
+void BKE_sound_set_cfra(int UNUSED(cfra)) {}
+void BKE_sound_update_sequencer(struct Main *UNUSED(main), struct bSound *UNUSED(sound)) {}
+void BKE_sound_update_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene)) {}
+void BKE_sound_update_scene_sound(void *UNUSED(handle), struct bSound *UNUSED(sound)) {}
+void BKE_sound_update_scene_listener(struct Scene *UNUSED(scene)) {}
+void BKE_sound_update_fps(struct Scene *UNUSED(scene)) {}
+void BKE_sound_set_scene_sound_volume(void *UNUSED(handle), float UNUSED(volume), char UNUSED(animated)) {}
+void BKE_sound_set_scene_sound_pan(void *UNUSED(handle), float UNUSED(pan), char UNUSED(animated)) {}
+void BKE_sound_set_scene_volume(struct Scene *UNUSED(scene), float UNUSED(volume)) {}
+void BKE_sound_set_scene_sound_pitch(void *UNUSED(handle), float UNUSED(pitch), char UNUSED(animated)) {}
+float BKE_sound_get_length(struct bSound *UNUSED(sound)) { return 0; }
+bool BKE_sound_is_jack_supported(void) { return false; }
#endif /* WITH_AUDASPACE */
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index b11d0ae03b0..7a800555144 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -130,5 +130,5 @@ void BKE_speaker_free(Speaker *spk)
if (spk->sound)
spk->sound->id.us--;
- BKE_free_animdata((ID *)spk);
+ BKE_animdata_free((ID *)spk);
}
diff --git a/source/blender/blenkernel/intern/strands.c b/source/blender/blenkernel/intern/strands.c
new file mode 100644
index 00000000000..38d35a7309e
--- /dev/null
+++ b/source/blender/blenkernel/intern/strands.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_strands.h"
+
+Strands *BKE_strands_new(int curves, int verts)
+{
+ Strands *strands = MEM_mallocN(sizeof(Strands), "strands");
+
+ strands->totcurves = curves;
+ strands->curves = MEM_mallocN(sizeof(StrandsCurve) * curves, "strand curves");
+
+ strands->totverts = verts;
+ strands->verts = MEM_mallocN(sizeof(StrandsVertex) * verts, "strand vertices");
+
+ /* must be added explicitly */
+ strands->state = NULL;
+
+ return strands;
+}
+
+Strands *BKE_strands_copy(Strands *strands)
+{
+ Strands *new_strands = MEM_dupallocN(strands);
+ if (new_strands->curves)
+ new_strands->curves = MEM_dupallocN(new_strands->curves);
+ if (new_strands->verts)
+ new_strands->verts = MEM_dupallocN(new_strands->verts);
+ if (new_strands->state)
+ new_strands->state = MEM_dupallocN(new_strands->state);
+ return new_strands;
+}
+
+void BKE_strands_free(Strands *strands)
+{
+ if (strands) {
+ if (strands->curves)
+ MEM_freeN(strands->curves);
+ if (strands->verts)
+ MEM_freeN(strands->verts);
+ if (strands->state)
+ MEM_freeN(strands->state);
+ MEM_freeN(strands);
+ }
+}
+
+/* copy the rest positions to initialize the motion state */
+void BKE_strands_state_copy_rest_positions(Strands *strands)
+{
+ if (strands->state) {
+ int i;
+ for (i = 0; i < strands->totverts; ++i) {
+ copy_v3_v3(strands->state[i].co, strands->verts[i].co);
+ }
+ }
+}
+
+/* copy the rest positions to initialize the motion state */
+void BKE_strands_state_clear_velocities(Strands *strands)
+{
+ if (strands->state) {
+ int i;
+
+ for (i = 0; i < strands->totverts; ++i) {
+ zero_v3(strands->state[i].vel);
+ }
+ }
+}
+
+void BKE_strands_add_motion_state(Strands *strands)
+{
+ if (!strands->state) {
+ int i;
+
+ strands->state = MEM_mallocN(sizeof(StrandsMotionState) * strands->totverts, "strand motion states");
+
+ BKE_strands_state_copy_rest_positions(strands);
+ BKE_strands_state_clear_velocities(strands);
+
+ /* initialize normals */
+ for (i = 0; i < strands->totverts; ++i) {
+ copy_v3_v3(strands->state[i].nor, strands->verts[i].nor);
+ }
+ }
+}
+
+void BKE_strands_remove_motion_state(Strands *strands)
+{
+ if (strands) {
+ if (strands->state) {
+ MEM_freeN(strands->state);
+ strands->state = NULL;
+ }
+ }
+}
+
+static void calc_normals(Strands *strands, bool use_motion_state)
+{
+ StrandIterator it_strand;
+ for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+ StrandEdgeIterator it_edge;
+ int numverts = it_strand.curve->numverts;
+ if (use_motion_state) {
+ for (BKE_strand_edge_iter_init(&it_edge, &it_strand); BKE_strand_edge_iter_valid(&it_edge); BKE_strand_edge_iter_next(&it_edge)) {
+ sub_v3_v3v3(it_edge.state0->nor, it_edge.state1->co, it_edge.state0->co);
+ normalize_v3(it_edge.state0->nor);
+ }
+ if (numverts > 1)
+ copy_v3_v3(it_strand.state[numverts-1].nor, it_strand.state[numverts-2].nor);
+ }
+ else {
+ for (BKE_strand_edge_iter_init(&it_edge, &it_strand); BKE_strand_edge_iter_valid(&it_edge); BKE_strand_edge_iter_next(&it_edge)) {
+ sub_v3_v3v3(it_edge.vertex0->nor, it_edge.vertex1->co, it_edge.vertex0->co);
+ normalize_v3(it_edge.vertex0->nor);
+ }
+ if (numverts > 1)
+ copy_v3_v3(it_strand.verts[numverts-1].nor, it_strand.verts[numverts-2].nor);
+ }
+ }
+}
+
+void BKE_strands_ensure_normals(Strands *strands)
+{
+ const bool use_motion_state = (strands->state);
+
+ calc_normals(strands, false);
+
+ if (use_motion_state)
+ calc_normals(strands, true);
+}
+
+void BKE_strands_get_minmax(Strands *strands, float min[3], float max[3], bool use_motion_state)
+{
+ int numverts = strands->totverts;
+ int i;
+
+ if (use_motion_state && strands->state) {
+ for (i = 0; i < numverts; ++i) {
+ minmax_v3v3_v3(min, max, strands->state[i].co);
+ }
+ }
+ else {
+ for (i = 0; i < numverts; ++i) {
+ minmax_v3v3_v3(min, max, strands->verts[i].co);
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+StrandsChildren *BKE_strands_children_new(int curves, int verts)
+{
+ StrandsChildren *strands = MEM_mallocN(sizeof(StrandsChildren), "strands children");
+
+ strands->totcurves = curves;
+ strands->curves = MEM_mallocN(sizeof(StrandsChildCurve) * curves, "strand children curves");
+
+ strands->totverts = verts;
+ strands->verts = MEM_mallocN(sizeof(StrandsChildVertex) * verts, "strand children vertices");
+
+ /* must be added explicitly */
+ strands->curve_uvs = NULL;
+ strands->numuv = 0;
+ strands->curve_vcols = NULL;
+ strands->numvcol = 0;
+
+ return strands;
+}
+
+StrandsChildren *BKE_strands_children_copy(StrandsChildren *strands)
+{
+ StrandsChildren *new_strands = MEM_dupallocN(strands);
+ if (new_strands->curves)
+ new_strands->curves = MEM_dupallocN(new_strands->curves);
+ if (new_strands->curve_uvs)
+ new_strands->curve_uvs = MEM_dupallocN(new_strands->curve_uvs);
+ if (new_strands->curve_vcols)
+ new_strands->curve_vcols = MEM_dupallocN(new_strands->curve_vcols);
+ if (new_strands->verts)
+ new_strands->verts = MEM_dupallocN(new_strands->verts);
+ return new_strands;
+}
+
+void BKE_strands_children_free(StrandsChildren *strands)
+{
+ if (strands) {
+ if (strands->curves)
+ MEM_freeN(strands->curves);
+ if (strands->curve_uvs)
+ MEM_freeN(strands->curve_uvs);
+ if (strands->curve_vcols)
+ MEM_freeN(strands->curve_vcols);
+ if (strands->verts)
+ MEM_freeN(strands->verts);
+ MEM_freeN(strands);
+ }
+}
+
+void BKE_strands_children_add_uvs(StrandsChildren *strands, int num_layers)
+{
+ if (strands->curve_uvs && strands->numuv != num_layers) {
+ MEM_freeN(strands->curve_uvs);
+ strands->curve_uvs = NULL;
+ strands->numuv = 0;
+ }
+
+ if (!strands->curve_uvs) {
+ strands->curve_uvs = MEM_callocN(sizeof(StrandsChildCurveUV) * strands->totcurves * num_layers, "strands children uv layers");
+ strands->numuv = num_layers;
+ }
+}
+
+void BKE_strands_children_add_vcols(StrandsChildren *strands, int num_layers)
+{
+ if (strands->curve_vcols && strands->numvcol != num_layers) {
+ MEM_freeN(strands->curve_vcols);
+ strands->curve_vcols = NULL;
+ strands->numvcol = 0;
+ }
+
+ if (!strands->curve_vcols) {
+ strands->curve_vcols = MEM_callocN(sizeof(StrandsChildCurveVCol) * strands->totcurves * num_layers, "strands children vcol layers");
+ strands->numvcol = num_layers;
+ }
+}
+
+static int *strands_calc_vertex_start(Strands *strands)
+{
+ int *vertstart = MEM_mallocN(sizeof(int) * strands->totcurves, "strand curves vertex start");
+ StrandIterator it_strand;
+ int start;
+
+ start = 0;
+ for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+ vertstart[it_strand.index] = start;
+ start += it_strand.curve->numverts;
+ }
+
+ return vertstart;
+}
+
+
+/* 'out' is an optional array to write final positions to, instead of writing back to vertex locations.
+ * It must be at least as large as the number of vertices.
+ */
+static void strands_children_strand_deform(StrandChildIterator *it_strand, Strands *parents, int *vertstart, bool use_motion, float (*out)[3])
+{
+ int i;
+
+ if (!parents || !vertstart)
+ return;
+
+ if (!parents->state)
+ use_motion = false;
+
+ for (i = 0; i < 4; ++i) {
+ int p = it_strand->curve->parents[i];
+ float w = it_strand->curve->parent_weights[i];
+ if (p >= 0 && w > 0.0f) {
+ StrandsCurve *parent = &parents->curves[p];
+ StrandsVertex *pverts;
+ StrandsMotionState *pstate;
+ int pv0, pv1;
+ StrandChildVertexIterator it_vert;
+
+ if (parent->numverts <= 0)
+ continue;
+
+ pverts = &parents->verts[vertstart[p]];
+ pstate = &parents->state[vertstart[p]];
+ pv0 = 0;
+ for (BKE_strand_child_vertex_iter_init(&it_vert, it_strand); BKE_strand_child_vertex_iter_valid(&it_vert); BKE_strand_child_vertex_iter_next(&it_vert)) {
+ float time = it_vert.vertex->time;
+ float dt, x;
+ float poffset0[3], poffset1[3], offset[3];
+
+ /* advance to the matching parent edge for interpolation */
+ while (pv0 < parent->numverts-1 && pverts[pv0+1].time < time)
+ ++pv0;
+ pv1 = (pv0 < parent->numverts-1)? pv0+1 : pv0;
+
+ if (use_motion) {
+ sub_v3_v3v3(poffset0, pstate[pv0].co, pverts[pv0].base);
+ sub_v3_v3v3(poffset1, pstate[pv1].co, pverts[pv1].base);
+ }
+ else {
+ sub_v3_v3v3(poffset0, pverts[pv0].co, pverts[pv0].base);
+ sub_v3_v3v3(poffset1, pverts[pv1].co, pverts[pv1].base);
+ }
+
+ dt = pverts[pv1].time - pverts[pv0].time;
+ x = dt > 0.0f ? (time - pverts[pv0].time) / dt : 0.0f;
+ CLAMP(x, 0.0f, 1.0f);
+ interp_v3_v3v3(offset, poffset0, poffset1, x);
+
+ if (out)
+ madd_v3_v3fl(out[it_vert.index], offset, w);
+ else
+ madd_v3_v3fl(it_vert.vertex->co, offset, w);
+ }
+ }
+ }
+}
+
+void BKE_strands_children_deform(StrandsChildren *strands, Strands *parents, bool use_motion)
+{
+ int *vertstart = NULL;
+ StrandChildIterator it_strand;
+
+ if (parents)
+ vertstart = strands_calc_vertex_start(parents);
+
+ for (BKE_strand_child_iter_init(&it_strand, strands); BKE_strand_child_iter_valid(&it_strand); BKE_strand_child_iter_next(&it_strand)) {
+ /* move child strands from their local root space to object space */
+ StrandChildVertexIterator it_vert;
+ for (BKE_strand_child_vertex_iter_init(&it_vert, &it_strand); BKE_strand_child_vertex_iter_valid(&it_vert); BKE_strand_child_vertex_iter_next(&it_vert)) {
+ mul_v3_m4v3(it_vert.vertex->co, it_strand.curve->root_matrix, it_vert.vertex->base);
+ }
+
+ strands_children_strand_deform(&it_strand, parents, vertstart, use_motion, NULL);
+ }
+
+ if (vertstart)
+ MEM_freeN(vertstart);
+}
+
+static void calc_child_normals(StrandsChildren *strands)
+{
+ StrandChildIterator it_strand;
+ for (BKE_strand_child_iter_init(&it_strand, strands); BKE_strand_child_iter_valid(&it_strand); BKE_strand_child_iter_next(&it_strand)) {
+ StrandChildEdgeIterator it_edge;
+ int numverts = it_strand.curve->numverts;
+ for (BKE_strand_child_edge_iter_init(&it_edge, &it_strand); BKE_strand_child_edge_iter_valid(&it_edge); BKE_strand_child_edge_iter_next(&it_edge)) {
+ sub_v3_v3v3(it_edge.vertex0->nor, it_edge.vertex1->co, it_edge.vertex0->co);
+ normalize_v3(it_edge.vertex0->nor);
+ }
+ if (numverts > 1)
+ copy_v3_v3(it_strand.verts[numverts-1].nor, it_strand.verts[numverts-2].nor);
+ }
+}
+
+void BKE_strands_children_ensure_normals(StrandsChildren *strands)
+{
+ calc_child_normals(strands);
+}
+
+void BKE_strands_children_get_minmax(StrandsChildren *strands, float min[3], float max[3])
+{
+ int numverts = strands->totverts;
+ int i;
+
+ for (i = 0; i < numverts; ++i) {
+ minmax_v3v3_v3(min, max, strands->verts[i].co);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+void BKE_strand_bend_iter_transform_rest(StrandBendIterator *iter, float mat[3][3])
+{
+ float dir0[3], dir1[3];
+
+ sub_v3_v3v3(dir0, iter->vertex1->co, iter->vertex0->co);
+ sub_v3_v3v3(dir1, iter->vertex2->co, iter->vertex1->co);
+ normalize_v3(dir0);
+ normalize_v3(dir1);
+
+ /* rotation between segments */
+ rotation_between_vecs_to_mat3(mat, dir0, dir1);
+}
+
+void BKE_strand_bend_iter_transform_state(StrandBendIterator *iter, float mat[3][3])
+{
+ if (iter->state0) {
+ float dir0[3], dir1[3];
+
+ sub_v3_v3v3(dir0, iter->state1->co, iter->state0->co);
+ sub_v3_v3v3(dir1, iter->state2->co, iter->state1->co);
+ normalize_v3(dir0);
+ normalize_v3(dir1);
+
+ /* rotation between segments */
+ rotation_between_vecs_to_mat3(mat, dir0, dir1);
+ }
+ else
+ unit_m3(mat);
+}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index fc97d156852..16f218d5fb6 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -301,7 +301,11 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm,
float uv[3] = {0.0f, 0.0f, 0.0f}; /* only first 2 values are written into */
limit[0] = limit[1] = STD_UV_CONNECT_LIMIT;
- vmap = BKE_mesh_uv_vert_map_create(mpoly, mloop, mloopuv, totface, totvert, 0, limit);
+ /* previous behavior here is without accounting for winding, however this causes stretching in
+ * UV map in really simple cases with mirror + subsurf, see second part of T44530. Also, initially
+ * intention is to treat merged vertices from mirror modifier as seams, see code below with ME_VERT_MERGED
+ * This fixes a very old regression (2.49 was correct here) */
+ vmap = BKE_mesh_uv_vert_map_create(mpoly, mloop, mloopuv, totface, totvert, limit, false, true);
if (!vmap)
return 0;
@@ -2041,7 +2045,7 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
ccgdm_pbvh_update(ccgdm);
if (ccgdm->pbvh && ccgdm->multires.mmd && !fast) {
- if (dm->numTessFaceData) {
+ if (BKE_pbvh_has_faces(ccgdm->pbvh)) {
BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL,
setMaterial, false);
glShadeModel(GL_FLAT);
@@ -3105,7 +3109,6 @@ static void ccgDM_release(DerivedMesh *dm)
if (ccgdm->reverseFaceMap) MEM_freeN(ccgdm->reverseFaceMap);
if (ccgdm->gridFaces) MEM_freeN(ccgdm->gridFaces);
if (ccgdm->gridData) MEM_freeN(ccgdm->gridData);
- if (ccgdm->gridAdjacency) MEM_freeN(ccgdm->gridAdjacency);
if (ccgdm->gridOffset) MEM_freeN(ccgdm->gridOffset);
if (ccgdm->gridFlagMats) MEM_freeN(ccgdm->gridFlagMats);
if (ccgdm->gridHidden) {
@@ -3416,46 +3419,11 @@ static int ccgDM_getGridSize(DerivedMesh *dm)
return ccgSubSurf_getGridSize(ccgdm->ss);
}
-static int ccgdm_adjacent_grid(int *gridOffset, CCGFace *f, int S, int offset)
-{
- CCGFace *adjf;
- CCGEdge *e;
- int i, j = 0, numFaces, fIndex, numEdges = 0;
-
- e = ccgSubSurf_getFaceEdge(f, S);
- numFaces = ccgSubSurf_getEdgeNumFaces(e);
-
- if (numFaces != 2)
- return -1;
-
- for (i = 0; i < numFaces; i++) {
- adjf = ccgSubSurf_getEdgeFace(e, i);
-
- if (adjf != f) {
- numEdges = ccgSubSurf_getFaceNumVerts(adjf);
- for (j = 0; j < numEdges; j++)
- if (ccgSubSurf_getFaceEdge(adjf, j) == e)
- break;
-
- if (j != numEdges)
- break;
- }
- }
-
- if (numEdges == 0)
- return -1;
-
- fIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(adjf));
-
- return gridOffset[fIndex] + (j + offset) % numEdges;
-}
-
static void ccgdm_create_grids(DerivedMesh *dm)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
CCGSubSurf *ss = ccgdm->ss;
CCGElem **gridData;
- DMGridAdjacency *gridAdjacency, *adj;
DMFlagMat *gridFlagMats;
CCGFace **gridFaces;
int *gridOffset;
@@ -3481,7 +3449,6 @@ static void ccgdm_create_grids(DerivedMesh *dm)
/* compute grid data */
gridData = MEM_mallocN(sizeof(CCGElem *) * numGrids, "ccgdm.gridData");
- gridAdjacency = MEM_mallocN(sizeof(DMGridAdjacency) * numGrids, "ccgdm.gridAdjacency");
gridFaces = MEM_mallocN(sizeof(CCGFace *) * numGrids, "ccgdm.gridFaces");
gridFlagMats = MEM_mallocN(sizeof(DMFlagMat) * numGrids, "ccgdm.gridFlagMats");
@@ -3492,29 +3459,14 @@ static void ccgdm_create_grids(DerivedMesh *dm)
int numVerts = ccgSubSurf_getFaceNumVerts(f);
for (S = 0; S < numVerts; S++, gIndex++) {
- int prevS = (S - 1 + numVerts) % numVerts;
- int nextS = (S + 1 + numVerts) % numVerts;
-
gridData[gIndex] = ccgSubSurf_getFaceGridDataArray(ss, f, S);
gridFaces[gIndex] = f;
gridFlagMats[gIndex] = ccgdm->faceFlags[index];
-
- adj = &gridAdjacency[gIndex];
-
- adj->index[0] = gIndex - S + nextS;
- adj->rotation[0] = 3;
- adj->index[1] = ccgdm_adjacent_grid(gridOffset, f, prevS, 0);
- adj->rotation[1] = 1;
- adj->index[2] = ccgdm_adjacent_grid(gridOffset, f, S, 1);
- adj->rotation[2] = 3;
- adj->index[3] = gIndex - S + prevS;
- adj->rotation[3] = 1;
}
}
ccgdm->gridData = gridData;
ccgdm->gridFaces = gridFaces;
- ccgdm->gridAdjacency = gridAdjacency;
ccgdm->gridOffset = gridOffset;
ccgdm->gridFlagMats = gridFlagMats;
}
@@ -3527,14 +3479,6 @@ static CCGElem **ccgDM_getGridData(DerivedMesh *dm)
return ccgdm->gridData;
}
-static DMGridAdjacency *ccgDM_getGridAdjacency(DerivedMesh *dm)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
-
- ccgdm_create_grids(dm);
- return ccgdm->gridAdjacency;
-}
-
static int *ccgDM_getGridOffset(DerivedMesh *dm)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
@@ -3617,7 +3561,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
* when the ccgdm gets remade, the assumption is that the topology
* does not change. */
ccgdm_create_grids(dm);
- BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, (void **)ccgdm->gridFaces,
+ BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, (void **)ccgdm->gridFaces,
ccgdm->gridFlagMats, ccgdm->gridHidden);
}
@@ -3636,7 +3580,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
numGrids = ccgDM_getNumGrids(dm);
ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new();
- BKE_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, ccgdm->gridAdjacency,
+ BKE_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData,
numGrids, &key, (void **) ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden);
}
else if (ob->type == OB_MESH) {
@@ -3764,7 +3708,6 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->dm.getNumGrids = ccgDM_getNumGrids;
ccgdm->dm.getGridSize = ccgDM_getGridSize;
ccgdm->dm.getGridData = ccgDM_getGridData;
- ccgdm->dm.getGridAdjacency = ccgDM_getGridAdjacency;
ccgdm->dm.getGridOffset = ccgDM_getGridOffset;
ccgdm->dm.getGridKey = ccgDM_getGridKey;
ccgdm->dm.getGridFlagMats = ccgDM_getGridFlagMats;
@@ -4131,7 +4074,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
SubsurfFlags flags)
{
int useSimple = (smd->subdivType == ME_SIMPLE_SUBSURF) ? CCG_SIMPLE_SUBDIV : 0;
- CCGFlags useAging = smd->flags & eSubsurfModifierFlag_DebugIncr ? CCG_USE_AGING : 0;
+ CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0;
int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv;
int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
CCGDerivedMesh *result;
@@ -4139,7 +4082,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
/* note: editmode calculation can only run once per
* modifier stack evaluation (uses freed cache) [#36299] */
if (flags & SUBSURF_FOR_EDIT_MODE) {
- int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels) : smd->levels;
+ int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels;
smd->emCache = _getSubSurf(smd->emCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS);
ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple);
@@ -4151,7 +4094,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
else if (flags & SUBSURF_USE_RENDER_PARAMS) {
/* Do not use cache in render mode. */
CCGSubSurf *ss;
- int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->renderLevels) : smd->renderLevels;
+ int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->renderLevels, true) : smd->renderLevels;
if (levels == 0)
return dm;
@@ -4167,7 +4110,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
}
else {
int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental);
- int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels) : smd->levels;
+ int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels;
CCGSubSurf *ss;
/* It is quite possible there is a much better place to do this. It
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 9f441b45db9..89456763b95 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -330,7 +330,7 @@ static void text_from_buf(Text *text, const unsigned char *buffer, const int len
text->curc = text->selc = 0;
}
-int BKE_text_reload(Text *text)
+bool BKE_text_reload(Text *text)
{
FILE *fp;
int len;
@@ -339,13 +339,24 @@ int BKE_text_reload(Text *text)
char str[FILE_MAX];
BLI_stat_t st;
- if (!text->name) return 0;
-
+ if (!text->name) {
+ return false;
+ }
+
BLI_strncpy(str, text->name, FILE_MAX);
BLI_path_abs(str, G.main->name);
fp = BLI_fopen(str, "r");
- if (fp == NULL) return 0;
+ if (fp == NULL) {
+ return false;
+ }
+ fseek(fp, 0L, SEEK_END);
+ len = ftell(fp);
+ fseek(fp, 0L, SEEK_SET);
+ if (UNLIKELY(len == -1)) {
+ fclose(fp);
+ return false;
+ }
/* free memory: */
@@ -363,11 +374,6 @@ int BKE_text_reload(Text *text)
MEM_freeN(text->undo_buf);
init_undo_text(text);
- fseek(fp, 0L, SEEK_END);
- len = ftell(fp);
- fseek(fp, 0L, SEEK_SET);
-
-
buffer = MEM_mallocN(len, "text_buffer");
/* under windows fread can return less than len bytes because
* of CR stripping */
@@ -385,7 +391,7 @@ int BKE_text_reload(Text *text)
text_from_buf(text, buffer, len);
MEM_freeN(buffer);
- return 1;
+ return true;
}
Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const bool is_internal)
@@ -402,8 +408,18 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
BLI_path_abs(str, relpath);
fp = BLI_fopen(str, "r");
- if (fp == NULL) return NULL;
-
+ if (fp == NULL) {
+ return NULL;
+ }
+
+ fseek(fp, 0L, SEEK_END);
+ len = ftell(fp);
+ fseek(fp, 0L, SEEK_SET);
+ if (UNLIKELY(len == -1)) {
+ fclose(fp);
+ return NULL;
+ }
+
ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(str));
ta->id.us = 1;
@@ -423,10 +439,6 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
/* clear undo buffer */
init_undo_text(ta);
-
- fseek(fp, 0L, SEEK_END);
- len = ftell(fp);
- fseek(fp, 0L, SEEK_SET);
buffer = MEM_mallocN(len, "text_buffer");
/* under windows fread can return less than len bytes because
@@ -473,6 +485,7 @@ Text *BKE_text_copy(Main *bmain, Text *ta)
BLI_listbase_clear(&tan->lines);
tan->curl = tan->sell = NULL;
+ tan->compiled = NULL;
tan->nlines = ta->nlines;
@@ -651,7 +664,7 @@ void BKE_text_unlink(Main *bmain, Text *text)
}
}
- /* Freestyle (while looping oer the scene) */
+ /* Freestyle (while looping over the scene) */
for (srl = sce->r.layers.first; srl; srl = srl->next) {
for (module = srl->freestyleConfig.modules.first; module; module = module->next) {
if (module->script == text)
@@ -1895,6 +1908,47 @@ static void txt_undo_add_charop(Text *text, int op_start, unsigned int c)
text->undo_buf[text->undo_pos + 1] = 0;
}
+/* extends Link */
+struct LinkInt {
+ struct LinkInt *next, *prev;
+ int value;
+};
+
+/* unindentLines points to a ListBase composed of LinkInt elements, listing the numbers
+ * of the lines that should not be indented back. */
+static void txt_undo_add_unindent_op(Text *text, const ListBase *line_index_mask, const int line_index_mask_len)
+{
+ struct LinkInt *idata;
+
+ BLI_assert(BLI_listbase_count(line_index_mask) == line_index_mask_len);
+
+ /* OP byte + UInt32 count + counted UInt32 line numbers + UInt32 count + 12-bytes selection + OP byte */
+ if (!max_undo_test(text, 1 + 4 + (line_index_mask_len * 4) + 4 + 12 + 1)) {
+ return;
+ }
+
+ /* Opening buffer sequence with OP */
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos] = UNDO_UNINDENT;
+ text->undo_pos++;
+ /* Adding number of line numbers to read */
+ txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len);
+
+ /* Adding linenumbers of lines that shall not be indented if undoing */
+ for (idata = line_index_mask->first; idata; idata = idata->next) {
+ txt_undo_store_uint32(text->undo_buf, &text->undo_pos, idata->value);
+ }
+
+ /* Adding number of line numbers to read again */
+ txt_undo_store_uint32(text->undo_buf, &text->undo_pos, line_index_mask_len);
+ /* Adding current selection */
+ txt_undo_store_cursors(text);
+ /* Closing with OP (same as above) */
+ text->undo_buf[text->undo_pos] = UNDO_UNINDENT;
+ /* Marking as last undo operation */
+ text->undo_buf[text->undo_pos + 1] = 0;
+}
+
static unsigned short txt_undo_read_uint16(const char *undo_buf, int *undo_pos)
{
unsigned short val;
@@ -2189,7 +2243,6 @@ void txt_do_undo(Text *text)
text->undo_pos--;
break;
case UNDO_INDENT:
- case UNDO_UNINDENT:
case UNDO_COMMENT:
case UNDO_UNCOMMENT:
case UNDO_DUPLICATE:
@@ -2203,9 +2256,6 @@ void txt_do_undo(Text *text)
if (op == UNDO_INDENT) {
txt_unindent(text);
}
- else if (op == UNDO_UNINDENT) {
- txt_indent(text);
- }
else if (op == UNDO_COMMENT) {
txt_uncomment(text);
}
@@ -2224,6 +2274,37 @@ void txt_do_undo(Text *text)
text->undo_pos--;
break;
+ case UNDO_UNINDENT:
+ {
+ int count;
+ int i;
+ /* Get and restore the cursors */
+ txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+
+ /* Un-unindent */
+ txt_indent(text);
+
+ /* Get the count */
+ count = txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
+ /* Iterate! */
+ txt_pop_sel(text);
+
+ for (i = 0; i < count; i++) {
+ txt_move_to(text, txt_undo_read_uint32(text->undo_buf, &text->undo_pos), 0, 0);
+ /* Un-un-unindent */
+ txt_unindent(text);
+ }
+ /* Restore selection */
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+ /* Jumo over count */
+ txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
+ /* Jump over closing OP byte */
+ text->undo_pos--;
+ break;
+ }
default:
//XXX error("Undo buffer error - resetting");
text->undo_pos = -1;
@@ -2353,7 +2434,6 @@ void txt_do_redo(Text *text)
break;
case UNDO_INDENT:
- case UNDO_UNINDENT:
case UNDO_COMMENT:
case UNDO_UNCOMMENT:
case UNDO_DUPLICATE:
@@ -2369,9 +2449,6 @@ void txt_do_redo(Text *text)
if (op == UNDO_INDENT) {
txt_indent(text);
}
- else if (op == UNDO_UNINDENT) {
- txt_unindent(text);
- }
else if (op == UNDO_COMMENT) {
txt_comment(text);
}
@@ -2401,6 +2478,26 @@ void txt_do_redo(Text *text)
txt_move_to(text, selln, selc, 1);
break;
+ case UNDO_UNINDENT:
+ {
+ int count;
+ int i;
+
+ text->undo_pos++;
+ /* Scan all the stuff described in txt_undo_add_unindent_op */
+ count = txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
+ for (i = 0; i < count; i++) {
+ txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
+ }
+ /* Count again */
+ txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
+ /* Get the selection and re-unindent */
+ txt_redo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+ txt_unindent(text);
+ break;
+ }
default:
//XXX error("Undo buffer error - resetting");
text->undo_pos = -1;
@@ -2801,6 +2898,12 @@ void txt_unindent(Text *text)
int indentlen = 1;
bool unindented_first = false;
+ /* List of lines that are already at indent level 0, to store them later into the undo buffer */
+ ListBase line_index_mask = {NULL, NULL};
+ int line_index_mask_len = 0;
+ int curl_span_init = 0;
+
+
/* hardcoded: TXT_TABSIZE = 4 spaces: */
int spaceslen = TXT_TABSIZE;
@@ -2814,6 +2917,10 @@ void txt_unindent(Text *text)
indentlen = spaceslen;
}
+ if (!undoing) {
+ curl_span_init = txt_get_span(text->lines.first, text->curl);
+ }
+
while (true) {
bool changed = false;
if (STREQLEN(text->curl->line, remove, indentlen)) {
@@ -2823,6 +2930,16 @@ void txt_unindent(Text *text)
memmove(text->curl->line, text->curl->line + indentlen, text->curl->len + 1);
changed = true;
}
+ else {
+ if (!undoing) {
+ /* Create list element for 0 indent line */
+ struct LinkInt *idata = MEM_mallocN(sizeof(struct LinkInt), __func__);
+ idata->value = curl_span_init + num;
+ BLI_assert(idata->value == txt_get_span(text->lines.first, text->curl));
+ BLI_addtail(&line_index_mask, idata);
+ line_index_mask_len += 1;
+ }
+ }
txt_make_dirty(text);
txt_clean_text(text);
@@ -2835,6 +2952,7 @@ void txt_unindent(Text *text)
else {
text->curl = text->curl->next;
num++;
+
}
}
@@ -2848,8 +2966,10 @@ void txt_unindent(Text *text)
}
if (!undoing) {
- txt_undo_add_op(text, UNDO_UNINDENT);
+ txt_undo_add_unindent_op(text, &line_index_mask, line_index_mask_len);
}
+
+ BLI_freelistN(&line_index_mask);
}
void txt_comment(Text *text)
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 3293cca76fe..88a412d5e95 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -73,16 +73,16 @@
/* ****************** Mapping ******************* */
-TexMapping *add_tex_mapping(int type)
+TexMapping *BKE_texture_mapping_add(int type)
{
TexMapping *texmap = MEM_callocN(sizeof(TexMapping), "TexMapping");
- default_tex_mapping(texmap, type);
+ BKE_texture_mapping_default(texmap, type);
return texmap;
}
-void default_tex_mapping(TexMapping *texmap, int type)
+void BKE_texture_mapping_default(TexMapping *texmap, int type)
{
memset(texmap, 0, sizeof(TexMapping));
@@ -97,7 +97,7 @@ void default_tex_mapping(TexMapping *texmap, int type)
texmap->type = type;
}
-void init_tex_mapping(TexMapping *texmap)
+void BKE_texture_mapping_init(TexMapping *texmap)
{
float smat[4][4], rmat[4][4], tmat[4][4], proj[4][4], size[3];
@@ -170,16 +170,16 @@ void init_tex_mapping(TexMapping *texmap)
}
}
-ColorMapping *add_color_mapping(void)
+ColorMapping *BKE_texture_colormapping_add(void)
{
ColorMapping *colormap = MEM_callocN(sizeof(ColorMapping), "ColorMapping");
- default_color_mapping(colormap);
+ BKE_texture_colormapping_default(colormap);
return colormap;
}
-void default_color_mapping(ColorMapping *colormap)
+void BKE_texture_colormapping_default(ColorMapping *colormap)
{
memset(colormap, 0, sizeof(ColorMapping));
@@ -560,14 +560,14 @@ int colorband_element_remove(struct ColorBand *coba, int index)
void BKE_texture_free(Tex *tex)
{
if (tex->coba) MEM_freeN(tex->coba);
- if (tex->env) BKE_free_envmap(tex->env);
- if (tex->pd) BKE_free_pointdensity(tex->pd);
- if (tex->vd) BKE_free_voxeldata(tex->vd);
- if (tex->ot) BKE_free_oceantex(tex->ot);
- BKE_free_animdata((struct ID *)tex);
+ if (tex->env) BKE_texture_envmap_free(tex->env);
+ if (tex->pd) BKE_texture_pointdensity_free(tex->pd);
+ if (tex->vd) BKE_texture_voxeldata_free(tex->vd);
+ if (tex->ot) BKE_texture_ocean_free(tex->ot);
+ BKE_animdata_free((struct ID *)tex);
BKE_previewimg_free(&tex->preview);
- BKE_icon_delete((struct ID *)tex);
+ BKE_icon_id_delete((struct ID *)tex);
tex->id.icon_id = 0;
if (tex->nodetree) {
@@ -578,7 +578,7 @@ void BKE_texture_free(Tex *tex)
/* ------------------------------------------------------------------------- */
-void default_tex(Tex *tex)
+void BKE_texture_default(Tex *tex)
{
tex->type = TEX_IMAGE;
tex->ima = NULL;
@@ -629,7 +629,7 @@ void default_tex(Tex *tex)
tex->env->stype = ENV_ANIM;
tex->env->clipsta = 0.1;
tex->env->clipend = 100;
- tex->env->cuberes = 600;
+ tex->env->cuberes = 512;
tex->env->depth = 0;
}
@@ -657,25 +657,25 @@ void default_tex(Tex *tex)
tex->preview = NULL;
}
-void tex_set_type(Tex *tex, int type)
+void BKE_texture_type_set(Tex *tex, int type)
{
switch (type) {
case TEX_VOXELDATA:
if (tex->vd == NULL)
- tex->vd = BKE_add_voxeldata();
+ tex->vd = BKE_texture_voxeldata_add();
break;
case TEX_POINTDENSITY:
if (tex->pd == NULL)
- tex->pd = BKE_add_pointdensity();
+ tex->pd = BKE_texture_pointdensity_add();
break;
case TEX_ENVMAP:
if (tex->env == NULL)
- tex->env = BKE_add_envmap();
+ tex->env = BKE_texture_envmap_add();
break;
case TEX_OCEAN:
if (tex->ot == NULL)
- tex->ot = BKE_add_oceantex();
+ tex->ot = BKE_texture_ocean_add();
break;
}
@@ -684,20 +684,20 @@ void tex_set_type(Tex *tex, int type)
/* ------------------------------------------------------------------------- */
-Tex *add_texture(Main *bmain, const char *name)
+Tex *BKE_texture_add(Main *bmain, const char *name)
{
Tex *tex;
tex = BKE_libblock_alloc(bmain, ID_TE, name);
- default_tex(tex);
+ BKE_texture_default(tex);
return tex;
}
/* ------------------------------------------------------------------------- */
-void default_mtex(MTex *mtex)
+void BKE_texture_mtex_default(MTex *mtex)
{
mtex->texco = TEXCO_UV;
mtex->mapto = MAP_COL;
@@ -767,19 +767,19 @@ void default_mtex(MTex *mtex)
/* ------------------------------------------------------------------------- */
-MTex *add_mtex(void)
+MTex *BKE_texture_mtex_add(void)
{
MTex *mtex;
- mtex = MEM_callocN(sizeof(MTex), "add_mtex");
+ mtex = MEM_callocN(sizeof(MTex), "BKE_texture_mtex_add");
- default_mtex(mtex);
+ BKE_texture_mtex_default(mtex);
return mtex;
}
/* slot -1 for first free ID */
-MTex *add_mtex_id(ID *id, int slot)
+MTex *BKE_texture_mtex_add_id(ID *id, int slot)
{
MTex **mtex_ar;
short act;
@@ -820,7 +820,7 @@ MTex *add_mtex_id(ID *id, int slot)
((Material *)id)->septex &= ~(1 << slot);
}
- mtex_ar[slot] = add_mtex();
+ mtex_ar[slot] = BKE_texture_mtex_add();
return mtex_ar[slot];
}
@@ -840,10 +840,10 @@ Tex *BKE_texture_copy(Tex *tex)
}
if (texn->coba) texn->coba = MEM_dupallocN(texn->coba);
- if (texn->env) texn->env = BKE_copy_envmap(texn->env);
- if (texn->pd) texn->pd = BKE_copy_pointdensity(texn->pd);
+ if (texn->env) texn->env = BKE_texture_envmap_copy(texn->env);
+ 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_copy_oceantex(texn->ot);
+ if (texn->ot) texn->ot = BKE_texture_ocean_copy(texn->ot);
if (tex->preview) texn->preview = BKE_previewimg_copy(tex->preview);
if (tex->nodetree) {
@@ -861,7 +861,7 @@ Tex *BKE_texture_copy(Tex *tex)
}
/* texture copy without adding to main dbase */
-Tex *localize_texture(Tex *tex)
+Tex *BKE_texture_localize(Tex *tex)
{
Tex *texn;
@@ -871,17 +871,17 @@ Tex *localize_texture(Tex *tex)
if (texn->coba) texn->coba = MEM_dupallocN(texn->coba);
if (texn->env) {
- texn->env = BKE_copy_envmap(texn->env);
+ texn->env = BKE_texture_envmap_copy(texn->env);
id_us_min(&texn->env->ima->id);
}
- if (texn->pd) texn->pd = BKE_copy_pointdensity(texn->pd);
+ if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd);
if (texn->vd) {
texn->vd = MEM_dupallocN(texn->vd);
if (texn->vd->dataset)
texn->vd->dataset = MEM_dupallocN(texn->vd->dataset);
}
if (texn->ot) {
- texn->ot = BKE_copy_oceantex(tex->ot);
+ texn->ot = BKE_texture_ocean_copy(tex->ot);
}
texn->preview = NULL;
@@ -1132,7 +1132,7 @@ void set_current_lamp_texture(Lamp *la, Tex *newtex)
if (newtex) {
if (!la->mtex[act]) {
- la->mtex[act] = add_mtex();
+ la->mtex[act] = BKE_texture_mtex_add();
la->mtex[act]->texco = TEXCO_GLOB;
}
@@ -1167,7 +1167,7 @@ void set_current_linestyle_texture(FreestyleLineStyle *linestyle, Tex *newtex)
if (newtex) {
if (!linestyle->mtex[act]) {
- linestyle->mtex[act] = add_mtex();
+ linestyle->mtex[act] = BKE_texture_mtex_add();
linestyle->mtex[act]->texco = TEXCO_STROKE;
}
@@ -1296,7 +1296,7 @@ void set_current_material_texture(Material *ma, Tex *newtex)
if (newtex) {
if (!ma->mtex[act]) {
- ma->mtex[act] = add_mtex();
+ ma->mtex[act] = BKE_texture_mtex_add();
/* Reset this slot's ON/OFF toggle, for materials, when slot was empty. */
ma->septex &= ~(1 << act);
}
@@ -1347,7 +1347,7 @@ void set_current_world_texture(World *wo, Tex *newtex)
if (newtex) {
if (!wo->mtex[act]) {
- wo->mtex[act] = add_mtex();
+ wo->mtex[act] = BKE_texture_mtex_add();
wo->mtex[act]->texco = TEXCO_VIEW;
}
@@ -1398,7 +1398,7 @@ void set_current_particle_texture(ParticleSettings *part, Tex *newtex)
if (newtex) {
if (!part->mtex[act]) {
- part->mtex[act] = add_mtex();
+ part->mtex[act] = BKE_texture_mtex_add();
part->mtex[act]->texco = TEXCO_ORCO;
part->mtex[act]->blendtype = MTEX_MUL;
}
@@ -1414,7 +1414,7 @@ void set_current_particle_texture(ParticleSettings *part, Tex *newtex)
/* ------------------------------------------------------------------------- */
-EnvMap *BKE_add_envmap(void)
+EnvMap *BKE_texture_envmap_add(void)
{
EnvMap *env;
@@ -1423,7 +1423,7 @@ EnvMap *BKE_add_envmap(void)
env->stype = ENV_ANIM;
env->clipsta = 0.1;
env->clipend = 100.0;
- env->cuberes = 600;
+ env->cuberes = 512;
env->viewscale = 0.5;
return env;
@@ -1431,7 +1431,7 @@ EnvMap *BKE_add_envmap(void)
/* ------------------------------------------------------------------------- */
-EnvMap *BKE_copy_envmap(EnvMap *env)
+EnvMap *BKE_texture_envmap_copy(EnvMap *env)
{
EnvMap *envn;
int a;
@@ -1446,7 +1446,7 @@ EnvMap *BKE_copy_envmap(EnvMap *env)
/* ------------------------------------------------------------------------- */
-void BKE_free_envmapdata(EnvMap *env)
+void BKE_texture_envmap_free_data(EnvMap *env)
{
unsigned int part;
@@ -1460,21 +1460,18 @@ void BKE_free_envmapdata(EnvMap *env)
/* ------------------------------------------------------------------------- */
-void BKE_free_envmap(EnvMap *env)
+void BKE_texture_envmap_free(EnvMap *env)
{
- BKE_free_envmapdata(env);
+ BKE_texture_envmap_free_data(env);
MEM_freeN(env);
}
/* ------------------------------------------------------------------------- */
-PointDensity *BKE_add_pointdensity(void)
+void BKE_texture_pointdensity_init_data(PointDensity *pd)
{
- PointDensity *pd;
-
- pd = MEM_callocN(sizeof(PointDensity), "pointdensity");
pd->flag = 0;
pd->radius = 0.3f;
pd->falloff_type = TEX_PD_FALLOFF_STD;
@@ -1498,11 +1495,16 @@ PointDensity *BKE_add_pointdensity(void)
pd->falloff_curve->cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
curvemap_reset(pd->falloff_curve->cm, &pd->falloff_curve->clipr, pd->falloff_curve->preset, CURVEMAP_SLOPE_POSITIVE);
curvemapping_changed(pd->falloff_curve, false);
+}
+PointDensity *BKE_texture_pointdensity_add(void)
+{
+ PointDensity *pd = MEM_callocN(sizeof(PointDensity), "pointdensity");
+ BKE_texture_pointdensity_init_data(pd);
return pd;
}
-PointDensity *BKE_copy_pointdensity(PointDensity *pd)
+PointDensity *BKE_texture_pointdensity_copy(PointDensity *pd)
{
PointDensity *pdn;
@@ -1514,7 +1516,7 @@ PointDensity *BKE_copy_pointdensity(PointDensity *pd)
return pdn;
}
-void BKE_free_pointdensitydata(PointDensity *pd)
+void BKE_texture_pointdensity_free_data(PointDensity *pd)
{
if (pd->point_tree) {
BLI_bvhtree_free(pd->point_tree);
@@ -1532,15 +1534,15 @@ void BKE_free_pointdensitydata(PointDensity *pd)
curvemapping_free(pd->falloff_curve); /* can be NULL */
}
-void BKE_free_pointdensity(PointDensity *pd)
+void BKE_texture_pointdensity_free(PointDensity *pd)
{
- BKE_free_pointdensitydata(pd);
+ BKE_texture_pointdensity_free_data(pd);
MEM_freeN(pd);
}
/* ------------------------------------------------------------------------- */
-void BKE_free_voxeldatadata(VoxelData *vd)
+void BKE_texture_voxeldata_free_data(VoxelData *vd)
{
if (vd->dataset) {
MEM_freeN(vd->dataset);
@@ -1549,13 +1551,13 @@ void BKE_free_voxeldatadata(VoxelData *vd)
}
-void BKE_free_voxeldata(VoxelData *vd)
+void BKE_texture_voxeldata_free(VoxelData *vd)
{
- BKE_free_voxeldatadata(vd);
+ BKE_texture_voxeldata_free_data(vd);
MEM_freeN(vd);
}
-VoxelData *BKE_add_voxeldata(void)
+VoxelData *BKE_texture_voxeldata_add(void)
{
VoxelData *vd;
@@ -1573,7 +1575,7 @@ VoxelData *BKE_add_voxeldata(void)
return vd;
}
-VoxelData *BKE_copy_voxeldata(VoxelData *vd)
+VoxelData *BKE_texture_voxeldata_copy(VoxelData *vd)
{
VoxelData *vdn;
@@ -1585,7 +1587,7 @@ VoxelData *BKE_copy_voxeldata(VoxelData *vd)
/* ------------------------------------------------------------------------- */
-OceanTex *BKE_add_oceantex(void)
+OceanTex *BKE_texture_ocean_add(void)
{
OceanTex *ot;
@@ -1596,14 +1598,14 @@ OceanTex *BKE_add_oceantex(void)
return ot;
}
-OceanTex *BKE_copy_oceantex(struct OceanTex *ot)
+OceanTex *BKE_texture_ocean_copy(struct OceanTex *ot)
{
OceanTex *otn = MEM_dupallocN(ot);
return otn;
}
-void BKE_free_oceantex(struct OceanTex *ot)
+void BKE_texture_ocean_free(struct OceanTex *ot)
{
MEM_freeN(ot);
}
@@ -1651,7 +1653,9 @@ bool BKE_texture_dependsOnTime(const struct Tex *texture)
/* ------------------------------------------------------------------------- */
-void BKE_texture_get_value(Scene *scene, Tex *texture, float *tex_co, TexResult *texres, bool use_color_management)
+void BKE_texture_get_value(
+ const Scene *scene, Tex *texture,
+ float *tex_co, TexResult *texres, bool use_color_management)
{
int result_type;
bool do_color_manage = false;
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 0037002f6d8..f9ae987db70 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -547,7 +547,7 @@ bool BKE_tracking_track_has_enabled_marker_at_frame(MovieTrackingTrack *track, i
* - If action is TRACK_CLEAR_UPTO path from the beginning up to
* ref_frame-1 will be clear.
*
- * - If action is TRACK_CLEAR_ALL only mareker at frame ref_frame will remain.
+ * - If action is TRACK_CLEAR_ALL only marker at frame ref_frame will remain.
*
* NOTE: frame number should be in clip space, not scene space
*/
@@ -730,7 +730,7 @@ MovieTrackingTrack *BKE_tracking_track_get_named(MovieTracking *tracking, MovieT
return NULL;
}
-MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int tracknr, ListBase **tracksbase_r)
+MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int tracknr, ListBase **r_tracksbase)
{
MovieTrackingObject *object;
int cur = 1;
@@ -743,7 +743,7 @@ MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int
while (track) {
if (track->flag & TRACK_HAS_BUNDLE) {
if (cur == tracknr) {
- *tracksbase_r = tracksbase;
+ *r_tracksbase = tracksbase;
return track;
}
@@ -756,7 +756,7 @@ MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int
object = object->next;
}
- *tracksbase_r = NULL;
+ *r_tracksbase = NULL;
return NULL;
}
@@ -1302,6 +1302,95 @@ void BKE_tracking_plane_tracks_deselect_all(ListBase *plane_tracks_base)
}
}
+bool BKE_tracking_plane_track_has_point_track(MovieTrackingPlaneTrack *plane_track,
+ MovieTrackingTrack *track)
+{
+ int i;
+ for (i = 0; i < plane_track->point_tracksnr; i++) {
+ if (plane_track->point_tracks[i] == track) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BKE_tracking_plane_track_remove_point_track(MovieTrackingPlaneTrack *plane_track,
+ MovieTrackingTrack *track)
+{
+ int i, track_index;
+ MovieTrackingTrack **new_point_tracks;
+
+ if (plane_track->point_tracksnr <= 4) {
+ return false;
+ }
+
+ new_point_tracks = MEM_mallocN(sizeof(*new_point_tracks) * (plane_track->point_tracksnr - 1),
+ "new point tracks array");
+
+ for (i = 0, track_index = 0; i < plane_track->point_tracksnr; i++) {
+ if (plane_track->point_tracks[i] != track) {
+ new_point_tracks[track_index++] = plane_track->point_tracks[i];
+ }
+ }
+
+ MEM_freeN(plane_track->point_tracks);
+ plane_track->point_tracks = new_point_tracks;
+ plane_track->point_tracksnr--;
+
+ return true;
+}
+
+void BKE_tracking_plane_tracks_remove_point_track(MovieTracking *tracking,
+ MovieTrackingTrack *track)
+{
+ MovieTrackingPlaneTrack *plane_track, *next_plane_track;
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = next_plane_track)
+ {
+ next_plane_track = plane_track->next;
+ if (BKE_tracking_plane_track_has_point_track(plane_track, track)) {
+ if (!BKE_tracking_plane_track_remove_point_track(plane_track, track)) {
+ /* Delete planes with less than 3 point tracks in it. */
+ BKE_tracking_plane_track_free(plane_track);
+ BLI_freelinkN(plane_tracks_base, plane_track);
+ }
+ }
+ }
+}
+
+void BKE_tracking_plane_track_replace_point_track(MovieTrackingPlaneTrack *plane_track,
+ MovieTrackingTrack *old_track,
+ MovieTrackingTrack *new_track)
+{
+ int i;
+ for (i = 0; i < plane_track->point_tracksnr; i++) {
+ if (plane_track->point_tracks[i] == old_track) {
+ plane_track->point_tracks[i] = new_track;
+ break;
+ }
+ }
+}
+
+void BKE_tracking_plane_tracks_replace_point_track(MovieTracking *tracking,
+ MovieTrackingTrack *old_track,
+ MovieTrackingTrack *new_track)
+{
+ MovieTrackingPlaneTrack *plane_track;
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ if (BKE_tracking_plane_track_has_point_track(plane_track, old_track)) {
+ BKE_tracking_plane_track_replace_point_track(plane_track,
+ old_track,
+ new_track);
+ }
+ }
+}
+
/*********************** Plane Marker *************************/
MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(MovieTrackingPlaneTrack *plane_track,
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index 4cb3f2ca493..76261bddfbc 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -534,19 +534,9 @@ void BKE_autotrack_context_finish(AutoTrackContext *context)
if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
int track;
for (track = 0; track < context->num_tracks; ++track) {
- MovieTrackingTrack *old_track;
- bool do_update = false;
- int j;
-
- old_track = context->options[track].track;
- for (j = 0; j < plane_track->point_tracksnr; j++) {
- if (plane_track->point_tracks[j] == old_track) {
- do_update = true;
- break;
- }
- }
-
- if (do_update) {
+ if (BKE_tracking_plane_track_has_point_track(plane_track,
+ context->options[track].track))
+ {
BKE_tracking_track_plane_from_existing_motion(
plane_track,
context->first_frame);
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index 882a6fabef1..56119b732fc 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -423,6 +423,7 @@ void tracking_cameraIntrinscisOptionsFromTracking(MovieTracking *tracking,
break;
default:
BLI_assert(!"Unknown distortion model");
+ break;
}
camera_intrinsics_options->image_width = calibration_width;
@@ -454,6 +455,7 @@ void tracking_trackingCameraFromIntrinscisOptions(MovieTracking *tracking,
break;
default:
BLI_assert(!"Unknown distortion model");
+ break;
}
}
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 5a2c77b5619..0d83695d2f1 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -370,12 +370,7 @@ static size_t unit_as_string(char *str, int len_max, double value, int prec, bUn
value_conv = value / unit->scalar;
/* Convert to a string */
- {
- len = BLI_snprintf(str, len_max, "%.*f", prec, value_conv);
-
- if (len >= len_max)
- len = len_max;
- }
+ len = BLI_snprintf_rlen(str, len_max, "%.*f", prec, value_conv);
/* Add unit prefix and strip zeros */
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 699e0d34161..e4736b1f54c 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -63,7 +63,7 @@ void BKE_world_free_ex(World *wrld, bool do_id_user)
}
BKE_previewimg_free(&wrld->preview);
- BKE_free_animdata((ID *)wrld);
+ BKE_animdata_free((ID *)wrld);
/* is no lib link block, but world extension */
if (wrld->nodetree) {
@@ -74,7 +74,7 @@ void BKE_world_free_ex(World *wrld, bool do_id_user)
if (wrld->gpumaterial.first)
GPU_material_free(&wrld->gpumaterial);
- BKE_icon_delete((struct ID *)wrld);
+ BKE_icon_id_delete((struct ID *)wrld);
wrld->id.icon_id = 0;
}
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index 85eac1f21ed..cec455e01b9 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -50,26 +50,34 @@
/* ********************** general blender movie support ***************************** */
-static int start_stub(Scene *UNUSED(scene), RenderData *UNUSED(rd), int UNUSED(rectx), int UNUSED(recty),
- ReportList *UNUSED(reports))
+static int start_stub(void *UNUSED(context_v), Scene *UNUSED(scene), RenderData *UNUSED(rd), int UNUSED(rectx), int UNUSED(recty),
+ ReportList *UNUSED(reports), bool UNUSED(preview), const char *UNUSED(suffix))
{ return 0; }
-static void end_stub(void)
+static void end_stub(void *UNUSED(context_v))
{}
-static int append_stub(RenderData *UNUSED(rd), int UNUSED(start_frame), int UNUSED(frame), int *UNUSED(pixels),
- int UNUSED(rectx), int UNUSED(recty), ReportList *UNUSED(reports))
+static int append_stub(void *UNUSED(context_v), RenderData *UNUSED(rd), int UNUSED(start_frame), int UNUSED(frame), int *UNUSED(pixels),
+ int UNUSED(rectx), int UNUSED(recty), const char *UNUSED(suffix), ReportList *UNUSED(reports))
{ return 0; }
+static void *context_create_stub(void)
+{ return NULL; }
+
+static void context_free_stub(void *UNUSED(context_v))
+{}
+
#ifdef WITH_AVI
# include "AVI_avi.h"
/* callbacks */
-static int start_avi(Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports);
-static void end_avi(void);
-static int append_avi(RenderData *rd, int start_frame, int frame, int *pixels,
- int rectx, int recty, ReportList *reports);
-static void filepath_avi(char *string, RenderData *rd);
+static int start_avi(void *context_v, Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports, bool preview, const char *suffix);
+static void end_avi(void *context_v);
+static int append_avi(void *context_v, RenderData *rd, int start_frame, int frame, int *pixels,
+ int rectx, int recty, const char *suffix, ReportList *reports);
+static void filepath_avi(char *string, RenderData *rd, bool preview, const char *suffix);
+static void *context_create_avi(void);
+static void context_free_avi(void *context_v);
#endif /* WITH_AVI */
#ifdef WITH_QUICKTIME
@@ -93,13 +101,17 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.end_movie = end_stub;
mh.get_next_frame = NULL;
mh.get_movie_path = NULL;
-
+ mh.context_create = context_create_stub;
+ mh.context_free = context_free_stub;
+
/* set the default handle, as builtin */
#ifdef WITH_AVI
mh.start_movie = start_avi;
mh.append_movie = append_avi;
mh.end_movie = end_avi;
mh.get_movie_path = filepath_avi;
+ mh.context_create = context_create_avi;
+ mh.context_free = context_free_avi;
#endif
/* do the platform specific handles */
@@ -109,6 +121,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.append_movie = append_qt;
mh.end_movie = end_qt;
mh.get_movie_path = filepath_qt;
+ mh.context_create = context_create_qt;
+ mh.context_free = context_free_qt;
}
#endif
#ifdef WITH_FFMPEG
@@ -117,6 +131,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.append_movie = BKE_ffmpeg_append;
mh.end_movie = BKE_ffmpeg_end;
mh.get_movie_path = BKE_ffmpeg_filepath_get;
+ mh.context_create = BKE_ffmpeg_context_create;
+ mh.context_free = BKE_ffmpeg_context_free;
}
#endif
#ifdef WITH_FRAMESERVER
@@ -125,13 +141,13 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.append_movie = BKE_frameserver_append;
mh.end_movie = BKE_frameserver_end;
mh.get_next_frame = BKE_frameserver_loop;
+ mh.context_create = BKE_frameserver_context_create;
+ mh.context_free = BKE_frameserver_context_free;
}
#endif
/* in case all above are disabled */
- (void)imtype;
-
- return &mh;
+ (void)imtype;return &mh;
}
/* ****************************************************************** */
@@ -139,12 +155,21 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
#ifdef WITH_AVI
-static AviMovie *avi = NULL;
-
-static void filepath_avi(char *string, RenderData *rd)
+static void filepath_avi(char *string, RenderData *rd, bool preview, const char *suffix)
{
+ int sfra, efra;
+
if (string == NULL) return;
+ if (preview) {
+ sfra = rd->psfra;
+ efra = rd->pefra;
+ }
+ else {
+ sfra = rd->sfra;
+ efra = rd->efra;
+ }
+
strcpy(string, rd->pic);
BLI_path_abs(string, G.main->name);
@@ -152,36 +177,36 @@ static void filepath_avi(char *string, RenderData *rd)
if (rd->scemode & R_EXTENSION) {
if (!BLI_testextensie(string, ".avi")) {
- BLI_path_frame_range(string, rd->sfra, rd->efra, 4);
+ BLI_path_frame_range(string, sfra, efra, 4);
strcat(string, ".avi");
}
}
else {
if (BLI_path_frame_check_chars(string)) {
- BLI_path_frame_range(string, rd->sfra, rd->efra, 4);
+ BLI_path_frame_range(string, sfra, efra, 4);
}
}
+
+ BLI_path_suffix(string, FILE_MAX, suffix, "");
}
-static int start_avi(Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports)
+static int start_avi(void *context_v, Scene *UNUSED(scene), RenderData *rd, int rectx, int recty,
+ ReportList *reports, bool preview, const char *suffix)
{
int x, y;
char name[256];
AviFormat format;
int quality;
double framerate;
-
- (void)scene; /* unused */
-
- filepath_avi(name, rd);
+ AviMovie *avi = context_v;
+
+ filepath_avi(name, rd, preview, suffix);
x = rectx;
y = recty;
quality = rd->im_format.quality;
framerate = (double) rd->frs_sec / (double) rd->frs_sec_base;
-
- avi = MEM_mallocN(sizeof(AviMovie), "avimovie");
if (rd->im_format.imtype != R_IMF_IMTYPE_AVIJPEG) format = AVI_FORMAT_AVI_RGB;
else format = AVI_FORMAT_MJPEG;
@@ -207,12 +232,13 @@ static int start_avi(Scene *scene, RenderData *rd, int rectx, int recty, ReportL
return 1;
}
-static int append_avi(RenderData *UNUSED(rd), int start_frame, int frame, int *pixels,
- int rectx, int recty, ReportList *UNUSED(reports))
+static int append_avi(void *context_v, RenderData *UNUSED(rd), int start_frame, int frame, int *pixels,
+ int rectx, int recty, const char *UNUSED(suffix), ReportList *UNUSED(reports))
{
unsigned int *rt1, *rt2, *rectot;
int x, y;
char *cp, rt;
+ AviMovie *avi = context_v;
if (avi == NULL)
return 0;
@@ -243,22 +269,37 @@ static int append_avi(RenderData *UNUSED(rd), int start_frame, int frame, int *p
return 1;
}
-static void end_avi(void)
+static void end_avi(void *context_v)
{
+ AviMovie *avi = context_v;
+
if (avi == NULL) return;
AVI_close_compress(avi);
- MEM_freeN(avi);
- avi = NULL;
}
+
+static void *context_create_avi(void)
+{
+ AviMovie *avi = MEM_mallocN(sizeof(AviMovie), "avimovie");
+ return avi;
+}
+
+static void context_free_avi(void *context_v)
+{
+ AviMovie *avi = context_v;
+ if (avi) {
+ MEM_freeN(avi);
+ }
+}
+
#endif /* WITH_AVI */
/* similar to BKE_image_path_from_imformat() */
-void BKE_movie_filepath_get(char *string, RenderData *rd)
+void BKE_movie_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix)
{
bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype);
if (mh->get_movie_path)
- mh->get_movie_path(string, rd);
+ mh->get_movie_path(string, rd, preview, suffix);
else
string[0] = '\0';
}
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 128a5da9b68..af71f19c226 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -61,35 +61,38 @@
#include "ffmpeg_compat.h"
-static int ffmpeg_type = 0;
-static int ffmpeg_codec = AV_CODEC_ID_MPEG4;
-static int ffmpeg_audio_codec = AV_CODEC_ID_NONE;
-static int ffmpeg_video_bitrate = 1150;
-static int ffmpeg_audio_bitrate = 128;
-static int ffmpeg_gop_size = 12;
-static int ffmpeg_autosplit = 0;
-static int ffmpeg_autosplit_count = 0;
-
-static AVFormatContext *outfile = 0;
-static AVStream *video_stream = 0;
-static AVStream *audio_stream = 0;
-static AVFrame *current_frame = 0;
-static struct SwsContext *img_convert_ctx = 0;
-
-static uint8_t *audio_input_buffer = 0;
-static uint8_t *audio_deinterleave_buffer = 0;
-static int audio_input_samples = 0;
+typedef struct FFMpegContext {
+ int ffmpeg_type;
+ int ffmpeg_codec;
+ int ffmpeg_audio_codec;
+ int ffmpeg_video_bitrate;
+ int ffmpeg_audio_bitrate;
+ int ffmpeg_gop_size;
+ int ffmpeg_autosplit;
+ int ffmpeg_autosplit_count;
+ bool ffmpeg_preview;
+
+ AVFormatContext *outfile;
+ AVStream *video_stream;
+ AVStream *audio_stream;
+ AVFrame *current_frame;
+ struct SwsContext *img_convert_ctx;
+
+ uint8_t *audio_input_buffer;
+ uint8_t *audio_deinterleave_buffer;
+ int audio_input_samples;
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
-static uint8_t *audio_output_buffer = 0;
-static int audio_outbuf_size = 0;
+ uint8_t *audio_output_buffer;
+ int audio_outbuf_size;
#endif
-static double audio_time = 0.0f;
-static bool audio_deinterleave = false;
-static int audio_sample_size = 0;
+ double audio_time;
+ bool audio_deinterleave;
+ int audio_sample_size;
#ifdef WITH_AUDASPACE
-static AUD_Device *audio_mixdown_device = 0;
+ AUD_Device *audio_mixdown_device;
#endif
+} FFMpegContext;
#define FFMPEG_AUTOSPLIT_SIZE 2000000000
@@ -98,6 +101,7 @@ static AUD_Device *audio_mixdown_device = 0;
static void ffmpeg_dict_set_int(AVDictionary **dict, const char *key, int value);
static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float value);
static void ffmpeg_set_expert_options(RenderData *rd);
+static void ffmpeg_filepath_get(FFMpegContext *context, char *string, struct RenderData *rd, bool preview, const char *suffix);
/* Delete a picture buffer */
@@ -116,50 +120,50 @@ static int request_float_audio_buffer(int codec_id)
}
#ifdef WITH_AUDASPACE
-static int write_audio_frame(void)
+static int write_audio_frame(FFMpegContext *context)
{
AVCodecContext *c = NULL;
AVPacket pkt;
AVFrame *frame = NULL;
int got_output = 0;
- c = audio_stream->codec;
+ c = context->audio_stream->codec;
av_init_packet(&pkt);
pkt.size = 0;
pkt.data = NULL;
- AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_samples);
- audio_time += (double) audio_input_samples / (double) c->sample_rate;
+ AUD_readDevice(context->audio_mixdown_device, context->audio_input_buffer, context->audio_input_samples);
+ context->audio_time += (double) context->audio_input_samples / (double) c->sample_rate;
#ifdef FFMPEG_HAVE_ENCODE_AUDIO2
frame = avcodec_alloc_frame();
avcodec_get_frame_defaults(frame);
- frame->pts = audio_time / av_q2d(c->time_base);
- frame->nb_samples = audio_input_samples;
+ frame->pts = context->audio_time / av_q2d(c->time_base);
+ frame->nb_samples = context->audio_input_samples;
frame->format = c->sample_fmt;
#ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
frame->channel_layout = c->channel_layout;
#endif
- if (audio_deinterleave) {
+ if (context->audio_deinterleave) {
int channel, i;
uint8_t *temp;
for (channel = 0; channel < c->channels; channel++) {
for (i = 0; i < frame->nb_samples; i++) {
- memcpy(audio_deinterleave_buffer + (i + channel * frame->nb_samples) * audio_sample_size,
- audio_input_buffer + (c->channels * i + channel) * audio_sample_size, audio_sample_size);
+ memcpy(context->audio_deinterleave_buffer + (i + channel * frame->nb_samples) * context->audio_sample_size,
+ context->audio_input_buffer + (c->channels * i + channel) * context->audio_sample_size, context->audio_sample_size);
}
}
- temp = audio_deinterleave_buffer;
- audio_deinterleave_buffer = audio_input_buffer;
- audio_input_buffer = temp;
+ temp = context->audio_deinterleave_buffer;
+ context->audio_deinterleave_buffer = context->audio_input_buffer;
+ context->audio_input_buffer = temp;
}
- avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, audio_input_buffer,
- audio_input_samples * c->channels * audio_sample_size, 1);
+ avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, context->audio_input_buffer,
+ context->audio_input_samples * c->channels * context->audio_sample_size, 1);
if (avcodec_encode_audio2(c, &pkt, frame, &got_output) < 0) {
// XXX error("Error writing audio packet");
@@ -171,30 +175,30 @@ static int write_audio_frame(void)
return 0;
}
#else
- pkt.size = avcodec_encode_audio(c, audio_output_buffer, audio_outbuf_size, (short *) audio_input_buffer);
+ pkt.size = avcodec_encode_audio(c, context->audio_output_buffer, context->audio_outbuf_size, (short *) context->audio_input_buffer);
if (pkt.size < 0) {
// XXX error("Error writing audio packet");
return -1;
}
- pkt.data = audio_output_buffer;
+ pkt.data = context->audio_output_buffer;
got_output = 1;
#endif
if (got_output) {
if (pkt.pts != AV_NOPTS_VALUE)
- pkt.pts = av_rescale_q(pkt.pts, c->time_base, audio_stream->time_base);
+ pkt.pts = av_rescale_q(pkt.pts, c->time_base, context->audio_stream->time_base);
if (pkt.dts != AV_NOPTS_VALUE)
- pkt.dts = av_rescale_q(pkt.dts, c->time_base, audio_stream->time_base);
+ pkt.dts = av_rescale_q(pkt.dts, c->time_base, context->audio_stream->time_base);
if (pkt.duration > 0)
- pkt.duration = av_rescale_q(pkt.duration, c->time_base, audio_stream->time_base);
+ pkt.duration = av_rescale_q(pkt.duration, c->time_base, context->audio_stream->time_base);
- pkt.stream_index = audio_stream->index;
+ pkt.stream_index = context->audio_stream->index;
pkt.flags |= AV_PKT_FLAG_KEY;
- if (av_interleaved_write_frame(outfile, &pkt) != 0) {
+ if (av_interleaved_write_frame(context->outfile, &pkt) != 0) {
fprintf(stderr, "Error writing audio packet!\n");
if (frame)
avcodec_free_frame(&frame);
@@ -301,11 +305,11 @@ static const char **get_file_extensions(int format)
}
/* Write a frame to the output file */
-static int write_video_frame(RenderData *rd, int cfra, AVFrame *frame, ReportList *reports)
+static int write_video_frame(FFMpegContext *context, RenderData *rd, int cfra, AVFrame *frame, ReportList *reports)
{
int got_output;
int ret, success = 1;
- AVCodecContext *c = video_stream->codec;
+ AVCodecContext *c = context->video_stream->codec;
AVPacket packet = { 0 };
av_init_packet(&packet);
@@ -320,22 +324,22 @@ static int write_video_frame(RenderData *rd, int cfra, AVFrame *frame, ReportLis
if (ret >= 0 && got_output) {
if (packet.pts != AV_NOPTS_VALUE) {
- packet.pts = av_rescale_q(packet.pts, c->time_base, video_stream->time_base);
+ packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame PTS: %d\n", (int)packet.pts);
}
else {
PRINT("Video Frame PTS: not set\n");
}
if (packet.dts != AV_NOPTS_VALUE) {
- packet.dts = av_rescale_q(packet.dts, c->time_base, video_stream->time_base);
+ packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame DTS: %d\n", (int)packet.dts);
}
else {
PRINT("Video Frame DTS: not set\n");
}
- packet.stream_index = video_stream->index;
- ret = av_interleaved_write_frame(outfile, &packet);
+ packet.stream_index = context->video_stream->index;
+ ret = av_interleaved_write_frame(context->outfile, &packet);
success = (ret == 0);
}
else if (ret < 0) {
@@ -349,11 +353,11 @@ static int write_video_frame(RenderData *rd, int cfra, AVFrame *frame, ReportLis
}
/* read and encode a frame of audio from the buffer */
-static AVFrame *generate_video_frame(uint8_t *pixels, ReportList *reports)
+static AVFrame *generate_video_frame(FFMpegContext *context, uint8_t *pixels, ReportList *reports)
{
uint8_t *rendered_frame;
- AVCodecContext *c = video_stream->codec;
+ AVCodecContext *c = context->video_stream->codec;
int width = c->width;
int height = c->height;
AVFrame *rgb_frame;
@@ -366,7 +370,7 @@ static AVFrame *generate_video_frame(uint8_t *pixels, ReportList *reports)
}
}
else {
- rgb_frame = current_frame;
+ rgb_frame = context->current_frame;
}
rendered_frame = pixels;
@@ -410,17 +414,17 @@ static AVFrame *generate_video_frame(uint8_t *pixels, ReportList *reports)
}
if (c->pix_fmt != PIX_FMT_BGR32) {
- sws_scale(img_convert_ctx, (const uint8_t *const *) rgb_frame->data,
+ sws_scale(context->img_convert_ctx, (const uint8_t *const *) rgb_frame->data,
rgb_frame->linesize, 0, c->height,
- current_frame->data, current_frame->linesize);
+ context->current_frame->data, context->current_frame->linesize);
delete_picture(rgb_frame);
}
- current_frame->format = PIX_FMT_BGR32;
- current_frame->width = width;
- current_frame->height = height;
+ context->current_frame->format = PIX_FMT_BGR32;
+ context->current_frame->width = width;
+ context->current_frame->height = height;
- return current_frame;
+ return context->current_frame;
}
static void set_ffmpeg_property_option(AVCodecContext *c, IDProperty *prop, AVDictionary **dictionary)
@@ -515,7 +519,7 @@ static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char
/* prepare a video stream for the output file */
-static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContext *of,
+static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int codec_id, AVFormatContext *of,
int rectx, int recty, char *error, int error_size)
{
AVStream *st;
@@ -541,7 +545,7 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
c->height = recty;
/* FIXME: Really bad hack (tm) for NTSC support */
- if (ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) {
+ if (context->ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) {
c->time_base.den = 2997;
c->time_base.num = 100;
}
@@ -554,8 +558,8 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
c->time_base.num = ((double) rd->frs_sec_base) * 100000;
}
- c->gop_size = ffmpeg_gop_size;
- c->bit_rate = ffmpeg_video_bitrate * 1000;
+ c->gop_size = context->ffmpeg_gop_size;
+ c->bit_rate = context->ffmpeg_video_bitrate * 1000;
c->rc_max_rate = rd->ffcodecdata.rc_max_rate * 1000;
c->rc_min_rate = rd->ffcodecdata.rc_min_rate * 1000;
c->rc_buffer_size = rd->ffcodecdata.rc_buffer_size * 1024;
@@ -584,7 +588,7 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
c->pix_fmt = PIX_FMT_YUV422P;
}
- if (ffmpeg_type == FFMPEG_XVID) {
+ if (context->ffmpeg_type == FFMPEG_XVID) {
/* arghhhh ... */
c->pix_fmt = PIX_FMT_YUV420P;
c->codec_tag = (('D' << 24) + ('I' << 16) + ('V' << 8) + 'X');
@@ -654,14 +658,14 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
}
av_dict_free(&opts);
- current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
+ context->current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
- img_convert_ctx = sws_getContext(c->width, c->height, PIX_FMT_BGR32, c->width, c->height, c->pix_fmt, SWS_BICUBIC,
+ context->img_convert_ctx = sws_getContext(c->width, c->height, PIX_FMT_BGR32, c->width, c->height, c->pix_fmt, SWS_BICUBIC,
NULL, NULL, NULL);
return st;
}
-static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContext *of, char *error, int error_size)
+static AVStream *alloc_audio_stream(FFMpegContext *context, RenderData *rd, int codec_id, AVFormatContext *of, char *error, int error_size)
{
AVStream *st;
AVCodecContext *c;
@@ -679,7 +683,7 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
c->codec_type = AVMEDIA_TYPE_AUDIO;
c->sample_rate = rd->ffcodecdata.audio_mixrate;
- c->bit_rate = ffmpeg_audio_bitrate * 1000;
+ c->bit_rate = context->ffmpeg_audio_bitrate * 1000;
c->sample_fmt = AV_SAMPLE_FMT_S16;
c->channels = rd->ffcodecdata.audio_channels;
@@ -746,35 +750,35 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
st->codec->time_base.den = st->codec->sample_rate;
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- audio_outbuf_size = FF_MIN_BUFFER_SIZE;
+ context->audio_outbuf_size = FF_MIN_BUFFER_SIZE;
#endif
if (c->frame_size == 0)
// used to be if ((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD))
// not sure if that is needed anymore, so let's try out if there are any
// complaints regarding some ffmpeg versions users might have
- audio_input_samples = FF_MIN_BUFFER_SIZE * 8 / c->bits_per_coded_sample / c->channels;
+ context->audio_input_samples = FF_MIN_BUFFER_SIZE * 8 / c->bits_per_coded_sample / c->channels;
else {
- audio_input_samples = c->frame_size;
+ context->audio_input_samples = c->frame_size;
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- if (c->frame_size * c->channels * sizeof(int16_t) * 4 > audio_outbuf_size)
- audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4;
+ if (c->frame_size * c->channels * sizeof(int16_t) * 4 > context->audio_outbuf_size)
+ context->audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4;
#endif
}
- audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt);
+ context->audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt);
- audio_sample_size = av_get_bytes_per_sample(c->sample_fmt);
+ context->audio_sample_size = av_get_bytes_per_sample(c->sample_fmt);
- audio_input_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * audio_sample_size);
+ context->audio_input_buffer = (uint8_t *) av_malloc(context->audio_input_samples * c->channels * context->audio_sample_size);
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- audio_output_buffer = (uint8_t *) av_malloc(audio_outbuf_size);
+ context->audio_output_buffer = (uint8_t *) av_malloc(context->audio_outbuf_size);
#endif
- if (audio_deinterleave)
- audio_deinterleave_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * audio_sample_size);
+ if (context->audio_deinterleave)
+ context->audio_deinterleave_buffer = (uint8_t *) av_malloc(context->audio_input_samples * c->channels * context->audio_sample_size);
- audio_time = 0.0f;
+ context->audio_time = 0.0f;
return st;
}
@@ -798,7 +802,7 @@ static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float va
av_dict_set(dict, key, buffer, 0);
}
-static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, ReportList *reports)
+static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int rectx, int recty, const char *suffix, ReportList *reports)
{
/* Handle to the output file */
AVFormatContext *of;
@@ -807,26 +811,26 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
char name[256], error[1024];
const char **exts;
- ffmpeg_type = rd->ffcodecdata.type;
- ffmpeg_codec = rd->ffcodecdata.codec;
- ffmpeg_audio_codec = rd->ffcodecdata.audio_codec;
- ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate;
- ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate;
- ffmpeg_gop_size = rd->ffcodecdata.gop_size;
- ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT;
-
+ context->ffmpeg_type = rd->ffcodecdata.type;
+ context->ffmpeg_codec = rd->ffcodecdata.codec;
+ context->ffmpeg_audio_codec = rd->ffcodecdata.audio_codec;
+ context->ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate;
+ context->ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate;
+ context->ffmpeg_gop_size = rd->ffcodecdata.gop_size;
+ context->ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT;
+
/* Determine the correct filename */
- BKE_ffmpeg_filepath_get(name, rd);
+ ffmpeg_filepath_get(context, name, rd, context->ffmpeg_preview, suffix);
PRINT("Starting output to %s(ffmpeg)...\n"
" Using type=%d, codec=%d, audio_codec=%d,\n"
" video_bitrate=%d, audio_bitrate=%d,\n"
" gop_size=%d, autosplit=%d\n"
" render width=%d, render height=%d\n",
- name, ffmpeg_type, ffmpeg_codec, ffmpeg_audio_codec,
- ffmpeg_video_bitrate, ffmpeg_audio_bitrate,
- ffmpeg_gop_size, ffmpeg_autosplit, rectx, recty);
+ name, context->ffmpeg_type, context->ffmpeg_codec, context->ffmpeg_audio_codec,
+ context->ffmpeg_video_bitrate, context->ffmpeg_audio_bitrate,
+ context->ffmpeg_gop_size, context->ffmpeg_autosplit, rectx, recty);
- exts = get_file_extensions(ffmpeg_type);
+ exts = get_file_extensions(context->ffmpeg_type);
if (!exts) {
BKE_report(reports, RPT_ERROR, "No valid formats found");
return 0;
@@ -845,7 +849,7 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
of->oformat = fmt;
of->packet_size = rd->ffcodecdata.mux_packet_size;
- if (ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
+ if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
ffmpeg_dict_set_int(&opts, "muxrate", rd->ffcodecdata.mux_rate);
}
else {
@@ -856,15 +860,15 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
of->max_delay = (int)(0.7 * AV_TIME_BASE);
- fmt->audio_codec = ffmpeg_audio_codec;
+ fmt->audio_codec = context->ffmpeg_audio_codec;
BLI_strncpy(of->filename, name, sizeof(of->filename));
/* set the codec to the user's selection */
- switch (ffmpeg_type) {
+ switch (context->ffmpeg_type) {
case FFMPEG_AVI:
case FFMPEG_MOV:
case FFMPEG_MKV:
- fmt->video_codec = ffmpeg_codec;
+ fmt->video_codec = context->ffmpeg_codec;
break;
case FFMPEG_OGG:
fmt->video_codec = AV_CODEC_ID_THEORA;
@@ -907,9 +911,9 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
}
}
- if (ffmpeg_type == FFMPEG_DV) {
+ if (context->ffmpeg_type == FFMPEG_DV) {
fmt->audio_codec = AV_CODEC_ID_PCM_S16LE;
- if (ffmpeg_audio_codec != AV_CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) {
+ if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) {
BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!");
av_dict_free(&opts);
return 0;
@@ -917,9 +921,9 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
}
if (fmt->video_codec != AV_CODEC_ID_NONE) {
- video_stream = alloc_video_stream(rd, fmt->video_codec, of, rectx, recty, error, sizeof(error));
- PRINT("alloc video stream %p\n", video_stream);
- if (!video_stream) {
+ context->video_stream = alloc_video_stream(context, rd, fmt->video_codec, of, rectx, recty, error, sizeof(error));
+ PRINT("alloc video stream %p\n", context->video_stream);
+ if (!context->video_stream) {
if (error[0])
BKE_report(reports, RPT_ERROR, error);
else
@@ -930,9 +934,9 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
}
}
- if (ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
- audio_stream = alloc_audio_stream(rd, fmt->audio_codec, of, error, sizeof(error));
- if (!audio_stream) {
+ if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
+ context->audio_stream = alloc_audio_stream(context, rd, fmt->audio_codec, of, error, sizeof(error));
+ if (!context->audio_stream) {
if (error[0])
BKE_report(reports, RPT_ERROR, error);
else
@@ -955,7 +959,7 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
return 0;
}
- outfile = of;
+ context->outfile = of;
av_dump_format(of, 0, name, 1);
av_dict_free(&opts);
@@ -979,11 +983,11 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
* parameter.
* </p>
*/
-static void flush_ffmpeg(void)
+static void flush_ffmpeg(FFMpegContext *context)
{
int ret = 0;
- AVCodecContext *c = video_stream->codec;
+ AVCodecContext *c = context->video_stream->codec;
/* get the delayed frames */
while (1) {
int got_output;
@@ -999,28 +1003,28 @@ static void flush_ffmpeg(void)
break;
}
if (packet.pts != AV_NOPTS_VALUE) {
- packet.pts = av_rescale_q(packet.pts, c->time_base, video_stream->time_base);
+ packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame PTS: %d\n", (int) packet.pts);
}
else {
PRINT("Video Frame PTS: not set\n");
}
if (packet.dts != AV_NOPTS_VALUE) {
- packet.dts = av_rescale_q(packet.dts, c->time_base, video_stream->time_base);
+ packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame DTS: %d\n", (int) packet.dts);
}
else {
PRINT("Video Frame DTS: not set\n");
}
- packet.stream_index = video_stream->index;
- ret = av_interleaved_write_frame(outfile, &packet);
+ packet.stream_index = context->video_stream->index;
+ ret = av_interleaved_write_frame(context->outfile, &packet);
if (ret != 0) {
fprintf(stderr, "Error writing delayed frame %d\n", ret);
break;
}
}
- avcodec_flush_buffers(video_stream->codec);
+ avcodec_flush_buffers(context->video_stream->codec);
}
/* **********************************************************************
@@ -1028,15 +1032,25 @@ static void flush_ffmpeg(void)
* ********************************************************************** */
/* Get the output filename-- similar to the other output formats */
-void BKE_ffmpeg_filepath_get(char *string, RenderData *rd)
+static void ffmpeg_filepath_get(FFMpegContext *context, char *string, RenderData *rd, bool preview, const char *suffix)
{
char autosplit[20];
const char **exts = get_file_extensions(rd->ffcodecdata.type);
const char **fe = exts;
+ int sfra, efra;
if (!string || !exts) return;
+ if (preview) {
+ sfra = rd->psfra;
+ efra = rd->pefra;
+ }
+ else {
+ sfra = rd->sfra;
+ efra = rd->efra;
+ }
+
strcpy(string, rd->pic);
BLI_path_abs(string, G.main->name);
@@ -1045,7 +1059,9 @@ void BKE_ffmpeg_filepath_get(char *string, RenderData *rd)
autosplit[0] = 0;
if ((rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) {
- sprintf(autosplit, "_%03d", ffmpeg_autosplit_count);
+ if (context) {
+ sprintf(autosplit, "_%03d", context->ffmpeg_autosplit_count);
+ }
}
if (rd->scemode & R_EXTENSION) {
@@ -1059,7 +1075,7 @@ void BKE_ffmpeg_filepath_get(char *string, RenderData *rd)
if (*fe == NULL) {
strcat(string, autosplit);
- BLI_path_frame_range(string, rd->sfra, rd->efra, 4);
+ BLI_path_frame_range(string, sfra, efra, 4);
strcat(string, *exts);
}
else {
@@ -1070,23 +1086,33 @@ void BKE_ffmpeg_filepath_get(char *string, RenderData *rd)
}
else {
if (BLI_path_frame_check_chars(string)) {
- BLI_path_frame_range(string, rd->sfra, rd->efra, 4);
+ BLI_path_frame_range(string, sfra, efra, 4);
}
strcat(string, autosplit);
}
+
+ BLI_path_suffix(string, FILE_MAX, suffix, "");
+}
+
+void BKE_ffmpeg_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix)
+{
+ ffmpeg_filepath_get(NULL, string, rd, preview, suffix);
}
-int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports)
+int BKE_ffmpeg_start(void *context_v, struct Scene *scene, RenderData *rd, int rectx, int recty,
+ ReportList *reports, bool preview, const char *suffix)
{
int success;
+ FFMpegContext *context = context_v;
- ffmpeg_autosplit_count = 0;
+ context->ffmpeg_autosplit_count = 0;
+ context->ffmpeg_preview = preview;
- success = start_ffmpeg_impl(rd, rectx, recty, reports);
+ success = start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
#ifdef WITH_AUDASPACE
- if (audio_stream) {
- AVCodecContext *c = audio_stream->codec;
+ if (context->audio_stream) {
+ AVCodecContext *c = context->audio_stream->codec;
AUD_DeviceSpecs specs;
specs.channels = c->channels;
@@ -1111,7 +1137,7 @@ int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty,
}
specs.rate = rd->ffcodecdata.audio_mixrate;
- audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->ffcodecdata.audio_volume);
+ context->audio_mixdown_device = BKE_sound_mixdown(scene, specs, preview ? rd->psfra : rd->sfra, rd->ffcodecdata.audio_volume);
#ifdef FFMPEG_CODEC_TIME_BASE
c->time_base.den = specs.rate;
c->time_base.num = 1;
@@ -1121,16 +1147,16 @@ int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty,
return success;
}
-static void end_ffmpeg_impl(int is_autosplit);
+static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit);
#ifdef WITH_AUDASPACE
-static void write_audio_frames(double to_pts)
+static void write_audio_frames(FFMpegContext *context, double to_pts)
{
int finished = 0;
- while (audio_stream && !finished) {
- if ((audio_time >= to_pts) ||
- (write_audio_frame()))
+ while (context->audio_stream && !finished) {
+ if ((context->audio_time >= to_pts) ||
+ (write_audio_frame(context)))
{
finished = 1;
}
@@ -1138,8 +1164,10 @@ static void write_audio_frames(double to_pts)
}
#endif
-int BKE_ffmpeg_append(RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty, ReportList *reports)
+int BKE_ffmpeg_append(void *context_v, RenderData *rd, int start_frame, int frame, int *pixels,
+ int rectx, int recty, const char *suffix, ReportList *reports)
{
+ FFMpegContext *context = context_v;
AVFrame *avframe;
int success = 1;
@@ -1148,111 +1176,112 @@ int BKE_ffmpeg_append(RenderData *rd, int start_frame, int frame, int *pixels, i
/* why is this done before writing the video frame and again at end_ffmpeg? */
// write_audio_frames(frame / (((double)rd->frs_sec) / rd->frs_sec_base));
- if (video_stream) {
- avframe = generate_video_frame((unsigned char *) pixels, reports);
- success = (avframe && write_video_frame(rd, frame - start_frame, avframe, reports));
+ if (context->video_stream) {
+ avframe = generate_video_frame(context, (unsigned char *) pixels, reports);
+ success = (avframe && write_video_frame(context, rd, frame - start_frame, avframe, reports));
- if (ffmpeg_autosplit) {
- if (avio_tell(outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
- end_ffmpeg_impl(true);
- ffmpeg_autosplit_count++;
- success &= start_ffmpeg_impl(rd, rectx, recty, reports);
+ if (context->ffmpeg_autosplit) {
+ if (avio_tell(context->outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
+ end_ffmpeg_impl(context, true);
+ context->ffmpeg_autosplit_count++;
+ success &= start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
}
}
}
#ifdef WITH_AUDASPACE
- write_audio_frames((frame - rd->sfra) / (((double)rd->frs_sec) / (double)rd->frs_sec_base));
+ write_audio_frames(context, (frame - start_frame) / (((double)rd->frs_sec) / (double)rd->frs_sec_base));
#endif
return success;
}
-static void end_ffmpeg_impl(int is_autosplit)
+static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
{
unsigned int i;
PRINT("Closing ffmpeg...\n");
#if 0
- if (audio_stream) { /* SEE UPPER */
- write_audio_frames();
+ if (context->audio_stream) { /* SEE UPPER */
+ write_audio_frames(context);
}
#endif
#ifdef WITH_AUDASPACE
if (is_autosplit == false) {
- if (audio_mixdown_device) {
- AUD_closeReadDevice(audio_mixdown_device);
- audio_mixdown_device = 0;
+ if (context->audio_mixdown_device) {
+ AUD_closeReadDevice(context->audio_mixdown_device);
+ context->audio_mixdown_device = 0;
}
}
#endif
- if (video_stream && video_stream->codec) {
+ if (context->video_stream && context->video_stream->codec) {
PRINT("Flushing delayed frames...\n");
- flush_ffmpeg();
+ flush_ffmpeg(context);
}
- if (outfile) {
- av_write_trailer(outfile);
+ if (context->outfile) {
+ av_write_trailer(context->outfile);
}
/* Close the video codec */
- if (video_stream && video_stream->codec) {
- avcodec_close(video_stream->codec);
- PRINT("zero video stream %p\n", video_stream);
- video_stream = 0;
+ if (context->video_stream && context->video_stream->codec) {
+ avcodec_close(context->video_stream->codec);
+ PRINT("zero video stream %p\n", context->video_stream);
+ context->video_stream = 0;
}
/* Close the output file */
- if (outfile) {
- for (i = 0; i < outfile->nb_streams; i++) {
- if (&outfile->streams[i]) {
- av_freep(&outfile->streams[i]);
+ if (context->outfile) {
+ for (i = 0; i < context->outfile->nb_streams; i++) {
+ if (&context->outfile->streams[i]) {
+ av_freep(&context->outfile->streams[i]);
}
}
}
/* free the temp buffer */
- if (current_frame) {
- delete_picture(current_frame);
- current_frame = 0;
+ if (context->current_frame) {
+ delete_picture(context->current_frame);
+ context->current_frame = 0;
}
- if (outfile && outfile->oformat) {
- if (!(outfile->oformat->flags & AVFMT_NOFILE)) {
- avio_close(outfile->pb);
+ if (context->outfile && context->outfile->oformat) {
+ if (!(context->outfile->oformat->flags & AVFMT_NOFILE)) {
+ avio_close(context->outfile->pb);
}
}
- if (outfile) {
- av_free(outfile);
- outfile = 0;
+ if (context->outfile) {
+ av_free(context->outfile);
+ context->outfile = 0;
}
- if (audio_input_buffer) {
- av_free(audio_input_buffer);
- audio_input_buffer = 0;
+ if (context->audio_input_buffer) {
+ av_free(context->audio_input_buffer);
+ context->audio_input_buffer = 0;
}
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- if (audio_output_buffer) {
- av_free(audio_output_buffer);
- audio_output_buffer = 0;
+ if (context->audio_output_buffer) {
+ av_free(context->audio_output_buffer);
+ context->audio_output_buffer = 0;
}
#endif
- if (audio_deinterleave_buffer) {
- av_free(audio_deinterleave_buffer);
- audio_deinterleave_buffer = 0;
+ if (context->audio_deinterleave_buffer) {
+ av_free(context->audio_deinterleave_buffer);
+ context->audio_deinterleave_buffer = 0;
}
- if (img_convert_ctx) {
- sws_freeContext(img_convert_ctx);
- img_convert_ctx = 0;
+ if (context->img_convert_ctx) {
+ sws_freeContext(context->img_convert_ctx);
+ context->img_convert_ctx = 0;
}
}
-void BKE_ffmpeg_end(void)
+void BKE_ffmpeg_end(void *context_v)
{
- end_ffmpeg_impl(false);
+ FFMpegContext *context = context_v;
+ end_ffmpeg_impl(context, false);
}
/* properties */
@@ -1646,4 +1675,31 @@ bool BKE_ffmpeg_alpha_channel_is_supported(RenderData *rd)
return false;
}
-#endif
+void *BKE_ffmpeg_context_create(void)
+{
+ FFMpegContext *context;
+
+ /* new ffmpeg data struct */
+ context = MEM_callocN(sizeof(FFMpegContext), "new ffmpeg context");
+
+ context->ffmpeg_codec = AV_CODEC_ID_MPEG4;
+ context->ffmpeg_audio_codec = AV_CODEC_ID_NONE;
+ context->ffmpeg_video_bitrate = 1150;
+ context->ffmpeg_audio_bitrate = 128;
+ context->ffmpeg_gop_size = 12;
+ context->ffmpeg_autosplit = 0;
+ context->ffmpeg_autosplit_count = 0;
+ context->ffmpeg_preview = false;
+
+ return context;
+}
+
+void BKE_ffmpeg_context_free(void *context_v)
+{
+ FFMpegContext *context = context_v;
+ if (context) {
+ MEM_freeN(context);
+ }
+}
+
+#endif /* WITH_FFMPEG */
diff --git a/source/blender/blenkernel/intern/writeframeserver.c b/source/blender/blenkernel/intern/writeframeserver.c
index ae6b19fb019..ba58038bbd8 100644
--- a/source/blender/blenkernel/intern/writeframeserver.c
+++ b/source/blender/blenkernel/intern/writeframeserver.c
@@ -66,12 +66,15 @@
#include "BKE_report.h"
#include "DNA_scene_types.h"
+#include "MEM_guardedalloc.h"
-static int sock;
-static int connsock;
-static int write_ppm;
-static int render_width;
-static int render_height;
+typedef struct FrameserverContext {
+ int sock;
+ int connsock;
+ int write_ppm;
+ int render_width;
+ int render_height;
+} FrameserverContext;
#if defined(_WIN32)
@@ -110,10 +113,11 @@ static int closesocket(int fd)
}
#endif
-int BKE_frameserver_start(struct Scene *scene, RenderData *UNUSED(rd), int rectx, int recty, ReportList *reports)
+int BKE_frameserver_start(void *context_v, struct Scene *scene, RenderData *UNUSED(rd), int rectx, int recty, ReportList *reports, bool UNUSED(preview), const char *UNUSED(suffix))
{
struct sockaddr_in addr;
int arg = 1;
+ FrameserverContext *context = context_v;
(void)scene; /* unused */
@@ -122,33 +126,33 @@ int BKE_frameserver_start(struct Scene *scene, RenderData *UNUSED(rd), int rectx
return 0;
}
- if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ if ((context->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
shutdown_socket_system();
BKE_report(reports, RPT_ERROR, "Cannot open socket");
return 0;
}
- setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(arg));
+ setsockopt(context->sock, SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(arg));
addr.sin_family = AF_INET;
addr.sin_port = htons(U.frameserverport);
addr.sin_addr.s_addr = INADDR_ANY;
- if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ if (bind(context->sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
shutdown_socket_system();
BKE_report(reports, RPT_ERROR, "Cannot bind to socket");
return 0;
}
- if (listen(sock, SOMAXCONN) < 0) {
+ if (listen(context->sock, SOMAXCONN) < 0) {
shutdown_socket_system();
BKE_report(reports, RPT_ERROR, "Cannot establish listen backlog");
return 0;
}
- connsock = -1;
+ context->connsock = -1;
- render_width = rectx;
- render_height = recty;
+ context->render_width = rectx;
+ context->render_height = recty;
return 1;
}
@@ -177,7 +181,7 @@ static char good_bye[] =
"<body><pre>\n"
"Render stopped. Goodbye</pre></body></html>";
-static int safe_write(char *s, int tosend)
+static int safe_write(const int connsock, char *s, int tosend)
{
int total = tosend;
do {
@@ -192,12 +196,12 @@ static int safe_write(char *s, int tosend)
return total;
}
-static int safe_puts(char *s)
+static int safe_puts(const int connsock, char *s)
{
- return safe_write(s, strlen(s));
+ return safe_write(connsock, s, strlen(s));
}
-static int handle_request(RenderData *rd, char *req)
+static int handle_request(FrameserverContext *context, RenderData *rd, char *req)
{
char *p;
char *path;
@@ -214,16 +218,16 @@ static int handle_request(RenderData *rd, char *req)
*p = 0;
- if (STREQ(path, "/index.html") || STREQ(path, "/")) {
- safe_puts(index_page);
+ if (STREQ(path, "/index.html") || strcmp(path, "/")) {
+ safe_puts(context->connsock, index_page);
return -1;
}
- write_ppm = 0;
+ context->write_ppm = 0;
pathlen = strlen(path);
if (pathlen > 12 && memcmp(path, "/images/ppm/", 12) == 0) {
- write_ppm = 1;
+ context->write_ppm = 1;
return atoi(path + 12);
}
if (STREQ(path, "/info.txt")) {
@@ -241,24 +245,24 @@ static int handle_request(RenderData *rd, char *req)
"ratescale %d\n",
rd->sfra,
rd->efra,
- render_width,
- render_height,
+ context->render_width,
+ context->render_height,
rd->frs_sec,
1
);
- safe_puts(buf);
+ safe_puts(context->connsock, buf);
return -1;
}
if (STREQ(path, "/close.txt")) {
- safe_puts(good_bye);
+ safe_puts(context->connsock, good_bye);
G.is_break = true; /* Abort render */
return -1;
}
return -1;
}
-int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
+int BKE_frameserver_loop(void *context_v, RenderData *rd, ReportList *UNUSED(reports))
{
fd_set readfds;
struct timeval tv;
@@ -271,18 +275,20 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
#endif
char buf[4096];
- if (connsock != -1) {
- closesocket(connsock);
- connsock = -1;
+ FrameserverContext *context = context_v;
+
+ if (context->connsock != -1) {
+ closesocket(context->connsock);
+ context->connsock = -1;
}
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&readfds);
- FD_SET(sock, &readfds);
+ FD_SET(context->sock, &readfds);
- rval = select(sock + 1, &readfds, NULL, NULL, &tv);
+ rval = select(context->sock + 1, &readfds, NULL, NULL, &tv);
if (rval < 0) {
return -1;
}
@@ -293,19 +299,19 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
socklen = sizeof(addr);
- if ((connsock = accept(sock, (struct sockaddr *)&addr, &socklen)) < 0) {
+ if ((context->connsock = accept(context->sock, (struct sockaddr *)&addr, &socklen)) < 0) {
return -1;
}
FD_ZERO(&readfds);
- FD_SET(connsock, &readfds);
+ FD_SET(context->connsock, &readfds);
for (;;) {
/* give 10 seconds for telnet testing... */
tv.tv_sec = 10;
tv.tv_usec = 0;
- rval = select(connsock + 1, &readfds, NULL, NULL, &tv);
+ rval = select(context->connsock + 1, &readfds, NULL, NULL, &tv);
if (rval > 0) {
break;
}
@@ -319,7 +325,7 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
}
}
- len = recv(connsock, buf, sizeof(buf) - 1, 0);
+ len = recv(context->connsock, buf, sizeof(buf) - 1, 0);
if (len < 0) {
return -1;
@@ -327,13 +333,13 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
buf[len] = 0;
- return handle_request(rd, buf);
+ return handle_request(context, rd, buf);
}
-static void serve_ppm(int *pixels, int rectx, int recty)
+static void serve_ppm(FrameserverContext *context, int *pixels, int rectx, int recty)
{
unsigned char *rendered_frame;
- unsigned char *row = (unsigned char *) malloc(render_width * 3);
+ unsigned char *row = (unsigned char *) malloc(context->render_width * 3);
int y;
char header[1024];
@@ -348,7 +354,7 @@ static void serve_ppm(int *pixels, int rectx, int recty)
"255\n",
rectx, recty);
- safe_puts(header);
+ safe_puts(context->connsock, header);
rendered_frame = (unsigned char *)pixels;
@@ -364,36 +370,54 @@ static void serve_ppm(int *pixels, int rectx, int recty)
target += 3;
src += 4;
}
- safe_write((char *)row, 3 * rectx);
+ safe_write(context->connsock, (char *)row, 3 * rectx);
}
free(row);
- closesocket(connsock);
- connsock = -1;
+ closesocket(context->connsock);
+ context->connsock = -1;
}
-int BKE_frameserver_append(RenderData *UNUSED(rd), int UNUSED(start_frame), int frame, int *pixels,
- int rectx, int recty, ReportList *UNUSED(reports))
+int BKE_frameserver_append(void *context_v, RenderData *UNUSED(rd), int UNUSED(start_frame), int frame, int *pixels,
+ int rectx, int recty, const char *UNUSED(suffix), ReportList *UNUSED(reports))
{
+ FrameserverContext *context = context_v;
+
fprintf(stderr, "Serving frame: %d\n", frame);
- if (write_ppm) {
- serve_ppm(pixels, rectx, recty);
+ if (context->write_ppm) {
+ serve_ppm(context, pixels, rectx, recty);
}
- if (connsock != -1) {
- closesocket(connsock);
- connsock = -1;
+ if (context->connsock != -1) {
+ closesocket(context->connsock);
+ context->connsock = -1;
}
return 1;
}
-void BKE_frameserver_end(void)
+void BKE_frameserver_end(void *context_v)
{
- if (connsock != -1) {
- closesocket(connsock);
- connsock = -1;
+ FrameserverContext *context = context_v;
+
+ if (context->connsock != -1) {
+ closesocket(context->connsock);
+ context->connsock = -1;
}
- closesocket(sock);
+ closesocket(context->sock);
shutdown_socket_system();
}
+void *BKE_frameserver_context_create(void)
+{
+ FrameserverContext *context = MEM_mallocN(sizeof(FrameserverContext), "Frameserver Context");
+ return context;
+}
+
+void BKE_frameserver_context_free(void *context_v)
+{
+ FrameserverContext *context = context_v;
+ if (context) {
+ MEM_freeN(context);
+ }
+}
+
#endif /* WITH_FRAMESERVER */
diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h
index 0dd1439e58c..ff7976dc701 100644
--- a/source/blender/blenlib/BLI_array_utils.h
+++ b/source/blender/blenlib/BLI_array_utils.h
@@ -34,6 +34,14 @@ void _bli_array_wrap(void *arr, unsigned int arr_len, size_t arr_stride, int dir
#define BLI_array_wrap(arr, arr_len, dir) \
_bli_array_wrap(arr, arr_len, sizeof(*(arr)), dir)
+void _bli_array_permute(
+ void *arr, const unsigned int arr_len, const size_t arr_stride,
+ const unsigned int *index, void *arr_temp);
+#define BLI_array_permute(arr, arr_len, order) \
+ _bli_array_permute(arr, arr_len, sizeof(*(arr)), order, NULL)
+#define BLI_array_permute_ex(arr, arr_len, index, arr_temp) \
+ _bli_array_permute(arr, arr_len, sizeof(*(arr)), order, arr_temp)
+
int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p);
#define BLI_array_findindex(arr, arr_len, p) \
_bli_array_findindex(arr, arr_len, sizeof(*(arr)), p)
diff --git a/source/blender/blenlib/BLI_blenlib.h b/source/blender/blenlib/BLI_blenlib.h
index 03b75975af4..06bbf29a223 100644
--- a/source/blender/blenlib/BLI_blenlib.h
+++ b/source/blender/blenlib/BLI_blenlib.h
@@ -58,7 +58,6 @@
#ifndef __BLI_BLENLIB_H__
#define __BLI_BLENLIB_H__
-struct ListBase;
#include <stdlib.h>
diff --git a/source/blender/blenlib/BLI_callbacks.h b/source/blender/blenlib/BLI_callbacks.h
index 7cf524749c2..fdffbeb4c8d 100644
--- a/source/blender/blenlib/BLI_callbacks.h
+++ b/source/blender/blenlib/BLI_callbacks.h
@@ -25,7 +25,6 @@
#ifndef __BLI_CALLBACKS_H__
#define __BLI_CALLBACKS_H__
-struct bContext;
struct Main;
struct ID;
diff --git a/source/blender/blenlib/BLI_compiler_compat.h b/source/blender/blenlib/BLI_compiler_compat.h
index 10c0752c9a7..876d2c459c5 100644
--- a/source/blender/blenlib/BLI_compiler_compat.h
+++ b/source/blender/blenlib/BLI_compiler_compat.h
@@ -37,4 +37,16 @@
# include <malloc.h>
#endif
+#if defined(__cplusplus) && ((__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1800))
+# define HAS_CPP11_FEATURES
+#endif
+
+#if (defined(__GNUC__) || defined(__clang__)) && defined(HAS_CPP11_FEATURES)
+extern "C++" {
+ /* Some magic to be sure we don't have reference in the type. */
+ template<typename T> static inline T decltype_helper(T x) { return x; }
+# define typeof(x) decltype(decltype_helper(x))
+}
+#endif
+
#endif /* __BLI_COMPILER_COMPAT_H__ */
diff --git a/source/blender/blenlib/BLI_compiler_typecheck.h b/source/blender/blenlib/BLI_compiler_typecheck.h
index 652c4a954b9..b9fb3ebf47a 100644
--- a/source/blender/blenlib/BLI_compiler_typecheck.h
+++ b/source/blender/blenlib/BLI_compiler_typecheck.h
@@ -381,4 +381,303 @@
# define CHECK_TYPE_ANY(...) (void)0
#endif
+
+/**
+ * GENERIC_TYPE_ANY: handy macro to reuse a single expression for multiple types, eg:
+ *
+ * \code{.c}
+ * _Generic(value,
+ * GENERIC_TYPE_ANY(result_a, Foo *, Bar *, Baz *),
+ * GENERIC_TYPE_ANY(result_b, Spam *, Spaz *, Spot *),
+ * )
+ * \endcode
+ *
+ * excuse ridiculously long generated args.
+ * \code{.py}
+ * for i in range(63):
+ * args = [(chr(ord('a') + (c % 26)) + (chr(ord('0') + (c // 26)))) for c in range(i + 1)]
+ * print("#define _VA_GENERIC_TYPE_ANY%d(r, %s) \\" % (i + 2, ", ".join(args)))
+ * print(" %s: r " % (": r, ".join(args)))
+ * \endcode
+ */
+#define _VA_GENERIC_TYPE_ANY2(r, a0) \
+ a0: r
+#define _VA_GENERIC_TYPE_ANY3(r, a0, b0) \
+ a0: r, b0: r
+#define _VA_GENERIC_TYPE_ANY4(r, a0, b0, c0) \
+ a0: r, b0: r, c0: r
+#define _VA_GENERIC_TYPE_ANY5(r, a0, b0, c0, d0) \
+ a0: r, b0: r, c0: r, d0: r
+#define _VA_GENERIC_TYPE_ANY6(r, a0, b0, c0, d0, e0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r
+#define _VA_GENERIC_TYPE_ANY7(r, a0, b0, c0, d0, e0, f0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r
+#define _VA_GENERIC_TYPE_ANY8(r, a0, b0, c0, d0, e0, f0, g0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r
+#define _VA_GENERIC_TYPE_ANY9(r, a0, b0, c0, d0, e0, f0, g0, h0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r
+#define _VA_GENERIC_TYPE_ANY10(r, a0, b0, c0, d0, e0, f0, g0, h0, i0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r
+#define _VA_GENERIC_TYPE_ANY11(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r
+#define _VA_GENERIC_TYPE_ANY12(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r
+#define _VA_GENERIC_TYPE_ANY13(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r
+#define _VA_GENERIC_TYPE_ANY14(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r
+#define _VA_GENERIC_TYPE_ANY15(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r
+#define _VA_GENERIC_TYPE_ANY16(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r
+#define _VA_GENERIC_TYPE_ANY17(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r
+#define _VA_GENERIC_TYPE_ANY18(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r
+#define _VA_GENERIC_TYPE_ANY19(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r
+#define _VA_GENERIC_TYPE_ANY20(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r
+#define _VA_GENERIC_TYPE_ANY21(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r
+#define _VA_GENERIC_TYPE_ANY22(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r
+#define _VA_GENERIC_TYPE_ANY23(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r
+#define _VA_GENERIC_TYPE_ANY24(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r
+#define _VA_GENERIC_TYPE_ANY25(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r
+#define _VA_GENERIC_TYPE_ANY26(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r
+#define _VA_GENERIC_TYPE_ANY27(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r
+#define _VA_GENERIC_TYPE_ANY28(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r
+#define _VA_GENERIC_TYPE_ANY29(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r
+#define _VA_GENERIC_TYPE_ANY30(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r
+#define _VA_GENERIC_TYPE_ANY31(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r
+#define _VA_GENERIC_TYPE_ANY32(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r
+#define _VA_GENERIC_TYPE_ANY33(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r
+#define _VA_GENERIC_TYPE_ANY34(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r
+#define _VA_GENERIC_TYPE_ANY35(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r
+#define _VA_GENERIC_TYPE_ANY36(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r
+#define _VA_GENERIC_TYPE_ANY37(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r
+#define _VA_GENERIC_TYPE_ANY38(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r
+#define _VA_GENERIC_TYPE_ANY39(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r
+#define _VA_GENERIC_TYPE_ANY40(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r
+#define _VA_GENERIC_TYPE_ANY41(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r
+#define _VA_GENERIC_TYPE_ANY42(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r
+#define _VA_GENERIC_TYPE_ANY43(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r
+#define _VA_GENERIC_TYPE_ANY44(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r
+#define _VA_GENERIC_TYPE_ANY45(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r
+#define _VA_GENERIC_TYPE_ANY46(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r
+#define _VA_GENERIC_TYPE_ANY47(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r
+#define _VA_GENERIC_TYPE_ANY48(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r
+#define _VA_GENERIC_TYPE_ANY49(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r
+#define _VA_GENERIC_TYPE_ANY50(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r
+#define _VA_GENERIC_TYPE_ANY51(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r
+#define _VA_GENERIC_TYPE_ANY52(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r
+#define _VA_GENERIC_TYPE_ANY53(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r
+#define _VA_GENERIC_TYPE_ANY54(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r
+#define _VA_GENERIC_TYPE_ANY55(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r
+#define _VA_GENERIC_TYPE_ANY56(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r
+#define _VA_GENERIC_TYPE_ANY57(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2, d2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r, d2: r
+#define _VA_GENERIC_TYPE_ANY58(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2, d2, e2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r, d2: r, e2: r
+#define _VA_GENERIC_TYPE_ANY59(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2, d2, e2, f2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r, d2: r, e2: r, f2: r
+#define _VA_GENERIC_TYPE_ANY60(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2, d2, e2, f2, g2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r, d2: r, e2: r, f2: r, g2: r
+#define _VA_GENERIC_TYPE_ANY61(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2, d2, e2, f2, g2, h2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r, d2: r, e2: r, f2: r, g2: r, h2: r
+#define _VA_GENERIC_TYPE_ANY62(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2, d2, e2, f2, g2, h2, i2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r, d2: r, e2: r, f2: r, g2: r, h2: r, i2: r
+#define _VA_GENERIC_TYPE_ANY63(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2, d2, e2, f2, g2, h2, i2, j2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r, d2: r, e2: r, f2: r, g2: r, h2: r, i2: r, j2: r
+#define _VA_GENERIC_TYPE_ANY64(r, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, \
+ u0, v0, w0, x0, y0, z0, a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1, q1, r1, s1, t1, u1, v1, \
+ w1, x1, y1, z1, a2, b2, c2, d2, e2, f2, g2, h2, i2, j2, k2) \
+ a0: r, b0: r, c0: r, d0: r, e0: r, f0: r, g0: r, h0: r, i0: r, j0: r, k0: r, l0: r, m0: r, n0: r, o0: r, p0: r, \
+ q0: r, r0: r, s0: r, t0: r, u0: r, v0: r, w0: r, x0: r, y0: r, z0: r, a1: r, b1: r, c1: r, d1: r, e1: r, f1: r, \
+ g1: r, h1: r, i1: r, j1: r, k1: r, l1: r, m1: r, n1: r, o1: r, p1: r, q1: r, r1: r, s1: r, t1: r, u1: r, v1: r, \
+ w1: r, x1: r, y1: r, z1: r, a2: r, b2: r, c2: r, d2: r, e2: r, f2: r, g2: r, h2: r, i2: r, j2: r, k2: r
+
+# define GENERIC_TYPE_ANY(...) VA_NARGS_CALL_OVERLOAD(_VA_GENERIC_TYPE_ANY, __VA_ARGS__)
+
#endif /* __BLI_COMPILER_TYPECHECK_H__ */
diff --git a/source/blender/blenlib/BLI_edgehash.h b/source/blender/blenlib/BLI_edgehash.h
index ded4b163f71..20272dd97cd 100644
--- a/source/blender/blenlib/BLI_edgehash.h
+++ b/source/blender/blenlib/BLI_edgehash.h
@@ -54,6 +54,7 @@ bool BLI_edgehash_reinsert(EdgeHash *eh, unsigned int v0, unsigned in
void *BLI_edgehash_lookup(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT;
void *BLI_edgehash_lookup_default(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val_default) ATTR_WARN_UNUSED_RESULT;
void **BLI_edgehash_lookup_p(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT;
+bool BLI_edgehash_ensure_p(EdgeHash *eh, unsigned int v0, unsigned int v1, void ***r_val) ATTR_WARN_UNUSED_RESULT;
bool BLI_edgehash_remove(EdgeHash *eh, unsigned int v0, unsigned int v1, EdgeHashFreeFP valfreefp);
void *BLI_edgehash_popkey(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h
index 7898a54002f..642896ac701 100644
--- a/source/blender/blenlib/BLI_fileops.h
+++ b/source/blender/blenlib/BLI_fileops.h
@@ -51,7 +51,6 @@ extern "C" {
# define PATH_MAX 4096
#endif
-struct gzFile;
/* Common */
@@ -107,6 +106,7 @@ int BLI_access(const char *filename, int mode) ATTR_WARN_UNUSED_RESULT ATTR_N
bool BLI_file_is_writable(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BLI_file_touch(const char *file) ATTR_NONNULL();
+void BLI_file_size_string(off_t st_size, char *size, size_t len);
#if 0 /* UNUSED */
int BLI_file_gzip(const char *from, const char *to) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_fileops_types.h b/source/blender/blenlib/BLI_fileops_types.h
index 0e6eab687ad..e596fa55877 100644
--- a/source/blender/blenlib/BLI_fileops_types.h
+++ b/source/blender/blenlib/BLI_fileops_types.h
@@ -34,6 +34,7 @@
*/
#include <sys/stat.h>
+#include "BLI_listbase.h"
#if defined(WIN32) && !defined(FREE_WINDOWS)
typedef unsigned int mode_t;
@@ -41,6 +42,19 @@ typedef unsigned int mode_t;
struct ImBuf;
+typedef struct CollapsedEntry {
+ /* list that gets populated during file open */
+ ListBase list;
+ /* sorted array of the files for quick access of frames */
+ struct direntry **darray;
+ off_t totalsize;
+ int minframe;
+ int maxframe;
+ int numdigits;
+ int totfiles;
+ int curfra;
+} CollapsedEntry;
+
struct direntry {
mode_t type;
char *relname;
@@ -69,6 +83,10 @@ struct direntry {
int nr;
struct ImBuf *image;
unsigned int selflag; /* selection flag */
+ off_t realsize; /* real size of file */
+ int frame; /* frame of file in a movie sequence */
+
+ CollapsedEntry collapsed_info;
};
struct dirlink {
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index bf2b4126453..a9f8d9fc268 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -44,6 +44,8 @@ typedef unsigned int (*GHashHashFP) (const void *key);
typedef bool (*GHashCmpFP) (const void *a, const void *b);
typedef void (*GHashKeyFreeFP) (void *key);
typedef void (*GHashValFreeFP) (void *val);
+typedef void *(*GHashKeyCopyFP) (const void *key);
+typedef void *(*GHashValCopyFP) (const void *val);
typedef struct GHash GHash;
@@ -54,7 +56,13 @@ typedef struct GHashIterator {
} GHashIterator;
enum {
- GHASH_FLAG_ALLOW_DUPES = (1 << 0), /* only checked for in debug mode */
+ GHASH_FLAG_ALLOW_DUPES = (1 << 0), /* Only checked for in debug mode */
+ GHASH_FLAG_ALLOW_SHRINK = (1 << 1), /* Allow to shrink buckets' size. */
+
+#ifdef GHASH_INTERNAL_API
+ /* Internal usage only */
+ GHASH_FLAG_IS_GSET = (1 << 16), /* Whether the GHash is actually used as GSet (no value storage). */
+#endif
};
/* *** */
@@ -62,19 +70,24 @@ enum {
GHash *BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info,
const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_copy(GHash *gh, GHashKeyCopyFP keycopyfp,
+ GHashValCopyFP valcopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+void BLI_ghash_reserve(GHash *gh, const unsigned int nentries_reserve);
void BLI_ghash_insert(GHash *gh, void *key, void *val);
bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
void *BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
void *BLI_ghash_lookup_default(GHash *gh, const void *key, void *val_default) ATTR_WARN_UNUSED_RESULT;
void **BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
-bool BLI_ghash_remove(GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT;
+bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_val, GHashKeyCopyFP keycopyfp) ATTR_WARN_UNUSED_RESULT;
+bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
void BLI_ghash_clear_ex(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp,
const unsigned int nentries_reserve);
-void *BLI_ghash_popkey(GHash *gh, void *key, GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT;
+void *BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT;
bool BLI_ghash_haskey(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
-int BLI_ghash_size(GHash *gh) ATTR_WARN_UNUSED_RESULT;
+unsigned int BLI_ghash_size(GHash *gh) ATTR_WARN_UNUSED_RESULT;
void BLI_ghash_flag_set(GHash *gh, unsigned int flag);
void BLI_ghash_flag_clear(GHash *gh, unsigned int flag);
@@ -127,23 +140,38 @@ unsigned int BLI_ghashutil_strhash_n(const char *key, size_t n);
CHECK_TYPE_ANY(key, char *, const char *, const char * const), \
BLI_ghashutil_strhash_p(key))
unsigned int BLI_ghashutil_strhash_p(const void *key);
+unsigned int BLI_ghashutil_strhash_p_murmur(const void *key);
bool BLI_ghashutil_strcmp(const void *a, const void *b);
#define BLI_ghashutil_inthash(key) ( \
CHECK_TYPE_ANY(&(key), int *, const int *), \
BLI_ghashutil_uinthash((unsigned int)key))
unsigned int BLI_ghashutil_uinthash(unsigned int key);
+unsigned int BLI_ghashutil_inthash_p(const void *ptr);
+unsigned int BLI_ghashutil_inthash_p_murmur(const void *ptr);
+unsigned int BLI_ghashutil_inthash_p_simple(const void *ptr);
+bool BLI_ghashutil_intcmp(const void *a, const void *b);
+
+
+unsigned int BLI_ghashutil_uinthash_v4(const unsigned int key[4]);
#define BLI_ghashutil_inthash_v4(key) ( \
CHECK_TYPE_ANY(key, int *, const int *), \
BLI_ghashutil_uinthash_v4((const unsigned int *)key))
-unsigned int BLI_ghashutil_uinthash_v4(const unsigned int key[4]);
#define BLI_ghashutil_inthash_v4_p \
((GSetHashFP)BLI_ghashutil_uinthash_v4)
+#define BLI_ghashutil_uinthash_v4_p \
+ ((GSetHashFP)BLI_ghashutil_uinthash_v4)
+unsigned int BLI_ghashutil_uinthash_v4_murmur(const unsigned int key[4]);
+#define BLI_ghashutil_inthash_v4_murmur(key) ( \
+ CHECK_TYPE_ANY(key, int *, const int *), \
+ BLI_ghashutil_uinthash_v4_murmur((const unsigned int *)key))
+#define BLI_ghashutil_inthash_v4_p_murmur \
+ ((GSetHashFP)BLI_ghashutil_uinthash_v4_murmur)
+#define BLI_ghashutil_uinthash_v4_p_murmur \
+ ((GSetHashFP)BLI_ghashutil_uinthash_v4_murmur)
bool BLI_ghashutil_uinthash_v4_cmp(const void *a, const void *b);
#define BLI_ghashutil_inthash_v4_cmp \
BLI_ghashutil_uinthash_v4_cmp
-unsigned int BLI_ghashutil_inthash_p(const void *ptr);
-bool BLI_ghashutil_intcmp(const void *a, const void *b);
/** \} */
@@ -178,6 +206,7 @@ typedef struct GSet GSet;
typedef GHashHashFP GSetHashFP;
typedef GHashCmpFP GSetCmpFP;
typedef GHashKeyFreeFP GSetKeyFreeFP;
+typedef GHashKeyCopyFP GSetKeyCopyFP;
/* so we can cast but compiler sees as different */
typedef struct GSetIterator {
@@ -191,7 +220,8 @@ typedef struct GSetIterator {
GSet *BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info,
const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-int BLI_gset_size(GSet *gs) ATTR_WARN_UNUSED_RESULT;
+GSet *BLI_gset_copy(GSet *gs, GSetKeyCopyFP keycopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+unsigned int BLI_gset_size(GSet *gs) ATTR_WARN_UNUSED_RESULT;
void BLI_gset_flag_set(GSet *gs, unsigned int flag);
void BLI_gset_flag_clear(GSet *gs, unsigned int flag);
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp);
@@ -199,10 +229,10 @@ void BLI_gset_insert(GSet *gh, void *key);
bool BLI_gset_add(GSet *gs, void *key);
bool BLI_gset_reinsert(GSet *gh, void *key, GSetKeyFreeFP keyfreefp);
bool BLI_gset_haskey(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
-bool BLI_gset_remove(GSet *gs, void *key, GSetKeyFreeFP keyfreefp);
+bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp);
void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp,
const unsigned int nentries_reserve);
-void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp);
+void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp);
GSet *BLI_gset_ptr_new_ex(const char *info,
const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
@@ -229,10 +259,22 @@ BLI_INLINE bool BLI_gsetIterator_done(GSetIterator *gsi) { return BLI_ghashItera
BLI_gsetIterator_done(&gs_iter_) == false; \
BLI_gsetIterator_step(&gs_iter_), i_++)
-#ifdef DEBUG
+
+/* For testing, debugging only */
+#ifdef GHASH_INTERNAL_API
+int BLI_ghash_buckets_size(GHash *gh);
+int BLI_gset_buckets_size(GSet *gs);
+
+double BLI_ghash_calc_quality_ex(
+ GHash *gh, double *r_load, double *r_variance,
+ double *r_prop_empty_buckets, double *r_prop_overloaded_buckets, int *r_biggest_bucket);
+double BLI_gset_calc_quality_ex(
+ GSet *gs, double *r_load, double *r_variance,
+ double *r_prop_empty_buckets, double *r_prop_overloaded_buckets, int *r_biggest_bucket);
double BLI_ghash_calc_quality(GHash *gh);
double BLI_gset_calc_quality(GSet *gs);
-#endif
+#endif /* GHASH_INTERNAL_API */
+
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_hash_mm2a.h b/source/blender/blenlib/BLI_hash_mm2a.h
index 007dec4f4d6..6beaf50ae8f 100644
--- a/source/blender/blenlib/BLI_hash_mm2a.h
+++ b/source/blender/blenlib/BLI_hash_mm2a.h
@@ -42,4 +42,6 @@ void BLI_hash_mm2a_add_int(BLI_HashMurmur2A *mm2, int data);
uint32_t BLI_hash_mm2a_end(BLI_HashMurmur2A *mm2);
+uint32_t BLI_hash_mm2(const unsigned char *data, size_t len, uint32_t seed);
+
#endif /* __BLI_HASH_MM2A_H__ */
diff --git a/source/blender/blenlib/BLI_linklist_stack.h b/source/blender/blenlib/BLI_linklist_stack.h
index 9ac233a8fa4..a4b8f77bfa6 100644
--- a/source/blender/blenlib/BLI_linklist_stack.h
+++ b/source/blender/blenlib/BLI_linklist_stack.h
@@ -168,6 +168,16 @@
#define BLI_SMALLSTACK_IS_EMPTY(var) \
((_BLI_SMALLSTACK_CAST(var) _##var##_stack) == NULL)
+/* fill in a lookup table */
+#define BLI_SMALLSTACK_AS_TABLE(var, data) \
+{ \
+ LinkNode *_##var##_iter; \
+ unsigned int i; \
+ for (_##var##_iter = _##var##_stack, i = 0; _##var##_iter; _##var##_iter = _##var##_iter->next, i++) { \
+ (data)[i] = _BLI_SMALLSTACK_CAST(var) (_##var##_iter->link); \
+ } \
+} ((void)0)
+
/* loop over stack members last-added-first */
#define BLI_SMALLSTACK_ITER_BEGIN(var, item) \
{ \
diff --git a/source/blender/blenlib/BLI_math.h b/source/blender/blenlib/BLI_math.h
index db2fed433da..62ed8045109 100644
--- a/source/blender/blenlib/BLI_math.h
+++ b/source/blender/blenlib/BLI_math.h
@@ -30,18 +30,30 @@
* \ingroup bli
* \section mathabbrev Abbreviations
*
- * - fl = float
- * - db = double
- * - v2 = vec2 = vector 2
- * - v3 = vec3 = vector 3
- * - v4 = vec4 = vector 4
- * - qt = quat = quaternion
- * - dq = dquat = dual quaternion
- * - m2 = mat2 = matrix 2x2
- * - m3 = mat3 = matrix 3x3
- * - m4 = mat4 = matrix 4x4
- * - eul = euler rotation
- * - eulO = euler with order
+ * - ``fl`` = float
+ * - ``db`` = double
+ * - ``v2`` = vec2 = vector 2
+ * - ``v3`` = vec3 = vector 3
+ * - ``v4`` = vec4 = vector 4
+ * - ``vn`` = vec4 = vector N dimensions, *passed as an arg, after the vector*.
+ * - ``qt`` = quat = quaternion
+ * - ``dq`` = dquat = dual quaternion
+ * - ``m2`` = mat2 = matrix 2x2
+ * - ``m3`` = mat3 = matrix 3x3
+ * - ``m4`` = mat4 = matrix 4x4
+ * - ``eul`` = euler rotation
+ * - ``eulO`` = euler with order
+ *
+ * \subsection mathabbrev_all Function Type Abbreviations
+ *
+ * For non float versions of functions (which typically operate on floats),
+ * use single suffix abbreviations.
+ *
+ * - ``_d`` = double
+ * - ``_i`` = int
+ * - ``_u`` = unsigned int
+ * - ``_char`` = char
+ * - ``_uchar`` = unsigned char
*
* \section mathvarnames Variable Names
*
@@ -61,4 +73,3 @@
#include "BLI_math_interp.h"
#endif /* __BLI_MATH_H__ */
-
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index daa7db8e3cf..79a2d57c966 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -214,9 +214,7 @@ MINLINE int iroundf(float a);
MINLINE int divide_round_i(int a, int b);
MINLINE int mod_i(int i, int n);
-MINLINE unsigned int highest_order_bit_i(unsigned int n);
-MINLINE unsigned short highest_order_bit_s(unsigned short n);
-
+int pow_i(int base, int exp);
double double_round(double x, int ndigits);
#ifdef BLI_MATH_GCC_WARN_PRAGMA
diff --git a/source/blender/blenlib/BLI_math_bits.h b/source/blender/blenlib/BLI_math_bits.h
new file mode 100644
index 00000000000..876c0d92e31
--- /dev/null
+++ b/source/blender/blenlib/BLI_math_bits.h
@@ -0,0 +1,51 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * */
+
+#ifndef __BLI_MATH_BITS_H__
+#define __BLI_MATH_BITS_H__
+
+/** \file BLI_math_bits.h
+ * \ingroup bli
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "BLI_math_inline.h"
+
+MINLINE unsigned int highest_order_bit_i(unsigned int n);
+MINLINE unsigned short highest_order_bit_s(unsigned short n);
+
+#ifdef __GNUC__
+# define count_bits_i(i) __builtin_popcount(i)
+#else
+MINLINE int count_bits_i(unsigned int n);
+#endif
+
+#if BLI_MATH_DO_INLINE
+#include "intern/math_bits_inline.c"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BLI_MATH_BITS_H__ */
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index 55e57b14d09..d70dfcd9e58 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -80,13 +80,6 @@ void rgb_to_xyz(float r, float g, float b, float *x, float *y, float *z);
unsigned int rgb_to_cpack(float r, float g, float b);
unsigned int hsv_to_cpack(float h, float s, float v);
-MINLINE float rgb_to_bw(const float rgb[3]);
-MINLINE float rgb_to_grayscale(const float rgb[3]);
-MINLINE unsigned char rgb_to_grayscale_byte(const unsigned char rgb[3]);
-MINLINE float rgb_to_luma(const float rgb[3]);
-MINLINE unsigned char rgb_to_luma_byte(const unsigned char rgb[3]);
-MINLINE float rgb_to_luma_y(const float rgb[3]);
-
/**************** Profile Transformations *****************/
float srgb_to_linearrgb(float c);
@@ -136,6 +129,9 @@ void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4]);
void xyz_to_lab(float x, float y, float z, float *l, float *a, float *b);
+MINLINE float rgb_to_grayscale(const float rgb[3]);
+MINLINE unsigned char rgb_to_grayscale_byte(const unsigned char rgb[3]);
+
MINLINE int compare_rgb_uchar(const unsigned char a[3], const unsigned char b[3], const int limit);
MINLINE float dither_random_value(float s, float t);
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 4f7a3310ee6..91610ccfe5b 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -227,6 +227,8 @@ void fill_poly_v2i_n(
/* tri or quad, d can be NULL */
void interp_weights_face_v3(float w[4],
const float a[3], const float b[3], const float c[3], const float d[3], const float p[3]);
+/* also returns three indices of the triangle actually used */
+void interp_weights_face_v3_index(int tri[3], float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3]);
void interp_weights_poly_v3(float w[], float v[][3], const int n, const float co[3]);
void interp_weights_poly_v2(float w[], float v[][2], const int n, const float co[2]);
@@ -259,6 +261,7 @@ void resolve_tri_uv_v3(float r_uv[2], const float st[3], const float st0[3], con
void resolve_quad_uv_v2(float r_uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2], const float st3[2]);
void resolve_quad_uv_v2_deriv(float r_uv[2], float r_deriv[2][2],
const float st[2], const float st0[2], const float st1[2], const float st2[2], const float st3[2]);
+float resolve_quad_u_v2(const float st[2], const float st0[2], const float st1[2], const float st2[2], const float st3[2]);
/* use to find the point of a UV on a face */
void interp_bilinear_quad_v3(float data[4][3], float u, float v, float res[3]);
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 45972d03175..f7eeb1ec7a1 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -106,6 +106,7 @@ void mul_v2_m4v3(float r[2], float M[4][4], const float v[3]);
void mul_v2_m2v2(float r[2], float M[2][2], const float v[2]);
void mul_m2v2(float M[2][2], float v[2]);
void mul_mat3_m4_v3(float M[4][4], float r[3]);
+void mul_v3_mat3_m4v3(float r[3], float M[4][4], const float v[3]);
void mul_m4_v4(float M[4][4], float r[4]);
void mul_v4_m4v4(float r[4], float M[4][4], const float v[4]);
void mul_project_m4_v3(float M[4][4], float vec[3]);
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index ffd80f46725..9bc1121801e 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -146,11 +146,20 @@ MINLINE void negate_v4_v4(float r[4], const float a[3]);
MINLINE void negate_v3_short(short r[3]);
+MINLINE void abs_v2(float r[2]);
+MINLINE void abs_v2_v2(float r[2], const float a[2]);
+MINLINE void abs_v3(float r[3]);
+MINLINE void abs_v3_v3(float r[3], const float a[3]);
+MINLINE void abs_v4(float r[4]);
+MINLINE void abs_v4_v4(float r[4], const float a[4]);
+
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_v3v3v3(const float p[3], const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_v4v4(const float a[4], const float b[4]) ATTR_WARN_UNUSED_RESULT;
+MINLINE double dot_v3db_v3fl(const double a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
+
MINLINE float cross_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3]);
@@ -264,6 +273,8 @@ void angle_poly_v3(float *angles, const float *verts[3], int len);
void project_v2_v2v2(float c[2], const float v1[2], const float v2[2]);
void project_v3_v3v3(float r[3], const float p[3], const float n[3]);
+void project_plane_v3_v3v3(float c[3], const float v[3], const float v_plane[3]);
+void project_plane_v2_v2v2(float c[2], const float v[2], const float v_plane[2]);
void project_v3_plane(float v[3], const float n[3], const float p[3]);
void reflect_v3_v3v3(float r[3], const float v[3], const float n[3]);
void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3]);
@@ -299,12 +310,13 @@ void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist);
void axis_sort_v3(const float axis_values[3], int r_axis_order[3]);
/***************************** Array Functions *******************************/
-/* attempted to follow fixed length vertex functions. names could be improved*/
+/* follow fixed length vector function conventions. */
double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int size) ATTR_WARN_UNUSED_RESULT;
double len_squared_vn(const float *array, const int size) ATTR_WARN_UNUSED_RESULT;
float normalize_vn_vn(float *array_tar, const float *array_src, const int size);
float normalize_vn(float *array_tar, const int size);
void range_vn_i(int *array_tar, const int size, const int start);
+void range_vn_u(unsigned int *array_tar, const int size, const unsigned int start);
void range_vn_fl(float *array_tar, const int size, const float start, const float step);
void negate_vn(float *array_tar, const int size);
void negate_vn_vn(float *array_tar, const float *array_src, const int size);
@@ -319,11 +331,15 @@ void sub_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_
void msub_vn_vn(float *array_tar, const float *array_src, const float f, const int size);
void msub_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, const float f, const int size);
void interp_vn_vn(float *array_tar, const float *array_src, const float t, const int size);
-void fill_vn_i(int *array_tar, const int size, const int val);
-void fill_vn_short(short *array_tar, const int size, const short val);
-void fill_vn_ushort(unsigned short *array_tar, const int size, const unsigned short val);
-void fill_vn_uchar(unsigned char *array_tar, const int size, const unsigned char val);
-void fill_vn_fl(float *array_tar, const int size, const float val);
+void copy_vn_i(int *array_tar, const int size, const int val);
+void copy_vn_short(short *array_tar, const int size, const short val);
+void copy_vn_ushort(unsigned short *array_tar, const int size, const unsigned short val);
+void copy_vn_uchar(unsigned char *array_tar, const int size, const unsigned char val);
+void copy_vn_fl(float *array_tar, const int size, const float val);
+
+void add_vn_vn_d(double *array_tar, const double *array_src, const int size);
+void add_vn_vnvn_d(double *array_tar, const double *array_src_a, const double *array_src_b, const int size);
+void mul_vn_db(double *array_tar, const int size, const double f);
/**************************** Inline Definitions ******************************/
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index d99df24aaf7..c488856ca30 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -38,7 +38,6 @@ extern "C" {
#include "BLI_compiler_attrs.h"
struct ListBase;
-struct direntry;
#ifdef WIN32
#define SEP '\\'
@@ -79,6 +78,11 @@ void BLI_del_slash(char *string) ATTR_NONNULL();
const char *BLI_first_slash(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
void BLI_path_native_slash(char *path) ATTR_NONNULL();
+#ifdef _WIN32
+bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen);
+#endif
+bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *name);
+
void BLI_getlastdir(const char *dir, char *last, const size_t maxlen);
bool BLI_testextensie(const char *str, const char *ext) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
bool BLI_testextensie_n(const char *str, ...) ATTR_NONNULL(1) ATTR_SENTINEL(0);
@@ -128,6 +132,8 @@ bool BLI_parent_dir(char *path) ATTR_NONNULL();
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL();
bool BLI_path_frame(char *path, int frame, int digits) ATTR_NONNULL();
bool BLI_path_frame_range(char *path, int sta, int end, int digits) ATTR_NONNULL();
+bool BLI_path_frame_get(char *path, int *r_frame, int *numdigits) ATTR_NONNULL();
+bool BLI_path_frame_strip(char *path, bool setsharp, char *ext);
bool BLI_path_frame_check_chars(const char *path) ATTR_NONNULL();
bool BLI_path_cwd(char *path) ATTR_NONNULL();
void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_quadric.h b/source/blender/blenlib/BLI_quadric.h
index 82c39463dd2..eaf9c7a0738 100644
--- a/source/blender/blenlib/BLI_quadric.h
+++ b/source/blender/blenlib/BLI_quadric.h
@@ -31,14 +31,14 @@
*/
typedef struct Quadric {
- float a2, ab, ac, ad,
- b2, bc, bd,
- c2, cd,
- d2;
+ double a2, ab, ac, ad,
+ b2, bc, bd,
+ c2, cd,
+ d2;
} Quadric;
/* conversion */
-void BLI_quadric_from_v3_dist(Quadric *q, const float v[3], const float offset);
+void BLI_quadric_from_plane(Quadric *q, const double v[4]);
void BLI_quadric_to_tensor_m3(const Quadric *q, float m[3][3]);
void BLI_quadric_to_vector_v3(const Quadric *q, float v[3]);
@@ -47,10 +47,10 @@ void BLI_quadric_clear(Quadric *q);
/* math */
void BLI_quadric_add_qu_qu(Quadric *a, const Quadric *b);
void BLI_quadric_add_qu_ququ(Quadric *r, const Quadric *a, const Quadric *b);
-void BLI_quadric_mul(Quadric *a, const float scalar);
+void BLI_quadric_mul(Quadric *a, const double scalar);
/* solve */
-float BLI_quadric_evaluate(const Quadric *q, const float v[3]);
+double BLI_quadric_evaluate(const Quadric *q, const float v_fl[3]);
bool BLI_quadric_optimize(const Quadric *q, float v[3], const float epsilon);
#endif /* __BLI_QUADRIC_H__ */
diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h
index a132ac40206..e0a0b34ac5f 100644
--- a/source/blender/blenlib/BLI_rect.h
+++ b/source/blender/blenlib/BLI_rect.h
@@ -89,6 +89,8 @@ void BLI_rctf_union(struct rctf *rctf1, const struct rctf *rctf2);
void BLI_rcti_rctf_copy(struct rcti *dst, const struct rctf *src);
void BLI_rctf_rcti_copy(struct rctf *dst, const struct rcti *src);
+void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle);
+
void print_rctf(const char *str, const struct rctf *rect);
void print_rcti(const char *str, const struct rcti *rect);
diff --git a/source/blender/blenlib/BLI_stack.h b/source/blender/blenlib/BLI_stack.h
index a8c4478c450..6d41e5feb88 100644
--- a/source/blender/blenlib/BLI_stack.h
+++ b/source/blender/blenlib/BLI_stack.h
@@ -48,6 +48,7 @@ void BLI_stack_pop(BLI_Stack *stack, void *dst) ATTR_NONNULL();
void *BLI_stack_peek(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BLI_stack_discard(BLI_Stack *stack) ATTR_NONNULL();
+void BLI_stack_clear(BLI_Stack *stack) ATTR_NONNULL();
size_t BLI_stack_count(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h
index c4853e37398..e6c1cc8b4b6 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -59,8 +59,10 @@ char *BLI_str_quoted_substrN(const char *__restrict str, const char *__restrict
char *BLI_replacestrN(const char *__restrict str, const char *__restrict substr_old, const char *__restrict substr_new) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC;
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...) ATTR_NONNULL(1, 3) ATTR_PRINTF_FORMAT(3, 4);
+size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...) ATTR_NONNULL(1, 3) ATTR_PRINTF_FORMAT(3, 4);
size_t BLI_vsnprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, va_list arg) ATTR_PRINTF_FORMAT(3, 0);
+size_t BLI_vsnprintf_rlen(char *__restrict buffer, size_t maxncpy, const char *__restrict format, va_list arg) ATTR_PRINTF_FORMAT(3, 0);
char *BLI_sprintfN(const char *__restrict format, ...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1, 2);
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 2eaec024ce2..780b0bfbbd6 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -88,6 +88,9 @@ void BLI_task_pool_cancel(TaskPool *pool);
/* stop all worker threads */
void BLI_task_pool_stop(TaskPool *pool);
+/* get number of threads allowed to be used by this pool */
+int BLI_pool_get_num_threads(TaskPool *pool);
+
/* set number of threads allowed to be used by this pool */
void BLI_pool_set_num_threads(TaskPool *pool, int num_threads);
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index 74291ca305e..18b8feaa99c 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -89,6 +89,7 @@ int BLI_system_num_threads_override_get(void);
#define LOCK_MOVIECLIP 7
#define LOCK_COLORMANAGE 8
#define LOCK_FFTW 9
+#define LOCK_VIEW3D 10
void BLI_lock_thread(int type);
void BLI_unlock_thread(int type);
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index 1e8440e55e9..8f2f906ed17 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -252,7 +252,7 @@ extern "C" {
#define FTOCHAR(val) ((CHECK_TYPE_INLINE(val, float)), \
(char)(((val) <= 0.0f) ? 0 : (((val) > (1.0f - 0.5f / 255.0f)) ? 255 : ((255.0f * (val)) + 0.5f))))
#define FTOUSHORT(val) ((CHECK_TYPE_INLINE(val, float)), \
- ((val >= 1.0f - 0.5f / 65535) ? 65535 : (val <= 0.0f) ? 0 : (unsigned short)(val * 65535.0f + 0.5f)))
+ (unsigned short)((val >= 1.0f - 0.5f / 65535) ? 65535 : (val <= 0.0f) ? 0 : (val * 65535.0f + 0.5f)))
#define USHORTTOUCHAR(val) ((unsigned char)(((val) >= 65535 - 128) ? 255 : ((val) + 128) >> 8))
#define F3TOCHAR3(v2, v1) { \
(v1)[0] = FTOCHAR((v2[0])); \
@@ -435,7 +435,7 @@ extern "C" {
} (void)0
/* assuming a static array */
-#if defined(__GNUC__) && !defined(__cplusplus)
+#if defined(__GNUC__) && !defined(__cplusplus) && !defined(__clang__)
# define ARRAY_SIZE(arr) \
((sizeof(struct {int isnt_array : ((const void *)&(arr) == &(arr)[0]);}) * 0) + \
(sizeof(arr) / sizeof(*(arr))))
@@ -493,8 +493,11 @@ extern "C" {
#define OFFSETOF_STRUCT(_struct, _member) \
((((char *)&((_struct)->_member)) - ((char *)(_struct))) + sizeof((_struct)->_member))
-/* memcpy, skipping the first part of a struct,
- * ensures 'struct_dst' isn't const and that the offset can be computed at compile time */
+/**
+ * memcpy helper, skipping the first part of a struct,
+ * ensures 'struct_dst' isn't const and the offset can be computed at compile time.
+ * This isn't inclusive, the value of \a member isn't copied.
+ */
#define MEMCPY_STRUCT_OFS(struct_dst, struct_src, member) { \
CHECK_TYPE_NONCONST(struct_dst); \
((void)(struct_dst == struct_src), \
@@ -503,6 +506,13 @@ extern "C" {
sizeof(*(struct_dst)) - OFFSETOF_STRUCT(struct_dst, member))); \
} (void)0
+#define MEMSET_STRUCT_OFS(struct_var, value, member) { \
+ CHECK_TYPE_NONCONST(struct_var); \
+ memset((char *)(struct_var) + OFFSETOF_STRUCT(struct_var, member), \
+ value, \
+ sizeof(*(struct_var)) - OFFSETOF_STRUCT(struct_var, member)); \
+} (void)0
+
/* Warning-free macros for storing ints in pointers. Use these _only_
* for storing an int in a pointer, not a pointer in an int (64bit)! */
#define SET_INT_IN_POINTER(i) ((void *)(intptr_t)(i))
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index e614a2a0663..e39202d35fd 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -44,6 +44,7 @@ set(SRC
intern/BLI_array.c
intern/BLI_dial.c
intern/BLI_dynstr.c
+ intern/BLI_filelist.c
intern/BLI_ghash.c
intern/BLI_heap.c
intern/BLI_kdopbvh.c
@@ -74,6 +75,7 @@ set(SRC
intern/listbase.c
intern/math_base.c
intern/math_base_inline.c
+ intern/math_bits_inline.c
intern/math_color.c
intern/math_color_blend_inline.c
intern/math_color_inline.c
@@ -153,6 +155,7 @@ set(SRC
BLI_listbase.h
BLI_math.h
BLI_math_base.h
+ BLI_math_bits.h
BLI_math_color.h
BLI_math_color_blend.h
BLI_math_geom.h
@@ -205,10 +208,15 @@ if(WIN32)
)
endif()
-blender_add_lib(bf_blenlib "${SRC}" "${INC}" "${INC_SYS}")
+# no need to compile object files for inline headers.
+set_source_files_properties(
+ intern/math_base_inline.c
+ intern/math_bits_inline.c
+ intern/math_color_blend_inline.c
+ intern/math_color_inline.c
+ intern/math_geom_inline.c
+ intern/math_vector_inline.c
+ PROPERTIES HEADER_FILE_ONLY TRUE
+)
-if(MSVC)
- # Quiet warning about inline math library files that do not export symbols.
- # (normally you'd exclude from project, but we still want to see the files in MSVC)
- set_target_properties(bf_blenlib PROPERTIES STATIC_LIBRARY_FLAGS /ignore:4221)
-endif()
+blender_add_lib(bf_blenlib "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/blenlib/intern/BLI_dynstr.c b/source/blender/blenlib/intern/BLI_dynstr.c
index 8617132e988..80cbce7e256 100644
--- a/source/blender/blenlib/intern/BLI_dynstr.c
+++ b/source/blender/blenlib/intern/BLI_dynstr.c
@@ -258,11 +258,11 @@ int BLI_dynstr_get_len(DynStr *ds)
/**
* Get a DynStr's contents as a c-string.
- * <i> The str argument must be allocated to be at
- * least the size of BLI_dynstr_get_len(ds) + 1. </i>
+ * he \a rets argument must be allocated to be at
+ * least the size of ``BLI_dynstr_get_len(ds) + 1``.
*
- * \param ds The DynStr of interest.
- * \param str The string to fill.
+ * \param ds: The DynStr of interest.
+ * \param rets: The string to fill.
*/
void BLI_dynstr_get_cstring_ex(DynStr *__restrict ds, char *__restrict rets)
{
diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c
new file mode 100644
index 00000000000..f700a12fbca
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_filelist.c
@@ -0,0 +1,398 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenlib/intern/BLI_filelist.c
+ * \ingroup bli
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef WIN32
+# include <dirent.h>
+#endif
+
+#include <time.h>
+#include <sys/stat.h>
+#include <string.h> /* strcpy etc.. */
+
+#ifdef WIN32
+# include <io.h>
+# include <direct.h>
+# include "BLI_winstuff.h"
+# include "utfconv.h"
+#else
+# include <sys/ioctl.h>
+# include <unistd.h>
+# include <pwd.h>
+#endif
+
+/* lib includes */
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_fileops.h"
+#include "BLI_fileops_types.h"
+#include "BLI_path_util.h"
+
+#include "../imbuf/IMB_imbuf.h"
+
+
+/*
+ * Ordering function for sorting lists of files/directories. Returns -1 if
+ * entry1 belongs before entry2, 0 if they are equal, 1 if they should be swapped.
+ */
+static int bli_compare(struct direntry *entry1, struct direntry *entry2)
+{
+ /* type is equal to stat.st_mode */
+
+ /* directories come before non-directories */
+ if (S_ISDIR(entry1->type)) {
+ if (S_ISDIR(entry2->type) == 0) return (-1);
+ }
+ else {
+ if (S_ISDIR(entry2->type)) return (1);
+ }
+ /* non-regular files come after regular files */
+ if (S_ISREG(entry1->type)) {
+ if (S_ISREG(entry2->type) == 0) return (-1);
+ }
+ else {
+ if (S_ISREG(entry2->type)) return (1);
+ }
+ /* arbitrary, but consistent, ordering of different types of non-regular files */
+ if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
+ if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
+
+ /* OK, now we know their S_IFMT fields are the same, go on to a name comparison */
+ /* make sure "." and ".." are always first */
+ if (FILENAME_IS_CURRENT(entry1->relname)) return (-1);
+ if (FILENAME_IS_CURRENT(entry2->relname)) return (1);
+ if (FILENAME_IS_PARENT(entry1->relname)) return (-1);
+ if (FILENAME_IS_PARENT(entry2->relname)) return (1);
+
+ return (BLI_natstrcmp(entry1->relname, entry2->relname));
+}
+
+
+struct BuildDirCtx {
+ struct direntry *files; /* array[nrfiles] */
+ int nrfiles;
+};
+
+/**
+ * Scans the directory named *dirname and appends entries for its contents to files.
+ */
+static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
+{
+ struct ListBase dirbase = {NULL, NULL};
+ int newnum = 0;
+ DIR *dir;
+
+ if ((dir = opendir(dirname)) != NULL) {
+ const struct dirent *fname;
+ bool has_current = false, has_parent = false;
+
+ while ((fname = readdir(dir)) != NULL) {
+ struct dirlink * const dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
+ if (dlink != NULL) {
+ dlink->name = BLI_strdup(fname->d_name);
+ if (FILENAME_IS_PARENT(dlink->name)) {
+ has_parent = true;
+ }
+ else if (FILENAME_IS_CURRENT(dlink->name)) {
+ has_current = true;
+ }
+ BLI_addhead(&dirbase, dlink);
+ newnum++;
+ }
+ }
+
+ if (!has_parent) {
+ char pardir[FILE_MAXDIR];
+
+ BLI_strncpy(pardir, dirname, sizeof(pardir));
+ if (BLI_parent_dir(pardir) && (BLI_access(pardir, R_OK) == 0)) {
+ struct dirlink * const dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
+ if (dlink != NULL) {
+ dlink->name = BLI_strdup(FILENAME_PARENT);
+ BLI_addhead(&dirbase, dlink);
+ newnum++;
+ }
+ }
+ }
+ if (!has_current) {
+ struct dirlink * const dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
+ if (dlink != NULL) {
+ dlink->name = BLI_strdup(FILENAME_CURRENT);
+ BLI_addhead(&dirbase, dlink);
+ newnum++;
+ }
+ }
+
+ if (newnum) {
+ if (dir_ctx->files) {
+ void * const tmp = MEM_reallocN(dir_ctx->files, (dir_ctx->nrfiles + newnum) * sizeof(struct direntry));
+ if (tmp) {
+ dir_ctx->files = (struct direntry *)tmp;
+ }
+ else { /* realloc fail */
+ MEM_freeN(dir_ctx->files);
+ dir_ctx->files = NULL;
+ }
+ }
+
+ if (dir_ctx->files == NULL)
+ dir_ctx->files = (struct direntry *)MEM_mallocN(newnum * sizeof(struct direntry), __func__);
+
+ if (dir_ctx->files) {
+ struct dirlink * dlink = (struct dirlink *) dirbase.first;
+ struct direntry *file = &dir_ctx->files[dir_ctx->nrfiles];
+ while (dlink) {
+ char fullname[PATH_MAX];
+ memset(file, 0, sizeof(struct direntry));
+ file->relname = dlink->name;
+ file->path = BLI_strdupcat(dirname, dlink->name);
+ BLI_join_dirfile(fullname, sizeof(fullname), dirname, dlink->name);
+ if (BLI_stat(fullname, &file->s) != -1) {
+ file->type = file->s.st_mode;
+ }
+ else if (FILENAME_IS_CURRPAR(file->relname)) {
+ /* Hack around for UNC paths on windows - does not support stat on '\\SERVER\foo\..', sigh... */
+ file->type |= S_IFDIR;
+ }
+ file->flags = 0;
+ dir_ctx->nrfiles++;
+ file++;
+ dlink = dlink->next;
+ }
+ }
+ else {
+ printf("Couldn't get memory for dir\n");
+ exit(1);
+ }
+
+ BLI_freelist(&dirbase);
+ if (dir_ctx->files) {
+ qsort(dir_ctx->files, dir_ctx->nrfiles, sizeof(struct direntry), (int (*)(const void *, const void *))bli_compare);
+ }
+ }
+ else {
+ printf("%s empty directory\n", dirname);
+ }
+
+ closedir(dir);
+ }
+ else {
+ printf("%s non-existent directory\n", dirname);
+ }
+}
+
+/**
+ * Fills in the "mode[123]", "size" and "string" fields in the elements of the files
+ * array with descriptive details about each item. "string" will have a format similar to "ls -l".
+ */
+static void bli_adddirstrings(struct BuildDirCtx *dir_ctx)
+{
+ const char *types[8] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
+ /* symbolic display, indexed by mode field value */
+ int num;
+ struct direntry *file;
+ struct tm *tm;
+ time_t zero = 0;
+
+#ifndef WIN32
+ int mode;
+#endif
+
+ for (num = 0, file = dir_ctx->files; num < dir_ctx->nrfiles; num++, file++) {
+
+ /* Mode */
+#ifdef WIN32
+ BLI_strncpy(file->mode1, types[0], sizeof(file->mode1));
+ BLI_strncpy(file->mode2, types[0], sizeof(file->mode2));
+ BLI_strncpy(file->mode3, types[0], sizeof(file->mode3));
+#else
+ mode = file->s.st_mode;
+
+ BLI_strncpy(file->mode1, types[(mode & 0700) >> 6], sizeof(file->mode1));
+ BLI_strncpy(file->mode2, types[(mode & 0070) >> 3], sizeof(file->mode2));
+ BLI_strncpy(file->mode3, types[(mode & 0007)], sizeof(file->mode3));
+
+ if (((mode & S_ISGID) == S_ISGID) && (file->mode2[2] == '-')) file->mode2[2] = 'l';
+
+ if (mode & (S_ISUID | S_ISGID)) {
+ if (file->mode1[2] == 'x') file->mode1[2] = 's';
+ else file->mode1[2] = 'S';
+
+ if (file->mode2[2] == 'x') file->mode2[2] = 's';
+ }
+
+ if (mode & S_ISVTX) {
+ if (file->mode3[2] == 'x') file->mode3[2] = 't';
+ else file->mode3[2] = 'T';
+ }
+#endif
+
+
+ /* User */
+#ifdef WIN32
+ strcpy(file->owner, "user");
+#else
+ {
+ struct passwd *pwuser;
+ pwuser = getpwuid(file->s.st_uid);
+ if (pwuser) {
+ BLI_strncpy(file->owner, pwuser->pw_name, sizeof(file->owner));
+ }
+ else {
+ BLI_snprintf(file->owner, sizeof(file->owner), "%u", file->s.st_uid);
+ }
+ }
+#endif
+
+
+ /* Time */
+ tm = localtime(&file->s.st_mtime);
+ // prevent impossible dates in windows
+ if (tm == NULL) tm = localtime(&zero);
+ strftime(file->time, sizeof(file->time), "%H:%M", tm);
+ strftime(file->date, sizeof(file->date), "%d-%b-%y", tm);
+
+
+ /* Size */
+ /*
+ * Seems st_size is signed 32-bit value in *nix and Windows. This
+ * will buy us some time until files get bigger than 4GB or until
+ * everyone starts using __USE_FILE_OFFSET64 or equivalent.
+ */
+ file->realsize = file->s.st_size;
+
+ BLI_file_size_string(file->realsize, file->size, sizeof(file->size));
+ }
+}
+
+void BLI_file_size_string(off_t st_size, char *size, size_t len)
+{
+ if (st_size > 1024 * 1024 * 1024) {
+ BLI_snprintf(size, len, "%.2f GiB", ((double)st_size) / (1024 * 1024 * 1024));
+ }
+ else if (st_size > 1024 * 1024) {
+ BLI_snprintf(size, len, "%.1f MiB", ((double)st_size) / (1024 * 1024));
+ }
+ else if (st_size > 1024) {
+ BLI_snprintf(size, len, "%d KiB", (int)(st_size / 1024));
+ }
+ else {
+ BLI_snprintf(size, len, "%d B", (int)st_size);
+ }
+}
+
+/**
+ * Scans the contents of the directory named *dirname, and allocates and fills in an
+ * array of entries describing them in *filelist.
+ *
+ * \return The length of filelist array.
+ */
+unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **filelist)
+{
+ struct BuildDirCtx dir_ctx;
+
+ dir_ctx.nrfiles = 0;
+ dir_ctx.files = NULL;
+
+ bli_builddir(&dir_ctx, dirname);
+ bli_adddirstrings(&dir_ctx);
+
+ if (dir_ctx.files) {
+ *filelist = dir_ctx.files;
+ }
+ else {
+ // keep blender happy. Blender stores this in a variable
+ // where 0 has special meaning.....
+ *filelist = MEM_mallocN(sizeof(**filelist), __func__);
+ }
+
+ return dir_ctx.nrfiles;
+}
+
+/**
+ * Deep-duplicate of an array of direntries, including the array itself.
+ *
+ * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over.
+ */
+void BLI_filelist_duplicate(
+ struct direntry **dest_filelist, struct direntry *src_filelist, unsigned int nrentries,
+ void *(*dup_poin)(void *))
+{
+ unsigned int i;
+
+ *dest_filelist = MEM_mallocN(sizeof(**dest_filelist) * (size_t)(nrentries), __func__);
+ for (i = 0; i < nrentries; ++i) {
+ struct direntry * const src = &src_filelist[i];
+ struct direntry *dest = &(*dest_filelist)[i];
+ *dest = *src;
+ if (dest->image) {
+ dest->image = IMB_dupImBuf(src->image);
+ }
+ if (dest->relname) {
+ dest->relname = MEM_dupallocN(src->relname);
+ }
+ if (dest->path) {
+ dest->path = MEM_dupallocN(src->path);
+ }
+ if (dest->poin && dup_poin) {
+ dest->poin = dup_poin(src->poin);
+ }
+ if (dest->collapsed_info.darray) {
+ dest->collapsed_info.darray = NULL;
+ }
+ }
+}
+
+/**
+ * frees storage for an array of direntries, including the array itself.
+ */
+void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries, void (*free_poin)(void *))
+{
+ unsigned int i;
+ for (i = 0; i < nrentries; ++i) {
+ struct direntry *entry = filelist + i;
+ if (entry->image) {
+ IMB_freeImBuf(entry->image);
+ }
+ if (entry->relname)
+ MEM_freeN(entry->relname);
+ if (entry->path)
+ MEM_freeN(entry->path);
+ if (entry->poin && free_poin)
+ free_poin(entry->poin);
+ if (entry->collapsed_info.darray)
+ MEM_freeN(entry->collapsed_info.darray);
+ }
+
+ if (filelist != NULL) {
+ MEM_freeN(filelist);
+ }
+}
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index 5360ea744a1..9287d62a683 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -36,17 +36,23 @@
#include <string.h>
#include <stdlib.h>
+#include <stdarg.h>
#include <limits.h>
#include "MEM_guardedalloc.h"
#include "BLI_sys_types.h" /* for intptr_t support */
#include "BLI_utildefines.h"
+#include "BLI_hash_mm2a.h"
#include "BLI_mempool.h"
+
+#define GHASH_INTERNAL_API
#include "BLI_ghash.h"
#include "BLI_strict_flags.h"
+#define GHASH_USE_MODULO_BUCKETS
+/* Also used by smallhash! */
const unsigned int hashsizes[] = {
5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209,
16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169,
@@ -54,24 +60,43 @@ const unsigned int hashsizes[] = {
268435459
};
-/* internal flag to ensure sets values aren't used */
-#ifndef NDEBUG
-# define GHASH_FLAG_IS_SET (1 << 8)
-# define IS_GHASH_ASSERT(gh) BLI_assert((gh->flag & GHASH_FLAG_IS_SET) == 0)
-// # define IS_GSET_ASSERT(gs) BLI_assert((gs->flag & GHASH_FLAG_IS_SET) != 0)
+#ifdef GHASH_USE_MODULO_BUCKETS
+# define GHASH_MAX_SIZE 27
#else
-# define IS_GHASH_ASSERT(gh)
-// # define IS_GSET_ASSERT(eh)
+# define GHASH_BUCKET_BIT_MIN 2
+# define GHASH_BUCKET_BIT_MAX 28 /* About 268M of buckets... */
#endif
+/**
+ * \note Max load #GHASH_LIMIT_GROW used to be 3. (pre 2.74).
+ * Python uses 0.6666, tommyhaslib even goes down to 0.5.
+ * Reducing our from 3 to 0.75 gives huge speedup (about twice quicker pure GHash insertions/lookup,
+ * about 25% - 30% quicker 'dynamic-topology' stroke drawing e.g.).
+ * Min load #GHASH_LIMIT_SHRINK is a quarter of max load, to avoid resizing to quickly.
+ */
+#define GHASH_LIMIT_GROW(_nbkt) (((_nbkt) * 3) / 4)
+#define GHASH_LIMIT_SHRINK(_nbkt) (((_nbkt) * 3) / 16)
+
/***/
+/* WARNING! Keep in sync with ugly _gh_Entry in header!!! */
typedef struct Entry {
struct Entry *next;
- void *key, *val;
+ void *key;
} Entry;
+typedef struct GHashEntry {
+ Entry e;
+
+ void *val;
+} GHashEntry;
+
+typedef Entry GSetEntry;
+
+#define GHASH_ENTRY_SIZE(_is_gset) \
+ ((_is_gset) ? sizeof(GSetEntry) : sizeof(GHashEntry))
+
struct GHash {
GHashHashFP hashfp;
GHashCmpFP cmpfp;
@@ -79,11 +104,34 @@ struct GHash {
Entry **buckets;
struct BLI_mempool *entrypool;
unsigned int nbuckets;
+ unsigned int limit_grow, limit_shrink;
+#ifdef GHASH_USE_MODULO_BUCKETS
+ unsigned int cursize, size_min;
+#else
+ unsigned int bucket_mask, bucket_bit, bucket_bit_min;
+#endif
+
unsigned int nentries;
- unsigned int cursize, flag;
+ unsigned int flag;
};
+BLI_INLINE void ghash_entry_copy(
+ GHash *gh_dst, Entry *dst, GHash *gh_src, Entry *src,
+ GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp)
+{
+ dst->key = (keycopyfp) ? keycopyfp(src->key) : src->key;
+
+ if ((gh_dst->flag & GHASH_FLAG_IS_GSET) == 0) {
+ if ((gh_src->flag & GHASH_FLAG_IS_GSET) == 0) {
+ ((GHashEntry *)dst)->val = (valcopyfp) ? valcopyfp(((GHashEntry *)src)->val) : ((GHashEntry *)src)->val;
+ }
+ else {
+ ((GHashEntry *)dst)->val = NULL;
+ }
+ }
+}
+
/* -------------------------------------------------------------------- */
/* GHash API */
@@ -91,25 +139,37 @@ struct GHash {
* \{ */
/**
- * Get the hash for a key.
+ * Get the full hash for a key.
*/
BLI_INLINE unsigned int ghash_keyhash(GHash *gh, const void *key)
{
- return gh->hashfp(key) % gh->nbuckets;
+ return gh->hashfp(key);
}
/**
- * Check if the number of items in the GHash is large enough to require more buckets.
+ * Get the full hash for an entry.
*/
-BLI_INLINE bool ghash_test_expand_buckets(const unsigned int nentries, const unsigned int nbuckets)
+BLI_INLINE unsigned int ghash_entryhash(GHash *gh, const Entry *e)
{
- return (nentries > nbuckets * 3);
+ return gh->hashfp(e->key);
}
/**
- * Expand buckets to the next size up.
+ * Get the bucket-hash for an already-computed full hash.
*/
-BLI_INLINE void ghash_resize_buckets(GHash *gh, const unsigned int nbuckets)
+BLI_INLINE unsigned int ghash_bucket_index(GHash *gh, const unsigned int hash)
+{
+#ifdef GHASH_USE_MODULO_BUCKETS
+ return hash % gh->nbuckets;
+#else
+ return hash & gh->bucket_mask;
+#endif
+}
+
+/**
+ * Expand buckets to the next size up or down.
+ */
+static void ghash_buckets_resize(GHash *gh, const unsigned int nbuckets)
{
Entry **buckets_old = gh->buckets;
Entry **buckets_new;
@@ -117,49 +177,223 @@ BLI_INLINE void ghash_resize_buckets(GHash *gh, const unsigned int nbuckets)
unsigned int i;
Entry *e;
- BLI_assert(gh->nbuckets != nbuckets);
+ BLI_assert((gh->nbuckets != nbuckets) || !gh->buckets);
+// printf("%s: %d -> %d\n", __func__, nbuckets_old, nbuckets);
gh->nbuckets = nbuckets;
- buckets_new = (Entry **)MEM_callocN(gh->nbuckets * sizeof(*gh->buckets), "buckets");
-
- for (i = 0; i < nbuckets_old; i++) {
- Entry *e_next;
- for (e = buckets_old[i]; e; e = e_next) {
- const unsigned hash = ghash_keyhash(gh, e->key);
- e_next = e->next;
- e->next = buckets_new[hash];
- buckets_new[hash] = e;
+#ifdef GHASH_USE_MODULO_BUCKETS
+#else
+ gh->bucket_mask = nbuckets - 1;
+#endif
+
+ buckets_new = (Entry **)MEM_callocN(sizeof(*gh->buckets) * gh->nbuckets, __func__);
+
+ if (buckets_old) {
+ if (nbuckets > nbuckets_old) {
+ for (i = 0; i < nbuckets_old; i++) {
+ Entry *e_next;
+ for (e = buckets_old[i]; e; e = e_next) {
+ const unsigned hash = ghash_entryhash(gh, e);
+ const unsigned bucket_index = ghash_bucket_index(gh, hash);
+ e_next = e->next;
+ e->next = buckets_new[bucket_index];
+ buckets_new[bucket_index] = e;
+ }
+ }
+ }
+ else {
+ for (i = 0; i < nbuckets_old; i++) {
+#ifdef GHASH_USE_MODULO_BUCKETS
+ Entry *e_next;
+ for (e = buckets_old[i]; e; e = e_next) {
+ const unsigned hash = ghash_entryhash(gh, e);
+ const unsigned bucket_index = ghash_bucket_index(gh, hash);
+ e_next = e->next;
+ e->next = buckets_new[bucket_index];
+ buckets_new[bucket_index] = e;
+ }
+#else
+ /* No need to recompute hashes in this case, since our mask is just smaller, all items in old bucket i
+ * will go in same new bucket (i & new_mask)! */
+ const unsigned bucket_index = ghash_bucket_index(gh, i);
+ BLI_assert(!buckets_old[i] || (bucket_index == ghash_bucket_index(gh, ghash_entryhash(gh, buckets_old[i]))));
+ for (e = buckets_old[i]; e && e->next; e = e->next);
+ if (e) {
+ e->next = buckets_new[bucket_index];
+ buckets_new[bucket_index] = buckets_old[i];
+ }
+#endif
+ }
}
}
gh->buckets = buckets_new;
- MEM_freeN(buckets_old);
+ if (buckets_old) {
+ MEM_freeN(buckets_old);
+ }
}
/**
- * Increase initial bucket size to match a reserved amount.
+ * Check if the number of items in the GHash is large enough to require more buckets,
+ * or small enough to require less buckets, and resize \a gh accordingly.
*/
-BLI_INLINE void ghash_buckets_reserve(GHash *gh, const unsigned int nentries_reserve)
+static void ghash_buckets_expand(
+ GHash *gh, const unsigned int nentries, const bool user_defined)
{
- while (ghash_test_expand_buckets(nentries_reserve, gh->nbuckets)) {
- gh->nbuckets = hashsizes[++gh->cursize];
+ unsigned int new_nbuckets;
+
+ if (LIKELY(gh->buckets && (nentries < gh->limit_grow))) {
+ return;
+ }
+
+ new_nbuckets = gh->nbuckets;
+
+#ifdef GHASH_USE_MODULO_BUCKETS
+ while ((nentries > gh->limit_grow) &&
+ (gh->cursize < GHASH_MAX_SIZE - 1))
+ {
+ new_nbuckets = hashsizes[++gh->cursize];
+ gh->limit_grow = GHASH_LIMIT_GROW(new_nbuckets);
}
+#else
+ while ((nentries > gh->limit_grow) &&
+ (gh->bucket_bit < GHASH_BUCKET_BIT_MAX))
+ {
+ new_nbuckets = 1u << ++gh->bucket_bit;
+ gh->limit_grow = GHASH_LIMIT_GROW(new_nbuckets);
+ }
+#endif
+
+ if (user_defined) {
+#ifdef GHASH_USE_MODULO_BUCKETS
+ gh->size_min = gh->cursize;
+#else
+ gh->bucket_bit_min = gh->bucket_bit;
+#endif
+ }
+
+ if ((new_nbuckets == gh->nbuckets) && gh->buckets) {
+ return;
+ }
+
+ gh->limit_grow = GHASH_LIMIT_GROW(new_nbuckets);
+ gh->limit_shrink = GHASH_LIMIT_SHRINK(new_nbuckets);
+ ghash_buckets_resize(gh, new_nbuckets);
+}
+
+static void ghash_buckets_contract(
+ GHash *gh, const unsigned int nentries, const bool user_defined, const bool force_shrink)
+{
+ unsigned int new_nbuckets;
+
+ if (!(force_shrink || (gh->flag & GHASH_FLAG_ALLOW_SHRINK))) {
+ return;
+ }
+
+ if (LIKELY(gh->buckets && (nentries > gh->limit_shrink))) {
+ return;
+ }
+
+ new_nbuckets = gh->nbuckets;
+
+#ifdef GHASH_USE_MODULO_BUCKETS
+ while ((nentries < gh->limit_shrink) &&
+ (gh->cursize > gh->size_min))
+ {
+ new_nbuckets = hashsizes[--gh->cursize];
+ gh->limit_shrink = GHASH_LIMIT_SHRINK(new_nbuckets);
+ }
+#else
+ while ((nentries < gh->limit_shrink) &&
+ (gh->bucket_bit > gh->bucket_bit_min))
+ {
+ new_nbuckets = 1u << --gh->bucket_bit;
+ gh->limit_shrink = GHASH_LIMIT_SHRINK(new_nbuckets);
+ }
+#endif
+
+ if (user_defined) {
+#ifdef GHASH_USE_MODULO_BUCKETS
+ gh->size_min = gh->cursize;
+#else
+ gh->bucket_bit_min = gh->bucket_bit;
+#endif
+ }
+
+ if ((new_nbuckets == gh->nbuckets) && gh->buckets) {
+ return;
+ }
+
+ gh->limit_grow = GHASH_LIMIT_GROW(new_nbuckets);
+ gh->limit_shrink = GHASH_LIMIT_SHRINK(new_nbuckets);
+ ghash_buckets_resize(gh, new_nbuckets);
+}
+
+/**
+ * Clear and reset \a gh buckets, reserve again buckets for given number of entries.
+ */
+BLI_INLINE void ghash_buckets_reset(GHash *gh, const unsigned int nentries)
+{
+ MEM_SAFE_FREE(gh->buckets);
+
+#ifdef GHASH_USE_MODULO_BUCKETS
+ gh->cursize = 0;
+ gh->size_min = 0;
+ gh->nbuckets = hashsizes[gh->cursize];
+#else
+ gh->bucket_bit = GHASH_BUCKET_BIT_MIN;
+ gh->bucket_bit_min = GHASH_BUCKET_BIT_MIN;
+ gh->nbuckets = 1u << gh->bucket_bit;
+ gh->bucket_mask = gh->nbuckets - 1;
+#endif
+
+ gh->limit_grow = GHASH_LIMIT_GROW(gh->nbuckets);
+ gh->limit_shrink = GHASH_LIMIT_SHRINK(gh->nbuckets);
+
+ gh->nentries = 0;
+
+ ghash_buckets_expand(gh, nentries, (nentries != 0));
}
/**
* Internal lookup function.
- * Takes a hash argument to avoid calling #ghash_keyhash multiple times.
+ * Takes hash and bucket_index arguments to avoid calling #ghash_keyhash and #ghash_bucket_index multiple times.
*/
-BLI_INLINE Entry *ghash_lookup_entry_ex(GHash *gh, const void *key,
- const unsigned int hash)
+BLI_INLINE Entry *ghash_lookup_entry_ex(
+ GHash *gh, const void *key, const unsigned int bucket_index)
{
Entry *e;
+ /* If we do not store GHash, not worth computing it for each entry here!
+ * Typically, comparison function will be quicker, and since it's needed in the end anyway... */
+ for (e = gh->buckets[bucket_index]; e; e = e->next) {
+ if (UNLIKELY(gh->cmpfp(key, e->key) == false)) {
+ return e;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Internal lookup function, returns previous entry of target one too.
+ * Takes hash and bucket_index arguments to avoid calling #ghash_keyhash and #ghash_bucket_index multiple times.
+ * Useful when modifying buckets somehow (like removing an entry...).
+ */
+BLI_INLINE Entry *ghash_lookup_entry_prev_ex(
+ GHash *gh, const void *key, Entry **r_e_prev, const unsigned int bucket_index)
+{
+ Entry *e, *e_prev = NULL;
- for (e = gh->buckets[hash]; e; e = e->next) {
+ /* If we do not store GHash, not worth computing it for each entry here!
+ * Typically, comparison function will be quicker, and since it's needed in the end anyway... */
+ for (e = gh->buckets[bucket_index]; e; e_prev = e, e = e->next) {
if (UNLIKELY(gh->cmpfp(key, e->key) == false)) {
+ *r_e_prev = e_prev;
return e;
}
}
+
+ *r_e_prev = NULL;
return NULL;
}
@@ -169,105 +403,157 @@ BLI_INLINE Entry *ghash_lookup_entry_ex(GHash *gh, const void *key,
BLI_INLINE Entry *ghash_lookup_entry(GHash *gh, const void *key)
{
const unsigned int hash = ghash_keyhash(gh, key);
- return ghash_lookup_entry_ex(gh, key, hash);
+ const unsigned int bucket_index = ghash_bucket_index(gh, hash);
+ return ghash_lookup_entry_ex(gh, key, bucket_index);
}
static GHash *ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info,
- const unsigned int nentries_reserve,
- const unsigned int entry_size)
+ const unsigned int nentries_reserve, const unsigned int flag)
{
GHash *gh = MEM_mallocN(sizeof(*gh), info);
gh->hashfp = hashfp;
gh->cmpfp = cmpfp;
- gh->nbuckets = hashsizes[0]; /* gh->cursize */
- gh->nentries = 0;
- gh->cursize = 0;
- gh->flag = 0;
+ gh->buckets = NULL;
+ gh->flag = flag;
- /* if we have reserved the number of elements that this hash will contain */
- if (nentries_reserve) {
- ghash_buckets_reserve(gh, nentries_reserve);
- }
-
- gh->buckets = MEM_callocN(gh->nbuckets * sizeof(*gh->buckets), "buckets");
- gh->entrypool = BLI_mempool_create(entry_size, 64, 64, BLI_MEMPOOL_NOP);
+ ghash_buckets_reset(gh, nentries_reserve);
+ gh->entrypool = BLI_mempool_create(GHASH_ENTRY_SIZE(flag & GHASH_FLAG_IS_GSET), 64, 64, BLI_MEMPOOL_NOP);
return gh;
}
/**
* Internal insert function.
- * Takes a hash argument to avoid calling #ghash_keyhash multiple times.
+ * Takes hash and bucket_index arguments to avoid calling #ghash_keyhash and #ghash_bucket_index multiple times.
*/
-BLI_INLINE void ghash_insert_ex(GHash *gh, void *key, void *val,
- unsigned int hash)
+BLI_INLINE void ghash_insert_ex(
+ GHash *gh, void *key, void *val, const unsigned int bucket_index)
{
- Entry *e = (Entry *)BLI_mempool_alloc(gh->entrypool);
+ GHashEntry *e = BLI_mempool_alloc(gh->entrypool);
+
BLI_assert((gh->flag & GHASH_FLAG_ALLOW_DUPES) || (BLI_ghash_haskey(gh, key) == 0));
- IS_GHASH_ASSERT(gh);
+ BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
- e->next = gh->buckets[hash];
- e->key = key;
+ e->e.next = gh->buckets[bucket_index];
+ e->e.key = key;
e->val = val;
- gh->buckets[hash] = e;
+ gh->buckets[bucket_index] = (Entry *)e;
- if (UNLIKELY(ghash_test_expand_buckets(++gh->nentries, gh->nbuckets))) {
- ghash_resize_buckets(gh, hashsizes[++gh->cursize]);
- }
+ ghash_buckets_expand(gh, ++gh->nentries, false);
+}
+
+/**
+ * Insert function that takes a pre-allocated entry.
+ */
+BLI_INLINE void ghash_insert_ex_keyonly_entry(
+ GHash *gh, void *key, const unsigned int bucket_index,
+ Entry *e)
+{
+ BLI_assert((gh->flag & GHASH_FLAG_ALLOW_DUPES) || (BLI_ghash_haskey(gh, key) == 0));
+
+ e->next = gh->buckets[bucket_index];
+ e->key = key;
+ gh->buckets[bucket_index] = e;
+
+ ghash_buckets_expand(gh, ++gh->nentries, false);
}
/**
* Insert function that doesn't set the value (use for GSet)
*/
-BLI_INLINE void ghash_insert_ex_keyonly(GHash *gh, void *key,
- unsigned int hash)
+BLI_INLINE void ghash_insert_ex_keyonly(
+ GHash *gh, void *key, const unsigned int bucket_index)
{
- Entry *e = (Entry *)BLI_mempool_alloc(gh->entrypool);
+ Entry *e = BLI_mempool_alloc(gh->entrypool);
+
BLI_assert((gh->flag & GHASH_FLAG_ALLOW_DUPES) || (BLI_ghash_haskey(gh, key) == 0));
- e->next = gh->buckets[hash];
+ BLI_assert((gh->flag & GHASH_FLAG_IS_GSET) != 0);
+
+ e->next = gh->buckets[bucket_index];
e->key = key;
- /* intentionally leave value unset */
- gh->buckets[hash] = e;
+ gh->buckets[bucket_index] = e;
- if (UNLIKELY(ghash_test_expand_buckets(++gh->nentries, gh->nbuckets))) {
- ghash_resize_buckets(gh, hashsizes[++gh->cursize]);
- }
+ ghash_buckets_expand(gh, ++gh->nentries, false);
}
BLI_INLINE void ghash_insert(GHash *gh, void *key, void *val)
{
const unsigned int hash = ghash_keyhash(gh, key);
- ghash_insert_ex(gh, key, val, hash);
+ const unsigned int bucket_index = ghash_bucket_index(gh, hash);
+
+ ghash_insert_ex(gh, key, val, bucket_index);
+}
+
+BLI_INLINE bool ghash_insert_safe(
+ GHash *gh, void *key, void *val, const bool override, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
+{
+ const unsigned int hash = ghash_keyhash(gh, key);
+ const unsigned int bucket_index = ghash_bucket_index(gh, hash);
+ GHashEntry *e = (GHashEntry *)ghash_lookup_entry_ex(gh, key, bucket_index);
+
+ BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
+
+ if (e) {
+ if (override) {
+ if (keyfreefp) keyfreefp(e->e.key);
+ if (valfreefp) valfreefp(e->val);
+ e->e.key = key;
+ e->val = val;
+ }
+ return false;
+ }
+ else {
+ ghash_insert_ex(gh, key, val, bucket_index);
+ return true;
+ }
+}
+
+BLI_INLINE bool ghash_insert_safe_keyonly(GHash *gh, void *key, const bool override, GHashKeyFreeFP keyfreefp)
+{
+ const unsigned int hash = ghash_keyhash(gh, key);
+ const unsigned int bucket_index = ghash_bucket_index(gh, hash);
+ Entry *e = ghash_lookup_entry_ex(gh, key, bucket_index);
+
+ BLI_assert((gh->flag & GHASH_FLAG_IS_GSET) != 0);
+
+ if (e) {
+ if (override) {
+ if (keyfreefp) keyfreefp(e->key);
+ e->key = key;
+ }
+ return false;
+ }
+ else {
+ ghash_insert_ex_keyonly(gh, key, bucket_index);
+ return true;
+ }
}
/**
* Remove the entry and return it, caller must free from gh->entrypool.
*/
-static Entry *ghash_remove_ex(GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp,
- unsigned int hash)
+static Entry *ghash_remove_ex(
+ GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp,
+ const unsigned int bucket_index)
{
- Entry *e;
- Entry *e_prev = NULL;
+ Entry *e_prev;
+ Entry *e = ghash_lookup_entry_prev_ex(gh, key, &e_prev, bucket_index);
- for (e = gh->buckets[hash]; e; e = e->next) {
- if (UNLIKELY(gh->cmpfp(key, e->key) == false)) {
- Entry *e_next = e->next;
+ BLI_assert(!valfreefp || !(gh->flag & GHASH_FLAG_IS_GSET));
- if (keyfreefp) keyfreefp(e->key);
- if (valfreefp) valfreefp(e->val);
+ if (e) {
+ if (keyfreefp) keyfreefp(e->key);
+ if (valfreefp) valfreefp(((GHashEntry *)e)->val);
- if (e_prev) e_prev->next = e_next;
- else gh->buckets[hash] = e_next;
+ if (e_prev) e_prev->next = e->next;
+ else gh->buckets[bucket_index] = e->next;
- gh->nentries--;
- return e;
- }
- e_prev = e;
+ ghash_buckets_contract(gh, --gh->nentries, false, false);
}
- return NULL;
+ return e;
}
/**
@@ -277,21 +563,57 @@ static void ghash_free_cb(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP va
{
unsigned int i;
- BLI_assert(keyfreefp || valfreefp);
+ BLI_assert(keyfreefp || valfreefp);
+ BLI_assert(!valfreefp || !(gh->flag & GHASH_FLAG_IS_GSET));
for (i = 0; i < gh->nbuckets; i++) {
Entry *e;
- for (e = gh->buckets[i]; e; ) {
- Entry *e_next = e->next;
-
+ for (e = gh->buckets[i]; e; e = e->next) {
if (keyfreefp) keyfreefp(e->key);
- if (valfreefp) valfreefp(e->val);
+ if (valfreefp) valfreefp(((GHashEntry *)e)->val);
+ }
+ }
+}
+
+/**
+ * Copy the GHash.
+ */
+static GHash *ghash_copy(GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp)
+{
+ GHash *gh_new;
+ unsigned int i;
+ /* This allows us to be sure to get the same number of buckets in gh_new as in ghash. */
+ const unsigned int reserve_nentries_new = MAX2(GHASH_LIMIT_GROW(gh->nbuckets) - 1, gh->nentries);
+
+ BLI_assert(!valcopyfp || !(gh->flag & GHASH_FLAG_IS_GSET));
- e = e_next;
+ gh_new = ghash_new(gh->hashfp, gh->cmpfp, __func__, 0, gh->flag);
+ ghash_buckets_expand(gh_new, reserve_nentries_new, false);
+
+ BLI_assert(gh_new->nbuckets == gh->nbuckets);
+
+ for (i = 0; i < gh->nbuckets; i++) {
+ Entry *e;
+
+ for (e = gh->buckets[i]; e; e = e->next) {
+ Entry *e_new = BLI_mempool_alloc(gh_new->entrypool);
+ ghash_entry_copy(gh_new, e_new, gh, e, keycopyfp, valcopyfp);
+
+ /* Warning!
+ * This means entries in buckets in new copy will be in reversed order!
+ * This shall not be an issue though, since order should never be assumed in ghash. */
+
+ /* Note: We can use 'i' here, since we are sure that 'gh' and 'gh_new' have the same number of buckets! */
+ e_new->next = gh_new->buckets[i];
+ gh_new->buckets[i] = e_new;
}
}
+ gh_new->nentries = gh->nentries;
+
+ return gh_new;
}
+
/** \} */
@@ -311,9 +633,7 @@ static void ghash_free_cb(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP va
GHash *BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info,
const unsigned int nentries_reserve)
{
- return ghash_new(hashfp, cmpfp, info,
- nentries_reserve,
- (unsigned int)sizeof(Entry));
+ return ghash_new(hashfp, cmpfp, info, nentries_reserve, 0);
}
/**
@@ -325,11 +645,28 @@ GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info)
}
/**
+ * Copy given GHash. Keys and values are also copied if relevant callback is provided, else pointers remain the same.
+ */
+GHash *BLI_ghash_copy(GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp)
+{
+ return ghash_copy(gh, keycopyfp, valcopyfp);
+}
+
+/**
+ * Reverve given ammount of entries (resize \a gh accordingly if needed).
+ */
+void BLI_ghash_reserve(GHash *gh, const unsigned int nentries_reserve)
+{
+ ghash_buckets_expand(gh, nentries_reserve, true);
+ ghash_buckets_contract(gh, nentries_reserve, true, false);
+}
+
+/**
* \return size of the GHash.
*/
-int BLI_ghash_size(GHash *gh)
+unsigned int BLI_ghash_size(GHash *gh)
{
- return (int)gh->nentries;
+ return gh->nentries;
}
/**
@@ -353,19 +690,7 @@ void BLI_ghash_insert(GHash *gh, void *key, void *val)
*/
bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{
- const unsigned int hash = ghash_keyhash(gh, key);
- Entry *e = ghash_lookup_entry_ex(gh, key, hash);
- if (e) {
- if (keyfreefp) keyfreefp(e->key);
- if (valfreefp) valfreefp(e->val);
- e->key = key;
- e->val = val;
- return false;
- }
- else {
- ghash_insert_ex(gh, key, val, hash);
- return true;
- }
+ return ghash_insert_safe(gh, key, val, true, keyfreefp, valfreefp);
}
/**
@@ -379,8 +704,8 @@ bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreef
*/
void *BLI_ghash_lookup(GHash *gh, const void *key)
{
- Entry *e = ghash_lookup_entry(gh, key);
- IS_GHASH_ASSERT(gh);
+ GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
+ BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
return e ? e->val : NULL;
}
@@ -389,8 +714,8 @@ void *BLI_ghash_lookup(GHash *gh, const void *key)
*/
void *BLI_ghash_lookup_default(GHash *gh, const void *key, void *val_default)
{
- Entry *e = ghash_lookup_entry(gh, key);
- IS_GHASH_ASSERT(gh);
+ GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
+ BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
return e ? e->val : val_default;
}
@@ -406,12 +731,64 @@ void *BLI_ghash_lookup_default(GHash *gh, const void *key, void *val_default)
*/
void **BLI_ghash_lookup_p(GHash *gh, const void *key)
{
- Entry *e = ghash_lookup_entry(gh, key);
- IS_GHASH_ASSERT(gh);
+ GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
+ BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
return e ? &e->val : NULL;
}
/**
+ * Ensure \a key is exists in \a gh.
+ *
+ * This handles the common situation where the caller needs ensure a key is added to \a gh,
+ * constructing a new value in the case the key isn't found.
+ * Otherwise use the existing value.
+ *
+ * Such situations typically incur multiple lookups, however this function
+ * avoids them by ensuring the key is added,
+ * returning a pointer to the value so it can be used or initialized by the caller.
+ *
+ * \returns true when the value didn't need to be added.
+ * (when false, the caller _must_ initialize the value).
+ */
+bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val)
+{
+ const unsigned int hash = ghash_keyhash(gh, key);
+ const unsigned int bucket_index = ghash_bucket_index(gh, hash);
+ GHashEntry *e = (GHashEntry *)ghash_lookup_entry_ex(gh, key, bucket_index);
+ const bool haskey = (e != NULL);
+
+ if (!haskey) {
+ e = BLI_mempool_alloc(gh->entrypool);
+ ghash_insert_ex_keyonly_entry(gh, key, bucket_index, (Entry *)e);
+ }
+
+ *r_val = &e->val;
+ return haskey;
+}
+
+/**
+ * A version of #BLI_ghash_ensure_p copies the key on insertion.
+ */
+bool BLI_ghash_ensure_p_ex(
+ GHash *gh, const void *key, void ***r_val,
+ GHashKeyCopyFP keycopyfp)
+{
+ const unsigned int hash = ghash_keyhash(gh, key);
+ const unsigned int bucket_index = ghash_bucket_index(gh, hash);
+ GHashEntry *e = (GHashEntry *)ghash_lookup_entry_ex(gh, key, bucket_index);
+ const bool haskey = (e != NULL);
+
+ if (!haskey) {
+ /* keycopyfp(key) is the only difference to BLI_ghash_ensure_p */
+ e = BLI_mempool_alloc(gh->entrypool);
+ ghash_insert_ex_keyonly_entry(gh, keycopyfp(key), bucket_index, (Entry *)e);
+ }
+
+ *r_val = &e->val;
+ return haskey;
+}
+
+/**
* Remove \a key from \a gh, or return false if the key wasn't found.
*
* \param key The key to remove.
@@ -419,10 +796,11 @@ void **BLI_ghash_lookup_p(GHash *gh, const void *key)
* \param valfreefp Optional callback to free the value.
* \return true if \a key was removed from \a gh.
*/
-bool BLI_ghash_remove(GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
+bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{
const unsigned int hash = ghash_keyhash(gh, key);
- Entry *e = ghash_remove_ex(gh, key, keyfreefp, valfreefp, hash);
+ const unsigned int bucket_index = ghash_bucket_index(gh, hash);
+ Entry *e = ghash_remove_ex(gh, key, keyfreefp, valfreefp, bucket_index);
if (e) {
BLI_mempool_free(gh->entrypool, e);
return true;
@@ -441,11 +819,12 @@ bool BLI_ghash_remove(GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFr
* \param keyfreefp Optional callback to free the key.
* \return the value of \a key int \a gh or NULL.
*/
-void *BLI_ghash_popkey(GHash *gh, void *key, GHashKeyFreeFP keyfreefp)
+void *BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp)
{
const unsigned int hash = ghash_keyhash(gh, key);
- Entry *e = ghash_remove_ex(gh, key, keyfreefp, NULL, hash);
- IS_GHASH_ASSERT(gh);
+ const unsigned int bucket_index = ghash_bucket_index(gh, hash);
+ GHashEntry *e = (GHashEntry *)ghash_remove_ex(gh, key, keyfreefp, NULL, bucket_index);
+ BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
if (e) {
void *val = e->val;
BLI_mempool_free(gh->entrypool, e);
@@ -477,17 +856,7 @@ void BLI_ghash_clear_ex(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valf
if (keyfreefp || valfreefp)
ghash_free_cb(gh, keyfreefp, valfreefp);
- gh->nbuckets = hashsizes[0]; /* gh->cursize */
- gh->nentries = 0;
- gh->cursize = 0;
-
- if (nentries_reserve) {
- ghash_buckets_reserve(gh, nentries_reserve);
- }
-
- MEM_freeN(gh->buckets);
- gh->buckets = MEM_callocN(gh->nbuckets * sizeof(*gh->buckets), "buckets");
-
+ ghash_buckets_reset(gh, nentries_reserve);
BLI_mempool_clear_ex(gh->entrypool, nentries_reserve ? (int)nentries_reserve : -1);
}
@@ -701,6 +1070,10 @@ unsigned int BLI_ghashutil_uinthash_v4(const unsigned int key[4])
hash += key[3];
return hash;
}
+unsigned int BLI_ghashutil_uinthash_v4_murmur(const unsigned int key[4])
+{
+ return BLI_hash_mm2((const unsigned char *)key, sizeof(int) * 4 /* sizeof(key) */, 0);
+}
bool BLI_ghashutil_uinthash_v4_cmp(const void *a, const void *b)
{
@@ -733,6 +1106,18 @@ unsigned int BLI_ghashutil_inthash_p(const void *ptr)
return (unsigned int)(key & 0xffffffff);
}
+unsigned int BLI_ghashutil_inthash_p_murmur(const void *ptr)
+{
+ uintptr_t key = (uintptr_t)ptr;
+
+ return BLI_hash_mm2((const unsigned char *)&key, sizeof(key), 0);
+}
+
+unsigned int BLI_ghashutil_inthash_p_simple(const void *ptr)
+{
+ return GET_UINT_FROM_POINTER(ptr);
+}
+
bool BLI_ghashutil_intcmp(const void *a, const void *b)
{
return (a != b);
@@ -769,9 +1154,15 @@ unsigned int BLI_ghashutil_strhash_p(const void *ptr)
return h;
}
+unsigned int BLI_ghashutil_strhash_p_murmur(const void *ptr)
+{
+ const unsigned char *key = ptr;
+
+ return BLI_hash_mm2(key, strlen((const char *)key) + 1, 0);
+}
bool BLI_ghashutil_strcmp(const void *a, const void *b)
{
- return (!STREQ(a, b));
+ return (a == b) ? false : !STREQ(a, b);
}
GHashPair *BLI_ghashutil_pairalloc(const void *first, const void *second)
@@ -809,44 +1200,36 @@ void BLI_ghashutil_pairfree(void *ptr)
/** \name Convenience GHash Creation Functions
* \{ */
-GHash *BLI_ghash_ptr_new_ex(const char *info,
- const unsigned int nentries_reserve)
+GHash *BLI_ghash_ptr_new_ex(const char *info, const unsigned int nentries_reserve)
{
- return BLI_ghash_new_ex(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, info,
- nentries_reserve);
+ return BLI_ghash_new_ex(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, info, nentries_reserve);
}
GHash *BLI_ghash_ptr_new(const char *info)
{
return BLI_ghash_ptr_new_ex(info, 0);
}
-GHash *BLI_ghash_str_new_ex(const char *info,
- const unsigned int nentries_reserve)
+GHash *BLI_ghash_str_new_ex(const char *info, const unsigned int nentries_reserve)
{
- return BLI_ghash_new_ex(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, info,
- nentries_reserve);
+ return BLI_ghash_new_ex(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, info, nentries_reserve);
}
GHash *BLI_ghash_str_new(const char *info)
{
return BLI_ghash_str_new_ex(info, 0);
}
-GHash *BLI_ghash_int_new_ex(const char *info,
- const unsigned int nentries_reserve)
+GHash *BLI_ghash_int_new_ex(const char *info, const unsigned int nentries_reserve)
{
- return BLI_ghash_new_ex(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, info,
- nentries_reserve);
+ return BLI_ghash_new_ex(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, info, nentries_reserve);
}
GHash *BLI_ghash_int_new(const char *info)
{
return BLI_ghash_int_new_ex(info, 0);
}
-GHash *BLI_ghash_pair_new_ex(const char *info,
- const unsigned int nentries_reserve)
+GHash *BLI_ghash_pair_new_ex(const char *info, const unsigned int nentries_reserve)
{
- return BLI_ghash_new_ex(BLI_ghashutil_pairhash, BLI_ghashutil_paircmp, info,
- nentries_reserve);
+ return BLI_ghash_new_ex(BLI_ghashutil_pairhash, BLI_ghashutil_paircmp, info, nentries_reserve);
}
GHash *BLI_ghash_pair_new(const char *info)
{
@@ -861,21 +1244,12 @@ GHash *BLI_ghash_pair_new(const char *info)
/* Use ghash API to give 'set' functionality */
-/* TODO: typical set functions
- * isdisjoint/issubset/issuperset/union/intersection/difference etc */
-
/** \name GSet Functions
* \{ */
GSet *BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info,
const unsigned int nentries_reserve)
{
- GSet *gs = (GSet *)ghash_new(hashfp, cmpfp, info,
- nentries_reserve,
- sizeof(Entry) - sizeof(void *));
-#ifndef NDEBUG
- ((GHash *)gs)->flag |= GHASH_FLAG_IS_SET;
-#endif
- return gs;
+ return (GSet *)ghash_new(hashfp, cmpfp, info, nentries_reserve, GHASH_FLAG_IS_GSET);
}
GSet *BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info)
@@ -883,9 +1257,17 @@ GSet *BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info)
return BLI_gset_new_ex(hashfp, cmpfp, info, 0);
}
-int BLI_gset_size(GSet *gs)
+/**
+ * Copy given GSet. Keys are also copied if callback is provided, else pointers remain the same.
+ */
+GSet *BLI_gset_copy(GSet *gs, GHashKeyCopyFP keycopyfp)
+{
+ return (GSet *)ghash_copy((GHash *)gs, keycopyfp, NULL);
+}
+
+unsigned int BLI_gset_size(GSet *gs)
{
- return (int)((GHash *)gs)->nentries;
+ return ((GHash *)gs)->nentries;
}
/**
@@ -895,7 +1277,8 @@ int BLI_gset_size(GSet *gs)
void BLI_gset_insert(GSet *gs, void *key)
{
const unsigned int hash = ghash_keyhash((GHash *)gs, key);
- ghash_insert_ex_keyonly((GHash *)gs, key, hash);
+ const unsigned int bucket_index = ghash_bucket_index((GHash *)gs, hash);
+ ghash_insert_ex_keyonly((GHash *)gs, key, bucket_index);
}
/**
@@ -906,15 +1289,7 @@ void BLI_gset_insert(GSet *gs, void *key)
*/
bool BLI_gset_add(GSet *gs, void *key)
{
- const unsigned int hash = ghash_keyhash((GHash *)gs, key);
- Entry *e = ghash_lookup_entry_ex((GHash *)gs, key, hash);
- if (e) {
- return false;
- }
- else {
- ghash_insert_ex_keyonly((GHash *)gs, key, hash);
- return true;
- }
+ return ghash_insert_safe_keyonly((GHash *)gs, key, false, NULL);
}
/**
@@ -925,20 +1300,10 @@ bool BLI_gset_add(GSet *gs, void *key)
*/
bool BLI_gset_reinsert(GSet *gs, void *key, GSetKeyFreeFP keyfreefp)
{
- const unsigned int hash = ghash_keyhash((GHash *)gs, key);
- Entry *e = ghash_lookup_entry_ex((GHash *)gs, key, hash);
- if (e) {
- if (keyfreefp) keyfreefp(e->key);
- e->key = key;
- return false;
- }
- else {
- ghash_insert_ex_keyonly((GHash *)gs, key, hash);
- return true;
- }
+ return ghash_insert_safe_keyonly((GHash *)gs, key, true, keyfreefp);
}
-bool BLI_gset_remove(GSet *gs, void *key, GSetKeyFreeFP keyfreefp)
+bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp)
{
return BLI_ghash_remove((GHash *)gs, key, keyfreefp, NULL);
}
@@ -982,22 +1347,18 @@ void BLI_gset_flag_clear(GSet *gs, unsigned int flag)
/** \name Convenience GSet Creation Functions
* \{ */
-GSet *BLI_gset_ptr_new_ex(const char *info,
- const unsigned int nentries_reserve)
+GSet *BLI_gset_ptr_new_ex(const char *info, const unsigned int nentries_reserve)
{
- return BLI_gset_new_ex(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, info,
- nentries_reserve);
+ return BLI_gset_new_ex(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, info, nentries_reserve);
}
GSet *BLI_gset_ptr_new(const char *info)
{
return BLI_gset_ptr_new_ex(info, 0);
}
-GSet *BLI_gset_pair_new_ex(const char *info,
- const unsigned int nentries_reserve)
+GSet *BLI_gset_pair_new_ex(const char *info, const unsigned int nentries_reserve)
{
- return BLI_gset_new_ex(BLI_ghashutil_pairhash, BLI_ghashutil_paircmp, info,
- nentries_reserve);
+ return BLI_gset_new_ex(BLI_ghashutil_pairhash, BLI_ghashutil_paircmp, info, nentries_reserve);
}
GSet *BLI_gset_pair_new(const char *info)
{
@@ -1009,37 +1370,126 @@ GSet *BLI_gset_pair_new(const char *info)
/** \name Debugging & Introspection
* \{ */
-#ifdef DEBUG
+
+#include "BLI_math.h"
+
+/**
+ * \return number of buckets in the GHash.
+ */
+int BLI_ghash_buckets_size(GHash *gh)
+{
+ return (int)gh->nbuckets;
+}
+int BLI_gset_buckets_size(GSet *gs)
+{
+ return BLI_ghash_buckets_size((GHash *)gs);
+}
/**
- * Measure how well the hash function performs
- * (1.0 is approx as good as random distribution).
+ * Measure how well the hash function performs (1.0 is approx as good as random distribution),
+ * and return a few other stats like load, variance of the distribution of the entries in the buckets, etc.
*
* Smaller is better!
*/
-double BLI_ghash_calc_quality(GHash *gh)
+double BLI_ghash_calc_quality_ex(
+ GHash *gh, double *r_load, double *r_variance,
+ double *r_prop_empty_buckets, double *r_prop_overloaded_buckets, int *r_biggest_bucket)
{
- uint64_t sum = 0;
+ double mean;
unsigned int i;
- if (gh->nentries == 0)
- return -1.0;
+ if (gh->nentries == 0) {
+ if (r_load) {
+ *r_load = 0.0;
+ }
+ if (r_variance) {
+ *r_variance = 0.0;
+ }
+ if (r_prop_empty_buckets) {
+ *r_prop_empty_buckets = 1.0;
+ }
+ if (r_prop_overloaded_buckets) {
+ *r_prop_overloaded_buckets = 0.0;
+ }
+ if (r_biggest_bucket) {
+ *r_biggest_bucket = 0;
+ }
- for (i = 0; i < gh->nbuckets; i++) {
- uint64_t count = 0;
- Entry *e;
- for (e = gh->buckets[i]; e; e = e->next) {
- count += 1;
+ return 0.0;
+ }
+
+ mean = (double)gh->nentries / (double)gh->nbuckets;
+ if (r_load) {
+ *r_load = mean;
+ }
+ if (r_biggest_bucket) {
+ *r_biggest_bucket = 0;
+ }
+
+ if (r_variance) {
+ /* We already know our mean (i.e. load factor), easy to compute variance.
+ * See http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass_algorithm
+ */
+ double sum = 0.0;
+ for (i = 0; i < gh->nbuckets; i++) {
+ int count = 0;
+ Entry *e;
+ for (e = gh->buckets[i]; e; e = e->next) {
+ count++;
+ }
+ sum += ((double)count - mean) * ((double)count - mean);
}
- sum += count * (count + 1);
+ *r_variance = sum / (double)(gh->nbuckets - 1);
}
- return ((double)sum * (double)gh->nbuckets /
- ((double)gh->nentries * (gh->nentries + 2 * gh->nbuckets - 1)));
+
+ {
+ uint64_t sum = 0;
+ uint64_t overloaded_buckets_threshold = (uint64_t)max_ii(GHASH_LIMIT_GROW(1), 1);
+ uint64_t sum_overloaded = 0;
+ uint64_t sum_empty = 0;
+
+ for (i = 0; i < gh->nbuckets; i++) {
+ uint64_t count = 0;
+ Entry *e;
+ for (e = gh->buckets[i]; e; e = e->next) {
+ count++;
+ }
+ if (r_biggest_bucket) {
+ *r_biggest_bucket = max_ii(*r_biggest_bucket, (int)count);
+ }
+ if (r_prop_overloaded_buckets && (count > overloaded_buckets_threshold)) {
+ sum_overloaded++;
+ }
+ if (r_prop_empty_buckets && !count) {
+ sum_empty++;
+ }
+ sum += count * (count + 1);
+ }
+ if (r_prop_overloaded_buckets) {
+ *r_prop_overloaded_buckets = (double)sum_overloaded / (double)gh->nbuckets;
+ }
+ if (r_prop_empty_buckets) {
+ *r_prop_empty_buckets = (double)sum_empty / (double)gh->nbuckets;
+ }
+ return ((double)sum * (double)gh->nbuckets /
+ ((double)gh->nentries * (gh->nentries + 2 * gh->nbuckets - 1)));
+ }
+}
+double BLI_gset_calc_quality_ex(
+ GSet *gs, double *r_load, double *r_variance,
+ double *r_prop_empty_buckets, double *r_prop_overloaded_buckets, int *r_biggest_bucket)
+{
+ return BLI_ghash_calc_quality_ex((GHash *)gs, r_load, r_variance,
+ r_prop_empty_buckets, r_prop_overloaded_buckets, r_biggest_bucket);
+}
+
+double BLI_ghash_calc_quality(GHash *gh)
+{
+ return BLI_ghash_calc_quality_ex(gh, NULL, NULL, NULL, NULL, NULL);
}
double BLI_gset_calc_quality(GSet *gs)
{
- return BLI_ghash_calc_quality((GHash *)gs);
+ return BLI_ghash_calc_quality_ex((GHash *)gs, NULL, NULL, NULL, NULL, NULL);
}
-#endif
/** \} */
diff --git a/source/blender/blenlib/intern/BLI_heap.c b/source/blender/blenlib/intern/BLI_heap.c
index 66dfa87b7b9..c0f338a1918 100644
--- a/source/blender/blenlib/intern/BLI_heap.c
+++ b/source/blender/blenlib/intern/BLI_heap.c
@@ -183,8 +183,8 @@ HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr)
node = (HeapNode *)BLI_memarena_alloc(heap->arena, sizeof(*node));
}
- node->value = value;
node->ptr = ptr;
+ node->value = value;
node->index = heap->size;
heap->tree[node->index] = node;
diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c
index 391f3ef7702..f0efe49cfdb 100644
--- a/source/blender/blenlib/intern/BLI_linklist.c
+++ b/source/blender/blenlib/intern/BLI_linklist.c
@@ -230,7 +230,7 @@ void *BLI_linklist_pop(struct LinkNode **listp)
void *link = (*listp)->link;
void *next = (*listp)->next;
- MEM_freeN((*listp));
+ MEM_freeN(*listp);
*listp = next;
return link;
diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c
index 173effbc434..6c5dc5a7f1e 100644
--- a/source/blender/blenlib/intern/array_utils.c
+++ b/source/blender/blenlib/intern/array_utils.c
@@ -25,23 +25,28 @@
#include <string.h>
#include <stdlib.h>
+#include "MEM_guardedalloc.h"
+
#include "BLI_array_utils.h"
#include "BLI_sys_types.h"
#include "BLI_utildefines.h"
#include "BLI_alloca.h"
+#include "BLI_strict_flags.h"
+
void _bli_array_reverse(void *arr_v, unsigned int arr_len, size_t arr_stride)
{
- const unsigned int arr_half_stride = (arr_len / 2) * arr_stride;
+ const unsigned int arr_stride_uint = (unsigned int)arr_stride;
+ const unsigned int arr_half_stride = (arr_len / 2) * arr_stride_uint;
unsigned int i, i_end;
char *arr = arr_v;
char *buf = BLI_array_alloca(buf, arr_stride);
- for (i = 0, i_end = (arr_len - 1) * arr_stride;
+ for (i = 0, i_end = (arr_len - 1) * arr_stride_uint;
i < arr_half_stride;
- i += arr_stride, i_end -= arr_stride)
+ i += arr_stride_uint, i_end -= arr_stride_uint)
{
memcpy(buf, &arr[i], arr_stride);
memcpy(&arr[i], &arr[i_end], arr_stride);
@@ -69,6 +74,36 @@ void _bli_array_wrap(void *arr_v, unsigned int arr_len, size_t arr_stride, int d
}
}
+void _bli_array_permute(
+ void *arr_v, const unsigned int arr_len, const size_t arr_stride,
+ const unsigned int *order, void *arr_temp)
+{
+ const size_t len = arr_len * arr_stride;
+ const unsigned int arr_stride_uint = (unsigned int)arr_stride;
+ void *arr_orig;
+ unsigned int i;
+
+ if (arr_temp == NULL) {
+ arr_orig = MEM_mallocN(len, __func__);
+ }
+ else {
+ arr_orig = arr_temp;
+ }
+
+ memcpy(arr_orig, arr_v, len);
+
+ for (i = 0; i < arr_len; i++) {
+ BLI_assert(order[i] < arr_len);
+ memcpy(POINTER_OFFSET(arr_v, arr_stride_uint * i),
+ POINTER_OFFSET(arr_orig, arr_stride_uint * order[i]),
+ arr_stride);
+ }
+
+ if (arr_temp == NULL) {
+ MEM_freeN(arr_orig);
+ }
+}
+
/**
* \note Not efficient, use for error checks/asserts.
*/
diff --git a/source/blender/blenlib/intern/astar.c b/source/blender/blenlib/intern/astar.c
index b7b41d2497e..311d6dd89ae 100644
--- a/source/blender/blenlib/intern/astar.c
+++ b/source/blender/blenlib/intern/astar.c
@@ -229,7 +229,7 @@ bool BLI_astar_graph_solve(
r_solution->steps = 0;
prev_nodes[node_index_src] = -1;
BLI_BITMAP_SET_ALL(done_nodes, false, as_graph->node_num);
- fill_vn_fl(g_costs, as_graph->node_num, FLT_MAX);
+ copy_vn_fl(g_costs, as_graph->node_num, FLT_MAX);
g_costs[node_index_src] = 0.0f;
g_steps[node_index_src] = 0;
diff --git a/source/blender/blenlib/intern/convexhull2d.c b/source/blender/blenlib/intern/convexhull2d.c
index 5f64088f433..740f3cce4a4 100644
--- a/source/blender/blenlib/intern/convexhull2d.c
+++ b/source/blender/blenlib/intern/convexhull2d.c
@@ -239,7 +239,7 @@ int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[])
*
* Intended to be used with #BLI_convexhull_2d
*
- * \param points Orded hull points
+ * \param points_hull Ordered hull points
* (result of #BLI_convexhull_2d mapped to a contiguous array).
*
* \note we could return the index of the best edge too if its needed.
diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c
index 82d57dad753..cde4a8bf59d 100644
--- a/source/blender/blenlib/intern/edgehash.c
+++ b/source/blender/blenlib/intern/edgehash.c
@@ -240,6 +240,30 @@ BLI_INLINE void edgehash_insert_ex_keyonly(EdgeHash *eh, unsigned int v0, unsign
e->next = eh->buckets[hash];
e->v0 = v0;
e->v1 = v1;
+ eh->buckets[hash] = e;
+
+ if (UNLIKELY(edgehash_test_expand_buckets(++eh->nentries, eh->nbuckets))) {
+ edgehash_resize_buckets(eh, _ehash_hashsizes[++eh->cursize]);
+ }
+}
+
+/**
+ * Insert function that doesn't set the value (use for EdgeSet)
+ */
+BLI_INLINE void edgehash_insert_ex_keyonly_entry(
+ EdgeHash *eh, unsigned int v0, unsigned int v1,
+ unsigned int hash,
+ EdgeEntry *e)
+{
+ BLI_assert((eh->flag & EDGEHASH_FLAG_ALLOW_DUPES) || (BLI_edgehash_haskey(eh, v0, v1) == 0));
+
+ /* this helps to track down errors with bad edge data */
+ BLI_assert(v0 < v1);
+ BLI_assert(v0 != v1);
+
+ e->next = eh->buckets[hash];
+ e->v0 = v0;
+ e->v1 = v1;
/* intentionally leave value unset */
eh->buckets[hash] = e;
@@ -373,6 +397,40 @@ void **BLI_edgehash_lookup_p(EdgeHash *eh, unsigned int v0, unsigned int v1)
}
/**
+ * Ensure \a (v0, v1) is exists in \a eh.
+ *
+ * This handles the common situation where the caller needs ensure a key is added to \a eh,
+ * constructing a new value in the case the key isn't found.
+ * Otherwise use the existing value.
+ *
+ * Such situations typically incur multiple lookups, however this function
+ * avoids them by ensuring the key is added,
+ * returning a pointer to the value so it can be used or initialized by the caller.
+ *
+ * \returns true when the value didn't need to be added.
+ * (when false, the caller _must_ initialize the value).
+ */
+bool BLI_edgehash_ensure_p(EdgeHash *eh, unsigned int v0, unsigned int v1, void ***r_val)
+{
+ unsigned int hash;
+ EdgeEntry *e;
+ bool haskey;
+
+ EDGE_ORD(v0, v1); /* ensure v0 is smaller */
+ hash = edgehash_keyhash(eh, v0, v1);
+ e = edgehash_lookup_entry_ex(eh, v0, v1, hash);
+ haskey = (e != NULL);
+
+ if (!haskey) {
+ e = BLI_mempool_alloc(eh->epool);
+ edgehash_insert_ex_keyonly_entry(eh, v0, v1, hash, e);
+ }
+
+ *r_val = &e->val;
+ return haskey;
+}
+
+/**
* Return value for given edge (\a v0, \a v1), or NULL if
* if key does not exist in hash. (If need exists
* to differentiate between key-value being NULL and
@@ -396,9 +454,9 @@ void *BLI_edgehash_lookup_default(EdgeHash *eh, unsigned int v0, unsigned int v1
}
/**
- * Remove \a key from \a eh, or return false if the key wasn't found.
+ * Remove \a key (v0, v1) from \a eh, or return false if the key wasn't found.
*
- * \param key The key to remove.
+ * \param v0, v1: The key to remove.
* \param valfreefp Optional callback to free the value.
* \return true if \a key was removed from \a eh.
*/
@@ -422,9 +480,9 @@ bool BLI_edgehash_remove(EdgeHash *eh, unsigned int v0, unsigned int v1, EdgeHas
/* same as above but return the value,
* no free value argument since it will be returned */
/**
- * Remove \a key from \a eh, returning the value or NULL if the key wasn't found.
+ * Remove \a key (v0, v1) from \a eh, returning the value or NULL if the key wasn't found.
*
- * \param key The key to remove.
+ * \param v0, v1: The key to remove.
* \return the value of \a key int \a eh or NULL.
*/
void *BLI_edgehash_popkey(EdgeHash *eh, unsigned int v0, unsigned int v1)
diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c
index b3392e28223..8719c92a2a6 100644
--- a/source/blender/blenlib/intern/freetypefont.c
+++ b/source/blender/blenlib/intern/freetypefont.c
@@ -507,8 +507,7 @@ VChar *BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
/* Freetype2 Outline struct */
-typedef struct FT_Outline_
-{
+typedef struct FT_Outline_ {
short n_contours; /* number of contours in glyph */
short n_points; /* number of points in the glyph */
diff --git a/source/blender/blenlib/intern/gsqueue.c b/source/blender/blenlib/intern/gsqueue.c
index 94d18ce3c77..f1aff76b358 100644
--- a/source/blender/blenlib/intern/gsqueue.c
+++ b/source/blender/blenlib/intern/gsqueue.c
@@ -96,8 +96,8 @@ int BLI_gsqueue_size(GSQueue *gq)
* Access the item at the head of the queue
* without removing it.
*
- * \param item_r A pointer to an appropriately
- * sized structure (the size passed to BLI_gsqueue_new)
+ * \param r_item: A pointer to an appropriately
+ * sized structure (the size passed to #BLI_gsqueue_new)
*/
void BLI_gsqueue_peek(GSQueue *gq, void *r_item)
{
@@ -108,8 +108,8 @@ void BLI_gsqueue_peek(GSQueue *gq, void *r_item)
* Access the item at the head of the queue
* and remove it.
*
- * \param item_r A pointer to an appropriately
- * sized structure (the size passed to BLI_gsqueue_new).
+ * \param r_item: A pointer to an appropriately
+ * sized structure (the size passed to #BLI_gsqueue_new).
* Can be NULL if desired.
*/
void BLI_gsqueue_pop(GSQueue *gq, void *r_item)
diff --git a/source/blender/blenlib/intern/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c
index 4eec38278e9..d98b915983c 100644
--- a/source/blender/blenlib/intern/hash_md5.c
+++ b/source/blender/blenlib/intern/hash_md5.c
@@ -81,8 +81,7 @@
* 'BLI_hash_md5_stream' and 'BLI_hash_md5_buffer'. */
/* Structure to save state of computation between the single steps. */
-struct md5_ctx
-{
+struct md5_ctx {
md5_uint32 A;
md5_uint32 B;
md5_uint32 C;
diff --git a/source/blender/blenlib/intern/hash_mm2a.c b/source/blender/blenlib/intern/hash_mm2a.c
index bae098ae96b..af6ef4f355f 100644
--- a/source/blender/blenlib/intern/hash_mm2a.c
+++ b/source/blender/blenlib/intern/hash_mm2a.c
@@ -49,6 +49,13 @@
(h) = ((h) * MM2A_M) ^ (k); \
} (void)0
+#define MM2A_MIX_FINALIZE(h) \
+{ \
+ (h) ^= (h) >> 13; \
+ (h) *= MM2A_M; \
+ (h) ^= (h) >> 15; \
+} (void)0
+
static void mm2a_mix_tail(BLI_HashMurmur2A *mm2, const unsigned char **data, size_t *len)
{
while (*len && ((*len < 4) || mm2->count)) {
@@ -99,9 +106,40 @@ uint32_t BLI_hash_mm2a_end(BLI_HashMurmur2A *mm2)
MM2A_MIX(mm2->hash, mm2->tail);
MM2A_MIX(mm2->hash, mm2->size);
- mm2->hash ^= mm2->hash >> 13;
- mm2->hash *= MM2A_M;
- mm2->hash ^= mm2->hash >> 15;
+ MM2A_MIX_FINALIZE(mm2->hash);
return mm2->hash;
}
+
+/* Non-incremental version, quicker for small keys. */
+uint32_t BLI_hash_mm2(const unsigned char *data, size_t len, uint32_t seed)
+{
+ /* Initialize the hash to a 'random' value */
+ uint32_t h = seed ^ len;
+
+ /* Mix 4 bytes at a time into the hash */
+ for (; len >= 4; data += 4, len -= 4) {
+ uint32_t k = *(uint32_t *)data;
+
+ MM2A_MIX(h, k);
+ }
+
+ /* Handle the last few bytes of the input array */
+ switch (len) {
+ case 3:
+ h ^= data[2] << 16;
+ /* fall through */
+ case 2:
+ h ^= data[1] << 8;
+ /* fall through */
+ case 1:
+ h ^= data[0];
+ h *= MM2A_M;
+ }
+
+ /* Do a few final mixes of the hash to ensure the last few bytes are well-incorporated. */
+ MM2A_MIX_FINALIZE(h);
+
+ return h;
+}
+
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index d52c09790f9..f267cd777a5 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -208,7 +208,7 @@ void BLI_freelinkN(ListBase *listbase, void *vlink)
/**
* Sorts the elements of listbase into the order defined by cmp
- * (which should return 1 iff its first arg should come after its second arg).
+ * (which should return 1 if its first arg should come after its second arg).
* This uses insertion sort, so NOT ok for large list.
*/
void BLI_listbase_sort(ListBase *listbase, int (*cmp)(const void *, const void *))
diff --git a/source/blender/blenlib/intern/math_base.c b/source/blender/blenlib/intern/math_base.c
index 3ff1af3513e..0a1e9e8a8a1 100644
--- a/source/blender/blenlib/intern/math_base.c
+++ b/source/blender/blenlib/intern/math_base.c
@@ -31,41 +31,20 @@
#include "BLI_strict_flags.h"
-/* WARNING: MSVC compiling hack for double_round() */
-#if (defined(WIN32) || defined(WIN64)) && !(defined(FREE_WINDOWS))
-
-/* from python 3.1 pymath.c */
-double copysign(double x, double y)
+int pow_i(int base, int exp)
{
- /* use atan2 to distinguish -0.0 from 0.0 */
- if (y > 0.0 || (y == 0.0 && atan2(y, -1.0) > 0.0)) {
- return fabs(x);
- }
- else {
- return -fabs(x);
+ int result = 1;
+ BLI_assert(exp >= 0);
+ while (exp) {
+ if (exp & 1) {
+ result *= base;
+ }
+ exp >>= 1;
+ base *= base;
}
-}
-/* from python 3.1 pymath.c */
-double round(double x)
-{
- double absx, y;
- absx = fabs(x);
- y = floor(absx);
- if (absx - y >= 0.5)
- y += 1.0;
- return copysign(y, x);
+ return result;
}
-#else /* OpenSuse 11.1 seems to need this. */
-# ifdef __GNUC__
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wredundant-decls"
-# endif
-double round(double x);
-# ifdef __GNUC__
-# pragma GCC diagnostic pop
-# endif
-#endif
/* from python 3.1 floatobject.c
* ndigits must be between 0 and 21 */
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index f5713824296..facee8b0a89 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -198,25 +198,6 @@ MINLINE int mod_i(int i, int n)
return (i % n + n) % n;
}
-MINLINE unsigned int highest_order_bit_i(unsigned int n)
-{
- n |= (n >> 1);
- n |= (n >> 2);
- n |= (n >> 4);
- n |= (n >> 8);
- n |= (n >> 16);
- return n - (n >> 1);
-}
-
-MINLINE unsigned short highest_order_bit_s(unsigned short n)
-{
- n |= (n >> 1);
- n |= (n >> 2);
- n |= (n >> 4);
- n |= (n >> 8);
- return (unsigned short)(n - (n >> 1));
-}
-
MINLINE float min_ff(float a, float b)
{
return (a < b) ? a : b;
diff --git a/source/blender/blenlib/intern/math_bits_inline.c b/source/blender/blenlib/intern/math_bits_inline.c
new file mode 100644
index 00000000000..11ee6e7fa5b
--- /dev/null
+++ b/source/blender/blenlib/intern/math_bits_inline.c
@@ -0,0 +1,59 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * */
+
+/** \file blender/blenlib/intern/math_bits_inline.c
+ * \ingroup bli
+ */
+
+#ifndef __MATH_BITS_INLINE_C__
+#define __MATH_BITS_INLINE_C__
+
+#include "BLI_math_bits.h"
+
+MINLINE unsigned int highest_order_bit_i(unsigned int n)
+{
+ n |= (n >> 1);
+ n |= (n >> 2);
+ n |= (n >> 4);
+ n |= (n >> 8);
+ n |= (n >> 16);
+ return n - (n >> 1);
+}
+
+MINLINE unsigned short highest_order_bit_s(unsigned short n)
+{
+ n |= (n >> 1);
+ n |= (n >> 2);
+ n |= (n >> 4);
+ n |= (n >> 8);
+ return (unsigned short)(n - (n >> 1));
+}
+
+#ifndef __GNUC__
+MINLINE int count_bits_i(unsigned int i)
+{
+ /* variable-precision SWAR algorithm. */
+ i = i - ((i >> 1) & 0x55555555);
+ i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
+ return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
+}
+#endif
+
+#endif /* __MATH_BITS_INLINE_C__ */
diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c
index dc62d04ad55..45466226e72 100644
--- a/source/blender/blenlib/intern/math_color_inline.c
+++ b/source/blender/blenlib/intern/math_color_inline.c
@@ -200,60 +200,46 @@ MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack)
r_col[2] = ((pack) >> 16) & 0xFF;
}
-/* TODO:
+
+/** \name RGB/Grayscale Functions
*
- * regarding #rgb_to_bw vs #rgb_to_grayscale,
- * it seems nobody knows why we have both functions which convert color to grays
- * but with different influences, this is quite stupid, and should be resolved
- * by someone who knows this stuff: see this thread
- * http://lists.blender.org/pipermail/bf-committers/2012-June/037180.html
+ * \warning
+ * These are only an approximation,
+ * in almost _all_ cases, #IMB_colormanagement_get_luminance should be used instead.
+ * however for screen-only colors which don't depend on the currently loaded profile - this is preferred.
+ * Checking theme colors for contrast, etc. Basically anything outside the render pipeline.
*
- * Only conclusion is that rgb_to_grayscale is used more for compositing.
- */
-MINLINE float rgb_to_bw(const float rgb[3])
-{
- return 0.35f * rgb[0] + 0.45f * rgb[1] + 0.2f * rgb[2];
-}
+ * \{ */
-/* non-linear luma from ITU-R BT.601-2
- * see: http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC11
- * note: the values used for are not exact matches to those documented above,
- * but they are from the same */
+/**
+ * ITU-R BT.709 primaries
+ * http://en.wikipedia.org/wiki/Relative_luminance
+ *
+ * Real values are:
+ * ``Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)``
+ * according to: "Derivation of Basic Television Color Equations", RP 177-1993
+ *
+ * As this sums slightly above 1.0, the document recommends to use:
+ * ``0.2126(R) + 0.7152(G) + 0.0722(B)``, as used here.
+ *
+ * The high precision values are used to calculate the rounded byte weights so they add up to 255:
+ * ``54(R) + 182(G) + 19(B)``
+ */
MINLINE float rgb_to_grayscale(const float rgb[3])
{
- return 0.3f * rgb[0] + 0.58f * rgb[1] + 0.12f * rgb[2];
+ return (0.2126f * rgb[0]) + (0.7152f * rgb[1]) + (0.0722f * rgb[2]);
}
MINLINE unsigned char rgb_to_grayscale_byte(const unsigned char rgb[3])
{
- return (unsigned char)(((76 * (unsigned short)rgb[0]) +
- (148 * (unsigned short)rgb[1]) +
- (31 * (unsigned short)rgb[2])) / 255);
+ return (unsigned char)(((54 * (unsigned short)rgb[0]) +
+ (182 * (unsigned short)rgb[1]) +
+ (19 * (unsigned short)rgb[2])) / 255);
}
-/* luma from defined by 'YCC_JFIF', see #rgb_to_ycc */
-MINLINE float rgb_to_luma(const float rgb[3])
-{
- return 0.299f * rgb[0] + 0.587f * rgb[1] + 0.114f * rgb[2];
-}
+/** \} */
-MINLINE unsigned char rgb_to_luma_byte(const unsigned char rgb[3])
-{
- return (unsigned char)(((76 * (unsigned short)rgb[0]) +
- (150 * (unsigned short)rgb[1]) +
- (29 * (unsigned short)rgb[2])) / 255);
-}
-/* gamma-corrected RGB --> CIE XYZ
- * for this function we only get the Y component
- * see: http://software.intel.com/sites/products/documentation/hpc/ipp/ippi/ippi_ch6/ch6_color_models.html
- *
- * also known as:
- * luminance rec. 709 */
-MINLINE float rgb_to_luma_y(const float rgb[3])
-{
- return 0.212671f * rgb[0] + 0.71516f * rgb[1] + 0.072169f * rgb[2];
-}
MINLINE int compare_rgb_uchar(const unsigned char col_a[3], const unsigned char col_b[3], const int limit)
{
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index ba1f4480659..32308ad1ab5 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -2425,6 +2425,71 @@ void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], co
}
}
+void interp_weights_face_v3_index(int tri[3], float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3])
+{
+ float w2[3];
+
+ w[0] = w[1] = w[2] = w[3] = 0.0f;
+ tri[0] = tri[1] = tri[2] = -1;
+
+ /* first check for exact match */
+ if (equals_v3v3(co, v1)) {
+ w[0] = 1.0f;
+ tri[0] = 0; tri[1] = 1; tri[2] = 3;
+ }
+ else if (equals_v3v3(co, v2)) {
+ w[1] = 1.0f;
+ tri[0] = 0; tri[1] = 1; tri[2] = 3;
+ }
+ else if (equals_v3v3(co, v3)) {
+ w[2] = 1.0f;
+ tri[0] = 1; tri[1] = 2; tri[2] = 3;
+ }
+ else if (v4 && equals_v3v3(co, v4)) {
+ w[3] = 1.0f;
+ tri[0] = 1; tri[1] = 2; tri[2] = 3;
+ }
+ else {
+ /* otherwise compute barycentric interpolation weights */
+ float n1[3], n2[3], n[3];
+ bool degenerate;
+
+ sub_v3_v3v3(n1, v1, v3);
+ if (v4) {
+ sub_v3_v3v3(n2, v2, v4);
+ }
+ else {
+ sub_v3_v3v3(n2, v2, v3);
+ }
+ cross_v3_v3v3(n, n1, n2);
+
+ /* OpenGL seems to split this way, so we do too */
+ if (v4) {
+ degenerate = barycentric_weights(v1, v2, v4, co, n, w);
+ SWAP(float, w[2], w[3]);
+ tri[0] = 0; tri[1] = 1; tri[2] = 3;
+
+ if (degenerate || (w[0] < 0.0f)) {
+ /* if w[1] is negative, co is on the other side of the v1-v3 edge,
+ * so we interpolate using the other triangle */
+ degenerate = barycentric_weights(v2, v3, v4, co, n, w2);
+
+ if (!degenerate) {
+ w[0] = 0.0f;
+ w[1] = w2[0];
+ w[2] = w2[1];
+ w[3] = w2[2];
+ tri[0] = 1; tri[1] = 2; tri[2] = 3;
+ }
+ }
+ }
+ else {
+ barycentric_weights(v1, v2, v3, co, n, w);
+ tri[0] = 0; tri[1] = 1; tri[2] = 2;
+ }
+ }
+}
+
/* return 1 of point is inside triangle, 2 if it's on the edge, 0 if point is outside of triangle */
int barycentric_inside_triangle_v2(const float w[3])
{
@@ -3101,6 +3166,43 @@ void resolve_quad_uv_v2_deriv(float r_uv[2], float r_deriv[2][2],
}
}
+/* a version of resolve_quad_uv_v2 that only calculates the 'u' */
+float resolve_quad_u_v2(
+ const float st[2],
+ const float st0[2], const float st1[2], const float st2[2], const float st3[2])
+{
+ const double signed_area = (st0[0] * st1[1] - st0[1] * st1[0]) + (st1[0] * st2[1] - st1[1] * st2[0]) +
+ (st2[0] * st3[1] - st2[1] * st3[0]) + (st3[0] * st0[1] - st3[1] * st0[0]);
+
+ /* X is 2D cross product (determinant)
+ * A = (p0 - p) X (p0 - p3)*/
+ const double a = (st0[0] - st[0]) * (st0[1] - st3[1]) - (st0[1] - st[1]) * (st0[0] - st3[0]);
+
+ /* B = ( (p0 - p) X (p1 - p2) + (p1 - p) X (p0 - p3) ) / 2 */
+ const double b = 0.5 * (double)(((st0[0] - st[0]) * (st1[1] - st2[1]) - (st0[1] - st[1]) * (st1[0] - st2[0])) +
+ ((st1[0] - st[0]) * (st0[1] - st3[1]) - (st1[1] - st[1]) * (st0[0] - st3[0])));
+
+ /* C = (p1-p) X (p1-p2) */
+ const double fC = (st1[0] - st[0]) * (st1[1] - st2[1]) - (st1[1] - st[1]) * (st1[0] - st2[0]);
+ double denom = a - 2 * b + fC;
+
+ if (IS_ZERO(denom) != 0) {
+ const double fDen = a - fC;
+ if (IS_ZERO(fDen) == 0)
+ return (float)(a / fDen);
+ else
+ return 0.0f;
+ }
+ else {
+ const double desc_sq = b * b - a * fC;
+ const double desc = sqrt(desc_sq < 0.0 ? 0.0 : desc_sq);
+ const double s = signed_area > 0 ? (-1.0) : 1.0;
+
+ return (float)(((a - b) + s * desc) / denom);
+ }
+}
+
+
#undef IS_ZERO
/* reverse of the functions above */
diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c
index 67850463fe2..b45d8b4c13b 100644
--- a/source/blender/blenlib/intern/math_interp.c
+++ b/source/blender/blenlib/intern/math_interp.c
@@ -112,10 +112,10 @@ BLI_INLINE void bicubic_interpolation(const unsigned char *byte_buffer, const fl
/* sample area entirely outside image? */
if (ceil(u) < 0 || floor(u) > width - 1 || ceil(v) < 0 || floor(v) > height - 1) {
if (float_output) {
- fill_vn_fl(float_output, components, 0.0f);
+ copy_vn_fl(float_output, components, 0.0f);
}
if (byte_output) {
- fill_vn_uchar(byte_output, components, 0);
+ copy_vn_uchar(byte_output, components, 0);
}
return;
}
@@ -281,7 +281,7 @@ BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const f
/* sample area entirely outside image? */
if (x2 < 0 || x1 > width - 1 || y2 < 0 || y1 > height - 1) {
- fill_vn_fl(float_output, components, 0.0f);
+ copy_vn_fl(float_output, components, 0.0f);
return;
}
@@ -323,7 +323,7 @@ BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const f
/* sample area entirely outside image? */
if (x2 < 0 || x1 > width - 1 || y2 < 0 || y1 > height - 1) {
- fill_vn_uchar(byte_output, components, 0);
+ copy_vn_uchar(byte_output, components, 0);
return;
}
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index 1b4bbafdb04..a9afed7a63d 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -504,6 +504,16 @@ void mul_mat3_m4_v3(float mat[4][4], float vec[3])
vec[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2];
}
+void mul_v3_mat3_m4v3(float r[3], float mat[4][4], const float vec[3])
+{
+ const float x = vec[0];
+ const float y = vec[1];
+
+ r[0] = x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2];
+ r[1] = x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2];
+ r[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2];
+}
+
void mul_project_m4_v3(float mat[4][4], float vec[3])
{
const float w = mul_project_m4_v3_zfac(mat, vec);
@@ -1149,7 +1159,7 @@ bool is_orthogonal_m3(float m[3][3])
for (i = 0; i < 3; i++) {
for (j = 0; j < i; j++) {
- if (fabsf(dot_v3v3(m[i], m[j])) > 1.5f * FLT_EPSILON)
+ if (fabsf(dot_v3v3(m[i], m[j])) > 1e-5f)
return false;
}
}
@@ -1163,7 +1173,7 @@ bool is_orthogonal_m4(float m[4][4])
for (i = 0; i < 4; i++) {
for (j = 0; j < i; j++) {
- if (fabsf(dot_v4v4(m[i], m[j])) > 1.5f * FLT_EPSILON)
+ if (fabsf(dot_v4v4(m[i], m[j])) > 1e-5f)
return false;
}
@@ -1178,7 +1188,7 @@ bool is_orthonormal_m3(float m[3][3])
int i;
for (i = 0; i < 3; i++)
- if (fabsf(dot_v3v3(m[i], m[i]) - 1) > 1.5f * FLT_EPSILON)
+ if (fabsf(dot_v3v3(m[i], m[i]) - 1) > 1e-5f)
return false;
return true;
@@ -1193,7 +1203,7 @@ bool is_orthonormal_m4(float m[4][4])
int i;
for (i = 0; i < 4; i++)
- if (fabsf(dot_v4v4(m[i], m[i]) - 1) > 1.5f * FLT_EPSILON)
+ if (fabsf(dot_v4v4(m[i], m[i]) - 1) > 1e-5f)
return false;
return true;
@@ -1465,39 +1475,14 @@ float mat4_to_scale(float mat[4][4])
void mat3_to_rot_size(float rot[3][3], float size[3], float mat3[3][3])
{
- float mat3_n[3][3]; /* mat3 -> normalized, 3x3 */
- float imat3_n[3][3]; /* mat3 -> normalized & inverted, 3x3 */
-
- /* rotation & scale are linked, we need to create the mat's
- * for these together since they are related. */
-
- /* so scale doesn't interfere with rotation [#24291] */
- /* note: this is a workaround for negative matrix not working for rotation conversion, FIXME */
- normalize_m3_m3(mat3_n, mat3);
- if (is_negative_m3(mat3)) {
- negate_m3(mat3_n);
- }
-
- /* rotation */
/* keep rot as a 3x3 matrix, the caller can convert into a quat or euler */
- copy_m3_m3(rot, mat3_n);
-
- /* scale */
- /* note: mat4_to_size(ob->size, mat) fails for negative scale */
- invert_m3_m3(imat3_n, mat3_n);
-
- /* better not edit mat3 */
-#if 0
- mul_m3_m3m3(mat3, imat3_n, mat3);
-
- size[0] = mat3[0][0];
- size[1] = mat3[1][1];
- size[2] = mat3[2][2];
-#else
- size[0] = dot_m3_v3_row_x(imat3_n, mat3[0]);
- size[1] = dot_m3_v3_row_y(imat3_n, mat3[1]);
- size[2] = dot_m3_v3_row_z(imat3_n, mat3[2]);
-#endif
+ size[0] = normalize_v3_v3(rot[0], mat3[0]);
+ size[1] = normalize_v3_v3(rot[1], mat3[1]);
+ size[2] = normalize_v3_v3(rot[2], mat3[2]);
+ if (UNLIKELY(is_negative_m3(rot))) {
+ negate_m3(rot);
+ negate_v3(size);
+ }
}
void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], float wmat[4][4])
@@ -2251,7 +2236,7 @@ void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4])
void pseudoinverse_m4_m4(float Ainv[4][4], float A_[4][4], float epsilon)
{
- /* compute moon-penrose pseudo inverse of matrix, singular values
+ /* compute Moore-Penrose pseudo inverse of matrix, singular values
* below epsilon are ignored for stability (truncated SVD) */
float A[4][4], V[4][4], W[4], Wm[4][4], U[4][4];
int i;
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index 3d5d47bc2e0..5f039e89e89 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -1043,11 +1043,12 @@ void expmap_to_quat(float r[4], const float expmap[3])
float angle;
/* Obtain axis/angle representation. */
- angle = normalize_v3_v3(axis, expmap);
- angle = angle_wrap_rad(angle);
-
- /* Convert to quaternion. */
- axis_angle_to_quat(r, axis, angle);
+ if (LIKELY((angle = normalize_v3_v3(axis, expmap)) != 0.0f)) {
+ axis_angle_normalized_to_quat(r, axis, angle_wrap_rad(angle));
+ }
+ else {
+ unit_qt(r);
+ }
}
/******************************** XYZ Eulers *********************************/
@@ -1322,12 +1323,21 @@ static const RotOrderInfo rotOrders[] = {
* NOTE: since we start at 1 for the values, but arrays index from 0,
* there is -1 factor involved in this process...
*/
-#define GET_ROTATIONORDER_INFO(order) (assert(order >= 0 && order <= 6), (order < 1) ? &rotOrders[0] : &rotOrders[(order) - 1])
+static const RotOrderInfo *get_rotation_order_info(const short order)
+{
+ assert(order >= 0 && order <= 6);
+ if (order < 1)
+ return &rotOrders[0];
+ else if (order < 6)
+ return &rotOrders[order - 1];
+ else
+ return &rotOrders[5];
+}
/* Construct quaternion from Euler angles (in radians). */
void eulO_to_quat(float q[4], const float e[3], const short order)
{
- const RotOrderInfo *R = GET_ROTATIONORDER_INFO(order);
+ const RotOrderInfo *R = get_rotation_order_info(order);
short i = R->axis[0], j = R->axis[1], k = R->axis[2];
double ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
double a[3];
@@ -1372,7 +1382,7 @@ void quat_to_eulO(float e[3], short const order, const float q[4])
/* Construct 3x3 matrix from Euler angles (in radians). */
void eulO_to_mat3(float M[3][3], const float e[3], const short order)
{
- const RotOrderInfo *R = GET_ROTATIONORDER_INFO(order);
+ const RotOrderInfo *R = get_rotation_order_info(order);
short i = R->axis[0], j = R->axis[1], k = R->axis[2];
double ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
@@ -1413,7 +1423,7 @@ void eulO_to_mat3(float M[3][3], const float e[3], const short order)
/* returns two euler calculation methods, so we can pick the best */
static void mat3_to_eulo2(float M[3][3], float eul1[3], float eul2[3], const short order)
{
- const RotOrderInfo *R = GET_ROTATIONORDER_INFO(order);
+ const RotOrderInfo *R = get_rotation_order_info(order);
short i = R->axis[0], j = R->axis[1], k = R->axis[2];
float mat[3][3];
float cy;
@@ -1549,7 +1559,7 @@ void rotate_eulO(float beul[3], const short order, char axis, float ang)
/* the matrix is written to as 3 axis vectors */
void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], const short order)
{
- const RotOrderInfo *R = GET_ROTATIONORDER_INFO(order);
+ const RotOrderInfo *R = get_rotation_order_info(order);
float mat[3][3];
float teul[3];
@@ -1606,7 +1616,7 @@ void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], const short order
void mat4_to_dquat(DualQuat *dq, float basemat[4][4], float mat[4][4])
{
- float *t, *q, dscale[3], scale[3], basequat[4];
+ float *t, *q, dscale[3], scale[3], basequat[4], mat3[3][3];
float baseRS[4][4], baseinv[4][4], baseR[4][4], baseRinv[4][4];
float R[4][4], S[4][4];
@@ -1619,7 +1629,9 @@ void mat4_to_dquat(DualQuat *dq, float basemat[4][4], float mat[4][4])
dscale[1] = scale[1] - 1.0f;
dscale[2] = scale[2] - 1.0f;
- if ((determinant_m4(mat) < 0.0f) || len_v3(dscale) > 1e-4f) {
+ copy_m3_m4(mat3, mat);
+
+ if (!is_orthonormal_m3(mat3) || (determinant_m4(mat) < 0.0f) || len_v3(dscale) > 1e-4f) {
/* extract R and S */
float tmp[4][4];
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 814180bba24..6da0e87355d 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -572,6 +572,27 @@ void project_v3_v3v3(float c[3], const float v1[3], const float v2[3])
c[2] = mul * v2[2];
}
+/**
+ * In this case plane is a 3D vector only (no 4th component).
+ *
+ * Projecting will make \a c a copy of \a v orthogonal to \a v_plane.
+ *
+ * \note If \a v is exactly perpendicular to \a v_plane, \a c will just be a copy of \a v.
+ */
+void project_plane_v3_v3v3(float c[3], const float v[3], const float v_plane[3])
+{
+ float delta[3];
+ project_v3_v3v3(delta, v, v_plane);
+ sub_v3_v3v3(c, v, delta);
+}
+
+void project_plane_v2_v2v2(float c[2], const float v[2], const float v_plane[2])
+{
+ float delta[2];
+ project_v2_v2v2(delta, v, v_plane);
+ sub_v2_v2v2(c, v, delta);
+}
+
/* project a vector on a plane defined by normal and a plane point p */
void project_v3_plane(float v[3], const float n[3], const float p[3])
{
@@ -855,7 +876,7 @@ float normalize_vn_vn(float *array_tar, const float *array_src, const int size)
mul_vn_vn_fl(array_tar, array_src, size, 1.0f / d_sqrt);
}
else {
- fill_vn_fl(array_tar, size, 0.0f);
+ copy_vn_fl(array_tar, size, 0.0f);
d_sqrt = 0.0f;
}
return d_sqrt;
@@ -876,6 +897,16 @@ void range_vn_i(int *array_tar, const int size, const int start)
}
}
+void range_vn_u(unsigned int *array_tar, const int size, const unsigned int start)
+{
+ unsigned int *array_pt = array_tar + (size - 1);
+ unsigned int j = start + (unsigned int)(size - 1);
+ int i = size;
+ while (i--) {
+ *(array_pt--) = j--;
+ }
+}
+
void range_vn_fl(float *array_tar, const int size, const float start, const float step)
{
float *array_pt = array_tar + (size - 1);
@@ -1020,7 +1051,7 @@ void interp_vn_vn(float *array_tar, const float *array_src, const float t, const
}
}
-void fill_vn_i(int *array_tar, const int size, const int val)
+void copy_vn_i(int *array_tar, const int size, const int val)
{
int *tar = array_tar + (size - 1);
int i = size;
@@ -1029,7 +1060,7 @@ void fill_vn_i(int *array_tar, const int size, const int val)
}
}
-void fill_vn_short(short *array_tar, const int size, const short val)
+void copy_vn_short(short *array_tar, const int size, const short val)
{
short *tar = array_tar + (size - 1);
int i = size;
@@ -1038,7 +1069,7 @@ void fill_vn_short(short *array_tar, const int size, const short val)
}
}
-void fill_vn_ushort(unsigned short *array_tar, const int size, const unsigned short val)
+void copy_vn_ushort(unsigned short *array_tar, const int size, const unsigned short val)
{
unsigned short *tar = array_tar + (size - 1);
int i = size;
@@ -1047,7 +1078,7 @@ void fill_vn_ushort(unsigned short *array_tar, const int size, const unsigned sh
}
}
-void fill_vn_uchar(unsigned char *array_tar, const int size, const unsigned char val)
+void copy_vn_uchar(unsigned char *array_tar, const int size, const unsigned char val)
{
unsigned char *tar = array_tar + (size - 1);
int i = size;
@@ -1056,7 +1087,7 @@ void fill_vn_uchar(unsigned char *array_tar, const int size, const unsigned char
}
}
-void fill_vn_fl(float *array_tar, const int size, const float val)
+void copy_vn_fl(float *array_tar, const int size, const float val)
{
float *tar = array_tar + (size - 1);
int i = size;
@@ -1064,3 +1095,38 @@ void fill_vn_fl(float *array_tar, const int size, const float val)
*(tar--) = val;
}
}
+
+/** \name Double precision versions 'db'.
+ * \{ */
+
+void add_vn_vn_d(double *array_tar, const double *array_src, const int size)
+{
+ double *tar = array_tar + (size - 1);
+ const double *src = array_src + (size - 1);
+ int i = size;
+ while (i--) {
+ *(tar--) += *(src--);
+ }
+}
+
+void add_vn_vnvn_d(double *array_tar, const double *array_src_a, const double *array_src_b, const int size)
+{
+ double *tar = array_tar + (size - 1);
+ const double *src_a = array_src_a + (size - 1);
+ const double *src_b = array_src_b + (size - 1);
+ int i = size;
+ while (i--) {
+ *(tar--) = *(src_a--) + *(src_b--);
+ }
+}
+
+void mul_vn_db(double *array_tar, const int size, const double f)
+{
+ double *array_pt = array_tar + (size - 1);
+ int i = size;
+ while (i--) {
+ *(array_pt--) *= f;
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index 6b6a3113e0b..fb33fed33e4 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -611,6 +611,48 @@ MINLINE void negate_v3_short(short r[3])
r[2] = (short)-r[2];
}
+MINLINE void abs_v2(float r[2])
+{
+ r[0] = fabsf(r[0]);
+ r[1] = fabsf(r[1]);
+}
+
+MINLINE void abs_v2_v2(float r[2], const float a[2])
+{
+ r[0] = fabsf(a[0]);
+ r[1] = fabsf(a[1]);
+}
+
+MINLINE void abs_v3(float r[3])
+{
+ r[0] = fabsf(r[0]);
+ r[1] = fabsf(r[1]);
+ r[2] = fabsf(r[2]);
+}
+
+MINLINE void abs_v3_v3(float r[3], const float a[3])
+{
+ r[0] = fabsf(a[0]);
+ r[1] = fabsf(a[1]);
+ r[2] = fabsf(a[2]);
+}
+
+MINLINE void abs_v4(float r[4])
+{
+ r[0] = fabsf(r[0]);
+ r[1] = fabsf(r[1]);
+ r[2] = fabsf(r[2]);
+ r[3] = fabsf(r[3]);
+}
+
+MINLINE void abs_v4_v4(float r[4], const float a[4])
+{
+ r[0] = fabsf(a[0]);
+ r[1] = fabsf(a[1]);
+ r[2] = fabsf(a[2]);
+ r[3] = fabsf(a[3]);
+}
+
MINLINE float dot_v2v2(const float a[2], const float b[2])
{
return a[0] * b[0] + a[1] * b[1];
@@ -638,6 +680,11 @@ MINLINE float dot_v4v4(const float a[4], const float b[4])
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
}
+MINLINE double dot_v3db_v3fl(const double a[3], const float b[3])
+{
+ return a[0] * (double)b[0] + a[1] * (double)b[1] + a[2] * (double)b[2];
+}
+
MINLINE float cross_v2v2(const float a[2], const float b[2])
{
return a[0] * b[1] - a[1] * b[0];
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 72739018399..d411c2605d7 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -57,6 +57,9 @@
# include <shlobj.h>
# include "BLI_winstuff.h"
# include "MEM_guardedalloc.h"
+# include "BLI_alloca.h"
+#else
+# include "unistd.h"
#endif /* WIN32 */
/* local */
@@ -743,7 +746,7 @@ bool BLI_parent_dir(char *path)
BLI_cleanup_dir(NULL, tmp); /* does all the work of normalizing the path for us */
if (!BLI_testextensie(tmp, parent_dir)) {
- BLI_strncpy(path, tmp, sizeof(tmp));
+ strcpy(path, tmp); /* We assume pardir is always shorter... */
return true;
}
else {
@@ -856,6 +859,132 @@ bool BLI_path_frame_range(char *path, int sta, int end, int digits)
}
/**
+ * Get the frame from a filename formatted by blender's frame scheme
+ */
+bool BLI_path_frame_get(char *path, int *r_frame, int *r_numdigits)
+{
+ if (path && *path) {
+ char *file = (char *)BLI_last_slash(path);
+ char *c;
+ int len, numdigits;
+
+ numdigits = *r_numdigits = 0;
+
+ if (file == NULL)
+ file = path;
+
+ /* first get the extension part */
+ len = strlen(file);
+
+ c = file + len;
+
+ /* isolate extension */
+ while (--c != file) {
+ if (*c == '.') {
+ c--;
+ break;
+ }
+ }
+
+ /* find start of number */
+ while (c != (file - 1) && isdigit(*c)) {
+ c--;
+ numdigits++;
+ }
+
+ if (numdigits) {
+ char prevchar;
+
+ c++;
+ prevchar = c[numdigits];
+ c[numdigits] = 0;
+
+ /* was the number really an extension? */
+ *r_frame = atoi(c);
+ c[numdigits] = prevchar;
+
+ *r_numdigits = numdigits;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool BLI_path_frame_strip(char *path, bool setsharp, char *ext)
+{
+ if (path && *path) {
+ char *file = (char *)BLI_last_slash(path);
+ char *c, *suffix;
+ int len;
+ int numdigits = 0;
+
+ if (file == NULL)
+ file = path;
+
+ /* first get the extension part */
+ len = strlen(file);
+
+ c = file + len;
+
+ /* isolate extension */
+ while (--c != file) {
+ if (*c == '.') {
+ c--;
+ break;
+ }
+ }
+
+ suffix = c + 1;
+
+ /* find start of number */
+ while (c != (file - 1) && isdigit(*c)) {
+ c--;
+ numdigits++;
+ }
+
+ c++;
+
+ if(numdigits) {
+ /* logic here is a bit complex. Idea is: if ext has been provided,
+ * fill it with the extension part and do not keep it in filename
+ * if no ext has been provided, just strip the number or fill it with #
+ */
+ if (ext) {
+ while (*suffix) {
+ *ext++ = *suffix++;
+ }
+ *ext = 0;
+
+ if (setsharp) {
+ while (numdigits--) {
+ *c++ = '#';
+ }
+ }
+ *c = 0;
+ }
+ else {
+ if (setsharp) {
+ while (numdigits--) {
+ *c++ = '#';
+ }
+ }
+ while (*suffix) {
+ *c++ = *suffix++;
+ }
+ *c = 0;
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/**
* Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range
*/
bool BLI_path_frame_check_chars(const char *path)
@@ -1018,6 +1147,114 @@ bool BLI_path_cwd(char *path)
return wasrelative;
}
+#ifdef _WIN32
+/**
+ * Tries appending each of the semicolon-separated extensions in the PATHEXT
+ * environment variable (Windows-only) onto *name in turn until such a file is found.
+ * Returns success/failure.
+ */
+bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen)
+{
+ bool retval = false;
+ int type;
+
+ type = BLI_exists(name);
+ if ((type == 0) || S_ISDIR(type)) {
+ /* typically 3-5, ".EXE", ".BAT"... etc */
+ const int ext_max = 12;
+ const char *ext = getenv("PATHEXT");
+ if (ext) {
+ const int name_len = strlen(name);
+ char *filename = alloca(name_len + ext_max);
+ char *filename_ext;
+ const char *ext_next;
+
+ /* null terminated in the loop */
+ memcpy(filename, name, name_len);
+ filename_ext = filename + name_len;
+
+ do {
+ int ext_len;
+ ext_next = strchr(ext, ';');
+ ext_len = ext_next ? ((ext_next++) - ext) : strlen(ext);
+
+ if (LIKELY(ext_len < ext_max)) {
+ memcpy(filename_ext, ext, ext_len);
+ filename_ext[ext_len] = '\0';
+
+ type = BLI_exists(filename);
+ if (type && (!S_ISDIR(type))) {
+ retval = true;
+ BLI_strncpy(name, filename, maxlen);
+ break;
+ }
+ }
+ } while ((ext = ext_next));
+ }
+ }
+ else {
+ retval = true;
+ }
+
+ return retval;
+}
+#endif /* WIN32 */
+
+/**
+ * Search for a binary (executable)
+ */
+bool BLI_path_program_search(
+ char *fullname, const size_t maxlen,
+ const char *name)
+{
+ const char *path;
+ bool retval = false;
+
+#ifdef _WIN32
+ const char separator = ';';
+#else
+ const char separator = ':';
+#endif
+
+ path = getenv("PATH");
+ if (path) {
+ char filename[FILE_MAX];
+ const char *temp;
+
+ do {
+ temp = strchr(path, separator);
+ if (temp) {
+ strncpy(filename, path, temp - path);
+ filename[temp - path] = 0;
+ path = temp + 1;
+ }
+ else {
+ strncpy(filename, path, sizeof(filename));
+ }
+
+ BLI_path_append(filename, maxlen, name);
+ if (
+#ifdef _WIN32
+ BLI_path_program_extensions_add_win32(filename, maxlen)
+#else
+ BLI_exists(filename)
+#endif
+ )
+ {
+ BLI_strncpy(fullname, filename, maxlen);
+ retval = true;
+ break;
+ }
+ } while (temp);
+ }
+
+ if (retval == false) {
+ *fullname = '\0';
+ }
+
+ return retval;
+}
+
/**
* Copies into *last the part of *dir following the second-last slash.
*/
@@ -1109,33 +1346,18 @@ void BLI_char_switch(char *string, char from, char to)
*/
void BLI_make_exist(char *dir)
{
- int a;
- char par_path[PATH_MAX + 3];
+ bool valid_path = true;
- BLI_char_switch(dir, ALTSEP, SEP);
+ /* Loop as long as cur path is not a dir, and we can get a parent path. */
+ while ((BLI_access(dir, R_OK) != 0) && (valid_path = BLI_parent_dir(dir)));
- a = strlen(dir);
-
- for (BLI_join_dirfile(par_path, sizeof(par_path), dir, FILENAME_PARENT);
- !(BLI_is_dir(dir) && BLI_exists(par_path));
- BLI_join_dirfile(par_path, sizeof(par_path), dir, FILENAME_PARENT))
- {
- a--;
- while (dir[a] != SEP) {
- a--;
- if (a <= 0) break;
- }
- if (a >= 0) {
- dir[a + 1] = '\0';
- }
- else {
+ /* If we could not find an existing dir, use default root... */
+ if (!valid_path || !dir[0]) {
#ifdef WIN32
- get_default_root(dir);
+ get_default_root(dir);
#else
- strcpy(dir, "/");
+ strcpy(dir, "/");
#endif
- break;
- }
}
}
diff --git a/source/blender/blenlib/intern/polyfill2d.c b/source/blender/blenlib/intern/polyfill2d.c
index 3aadbe5f1df..629bed10191 100644
--- a/source/blender/blenlib/intern/polyfill2d.c
+++ b/source/blender/blenlib/intern/polyfill2d.c
@@ -179,7 +179,7 @@ BLI_INLINE eSign signum_enum(float a)
* alternative version of #area_tri_signed_v2
* needed because of float precision issues
*
- * \note removes / 2 since its not needed since we only need ths sign.
+ * \note removes / 2 since its not needed since we only need the sign.
*/
BLI_INLINE float area_tri_signed_v2_alt_2x(const float v1[2], const float v2[2], const float v3[2])
{
diff --git a/source/blender/blenlib/intern/polyfill2d_beautify.c b/source/blender/blenlib/intern/polyfill2d_beautify.c
index ba71f52b530..46f9251bea7 100644
--- a/source/blender/blenlib/intern/polyfill2d_beautify.c
+++ b/source/blender/blenlib/intern/polyfill2d_beautify.c
@@ -430,17 +430,19 @@ void BLI_polyfill_beautify(
}
if (!is_boundary_edge(e_pair[0], e_pair[1], coord_last)) {
- struct PolyEdge *e = BLI_edgehash_lookup(ehash, e_pair[0], e_pair[1]);
- if (e == NULL) {
+ struct PolyEdge *e;
+ void **val_p;
+
+ if (!BLI_edgehash_ensure_p(ehash, e_pair[0], e_pair[1], &val_p)) {
e = &edges[edges_tot_used++];
- BLI_edgehash_insert(ehash, e_pair[0], e_pair[1], e);
+ *val_p = e;
memcpy(e->verts, e_pair, sizeof(e->verts));
#ifndef NDEBUG
e->faces[!e_index] = (unsigned int)-1;
#endif
}
else {
-
+ e = *val_p;
/* ensure each edge only ever has 2x users */
#ifndef NDEBUG
BLI_assert(e->faces[e_index] == (unsigned int)-1);
diff --git a/source/blender/blenlib/intern/quadric.c b/source/blender/blenlib/intern/quadric.c
index 814d05ca80e..588cd9c2cb5 100644
--- a/source/blender/blenlib/intern/quadric.c
+++ b/source/blender/blenlib/intern/quadric.c
@@ -29,20 +29,24 @@
* \note This isn't fully complete,
* possible there are other useful functions to add here.
*
- * \note try to follow BLI_math naming convention here.
+ * \note follow BLI_math naming convention here.
+ *
+ * \note this uses doubles for internal calculations,
+ * even though input/output are floats in some cases.
+ *
+ * This is done because the cases quadrics are useful
+ * often need high precision, see T44780.
*/
-//#include <string.h>
-
#include "BLI_math.h"
#include "BLI_strict_flags.h"
#include "BLI_quadric.h" /* own include */
-#define QUADRIC_FLT_TOT (sizeof(Quadric) / sizeof(float))
+#define QUADRIC_FLT_TOT (sizeof(Quadric) / sizeof(double))
-void BLI_quadric_from_v3_dist(Quadric *q, const float v[3], const float offset)
+void BLI_quadric_from_plane(Quadric *q, const double v[4])
{
q->a2 = v[0] * v[0];
q->b2 = v[1] * v[1];
@@ -52,33 +56,33 @@ void BLI_quadric_from_v3_dist(Quadric *q, const float v[3], const float offset)
q->ac = v[0] * v[2];
q->bc = v[1] * v[2];
- q->ad = v[0] * offset;
- q->bd = v[1] * offset;
- q->cd = v[2] * offset;
+ q->ad = v[0] * v[3];
+ q->bd = v[1] * v[3];
+ q->cd = v[2] * v[3];
- q->d2 = offset * offset;
+ q->d2 = v[3] * v[3];
}
void BLI_quadric_to_tensor_m3(const Quadric *q, float m[3][3])
{
- m[0][0] = q->a2;
- m[0][1] = q->ab;
- m[0][2] = q->ac;
+ m[0][0] = (float)q->a2;
+ m[0][1] = (float)q->ab;
+ m[0][2] = (float)q->ac;
- m[1][0] = q->ab;
- m[1][1] = q->b2;
- m[1][2] = q->bc;
+ m[1][0] = (float)q->ab;
+ m[1][1] = (float)q->b2;
+ m[1][2] = (float)q->bc;
- m[2][0] = q->ac;
- m[2][1] = q->bc;
- m[2][2] = q->c2;
+ m[2][0] = (float)q->ac;
+ m[2][1] = (float)q->bc;
+ m[2][2] = (float)q->c2;
}
void BLI_quadric_to_vector_v3(const Quadric *q, float v[3])
{
- v[0] = q->ad;
- v[1] = q->bd;
- v[2] = q->cd;
+ v[0] = (float)q->ad;
+ v[1] = (float)q->bd;
+ v[2] = (float)q->cd;
}
void BLI_quadric_clear(Quadric *q)
@@ -88,25 +92,26 @@ void BLI_quadric_clear(Quadric *q)
void BLI_quadric_add_qu_qu(Quadric *a, const Quadric *b)
{
- add_vn_vn((float *)a, (float *)b, QUADRIC_FLT_TOT);
+ add_vn_vn_d((double *)a, (double *)b, QUADRIC_FLT_TOT);
}
void BLI_quadric_add_qu_ququ(Quadric *r, const Quadric *a, const Quadric *b)
{
- add_vn_vnvn((float *)r, (const float *)a, (const float *)b, QUADRIC_FLT_TOT);
+ add_vn_vnvn_d((double *)r, (const double *)a, (const double *)b, QUADRIC_FLT_TOT);
}
-void BLI_quadric_mul(Quadric *a, const float scalar)
+void BLI_quadric_mul(Quadric *a, const double scalar)
{
- mul_vn_fl((float *)a, QUADRIC_FLT_TOT, scalar);
+ mul_vn_db((double *)a, QUADRIC_FLT_TOT, scalar);
}
-float BLI_quadric_evaluate(const Quadric *q, const float v[3])
+double BLI_quadric_evaluate(const Quadric *q, const float v_fl[3])
{
- return (v[0] * v[0] * q->a2 + 2.0f * v[0] * v[1] * q->ab + 2.0f * v[0] * v[2] * q->ac + 2.0f * v[0] * q->ad +
- v[1] * v[1] * q->b2 + 2.0f * v[1] * v[2] * q->bc + 2.0f * v[1] * q->bd +
- v[2] * v[2] * q->c2 + 2.0f * v[2] * q->cd +
- q->d2);
+ const double v[3] = {UNPACK3(v_fl)};
+ return ((q->a2 * v[0] * v[0]) + (q->ab * 2 * v[0] * v[1]) + (q->ac * 2 * v[0] * v[2]) + (q->ad * 2 * v[0]) +
+ (q->b2 * v[1] * v[1]) + (q->bc * 2 * v[1] * v[2]) + (q->bd * 2 * v[1]) +
+ (q->c2 * v[2] * v[2]) + (q->cd * 2 * v[2]) +
+ (q->d2));
}
bool BLI_quadric_optimize(const Quadric *q, float v[3], const float epsilon)
diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c
index a03b236b5c6..66c568a7ff3 100644
--- a/source/blender/blenlib/intern/rand.c
+++ b/source/blender/blenlib/intern/rand.c
@@ -68,6 +68,9 @@ RNG *BLI_rng_new(unsigned int seed)
return rng;
}
+/**
+ * A version of #BLI_rng_new that hashes the seed.
+ */
RNG *BLI_rng_new_srandom(unsigned int seed)
{
RNG *rng = MEM_mallocN(sizeof(*rng), "rng");
@@ -87,6 +90,9 @@ void BLI_rng_seed(RNG *rng, unsigned int seed)
rng->X = (((uint64_t) seed) << 16) | LOWSEED;
}
+/**
+ * Use a hash table to create better seed.
+ */
void BLI_rng_srandom(RNG *rng, unsigned int seed)
{
BLI_rng_seed(rng, seed + hash[seed & 255]);
@@ -113,11 +119,17 @@ unsigned int BLI_rng_get_uint(RNG *rng)
return (unsigned int) (rng->X >> 17);
}
+/**
+ * \return Random value (0..1), but never 1.0.
+ */
double BLI_rng_get_double(RNG *rng)
{
return (double) BLI_rng_get_int(rng) / 0x80000000;
}
+/**
+ * \return Random value (0..1), but never 1.0.
+ */
float BLI_rng_get_float(RNG *rng)
{
return (float) BLI_rng_get_int(rng) / 0x80000000;
@@ -172,7 +184,7 @@ void BLI_rng_get_tri_sample_float_v2(
void BLI_rng_shuffle_array(RNG *rng, void *data, unsigned int elem_size_i, unsigned int elem_tot)
{
- const size_t elem_size = (unsigned int)elem_size_i;
+ const size_t elem_size = (size_t)elem_size_i;
unsigned int i = elem_tot;
void *temp;
@@ -196,6 +208,11 @@ void BLI_rng_shuffle_array(RNG *rng, void *data, unsigned int elem_size_i, unsig
free(temp);
}
+/**
+ * Simulate getting \a n random values.
+ *
+ * \note Useful when threaded code needs consistent values, independent of task division.
+ */
void BLI_rng_skip(RNG *rng, int n)
{
while (n--) {
@@ -208,7 +225,6 @@ void BLI_rng_skip(RNG *rng, int n)
/* initialize with some non-zero seed */
static RNG theBLI_rng = {611330372042337130};
-/* using hash table to create better seed */
void BLI_srandom(unsigned int seed)
{
BLI_rng_srandom(&theBLI_rng, seed);
diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c
index 61e5783cd3e..1edc9002611 100644
--- a/source/blender/blenlib/intern/rct.c
+++ b/source/blender/blenlib/intern/rct.c
@@ -571,3 +571,46 @@ void print_rcti(const char *str, const rcti *rect)
printf("%s: xmin %d, xmax %d, ymin %d, ymax %d (%dx%d)\n", str,
rect->xmin, rect->xmax, rect->ymin, rect->ymax, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect));
}
+
+
+/* -------------------------------------------------------------------- */
+/* Comprehensive math (float only) */
+
+/** \name Rect math functions
+ * \{ */
+
+#define ROTATE_SINCOS(r_vec, mat2, vec) { \
+ (r_vec)[0] = (mat2)[1] * (vec)[0] + (+(mat2)[0]) * (vec)[1]; \
+ (r_vec)[1] = (mat2)[0] * (vec)[0] + (-(mat2)[1]) * (vec)[1]; \
+} ((void)0)
+
+/**
+ * Expand the rectangle to fit a rotated \a src.
+ */
+void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle)
+{
+ const float mat2[2] = {sinf(angle), cosf(angle)};
+ const float cent[2] = {BLI_rctf_cent_x(src), BLI_rctf_cent_y(src)};
+ float corner[2], corner_rot[2], corder_max[2];
+
+ /* x is same for both corners */
+ corner[0] = src->xmax - cent[0];
+ corner[1] = src->ymax - cent[1];
+ ROTATE_SINCOS(corner_rot, mat2, corner);
+ corder_max[0] = fabsf(corner_rot[0]);
+ corder_max[1] = fabsf(corner_rot[1]);
+
+ corner[1] *= -1;
+ ROTATE_SINCOS(corner_rot, mat2, corner);
+ corder_max[0] = MAX2(corder_max[0], fabsf(corner_rot[0]));
+ corder_max[1] = MAX2(corder_max[1], fabsf(corner_rot[1]));
+
+ dst->xmin = cent[0] - corder_max[0];
+ dst->xmax = cent[0] + corder_max[0];
+ dst->ymin = cent[1] - corder_max[1];
+ dst->ymax = cent[1] + corder_max[1];
+}
+
+#undef ROTATE_SINCOS
+
+/** \} */
diff --git a/source/blender/blenlib/intern/scanfill_utils.c b/source/blender/blenlib/intern/scanfill_utils.c
index a606ac41aa1..d0420a30448 100644
--- a/source/blender/blenlib/intern/scanfill_utils.c
+++ b/source/blender/blenlib/intern/scanfill_utils.c
@@ -112,11 +112,13 @@ void BLI_scanfill_view3d_dump(ScanFillContext *sf_ctx)
static ListBase *edge_isect_ls_ensure(GHash *isect_hash, ScanFillEdge *eed)
{
ListBase *e_ls;
- e_ls = BLI_ghash_lookup(isect_hash, eed);
- if (e_ls == NULL) {
- e_ls = MEM_callocN(sizeof(ListBase), __func__);
- BLI_ghash_insert(isect_hash, eed, e_ls);
+ void **val_p;
+
+ if (!BLI_ghash_ensure_p(isect_hash, eed, &val_p)) {
+ *val_p = MEM_callocN(sizeof(ListBase), __func__);
}
+ e_ls = *val_p;
+
return e_ls;
}
diff --git a/source/blender/blenlib/intern/stack.c b/source/blender/blenlib/intern/stack.c
index 2d3a2f77a3e..3c9e1a52cda 100644
--- a/source/blender/blenlib/intern/stack.c
+++ b/source/blender/blenlib/intern/stack.c
@@ -216,6 +216,41 @@ void BLI_stack_discard(BLI_Stack *stack)
}
}
+/**
+ * Discards all elements without freeing.
+ */
+void BLI_stack_clear(BLI_Stack *stack)
+{
+#ifdef USE_TOTELEM
+ if (UNLIKELY(stack->totelem == 0)) {
+ return;
+ }
+ stack->totelem = 0;
+#else
+ if (UNLIKELY(stack->chunk_curr == NULL)) {
+ return;
+ }
+#endif
+
+ stack->chunk_index = stack->chunk_elem_max - 1;
+
+ if (stack->chunk_free) {
+ if (stack->chunk_curr) {
+ /* move all used chunks into tail of free list */
+ struct StackChunk *chunk_free_last = stack->chunk_free;
+ while (chunk_free_last->next) {
+ chunk_free_last = chunk_free_last->next;
+ }
+ chunk_free_last->next = stack->chunk_curr;
+ stack->chunk_curr = NULL;
+ }
+ }
+ else {
+ stack->chunk_free = stack->chunk_curr;
+ stack->chunk_curr = NULL;
+ }
+}
+
size_t BLI_stack_count(const BLI_Stack *stack)
{
#ifdef USE_TOTELEM
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index 46c5a11949c..6394187d40a 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -35,11 +35,6 @@
#include <stdio.h>
#include <stdlib.h>
-#ifndef WIN32
-# include <dirent.h>
-#endif
-
-#include <time.h>
#include <sys/stat.h>
#if defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun__) || defined(__sun)
@@ -79,17 +74,13 @@
/* lib includes */
#include "MEM_guardedalloc.h"
-#include "DNA_listBase.h"
-
-#include "BLI_listbase.h"
+#include "BLI_utildefines.h"
#include "BLI_linklist.h"
#include "BLI_string.h"
#include "BLI_fileops.h"
#include "BLI_fileops_types.h"
#include "BLI_path_util.h"
-#include "../imbuf/IMB_imbuf.h"
-
/**
* Copies the current working directory into *dir (max size maxncpy), and
* returns a pointer to same.
@@ -107,42 +98,6 @@ char *BLI_current_working_dir(char *dir, const size_t maxncpy)
return getcwd(dir, maxncpy);
}
-/*
- * Ordering function for sorting lists of files/directories. Returns -1 if
- * entry1 belongs before entry2, 0 if they are equal, 1 if they should be swapped.
- */
-static int bli_compare(struct direntry *entry1, struct direntry *entry2)
-{
- /* type is equal to stat.st_mode */
-
- /* directories come before non-directories */
- if (S_ISDIR(entry1->type)) {
- if (S_ISDIR(entry2->type) == 0) return (-1);
- }
- else {
- if (S_ISDIR(entry2->type)) return (1);
- }
- /* non-regular files come after regular files */
- if (S_ISREG(entry1->type)) {
- if (S_ISREG(entry2->type) == 0) return (-1);
- }
- else {
- if (S_ISREG(entry2->type)) return (1);
- }
- /* arbitrary, but consistent, ordering of different types of non-regular files */
- if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
- if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
-
- /* OK, now we know their S_IFMT fields are the same, go on to a name comparison */
- /* make sure "." and ".." are always first */
- if (FILENAME_IS_CURRENT(entry1->relname)) return (-1);
- if (FILENAME_IS_CURRENT(entry2->relname)) return (1);
- if (FILENAME_IS_PARENT(entry1->relname)) return (-1);
- if (FILENAME_IS_PARENT(entry2->relname)) return (1);
-
- return (BLI_natstrcmp(entry1->relname, entry2->relname));
-}
-
/**
* Returns the number of free bytes on the volume containing the specified pathname. */
/* Not actually used anywhere.
@@ -204,267 +159,6 @@ double BLI_dir_free_space(const char *dir)
#endif
}
-struct BuildDirCtx {
- struct direntry *files; /* array[nrfiles] */
- int nrfiles;
-};
-
-/**
- * Scans the directory named *dirname and appends entries for its contents to files.
- */
-static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
-{
- struct ListBase dirbase = {NULL, NULL};
- int newnum = 0;
- DIR *dir;
-
- if ((dir = opendir(dirname)) != NULL) {
- const struct dirent *fname;
- while ((fname = readdir(dir)) != NULL) {
- struct dirlink * const dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
- if (dlink != NULL) {
- dlink->name = BLI_strdup(fname->d_name);
- BLI_addhead(&dirbase, dlink);
- newnum++;
- }
- }
-
- if (newnum) {
- if (dir_ctx->files) {
- void * const tmp = MEM_reallocN(dir_ctx->files, (dir_ctx->nrfiles + newnum) * sizeof(struct direntry));
- if (tmp) {
- dir_ctx->files = (struct direntry *)tmp;
- }
- else { /* realloc fail */
- MEM_freeN(dir_ctx->files);
- dir_ctx->files = NULL;
- }
- }
-
- if (dir_ctx->files == NULL)
- dir_ctx->files = (struct direntry *)MEM_mallocN(newnum * sizeof(struct direntry), __func__);
-
- if (dir_ctx->files) {
- struct dirlink * dlink = (struct dirlink *) dirbase.first;
- struct direntry *file = &dir_ctx->files[dir_ctx->nrfiles];
- while (dlink) {
- char fullname[PATH_MAX];
- memset(file, 0, sizeof(struct direntry));
- file->relname = dlink->name;
- file->path = BLI_strdupcat(dirname, dlink->name);
- BLI_join_dirfile(fullname, sizeof(fullname), dirname, dlink->name);
- if (BLI_stat(fullname, &file->s) != -1) {
- file->type = file->s.st_mode;
- }
- file->flags = 0;
- dir_ctx->nrfiles++;
- file++;
- dlink = dlink->next;
- }
- }
- else {
- printf("Couldn't get memory for dir\n");
- exit(1);
- }
-
- BLI_freelist(&dirbase);
- if (dir_ctx->files) {
- qsort(dir_ctx->files, dir_ctx->nrfiles, sizeof(struct direntry), (int (*)(const void *, const void *))bli_compare);
- }
- }
- else {
- printf("%s empty directory\n", dirname);
- }
-
- closedir(dir);
- }
- else {
- printf("%s non-existent directory\n", dirname);
- }
-}
-
-/**
- * Fills in the "mode[123]", "size" and "string" fields in the elements of the files
- * array with descriptive details about each item. "string" will have a format similar to "ls -l".
- */
-static void bli_adddirstrings(struct BuildDirCtx *dir_ctx)
-{
- const char *types[8] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
- /* symbolic display, indexed by mode field value */
- int num;
-#ifdef WIN32
- __int64 st_size;
-#else
- off_t st_size;
- int mode;
-#endif
-
- struct direntry *file;
- struct tm *tm;
- time_t zero = 0;
-
- for (num = 0, file = dir_ctx->files; num < dir_ctx->nrfiles; num++, file++) {
-
-
- /* Mode */
-#ifdef WIN32
- BLI_strncpy(file->mode1, types[0], sizeof(file->mode1));
- BLI_strncpy(file->mode2, types[0], sizeof(file->mode2));
- BLI_strncpy(file->mode3, types[0], sizeof(file->mode3));
-#else
- mode = file->s.st_mode;
-
- BLI_strncpy(file->mode1, types[(mode & 0700) >> 6], sizeof(file->mode1));
- BLI_strncpy(file->mode2, types[(mode & 0070) >> 3], sizeof(file->mode2));
- BLI_strncpy(file->mode3, types[(mode & 0007)], sizeof(file->mode3));
-
- if (((mode & S_ISGID) == S_ISGID) && (file->mode2[2] == '-')) file->mode2[2] = 'l';
-
- if (mode & (S_ISUID | S_ISGID)) {
- if (file->mode1[2] == 'x') file->mode1[2] = 's';
- else file->mode1[2] = 'S';
-
- if (file->mode2[2] == 'x') file->mode2[2] = 's';
- }
-
- if (mode & S_ISVTX) {
- if (file->mode3[2] == 'x') file->mode3[2] = 't';
- else file->mode3[2] = 'T';
- }
-#endif
-
-
- /* User */
-#ifdef WIN32
- strcpy(file->owner, "user");
-#else
- {
- struct passwd *pwuser;
- pwuser = getpwuid(file->s.st_uid);
- if (pwuser) {
- BLI_strncpy(file->owner, pwuser->pw_name, sizeof(file->owner));
- }
- else {
- BLI_snprintf(file->owner, sizeof(file->owner), "%u", file->s.st_uid);
- }
- }
-#endif
-
-
- /* Time */
- tm = localtime(&file->s.st_mtime);
- // prevent impossible dates in windows
- if (tm == NULL) tm = localtime(&zero);
- strftime(file->time, sizeof(file->time), "%H:%M", tm);
- strftime(file->date, sizeof(file->date), "%d-%b-%y", tm);
-
-
- /* Size */
- /*
- * Seems st_size is signed 32-bit value in *nix and Windows. This
- * will buy us some time until files get bigger than 4GB or until
- * everyone starts using __USE_FILE_OFFSET64 or equivalent.
- */
- st_size = file->s.st_size;
-
- if (st_size > 1024 * 1024 * 1024) {
- BLI_snprintf(file->size, sizeof(file->size), "%.2f GiB", ((double)st_size) / (1024 * 1024 * 1024));
- }
- else if (st_size > 1024 * 1024) {
- BLI_snprintf(file->size, sizeof(file->size), "%.1f MiB", ((double)st_size) / (1024 * 1024));
- }
- else if (st_size > 1024) {
- BLI_snprintf(file->size, sizeof(file->size), "%d KiB", (int)(st_size / 1024));
- }
- else {
- BLI_snprintf(file->size, sizeof(file->size), "%d B", (int)st_size);
- }
- }
-}
-
-/**
- * Scans the contents of the directory named *dirname, and allocates and fills in an
- * array of entries describing them in *filelist.
- *
- * \return The length of filelist array.
- */
-unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **filelist)
-{
- struct BuildDirCtx dir_ctx;
-
- dir_ctx.nrfiles = 0;
- dir_ctx.files = NULL;
-
- bli_builddir(&dir_ctx, dirname);
- bli_adddirstrings(&dir_ctx);
-
- if (dir_ctx.files) {
- *filelist = dir_ctx.files;
- }
- else {
- // keep blender happy. Blender stores this in a variable
- // where 0 has special meaning.....
- *filelist = MEM_mallocN(sizeof(**filelist), __func__);
- }
-
- return dir_ctx.nrfiles;
-}
-
-/**
- * Deep-duplicate of an array of direntries, including the array itself.
- *
- * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over.
- */
-void BLI_filelist_duplicate(
- struct direntry **dest_filelist, struct direntry *src_filelist, unsigned int nrentries,
- void *(*dup_poin)(void *))
-{
- unsigned int i;
-
- *dest_filelist = MEM_mallocN(sizeof(**dest_filelist) * (size_t)(nrentries), __func__);
- for (i = 0; i < nrentries; ++i) {
- struct direntry * const src = &src_filelist[i];
- struct direntry *dest = &(*dest_filelist)[i];
- *dest = *src;
- if (dest->image) {
- dest->image = IMB_dupImBuf(src->image);
- }
- if (dest->relname) {
- dest->relname = MEM_dupallocN(src->relname);
- }
- if (dest->path) {
- dest->path = MEM_dupallocN(src->path);
- }
- if (dest->poin && dup_poin) {
- dest->poin = dup_poin(src->poin);
- }
- }
-}
-
-/**
- * frees storage for an array of direntries, including the array itself.
- */
-void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries, void (*free_poin)(void *))
-{
- unsigned int i;
- for (i = 0; i < nrentries; ++i) {
- struct direntry *entry = filelist + i;
- if (entry->image) {
- IMB_freeImBuf(entry->image);
- }
- if (entry->relname)
- MEM_freeN(entry->relname);
- if (entry->path)
- MEM_freeN(entry->path);
- if (entry->poin && free_poin)
- free_poin(entry->poin);
- }
-
- if (filelist != NULL) {
- MEM_freeN(filelist);
- }
-}
-
/**
* Returns the file size of an opened file descriptor.
@@ -602,6 +296,11 @@ LinkNode *BLI_file_read_as_lines(const char *name)
size = (size_t)ftell(fp);
fseek(fp, 0, SEEK_SET);
+ if (UNLIKELY(size == (size_t)-1)) {
+ fclose(fp);
+ return NULL;
+ }
+
buf = MEM_mallocN(size, "file_as_lines");
if (buf) {
size_t i, last = 0;
@@ -674,4 +373,3 @@ bool BLI_file_older(const char *file1, const char *file2)
#endif
return (st1.st_mtime < st2.st_mtime);
}
-
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index cc5a90dbc39..e41e52a7c6e 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -231,6 +231,30 @@ size_t BLI_vsnprintf(char *__restrict buffer, size_t maxncpy, const char *__rest
}
/**
+ * A version of #BLI_vsnprintf that returns ``strlen(buffer)``
+ */
+size_t BLI_vsnprintf_rlen(char *__restrict buffer, size_t maxncpy, const char *__restrict format, va_list arg)
+{
+ size_t n;
+
+ BLI_assert(buffer != NULL);
+ BLI_assert(maxncpy > 0);
+ BLI_assert(format != NULL);
+
+ n = (size_t)vsnprintf(buffer, maxncpy, format, arg);
+
+ if (n != -1 && n < maxncpy) {
+ /* pass */
+ }
+ else {
+ n = maxncpy - 1;
+ }
+ buffer[n] = '\0';
+
+ return n;
+}
+
+/**
* Portable replacement for #snprintf
*/
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
@@ -250,6 +274,25 @@ size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict
}
/**
+ * A version of #BLI_snprintf that returns ``strlen(dst)``
+ */
+size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
+{
+ size_t n;
+ va_list arg;
+
+#ifdef DEBUG_STRSIZE
+ memset(dst, 0xff, sizeof(*dst) * maxncpy);
+#endif
+
+ va_start(arg, format);
+ n = BLI_vsnprintf_rlen(dst, maxncpy, format, arg);
+ va_end(arg);
+
+ return n;
+}
+
+/**
* Print formatted string into a newly #MEM_mallocN'd string
* and return it.
*/
diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c
index 67ff532cb6f..22f44a38c7a 100644
--- a/source/blender/blenlib/intern/string_utf8.c
+++ b/source/blender/blenlib/intern/string_utf8.c
@@ -329,8 +329,8 @@ size_t BLI_strnlen_utf8_ex(const char *strc, const size_t maxlen, size_t *r_len_
}
/**
- * \param start the string to measure the length.
- * \param maxlen the string length (in bytes)
+ * \param strc: the string to measure the length.
+ * \param maxlen: the string length (in bytes)
* \return the unicode length (not in bytes!)
*/
size_t BLI_strnlen_utf8(const char *strc, const size_t maxlen)
@@ -599,14 +599,14 @@ unsigned int BLI_str_utf8_as_unicode_step(const char *__restrict p, size_t *__re
/* was g_unichar_to_utf8 */
/**
* BLI_str_utf8_from_unicode:
- * @c a Unicode character code
- * \param outbuf output buffer, must have at least 6 bytes of space.
+ * \param c: a Unicode character code
+ * \param outbuf: output buffer, must have at least 6 bytes of space.
* If %NULL, the length will be computed and returned
* and nothing will be written to outbuf.
*
* Converts a single character to UTF-8.
*
- * Return value: number of bytes written
+ * \return number of bytes written
**/
size_t BLI_str_utf8_from_unicode(unsigned int c, char *outbuf)
{
diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c
index b6b0f14a4e2..5d1bdd6d978 100644
--- a/source/blender/blenlib/intern/system.c
+++ b/source/blender/blenlib/intern/system.c
@@ -99,8 +99,7 @@ void BLI_system_backtrace(FILE *fp)
/* Windows */
#elif defined(_MSC_VER)
- (void)fp;
-#if defined WIN32
+#ifndef NDEBUG
#define MAXSYMBOL 256
#define SIZE 100
unsigned short i;
@@ -127,11 +126,12 @@ void BLI_system_backtrace(FILE *fp)
MEM_freeN(symbolinfo);
#undef MAXSYMBOL
#undef SIZE
-#endif
-
+#else
+ fprintf(fp, "Crash backtrace not supported on release builds\n");
+#endif /* NDEBUG */
+#else /* _MSC_VER */
/* ------------------ */
/* non msvc/osx/linux */
-#else
(void)fp;
#endif
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index d187a8d1968..08d40a158ca 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -417,6 +417,16 @@ void BLI_task_pool_work_and_wait(TaskPool *pool)
BLI_mutex_unlock(&pool->num_mutex);
}
+int BLI_pool_get_num_threads(TaskPool *pool)
+{
+ if (pool->num_threads != 0) {
+ return pool->num_threads;
+ }
+ else {
+ return BLI_task_scheduler_num_threads(pool->scheduler);
+ }
+}
+
void BLI_pool_set_num_threads(TaskPool *pool, int num_threads)
{
/* NOTE: Don't try to modify threads while tasks are running! */
@@ -498,16 +508,14 @@ BLI_INLINE bool parallel_range_next_iter_get(
int * __restrict iter, int * __restrict count)
{
bool result = false;
+ BLI_spin_lock(&state->lock);
if (state->iter < state->stop) {
- BLI_spin_lock(&state->lock);
- if (state->iter < state->stop) {
- *count = min_ii(state->chunk_size, state->stop - state->iter);
- *iter = state->iter;
- state->iter += *count;
- result = true;
- }
- BLI_spin_unlock(&state->lock);
+ *count = min_ii(state->chunk_size, state->stop - state->iter);
+ *iter = state->iter;
+ state->iter += *count;
+ result = true;
}
+ BLI_spin_unlock(&state->lock);
return result;
}
diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c
index ded2fd7e06d..50295954192 100644
--- a/source/blender/blenlib/intern/threads.c
+++ b/source/blender/blenlib/intern/threads.c
@@ -122,6 +122,7 @@ static pthread_mutex_t _nodes_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _movieclip_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _colormanage_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _fftw_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t _view3d_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_t mainid;
static int thread_levels = 0; /* threads can be invoked inside threads */
static int num_threads_override = 0;
@@ -198,6 +199,7 @@ void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot)
}
}
+ BLI_spin_lock(&_malloc_lock);
if (thread_levels == 0) {
MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
@@ -210,6 +212,7 @@ void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot)
}
thread_levels++;
+ BLI_spin_unlock(&_malloc_lock);
}
/* amount of available threads */
@@ -328,9 +331,11 @@ void BLI_end_threads(ListBase *threadbase)
BLI_freelistN(threadbase);
}
+ BLI_spin_lock(&_malloc_lock);
thread_levels--;
if (thread_levels == 0)
MEM_set_lock_callback(NULL, NULL);
+ BLI_spin_unlock(&_malloc_lock);
}
/* System Information */
@@ -402,6 +407,8 @@ void BLI_lock_thread(int type)
pthread_mutex_lock(&_colormanage_lock);
else if (type == LOCK_FFTW)
pthread_mutex_lock(&_fftw_lock);
+ else if (type == LOCK_VIEW3D)
+ pthread_mutex_lock(&_view3d_lock);
}
void BLI_unlock_thread(int type)
@@ -426,6 +433,8 @@ void BLI_unlock_thread(int type)
pthread_mutex_unlock(&_colormanage_lock);
else if (type == LOCK_FFTW)
pthread_mutex_unlock(&_fftw_lock);
+ else if (type == LOCK_VIEW3D)
+ pthread_mutex_unlock(&_view3d_lock);
}
/* Mutex Locks */
@@ -797,10 +806,12 @@ void BLI_begin_threaded_malloc(void)
/* Used for debug only */
/* BLI_assert(thread_levels >= 0); */
+ BLI_spin_lock(&_malloc_lock);
if (thread_levels == 0) {
MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
}
thread_levels++;
+ BLI_spin_unlock(&_malloc_lock);
}
void BLI_end_threaded_malloc(void)
@@ -808,8 +819,10 @@ void BLI_end_threaded_malloc(void)
/* Used for debug only */
/* BLI_assert(thread_levels >= 0); */
+ BLI_spin_lock(&_malloc_lock);
thread_levels--;
if (thread_levels == 0)
MEM_set_lock_callback(NULL, NULL);
+ BLI_spin_unlock(&_malloc_lock);
}
diff --git a/source/blender/blenlib/intern/timecode.c b/source/blender/blenlib/intern/timecode.c
index 0c8834008b6..39ffbcd7ebe 100644
--- a/source/blender/blenlib/intern/timecode.c
+++ b/source/blender/blenlib/intern/timecode.c
@@ -113,22 +113,22 @@ size_t BLI_timecode_string_from_time(
if (power <= 0) {
/* include "frames" in display */
if (hours) {
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%02d:%02d+%02d", neg, hours, minutes, seconds, frames);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d+%02d", neg, hours, minutes, seconds, frames);
}
else if (minutes) {
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%02d+%02d", neg, minutes, seconds, frames);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d+%02d", neg, minutes, seconds, frames);
}
else {
- rlen = BLI_snprintf(str, maxncpy, "%s%d+%02d", neg, seconds, frames);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%d+%02d", neg, seconds, frames);
}
}
else {
/* don't include 'frames' in display */
if (hours) {
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%02d:%02d", neg, hours, minutes, seconds);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, hours, minutes, seconds);
}
else {
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%02d", neg, minutes, seconds);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d", neg, minutes, seconds);
}
}
break;
@@ -137,10 +137,10 @@ size_t BLI_timecode_string_from_time(
{
/* reduced SMPTE format that always shows minutes, seconds, frames. Hours only shown as needed. */
if (hours) {
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
}
else {
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%02d:%02d", neg, minutes, seconds, frames);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, minutes, seconds, frames);
}
break;
}
@@ -156,10 +156,10 @@ size_t BLI_timecode_string_from_time(
const int s_pad = ms_dp + 3;
if (hours) {
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%02d:%0*.*f", neg, hours, minutes, s_pad, ms_dp, time);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%0*.*f", neg, hours, minutes, s_pad, ms_dp, time);
}
else {
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%0*.*f", neg, minutes, s_pad, ms_dp, time);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%0*.*f", neg, minutes, s_pad, ms_dp, time);
}
break;
}
@@ -168,10 +168,10 @@ size_t BLI_timecode_string_from_time(
/* only show the original seconds display */
/* round to whole numbers if power is >= 1 (i.e. scale is coarse) */
if (power <= 0) {
- rlen = BLI_snprintf(str, maxncpy, "%.*f", 1 - power, time_seconds);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds);
}
else {
- rlen = BLI_snprintf(str, maxncpy, "%d", iroundf(time_seconds));
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%d", iroundf(time_seconds));
}
break;
}
@@ -179,7 +179,7 @@ size_t BLI_timecode_string_from_time(
default:
{
/* full SMPTE format */
- rlen = BLI_snprintf(str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
break;
}
}
@@ -196,7 +196,6 @@ size_t BLI_timecode_string_from_time(
* \param power special setting for #View2D grid drawing,
* used to specify how detailed we need to be
* \param time_seconds time total time in seconds
- * \param seconds time in seconds.
* \return length of \a str
*
* \note in some cases this is used to print non-seconds values.
@@ -208,10 +207,10 @@ size_t BLI_timecode_string_from_time_simple(
/* round to whole numbers if power is >= 1 (i.e. scale is coarse) */
if (power <= 0) {
- rlen = BLI_snprintf(str, maxncpy, "%.*f", 1 - power, time_seconds);
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds);
}
else {
- rlen = BLI_snprintf(str, maxncpy, "%d", iroundf(time_seconds));
+ rlen = BLI_snprintf_rlen(str, maxncpy, "%d", iroundf(time_seconds));
}
return rlen;
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index 419d8c0f137..6fdcf7065c3 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -42,7 +42,6 @@ struct Main;
struct MemFile;
struct ReportList;
struct Scene;
-struct SpaceFile;
struct UserDef;
struct bContext;
struct BHead;
@@ -120,8 +119,8 @@ BLO_blendfiledata_free(BlendFileData *bfd);
/**
* Open a blendhandle from a file path.
*
- * \param file The file path to open.
- * \param reports Report errors in opening the file (can be NULL).
+ * \param filepath: The file path to open.
+ * \param reports: Report errors in opening the file (can be NULL).
* \return A handle on success, or NULL on failure.
*/
BlendHandle *BLO_blendhandle_from_file(
diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h
index f716b47ea2e..fb96ec75e62 100644
--- a/source/blender/blenloader/BLO_undofile.h
+++ b/source/blender/blenloader/BLO_undofile.h
@@ -47,11 +47,11 @@ typedef struct MemFile {
} MemFile;
/* actually only used writefile.c */
-extern void add_memfilechunk(MemFile *compare, MemFile *current, const char *buf, unsigned int size);
+extern void memfile_chunk_add(MemFile *compare, MemFile *current, const char *buf, unsigned int size);
/* exports */
-extern void BLO_free_memfile(MemFile *memfile);
-extern void BLO_merge_memfile(MemFile *first, MemFile *second);
+extern void BLO_memfile_free(MemFile *memfile);
+extern void BLO_memfile_merge(MemFile *first, MemFile *second);
#endif
diff --git a/source/blender/blenloader/SConscript b/source/blender/blenloader/SConscript
index bd002e59fa4..31dfc71ac73 100644
--- a/source/blender/blenloader/SConscript
+++ b/source/blender/blenloader/SConscript
@@ -43,11 +43,14 @@ incs = [
env['BF_ZLIB_INC'],
]
+defs = []
+
+if env['BF_BUILDINFO']:
+ defs.append('WITH_BUILDINFO')
+
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs.append(env['BF_PTHREADS_INC'])
-defs = []
-
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index 95440158277..20ec27a1f4b 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -176,26 +176,38 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *to
prv = BLO_library_read_struct(fd, bhead, "PreviewImage");
if (prv) {
memcpy(new_prv, prv, sizeof(PreviewImage));
- if (prv->rect[0]) {
+ if (prv->rect[0] && prv->w[0] && prv->h[0]) {
unsigned int *rect = NULL;
- new_prv->rect[0] = MEM_callocN(new_prv->w[0] * new_prv->h[0] * sizeof(unsigned int), "prvrect");
+ size_t len = new_prv->w[0] * new_prv->h[0] * sizeof(unsigned int);
+ new_prv->rect[0] = MEM_callocN(len, __func__);
bhead = blo_nextbhead(fd, bhead);
rect = (unsigned int *)(bhead + 1);
- memcpy(new_prv->rect[0], rect, bhead->len);
+ BLI_assert(len == bhead->len);
+ memcpy(new_prv->rect[0], rect, len);
}
else {
+ /* This should not be needed, but can happen in 'broken' .blend files,
+ * better handle this gracefully than crashing. */
+ BLI_assert(prv->rect[0] == NULL && prv->w[0] == 0 && prv->h[0] == 0);
new_prv->rect[0] = NULL;
+ new_prv->w[0] = new_prv->h[0] = 0;
}
- if (prv->rect[1]) {
+ if (prv->rect[1] && prv->w[1] && prv->h[1]) {
unsigned int *rect = NULL;
- new_prv->rect[1] = MEM_callocN(new_prv->w[1] * new_prv->h[1] * sizeof(unsigned int), "prvrect");
+ size_t len = new_prv->w[1] * new_prv->h[1] * sizeof(unsigned int);
+ new_prv->rect[1] = MEM_callocN(len, __func__);
bhead = blo_nextbhead(fd, bhead);
rect = (unsigned int *)(bhead + 1);
- memcpy(new_prv->rect[1], rect, bhead->len);
+ BLI_assert(len == bhead->len);
+ memcpy(new_prv->rect[1], rect, len);
}
else {
+ /* This should not be needed, but can happen in 'broken' .blend files,
+ * better handle this gracefully than crashing. */
+ BLI_assert(prv->rect[1] == NULL && prv->w[1] == 0 && prv->h[1] == 0);
new_prv->rect[1] = NULL;
+ new_prv->w[1] = new_prv->h[1] = 0;
}
MEM_freeN(prv);
}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index a150c82f09c..1edd694f935 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -58,6 +58,7 @@
#include "DNA_armature_types.h"
#include "DNA_actuator_types.h"
#include "DNA_brush_types.h"
+#include "DNA_cache_library_types.h"
#include "DNA_camera_types.h"
#include "DNA_cloth_types.h"
#include "DNA_controller_types.h"
@@ -111,8 +112,10 @@
#include "BLF_translation.h"
+#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_brush.h"
+#include "BKE_cache_library.h"
#include "BKE_cloth.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
@@ -122,9 +125,9 @@
#include "BKE_fcurve.h"
#include "BKE_global.h" // for G
#include "BKE_group.h"
+#include "BKE_key.h"
#include "BKE_library.h" // for which_libbase
#include "BKE_idcode.h"
-#include "BKE_key.h"
#include "BKE_material.h"
#include "BKE_main.h" // for Main
#include "BKE_mesh.h" // for ME_ defines (patching)
@@ -140,7 +143,7 @@
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
-#include "BKE_treehash.h"
+#include "BKE_outliner_treehash.h"
#include "BKE_sound.h"
@@ -207,6 +210,9 @@
* - initialize FileGlobal and copy pointers to Global
*/
+/* use GHash for BHead name-based lookups (speeds up linking) */
+#define USE_GHASH_BHEAD
+
/***/
typedef struct OldNew {
@@ -226,6 +232,8 @@ typedef struct OldNewMap {
static void *read_struct(FileData *fd, BHead *bh, const char *blockname);
static void direct_link_modifiers(FileData *fd, ListBase *lb);
static void convert_tface_mt(FileData *fd, Main *main);
+static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name);
+static BHead *find_bhead_from_idname(FileData *fd, const char *idname);
/* this function ensures that reports are printed,
* in the case of libraray linking errors this is important!
@@ -292,15 +300,9 @@ static void oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int n
if (oldaddr==NULL || newaddr==NULL) return;
- if (onm->nentries == onm->entriessize) {
- int osize = onm->entriessize;
- OldNew *oentries = onm->entries;
-
+ if (UNLIKELY(onm->nentries == onm->entriessize)) {
onm->entriessize *= 2;
- onm->entries = MEM_mallocN(sizeof(*onm->entries)*onm->entriessize, "OldNewMap.entries");
-
- memcpy(onm->entries, oentries, sizeof(*oentries)*osize);
- MEM_freeN(oentries);
+ onm->entries = MEM_reallocN(onm->entries, sizeof(*onm->entries) * onm->entriessize);
}
entry = &onm->entries[onm->nentries++];
@@ -509,6 +511,44 @@ static void read_file_version(FileData *fd, Main *main)
}
}
+#ifdef USE_GHASH_BHEAD
+static void read_file_bhead_idname_map_create(FileData *fd)
+{
+ BHead *bhead;
+
+ /* dummy values */
+ bool is_link = false;
+ int code_prev = ENDB;
+ unsigned int reserve = 0;
+
+ for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead)) {
+ if (code_prev != bhead->code) {
+ code_prev = bhead->code;
+ is_link = BKE_idcode_is_valid(code_prev) ? BKE_idcode_is_linkable(code_prev) : false;
+ }
+
+ if (is_link) {
+ reserve += 1;
+ }
+ }
+
+ BLI_assert(fd->bhead_idname_hash == NULL);
+
+ fd->bhead_idname_hash = BLI_ghash_str_new_ex(__func__, reserve);
+
+ for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead)) {
+ if (code_prev != bhead->code) {
+ code_prev = bhead->code;
+ is_link = BKE_idcode_is_valid(code_prev) ? BKE_idcode_is_linkable(code_prev) : false;
+ }
+
+ if (is_link) {
+ BLI_ghash_insert(fd->bhead_idname_hash, (void *)bhead_id_name(fd, bhead), bhead);
+ }
+ }
+}
+#endif
+
static Main *blo_find_main(FileData *fd, const char *filepath, const char *relabase)
{
@@ -737,7 +777,7 @@ BHead *blo_firstbhead(FileData *fd)
BHead *blo_prevbhead(FileData *UNUSED(fd), BHead *thisblock)
{
- BHeadN *bheadn = (BHeadN *) (((char *) thisblock) - offsetof(BHeadN, bhead));
+ BHeadN *bheadn = (BHeadN *)POINTER_OFFSET(thisblock, -offsetof(BHeadN, bhead));
BHeadN *prev = bheadn->prev;
return (prev) ? &prev->bhead : NULL;
@@ -751,7 +791,7 @@ BHead *blo_nextbhead(FileData *fd, BHead *thisblock)
if (thisblock) {
/* bhead is actually a sub part of BHeadN
* We calculate the BHeadN pointer from the BHead pointer below */
- new_bhead = (BHeadN *) (((char *) thisblock) - offsetof(BHeadN, bhead));
+ new_bhead = (BHeadN *)POINTER_OFFSET(thisblock, -offsetof(BHeadN, bhead));
/* get the next BHeadN. If it doesn't exist we read in the next one */
new_bhead = new_bhead->next;
@@ -921,7 +961,7 @@ static int fd_read_from_memfile(FileData *filedata, void *buffer, unsigned int s
if (chunkoffset+readsize > chunk->size)
readsize= chunk->size-chunkoffset;
- memcpy((char *)buffer + totread, chunk->buf + chunkoffset, readsize);
+ memcpy(POINTER_OFFSET(buffer, totread), chunk->buf + chunkoffset, readsize);
totread += readsize;
filedata->seek += readsize;
seek += readsize;
@@ -1134,6 +1174,12 @@ void blo_freefiledata(FileData *fd)
if (fd->bheadmap)
MEM_freeN(fd->bheadmap);
+#ifdef USE_GHASH_BHEAD
+ if (fd->bhead_idname_hash) {
+ BLI_ghash_free(fd->bhead_idname_hash, NULL, NULL);
+ }
+#endif
+
MEM_freeN(fd);
}
}
@@ -1491,9 +1537,16 @@ void blo_make_packed_pointer_map(FileData *fd, Main *oldmain)
fd->packedmap = oldnewmap_new();
- for (ima = oldmain->image.first; ima; ima = ima->id.next)
+ for (ima = oldmain->image.first; ima; ima = ima->id.next) {
+ ImagePackedFile *imapf;
+
if (ima->packedfile)
insert_packedmap(fd, ima->packedfile);
+
+ for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next)
+ if (imapf->packedfile)
+ insert_packedmap(fd, imapf->packedfile);
+ }
for (vfont = oldmain->vfont.first; vfont; vfont = vfont->id.next)
if (vfont->packedfile)
@@ -1526,8 +1579,14 @@ void blo_end_packed_pointer_map(FileData *fd, Main *oldmain)
entry->newp = NULL;
}
- for (ima = oldmain->image.first; ima; ima = ima->id.next)
+ for (ima = oldmain->image.first; ima; ima = ima->id.next) {
+ ImagePackedFile *imapf;
+
ima->packedfile = newpackedadr(fd, ima->packedfile);
+
+ for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next)
+ imapf->packedfile = newpackedadr(fd, imapf->packedfile);
+ }
for (vfont = oldmain->vfont.first; vfont; vfont = vfont->id.next)
vfont->packedfile = newpackedadr(fd, vfont->packedfile);
@@ -1908,7 +1967,6 @@ static void direct_link_palette(FileData *fd, Palette *palette)
{
/* palette itself has been read */
link_list(fd, &palette->colors);
- BLI_listbase_clear(&palette->deleted);
}
static void lib_link_paint_curve(FileData *UNUSED(fd), Main *main)
@@ -1928,7 +1986,6 @@ static void direct_link_paint_curve(FileData *fd, PaintCurve *pc)
pc->points = newdataadr(fd, pc->points);
}
-
static void direct_link_script(FileData *UNUSED(fd), Script *script)
{
script->id.us = 1;
@@ -1936,12 +1993,102 @@ static void direct_link_script(FileData *UNUSED(fd), Script *script)
}
+/* ************ READ CacheLibrary *************** */
+
+static void lib_link_cache_modifiers_cb(void *userData, CacheLibrary *cachelib, CacheModifier *UNUSED(md), ID **idpoin)
+{
+ FileData *fd = userData;
+
+ *idpoin = newlibadr(fd, cachelib->id.lib, *idpoin);
+ /* hardcoded bad exception; non-object modifier data gets user count (texture, displace) */
+ if (*idpoin && GS((*idpoin)->name)!=ID_OB)
+ (*idpoin)->us++;
+}
+static void lib_link_cache_modifiers(FileData *fd, CacheLibrary *cachelib)
+{
+ CacheModifier *md;
+ for (md = cachelib->modifiers.first; md; md = md->next) {
+ BKE_cache_modifier_foreachIDLink(cachelib, md, lib_link_cache_modifiers_cb, fd);
+
+ /* special cases */
+ switch (md->type) {
+ case eCacheModifierType_StrandsKey: {
+ StrandsKeyCacheModifier *skmd = (StrandsKeyCacheModifier *)md;
+ /* Key is a local ID block, not handled by foreachIDLink */
+ skmd->key = newlibadr_us(fd, cachelib->id.lib, skmd->key);
+ break;
+ }
+ }
+ }
+}
+
+static void lib_link_cache_library(FileData *fd, Main *main)
+{
+ CacheLibrary *cachelib;
+
+ for (cachelib = main->cache_library.first; cachelib; cachelib = cachelib->id.next) {
+ if (cachelib->id.flag & LIB_NEED_LINK) {
+ cachelib->id.flag -= LIB_NEED_LINK;
+
+ cachelib->filter_group = newlibadr_us(fd, cachelib->id.lib, cachelib->filter_group);
+
+ lib_link_cache_modifiers(fd, cachelib);
+ }
+ }
+}
+
+static void direct_link_cache_modifiers(FileData *fd, ListBase *modifiers)
+{
+ CacheModifier *md;
+
+ link_list(fd, modifiers);
+
+ for (md = modifiers->first; md; md = md->next) {
+ /* if modifiers disappear, or for upward compatibility */
+ if (md->type >= NUM_CACHE_MODIFIER_TYPES)
+ md->type = eCacheModifierType_None;
+
+
+ switch (md->type) {
+ case eCacheModifierType_HairSimulation: {
+ HairSimCacheModifier *hsmd = (HairSimCacheModifier *)md;
+ hsmd->sim_params.effector_weights = newdataadr(fd, hsmd->sim_params.effector_weights);
+ hsmd->sim_params.goal_stiffness_mapping = newdataadr(fd, hsmd->sim_params.goal_stiffness_mapping);
+ if (hsmd->sim_params.goal_stiffness_mapping)
+ direct_link_curvemapping(fd, hsmd->sim_params.goal_stiffness_mapping);
+ hsmd->sim_params.bend_stiffness_mapping = newdataadr(fd, hsmd->sim_params.bend_stiffness_mapping);
+ if (hsmd->sim_params.bend_stiffness_mapping)
+ direct_link_curvemapping(fd, hsmd->sim_params.bend_stiffness_mapping);
+ break;
+ }
+ case eCacheModifierType_ForceField: {
+ ForceFieldCacheModifier *ffmd = (ForceFieldCacheModifier *)md;
+ ffmd->vertex_cache = NULL;
+ break;
+ }
+ case eCacheModifierType_StrandsKey: {
+ StrandsKeyCacheModifier *skmd = (StrandsKeyCacheModifier *)md;
+ skmd->edit = NULL;
+ break;
+ }
+ }
+ }
+}
+
+static void direct_link_cache_library(FileData *fd, CacheLibrary *cachelib)
+{
+ direct_link_cache_modifiers(fd, &cachelib->modifiers);
+
+ cachelib->archive_info = NULL; /* runtime */
+}
+
+
/* ************ READ PACKEDFILE *************** */
static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf)
{
PackedFile *pf = newpackedadr(fd, oldpf);
-
+
if (pf) {
pf->data = newpackedadr(fd, pf->data);
}
@@ -2379,12 +2526,13 @@ static void direct_link_animdata(FileData *fd, AnimData *adt)
link_list(fd, &adt->nla_tracks);
direct_link_nladata(fd, &adt->nla_tracks);
- /* relink active strip - even though strictly speaking this should only be used
+ /* relink active track/strip - even though strictly speaking this should only be used
* if we're in 'tweaking mode', we need to be able to have this loaded back for
* undo, but also since users may not exit tweakmode before saving (#24535)
*/
// TODO: it's not really nice that anyone should be able to save the file in this
// state, but it's going to be too hard to enforce this single case...
+ adt->act_track = newdataadr(fd, adt->act_track);
adt->actstrip = newdataadr(fd, adt->actstrip);
}
@@ -2586,7 +2734,7 @@ static void lib_verify_nodetree(Main *main, int UNUSED(open))
* New file versions already have input/output nodes with duplicate links,
* in that case just remove the invalid links.
*/
- int create_io_nodes = (ntree->flag & NTREE_DO_VERSIONS_CUSTOMNODES_GROUP_CREATE_INTERFACE);
+ const bool create_io_nodes = (ntree->flag & NTREE_DO_VERSIONS_CUSTOMNODES_GROUP_CREATE_INTERFACE) != 0;
float input_locx = 1000000.0f, input_locy = 0.0f;
float output_locx = -1000000.0f, output_locy = 0.0f;
@@ -2956,7 +3104,7 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose)
if (rebuild) {
DAG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- pose->flag |= POSE_RECALC;
+ BKE_pose_tag_recalc(bmain, pose);
}
}
@@ -3116,8 +3264,8 @@ static void lib_link_key(FileData *fd, Main *main)
key->ipo = newlibadr_us(fd, key->id.lib, key->ipo); // XXX deprecated - old animation system
key->from = newlibadr(fd, key->id.lib, key->from);
- /* versioning: initialize from_extra */
- if (!key->from_extra.type && key->from) {
+ /* versioning: initialize extra owner info */
+ if (!key->fromtype && key->from) {
BKE_key_set_from_id(key, key->from);
}
@@ -3354,6 +3502,8 @@ static void lib_link_image(FileData *fd, Main *main)
static void direct_link_image(FileData *fd, Image *ima)
{
+ ImagePackedFile *imapf;
+
/* for undo system, pointers could be restored */
if (fd->imamap)
ima->cache = newimaadr(fd, ima->cache);
@@ -3367,8 +3517,7 @@ static void direct_link_image(FileData *fd, Image *ima)
ima->gputexture = NULL;
ima->rr = NULL;
}
-
- ima->anim = NULL;
+
ima->repbind = NULL;
/* undo system, try to restore render buffers */
@@ -3382,9 +3531,23 @@ static void direct_link_image(FileData *fd, Image *ima)
memset(ima->renders, 0, sizeof(ima->renders));
ima->last_render_slot = ima->render_slot;
}
-
- ima->packedfile = direct_link_packedfile(fd, ima->packedfile);
+
+ link_list(fd, &(ima->views));
+ link_list(fd, &(ima->packedfiles));
+
+ if (ima->packedfiles.first) {
+ for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) {
+ imapf->packedfile = direct_link_packedfile(fd, imapf->packedfile);
+ }
+ ima->packedfile = NULL;
+ }
+ else {
+ ima->packedfile = direct_link_packedfile(fd, ima->packedfile);
+ }
+
+ ima->anims.first = ima->anims.last = NULL;
ima->preview = direct_link_preview_image(fd, ima->preview);
+ ima->stereo3d_format = newdataadr(fd, ima->stereo3d_format);
ima->ok = 1;
}
@@ -3473,7 +3636,7 @@ static void direct_link_curve(FileData *fd, Curve *cu)
nu->bp = newdataadr(fd, nu->bp);
nu->knotsu = newdataadr(fd, nu->knotsu);
nu->knotsv = newdataadr(fd, nu->knotsv);
- if (cu->vfont == NULL) nu->charidx= nu->mat_nr;
+ if (cu->vfont == NULL) nu->charidx = 0;
if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
switch_endian_knots(nu);
@@ -3772,25 +3935,26 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
BoidRule *rule;
for (; state; state=state->next) {
rule = state->rules.first;
- for (; rule; rule=rule->next)
- switch (rule->type) {
- case eBoidRuleType_Goal:
- case eBoidRuleType_Avoid:
- {
- BoidRuleGoalAvoid *brga = (BoidRuleGoalAvoid*)rule;
- brga->ob = newlibadr(fd, part->id.lib, brga->ob);
- break;
- }
- case eBoidRuleType_FollowLeader:
- {
- BoidRuleFollowLeader *brfl = (BoidRuleFollowLeader*)rule;
- brfl->ob = newlibadr(fd, part->id.lib, brfl->ob);
- break;
+ for (; rule; rule=rule->next) {
+ switch (rule->type) {
+ case eBoidRuleType_Goal:
+ case eBoidRuleType_Avoid:
+ {
+ BoidRuleGoalAvoid *brga = (BoidRuleGoalAvoid*)rule;
+ brga->ob = newlibadr(fd, part->id.lib, brga->ob);
+ break;
+ }
+ case eBoidRuleType_FollowLeader:
+ {
+ BoidRuleFollowLeader *brfl = (BoidRuleFollowLeader*)rule;
+ brfl->ob = newlibadr(fd, part->id.lib, brfl->ob);
+ break;
+ }
}
}
}
}
-
+
for (a = 0; a < MAX_MTEX; a++) {
mtex= part->mtex[a];
if (mtex) {
@@ -3934,6 +4098,7 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
psys->edit = NULL;
psys->free_edit = NULL;
+ psys->hairedit = NULL;
psys->pathcache = NULL;
psys->childcache = NULL;
BLI_listbase_clear(&psys->pathcachebufs);
@@ -4370,6 +4535,7 @@ static void lib_link_object(FileData *fd, Main *main)
ob->track = newlibadr(fd, ob->id.lib, ob->track);
ob->poselib = newlibadr_us(fd, ob->id.lib, ob->poselib);
ob->dup_group = newlibadr_us(fd, ob->id.lib, ob->dup_group);
+ ob->cache_library = newlibadr_us(fd, ob->id.lib, ob->cache_library);
ob->proxy = newlibadr_us(fd, ob->id.lib, ob->proxy);
if (ob->proxy) {
@@ -4913,6 +5079,20 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
}
lmd->cache_system = NULL;
}
+ else if (md->type == eModifierType_CorrectiveSmooth) {
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData*)md;
+
+ if (csmd->bind_coords) {
+ csmd->bind_coords = newdataadr(fd, csmd->bind_coords);
+ if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ BLI_endian_switch_float_array((float *)csmd->bind_coords, csmd->bind_coords_num * 3);
+ }
+ }
+
+ /* runtime only */
+ csmd->delta_cache = NULL;
+ csmd->delta_cache_num = 0;
+ }
}
}
@@ -4939,7 +5119,7 @@ static void direct_link_object(FileData *fd, Object *ob)
* See [#34776, #42780] for more information.
*/
if (fd->memfile || (ob->id.flag & (LIB_EXTERN | LIB_INDIRECT))) {
- ob->mode &= ~(OB_MODE_EDIT | OB_MODE_PARTICLE_EDIT);
+ ob->mode &= ~(OB_MODE_EDIT | OB_MODE_PARTICLE_EDIT | OB_MODE_HAIR_EDIT);
if (!fd->memfile) {
ob->mode &= ~OB_MODE_POSE;
}
@@ -4969,6 +5149,8 @@ static void direct_link_object(FileData *fd, Object *ob)
/* do it here, below old data gets converted */
direct_link_modifiers(fd, &ob->modifiers);
+ ob->dup_cache = NULL;
+
link_list(fd, &ob->effect);
paf= ob->effect.first;
while (paf) {
@@ -5276,6 +5458,14 @@ static void lib_link_scene(FileData *fd, Main *main)
sce->toolsettings->particle.shape_object = newlibadr(fd, sce->id.lib, sce->toolsettings->particle.shape_object);
+ {
+ HairEditSettings *hair_edit = &sce->toolsettings->hair_edit;
+ if (hair_edit->brush)
+ hair_edit->brush = newlibadr(fd, sce->id.lib, hair_edit->brush);
+ if (hair_edit->shape_object)
+ hair_edit->shape_object = newlibadr(fd, sce->id.lib, hair_edit->shape_object);
+ }
+
for (base = sce->base.first; base; base = next) {
next = base->next;
@@ -5298,7 +5488,7 @@ static void lib_link_scene(FileData *fd, Main *main)
if (seq->scene) {
seq->scene = newlibadr(fd, sce->id.lib, seq->scene);
if (seq->scene) {
- seq->scene_sound = sound_scene_add_scene_sound_defaults(sce, seq);
+ seq->scene_sound = BKE_sound_scene_add_scene_sound_defaults(sce, seq);
}
}
if (seq->clip) {
@@ -5326,10 +5516,10 @@ static void lib_link_scene(FileData *fd, Main *main)
}
if (seq->sound) {
seq->sound->id.us++;
- seq->scene_sound = sound_add_scene_sound_defaults(sce, seq);
+ seq->scene_sound = BKE_sound_add_scene_sound_defaults(sce, seq);
}
}
- seq->anim = NULL;
+ seq->anims.first = seq->anims.last = NULL;
lib_link_sequence_modifiers(fd, sce, &seq->modifiers);
}
@@ -5495,13 +5685,14 @@ static void direct_link_scene(FileData *fd, Scene *sce)
SceneRenderLayer *srl;
sce->theDag = NULL;
+ sce->depsgraph = NULL;
sce->obedit = NULL;
sce->stats = NULL;
sce->fps_info = NULL;
sce->customdata_mask_modal = 0;
sce->lay_updated = 0;
- sound_create_scene(sce);
+ BKE_sound_create_scene(sce);
/* set users to one by default, not in lib-link, this will increase it for compo nodes */
sce->id.us = 1;
@@ -5529,7 +5720,8 @@ static void direct_link_scene(FileData *fd, Scene *sce)
sce->toolsettings->particle.paintcursor = NULL;
sce->toolsettings->particle.scene = NULL;
sce->toolsettings->particle.object = NULL;
-
+ sce->toolsettings->hair_edit.paint_cursor = NULL;
+
/* in rare cases this is needed, see [#33806] */
if (sce->toolsettings->vpaint) {
sce->toolsettings->vpaint->vpaint_prev = NULL;
@@ -5561,6 +5753,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
if (seq->seq3 == NULL) seq->seq3 = seq->seq2;
seq->effectdata = newdataadr(fd, seq->effectdata);
+ seq->stereo3d_format = newdataadr(fd, seq->stereo3d_format);
if (seq->type & SEQ_TYPE_EFFECT)
seq->flag |= SEQ_EFFECT_NOT_LOADED;
@@ -5569,7 +5762,10 @@ static void direct_link_scene(FileData *fd, Scene *sce)
SpeedControlVars *s = seq->effectdata;
s->frameMap = NULL;
}
-
+
+ seq->prop = newdataadr(fd, seq->prop);
+ IDP_DirectLinkGroup_OrFree(&seq->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
seq->strip = newdataadr(fd, seq->strip);
if (seq->strip && seq->strip->done==0) {
seq->strip->done = true;
@@ -5614,7 +5810,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
/* link metastack, slight abuse of structs here, have to restore pointer to internal part in struct */
{
Sequence temp;
- char *poin;
+ void *poin;
intptr_t offset;
offset = ((intptr_t)&(temp.seqbase)) - ((intptr_t)&temp);
@@ -5624,12 +5820,11 @@ static void direct_link_scene(FileData *fd, Scene *sce)
ed->seqbasep = &ed->seqbase;
}
else {
- poin = (char *)ed->seqbasep;
- poin -= offset;
+ poin = POINTER_OFFSET(ed->seqbasep, -offset);
poin = newdataadr(fd, poin);
if (poin)
- ed->seqbasep = (ListBase *)(poin+offset);
+ ed->seqbasep = (ListBase *)POINTER_OFFSET(poin, offset);
else
ed->seqbasep = &ed->seqbase;
}
@@ -5642,11 +5837,10 @@ static void direct_link_scene(FileData *fd, Scene *sce)
if (ms->oldbasep == old_seqbasep)
ms->oldbasep= &ed->seqbase;
else {
- poin = (char *)ms->oldbasep;
- poin -= offset;
+ poin = POINTER_OFFSET(ms->oldbasep, -offset);
poin = newdataadr(fd, poin);
if (poin)
- ms->oldbasep = (ListBase *)(poin+offset);
+ ms->oldbasep = (ListBase *)POINTER_OFFSET(poin, offset);
else
ms->oldbasep = &ed->seqbase;
}
@@ -5672,6 +5866,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
link_list(fd, &(sce->markers));
link_list(fd, &(sce->transform_spaces));
link_list(fd, &(sce->r.layers));
+ link_list(fd, &(sce->r.views));
for (srl = sce->r.layers.first; srl; srl = srl->next) {
link_list(fd, &(srl->freestyleConfig.modules));
@@ -5735,8 +5930,8 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
BLI_listbase_clear(&win->modalhandlers);
BLI_listbase_clear(&win->subwindows);
BLI_listbase_clear(&win->gesture);
+ BLI_listbase_clear(&win->drawdata);
- win->drawdata = NULL;
win->drawmethod = -1;
win->drawfail = 0;
win->active = 0;
@@ -5744,6 +5939,13 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
win->cursor = 0;
win->lastcursor = 0;
win->modalcursor = 0;
+ win->stereo3d_format = newdataadr(fd, win->stereo3d_format);
+
+ /* multiview always fallback to anaglyph at file opening
+ * otherwise quadbuffer saved files can break Blender */
+ if (win->stereo3d_format) {
+ win->stereo3d_format->display_mode = S3D_DISPLAY_ANAGLYPH;
+ }
}
BLI_listbase_clear(&wm->timers);
@@ -5890,10 +6092,14 @@ static void lib_link_screen(FileData *fd, Main *main)
ads->source = newlibadr(fd, sc->id.lib, ads->source);
ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
}
+ sipo->backdrop_camera = newlibadr(fd, sc->id.lib, sipo->backdrop_camera);
}
else if (sl->spacetype == SPACE_BUTS) {
SpaceButs *sbuts = (SpaceButs *)sl;
sbuts->pinid = newlibadr(fd, sc->id.lib, sbuts->pinid);
+ if (sbuts->pinid == NULL) {
+ sbuts->flag &= ~SB_PIN_CONTEXT;
+ }
}
else if (sl->spacetype == SPACE_FILE) {
;
@@ -5967,7 +6173,7 @@ static void lib_link_screen(FileData *fd, Main *main)
}
if (so->treehash) {
/* rebuild hash table, because it depends on ids too */
- BKE_treehash_rebuild_from_treestore(so->treehash, so->treestore);
+ so->storeflag |= SO_TREESTORE_REBUILD;
}
}
}
@@ -6214,6 +6420,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
if (ads->filter_grp)
ads->filter_grp = restore_pointer_by_name(newmain, (ID *)ads->filter_grp, USER_IGNORE);
}
+ sipo->backdrop_camera = restore_pointer_by_name(newmain, (ID *)sipo->backdrop_camera, USER_IGNORE);
/* force recalc of list of channels (i.e. includes calculating F-Curve colors)
* thus preventing the "black curves" problem post-undo
@@ -6223,6 +6430,9 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_BUTS) {
SpaceButs *sbuts = (SpaceButs *)sl;
sbuts->pinid = restore_pointer_by_name(newmain, sbuts->pinid, USER_IGNORE);
+ if (sbuts->pinid == NULL) {
+ sbuts->flag &= ~SB_PIN_CONTEXT;
+ }
/* TODO: restore path pointers: T40046
* (complicated because this contains data pointers too, not just ID)*/
@@ -6318,7 +6528,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
}
if (so->treehash) {
/* rebuild hash table, because it depends on ids too */
- BKE_treehash_rebuild_from_treestore(so->treehash, so->treestore);
+ so->storeflag |= SO_TREESTORE_REBUILD;
}
}
}
@@ -6932,7 +7142,7 @@ static void lib_link_sound(FileData *fd, Main *main)
sound->id.flag -= LIB_NEED_LINK;
sound->ipo = newlibadr_us(fd, sound->id.lib, sound->ipo); // XXX deprecated - old animation system
- sound_load(main, sound);
+ BKE_sound_load(main, sound);
}
}
}
@@ -7002,7 +7212,7 @@ static void direct_link_moviePlaneTracks(FileData *fd, ListBase *plane_tracks_ba
int i;
plane_track->point_tracks = newdataadr(fd, plane_track->point_tracks);
-
+ test_pointer_array(fd, (void**)&plane_track->point_tracks);
for (i = 0; i < plane_track->point_tracksnr; i++) {
plane_track->point_tracks[i] = newdataadr(fd, plane_track->point_tracks[i]);
}
@@ -7419,6 +7629,7 @@ static const char *dataname(short id_code)
case ID_MC: return "Data from MC";
case ID_MSK: return "Data from MSK";
case ID_LS: return "Data from LS";
+ case ID_CL: return "Data from CL";
}
return "Data from Lib Block";
@@ -7605,6 +7816,9 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
case ID_PC:
direct_link_paint_curve(fd, (PaintCurve *)id);
break;
+ case ID_CL:
+ direct_link_cache_library(fd, (CacheLibrary *)id);
+ break;
}
oldnewmap_free_unused(fd->datamap);
@@ -7717,7 +7931,6 @@ static void do_versions_userdef(FileData *fd, BlendFileData *bfd)
user->walk_navigation.jump_height = 0.4f; /* m */
user->walk_navigation.teleport_time = 0.2f; /* s */
}
-
}
static void do_versions(FileData *fd, Library *lib, Main *main)
@@ -7727,12 +7940,12 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
if (G.debug & G_DEBUG) {
char build_commit_datetime[32];
time_t temp_time = main->build_commit_timestamp;
- struct tm *tm = gmtime(&temp_time);
+ struct tm *tm = (temp_time) ? gmtime(&temp_time) : NULL;
if (LIKELY(tm)) {
strftime(build_commit_datetime, sizeof(build_commit_datetime), "%Y-%m-%d %H:%M", tm);
}
else {
- BLI_strncpy(build_commit_datetime, "date-unknown", sizeof(build_commit_datetime));
+ BLI_strncpy(build_commit_datetime, "unknown", sizeof(build_commit_datetime));
}
printf("read file %s\n Version %d sub %d date %s hash %s\n",
@@ -7799,6 +8012,7 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_mask(fd, main);
lib_link_linestyle(fd, main);
lib_link_gpencil(fd, main);
+ lib_link_cache_library(fd, main);
lib_link_mesh(fd, main); /* as last: tpage images with users at zero */
@@ -7840,7 +8054,7 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
link_list(fd, &user->user_keymaps);
link_list(fd, &user->addons);
link_list(fd, &user->autoexec_paths);
-
+
for (keymap=user->user_keymaps.first; keymap; keymap=keymap->next) {
keymap->modal_items= NULL;
keymap->poll = NULL;
@@ -8046,9 +8260,48 @@ static BHead *find_bhead(FileData *fd, void *old)
return NULL;
}
-char *bhead_id_name(FileData *fd, BHead *bhead)
+static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name)
+{
+#ifdef USE_GHASH_BHEAD
+
+ char idname_full[MAX_ID_NAME];
+
+ *((short *)idname_full) = idcode;
+ BLI_strncpy(idname_full + 2, name, sizeof(idname_full) - 2);
+
+ return BLI_ghash_lookup(fd->bhead_idname_hash, idname_full);
+
+#else
+ BHead *bhead;
+
+ for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead)) {
+ if (bhead->code == idcode) {
+ const char *idname_test = bhead_id_name(fd, bhead);
+ if (STREQ(idname_test + 2, name)) {
+ return bhead;
+ }
+ }
+ else if (bhead->code == ENDB) {
+ break;
+ }
+ }
+
+ return NULL;
+#endif
+}
+
+static BHead *find_bhead_from_idname(FileData *fd, const char *idname)
{
- return ((char *)(bhead+1)) + fd->id_name_offs;
+#ifdef USE_GHASH_BHEAD
+ return BLI_ghash_lookup(fd->bhead_idname_hash, idname);
+#else
+ return find_bhead_from_code_name(fd, GS(idname), idname + 2);
+#endif
+}
+
+const char *bhead_id_name(const FileData *fd, const BHead *bhead)
+{
+ return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offs);
}
static ID *is_yet_read(FileData *fd, Main *mainvar, BHead *bhead)
@@ -8636,6 +8889,8 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob)
if (ob->dup_group)
expand_doit(fd, mainvar, ob->dup_group);
+ if (ob->cache_library)
+ expand_doit(fd, mainvar, ob->cache_library);
if (ob->proxy)
expand_doit(fd, mainvar, ob->proxy);
@@ -8910,6 +9165,12 @@ static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd)
expand_animdata(fd, mainvar, gpd->adt);
}
+static void expand_cache_library(FileData *fd, Main *mainvar, CacheLibrary *cachelib)
+{
+ if (cachelib->filter_group)
+ expand_doit(fd, mainvar, cachelib->filter_group);
+}
+
void BLO_main_expander(void (*expand_doit_func)(void *, Main *, void *))
{
expand_doit = expand_doit_func;
@@ -9007,6 +9268,9 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
case ID_GD:
expand_gpencil(fd, mainvar, (bGPdata *)id);
break;
+ case ID_CL:
+ expand_cache_library(fd, mainvar, (CacheLibrary *)id);
+ break;
}
do_it = true;
@@ -9124,7 +9388,6 @@ static void give_base_to_groups(Main *mainvar, Scene *scene)
/* assign the group */
ob->dup_group = group;
ob->transflag |= OB_DUPLIGROUP;
- rename_id(&ob->id, group->id.name + 2);
copy_v3_v3(ob->loc, scene->cursor);
}
}
@@ -9134,50 +9397,40 @@ static void give_base_to_groups(Main *mainvar, Scene *scene)
* but it may already have already been appended/linked */
static ID *append_named_part(Main *mainl, FileData *fd, const char *idname, const short idcode)
{
- BHead *bhead;
- ID *id = NULL;
- int found = 0;
+ BHead *bhead = find_bhead_from_code_name(fd, idcode, idname);
+ ID *id;
- for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead)) {
- if (bhead->code == idcode) {
- const char *idname_test= bhead_id_name(fd, bhead);
-
- if (STREQ(idname_test + 2, idname)) {
- found = 1;
- id = is_yet_read(fd, mainl, bhead);
- if (id == NULL) {
- /* not read yet */
- read_libblock(fd, mainl, bhead, LIB_TESTEXT, &id);
-
- if (id) {
- /* sort by name in list */
- ListBase *lb = which_libbase(mainl, idcode);
- id_sort_by_name(lb, id);
- }
- }
- else {
- /* already linked */
- if (G.debug)
- printf("append: already linked\n");
- oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code);
- if (id->flag & LIB_INDIRECT) {
- id->flag -= LIB_INDIRECT;
- id->flag |= LIB_EXTERN;
- }
- }
-
- break;
+ if (bhead) {
+ id = is_yet_read(fd, mainl, bhead);
+ if (id == NULL) {
+ /* not read yet */
+ read_libblock(fd, mainl, bhead, LIB_TESTEXT, &id);
+
+ if (id) {
+ /* sort by name in list */
+ ListBase *lb = which_libbase(mainl, idcode);
+ id_sort_by_name(lb, id);
}
}
- else if (bhead->code == ENDB) {
- break;
+ else {
+ /* already linked */
+ if (G.debug)
+ printf("append: already linked\n");
+ oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code);
+ if (id->flag & LIB_INDIRECT) {
+ id->flag -= LIB_INDIRECT;
+ id->flag |= LIB_EXTERN;
+ }
}
}
+ else {
+ id = NULL;
+ }
/* if we found the id but the id is NULL, this is really bad */
- BLI_assert((found != 0) == (id != NULL));
+ BLI_assert((bhead != NULL) == (id != NULL));
- return (found) ? id : NULL;
+ return id;
}
/* simple reader for copy/paste buffers */
@@ -9258,22 +9511,13 @@ ID *BLO_library_append_named_part_ex(const bContext *C, Main *mainl, BlendHandle
static void append_id_part(FileData *fd, Main *mainvar, ID *id, ID **r_id)
{
- BHead *bhead;
-
- for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead)) {
- if (bhead->code == GS(id->name)) {
-
- if (STREQ(id->name, bhead_id_name(fd, bhead))) {
- id->flag &= ~LIB_READ;
- id->flag |= LIB_NEED_EXPAND;
-// printf("read lib block %s\n", id->name);
- read_libblock(fd, mainvar, bhead, id->flag, r_id);
-
- break;
- }
- }
- else if (bhead->code==ENDB)
- break;
+ BHead *bhead = find_bhead_from_idname(fd, id->name);
+
+ if (bhead) {
+ id->flag &= ~LIB_READ;
+ id->flag |= LIB_NEED_EXPAND;
+ // printf("read lib block %s\n", id->name);
+ read_libblock(fd, mainvar, bhead, id->flag, r_id);
}
}
@@ -9297,6 +9541,9 @@ static Main *library_append_begin(Main *mainvar, FileData **fd, const char *file
/* needed for do_version */
mainl->versionfile = (*fd)->fileversion;
read_file_version(*fd, mainl);
+#ifdef USE_GHASH_BHEAD
+ read_file_bhead_idname_map_create(*fd);
+#endif
return mainl;
}
@@ -9503,6 +9750,10 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
/* subversion */
read_file_version(fd, mainptr);
+#ifdef USE_GHASH_BHEAD
+ read_file_bhead_idname_map_create(fd);
+#endif
+
}
else {
mainptr->curlib->filedata = NULL;
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 2b40accbf21..ed22daef9ec 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -38,12 +38,10 @@
struct OldNewMap;
struct MemFile;
-struct bheadsort;
struct ReportList;
struct Object;
struct PartEff;
struct View3D;
-struct bNodeTree;
struct Key;
typedef struct FileData {
@@ -93,6 +91,9 @@ typedef struct FileData {
struct BHeadSort *bheadmap;
int tot_bheadmap;
+
+ /* see: USE_GHASH_BHEAD */
+ struct GHash *bhead_idname_hash;
ListBase *mainlist;
@@ -146,7 +147,7 @@ BHead *blo_firstbhead(FileData *fd);
BHead *blo_nextbhead(FileData *fd, BHead *thisblock);
BHead *blo_prevbhead(FileData *fd, BHead *thisblock);
-char *bhead_id_name(FileData *fd, BHead *bhead);
+const char *bhead_id_name(const FileData *fd, const BHead *bhead);
/* do versions stuff */
diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c
index f70d889828f..d0dc9a88cc0 100644
--- a/source/blender/blenloader/intern/undofile.c
+++ b/source/blender/blenloader/intern/undofile.c
@@ -46,7 +46,7 @@
/* **************** support for memory-write, for undo buffers *************** */
/* not memfile itself */
-void BLO_free_memfile(MemFile *memfile)
+void BLO_memfile_free(MemFile *memfile)
{
MemFileChunk *chunk;
@@ -60,7 +60,7 @@ void BLO_free_memfile(MemFile *memfile)
/* to keep list of memfiles consistent, 'first' is always first in list */
/* result is that 'first' is being freed */
-void BLO_merge_memfile(MemFile *first, MemFile *second)
+void BLO_memfile_merge(MemFile *first, MemFile *second)
{
MemFileChunk *fc, *sc;
@@ -77,7 +77,7 @@ void BLO_merge_memfile(MemFile *first, MemFile *second)
if (sc) sc = sc->next;
}
- BLO_free_memfile(first);
+ BLO_memfile_free(first);
}
static int my_memcmp(const int *mem1, const int *mem2, const int len)
@@ -94,7 +94,7 @@ static int my_memcmp(const int *mem1, const int *mem2, const int len)
return 0;
}
-void add_memfilechunk(MemFile *compare, MemFile *current, const char *buf, unsigned int size)
+void memfile_chunk_add(MemFile *compare, MemFile *current, const char *buf, unsigned int size)
{
static MemFileChunk *compchunk = NULL;
MemFileChunk *curchunk;
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 4125451ead9..2727f3a3965 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -766,7 +766,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
bSoundActuator *sAct = (bSoundActuator*) act->data;
if (sAct->sound) {
sound = blo_do_versions_newlibadr(fd, lib, sAct->sound);
- sAct->flag = sound->flags & SOUND_FLAGS_3D ? ACT_SND_3D_SOUND : 0;
+ sAct->flag = (sound->flags & SOUND_FLAGS_3D) ? ACT_SND_3D_SOUND : 0;
sAct->pitch = sound->pitch;
sAct->volume = sound->volume;
sAct->sound3D.reference_distance = sound->distance;
@@ -795,15 +795,19 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
char str[FILE_MAX];
BLI_join_dirfile(str, sizeof(str), seq->strip->dir, seq->strip->stripdata->name);
BLI_path_abs(str, main->name);
- seq->sound = sound_new_file(main, str);
+ seq->sound = BKE_sound_new_file(main, str);
}
+#define SEQ_USE_PROXY_CUSTOM_DIR (1 << 19)
+#define SEQ_USE_PROXY_CUSTOM_FILE (1 << 21)
/* don't know, if anybody used that this way, but just in case, upgrade to new way... */
if ((seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) &&
!(seq->flag & SEQ_USE_PROXY_CUSTOM_DIR))
{
BLI_snprintf(seq->strip->proxy->dir, FILE_MAXDIR, "%s/BL_proxy", seq->strip->dir);
}
- }
+#undef SEQ_USE_PROXY_CUSTOM_DIR
+#undef SEQ_USE_PROXY_CUSTOM_FILE
+ }
SEQ_END
}
}
@@ -1648,8 +1652,8 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
/* brush texture changes */
for (brush = main->brush.first; brush; brush = brush->id.next) {
- default_mtex(&brush->mtex);
- default_mtex(&brush->mask_mtex);
+ BKE_texture_mtex_default(&brush->mtex);
+ BKE_texture_mtex_default(&brush->mask_mtex);
}
for (ma = main->mat.first; ma; ma = ma->id.next) {
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 105cf770a0e..6a1052969c7 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -845,7 +845,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
Object *ob;
for (ob = main->object.first; ob; ob = ob->id.next) {
if (is_zero_v3(ob->dscale)) {
- fill_vn_fl(ob->dscale, 3, 1.0f);
+ copy_vn_fl(ob->dscale, 3, 1.0f);
}
}
}
@@ -2096,7 +2096,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
if (!MAIN_VERSION_ATLEAST(main, 266, 4)) {
Brush *brush;
for (brush = main->brush.first; brush; brush = brush->id.next) {
- default_mtex(&brush->mask_mtex);
+ BKE_texture_mtex_default(&brush->mask_mtex);
if (brush->ob_mode & OB_MODE_TEXTURE_PAINT) {
brush->spacing /= 2;
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index c6aea63081a..fa32469b549 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -27,6 +27,7 @@
#include "BLI_utildefines.h"
#include "BLI_compiler_attrs.h"
+#include "BLI_string.h"
/* for MinGW32 definition of NULL, could use BLI_blenlib.h instead too */
#include <stddef.h>
@@ -35,11 +36,13 @@
#define DNA_DEPRECATED_ALLOW
#include "DNA_brush_types.h"
+#include "DNA_cache_library_types.h"
#include "DNA_camera_types.h"
#include "DNA_cloth_types.h"
#include "DNA_constraint_types.h"
#include "DNA_key_types.h"
#include "DNA_sdna_types.h"
+#include "DNA_sequence_types.h"
#include "DNA_space_types.h"
#include "DNA_screen_types.h"
#include "DNA_object_types.h"
@@ -48,13 +51,20 @@
#include "DNA_particle_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_actuator_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_smoke_types.h"
#include "DNA_genfile.h"
+#include "BKE_colortools.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
+#include "BKE_scene.h"
+#include "BKE_sequencer.h"
#include "BKE_screen.h"
+#include "BKE_sequencer.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -508,10 +518,10 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
br->mtex.random_angle = 2.0 * M_PI;
br->mask_mtex.random_angle = 2.0 * M_PI;
}
+ }
#undef BRUSH_RAKE
#undef BRUSH_RANDOM_ROTATION
- }
if (!DNA_struct_elem_find(fd->filesdna, "ParticleSettings", "float", "clump_noise_size")) {
ParticleSettings *part;
@@ -739,18 +749,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
-
- if (!DNA_struct_elem_find(fd->filesdna, "bSteeringActuator", "float", "acceleration")) {
- for (ob = main->object.first; ob; ob = ob->id.next) {
- bActuator *act;
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_STEERING) {
- bSteeringActuator *sact = act->data;
- sact->acceleration = 1000.f;
- }
- }
- }
- }
}
if (!MAIN_VERSION_ATLEAST(main, 273, 9)) {
@@ -798,5 +796,287 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
+
+ /* particle systems need to be forced to redistribute for jitter mode fix */
+ {
+ Object *ob;
+ ParticleSystem *psys;
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ psys->recalc |= PSYS_RECALC_RESET;
+ }
+ }
+ }
+
+ /* hysteresis setted to 10% but not actived */
+ if (!DNA_struct_elem_find(fd->filesdna, "LodLevel", "int", "obhysteresis")) {
+ Object *ob;
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ LodLevel *level;
+ for (level = ob->lodlevels.first; level; level = level->next) {
+ level->obhysteresis = 10;
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "GameData", "int", "scehysteresis")) {
+ Scene *scene;
+ for (scene = main->scene.first; scene; scene = scene->id.next) {
+ scene->gm.scehysteresis = 10;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 274, 2)) {
+ FOREACH_NODETREE(main, ntree, id) {
+ bNode *node;
+ bNodeSocket *sock;
+
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_MATERIAL) {
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ if (STREQ(sock->name, "Refl")) {
+ BLI_strncpy(sock->name, "DiffuseIntensity", sizeof(sock->name));
+ }
+ }
+ }
+ else if (node->type == SH_NODE_MATERIAL_EXT) {
+ for (sock = node->outputs.first; sock; sock = sock->next) {
+ if (STREQ(sock->name, "Refl")) {
+ BLI_strncpy(sock->name, "DiffuseIntensity", sizeof(sock->name));
+ }
+ else if (STREQ(sock->name, "Ray Mirror")) {
+ BLI_strncpy(sock->name, "Reflectivity", sizeof(sock->name));
+ }
+ }
+ }
+ }
+ } FOREACH_NODETREE_END
+ }
+
+ {
+ bScreen *scr;
+ ScrArea *sa;
+ SpaceLink *sl;
+ ARegion *ar;
+ /* Make sure sequencer preview area limits zoom */
+ for (scr = main->screen.first; scr; scr = scr->id.next) {
+ for (sa = scr->areabase.first; sa; sa = sa->next) {
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_SEQ) {
+ ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+
+ for (ar = lb->first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ ar->v2d.max[1] = MAXSEQ * 4;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 274, 4)) {
+ SceneRenderView *srv;
+ wmWindowManager *wm;
+ bScreen *screen;
+ wmWindow *win;
+ Scene *scene;
+ Camera *cam;
+ Image *ima;
+
+ for (scene = main->scene.first; scene; scene = scene->id.next) {
+ Sequence *seq;
+
+ BKE_scene_add_render_view(scene, STEREO_LEFT_NAME);
+ srv = scene->r.views.first;
+ BLI_strncpy(srv->suffix, STEREO_LEFT_SUFFIX, sizeof(srv->suffix));
+
+ BKE_scene_add_render_view(scene, STEREO_RIGHT_NAME);
+ srv = scene->r.views.last;
+ BLI_strncpy(srv->suffix, STEREO_RIGHT_SUFFIX, sizeof(srv->suffix));
+
+ SEQ_BEGIN (scene->ed, seq)
+ {
+ seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo Display 3d Format");
+ /* patch sequencer scene strips (used to be the same flag before multiview merge)*/
+ if (seq->flag & SEQ_USE_VIEWS) {
+ seq->flag |= SEQ_SCENE_STRIPS;
+ seq->flag &= ~SEQ_USE_VIEWS;
+ }
+
+#define SEQ_USE_PROXY_CUSTOM_DIR (1 << 19)
+#define SEQ_USE_PROXY_CUSTOM_FILE (1 << 21)
+ if (seq->strip && seq->strip->proxy && !seq->strip->proxy->storage) {
+ if (seq->flag & SEQ_USE_PROXY_CUSTOM_DIR)
+ seq->strip->proxy->storage = SEQ_STORAGE_PROXY_CUSTOM_DIR;
+ if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE)
+ seq->strip->proxy->storage = SEQ_STORAGE_PROXY_CUSTOM_FILE;
+ }
+#undef SEQ_USE_PROXY_CUSTOM_DIR
+#undef SEQ_USE_PROXY_CUSTOM_FILE
+
+ }
+ SEQ_END
+ }
+
+ for (screen = main->screen.first; screen; screen = screen->id.next) {
+ ScrArea *sa;
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl;
+
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ switch (sl->spacetype) {
+ case SPACE_VIEW3D:
+ {
+ View3D *v3d = (View3D *)sl;
+ v3d->stereo3d_camera = STEREO_3D_ID;
+ v3d->stereo3d_flag |= V3D_S3D_DISPPLANE;
+ v3d->stereo3d_convergence_alpha = 0.15f;
+ v3d->stereo3d_volume_alpha = 0.05f;
+ break;
+ }
+ case SPACE_IMAGE:
+ {
+ SpaceImage *sima = (SpaceImage *) sl;
+ sima->iuser.flag |= IMA_SHOW_STEREO;
+ sima->iuser.passtype = SCE_PASS_COMBINED;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ for (cam = main->camera.first; cam; cam = cam->id.next) {
+ cam->stereo.interocular_distance = 0.065f;
+ cam->stereo.convergence_distance = 30.0f * 0.065f;
+ }
+
+ for (ima = main->image.first; ima; ima = ima->id.next) {
+ ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo 3d Format");
+
+ if (ima->packedfile) {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Packed File");
+ BLI_addtail(&ima->packedfiles, imapf);
+
+ imapf->packedfile = ima->packedfile;
+ BLI_strncpy(imapf->filepath, ima->name, FILE_MAX);
+ ima->packedfile = NULL;
+ }
+ }
+
+ for (wm = main->wm.first; wm; wm = wm->id.next) {
+ for (win = wm->windows.first; win; win = win->next) {
+ win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo Display 3d Format");
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "SmokeDomainSettings", "float", "display_thickness")) {
+ Object *ob;
+ ModifierData *md;
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Smoke) {
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ if (smd->domain) {
+ smd->domain->display_thickness = 1.0f;
+ }
+ }
+ }
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "SpaceIpo", "float", "backdrop_zoom")) {
+ bScreen *sc;
+ for (sc = main->screen.first; sc; sc = sc->id.next) {
+ ScrArea *sa;
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl;
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_IPO) {
+ SpaceIpo *sipo = (SpaceIpo *)sl;
+ sipo->backdrop_zoom = 1.0f;
+ sipo->backdrop_opacity = 0.7f;
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 274, 6)) {
+ bScreen *screen;
+
+ if (!DNA_struct_elem_find(fd->filesdna, "FileSelectParams", "int", "thumbnail_size")) {
+ for (screen = main->screen.first; screen; screen = screen->id.next) {
+ ScrArea *sa;
+
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl;
+
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = (SpaceFile *)sl;
+
+ if (sfile->params) {
+ sfile->params->thumbnail_size = 128;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "short", "simplify_subsurf_render")) {
+ Scene *scene;
+ for (scene = main->scene.first; scene != NULL; scene = scene->id.next) {
+ scene->r.simplify_subsurf_render = scene->r.simplify_subsurf;
+ scene->r.simplify_particles_render = scene->r.simplify_particles;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "DecimateModifierData", "float", "defgrp_factor")) {
+ 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_Decimate) {
+ DecimateModifierData *dmd = (DecimateModifierData *)md;
+ dmd->defgrp_factor = 1.0f;
+ }
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "HairSimParams", "CurveMapping", "*bend_stiffness_mapping")) {
+ CacheLibrary *cachelib;
+ for (cachelib = main->cache_library.first; cachelib; cachelib = cachelib->id.next) {
+ CacheModifier *md;
+ for (md = cachelib->modifiers.first; md; md = md->next) {
+ if (md->type == eCacheModifierType_HairSimulation) {
+ HairSimCacheModifier *hsmd = (HairSimCacheModifier *)md;
+ {
+ CurveMapping *cm = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ cm->cm[0].curve[0].x = 0.0f;
+ cm->cm[0].curve[0].y = 1.0f;
+ cm->cm[0].curve[1].x = 1.0f;
+ cm->cm[0].curve[1].y = 1.0f;
+ hsmd->sim_params.bend_stiffness_mapping = cm;
+ }
+ }
+ }
+ }
+ }
+
+ /* from_extra has been moved to fromtype, fromindex */
+ if (!DNA_struct_elem_find(fd->filesdna, "Key", "int", "fromindex")) {
+ Key *key;
+ for (key = main->key.first; key; key = key->id.next) {
+ key->fromtype = key->from_extra.type;
+ key->fromindex = key->from_extra.index;
+ }
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index 4c7b011097b..045f422e4ac 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -92,6 +92,9 @@ void BLO_update_defaults_startup_blend(Main *bmain)
sculpt->detail_size = 12;
}
}
+
+ scene->gm.lodflag |= SCE_LOD_USE_HYST;
+ scene->gm.scehysteresis = 10;
}
for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) {
@@ -118,9 +121,15 @@ void BLO_update_defaults_startup_blend(Main *bmain)
}
}
- /* Remove all stored panels, we want to use defaults (order, open/closed) as defined by UI code here! */
for (ar = area->regionbase.first; ar; ar = ar->next) {
+ /* Remove all stored panels, we want to use defaults (order, open/closed) as defined by UI code here! */
BLI_freelistN(&ar->panels);
+
+ /* simple fix for 3d view properties scrollbar being not set to top */
+ if (ar->regiontype == RGN_TYPE_UI) {
+ ar->v2d.cur.ymax = ar->v2d.tot.ymax;
+ ar->v2d.cur.ymin = ar->v2d.cur.ymax - ar->winy;
+ }
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 5dae6fbc464..dab22d414d8 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -77,6 +77,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_colortools.h"
#include "BKE_constraint.h"
@@ -795,22 +796,14 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
nr = me->totface;
tface = me->tface;
while (nr--) {
- cp = (char *)&tface->col[0];
- if (cp[1] > 126) cp[1] = 255; else cp[1] *= 2;
- if (cp[2] > 126) cp[2] = 255; else cp[2] *= 2;
- if (cp[3] > 126) cp[3] = 255; else cp[3] *= 2;
- cp = (char *)&tface->col[1];
- if (cp[1] > 126) cp[1] = 255; else cp[1] *= 2;
- if (cp[2] > 126) cp[2] = 255; else cp[2] *= 2;
- if (cp[3] > 126) cp[3] = 255; else cp[3] *= 2;
- cp = (char *)&tface->col[2];
- if (cp[1] > 126) cp[1] = 255; else cp[1] *= 2;
- if (cp[2] > 126) cp[2] = 255; else cp[2] *= 2;
- if (cp[3] > 126) cp[3] = 255; else cp[3] *= 2;
- cp = (char *)&tface->col[3];
- if (cp[1] > 126) cp[1] = 255; else cp[1] *= 2;
- if (cp[2] > 126) cp[2] = 255; else cp[2] *= 2;
- if (cp[3] > 126) cp[3] = 255; else cp[3] *= 2;
+ int j;
+ for (j = 0; j < 4; j++) {
+ int k;
+ cp = ((char *)&tface->col[j]) + 1;
+ for (k = 0; k < 3; k++) {
+ cp[k] = (cp[k] > 126) ? 255 : cp[k] * 2;
+ }
+ }
tface++;
}
@@ -1958,7 +1951,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
/* btw. armature_rebuild_pose is further only called on leave editmode */
if (ob->type == OB_ARMATURE) {
if (ob->pose)
- ob->pose->flag |= POSE_RECALC;
+ BKE_pose_tag_recalc(main, ob->pose);
/* cannot call stuff now (pointers!), done in setup_app_data */
ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME;
@@ -2082,7 +2075,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
data->rootbone = -1;
/* update_pose_etc handles rootbone == -1 */
- ob->pose->flag |= POSE_RECALC;
+ BKE_pose_tag_recalc(main, ob->pose);
}
}
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index e8f6cf15796..98cc1da574d 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -97,6 +97,7 @@
#include "DNA_armature_types.h"
#include "DNA_actuator_types.h"
#include "DNA_brush_types.h"
+#include "DNA_cache_library_types.h"
#include "DNA_camera_types.h"
#include "DNA_cloth_types.h"
#include "DNA_constraint_types.h"
@@ -147,6 +148,7 @@
#include "BKE_action.h"
#include "BKE_blender.h"
#include "BKE_bpath.h"
+#include "BKE_cache_library.h"
#include "BKE_curve.h"
#include "BKE_constraint.h"
#include "BKE_global.h" // for G
@@ -333,7 +335,7 @@ static void writedata_do_write(WriteData *wd, const void *mem, int memlen)
/* memory based save */
if (wd->current) {
- add_memfilechunk(NULL, wd->current, mem, memlen);
+ memfile_chunk_add(NULL, wd->current, mem, memlen);
}
else {
if (wd->ww->write(wd->ww, mem, memlen) != memlen) {
@@ -407,7 +409,7 @@ static void mywrite(WriteData *wd, const void *adr, int len)
/**
* BeGiN initializer for mywrite
- * \param file File descriptor
+ * \param ww: File write wrapper.
* \param compare Previous memory file (can be NULL).
* \param current The current memory file (can be NULL).
* \warning Talks to other functions with global parameters
@@ -421,7 +423,7 @@ static WriteData *bgnwrite(WriteWrap *ww, MemFile *compare, MemFile *current)
wd->compare= compare;
wd->current= current;
/* this inits comparing */
- add_memfilechunk(compare, NULL, NULL, 0);
+ memfile_chunk_add(compare, NULL, NULL, 0);
return wd;
}
@@ -597,7 +599,7 @@ static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers)
/* Modifiers */
for (fcm= fmodifiers->first; fcm; fcm= fcm->next) {
- FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
/* Write the specific data */
if (fmi && fcm->data) {
@@ -1404,7 +1406,7 @@ static void write_constraints(WriteData *wd, ListBase *conlist)
bConstraint *con;
for (con=conlist->first; con; con=con->next) {
- bConstraintTypeInfo *cti= BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti= BKE_constraint_typeinfo_get(con);
/* Write the specific data */
if (cti && con->data) {
@@ -1508,7 +1510,7 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
if (modbase == NULL) return;
for (md=modbase->first; md; md= md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti == NULL) return;
writestruct(wd, DATA, mti->structName, 1, md);
@@ -1628,6 +1630,13 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
writedata(wd, DATA, sizeof(float)*lmd->total_verts * 3, lmd->vertexco);
}
+ else if (md->type == eModifierType_CorrectiveSmooth) {
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+
+ if (csmd->bind_coords) {
+ writedata(wd, DATA, sizeof(float[3]) * csmd->bind_coords_num, csmd->bind_coords);
+ }
+ }
}
}
@@ -1905,26 +1914,35 @@ static void write_grid_paint_mask(WriteData *wd, int count, GridPaintMask *grid_
static void write_customdata(WriteData *wd, ID *id, int count, CustomData *data, int partial_type, int partial_count)
{
- CustomData data_tmp;
int i;
- /* This copy will automatically ignore/remove layers set as NO_COPY (and TEMPORARY). */
- CustomData_copy(data, &data_tmp, CD_MASK_EVERYTHING, CD_REFERENCE, count);
+ int nofree_buff[128];
+ int *nofree;
/* write external customdata (not for undo) */
- if (data_tmp.external && !wd->current)
- CustomData_external_write(&data_tmp, id, CD_MASK_MESH, count, 0);
+ if (data->external && !wd->current)
+ CustomData_external_write(data, id, CD_MASK_MESH, count, 0);
+
+ if (data->totlayer > ARRAY_SIZE(nofree_buff)) {
+ nofree = MEM_mallocN(sizeof(*nofree) * (size_t)data->totlayer, __func__);
+ }
+ else {
+ nofree = nofree_buff;
+ }
- for (i = 0; i < data_tmp.totlayer; i++)
- data_tmp.layers[i].flag &= ~CD_FLAG_NOFREE;
+ for (i = 0; i < data->totlayer; i++) {
+ nofree[i] = (data->layers[i].flag & CD_FLAG_NOFREE);
+ data->layers[i].flag &= ~CD_FLAG_NOFREE;
+ }
- writestruct_at_address(wd, DATA, "CustomDataLayer", data_tmp.maxlayer, data->layers, data_tmp.layers);
+ writestruct(wd, DATA, "CustomDataLayer", data->maxlayer, data->layers);
- for (i = 0; i < data_tmp.totlayer; i++)
- data_tmp.layers[i].flag |= CD_FLAG_NOFREE;
+ for (i = 0; i < data->totlayer; i++) {
+ data->layers[i].flag |= nofree[i];
+ }
- for (i = 0; i < data_tmp.totlayer; i++) {
- CustomDataLayer *layer= &data_tmp.layers[i];
+ for (i = 0; i < data->totlayer; i++) {
+ CustomDataLayer *layer= &data->layers[i];
const char *structname;
int structnum, datasize;
@@ -1964,10 +1982,12 @@ static void write_customdata(WriteData *wd, ID *id, int count, CustomData *data,
}
}
- if (data_tmp.external)
- writestruct_at_address(wd, DATA, "CustomDataExternal", 1, data->external, data_tmp.external);
+ if (data->external)
+ writestruct(wd, DATA, "CustomDataExternal", 1, data->external);
- CustomData_free(&data_tmp, count);
+ if (nofree != nofree_buff) {
+ MEM_freeN(nofree);
+ }
}
static void write_meshes(WriteData *wd, ListBase *idbase)
@@ -1984,23 +2004,32 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
if (mesh->id.us>0 || wd->current) {
/* write LibData */
if (!save_for_old_blender) {
-
-#ifdef USE_BMESH_SAVE_WITHOUT_MFACE
/* write a copy of the mesh, don't modify in place because it is
* not thread safe for threaded renders that are reading this */
Mesh *old_mesh = mesh;
Mesh copy_mesh = *mesh;
mesh = &copy_mesh;
+#ifdef USE_BMESH_SAVE_WITHOUT_MFACE
/* cache only - don't write */
mesh->mface = NULL;
mesh->totface = 0;
memset(&mesh->fdata, 0, sizeof(mesh->fdata));
+#endif /* USE_BMESH_SAVE_WITHOUT_MFACE */
+
+ /* Bummer! We need to do the copy *before* writing mesh's struct itself,
+ * because we eliminate NO_COPY & TEMPORARY layers here, which means
+ * **number of layers (data.totlayer) may be smaller!**
+ * If we do not do that, we can get crash by buffer-overflow on reading, see T44461. */
+ CustomData_copy(&old_mesh->vdata, &mesh->vdata, CD_MASK_EVERYTHING, CD_REFERENCE, mesh->totvert);
+ CustomData_copy(&old_mesh->edata, &mesh->edata, CD_MASK_EVERYTHING, CD_REFERENCE, mesh->totedge);
+#ifndef USE_BMESH_SAVE_WITHOUT_MFACE /* Do not copy org fdata in this case!!! */
+ CustomData_copy(&old_mesh->fdata, &mesh->fdata, CD_MASK_EVERYTHING, CD_REFERENCE, mesh->totface);
+#endif
+ CustomData_copy(&old_mesh->ldata, &mesh->ldata, CD_MASK_EVERYTHING, CD_REFERENCE, mesh->totloop);
+ CustomData_copy(&old_mesh->pdata, &mesh->pdata, CD_MASK_EVERYTHING, CD_REFERENCE, mesh->totpoly);
writestruct_at_address(wd, ID_ME, "Mesh", 1, old_mesh, mesh);
-#else
- writestruct(wd, ID_ME, "Mesh", 1, mesh);
-#endif /* USE_BMESH_SAVE_WITHOUT_MFACE */
/* direct data */
if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
@@ -2016,11 +2045,16 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, -1, 0);
write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, -1, 0);
-#ifdef USE_BMESH_SAVE_WITHOUT_MFACE
+ CustomData_free(&mesh->vdata, mesh->totvert);
+ CustomData_free(&mesh->edata, mesh->totedge);
+#ifndef USE_BMESH_SAVE_WITHOUT_MFACE
+ CustomData_free(&mesh->fdata, mesh->totface);
+#endif
+ CustomData_free(&mesh->ldata, mesh->totloop);
+ CustomData_free(&mesh->pdata, mesh->totpoly);
+
/* restore pointer */
mesh = old_mesh;
-#endif /* USE_BMESH_SAVE_WITHOUT_MFACE */
-
}
else {
@@ -2047,6 +2081,10 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
BKE_mesh_update_customdata_pointers(mesh, false);
+ /* See comment above. Note that loop/poly data are ignored here, and face ones are already handled. */
+ CustomData_copy(&old_mesh->vdata, &mesh->vdata, CD_MASK_EVERYTHING, CD_REFERENCE, mesh->totvert);
+ CustomData_copy(&old_mesh->edata, &mesh->edata, CD_MASK_EVERYTHING, CD_REFERENCE, mesh->totedge);
+
writestruct_at_address(wd, ID_ME, "Mesh", 1, old_mesh, mesh);
/* direct data */
@@ -2065,6 +2103,8 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, -1, 0);
#endif
+ CustomData_free(&mesh->vdata, mesh->totvert);
+ CustomData_free(&mesh->edata, mesh->totedge);
CustomData_free(&mesh->fdata, mesh->totface);
/* restore pointer */
@@ -2130,22 +2170,39 @@ static void write_images(WriteData *wd, ListBase *idbase)
{
Image *ima;
PackedFile * pf;
-
+ ImageView *iv;
+ ImagePackedFile *imapf;
ima= idbase->first;
while (ima) {
if (ima->id.us>0 || wd->current) {
+ /* Some trickery to keep forward compatibility of packed images. */
+ BLI_assert(ima->packedfile == NULL);
+ if (ima->packedfiles.first != NULL) {
+ imapf = ima->packedfiles.first;
+ ima->packedfile = imapf->packedfile;
+ }
+
/* write LibData */
writestruct(wd, ID_IM, "Image", 1, ima);
if (ima->id.properties) IDP_WriteProperty(ima->id.properties, wd);
- if (ima->packedfile) {
- pf = ima->packedfile;
- writestruct(wd, DATA, "PackedFile", 1, pf);
- writedata(wd, DATA, pf->size, pf->data);
+ for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) {
+ writestruct(wd, DATA, "ImagePackedFile", 1, imapf);
+ if (imapf->packedfile) {
+ pf = imapf->packedfile;
+ writestruct(wd, DATA, "PackedFile", 1, pf);
+ writedata(wd, DATA, pf->size, pf->data);
+ }
}
write_previews(wd, ima->preview);
+
+ for (iv = ima->views.first; iv; iv = iv->next)
+ writestruct(wd, DATA, "ImageView", 1, iv);
+ writestruct(wd, DATA, "Stereo3dFormat", 1, ima->stereo3d_format);
+
+ ima->packedfile = NULL;
}
ima= ima->id.next;
}
@@ -2300,7 +2357,7 @@ static void write_sequence_modifiers(WriteData *wd, ListBase *modbase)
SequenceModifierData *smd;
for (smd = modbase->first; smd; smd = smd->next) {
- SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
if (smti) {
writestruct(wd, DATA, smti->struct_name, 1, smd);
@@ -2346,6 +2403,7 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
TimeMarker *marker;
TransformOrientation *ts;
SceneRenderLayer *srl;
+ SceneRenderView *srv;
ToolSettings *tos;
FreestyleModuleConfig *fmc;
FreestyleLineSet *fls;
@@ -2427,7 +2485,9 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
break;
}
}
-
+
+ writestruct(wd, DATA, "Stereo3dFormat", 1, seq->stereo3d_format);
+
strip= seq->strip;
writestruct(wd, DATA, "Strip", 1, strip);
if (seq->flag & SEQ_USE_CROP && strip->crop) {
@@ -2447,6 +2507,10 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
strip->done = true;
}
+ if (seq->prop) {
+ IDP_WriteProperty(seq->prop, wd);
+ }
+
write_sequence_modifiers(wd, &seq->modifiers);
}
SEQ_END
@@ -2488,6 +2552,10 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
writestruct(wd, DATA, "FreestyleLineSet", 1, fls);
}
}
+
+ /* writing MultiView to the blend file */
+ for (srv = sce->r.views.first; srv; srv = srv->next)
+ writestruct(wd, DATA, "SceneRenderView", 1, srv);
if (sce->nodetree) {
writestruct(wd, DATA, "bNodeTree", 1, sce->nodetree);
@@ -2550,8 +2618,10 @@ static void write_windowmanagers(WriteData *wd, ListBase *lb)
for (wm= lb->first; wm; wm= wm->id.next) {
writestruct(wd, ID_WM, "wmWindowManager", 1, wm);
- for (win= wm->windows.first; win; win= win->next)
+ for (win= wm->windows.first; win; win= win->next) {
writestruct(wd, DATA, "wmWindow", 1, win);
+ writestruct(wd, DATA, "Stereo3dFormat", 1, win->stereo3d_format);
+ }
}
}
@@ -2710,7 +2780,10 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
writestruct(wd, DATA, "SpaceIpo", 1, sl);
if (sipo->ads) writestruct(wd, DATA, "bDopeSheet", 1, sipo->ads);
-
+
+ if (sipo->backdrop_camera)
+ writestruct(wd, DATA, "Object", 1, sipo->backdrop_camera);
+
/* reenable ghost curves */
sipo->ghostCurves= tmpGhosts;
}
@@ -3486,6 +3559,46 @@ static void write_linestyles(WriteData *wd, ListBase *idbase)
}
}
+static void write_cache_modifiers(WriteData *wd, CacheLibrary *cachelib)
+{
+ CacheModifier *md;
+ for (md = cachelib->modifiers.first; md; md = md->next) {
+ const char *struct_name = BKE_cache_modifier_type_struct_name(md->type);
+ if (!struct_name || struct_name[0] == '\0')
+ continue;
+
+ writestruct(wd, DATA, struct_name, 1, md);
+
+ switch (md->type) {
+ case eCacheModifierType_HairSimulation: {
+ HairSimCacheModifier *hsmd = (HairSimCacheModifier *)md;
+ writestruct(wd, DATA, "EffectorWeights", 1, hsmd->sim_params.effector_weights);
+ if (hsmd->sim_params.goal_stiffness_mapping)
+ write_curvemapping(wd, hsmd->sim_params.goal_stiffness_mapping);
+ if (hsmd->sim_params.bend_stiffness_mapping)
+ write_curvemapping(wd, hsmd->sim_params.bend_stiffness_mapping);
+ break;
+ }
+ }
+ }
+}
+
+static void write_cachelibraries(WriteData *wd, ListBase *idbase)
+{
+ CacheLibrary *cachelib;
+
+ for (cachelib = idbase->first; cachelib; cachelib = cachelib->id.next) {
+ if (cachelib->id.us > 0 || wd->current) {
+
+ writestruct(wd, ID_CL, "CacheLibrary", 1, cachelib);
+ if (cachelib->id.properties)
+ IDP_WriteProperty(cachelib->id.properties, wd);
+
+ write_cache_modifiers(wd, cachelib);
+ }
+ }
+}
+
/* context is usually defined by WM, two cases where no WM is available:
* - for forward compatibility, curscreen has to be saved
* - for undofile, curscene needs to be saved */
@@ -3614,6 +3727,7 @@ static int write_file_handle(
write_scripts (wd, &mainvar->script);
write_gpencils (wd, &mainvar->gpencil);
write_linestyles(wd, &mainvar->linestyle);
+ write_cachelibraries(wd, &mainvar->cache_library);
write_libraries(wd, mainvar->next);
if (write_user_block) {
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 80adb595ac9..6002b414779 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -114,6 +114,10 @@ set(SRC
intern/bmesh_queries.c
intern/bmesh_queries.h
intern/bmesh_queries_inline.h
+ intern/bmesh_strands.c
+ intern/bmesh_strands.h
+ intern/bmesh_strands_conv.c
+ intern/bmesh_strands_conv.h
intern/bmesh_structure.c
intern/bmesh_structure.h
intern/bmesh_structure_inline.h
diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h
index 87b1818fa5d..7ba700d17a2 100644
--- a/source/blender/bmesh/bmesh.h
+++ b/source/blender/bmesh/bmesh.h
@@ -256,6 +256,8 @@ extern "C" {
#include "intern/bmesh_mesh_validate.h"
#include "intern/bmesh_mods.h"
#include "intern/bmesh_operators.h"
+#include "intern/bmesh_strands.h"
+#include "intern/bmesh_strands_conv.h"
#include "intern/bmesh_polygon.h"
#include "intern/bmesh_queries.h"
#include "intern/bmesh_walkers.h"
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index 120ff4997dc..058fec548a3 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -256,11 +256,36 @@ enum {
#define BM_ALL (BM_VERT | BM_EDGE | BM_LOOP | BM_FACE)
#define BM_ALL_NOLOOP (BM_VERT | BM_EDGE | BM_FACE)
+/* args for _Generic */
+#define _BM_GENERIC_TYPE_ELEM_NONCONST \
+ void *, BMVert *, BMEdge *, BMLoop *, BMFace *, \
+ BMElem *, BMElemF *, BMHeader *
+
+#define _BM_GENERIC_TYPE_ELEM_CONST \
+ const void *, const BMVert *, const BMEdge *, const BMLoop *, const BMFace *, \
+ const BMElem *, const BMElemF *, const BMHeader *, \
+ void * const, BMVert * const, BMEdge * const, BMLoop * const, BMFace * const, \
+ BMElem * const, BMElemF * const, BMHeader * const
+
+#define BM_CHECK_TYPE_ELEM_CONST(ele) \
+ CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPES_CONST)
+
+#define BM_CHECK_TYPE_ELEM_NONCONST(ele) \
+ CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST)
+
#define BM_CHECK_TYPE_ELEM(ele) \
- CHECK_TYPE_ANY(ele, void *, BMFace *, BMEdge *, BMVert *, BMLoop *, BMElem *, BMElemF *, BMHeader *)
+ CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST, _BM_GENERIC_TYPE_ELEM_CONST)
+#ifndef __cplusplus
#define BM_CHECK_TYPE_ELEM_ASSIGN(ele) \
- (BM_CHECK_TYPE_ELEM(ele), CHECK_TYPE_NONCONST(ele)), ele
+ (BM_CHECK_TYPE_ELEM(ele)), ele
+#else
+/* for C++: cast the lhs to a void*,
+ * because C++ does not allow implicit void* casting of the rhs
+ */
+#define BM_CHECK_TYPE_ELEM_ASSIGN(ele) \
+ (BM_CHECK_TYPE_ELEM(ele), CHECK_TYPE_NONCONST(ele)), *(void**)(&(ele))
+#endif
/* BMHeader->hflag (char) */
enum {
@@ -297,8 +322,17 @@ typedef bool (*BMElemFilterFunc)(BMElem *, void *user_data);
#define BM_ELEM_CD_GET_INT(ele, offset) \
(assert(offset != -1), *((int *)((char *)(ele)->head.data + (offset))))
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+#define BM_ELEM_CD_GET_VOID_P(ele, offset) \
+ (assert(offset != -1), \
+ _Generic(ele, \
+ GENERIC_TYPE_ANY( POINTER_OFFSET((ele)->head.data, offset), _BM_GENERIC_TYPE_ELEM_NONCONST), \
+ GENERIC_TYPE_ANY((const void *)POINTER_OFFSET((ele)->head.data, offset), _BM_GENERIC_TYPE_ELEM_CONST)) \
+ )
+#else
#define BM_ELEM_CD_GET_VOID_P(ele, offset) \
(assert(offset != -1), (void *)((char *)(ele)->head.data + (offset)))
+#endif
#define BM_ELEM_CD_SET_FLOAT(ele, offset, f) { CHECK_TYPE_NONCONST(ele); \
assert(offset != -1); *((float *)((char *)(ele)->head.data + (offset))) = (f); } (void)0
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index e0348fea636..7664108f348 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -46,9 +46,41 @@
#define SELECT 1
+/**
+ * Fill in an edge array from a vertex array (connected polygon loop).
+ *
+ * \returns false if any edges aren't found .
+ */
+bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len)
+{
+ int i, i_prev = len - 1;
+ for (i = 0; i < len; i++) {
+ edge_arr[i_prev] = BM_edge_exists(vert_arr[i_prev], vert_arr[i]);
+ if (edge_arr[i_prev] == NULL) {
+ return false;
+ }
+ i_prev = i;
+ }
+ return true;
+}
+
+/**
+ * Fill in an edge array from a vertex array (connected polygon loop).
+ * Creating edges as-needed.
+ */
+void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len)
+{
+ int i, i_prev = len - 1;
+ for (i = 0; i < len; i++) {
+ edge_arr[i_prev] = BM_edge_create(bm, vert_arr[i_prev], vert_arr[i], NULL, BM_CREATE_NO_DOUBLE);
+ i_prev = i;
+ }
+}
+
/* prototypes */
-static void bm_loop_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
- const BMLoop *source_loop, BMLoop *target_loop);
+static void bm_loop_attrs_copy(
+ BMesh *source_mesh, BMesh *target_mesh,
+ const BMLoop *source_loop, BMLoop *target_loop);
/**
* \brief Make Quad/Triangle
@@ -64,9 +96,10 @@ static void bm_loop_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
* of the vertices in the vertex array.
*/
-BMFace *BM_face_create_quad_tri(BMesh *bm,
- BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
- const BMFace *f_example, const eBMCreateFlag create_flag)
+BMFace *BM_face_create_quad_tri(
+ BMesh *bm,
+ BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
+ const BMFace *f_example, const eBMCreateFlag create_flag)
{
BMVert *vtar[4] = {v1, v2, v3, v4};
return BM_face_create_verts(bm, vtar, v4 ? 4 : 3, f_example, create_flag, true);
@@ -81,8 +114,9 @@ BMFace *BM_face_create_quad_tri(BMesh *bm,
* this is done since the face may not be completely surrounded by faces,
* this way: a quad with 2 connected quads on either side will still get all 4 loops updated
*/
-void BM_face_copy_shared(BMesh *bm, BMFace *f,
- BMElemFilterFunc filter_fn, void *user_data)
+void BM_face_copy_shared(
+ BMesh *bm, BMFace *f,
+ BMElemFilterFunc filter_fn, void *user_data)
{
BMLoop *l_first;
BMLoop *l_iter;
@@ -132,155 +166,113 @@ void BM_face_copy_shared(BMesh *bm, BMFace *f,
}
/**
- * \brief Make NGon
+ * Given an array of edges,
+ * order them using the winding defined by \a v1 & \a v2
+ * into \a edges_sort & \a verts_sort.
*
- * Makes an ngon from an unordered list of edges. \a v1 and \a v2
- * must be the verts defining edges[0],
- * and define the winding of the new face.
- *
- * \a edges are not required to be ordered, simply to to form
- * a single closed loop as a whole.
- *
- * \note While this function will work fine when the edges
- * are already sorted, if the edges are always going to be sorted,
- * #BM_face_create should be considered over this function as it
- * avoids some unnecessary work.
+ * All arrays must be \a len long.
*/
-BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len,
- const BMFace *f_example, const eBMCreateFlag create_flag)
+static bool bm_edges_sort_winding(
+ BMVert *v1, BMVert *v2,
+ BMEdge **edges, const int len,
+ BMEdge **edges_sort, BMVert **verts_sort)
{
- BMEdge **edges_sort = BLI_array_alloca(edges_sort, len);
- BMVert **verts_sort = BLI_array_alloca(verts_sort, len + 1);
- int esort_index = 0;
- int vsort_index = 0;
-
- BMFace *f = NULL;
- BMEdge *e;
- BMVert *v, *ev1, *ev2;
+ BMEdge *e_iter, *e_first;
+ BMVert *v_iter;
int i;
- bool is_v1_found, is_reverse;
-
- /* this code is hideous, yeek. I'll have to think about ways of
- * cleaning it up. basically, it now combines the old BM_face_create_ngon
- * _and_ the old bmesh_mf functions, so its kindof smashed together
- * - joeedh */
-
- BLI_assert(len && v1 && v2 && edges && bm);
-
- /* put edges in correct order */
+ /* all flags _must_ be cleared on exit! */
for (i = 0; i < len; i++) {
BM_ELEM_API_FLAG_ENABLE(edges[i], _FLAG_MF);
+ BM_ELEM_API_FLAG_ENABLE(edges[i]->v1, _FLAG_MV);
+ BM_ELEM_API_FLAG_ENABLE(edges[i]->v2, _FLAG_MV);
}
- ev1 = edges[0]->v1;
- ev2 = edges[0]->v2;
-
- BLI_assert(ELEM(v1, ev1, ev2) && ELEM(v2, ev1, ev2));
-
- if (v1 == ev2) {
- /* Swapping here improves performance and consistency of face
- * structure in the special case that the edges are already in
- * the correct order and winding */
- SWAP(BMVert *, ev1, ev2);
- }
-
- verts_sort[vsort_index++] = ev1;
- v = ev2;
- e = edges[0];
+ /* find first edge */
+ i = 0;
+ v_iter = v1;
+ e_iter = e_first = v1->e;
do {
- BMEdge *e2 = e;
-
- /* vertex array is (len + 1) */
- if (UNLIKELY(vsort_index > len)) {
- goto err; /* vertex in loop twice */
+ if (BM_ELEM_API_FLAG_TEST(e_iter, _FLAG_MF) &&
+ (BM_edge_other_vert(e_iter, v_iter) == v2))
+ {
+ i = 1;
+ break;
}
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v_iter)) != e_first);
+ if (i == 0) {
+ goto error;
+ }
- verts_sort[vsort_index++] = v;
- edges_sort[esort_index++] = e;
-
- /* we only flag the verts to check if they are in the face more than once */
- BM_ELEM_API_FLAG_ENABLE(v, _FLAG_MV);
-
- do {
- e2 = bmesh_disk_edge_next(e2, v);
- if (e2 != e && BM_ELEM_API_FLAG_TEST(e2, _FLAG_MF)) {
- v = BM_edge_other_vert(e2, v);
- break;
+ i = 0;
+ do {
+ /* entering loop will always succeed */
+ if (BM_ELEM_API_FLAG_TEST(e_iter, _FLAG_MF)) {
+ if (UNLIKELY(BM_ELEM_API_FLAG_TEST(v_iter, _FLAG_MV) == false)) {
+ /* vert is in loop multiple times */
+ goto error;
}
- } while (e2 != e);
- if (UNLIKELY(e2 == e)) {
- goto err; /* the edges do not form a closed loop */
- }
+ BM_ELEM_API_FLAG_DISABLE(e_iter, _FLAG_MF);
+ edges_sort[i] = e_iter;
- e = e2;
- } while (e != edges[0]);
+ BM_ELEM_API_FLAG_DISABLE(v_iter, _FLAG_MV);
+ verts_sort[i] = v_iter;
- if (UNLIKELY(esort_index != len)) {
- goto err; /* we didn't use all edges in forming the boundary loop */
- }
+ i += 1;
- /* ok, edges are in correct order, now ensure they are going
- * in the correct direction */
- is_v1_found = is_reverse = false;
- for (i = 0; i < len; i++) {
- if (BM_vert_in_edge(edges_sort[i], v1)) {
- /* see if v1 and v2 are in the same edge */
- if (BM_vert_in_edge(edges_sort[i], v2)) {
- /* if v1 is shared by the *next* edge, then the winding
- * is incorrect */
- if (BM_vert_in_edge(edges_sort[(i + 1) % len], v1)) {
- is_reverse = true;
- break;
+ /* walk onto the next vertex */
+ v_iter = BM_edge_other_vert(e_iter, v_iter);
+ if (i == len) {
+ if (UNLIKELY(v_iter != verts_sort[0])) {
+ goto error;
}
+ break;
}
- is_v1_found = true;
- }
-
- if ((is_v1_found == false) && BM_vert_in_edge(edges_sort[i], v2)) {
- is_reverse = true;
- break;
+ e_first = e_iter;
}
- }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v_iter)) != e_first);
- if (is_reverse) {
- for (i = 0; i < len / 2; i++) {
- v = verts_sort[i];
- verts_sort[i] = verts_sort[len - i - 1];
- verts_sort[len - i - 1] = v;
- }
+ if (i == len) {
+ return true;
}
+error:
for (i = 0; i < len; i++) {
- edges_sort[i] = BM_edge_exists(verts_sort[i], verts_sort[(i + 1) % len]);
- if (UNLIKELY(edges_sort[i] == NULL)) {
- goto err;
- }
-
- /* check if vert is in face more than once. if the flag is disabled. we've already visited */
- if (UNLIKELY(!BM_ELEM_API_FLAG_TEST(verts_sort[i], _FLAG_MV))) {
- goto err;
- }
- BM_ELEM_API_FLAG_DISABLE(verts_sort[i], _FLAG_MV);
+ BM_ELEM_API_FLAG_DISABLE(edges[i], _FLAG_MF);
+ BM_ELEM_API_FLAG_DISABLE(edges[i]->v1, _FLAG_MV);
+ BM_ELEM_API_FLAG_DISABLE(edges[i]->v2, _FLAG_MV);
}
- f = BM_face_create(bm, verts_sort, edges_sort, len, f_example, create_flag);
+ return false;
+}
- /* clean up flags */
- for (i = 0; i < len; i++) {
- BM_ELEM_API_FLAG_DISABLE(edges_sort[i], _FLAG_MF);
- }
+/**
+ * \brief Make NGon
+ *
+ * Makes an ngon from an unordered list of edges.
+ * Verts \a v1 and \a v2 define the winding of the new face.
+ *
+ * \a edges are not required to be ordered, simply to to form
+ * a single closed loop as a whole.
+ *
+ * \note While this function will work fine when the edges
+ * are already sorted, if the edges are always going to be sorted,
+ * #BM_face_create should be considered over this function as it
+ * avoids some unnecessary work.
+ */
+BMFace *BM_face_create_ngon(
+ BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag)
+{
+ BMEdge **edges_sort = BLI_array_alloca(edges_sort, len);
+ BMVert **verts_sort = BLI_array_alloca(verts_sort, len);
- return f;
+ BLI_assert(len && v1 && v2 && edges && bm);
-err:
- for (i = 0; i < len; i++) {
- BM_ELEM_API_FLAG_DISABLE(edges[i], _FLAG_MF);
- }
- for (i = 0; i < vsort_index; i++) {
- BM_ELEM_API_FLAG_DISABLE(verts_sort[i], _FLAG_MV);
+ if (bm_edges_sort_winding(v1, v2, edges, len, edges_sort, verts_sort)) {
+ return BM_face_create(bm, verts_sort, edges_sort, len, f_example, create_flag);
}
return NULL;
@@ -294,9 +286,10 @@ err:
* - Optionally create edges between vertices.
* - Uses verts so no need to find edges (handy when you only have verts)
*/
-BMFace *BM_face_create_ngon_verts(BMesh *bm, BMVert **vert_arr, const int len,
- const BMFace *f_example, const eBMCreateFlag create_flag,
- const bool calc_winding, const bool create_edges)
+BMFace *BM_face_create_ngon_verts(
+ BMesh *bm, BMVert **vert_arr, const int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag,
+ const bool calc_winding, const bool create_edges)
{
BMEdge **edge_arr = BLI_array_alloca(edge_arr, len);
unsigned int winding[2] = {0, 0};
@@ -375,8 +368,9 @@ BMFace *BM_face_create_ngon_verts(BMesh *bm, BMVert **vert_arr, const int len,
*
* \note Since this is a vcloud there is no direction.
*/
-BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int len,
- const BMFace *f_example, const eBMCreateFlag create_flag)
+BMFace *BM_face_create_ngon_vcloud(
+ BMesh *bm, BMVert **vert_arr, int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag)
{
struct SortIntByFloat *vang = BLI_array_alloca(vang, len);
BMVert **vert_arr_map = BLI_array_alloca(vert_arr_map, len);
@@ -497,8 +491,9 @@ BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int len,
/*************************************************************/
-static void bm_vert_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
- const BMVert *source_vertex, BMVert *target_vertex)
+static void bm_vert_attrs_copy(
+ BMesh *source_mesh, BMesh *target_mesh,
+ const BMVert *source_vertex, BMVert *target_vertex)
{
if ((source_mesh == target_mesh) && (source_vertex == target_vertex)) {
BLI_assert(!"BMVert: source and targer match");
@@ -510,8 +505,9 @@ static void bm_vert_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
source_vertex->head.data, &target_vertex->head.data);
}
-static void bm_edge_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
- const BMEdge *source_edge, BMEdge *target_edge)
+static void bm_edge_attrs_copy(
+ BMesh *source_mesh, BMesh *target_mesh,
+ const BMEdge *source_edge, BMEdge *target_edge)
{
if ((source_mesh == target_mesh) && (source_edge == target_edge)) {
BLI_assert(!"BMEdge: source and targer match");
@@ -522,8 +518,9 @@ static void bm_edge_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
source_edge->head.data, &target_edge->head.data);
}
-static void bm_loop_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
- const BMLoop *source_loop, BMLoop *target_loop)
+static void bm_loop_attrs_copy(
+ BMesh *source_mesh, BMesh *target_mesh,
+ const BMLoop *source_loop, BMLoop *target_loop)
{
if ((source_mesh == target_mesh) && (source_loop == target_loop)) {
BLI_assert(!"BMLoop: source and targer match");
@@ -534,8 +531,9 @@ static void bm_loop_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
source_loop->head.data, &target_loop->head.data);
}
-static void bm_face_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
- const BMFace *source_face, BMFace *target_face)
+static void bm_face_attrs_copy(
+ BMesh *source_mesh, BMesh *target_mesh,
+ const BMFace *source_face, BMFace *target_face)
{
if ((source_mesh == target_mesh) && (source_face == target_face)) {
BLI_assert(!"BMFace: source and targer match");
@@ -555,8 +553,9 @@ static void bm_face_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
* Copies attributes, e.g. customdata, header flags, etc, from one element
* to another of the same type.
*/
-void BM_elem_attrs_copy_ex(BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v,
- const char hflag_mask)
+void BM_elem_attrs_copy_ex(
+ BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v,
+ const char hflag_mask)
{
const BMHeader *ele_src = ele_src_v;
BMHeader *ele_dst = ele_dst_v;
@@ -621,9 +620,10 @@ void BM_elem_select_copy(BMesh *bm_dst, BMesh *UNUSED(bm_src), void *ele_dst_v,
}
/* helper function for 'BM_mesh_copy' */
-static BMFace *bm_mesh_copy_new_face(BMesh *bm_new, BMesh *bm_old,
- BMVert **vtable, BMEdge **etable,
- BMFace *f)
+static BMFace *bm_mesh_copy_new_face(
+ BMesh *bm_new, BMesh *bm_old,
+ BMVert **vtable, BMEdge **etable,
+ BMFace *f)
{
BMLoop **loops = BLI_array_alloca(loops, f->len);
BMVert **verts = BLI_array_alloca(verts, f->len);
diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h
index 12d3a4bd474..29503679547 100644
--- a/source/blender/bmesh/intern/bmesh_construct.h
+++ b/source/blender/bmesh/intern/bmesh_construct.h
@@ -29,23 +29,32 @@
struct BMAllocTemplate;
-BMFace *BM_face_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
- const BMFace *f_example, const eBMCreateFlag create_flag);
+bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len);
+void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len);
-void BM_face_copy_shared(BMesh *bm, BMFace *f,
- BMElemFilterFunc filter_fn, void *user_data);
+BMFace *BM_face_create_quad_tri(
+ BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
+ const BMFace *f_example, const eBMCreateFlag create_flag);
-BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len,
- const BMFace *f_example, const eBMCreateFlag create_flag);
-BMFace *BM_face_create_ngon_verts(BMesh *bm, BMVert **vert_arr, const int len,
- const BMFace *f_example, const eBMCreateFlag create_flag,
- const bool calc_winding, const bool create_edges);
+void BM_face_copy_shared(
+ BMesh *bm, BMFace *f,
+ BMElemFilterFunc filter_fn, void *user_data);
-BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int len,
- const BMFace *f_example, const eBMCreateFlag create_flag);
+BMFace *BM_face_create_ngon(
+ BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag);
+BMFace *BM_face_create_ngon_verts(
+ BMesh *bm, BMVert **vert_arr, const int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag,
+ const bool calc_winding, const bool create_edges);
-void BM_elem_attrs_copy_ex(BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v,
- const char hflag_mask);
+BMFace *BM_face_create_ngon_vcloud(
+ BMesh *bm, BMVert **vert_arr, int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag);
+
+void BM_elem_attrs_copy_ex(
+ BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v,
+ const char hflag_mask);
void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v);
void BM_elem_select_copy(BMesh *bm_dst, BMesh *bm_src, void *ele_dst_v, const void *ele_src_v);
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index 9e0807710fc..20a88b0e17c 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -31,7 +31,7 @@
#include "BLI_math_vector.h"
#include "BLI_array.h"
#include "BLI_alloca.h"
-#include "BLI_smallhash.h"
+#include "BLI_linklist_stack.h"
#include "BLI_stackdefines.h"
#include "BLF_translation.h"
@@ -57,8 +57,9 @@
/**
* \brief Main function for creating a new vertex.
*/
-BMVert *BM_vert_create(BMesh *bm, const float co[3],
- const BMVert *v_example, const eBMCreateFlag create_flag)
+BMVert *BM_vert_create(
+ BMesh *bm, const float co[3],
+ const BMVert *v_example, const eBMCreateFlag create_flag)
{
BMVert *v = BLI_mempool_alloc(bm->vpool);
@@ -88,7 +89,7 @@ BMVert *BM_vert_create(BMesh *bm, const float co[3],
else {
zero_v3(v->co);
}
- zero_v3(v->no);
+ /* 'v->no' set below */
v->e = NULL;
/* --- done --- */
@@ -107,6 +108,7 @@ BMVert *BM_vert_create(BMesh *bm, const float co[3],
if (v_example) {
int *keyi;
+ /* handles 'v->no' too */
BM_elem_attrs_copy(bm, bm, v_example, v);
/* exception: don't copy the original shapekey index */
@@ -117,6 +119,15 @@ BMVert *BM_vert_create(BMesh *bm, const float co[3],
}
else {
CustomData_bmesh_set_default(&bm->vdata, &v->head.data);
+ zero_v3(v->no);
+ }
+ }
+ else {
+ if (v_example) {
+ copy_v3_v3(v->no, v_example->no);
+ }
+ else {
+ zero_v3(v->no);
}
}
@@ -131,8 +142,9 @@ BMVert *BM_vert_create(BMesh *bm, const float co[3],
* \note Duplicate edges are supported by the API however users should _never_ see them.
* so unless you need a unique edge or know the edge won't exist, you should call with \a no_double = true
*/
-BMEdge *BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2,
- const BMEdge *e_example, const eBMCreateFlag create_flag)
+BMEdge *BM_edge_create(
+ BMesh *bm, BMVert *v1, BMVert *v2,
+ const BMEdge *e_example, const eBMCreateFlag create_flag)
{
BMEdge *e;
@@ -194,8 +206,9 @@ BMEdge *BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2,
return e;
}
-static BMLoop *bm_loop_create(BMesh *bm, BMVert *v, BMEdge *e, BMFace *f,
- const BMLoop *l_example, const eBMCreateFlag create_flag)
+static BMLoop *bm_loop_create(
+ BMesh *bm, BMVert *v, BMEdge *e, BMFace *f,
+ const BMLoop *l_example, const eBMCreateFlag create_flag)
{
BMLoop *l = NULL;
@@ -213,8 +226,8 @@ static BMLoop *bm_loop_create(BMesh *bm, BMVert *v, BMEdge *e, BMFace *f,
BM_elem_index_set(l, -1); /* set_ok_invalid */
#endif
- l->head.hflag = 0;
l->head.htype = BM_LOOP;
+ l->head.hflag = 0;
l->head.api_flag = 0;
l->v = v;
@@ -244,8 +257,9 @@ static BMLoop *bm_loop_create(BMesh *bm, BMVert *v, BMEdge *e, BMFace *f,
return l;
}
-static BMLoop *bm_face_boundary_add(BMesh *bm, BMFace *f, BMVert *startv, BMEdge *starte,
- const eBMCreateFlag create_flag)
+static BMLoop *bm_face_boundary_add(
+ BMesh *bm, BMFace *f, BMVert *startv, BMEdge *starte,
+ const eBMCreateFlag create_flag)
{
#ifdef USE_BMESH_HOLES
BMLoopList *lst = BLI_mempool_calloc(bm->looplistpool);
@@ -266,8 +280,9 @@ static BMLoop *bm_face_boundary_add(BMesh *bm, BMFace *f, BMVert *startv, BMEdge
return l;
}
-BMFace *BM_face_copy(BMesh *bm_dst, BMesh *bm_src, BMFace *f,
- const bool copy_verts, const bool copy_edges)
+BMFace *BM_face_copy(
+ BMesh *bm_dst, BMesh *bm_src, BMFace *f,
+ const bool copy_verts, const bool copy_edges)
{
BMVert **verts = BLI_array_alloca(verts, f->len);
BMEdge **edges = BLI_array_alloca(edges, f->len);
@@ -362,7 +377,8 @@ BLI_INLINE BMFace *bm_face_create__internal(BMesh *bm)
f->l_first = NULL;
#endif
f->len = 0;
- zero_v3(f->no);
+ /* caller must initialize */
+ // zero_v3(f->no);
f->mat_nr = 0;
/* --- done --- */
@@ -389,8 +405,9 @@ BLI_INLINE BMFace *bm_face_create__internal(BMesh *bm)
* \param len Length of the face
* \param create_flag Options for creating the face
*/
-BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len,
- const BMFace *f_example, const eBMCreateFlag create_flag)
+BMFace *BM_face_create(
+ BMesh *bm, BMVert **verts, BMEdge **edges, const int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag)
{
BMFace *f = NULL;
BMLoop *l, *startl, *lastl;
@@ -443,6 +460,15 @@ BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len,
}
else {
CustomData_bmesh_set_default(&bm->pdata, &f->head.data);
+ zero_v3(f->no);
+ }
+ }
+ else {
+ if (f_example) {
+ copy_v3_v3(f->no, f_example->no);
+ }
+ else {
+ zero_v3(f->no);
}
}
@@ -454,25 +480,18 @@ BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len,
/**
* Wrapper for #BM_face_create when you don't have an edge array
*/
-BMFace *BM_face_create_verts(BMesh *bm, BMVert **vert_arr, const int len,
- const BMFace *f_example, const eBMCreateFlag create_flag, const bool create_edges)
+BMFace *BM_face_create_verts(
+ BMesh *bm, BMVert **vert_arr, const int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag, const bool create_edges)
{
BMEdge **edge_arr = BLI_array_alloca(edge_arr, len);
- int i, i_prev = len - 1;
if (create_edges) {
- for (i = 0; i < len; i++) {
- edge_arr[i_prev] = BM_edge_create(bm, vert_arr[i_prev], vert_arr[i], NULL, BM_CREATE_NO_DOUBLE);
- i_prev = i;
- }
+ BM_edges_from_verts_ensure(bm, edge_arr, vert_arr, len);
}
else {
- for (i = 0; i < len; i++) {
- edge_arr[i_prev] = BM_edge_exists(vert_arr[i_prev], vert_arr[i]);
- if (edge_arr[i_prev] == NULL) {
- return NULL;
- }
- i_prev = i;
+ if (BM_edges_from_verts(edge_arr, vert_arr, len) == false) {
+ return NULL;
}
}
@@ -1026,8 +1045,9 @@ static bool disk_is_flagged(BMVert *v, const char api_flag)
return false;
}
- if (bmesh_radial_length(l) == 1)
+ if (BM_edge_is_boundary(l->e)) {
return false;
+ }
do {
if (!BM_ELEM_API_FLAG_TEST(l->f, api_flag))
@@ -1111,7 +1131,7 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
if (!d1 && !d2 && !BM_ELEM_API_FLAG_TEST(l_iter->e, _FLAG_JF)) {
/* don't remove an edge it makes up the side of another face
* else this will remove the face as well - campbell */
- if (BM_edge_face_count(l_iter->e) <= 2) {
+ if (!BM_edge_face_count_is_over(l_iter->e, 3)) {
if (do_del) {
BLI_array_append(deledges, l_iter->e);
}
@@ -1307,14 +1327,14 @@ static BMFace *bm_face_create__sfme(BMesh *bm, BMFace *f_example)
*
* \return A BMFace pointer
*/
-BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMLoop *l_v1, BMLoop *l_v2,
- BMLoop **r_l,
+BMFace *bmesh_sfme(
+ BMesh *bm, BMFace *f, BMLoop *l_v1, BMLoop *l_v2,
+ BMLoop **r_l,
#ifdef USE_BMESH_HOLES
- ListBase *holes,
+ ListBase *holes,
#endif
- BMEdge *e_example,
- const bool no_double
- )
+ BMEdge *e_example,
+ const bool no_double)
{
#ifdef USE_BMESH_HOLES
BMLoopList *lst, *lst2;
@@ -1481,14 +1501,7 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
bmesh_disk_edge_remove(e_new, tv);
bmesh_disk_edge_remove(e_new, v_new);
- /* remove e from tv's disk cycle */
- bmesh_disk_edge_remove(e, tv);
-
- /* swap out tv for v_new in e */
- bmesh_edge_swapverts(e, tv, v_new);
-
- /* add e to v_new's disk cycle */
- bmesh_disk_edge_append(e, v_new);
+ bmesh_disk_vert_replace(e, v_new, tv);
/* add e_new to v_new's disk cycle */
bmesh_disk_edge_append(e_new, v_new);
@@ -1653,13 +1666,14 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
* faces with just 2 edges. It is up to the caller to decide what to do with
* these faces.
*/
-BMEdge *bmesh_jekv(BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
- const bool do_del, const bool check_edge_double)
+BMEdge *bmesh_jekv(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
+ const bool do_del, const bool check_edge_double)
{
BMEdge *e_old;
BMVert *v_old, *tv;
BMLoop *l_kill;
- int len, radlen = 0, i;
+ int radlen = 0, i;
bool halt = false;
#ifndef NDEBUG
bool edok;
@@ -1670,10 +1684,8 @@ BMEdge *bmesh_jekv(BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
if (BM_vert_in_edge(e_kill, v_kill) == 0) {
return NULL;
}
-
- len = bmesh_disk_count(v_kill);
- if (len == 2) {
+ if (bmesh_disk_count_ex(v_kill, 3) == 2) {
#ifndef NDEBUG
int valence1, valence2;
BMLoop *l;
@@ -1700,12 +1712,8 @@ BMEdge *bmesh_jekv(BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
e_splice = BM_edge_exists(tv, v_old);
}
- /* remove e_old from v_kill's disk cycle */
- bmesh_disk_edge_remove(e_old, v_kill);
- /* relink e_old->v_kill to be e_old->tv */
- bmesh_edge_swapverts(e_old, v_kill, tv);
- /* append e_old to tv's disk cycle */
- bmesh_disk_edge_append(e_old, tv);
+ bmesh_disk_vert_replace(e_old, tv, v_kill);
+
/* remove e_kill from tv's disk cycle */
bmesh_disk_edge_remove(e_kill, tv);
@@ -1789,7 +1797,7 @@ BMEdge *bmesh_jekv(BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
if (check_edge_double) {
if (e_splice) {
/* removes e_splice */
- BM_edge_splice(bm, e_splice, e_old);
+ BM_edge_splice(bm, e_old, e_splice);
}
}
@@ -1963,27 +1971,38 @@ bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b)
BLI_assert(BM_edge_exists(v_a, v_b) == false);
if (v_a->e && v_b->e) {
- SmallHash visit;
BMEdge *e, *e_first;
- BLI_smallhash_init(&visit);
+#define VERT_VISIT _FLAG_WALK
+ /* tag 'v_a' */
e = e_first = v_a->e;
do {
BMVert *v_other = BM_edge_other_vert(e, v_a);
- BLI_smallhash_insert(&visit, (uintptr_t)v_other, NULL);
+ BLI_assert(!BM_ELEM_API_FLAG_TEST(v_other, VERT_VISIT));
+ BM_ELEM_API_FLAG_ENABLE(v_other, VERT_VISIT);
} while ((e = BM_DISK_EDGE_NEXT(e, v_a)) != e_first);
+ /* check 'v_b' connects to 'v_a' edges */
e = e_first = v_b->e;
do {
BMVert *v_other = BM_edge_other_vert(e, v_b);
- if (BLI_smallhash_haskey(&visit, (uintptr_t)v_other)) {
+ if (BM_ELEM_API_FLAG_TEST(v_other, VERT_VISIT)) {
is_double = true;
break;
}
} while ((e = BM_DISK_EDGE_NEXT(e, v_b)) != e_first);
- BLI_smallhash_release(&visit);
+ /* cleanup */
+ e = e_first = v_a->e;
+ do {
+ BMVert *v_other = BM_edge_other_vert(e, v_a);
+ BLI_assert(BM_ELEM_API_FLAG_TEST(v_other, VERT_VISIT));
+ BM_ELEM_API_FLAG_DISABLE(v_other, VERT_VISIT);
+ } while ((e = BM_DISK_EDGE_NEXT(e, v_a)) != e_first);
+
+#undef VERT_VISIT
+
}
return is_double;
@@ -1992,7 +2011,8 @@ bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b)
/**
* \brief Splice Vert
*
- * Merges two verts into one (\a v into \a vtarget).
+ * Merges two verts into one
+ * (\a v_src into \a v_dst, removing \a v_src).
*
* \return Success
*
@@ -2000,49 +2020,42 @@ bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b)
* where \a v and \a vtarget are connected by an edge
* (assert checks for this case).
*/
-bool BM_vert_splice(BMesh *bm, BMVert *v, BMVert *v_target)
+bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
{
BMEdge *e;
/* verts already spliced */
- if (v == v_target) {
+ if (v_src == v_dst) {
return false;
}
- BLI_assert(BM_vert_pair_share_face_check(v, v_target) == false);
-
- /* move all the edges from v's disk to vtarget's disk */
- while ((e = v->e)) {
+ BLI_assert(BM_vert_pair_share_face_check(v_src, v_dst) == false);
- /* loop */
- BMLoop *l_first;
- if ((l_first = e->l)) {
- BMLoop *l_iter = l_first;
- do {
- if (l_iter->v == v) {
- l_iter->v = v_target;
- }
- /* else if (l_iter->prev->v == v) {...}
- * (this case will be handled by a different edge) */
- } while ((l_iter = l_iter->radial_next) != l_first);
- }
-
- /* disk */
- bmesh_disk_edge_remove(e, v);
- bmesh_edge_swapverts(e, v, v_target);
- bmesh_disk_edge_append(e, v_target);
+ /* move all the edges from 'v_src' disk to 'v_dst' */
+ while ((e = v_src->e)) {
+ bmesh_edge_vert_swap(e, v_dst, v_src);
BLI_assert(e->v1 != e->v2);
}
- BM_CHECK_ELEMENT(v);
- BM_CHECK_ELEMENT(v_target);
+ BM_CHECK_ELEMENT(v_src);
+ BM_CHECK_ELEMENT(v_dst);
- /* v is unused now, and can be killed */
- BM_vert_kill(bm, v);
+ /* 'v_src' is unused now, and can be killed */
+ BM_vert_kill(bm, v_src);
return true;
}
+
+/** \name BM_vert_separate, bmesh_vert_separate and friends
+ * \{ */
+
+/* BM_edge_face_count(e) >= 1 */
+BLI_INLINE bool bm_edge_supports_separate(const BMEdge *e)
+{
+ return (e->l && e->l->radial_next != e->l);
+}
+
/**
* \brief Separate Vert
*
@@ -2054,167 +2067,252 @@ bool BM_vert_splice(BMesh *bm, BMVert *v, BMVert *v_target)
*
* \return Success
*/
-void bmesh_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
- const bool copy_select)
+void bmesh_vert_separate(
+ BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
+ const bool copy_select)
{
- const int v_edgetot = BM_vert_face_count(v);
- BMEdge **stack = BLI_array_alloca(stack, v_edgetot);
- STACK_DECLARE(stack);
+ int v_edges_num = 0;
- SmallHash visithash;
- BMVert **verts = NULL;
- BMIter eiter, liter;
- BMLoop *l;
- BMEdge *e;
- int i, maxindex;
- BMLoop *l_new;
+ /* Detailed notes on array use since this is stack memory, we have to be careful */
- BLI_smallhash_init_ex(&visithash, v_edgetot);
+ /* newly created vertices, only use when 'r_vout' is set
+ * (total size will be number of fans) */
+ BLI_SMALLSTACK_DECLARE(verts_new, BMVert *);
+ /* fill with edges from the face-fan, clearing on completion
+ * (total size will be max fan edge count) */
+ BLI_SMALLSTACK_DECLARE(edges, BMEdge *);
+ /* temp store edges to walk over when filling 'edges',
+ * (total size will be max radial edges of any edge) */
+ BLI_SMALLSTACK_DECLARE(edges_search, BMEdge *);
- STACK_INIT(stack, v_edgetot);
+ /* number of resulting verts, include self */
+ int verts_num = 1;
+ /* track the total number of edges handled, so we know when we've found the last fan */
+ int edges_found = 0;
- maxindex = 0;
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (BLI_smallhash_haskey(&visithash, (uintptr_t)e)) {
- continue;
- }
+#define EDGE_VISIT _FLAG_WALK
+
+ /* count and flag at once */
+ if (v->e) {
+ BMEdge *e_first, *e_iter;
+ e_iter = e_first = v->e;
+ do {
+ v_edges_num += 1;
+
+ BLI_assert(!BM_ELEM_API_FLAG_TEST(e_iter, EDGE_VISIT));
+ BM_ELEM_API_FLAG_ENABLE(e_iter, EDGE_VISIT);
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
+ }
+ while (true) {
/* Considering only edges and faces incident on vertex v, walk
- * the edges & faces and assign an index to each connected set */
- BLI_smallhash_insert(&visithash, (uintptr_t)e, SET_INT_IN_POINTER(maxindex));
+ * the edges & collect in the 'edges' list for splitting */
+
+ BMEdge *e = v->e;
+ BM_ELEM_API_FLAG_DISABLE(e, EDGE_VISIT);
+
do {
+ BLI_assert(!BM_ELEM_API_FLAG_TEST(e, EDGE_VISIT));
+ BLI_SMALLSTACK_PUSH(edges, e);
+ edges_found += 1;
+
if (e->l) {
BMLoop *l_iter, *l_first;
l_iter = l_first = e->l;
do {
- l_new = (l_iter->v == v) ? l_iter->prev : l_iter->next;
- BLI_assert(BM_vert_in_edge(l_new->e, v));
- if (!BLI_smallhash_haskey(&visithash, (uintptr_t)l_new->e)) {
- BLI_smallhash_insert(&visithash, (uintptr_t)l_new->e, SET_INT_IN_POINTER(maxindex));
- STACK_PUSH(stack, l_new->e);
+ BMLoop *l_adjacent = (l_iter->v == v) ? l_iter->prev : l_iter->next;
+ BLI_assert(BM_vert_in_edge(l_adjacent->e, v));
+ if (BM_ELEM_API_FLAG_TEST(l_adjacent->e, EDGE_VISIT)) {
+ BM_ELEM_API_FLAG_DISABLE(l_adjacent->e, EDGE_VISIT);
+ BLI_SMALLSTACK_PUSH(edges_search, l_adjacent->e);
}
} while ((l_iter = l_iter->radial_next) != l_first);
}
- } while ((e = STACK_POP(stack)));
+ } while ((e = BLI_SMALLSTACK_POP(edges_search)));
- maxindex++;
- }
-
- /* Make enough verts to split v for each group */
- if (r_vout != NULL) {
- verts = MEM_callocN(sizeof(BMVert *) * maxindex, __func__);
- }
- else {
- verts = BLI_array_alloca(verts, maxindex);
- }
+ /* now we have all edges connected to 'v->e' */
- verts[0] = v;
- for (i = 1; i < maxindex; i++) {
- verts[i] = BM_vert_create(bm, v->co, v, BM_CREATE_NOP);
- if (copy_select) {
- BM_elem_select_copy(bm, bm, verts[i], v);
- }
- }
+ BLI_assert(edges_found <= v_edges_num);
- /* Replace v with the new verts in each group */
-#if 0
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- /* call first since its faster then a hash lookup */
- if (l->v != v) {
- continue;
- }
- i = GET_INT_FROM_POINTER(BLI_ghash_lookup(visithash, l->e));
- if (i == 0) {
- continue;
+ if (edges_found == v_edges_num) {
+ /* We're done! The remaining edges in 'edges' form the last fan,
+ * which can be left as is.
+ * if 'edges' were alloc'd it'd be freed here. */
+ break;
}
+ else {
+ BMVert *v_new;
- /* Loops here should always refer to an edge that has v as an
- * endpoint. For each appearance of this vert in a face, there
- * will actually be two iterations: one for the loop heading
- * towards vertex v, and another for the loop heading out from
- * vertex v. Only need to swap the vertex on one of those times,
- * on the outgoing loop. */
+ v_new = BM_vert_create(bm, v->co, v, BM_CREATE_NOP);
+ if (copy_select) {
+ BM_elem_select_copy(bm, bm, v_new, v);
+ }
- /* XXX - because this clobbers the iterator, this *whole* block is commented, see below */
- l->v = verts[i];
- }
-#else
- /* note: this is the same as the commented code above *except* that it doesn't break iterator
- * by modifying data it loops over [#30632], this re-uses the 'stack' variable which is a bit
- * bad practice but save alloc'ing a new array - note, the comment above is useful, keep it
- * if you are tidying up code - campbell */
- STACK_INIT(stack, v_edgetot);
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- if (l->v == v) {
- STACK_PUSH(stack, (BMEdge *)l);
- }
- }
- while ((l = (BMLoop *)(STACK_POP(stack)))) {
- if ((i = GET_INT_FROM_POINTER(BLI_smallhash_lookup(&visithash, (uintptr_t)l->e)))) {
- l->v = verts[i];
- }
- }
-#endif
+ while ((e = BLI_SMALLSTACK_POP(edges))) {
+ bmesh_edge_vert_swap(e, v_new, v);
+ }
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- i = GET_INT_FROM_POINTER(BLI_smallhash_lookup(&visithash, (uintptr_t)e));
- if (i == 0) {
- continue;
+ if (r_vout) {
+ BLI_SMALLSTACK_PUSH(verts_new, v_new);
+ }
+ verts_num += 1;
}
-
- BLI_assert(e->v1 == v || e->v2 == v);
- bmesh_disk_edge_remove(e, v);
- bmesh_edge_swapverts(e, v, verts[i]);
- bmesh_disk_edge_append(e, verts[i]);
}
- BLI_smallhash_release(&visithash);
+#undef EDGE_VISIT
- for (i = 0; i < maxindex; i++) {
- BM_CHECK_ELEMENT(verts[i]);
- }
+ /* flags are clean now, handle return values */
if (r_vout_len != NULL) {
- *r_vout_len = maxindex;
+ *r_vout_len = verts_num;
}
if (r_vout != NULL) {
+ BMVert **verts;
+
+ verts = MEM_mallocN(sizeof(BMVert *) * verts_num, __func__);
*r_vout = verts;
+
+ verts[0] = v;
+ BLI_SMALLSTACK_AS_TABLE(verts_new, &verts[1]);
}
}
/**
+ * Utility function for #BM_vert_separate
+ *
+ * Takes a list of edges, which have been split from their original.
+ *
+ * Any edges which failed to split off in #bmesh_vert_separate will be merged back into the original edge.
+ *
+ * \param edges_separate
+ * A list-of-lists, each list is from a single original edge (the first edge is the original),
+ * Check for duplicates (not just with the first) but between all.
+ * This is O(n2) but radial edges are very rarely >2 and almost never >~10.
+ *
+ * \note typically its best to avoid creating the data in the first place,
+ * but inspecting all loops connectivity is quite involved.
+ *
+ * \note this function looks like it could become slow,
+ * but in common cases its only going to iterate a few times.
+ */
+static void bmesh_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separate)
+{
+ do {
+ LinkNode *n_orig = edges_separate->link;
+ do {
+ BMEdge *e_orig = n_orig->link;
+ LinkNode *n_step = n_orig->next;
+ LinkNode *n_prev = n_orig;
+ do {
+ BMEdge *e = n_step->link;
+ BLI_assert(e != e_orig);
+ if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2)) {
+ BM_edge_splice(bm, e_orig, e);
+ n_prev->next = n_step->next;
+ n_step = n_prev;
+ }
+ } while ((n_prev = n_step),
+ (n_step = n_step->next));
+
+ } while ((n_orig = n_orig->next) && n_orig->next);
+ } while ((edges_separate = edges_separate->next));
+}
+
+/**
* High level function which wraps both #bmesh_vert_separate and #bmesh_edge_separate
*/
-void BM_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
- BMEdge **e_in, int e_in_len)
+void BM_vert_separate(
+ BMesh *bm, BMVert *v,
+ BMEdge **e_in, int e_in_len,
+ const bool copy_select,
+ BMVert ***r_vout, int *r_vout_len)
{
+ LinkNode *edges_separate = NULL;
int i;
for (i = 0; i < e_in_len; i++) {
BMEdge *e = e_in[i];
- if (e->l && BM_vert_in_edge(e, v)) {
- bmesh_edge_separate(bm, e, e->l, false);
+ if (bm_edge_supports_separate(e)) {
+ LinkNode *edges_orig = NULL;
+ do {
+ BMLoop *l_sep = e->l;
+ bmesh_edge_separate(bm, e, l_sep, copy_select);
+ BLI_linklist_prepend_alloca(&edges_orig, l_sep->e);
+ BLI_assert(e != l_sep->e);
+ } while (bm_edge_supports_separate(e));
+ BLI_linklist_prepend_alloca(&edges_orig, e);
+ BLI_linklist_prepend_alloca(&edges_separate, edges_orig);
}
}
- bmesh_vert_separate(bm, v, r_vout, r_vout_len, false);
+ bmesh_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
+
+ if (edges_separate) {
+ bmesh_vert_separate__cleanup(bm, edges_separate);
+ }
+}
+
+
+/**
+ * A version of #BM_vert_separate which takes a flag.
+ */
+void BM_vert_separate_hflag(
+ BMesh *bm, BMVert *v,
+ const char hflag,
+ const bool copy_select,
+ BMVert ***r_vout, int *r_vout_len)
+{
+ LinkNode *edges_separate = NULL;
+ BMEdge *e_iter, *e_first;
+
+ e_iter = e_first = v->e;
+ do {
+ if (BM_elem_flag_test(e_iter, hflag)) {
+ BMEdge *e = e_iter;
+ if (bm_edge_supports_separate(e)) {
+ LinkNode *edges_orig = NULL;
+ do {
+ BMLoop *l_sep = e->l;
+ bmesh_edge_separate(bm, e, l_sep, copy_select);
+ /* trick to avoid looping over seperated edges */
+ if (edges_separate == NULL && edges_orig == NULL) {
+ e_first = l_sep->e;
+ }
+ BLI_linklist_prepend_alloca(&edges_orig, l_sep->e);
+ BLI_assert(e != l_sep->e);
+ } while (bm_edge_supports_separate(e));
+ BLI_linklist_prepend_alloca(&edges_orig, e);
+ BLI_linklist_prepend_alloca(&edges_separate, edges_orig);
+ }
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
+
+ bmesh_vert_separate(bm, v, r_vout, r_vout_len, copy_select);
+
+ if (edges_separate) {
+ bmesh_vert_separate__cleanup(bm, edges_separate);
+ }
}
+/** \} */
+
+
/**
* \brief Splice Edge
*
* Splice two unique edges which share the same two vertices into one edge.
+ * (\a e_src into \a e_dst, removing e_src).
*
* \return Success
*
* \note Edges must already have the same vertices.
*/
-bool BM_edge_splice(BMesh *bm, BMEdge *e, BMEdge *e_target)
+bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
{
BMLoop *l;
- if (!BM_vert_in_edge(e, e_target->v1) || !BM_vert_in_edge(e, e_target->v2)) {
+ if (!BM_vert_in_edge(e_src, e_dst->v1) || !BM_vert_in_edge(e_src, e_dst->v2)) {
/* not the same vertices can't splice */
/* the caller should really make sure this doesn't happen ever
@@ -2224,21 +2322,21 @@ bool BM_edge_splice(BMesh *bm, BMEdge *e, BMEdge *e_target)
return false;
}
- while (e->l) {
- l = e->l;
- BLI_assert(BM_vert_in_edge(e_target, l->v));
- BLI_assert(BM_vert_in_edge(e_target, l->next->v));
- bmesh_radial_loop_remove(l, e);
- bmesh_radial_append(e_target, l);
+ while (e_src->l) {
+ l = e_src->l;
+ BLI_assert(BM_vert_in_edge(e_dst, l->v));
+ BLI_assert(BM_vert_in_edge(e_dst, l->next->v));
+ bmesh_radial_loop_remove(l, e_src);
+ bmesh_radial_append(e_dst, l);
}
- BLI_assert(bmesh_radial_length(e->l) == 0);
+ BLI_assert(bmesh_radial_length(e_src->l) == 0);
- BM_CHECK_ELEMENT(e);
- BM_CHECK_ELEMENT(e_target);
+ BM_CHECK_ELEMENT(e_src);
+ BM_CHECK_ELEMENT(e_dst);
/* removes from disks too */
- BM_edge_kill(bm, e);
+ BM_edge_kill(bm, e_src);
return true;
}
@@ -2254,8 +2352,9 @@ bool BM_edge_splice(BMesh *bm, BMEdge *e, BMEdge *e_target)
* \note Does nothing if \a l_sep is already the only loop in the
* edge radial.
*/
-void bmesh_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep,
- const bool copy_select)
+void bmesh_edge_separate(
+ BMesh *bm, BMEdge *e, BMLoop *l_sep,
+ const bool copy_select)
{
BMEdge *e_new;
#ifndef NDEBUG
@@ -2266,7 +2365,7 @@ void bmesh_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep,
BLI_assert(e->l);
if (BM_edge_is_boundary(e)) {
- /* no cut required */
+ BLI_assert(0); /* no cut required */
return;
}
@@ -2299,72 +2398,245 @@ void bmesh_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep,
*/
BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep)
{
- BMVert **vtar;
- int len, i;
BMVert *v_new = NULL;
BMVert *v_sep = l_sep->v;
+ BMEdge *e_iter;
+ BMEdge *edges[2];
+ int i;
/* peel the face from the edge radials on both sides of the
* loop vert, disconnecting the face from its fan */
bmesh_edge_separate(bm, l_sep->e, l_sep, false);
bmesh_edge_separate(bm, l_sep->prev->e, l_sep->prev, false);
- if (bmesh_disk_count(v_sep) == 2) {
- /* If there are still only two edges out of v_sep, then
- * this whole URMV was just a no-op, so exit now. */
+ /* do inline, below */
+#if 0
+ if (BM_vert_edge_count_is_equal(v_sep, 2)) {
return v_sep;
}
+#endif
- /* Update the disk start, so that v->e points to an edge
- * not touching the split loop. This is so that BM_vert_split
- * will leave the original v_sep on some *other* fan (not the
- * one-face fan that holds the unglue face). */
- while (v_sep->e == l_sep->e || v_sep->e == l_sep->prev->e) {
- v_sep->e = bmesh_disk_edge_next(v_sep->e, v_sep);
+ /* Search for an edge unattached to this loop */
+ e_iter = v_sep->e;
+ while (!ELEM(e_iter, l_sep->e, l_sep->prev->e)) {
+ e_iter = bmesh_disk_edge_next(e_iter, v_sep);
+
+ /* We've come back around to the initial edge, all touch this loop.
+ * If there are still only two edges out of v_sep,
+ * then this whole URMV was just a no-op, so exit now. */
+ if (e_iter == v_sep->e) {
+ BLI_assert(BM_vert_edge_count_is_equal(v_sep, 2));
+ return v_sep;
+ }
}
- /* Split all fans connected to the vert, duplicating it for
- * each fans. */
- bmesh_vert_separate(bm, v_sep, &vtar, &len, false);
+ v_sep->e = l_sep->e;
- /* There should have been at least two fans cut apart here,
- * otherwise the early exit would have kicked in. */
- BLI_assert(len >= 2);
+ v_new = BM_vert_create(bm, v_sep->co, v_sep, BM_CREATE_NOP);
- v_new = l_sep->v;
+ edges[0] = l_sep->e;
+ edges[1] = l_sep->prev->e;
- /* Desired result here is that a new vert should always be
- * created for the unglue face. This is so we can glue any
- * extras back into the original vert. */
- BLI_assert(v_new != v_sep);
- BLI_assert(v_sep == vtar[0]);
+ for (i = 0; i < ARRAY_SIZE(edges); i++) {
+ BMEdge *e = edges[i];
+ bmesh_edge_vert_swap(e, v_new, v_sep);
+ }
- /* If there are more than two verts as a result, glue together
- * all the verts except the one this URMV intended to create */
- if (len > 2) {
- for (i = 0; i < len; i++) {
- if (vtar[i] == v_new) {
- break;
+ BLI_assert(v_sep != l_sep->v);
+ BLI_assert(v_sep->e != l_sep->v->e);
+
+ BM_CHECK_ELEMENT(l_sep);
+ BM_CHECK_ELEMENT(v_sep);
+ BM_CHECK_ELEMENT(edges[0]);
+ BM_CHECK_ELEMENT(edges[1]);
+ BM_CHECK_ELEMENT(v_new);
+
+ return v_new;
+}
+
+/**
+ * A version of #bmesh_urmv_loop that disconnects multiple loops at once.
+ *
+ * Handles the task of finding fans boundaris.
+ */
+BMVert *bmesh_urmv_loop_multi(
+ BMesh *bm, BMLoop **larr, int larr_len)
+{
+ BMVert *v_sep = larr[0]->v;
+ BMVert *v_new;
+ int i;
+ bool is_mixed_any = false;
+
+ BLI_SMALLSTACK_DECLARE(edges, BMEdge *);
+
+#define LOOP_VISIT _FLAG_WALK
+#define EDGE_VISIT _FLAG_WALK
+
+ for (i = 0; i < larr_len; i++) {
+ BMLoop *l_sep = larr[i];
+
+ /* all must be from the same vert! */
+ BLI_assert(v_sep == l_sep->v);
+
+ BLI_assert(!BM_ELEM_API_FLAG_TEST(l_sep, LOOP_VISIT));
+ BM_ELEM_API_FLAG_ENABLE(l_sep, LOOP_VISIT);
+
+ /* weak! but it makes it simpler to check for edges to split
+ * while doing a radial loop (where loops may be adjacent) */
+ BM_ELEM_API_FLAG_ENABLE(l_sep->next, LOOP_VISIT);
+ BM_ELEM_API_FLAG_ENABLE(l_sep->prev, LOOP_VISIT);
+ }
+
+ for (i = 0; i < larr_len; i++) {
+ BMLoop *l_sep = larr[i];
+
+ BMLoop *loop_pair[2] = {l_sep, l_sep->prev};
+ int j;
+ for (j = 0; j < ARRAY_SIZE(loop_pair); j++) {
+ BMEdge *e = loop_pair[j]->e;
+ if (!BM_ELEM_API_FLAG_TEST(e, EDGE_VISIT)) {
+ BMLoop *l_iter, *l_first;
+ bool is_mixed = false;
+
+ BM_ELEM_API_FLAG_ENABLE(e, EDGE_VISIT);
+
+ l_iter = l_first = e->l;
+ do {
+ if (!BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) {
+ is_mixed = true;
+ is_mixed_any = true;
+ break;
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+
+ if (is_mixed) {
+ /* ensure the first loop is one we don't own so we can do a quick check below
+ * on the edge's loop-flag to see if the edge is mixed or not. */
+ e->l = l_iter;
+ }
+ BLI_SMALLSTACK_PUSH(edges, e);
}
}
+ }
+
+ if (is_mixed_any == false) {
+ /* all loops in 'larr' are the soul owners of their edges.
+ * nothing to split away from, this is a no-op */
+ v_new = v_sep;
+ }
+ else {
+ BMEdge *e;
+
+ BLI_assert(!BLI_SMALLSTACK_IS_EMPTY(edges));
+
+ v_new = BM_vert_create(bm, v_sep->co, v_sep, BM_CREATE_NOP);
+ while ((e = BLI_SMALLSTACK_POP(edges))) {
+ BMLoop *l_iter, *l_first, *l_next;
+ BMEdge *e_new;
+
+ /* disable so copied edge isn't left dirty (loop edges are cleared last too) */
+ BM_ELEM_API_FLAG_DISABLE(e, EDGE_VISIT);
+
+ if (!BM_ELEM_API_FLAG_TEST(e->l, LOOP_VISIT)) {
+ /* edge has some loops owned by us, some owned by other loops */
+ BMVert *e_new_v_pair[2];
- if (i != len) {
- /* Swap the single vert that was needed for the
- * unglue into the last array slot */
- SWAP(BMVert *, vtar[i], vtar[len - 1]);
+ if (e->v1 == v_sep) {
+ e_new_v_pair[0] = v_new;
+ e_new_v_pair[1] = e->v2;
+ }
+ else {
+ BLI_assert(v_sep == e->v2);
+ e_new_v_pair[0] = e->v1;
+ e_new_v_pair[1] = v_new;
+ }
- /* And then glue the rest back together */
- for (i = 1; i < len - 1; i++) {
- BM_vert_splice(bm, vtar[i], vtar[0]);
+ e_new = BM_edge_create(bm, UNPACK2(e_new_v_pair), e, BM_CREATE_NOP);
+
+ /* now moved all loops from 'larr' to this newly created edge */
+ l_iter = l_first = e->l;
+ do {
+ l_next = l_iter->radial_next;
+ if (BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) {
+ bmesh_radial_loop_remove(l_iter, e);
+ bmesh_radial_append(e_new, l_iter);
+ l_iter->e = e_new;
+ }
+ } while ((l_iter = l_next) != l_first);
+ }
+ else {
+ /* we own the edge entirely, replace the vert */
+ bmesh_disk_vert_replace(e, v_new, v_sep);
}
+
+ /* loop vert is handled last! */
}
}
- MEM_freeN(vtar);
+ for (i = 0; i < larr_len; i++) {
+ BMLoop *l_sep = larr[i];
+
+ l_sep->v = v_new;
+
+ BLI_assert(BM_ELEM_API_FLAG_TEST(l_sep, LOOP_VISIT));
+ BLI_assert(BM_ELEM_API_FLAG_TEST(l_sep->prev, LOOP_VISIT));
+ BLI_assert(BM_ELEM_API_FLAG_TEST(l_sep->next, LOOP_VISIT));
+ BM_ELEM_API_FLAG_DISABLE(l_sep, LOOP_VISIT);
+ BM_ELEM_API_FLAG_DISABLE(l_sep->prev, LOOP_VISIT);
+ BM_ELEM_API_FLAG_DISABLE(l_sep->next, LOOP_VISIT);
+
+
+ BM_ELEM_API_FLAG_DISABLE(l_sep->prev->e, EDGE_VISIT);
+ BM_ELEM_API_FLAG_DISABLE(l_sep->e, EDGE_VISIT);
+ }
+
+#undef LOOP_VISIT
+#undef EDGE_VISIT
+
+ return v_new;
+}
+
+static void bmesh_edge_vert_swap__recursive(BMEdge *e, BMVert *v_dst, BMVert *v_src)
+{
+ BMLoop *l_iter, *l_first;
+
+ BLI_assert(ELEM(v_src, e->v1, e->v2));
+ bmesh_disk_vert_replace(e, v_dst, v_src);
+
+ l_iter = l_first = e->l;
+ do {
+ if (l_iter->v == v_src) {
+ l_iter->v = v_dst;
+ if (BM_vert_in_edge(l_iter->prev->e, v_src)) {
+ bmesh_edge_vert_swap__recursive(l_iter->prev->e, v_dst, v_src);
+ }
+ }
+ else if (l_iter->next->v == v_src) {
+ l_iter->next->v = v_dst;
+ if (BM_vert_in_edge(l_iter->next->e, v_src)) {
+ bmesh_edge_vert_swap__recursive(l_iter->next->e, v_dst, v_src);
+ }
+ }
+ else {
+ BLI_assert(l_iter->prev->v != v_src);
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+}
+/**
+ * This function assumes l_sep is apart of a larger fan which has already been
+ * isolated by calling bmesh_edge_separate to segregate it radially.
+ */
+BMVert *bmesh_urmv_loop_region(BMesh *bm, BMLoop *l_sep)
+{
+ BMVert *v_new = BM_vert_create(bm, l_sep->v->co, l_sep->v, BM_CREATE_NOP);
+ /* passing either 'l_sep->e', 'l_sep->prev->e' will work */
+ bmesh_edge_vert_swap__recursive(l_sep->e, v_new, l_sep->v);
+ BLI_assert(l_sep->v == v_new);
return v_new;
}
+
/**
* \brief Unglue Region Make Vert (URMV)
*
diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h
index ab847fc82eb..2b100eb7b8d 100644
--- a/source/blender/bmesh/intern/bmesh_core.h
+++ b/source/blender/bmesh/intern/bmesh_core.h
@@ -27,8 +27,9 @@
* \ingroup bmesh
*/
-BMFace *BM_face_copy(BMesh *bm_dst, BMesh *bm_src, BMFace *f,
- const bool copy_verts, const bool copy_edges);
+BMFace *BM_face_copy(
+ BMesh *bm_dst, BMesh *bm_src, BMFace *f,
+ const bool copy_verts, const bool copy_edges);
typedef enum eBMCreateFlag {
BM_CREATE_NOP = 0,
@@ -40,15 +41,19 @@ typedef enum eBMCreateFlag {
BM_CREATE_SKIP_CD = (1 << 2),
} eBMCreateFlag;
-BMVert *BM_vert_create(BMesh *bm, const float co[3],
- const BMVert *v_example, const eBMCreateFlag create_flag);
-BMEdge *BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2,
- const BMEdge *e_example, const eBMCreateFlag create_flag);
-BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len,
- const BMFace *f_example, const eBMCreateFlag create_flag);
-BMFace *BM_face_create_verts(BMesh *bm, BMVert **verts, const int len,
- const BMFace *f_example, const eBMCreateFlag create_flag,
- const bool create_edges);
+BMVert *BM_vert_create(
+ BMesh *bm, const float co[3],
+ const BMVert *v_example, const eBMCreateFlag create_flag);
+BMEdge *BM_edge_create(
+ BMesh *bm, BMVert *v1, BMVert *v2,
+ const BMEdge *e_example, const eBMCreateFlag create_flag);
+BMFace *BM_face_create(
+ BMesh *bm, BMVert **verts, BMEdge **edges, const int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag);
+BMFace *BM_face_create_verts(
+ BMesh *bm, BMVert **verts, const int len,
+ const BMFace *f_example, const eBMCreateFlag create_flag,
+ const bool create_edges);
void BM_face_edges_kill(BMesh *bm, BMFace *f);
void BM_face_verts_kill(BMesh *bm, BMFace *f);
@@ -57,25 +62,32 @@ void BM_face_kill(BMesh *bm, BMFace *f);
void BM_edge_kill(BMesh *bm, BMEdge *e);
void BM_vert_kill(BMesh *bm, BMVert *v);
-void bmesh_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep,
- const bool copy_select);
-bool BM_edge_splice(BMesh *bm, BMEdge *e, BMEdge *e_target);
-bool BM_vert_splice(BMesh *bm, BMVert *v, BMVert *v_target);
+void bmesh_edge_separate(
+ BMesh *bm, BMEdge *e, BMLoop *l_sep,
+ const bool copy_select);
+bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src);
+bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src);
bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b);
-void bmesh_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
- const bool copy_select);
+void bmesh_vert_separate(
+ BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
+ const bool copy_select);
bool bmesh_loop_reverse(BMesh *bm, BMFace *f);
BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del);
-void BM_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
- BMEdge **e_in, int e_in_len);
+void BM_vert_separate(
+ BMesh *bm, BMVert *v, BMEdge **e_in, int e_in_len, const bool copy_select,
+ BMVert ***r_vout, int *r_vout_len);
+void BM_vert_separate_hflag(
+ BMesh *bm, BMVert *v, const char hflag, const bool copy_select,
+ BMVert ***r_vout, int *r_vout_len);
/* EULER API - For modifying structure */
-BMFace *bmesh_sfme(BMesh *bm, BMFace *f,
- BMLoop *l1, BMLoop *l2,
- BMLoop **r_l,
+BMFace *bmesh_sfme(
+ BMesh *bm, BMFace *f,
+ BMLoop *l1, BMLoop *l2,
+ BMLoop **r_l,
#ifdef USE_BMESH_HOLES
ListBase *holes,
#endif
@@ -84,11 +96,15 @@ BMFace *bmesh_sfme(BMesh *bm, BMFace *f,
);
BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e);
-BMEdge *bmesh_jekv(BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
- const bool do_del, const bool check_edge_splice);
+BMEdge *bmesh_jekv(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
+ const bool do_del, const bool check_edge_splice);
BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e);
BMVert *bmesh_urmv(BMesh *bm, BMFace *f_sep, BMVert *v_sep);
BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep);
+BMVert *bmesh_urmv_loop_multi(
+ BMesh *bm, BMLoop **larr, int larr_len);
+BMVert *bmesh_urmv_loop_region(BMesh *bm, BMLoop *l_sep);
void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b);
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c
index aa1f511e8d7..eaa070151a6 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.c
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.c
@@ -52,8 +52,9 @@ typedef struct BMEdgeLoopStore {
/* -------------------------------------------------------------------- */
/* BM_mesh_edgeloops_find & Util Functions */
-static int bm_vert_other_tag(BMVert *v, BMVert *v_prev,
- BMEdge **r_e)
+static int bm_vert_other_tag(
+ BMVert *v, BMVert *v_prev,
+ BMEdge **r_e)
{
BMIter iter;
BMEdge *e, *e_next = NULL;
@@ -125,8 +126,9 @@ static bool bm_loop_build(BMEdgeLoopStore *el_store, BMVert *v_prev, BMVert *v,
/**
* \return listbase of listbases, each linking to a vertex.
*/
-int BM_mesh_edgeloops_find(BMesh *bm, ListBase *r_eloops,
- bool (*test_fn)(BMEdge *, void *user_data), void *user_data)
+int BM_mesh_edgeloops_find(
+ BMesh *bm, ListBase *r_eloops,
+ bool (*test_fn)(BMEdge *, void *user_data), void *user_data)
{
BMIter iter;
BMEdge *e;
@@ -183,8 +185,9 @@ struct VertStep {
BMVert *v;
};
-static void vs_add(BLI_mempool *vs_pool, ListBase *lb,
- BMVert *v, BMEdge *e_prev, const int iter_tot)
+static void vs_add(
+ BLI_mempool *vs_pool, ListBase *lb,
+ BMVert *v, BMEdge *e_prev, const int iter_tot)
{
struct VertStep *vs_new = BLI_mempool_alloc(vs_pool);
vs_new->v = v;
@@ -256,9 +259,10 @@ static bool bm_loop_path_build_step(BLI_mempool *vs_pool, ListBase *lb, const in
return (BLI_listbase_is_empty(lb) == false);
}
-bool BM_mesh_edgeloops_find_path(BMesh *bm, ListBase *r_eloops,
- bool (*test_fn)(BMEdge *, void *user_data), void *user_data,
- BMVert *v_src, BMVert *v_dst)
+bool BM_mesh_edgeloops_find_path(
+ BMesh *bm, ListBase *r_eloops,
+ bool (*test_fn)(BMEdge *, void *user_data), void *user_data,
+ BMVert *v_src, BMVert *v_dst)
{
BMIter iter;
BMEdge *e;
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.h b/source/blender/bmesh/intern/bmesh_edgeloop.h
index 527dba120e1..5df4ee5848e 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.h
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.h
@@ -32,17 +32,20 @@ struct ListBase;
struct BMEdgeLoopStore;
/* multiple edgeloops (ListBase) */
-int BM_mesh_edgeloops_find(BMesh *bm, struct ListBase *r_lb,
- bool (*test_fn)(BMEdge *, void *user_data), void *user_data);
-bool BM_mesh_edgeloops_find_path(BMesh *bm, ListBase *r_eloops,
- bool (*test_fn)(BMEdge *, void *user_data), void *user_data,
- BMVert *v_src, BMVert *v_dst);
+int BM_mesh_edgeloops_find(
+ BMesh *bm, struct ListBase *r_lb,
+ bool (*test_fn)(BMEdge *, void *user_data), void *user_data);
+bool BM_mesh_edgeloops_find_path(
+ BMesh *bm, ListBase *r_eloops,
+ bool (*test_fn)(BMEdge *, void *user_data), void *user_data,
+ BMVert *v_src, BMVert *v_dst);
void BM_mesh_edgeloops_free(struct ListBase *eloops);
void BM_mesh_edgeloops_calc_center(BMesh *bm, struct ListBase *eloops);
void BM_mesh_edgeloops_calc_normal(BMesh *bm, struct ListBase *eloops);
-void BM_mesh_edgeloops_calc_normal_aligned(BMesh *bm, struct ListBase *eloops,
- const float no_align[3]);
+void BM_mesh_edgeloops_calc_normal_aligned(
+ BMesh *bm, struct ListBase *eloops,
+ const float no_align[3]);
void BM_mesh_edgeloops_calc_order(BMesh *UNUSED(bm), ListBase *eloops, const bool use_normals);
@@ -59,8 +62,9 @@ const float *BM_edgeloop_center_get(struct BMEdgeLoopStore *el_store);
void BM_edgeloop_edges_get(struct BMEdgeLoopStore *el_store, BMEdge **e_arr);
void BM_edgeloop_calc_center(BMesh *bm, struct BMEdgeLoopStore *el_store);
bool BM_edgeloop_calc_normal(BMesh *bm, struct BMEdgeLoopStore *el_store);
-bool BM_edgeloop_calc_normal_aligned(BMesh *bm, struct BMEdgeLoopStore *el_store,
- const float no_align[3]);
+bool BM_edgeloop_calc_normal_aligned(
+ BMesh *bm, struct BMEdgeLoopStore *el_store,
+ const float no_align[3]);
void BM_edgeloop_flip(BMesh *bm, struct BMEdgeLoopStore *el_store);
void BM_edgeloop_expand(BMesh *bm, struct BMEdgeLoopStore *el_store, int el_store_len);
diff --git a/source/blender/bmesh/intern/bmesh_inline.h b/source/blender/bmesh/intern/bmesh_inline.h
index 96b2cd396a2..4b55060875b 100644
--- a/source/blender/bmesh/intern/bmesh_inline.h
+++ b/source/blender/bmesh/intern/bmesh_inline.h
@@ -39,11 +39,13 @@
#define BM_elem_flag_merge( ele_a, ele_b) _bm_elem_flag_merge (&(ele_a)->head, &(ele_b)->head)
#define BM_elem_flag_merge_into(ele, ele_a, ele_b)_bm_elem_flag_merge_into (&(ele)->head, &(ele_a)->head, &(ele_b)->head)
+ATTR_WARN_UNUSED_RESULT
BLI_INLINE char _bm_elem_flag_test(const BMHeader *head, const char hflag)
{
return head->hflag & hflag;
}
+ATTR_WARN_UNUSED_RESULT
BLI_INLINE bool _bm_elem_flag_test_bool(const BMHeader *head, const char hflag)
{
return (head->hflag & hflag) != 0;
@@ -116,6 +118,7 @@ BLI_INLINE void _bm_elem_index_set(BMHeader *head, const int index)
head->index = index;
}
+ATTR_WARN_UNUSED_RESULT
BLI_INLINE int _bm_elem_index_get(const BMHeader *head)
{
return head->index;
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index f745972293e..81155bc017e 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -241,8 +241,9 @@ void BM_face_interp_from_face(BMesh *bm, BMFace *f_dst, const BMFace *f_src, con
* y
* </pre>
*/
-static int compute_mdisp_quad(BMLoop *l, float v1[3], float v2[3], float v3[3], float v4[3],
- float e1[3], float e2[3])
+static int compute_mdisp_quad(
+ BMLoop *l, float v1[3], float v2[3], float v3[3], float v4[3],
+ float e1[3], float e2[3])
{
float cent[3], n[3], p[3];
@@ -302,9 +303,10 @@ static float quad_coord(const float aa[3], const float bb[3], const float cc[3],
return f1;
}
-static int quad_co(float *x, float *y,
- const float v1[3], const float v2[3], const float v3[3], const float v4[3],
- const float p[3], const float n[3])
+static int quad_co(
+ float *r_x, float *r_y,
+ const float v1[3], const float v2[3], const float v3[3], const float v4[3],
+ const float p[3], const float n[3])
{
float projverts[5][3], n2[3];
float dprojverts[4][3], origin[3] = {0.0f, 0.0f, 0.0f};
@@ -340,14 +342,15 @@ static int quad_co(float *x, float *y,
return 0;
}
- *y = quad_coord(dprojverts[1], dprojverts[0], dprojverts[2], dprojverts[3], 0, 1);
- *x = quad_coord(dprojverts[2], dprojverts[1], dprojverts[3], dprojverts[0], 0, 1);
+ *r_y = quad_coord(dprojverts[1], dprojverts[0], dprojverts[2], dprojverts[3], 0, 1);
+ *r_x = quad_coord(dprojverts[2], dprojverts[1], dprojverts[3], dprojverts[0], 0, 1);
return 1;
}
-static void mdisp_axis_from_quad(float v1[3], float v2[3], float UNUSED(v3[3]), float v4[3],
- float axis_x[3], float axis_y[3])
+static void mdisp_axis_from_quad(
+ float v1[3], float v2[3], float UNUSED(v3[3]), float v4[3],
+ float axis_x[3], float axis_y[3])
{
sub_v3_v3v3(axis_x, v4, v1);
sub_v3_v3v3(axis_y, v2, v1);
@@ -358,8 +361,9 @@ static void mdisp_axis_from_quad(float v1[3], float v2[3], float UNUSED(v3[3]),
/* tl is loop to project onto, l is loop whose internal displacement, co, is being
* projected. x and y are location in loop's mdisps grid of point co. */
-static bool mdisp_in_mdispquad(BMLoop *l, BMLoop *tl, float p[3], float *x, float *y,
- int res, float axis_x[3], float axis_y[3])
+static bool mdisp_in_mdispquad(
+ BMLoop *l, BMLoop *tl, float p[3], float *x, float *y,
+ int res, float axis_x[3], float axis_y[3])
{
float v1[3], v2[3], c[3], v3[3], v4[3], e1[3], e2[3];
float eps = FLT_EPSILON * 4000;
@@ -392,8 +396,9 @@ static bool mdisp_in_mdispquad(BMLoop *l, BMLoop *tl, float p[3], float *x, floa
return 1;
}
-static float bm_loop_flip_equotion(float mat[2][2], float b[2], const float target_axis_x[3], const float target_axis_y[3],
- const float coord[3], int i, int j)
+static float bm_loop_flip_equotion(
+ float mat[2][2], float b[2], const float target_axis_x[3], const float target_axis_y[3],
+ const float coord[3], int i, int j)
{
mat[0][0] = target_axis_x[i];
mat[0][1] = target_axis_y[i];
@@ -405,8 +410,9 @@ static float bm_loop_flip_equotion(float mat[2][2], float b[2], const float targ
return mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0];
}
-static void bm_loop_flip_disp(const float source_axis_x[3], const float source_axis_y[3],
- const float target_axis_x[3], const float target_axis_y[3], float disp[3])
+static void bm_loop_flip_disp(
+ const float source_axis_x[3], const float source_axis_y[3],
+ const float target_axis_x[3], const float target_axis_y[3], float disp[3])
{
float vx[3], vy[3], coord[3];
float n[3], vec[3];
@@ -453,8 +459,8 @@ static void bm_loop_interp_mdisps(BMesh *bm, BMLoop *l_dst, const BMFace *f_src)
/* if no disps data allocate a new grid, the size of the first grid in f_src. */
if (!md_dst->totdisp) {
- MDisps *md_src = BM_ELEM_CD_GET_VOID_P(BM_FACE_FIRST_LOOP(f_src), cd_loop_mdisp_offset);
-
+ const MDisps *md_src = BM_ELEM_CD_GET_VOID_P(BM_FACE_FIRST_LOOP(f_src), cd_loop_mdisp_offset);
+
md_dst->totdisp = md_src->totdisp;
md_dst->level = md_src->level;
if (md_dst->totdisp) {
@@ -905,6 +911,34 @@ void BM_elem_float_data_set(CustomData *cd, void *element, int type, const float
if (f) *f = val;
}
+float BM_elem_float_data_named_get(CustomData *cd, void *element, int type, const char *name)
+{
+ const float *f = CustomData_bmesh_get_named(cd, ((BMHeader *)element)->data, type, name);
+ return f ? *f : 0.0f;
+}
+
+void BM_elem_float_data_named_set(CustomData *cd, void *element, int type, const char *name, const float val)
+{
+ float *f = CustomData_bmesh_get_named(cd, ((BMHeader *)element)->data, type, name);
+ if (f) *f = val;
+}
+
+void BM_elem_meshsample_data_named_get(CustomData *cd, void *element, int type, const char *name, MSurfaceSample *val)
+{
+ const MSurfaceSample *s = CustomData_bmesh_get_named(cd, ((BMHeader *)element)->data, type, name);
+ if (s)
+ memcpy(val, s, sizeof(MSurfaceSample));
+ else
+ memset(val, 0, sizeof(MSurfaceSample));
+}
+
+void BM_elem_meshsample_data_named_set(CustomData *cd, void *element, int type, const char *name, const MSurfaceSample *val)
+{
+ MSurfaceSample *s = CustomData_bmesh_get_named(cd, ((BMHeader *)element)->data, type, name);
+ if (s)
+ memcpy(s, val, sizeof(MSurfaceSample));
+}
+
/** \name Loop interpolation functions: BM_vert_loop_groups_data_layer_***
*
* Handling loop custom-data such as UV's, while keeping contiguous fans is rather tedious.
@@ -1051,7 +1085,7 @@ LinkNode *BM_vert_loop_groups_data_layer_create(
mul_vn_fl(lf->data_weights, lf->data_len, 1.0f / lwc.weight_accum);
}
else {
- fill_vn_fl(lf->data_weights, lf->data_len, 1.0f / (float)lf->data_len);
+ copy_vn_fl(lf->data_weights, lf->data_len, 1.0f / (float)lf->data_len);
}
BLI_linklist_prepend_arena(&groups, lf, lwc.arena);
diff --git a/source/blender/bmesh/intern/bmesh_interp.h b/source/blender/bmesh/intern/bmesh_interp.h
index 969e92f37db..6168a655c93 100644
--- a/source/blender/bmesh/intern/bmesh_interp.h
+++ b/source/blender/bmesh/intern/bmesh_interp.h
@@ -29,6 +29,8 @@
struct LinkNode;
struct MemArena;
+struct MSurfaceSample;
+
void BM_loop_interp_multires(BMesh *bm, BMLoop *l_dst, const BMFace *f_src);
void BM_vert_interp_from_face(BMesh *bm, BMVert *v_dst, const BMFace *f_src);
@@ -44,6 +46,10 @@ void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int d
float BM_elem_float_data_get(CustomData *cd, void *element, int type);
void BM_elem_float_data_set(CustomData *cd, void *element, int type, const float val);
+float BM_elem_float_data_named_get(CustomData *cd, void *element, int type, const char *name);
+void BM_elem_float_data_named_set(CustomData *cd, void *element, int type, const char *name, const float val);
+void BM_elem_meshsample_data_named_get(CustomData *cd, void *element, int type, const char *name, struct MSurfaceSample *val);
+void BM_elem_meshsample_data_named_set(CustomData *cd, void *element, int type, const char *name, const struct MSurfaceSample *val);
void BM_face_interp_from_face_ex(
BMesh *bm, BMFace *f_dst, const BMFace *f_src, const bool do_vertex,
diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c
index 4dc27d75a55..0abf41709a0 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.c
+++ b/source/blender/bmesh/intern/bmesh_iterators.c
@@ -136,8 +136,9 @@ int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, cons
*
* Sometimes its convenient to get the iterator as an array.
*/
-int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask,
- void **array, const int len)
+int BMO_iter_as_array(
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask,
+ void **array, const int len)
{
int i = 0;
@@ -169,9 +170,10 @@ int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_nam
*
* Caller needs to free the array.
*/
-void *BM_iter_as_arrayN(BMesh *bm, const char itype, void *data, int *r_len,
- /* optional args to avoid an alloc (normally stack array) */
- void **stack_array, int stack_array_size)
+void *BM_iter_as_arrayN(
+ BMesh *bm, const char itype, void *data, int *r_len,
+ /* optional args to avoid an alloc (normally stack array) */
+ void **stack_array, int stack_array_size)
{
BMIter iter;
@@ -212,10 +214,11 @@ void *BM_iter_as_arrayN(BMesh *bm, const char itype, void *data, int *r_len,
}
}
-void *BMO_iter_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask,
- int *r_len,
- /* optional args to avoid an alloc (normally stack array) */
- void **stack_array, int stack_array_size)
+void *BMO_iter_as_arrayN(
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask,
+ int *r_len,
+ /* optional args to avoid an alloc (normally stack array) */
+ void **stack_array, int stack_array_size)
{
BMOIter iter;
BMElem *ele;
@@ -273,8 +276,9 @@ int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, cons
*
* Counts how many flagged / unflagged items are found in this element.
*/
-int BMO_iter_elem_count_flag(BMesh *bm, const char itype, void *data,
- const short oflag, const bool value)
+int BMO_iter_elem_count_flag(
+ BMesh *bm, const char itype, void *data,
+ const short oflag, const bool value)
{
BMIter iter;
BMElemF *ele;
diff --git a/source/blender/bmesh/intern/bmesh_iterators.h b/source/blender/bmesh/intern/bmesh_iterators.h
index 49e511bdcb5..c4b184ef8b8 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.h
+++ b/source/blender/bmesh/intern/bmesh_iterators.h
@@ -197,14 +197,17 @@ typedef struct BMIter {
void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index) ATTR_WARN_UNUSED_RESULT;
int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len);
-void *BM_iter_as_arrayN(BMesh *bm, const char itype, void *data, int *r_len,
- void **stack_array, int stack_array_size) ATTR_WARN_UNUSED_RESULT;
-int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask,
- void **array, const int len);
-void *BMO_iter_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask,
- int *r_len,
- /* optional args to avoid an alloc (normally stack array) */
- void **stack_array, int stack_array_size);
+void *BM_iter_as_arrayN(
+ BMesh *bm, const char itype, void *data, int *r_len,
+ void **stack_array, int stack_array_size) ATTR_WARN_UNUSED_RESULT;
+int BMO_iter_as_array(
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask,
+ void **array, const int len);
+void *BMO_iter_as_arrayN(
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask,
+ int *r_len,
+ /* optional args to avoid an alloc (normally stack array) */
+ void **stack_array, int stack_array_size);
int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value);
int BMO_iter_elem_count_flag(BMesh *bm, const char itype, void *data, const short oflag, const bool value);
int BM_iter_mesh_count(const char itype, BMesh *bm);
diff --git a/source/blender/bmesh/intern/bmesh_iterators_inline.h b/source/blender/bmesh/intern/bmesh_iterators_inline.h
index d3e18b97acb..43b054d7845 100644
--- a/source/blender/bmesh/intern/bmesh_iterators_inline.h
+++ b/source/blender/bmesh/intern/bmesh_iterators_inline.h
@@ -29,6 +29,8 @@
#ifndef __BMESH_ITERATORS_INLINE_H__
#define __BMESH_ITERATORS_INLINE_H__
+#include "BLI_mempool.h"
+
/* inline here optimizes out the switch statement when called with
* constant values (which is very common), nicer for loop-in-loop situations */
@@ -37,12 +39,12 @@
*
* Calls an iterators step function to return the next element.
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE void *BM_iter_step(BMIter *iter)
{
return iter->step(iter);
}
-
/**
* \brief Iterator Init
*
@@ -50,6 +52,7 @@ BLI_INLINE void *BM_iter_step(BMIter *iter)
* it with the appropriate function pointers based
* upon its type.
*/
+ATTR_NONNULL(1)
BLI_INLINE bool BM_iter_init(BMIter *iter, BMesh *bm, const char itype, void *data)
{
/* int argtype; */
@@ -169,6 +172,7 @@ BLI_INLINE bool BM_iter_init(BMIter *iter, BMesh *bm, const char itype, void *da
* to return the first element of the iterator.
*
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE void *BM_iter_new(BMIter *iter, BMesh *bm, const char itype, void *data)
{
if (LIKELY(BM_iter_init(iter, bm, itype, data))) {
diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c
index 158c2aa4263..1f64f7b74cc 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -115,8 +115,8 @@ struct BMLog {
typedef struct {
float co[3];
short no[3];
- float mask;
char hflag;
+ float mask;
} BMLogVert;
typedef struct {
@@ -126,6 +126,10 @@ typedef struct {
/************************* Get/set element IDs ************************/
+/* bypass actual hashing, the keys don't overlap */
+#define logkey_hash BLI_ghashutil_inthash_p_simple
+#define logkey_cmp BLI_ghashutil_intcmp
+
/* Get the vertex's unique ID from the log */
static unsigned int bm_log_vert_id_get(BMLog *log, BMVert *v)
{
@@ -386,12 +390,12 @@ static BMLogEntry *bm_log_entry_create(void)
{
BMLogEntry *entry = MEM_callocN(sizeof(BMLogEntry), __func__);
- entry->deleted_verts = BLI_ghash_ptr_new(__func__);
- entry->deleted_faces = BLI_ghash_ptr_new(__func__);
- entry->added_verts = BLI_ghash_ptr_new(__func__);
- entry->added_faces = BLI_ghash_ptr_new(__func__);
- entry->modified_verts = BLI_ghash_ptr_new(__func__);
- entry->modified_faces = BLI_ghash_ptr_new(__func__);
+ entry->deleted_verts = BLI_ghash_new(logkey_hash, logkey_cmp, __func__);
+ entry->deleted_faces = BLI_ghash_new(logkey_hash, logkey_cmp, __func__);
+ entry->added_verts = BLI_ghash_new(logkey_hash, logkey_cmp, __func__);
+ entry->added_faces = BLI_ghash_new(logkey_hash, logkey_cmp, __func__);
+ entry->modified_verts = BLI_ghash_new(logkey_hash, logkey_cmp, __func__);
+ entry->modified_faces = BLI_ghash_new(logkey_hash, logkey_cmp, __func__);
entry->pool_verts = BLI_mempool_create(sizeof(BMLogVert), 0, 64, BLI_MEMPOOL_NOP);
entry->pool_faces = BLI_mempool_create(sizeof(BMLogFace), 0, 64, BLI_MEMPOOL_NOP);
@@ -476,10 +480,11 @@ static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash)
BMLog *BM_log_create(BMesh *bm)
{
BMLog *log = MEM_callocN(sizeof(*log), __func__);
+ const unsigned int reserve_num = (unsigned int)(bm->totvert + bm->totface);
log->unused_ids = range_tree_uint_alloc(0, (unsigned)-1);
- log->id_to_elem = BLI_ghash_ptr_new_ex(__func__, (unsigned int)(bm->totvert + bm->totface));
- log->elem_to_id = BLI_ghash_ptr_new_ex(__func__, (unsigned int)(bm->totvert + bm->totface));
+ log->id_to_elem = BLI_ghash_new_ex(logkey_hash, logkey_cmp, __func__, reserve_num);
+ log->elem_to_id = BLI_ghash_ptr_new_ex(__func__, reserve_num);
/* Assign IDs to all existing vertices and faces */
bm_log_assign_ids(bm, log);
@@ -588,8 +593,8 @@ int BM_log_length(const BMLog *log)
/* Apply a consistent ordering to BMesh vertices */
void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
{
- void *varr;
- void *farr;
+ unsigned int *varr;
+ unsigned int *farr;
GHash *id_to_idx;
@@ -597,41 +602,37 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
BMVert *v;
BMFace *f;
- int i;
+ unsigned int i;
/* Put all vertex IDs into an array */
- i = 0;
varr = MEM_mallocN(sizeof(int) * (size_t)bm->totvert, __func__);
- BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) {
- ((unsigned int *)varr)[i++] = bm_log_vert_id_get(log, v);
+ BM_ITER_MESH_INDEX (v, &bm_iter, bm, BM_VERTS_OF_MESH, i) {
+ varr[i] = bm_log_vert_id_get(log, v);
}
/* Put all face IDs into an array */
- i = 0;
farr = MEM_mallocN(sizeof(int) * (size_t)bm->totface, __func__);
- BM_ITER_MESH (f, &bm_iter, bm, BM_FACES_OF_MESH) {
- ((unsigned int *)farr)[i++] = bm_log_face_id_get(log, f);
+ BM_ITER_MESH_INDEX (f, &bm_iter, bm, BM_FACES_OF_MESH, i) {
+ farr[i] = bm_log_face_id_get(log, f);
}
/* Create BMVert index remap array */
id_to_idx = bm_log_compress_ids_to_indices(varr, (unsigned int)bm->totvert);
- i = 0;
- BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) {
+ BM_ITER_MESH_INDEX (v, &bm_iter, bm, BM_VERTS_OF_MESH, i) {
const unsigned id = bm_log_vert_id_get(log, v);
const void *key = SET_UINT_IN_POINTER(id);
const void *val = BLI_ghash_lookup(id_to_idx, key);
- ((unsigned int *)varr)[i++] = GET_UINT_FROM_POINTER(val);
+ varr[i] = GET_UINT_FROM_POINTER(val);
}
BLI_ghash_free(id_to_idx, NULL, NULL);
/* Create BMFace index remap array */
id_to_idx = bm_log_compress_ids_to_indices(farr, (unsigned int)bm->totface);
- i = 0;
- BM_ITER_MESH (f, &bm_iter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_MESH_INDEX (f, &bm_iter, bm, BM_FACES_OF_MESH, i) {
const unsigned id = bm_log_face_id_get(log, f);
const void *key = SET_UINT_IN_POINTER(id);
const void *val = BLI_ghash_lookup(id_to_idx, key);
- ((unsigned int *)farr)[i++] = GET_UINT_FROM_POINTER(val);
+ farr[i] = GET_UINT_FROM_POINTER(val);
}
BLI_ghash_free(id_to_idx, NULL, NULL);
@@ -836,14 +837,15 @@ void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_o
BMLogVert *lv;
unsigned int v_id = bm_log_vert_id_get(log, v);
void *key = SET_UINT_IN_POINTER(v_id);
+ void **val_p;
/* Find or create the BMLogVert entry */
if ((lv = BLI_ghash_lookup(entry->added_verts, key))) {
bm_log_vert_bmvert_copy(lv, v, cd_vert_mask_offset);
}
- else if (!BLI_ghash_haskey(entry->modified_verts, key)) {
+ else if (!BLI_ghash_ensure_p(entry->modified_verts, key, &val_p)) {
lv = bm_log_vert_alloc(log, v, cd_vert_mask_offset);
- BLI_ghash_insert(entry->modified_verts, key, lv);
+ *val_p = lv;
}
}
@@ -987,6 +989,15 @@ void BM_log_all_added(BMesh *bm, BMLog *log)
BMVert *v;
BMFace *f;
+ /* avoid unnecessary resizing on initialization */
+ if (BLI_ghash_size(log->current_entry->added_verts) == 0) {
+ BLI_ghash_reserve(log->current_entry->added_verts, (unsigned int)bm->totvert);
+ }
+
+ if (BLI_ghash_size(log->current_entry->added_faces) == 0) {
+ BLI_ghash_reserve(log->current_entry->added_faces, (unsigned int)bm->totface);
+ }
+
/* Log all vertices as newly created */
BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) {
BM_log_vert_added(log, v, cd_vert_mask_offset);
@@ -1071,6 +1082,24 @@ float BM_log_original_mask(BMLog *log, BMVert *v)
return lv->mask;
}
+void BM_log_original_vert_data(
+ BMLog *log, BMVert *v,
+ const float **r_co, const short **r_no)
+{
+ BMLogEntry *entry = log->current_entry;
+ const BMLogVert *lv;
+ unsigned v_id = bm_log_vert_id_get(log, v);
+ void *key = SET_UINT_IN_POINTER(v_id);
+
+ BLI_assert(entry);
+
+ BLI_assert(BLI_ghash_haskey(entry->modified_verts, key));
+
+ lv = BLI_ghash_lookup(entry->modified_verts, key);
+ *r_co = lv->co;
+ *r_no = lv->no;
+}
+
/************************ Debugging and Testing ***********************/
/* For internal use only (unit testing) */
diff --git a/source/blender/bmesh/intern/bmesh_log.h b/source/blender/bmesh/intern/bmesh_log.h
index 2147b5c64b4..dd1772af068 100644
--- a/source/blender/bmesh/intern/bmesh_log.h
+++ b/source/blender/bmesh/intern/bmesh_log.h
@@ -96,6 +96,11 @@ const short *BM_log_original_vert_no(BMLog *log, BMVert *v);
/* Get the logged mask of a vertex */
float BM_log_original_mask(BMLog *log, BMVert *v);
+/* Get the logged data of a vertex (avoid multiple lookups) */
+void BM_log_original_vert_data(
+ BMLog *log, BMVert *v,
+ const float **r_co, const short **r_no);
+
/* For internal use only (unit testing) */
BMLogEntry *BM_log_current_entry(BMLog *log);
struct RangeTreeUInt *BM_log_unused_ids(BMLog *log);
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index 8aa64906019..17b6d1d99e7 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -73,9 +73,9 @@ static void recount_totsels(BMesh *bm)
/** \name BMesh helper functions for selection flushing.
* \{ */
-static bool bm_vert_is_edge_select_any_other(BMVert *v, BMEdge *e_first)
+static bool bm_vert_is_edge_select_any_other(const BMVert *v, const BMEdge *e_first)
{
- BMEdge *e_iter = e_first;
+ const BMEdge *e_iter = e_first;
/* start by stepping over the current edge */
while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first) {
@@ -87,10 +87,10 @@ static bool bm_vert_is_edge_select_any_other(BMVert *v, BMEdge *e_first)
}
#if 0
-static bool bm_vert_is_edge_select_any(BMVert *v)
+static bool bm_vert_is_edge_select_any(const BMVert *v)
{
if (v->e) {
- BMEdge *e_iter, *e_first;
+ const BMEdge *e_iter, *e_first;
e_iter = e_first = v->e;
do {
if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT)) {
@@ -104,7 +104,7 @@ static bool bm_vert_is_edge_select_any(BMVert *v)
static bool bm_edge_is_face_select_any_other(BMLoop *l_first)
{
- BMLoop *l_iter = l_first;
+ const BMLoop *l_iter = l_first;
/* start by stepping over the current face */
while ((l_iter = l_iter->radial_next) != l_first) {
@@ -116,10 +116,10 @@ static bool bm_edge_is_face_select_any_other(BMLoop *l_first)
}
#if 0
-static bool bm_edge_is_face_select_any(BMEdge *e)
+static bool bm_edge_is_face_select_any(const BMEdge *e)
{
if (e->l) {
- BMLoop *l_iter, *l_first;
+ const BMLoop *l_iter, *l_first;
l_iter = l_first = e->l;
do {
if (BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT)) {
@@ -626,8 +626,9 @@ void BM_mesh_select_mode_set(BMesh *bm, int selectmode)
/**
* counts number of elements with flag enabled/disabled
*/
-static int bm_mesh_flag_count(BMesh *bm, const char htype, const char hflag,
- const bool respecthide, const bool test_for_enabled)
+static int bm_mesh_flag_count(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide, const bool test_for_enabled)
{
BMElem *ele;
BMIter iter;
@@ -913,6 +914,12 @@ void _bm_select_history_store_notest(BMesh *bm, BMHeader *ele)
BLI_addtail(&(bm->selected), ese);
}
+void _bm_select_history_store_head_notest(BMesh *bm, BMHeader *ele)
+{
+ BMEditSelection *ese = bm_select_history_create(ele);
+ BLI_addhead(&(bm->selected), ese);
+}
+
void _bm_select_history_store(BMesh *bm, BMHeader *ele)
{
if (!BM_select_history_check(bm, (BMElem *)ele)) {
@@ -920,6 +927,12 @@ void _bm_select_history_store(BMesh *bm, BMHeader *ele)
}
}
+void _bm_select_history_store_head(BMesh *bm, BMHeader *ele)
+{
+ if (!BM_select_history_check(bm, (BMElem *)ele)) {
+ BM_select_history_store_head_notest(bm, (BMElem *)ele);
+ }
+}
void _bm_select_history_store_after_notest(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele)
{
@@ -1013,8 +1026,9 @@ GHash *BM_select_history_map_create(BMesh *bm)
return map;
}
-void BM_mesh_elem_hflag_disable_test(BMesh *bm, const char htype, const char hflag,
- const bool respecthide, const bool overwrite, const char hflag_test)
+void BM_mesh_elem_hflag_disable_test(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide, const bool overwrite, const char hflag_test)
{
const char iter_types[3] = {BM_VERTS_OF_MESH,
BM_EDGES_OF_MESH,
@@ -1084,8 +1098,9 @@ void BM_mesh_elem_hflag_disable_test(BMesh *bm, const char htype, const char hfl
}
}
-void BM_mesh_elem_hflag_enable_test(BMesh *bm, const char htype, const char hflag,
- const bool respecthide, const bool overwrite, const char hflag_test)
+void BM_mesh_elem_hflag_enable_test(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide, const bool overwrite, const char hflag_test)
{
const char iter_types[3] = {BM_VERTS_OF_MESH,
BM_EDGES_OF_MESH,
@@ -1139,15 +1154,17 @@ void BM_mesh_elem_hflag_enable_test(BMesh *bm, const char htype, const char hfla
}
}
-void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag,
- const bool respecthide)
+void BM_mesh_elem_hflag_disable_all(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide)
{
/* call with 0 hflag_test */
BM_mesh_elem_hflag_disable_test(bm, htype, hflag, respecthide, false, 0);
}
-void BM_mesh_elem_hflag_enable_all(BMesh *bm, const char htype, const char hflag,
- const bool respecthide)
+void BM_mesh_elem_hflag_enable_all(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide)
{
/* call with 0 hflag_test */
BM_mesh_elem_hflag_enable_test(bm, htype, hflag, respecthide, false, 0);
diff --git a/source/blender/bmesh/intern/bmesh_marking.h b/source/blender/bmesh/intern/bmesh_marking.h
index 15f972c6435..4730af66a74 100644
--- a/source/blender/bmesh/intern/bmesh_marking.h
+++ b/source/blender/bmesh/intern/bmesh_marking.h
@@ -43,15 +43,19 @@ void BM_face_hide_set(BMFace *f, const bool hide);
/* Selection code */
void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select);
-void BM_mesh_elem_hflag_enable_test(BMesh *bm, const char htype, const char hflag,
- const bool respecthide, const bool overwrite, const char hflag_test);
-void BM_mesh_elem_hflag_disable_test(BMesh *bm, const char htype, const char hflag,
- const bool respecthide, const bool overwrite, const char hflag_test);
-
-void BM_mesh_elem_hflag_enable_all(BMesh *bm, const char htype, const char hflag,
- const bool respecthide);
-void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag,
- const bool respecthide);
+void BM_mesh_elem_hflag_enable_test(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide, const bool overwrite, const char hflag_test);
+void BM_mesh_elem_hflag_disable_test(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide, const bool overwrite, const char hflag_test);
+
+void BM_mesh_elem_hflag_enable_all(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide);
+void BM_mesh_elem_hflag_disable_all(
+ BMesh *bm, const char htype, const char hflag,
+ const bool respecthide);
/* individual element select functions, BM_elem_select_set is a shortcut for these
* that automatically detects which one to use*/
@@ -91,6 +95,8 @@ void BM_editselection_plane(BMEditSelection *ese, float r_plane[3]);
#define BM_select_history_remove(bm, ele) _bm_select_history_remove(bm, &(ele)->head)
#define BM_select_history_store_notest(bm, ele) _bm_select_history_store_notest(bm, &(ele)->head)
#define BM_select_history_store(bm, ele) _bm_select_history_store(bm, &(ele)->head)
+#define BM_select_history_store_head_notest(bm, ele) _bm_select_history_store_head_notest(bm, &(ele)->head)
+#define BM_select_history_store_head(bm, ele) _bm_select_history_store_head(bm, &(ele)->head)
#define BM_select_history_store_after_notest(bm, ese_ref, ele) _bm_select_history_store_after_notest(bm, ese_ref, &(ele)->head)
#define BM_select_history_store_after(bm, ese, ese_ref) _bm_select_history_store_after(bm, ese_ref, &(ele)->head)
@@ -98,6 +104,8 @@ bool _bm_select_history_check(BMesh *bm, const BMHeader *ele);
bool _bm_select_history_remove(BMesh *bm, BMHeader *ele);
void _bm_select_history_store_notest(BMesh *bm, BMHeader *ele);
void _bm_select_history_store(BMesh *bm, BMHeader *ele);
+void _bm_select_history_store_head_notest(BMesh *bm, BMHeader *ele);
+void _bm_select_history_store_head(BMesh *bm, BMHeader *ele);
void _bm_select_history_store_after(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele);
void _bm_select_history_store_after_notest(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele);
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index 9a2869b64ef..2c4a98b0b7e 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -303,8 +303,9 @@ static void bm_mesh_edges_calc_vectors(BMesh *bm, float (*edgevec)[3], const flo
bm->elem_index_dirty &= ~BM_EDGE;
}
-static void bm_mesh_verts_calc_normals(BMesh *bm, const float (*edgevec)[3], const float (*fnos)[3],
- const float (*vcos)[3], float (*vnos)[3])
+static void bm_mesh_verts_calc_normals(
+ BMesh *bm, const float (*edgevec)[3], const float (*fnos)[3],
+ const float (*vcos)[3], float (*vnos)[3])
{
BM_mesh_elem_index_ensure(bm, (vnos) ? (BM_EDGE | BM_VERT) : BM_EDGE);
@@ -437,8 +438,9 @@ void BM_verts_calc_normal_vcos(BMesh *bm, const float (*fnos)[3], const float (*
/**
* Helpers for #BM_mesh_loop_normals_update and #BM_loops_calc_normals_vnos
*/
-static void bm_mesh_edges_sharp_tag(BMesh *bm, const float (*vnos)[3], const float (*fnos)[3], float split_angle,
- float (*r_lnos)[3])
+static void bm_mesh_edges_sharp_tag(
+ BMesh *bm, const float (*vnos)[3], const float (*fnos)[3], float split_angle,
+ float (*r_lnos)[3])
{
BMIter eiter, viter;
BMVert *v;
@@ -1131,8 +1133,9 @@ finally:
* These functions ensure its correct and are called more often in debug mode.
*/
-void BM_mesh_elem_index_validate(BMesh *bm, const char *location, const char *func,
- const char *msg_a, const char *msg_b)
+void BM_mesh_elem_index_validate(
+ BMesh *bm, const char *location, const char *func,
+ const char *msg_a, const char *msg_b)
{
const char iter_types[3] = {BM_VERTS_OF_MESH,
BM_EDGES_OF_MESH,
@@ -1379,6 +1382,41 @@ BMFace *BM_face_at_index_find(BMesh *bm, const int index)
return BLI_mempool_findelem(bm->fpool, index);
}
+/**
+ * Use lookup table when available, else use slower find functions.
+ *
+ * \note Try to use #BM_mesh_elem_table_ensure instead.
+ */
+BMVert *BM_vert_at_index_find_or_table(BMesh *bm, const int index)
+{
+ if ((bm->elem_table_dirty & BM_VERT) == 0) {
+ return (index < bm->totvert) ? bm->vtable[index] : NULL;
+ }
+ else {
+ return BM_vert_at_index_find(bm, index);
+ }
+}
+
+BMEdge *BM_edge_at_index_find_or_table(BMesh *bm, const int index)
+{
+ if ((bm->elem_table_dirty & BM_EDGE) == 0) {
+ return (index < bm->totedge) ? bm->etable[index] : NULL;
+ }
+ else {
+ return BM_edge_at_index_find(bm, index);
+ }
+}
+
+BMFace *BM_face_at_index_find_or_table(BMesh *bm, const int index)
+{
+ if ((bm->elem_table_dirty & BM_FACE) == 0) {
+ return (index < bm->totface) ? bm->ftable[index] : NULL;
+ }
+ else {
+ return BM_face_at_index_find(bm, index);
+ }
+}
+
/**
* Return the amount of element of type 'type' in a given bmesh.
@@ -1459,7 +1497,7 @@ void BM_mesh_remap(
BMVert *new_vep = verts_pool[*new_idx];
*new_vep = *ve;
/* printf("mapping vert from %d to %d (%p/%p to %p)\n", i, *new_idx, *vep, verts_pool[i], new_vep);*/
- BLI_ghash_insert(vptr_map, (void *)*vep, (void *)new_vep);
+ BLI_ghash_insert(vptr_map, *vep, new_vep);
}
bm->elem_index_dirty |= BM_VERT;
bm->elem_table_dirty |= BM_VERT;
@@ -1490,7 +1528,7 @@ void BM_mesh_remap(
for (i = totedge; i--; new_idx--, ed--, edp--) {
BMEdge *new_edp = edges_pool[*new_idx];
*new_edp = *ed;
- BLI_ghash_insert(eptr_map, (void *)*edp, (void *)new_edp);
+ BLI_ghash_insert(eptr_map, *edp, new_edp);
/* printf("mapping edge from %d to %d (%p/%p to %p)\n", i, *new_idx, *edp, edges_pool[i], new_edp);*/
}
bm->elem_index_dirty |= BM_EDGE;
@@ -1522,7 +1560,7 @@ void BM_mesh_remap(
for (i = totface; i--; new_idx--, fa--, fap--) {
BMFace *new_fap = faces_pool[*new_idx];
*new_fap = *fa;
- BLI_ghash_insert(fptr_map, (void *)*fap, (void *)new_fap);
+ BLI_ghash_insert(fptr_map, *fap, new_fap);
}
bm->elem_index_dirty |= BM_FACE | BM_LOOP;
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index bac5da8347e..b157237c7d0 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -49,8 +49,9 @@ void bmesh_edit_begin(BMesh *bm, const BMOpTypeFlag type_flag);
void bmesh_edit_end(BMesh *bm, const BMOpTypeFlag type_flag);
void BM_mesh_elem_index_ensure(BMesh *bm, const char hflag);
-void BM_mesh_elem_index_validate(BMesh *bm, const char *location, const char *func,
- const char *msg_a, const char *msg_b);
+void BM_mesh_elem_index_validate(
+ BMesh *bm, const char *location, const char *func,
+ const char *msg_a, const char *msg_b);
#ifndef NDEBUG
bool BM_mesh_elem_table_check(BMesh *bm);
@@ -68,6 +69,10 @@ BMVert *BM_vert_at_index_find(BMesh *bm, const int index);
BMEdge *BM_edge_at_index_find(BMesh *bm, const int index);
BMFace *BM_face_at_index_find(BMesh *bm, const int index);
+BMVert *BM_vert_at_index_find_or_table(BMesh *bm, const int index);
+BMEdge *BM_edge_at_index_find_or_table(BMesh *bm, const int index);
+BMFace *BM_face_at_index_find_or_table(BMesh *bm, const int index);
+
// XXX
int BM_mesh_elem_count(BMesh *bm, const char htype);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c
index 3630bb78b8a..a0ef12c28db 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c
@@ -98,6 +98,9 @@
#include "bmesh.h"
#include "intern/bmesh_private.h" /* for element checking */
+/* XXX stupid hack: linker otherwise strips bmesh_strands_conv.c because it is not used inside bmesh */
+void *__dummy_hack__ = &BM_strands_count_psys_keys;
+
/**
* Currently this is only used for Python scripts
* which may fail to keep matching UV/TexFace layers.
@@ -200,8 +203,9 @@ char BM_mesh_cd_flag_from_bmesh(BMesh *bm)
}
/* Static function for alloc (duplicate in modifiers_bmesh.c) */
-static BMFace *bm_face_create_from_mpoly(MPoly *mp, MLoop *ml,
- BMesh *bm, BMVert **vtable, BMEdge **etable)
+static BMFace *bm_face_create_from_mpoly(
+ MPoly *mp, MLoop *ml,
+ BMesh *bm, BMVert **vtable, BMEdge **etable)
{
BMVert **verts = BLI_array_alloca(verts, mp->totloop);
BMEdge **edges = BLI_array_alloca(edges, mp->totloop);
@@ -221,8 +225,20 @@ static BMFace *bm_face_create_from_mpoly(MPoly *mp, MLoop *ml,
*
* \warning This function doesn't calculate face normals.
*/
-void BM_mesh_bm_from_me(BMesh *bm, Mesh *me,
- const bool calc_face_normal, const bool set_key, int act_key_nr)
+void BM_mesh_bm_from_me(
+ BMesh *bm, Mesh *me,
+ const bool calc_face_normal, const bool set_key, int act_key_nr)
+{
+ BM_mesh_bm_from_me_ex(bm, me, CD_MASK_BMESH, calc_face_normal, set_key, act_key_nr);
+}
+
+/**
+ * \brief Mesh -> BMesh
+ *
+ * \warning This function doesn't calculate face normals.
+ */
+void BM_mesh_bm_from_me_ex(BMesh *bm, Mesh *me, CustomDataMask mask,
+ const bool calc_face_normal, const bool set_key, int act_key_nr)
{
MVert *mvert;
MEdge *medge;
@@ -249,10 +265,10 @@ void BM_mesh_bm_from_me(BMesh *bm, Mesh *me,
if (!me || !me->totvert) {
if (me) { /*no verts? still copy customdata layout*/
- CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_ASSIGN, 0);
- CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_ASSIGN, 0);
- CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_ASSIGN, 0);
- CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_ASSIGN, 0);
+ CustomData_copy(&me->vdata, &bm->vdata, mask, CD_ASSIGN, 0);
+ CustomData_copy(&me->edata, &bm->edata, mask, CD_ASSIGN, 0);
+ CustomData_copy(&me->ldata, &bm->ldata, mask, CD_ASSIGN, 0);
+ CustomData_copy(&me->pdata, &bm->pdata, mask, CD_ASSIGN, 0);
CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT);
CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE);
@@ -264,10 +280,10 @@ void BM_mesh_bm_from_me(BMesh *bm, Mesh *me,
vtable = MEM_mallocN(sizeof(void **) * me->totvert, "mesh to bmesh vtable");
- CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
- CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
- CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
- CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&me->vdata, &bm->vdata, mask, CD_CALLOC, 0);
+ CustomData_copy(&me->edata, &bm->edata, mask, CD_CALLOC, 0);
+ CustomData_copy(&me->ldata, &bm->ldata, mask, CD_CALLOC, 0);
+ CustomData_copy(&me->pdata, &bm->pdata, mask, CD_CALLOC, 0);
/* make sure uv layer names are consisten */
totuv = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
@@ -568,6 +584,11 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
void BM_mesh_bm_to_me(BMesh *bm, Mesh *me, bool do_tessface)
{
+ BM_mesh_bm_to_me_ex(bm, me, CD_MASK_MESH, do_tessface);
+}
+
+void BM_mesh_bm_to_me_ex(BMesh *bm, Mesh *me, CustomDataMask mask, bool do_tessface)
+{
MLoop *mloop;
MPoly *mpoly;
MVert *mvert, *oldverts;
@@ -627,10 +648,10 @@ void BM_mesh_bm_to_me(BMesh *bm, Mesh *me, bool do_tessface)
me->totface = 0;
me->act_face = -1;
- CustomData_copy(&bm->vdata, &me->vdata, CD_MASK_MESH, CD_CALLOC, me->totvert);
- CustomData_copy(&bm->edata, &me->edata, CD_MASK_MESH, CD_CALLOC, me->totedge);
- CustomData_copy(&bm->ldata, &me->ldata, CD_MASK_MESH, CD_CALLOC, me->totloop);
- CustomData_copy(&bm->pdata, &me->pdata, CD_MASK_MESH, CD_CALLOC, me->totpoly);
+ CustomData_copy(&bm->vdata, &me->vdata, mask, CD_CALLOC, me->totvert);
+ CustomData_copy(&bm->edata, &me->edata, mask, CD_CALLOC, me->totedge);
+ CustomData_copy(&bm->ldata, &me->ldata, mask, CD_CALLOC, me->totloop);
+ CustomData_copy(&bm->pdata, &me->pdata, mask, CD_CALLOC, me->totpoly);
CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.h b/source/blender/bmesh/intern/bmesh_mesh_conv.h
index ab9d7a0ccf3..0d235a128ab 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.h
@@ -32,15 +32,22 @@
* \ingroup bmesh
*/
+#include "BLI_sys_types.h"
+
struct Mesh;
+typedef uint64_t CustomDataMask;
void BM_mesh_cd_validate(BMesh *bm);
void BM_mesh_cd_flag_ensure(BMesh *bm, struct Mesh *mesh, const char cd_flag);
void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag);
char BM_mesh_cd_flag_from_bmesh(BMesh *bm);
-void BM_mesh_bm_from_me(BMesh *bm, struct Mesh *me,
+void BM_mesh_bm_from_me(
+ BMesh *bm, struct Mesh *me,
+ const bool calc_face_normal, const bool set_key, int act_key_nr);
+void BM_mesh_bm_from_me_ex(BMesh *bm, struct Mesh *me, CustomDataMask mask,
const bool calc_face_normal, const bool set_key, int act_key_nr);
void BM_mesh_bm_to_me(BMesh *bm, struct Mesh *me, bool do_tessface);
+void BM_mesh_bm_to_me_ex(BMesh *bm, struct Mesh *me, CustomDataMask mask, bool do_tessface);
#endif /* __BMESH_MESH_CONV_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_validate.c b/source/blender/bmesh/intern/bmesh_mesh_validate.c
index 3a7a4f85e99..478194735f3 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_validate.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_validate.c
@@ -86,20 +86,19 @@ bool BM_mesh_validate(BMesh *bm)
/* check edges */
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
- BMEdge *e_other;
+ void **val_p;
if (e->v1 == e->v2) {
ERRMSG("edge %d: duplicate index: %d", i, BM_elem_index_get(e->v1));
}
-
/* build edgehash at the same time */
- e_other = BLI_edgehash_lookup(edge_hash, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2));
- if (e_other) {
+ if (BLI_edgehash_ensure_p(edge_hash, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2), &val_p)) {
+ BMEdge *e_other = *val_p;
ERRMSG("edge %d, %d: are duplicates", i, BM_elem_index_get(e_other));
}
else {
- BLI_edgehash_insert(edge_hash, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2), e);
+ *val_p = e;
}
}
@@ -196,7 +195,7 @@ bool BM_mesh_validate(BMesh *bm)
ERRMSG("Finished - errors %d", errtot);
- return true;
+ return (errtot == 0);
}
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
index 7b3f64dc5cd..13c43fabdb0 100644
--- a/source/blender/bmesh/intern/bmesh_mods.c
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -72,7 +72,8 @@
*/
bool BM_vert_dissolve(BMesh *bm, BMVert *v)
{
- const int len = BM_vert_edge_count(v);
+ /* logic for 3 or more is identical */
+ const int len = BM_vert_edge_count_ex(v, 3);
if (len == 1) {
BM_vert_kill(bm, v); /* will kill edges too */
@@ -97,7 +98,7 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v)
return false;
}
}
- else if (len == 2 && BM_vert_face_count(v) == 1) {
+ else if (len == 2 && BM_vert_face_count_is_equal(v, 1)) {
/* boundary vertex on a face */
return (BM_vert_collapse_edge(bm, v->e, v, true, true) != NULL);
}
@@ -269,16 +270,17 @@ BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f_a, BMFace *f_b, BMEdge *e, const
* the split edge to be created (must be differ and not can't be adjacent in the face).
* \param r_l pointer which will receive the BMLoop for the split edge in the new face
* \param example Edge used for attributes of splitting edge, if non-NULL
- * \param nodouble Use an existing edge if found
+ * \param no_double: Use an existing edge if found
*
* \return Pointer to the newly created face representing one side of the split
* if the split is successful (and the original original face will be the
* other side). NULL if the split fails.
*/
-BMFace *BM_face_split(BMesh *bm, BMFace *f,
- BMLoop *l_a, BMLoop *l_b,
- BMLoop **r_l, BMEdge *example,
- const bool no_double)
+BMFace *BM_face_split(
+ BMesh *bm, BMFace *f,
+ BMLoop *l_a, BMLoop *l_b,
+ BMLoop **r_l, BMEdge *example,
+ const bool no_double)
{
const bool has_mdisp = CustomData_has_layer(&bm->ldata, CD_MDISPS);
BMFace *f_new, *f_tmp;
@@ -356,10 +358,11 @@ BMFace *BM_face_split(BMesh *bm, BMFace *f,
* if the split is successful (and the original original face will be the
* other side). NULL if the split fails.
*/
-BMFace *BM_face_split_n(BMesh *bm, BMFace *f,
- BMLoop *l_a, BMLoop *l_b,
- float cos[][3], int n,
- BMLoop **r_l, BMEdge *example)
+BMFace *BM_face_split_n(
+ BMesh *bm, BMFace *f,
+ BMLoop *l_a, BMLoop *l_b,
+ float cos[][3], int n,
+ BMLoop **r_l, BMEdge *example)
{
BMFace *f_new, *f_tmp;
BMLoop *l_dummy;
@@ -990,8 +993,9 @@ bool BM_face_split_edgenet(
*
* \returns The New Edge
*/
-BMEdge *BM_vert_collapse_faces(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float fac,
- const bool do_del, const bool join_faces, const bool kill_degenerate_faces)
+BMEdge *BM_vert_collapse_faces(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float fac,
+ const bool do_del, const bool join_faces, const bool kill_degenerate_faces)
{
BMEdge *e_new = NULL;
BMVert *tv = BM_edge_other_vert(e_kill, v_kill);
@@ -1103,8 +1107,9 @@ BMEdge *BM_vert_collapse_faces(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float
*
* \return The New Edge
*/
-BMEdge *BM_vert_collapse_edge(BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
- const bool do_del, const bool kill_degenerate_faces)
+BMEdge *BM_vert_collapse_edge(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
+ const bool do_del, const bool kill_degenerate_faces)
{
/* nice example implementation but we want loops to have their customdata
* accounted for */
@@ -1353,8 +1358,9 @@ bool BM_face_validate(BMFace *face, FILE *err)
*
* \note #BM_edge_rotate_check must have already run.
*/
-void BM_edge_calc_rotate(BMEdge *e, const bool ccw,
- BMLoop **r_l1, BMLoop **r_l2)
+void BM_edge_calc_rotate(
+ BMEdge *e, const bool ccw,
+ BMLoop **r_l1, BMLoop **r_l2)
{
BMVert *v1, *v2;
BMFace *fa, *fb;
@@ -1516,8 +1522,9 @@ bool BM_edge_rotate_check_degenerate(BMEdge *e, BMLoop *l1, BMLoop *l2)
return true;
}
-bool BM_edge_rotate_check_beauty(BMEdge *e,
- BMLoop *l1, BMLoop *l2)
+bool BM_edge_rotate_check_beauty(
+ BMEdge *e,
+ BMLoop *l1, BMLoop *l2)
{
/* Stupid check for now:
* Could compare angles of surrounding edges
@@ -1643,3 +1650,9 @@ BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *sl)
{
return bmesh_urmv_loop(bm, sl);
}
+
+BMVert *BM_face_loop_separate_multi(
+ BMesh *bm, BMLoop **larr, int larr_len)
+{
+ return bmesh_urmv_loop_multi(bm, larr, larr_len);
+}
diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h
index 59aee323bba..1b826b1e0b2 100644
--- a/source/blender/bmesh/intern/bmesh_mods.h
+++ b/source/blender/bmesh/intern/bmesh_mods.h
@@ -35,24 +35,29 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v);
BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e, const bool do_del);
-BMFace *BM_face_split(BMesh *bm, BMFace *f,
- BMLoop *l_a, BMLoop *l_b,
- BMLoop **r_l,
- BMEdge *example, const bool no_double);
-
-BMFace *BM_face_split_n(BMesh *bm, BMFace *f,
- BMLoop *l_a, BMLoop *l_b,
- float cos[][3], int n,
- BMLoop **r_l, BMEdge *example);
-
-bool BM_face_split_edgenet(BMesh *bm, BMFace *f,
- BMEdge **edge_net, const int edge_net_len,
- BMFace ***r_face_arr, int *r_face_arr_len);
-
-BMEdge *BM_vert_collapse_faces(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float fac,
- const bool do_del, const bool join_faces, const bool kill_degenerate_faces);
-BMEdge *BM_vert_collapse_edge(BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
- const bool do_del, const bool kill_degenerate_faces);
+BMFace *BM_face_split(
+ BMesh *bm, BMFace *f,
+ BMLoop *l_a, BMLoop *l_b,
+ BMLoop **r_l,
+ BMEdge *example, const bool no_double);
+
+BMFace *BM_face_split_n(
+ BMesh *bm, BMFace *f,
+ BMLoop *l_a, BMLoop *l_b,
+ float cos[][3], int n,
+BMLoop **r_l, BMEdge *example);
+
+bool BM_face_split_edgenet(
+ BMesh *bm, BMFace *f,
+ BMEdge **edge_net, const int edge_net_len,
+ BMFace ***r_face_arr, int *r_face_arr_len);
+
+BMEdge *BM_vert_collapse_faces(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float fac,
+ const bool do_del, const bool join_faces, const bool kill_degenerate_faces);
+BMEdge *BM_vert_collapse_edge(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
+ const bool do_del, const bool kill_degenerate_faces);
BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float percent);
@@ -61,13 +66,16 @@ BMVert *BM_edge_split_n(BMesh *bm, BMEdge *e, int numcuts, BMVert **r_varr);
bool BM_face_validate(BMFace *face, FILE *err);
-void BM_edge_calc_rotate(BMEdge *e, const bool ccw,
- BMLoop **r_l1, BMLoop **r_l2);
+void BM_edge_calc_rotate(
+ BMEdge *e, const bool ccw,
+ BMLoop **r_l1, BMLoop **r_l2);
bool BM_edge_rotate_check(BMEdge *e);
-bool BM_edge_rotate_check_degenerate(BMEdge *e,
- BMLoop *l1, BMLoop *l2);
-bool BM_edge_rotate_check_beauty(BMEdge *e,
- BMLoop *l1, BMLoop *l2);
+bool BM_edge_rotate_check_degenerate(
+ BMEdge *e,
+ BMLoop *l1, BMLoop *l2);
+bool BM_edge_rotate_check_beauty(
+ BMEdge *e,
+ BMLoop *l1, BMLoop *l2);
BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_flag);
/* flags for BM_edge_rotate */
@@ -81,5 +89,7 @@ enum {
BMVert *BM_face_vert_separate(BMesh *bm, BMFace *sf, BMVert *sv);
BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *sl);
+BMVert *BM_face_loop_separate_multi(
+ BMesh *bm, BMLoop **larr, int larr_len);
#endif /* __BMESH_MODS_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index d0679b9919a..ce988c6c6dd 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -359,6 +359,7 @@ static BMOpDefine bmo_collapse_def = {
"collapse",
/* slots_in */
{{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input edges */
+ {"uvs", BMO_OP_SLOT_BOOL}, /* also collapse UVs and such */
{{'\0'}},
},
{{{'\0'}}}, /* no output */
@@ -486,17 +487,19 @@ static BMOpDefine bmo_create_vert_def = {
* Join Triangles.
*
* Tries to intelligently join triangles according
- * to various settings and stuff.
+ * to angle threshold and delimiters.
*/
static BMOpDefine bmo_join_triangles_def = {
"join_triangles",
/* slots_in */
{{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input geometry. */
+ {"cmp_seam", BMO_OP_SLOT_BOOL},
{"cmp_sharp", BMO_OP_SLOT_BOOL},
{"cmp_uvs", BMO_OP_SLOT_BOOL},
{"cmp_vcols", BMO_OP_SLOT_BOOL},
{"cmp_materials", BMO_OP_SLOT_BOOL},
- {"limit", BMO_OP_SLOT_FLT},
+ {"angle_face_threshold", BMO_OP_SLOT_FLT},
+ {"angle_shape_threshold", BMO_OP_SLOT_FLT},
{{'\0'}},
},
/* slots_out */
diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h
index d966d882c67..3f7fb7b257d 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api.h
@@ -273,9 +273,10 @@ BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identif
(op_dst)->slots_dst, slot_name_dst, \
(op_dst)->arena)
-void _bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
- BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
- struct MemArena *arena_dst);
+void _bmo_slot_copy(
+ BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
+ BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
+ struct MemArena *arena_dst);
/* del "context" slot values, used for operator too */
enum {
@@ -301,6 +302,8 @@ typedef enum {
BMO_DELIM_NORMAL = 1 << 0,
BMO_DELIM_MATERIAL = 1 << 1,
BMO_DELIM_SEAM = 1 << 2,
+ BMO_DELIM_SHARP = 1 << 3,
+ BMO_DELIM_UV = 1 << 4,
} BMO_Delimit;
void BMO_op_flag_enable(BMesh *bm, BMOperator *op, const int op_flag);
@@ -335,11 +338,12 @@ void BMO_slot_mat3_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na
void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *op, const char htype, const short oflag);
-void BMO_mesh_selected_remap(BMesh *bm,
- BMOpSlot *slot_vert_map,
- BMOpSlot *slot_edge_map,
- BMOpSlot *slot_face_map,
- const bool check_select);
+void BMO_mesh_selected_remap(
+ BMesh *bm,
+ BMOpSlot *slot_vert_map,
+ BMOpSlot *slot_edge_map,
+ BMOpSlot *slot_face_map,
+ const bool check_select);
/* copies the values from another slot to the end of the output slot */
#define BMO_slot_buffer_append(op_src, slots_src, slot_name_src, \
@@ -347,53 +351,62 @@ void BMO_mesh_selected_remap(BMesh *bm,
_bmo_slot_buffer_append((op_src)->slots_src, slot_name_src, \
(op_dst)->slots_dst, slot_name_dst, \
(op_dst)->arena)
-void _bmo_slot_buffer_append(BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
- BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
- struct MemArena *arena_dst);
+void _bmo_slot_buffer_append(
+ BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
+ BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
+ struct MemArena *arena_dst);
/* puts every element of type 'type' (which is a bitmask) with tool
* flag 'flag', into a slot. */
-void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag);
+void BMO_slot_buffer_from_enabled_flag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag);
/* puts every element of type 'type' (which is a bitmask) without tool
* flag 'flag', into a slot. */
-void BMO_slot_buffer_from_disabled_flag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag);
+void BMO_slot_buffer_from_disabled_flag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag);
/* tool-flags all elements inside an element slot array with flag flag. */
-void BMO_slot_buffer_flag_enable(BMesh *bm,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag);
+void BMO_slot_buffer_flag_enable(
+ BMesh *bm,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag);
/* clears tool-flag flag from all elements inside a slot array. */
-void BMO_slot_buffer_flag_disable(BMesh *bm,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag);
+void BMO_slot_buffer_flag_disable(
+ BMesh *bm,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag);
/* tool-flags all elements inside an element slot array with flag flag. */
-void BMO_slot_buffer_hflag_enable(BMesh *bm,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag, const bool do_flush);
+void BMO_slot_buffer_hflag_enable(
+ BMesh *bm,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag, const bool do_flush);
/* clears tool-flag flag from all elements inside a slot array. */
-void BMO_slot_buffer_hflag_disable(BMesh *bm,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag, const bool do_flush);
+void BMO_slot_buffer_hflag_disable(
+ BMesh *bm,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag, const bool do_flush);
/* puts every element of type 'type' (which is a bitmask) with header
* flag 'flag', into a slot. note: ignores hidden elements
* (e.g. elements with header flag BM_ELEM_HIDDEN set).*/
-void BMO_slot_buffer_from_enabled_hflag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag);
+void BMO_slot_buffer_from_enabled_hflag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag);
/* puts every element of type 'type' (which is a bitmask) without
* header flag 'flag', into a slot. note: ignores hidden elements
* (e.g. elements with header flag BM_ELEM_HIDDEN set).*/
-void BMO_slot_buffer_from_disabled_hflag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag);
+void BMO_slot_buffer_from_disabled_hflag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag);
void BMO_slot_buffer_from_array(BMOperator *op, BMOpSlot *slot, BMHeader **ele_buffer, int ele_buffer_len);
@@ -405,19 +418,23 @@ void *BMO_slot_buffer_get_single(BMOpSlot *slot);
int BMO_slot_buffer_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
int BMO_slot_map_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
-void BMO_slot_map_insert(BMOperator *op, BMOpSlot *slot,
- const void *element, const void *data);
+void BMO_slot_map_insert(
+ BMOperator *op, BMOpSlot *slot,
+ const void *element, const void *data);
/* flags all elements in a mapping. note that the mapping must only have
* bmesh elements in it.*/
-void BMO_slot_map_to_flag(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
- const char *slot_name, const char hflag, const short oflag);
+void BMO_slot_map_to_flag(
+ BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
+ const char *slot_name, const char hflag, const short oflag);
-void *BMO_slot_buffer_alloc(BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
- const char *slot_name, const int len);
+void *BMO_slot_buffer_alloc(
+ BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
+ const char *slot_name, const int len);
-void BMO_slot_buffer_from_all(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
- const char *slot_name, const char htype);
+void BMO_slot_buffer_from_all(
+ BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
+ const char *slot_name, const char htype);
/**
* This part of the API is used to iterate over element buffer or
@@ -466,9 +483,10 @@ typedef struct BMOIter {
void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
-void *BMO_iter_new(BMOIter *iter,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char restrictmask);
+void *BMO_iter_new(
+ BMOIter *iter,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char restrictmask);
void *BMO_iter_step(BMOIter *iter);
void **BMO_iter_map_value_p(BMOIter *iter);
@@ -483,9 +501,6 @@ bool BMO_iter_map_value_bool(BMOIter *iter);
ele; \
BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMO_iter_step(iter))
-/******************* Inlined Functions********************/
-typedef void (*opexec)(BMesh *bm, BMOperator *op);
-
extern const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES];
int BMO_opcode_from_opname(const char *opname);
diff --git a/source/blender/bmesh/intern/bmesh_operator_api_inline.h b/source/blender/bmesh/intern/bmesh_operator_api_inline.h
index 2b78b775723..4f995e08b9c 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api_inline.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api_inline.h
@@ -38,55 +38,67 @@
* ghash or a mapping slot to do it. */
/* flags 15 and 16 (1 << 14 and 1 << 15) are reserved for bmesh api use */
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE short _bmo_elem_flag_test(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
return oflags[bm->stackdepth - 1].f & oflag;
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
return (oflags[bm->stackdepth - 1].f & oflag) != 0;
}
+ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_enable(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
oflags[bm->stackdepth - 1].f |= oflag;
}
+ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_disable(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
oflags[bm->stackdepth - 1].f &= (short)~oflag;
}
+ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_set(BMesh *bm, BMFlagLayer *oflags, const short oflag, int val)
{
if (val) oflags[bm->stackdepth - 1].f |= oflag;
else oflags[bm->stackdepth - 1].f &= (short)~oflag;
}
+ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_toggle(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
oflags[bm->stackdepth - 1].f ^= oflag;
}
-BLI_INLINE void BMO_slot_map_int_insert(BMOperator *op, BMOpSlot *slot,
- void *element, const int val)
+ATTR_NONNULL(1, 2)
+BLI_INLINE void BMO_slot_map_int_insert(
+ BMOperator *op, BMOpSlot *slot,
+ void *element, const int val)
{
union { void *ptr; int val; } t = {NULL};
BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_INT);
BMO_slot_map_insert(op, slot, element, ((t.val = val), t.ptr));
}
-BLI_INLINE void BMO_slot_map_bool_insert(BMOperator *op, BMOpSlot *slot,
- void *element, const bool val)
+ATTR_NONNULL(1, 2)
+BLI_INLINE void BMO_slot_map_bool_insert(
+ BMOperator *op, BMOpSlot *slot,
+ void *element, const bool val)
{
union { void *ptr; bool val; } t = {NULL};
BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_BOOL);
BMO_slot_map_insert(op, slot, element, ((t.val = val), t.ptr));
}
-BLI_INLINE void BMO_slot_map_float_insert(BMOperator *op, BMOpSlot *slot,
- void *element, const float val)
+ATTR_NONNULL(1, 2)
+BLI_INLINE void BMO_slot_map_float_insert(
+ BMOperator *op, BMOpSlot *slot,
+ void *element, const float val)
{
union { void *ptr; float val; } t = {NULL};
BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_FLT);
@@ -99,15 +111,19 @@ BLI_INLINE void BMO_slot_map_float_insert(BMOperator *op, BMOpSlot *slot,
* do NOT use these for non-operator-api-allocated memory! instead
* use BMO_slot_map_data_get and BMO_slot_map_insert, which copies the data. */
-BLI_INLINE void BMO_slot_map_ptr_insert(BMOperator *op, BMOpSlot *slot,
- const void *element, void *val)
+ATTR_NONNULL(1, 2)
+BLI_INLINE void BMO_slot_map_ptr_insert(
+ BMOperator *op, BMOpSlot *slot,
+ const void *element, void *val)
{
BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL);
BMO_slot_map_insert(op, slot, element, val);
}
-BLI_INLINE void BMO_slot_map_elem_insert(BMOperator *op, BMOpSlot *slot,
- const void *element, void *val)
+ATTR_NONNULL(1, 2)
+BLI_INLINE void BMO_slot_map_elem_insert(
+ BMOperator *op, BMOpSlot *slot,
+ const void *element, void *val)
{
BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_ELEM);
BMO_slot_map_insert(op, slot, element, val);
@@ -115,25 +131,30 @@ BLI_INLINE void BMO_slot_map_elem_insert(BMOperator *op, BMOpSlot *slot,
/* no values */
-BLI_INLINE void BMO_slot_map_empty_insert(BMOperator *op, BMOpSlot *slot,
- const void *element)
+ATTR_NONNULL(1, 2)
+BLI_INLINE void BMO_slot_map_empty_insert(
+ BMOperator *op, BMOpSlot *slot,
+ const void *element)
{
BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_EMPTY);
BMO_slot_map_insert(op, slot, element, NULL);
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BMO_slot_map_contains(BMOpSlot *slot, const void *element)
{
BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING);
return BLI_ghash_haskey(slot->data.ghash, element);
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE void **BMO_slot_map_data_get(BMOpSlot *slot, const void *element)
{
return BLI_ghash_lookup_p(slot->data.ghash, element);
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE float BMO_slot_map_float_get(BMOpSlot *slot, const void *element)
{
void **data;
@@ -148,6 +169,7 @@ BLI_INLINE float BMO_slot_map_float_get(BMOpSlot *slot, const void *element)
}
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE int BMO_slot_map_int_get(BMOpSlot *slot, const void *element)
{
void **data;
@@ -162,6 +184,7 @@ BLI_INLINE int BMO_slot_map_int_get(BMOpSlot *slot, const void *element)
}
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BMO_slot_map_bool_get(BMOpSlot *slot, const void *element)
{
void **data;
@@ -176,6 +199,7 @@ BLI_INLINE bool BMO_slot_map_bool_get(BMOpSlot *slot, const void *element)
}
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE void *BMO_slot_map_ptr_get(BMOpSlot *slot, const void *element)
{
void **val = BMO_slot_map_data_get(slot, element);
@@ -185,6 +209,7 @@ BLI_INLINE void *BMO_slot_map_ptr_get(BMOpSlot *slot, const void *element)
return NULL;
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE void *BMO_slot_map_elem_get(BMOpSlot *slot, const void *element)
{
void **val = (void **) BMO_slot_map_data_get(slot, element);
diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c
index ba154b04838..dda1f2fe30a 100644
--- a/source/blender/bmesh/intern/bmesh_operators.c
+++ b/source/blender/bmesh/intern/bmesh_operators.c
@@ -281,9 +281,10 @@ BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identif
* define used.
* Copies data from one slot to another.
*/
-void _bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
- BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
- struct MemArena *arena_dst)
+void _bmo_slot_copy(
+ BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
+ BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
+ struct MemArena *arena_dst)
{
BMOpSlot *slot_src = BMO_slot_get(slot_args_src, slot_name_src);
BMOpSlot *slot_dst = BMO_slot_get(slot_args_dst, slot_name_dst);
@@ -543,8 +544,9 @@ void BMO_slot_vec_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_nam
*
*/
-static int bmo_mesh_flag_count(BMesh *bm, const char htype, const short oflag,
- const bool test_for_enabled)
+static int bmo_mesh_flag_count(
+ BMesh *bm, const char htype, const short oflag,
+ const bool test_for_enabled)
{
const char iter_types[3] = {BM_VERTS_OF_MESH,
BM_EDGES_OF_MESH,
@@ -602,11 +604,12 @@ void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char hty
}
}
-void BMO_mesh_selected_remap(BMesh *bm,
- BMOpSlot *slot_vert_map,
- BMOpSlot *slot_edge_map,
- BMOpSlot *slot_face_map,
- const bool check_select)
+void BMO_mesh_selected_remap(
+ BMesh *bm,
+ BMOpSlot *slot_vert_map,
+ BMOpSlot *slot_edge_map,
+ BMOpSlot *slot_face_map,
+ const bool check_select)
{
if (bm->selected.first) {
BMEditSelection *ese, *ese_next;
@@ -663,8 +666,9 @@ int BMO_slot_map_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na
/* inserts a key/value mapping into a mapping slot. note that it copies the
* value, it doesn't store a reference to it. */
-void BMO_slot_map_insert(BMOperator *op, BMOpSlot *slot,
- const void *element, const void *data)
+void BMO_slot_map_insert(
+ BMOperator *op, BMOpSlot *slot,
+ const void *element, const void *data)
{
(void) op; /* Ignored in release builds. */
@@ -717,8 +721,9 @@ void *bmo_slot_buffer_grow(BMesh *bm, BMOperator *op, int slot_code, int totadd)
}
#endif
-void BMO_slot_map_to_flag(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag)
+void BMO_slot_map_to_flag(
+ BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag)
{
GHashIterator gh_iter;
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
@@ -759,8 +764,9 @@ void *BMO_slot_buffer_alloc(BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS]
*
* Copies all elements of a certain type into an operator slot.
*/
-void BMO_slot_buffer_from_all(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
- const char *slot_name, const char htype)
+void BMO_slot_buffer_from_all(
+ BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
+ const char *slot_name, const char htype)
{
BMOpSlot *output = BMO_slot_get(slot_args, slot_name);
int totelement = 0, i = 0;
@@ -809,9 +815,10 @@ void BMO_slot_buffer_from_all(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_
* Copies elements of a certain type, which have a certain header flag
* enabled/disabled into a slot for an operator.
*/
-static void bmo_slot_buffer_from_hflag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag,
- const bool test_for_enabled)
+static void bmo_slot_buffer_from_hflag(
+ BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag,
+ const bool test_for_enabled)
{
BMOpSlot *output = BMO_slot_get(slot_args, slot_name);
int totelement = 0, i = 0;
@@ -872,16 +879,18 @@ static void bmo_slot_buffer_from_hflag(BMesh *bm, BMOperator *op, BMOpSlot slot_
}
}
-void BMO_slot_buffer_from_enabled_hflag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag)
+void BMO_slot_buffer_from_enabled_hflag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag)
{
bmo_slot_buffer_from_hflag(bm, op, slot_args, slot_name, htype, hflag, true);
}
-void BMO_slot_buffer_from_disabled_hflag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag)
+void BMO_slot_buffer_from_disabled_hflag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag)
{
bmo_slot_buffer_from_hflag(bm, op, slot_args, slot_name, htype, hflag, false);
}
@@ -927,9 +936,10 @@ void *BMO_slot_buffer_get_single(BMOpSlot *slot)
/**
* Copies the values from another slot to the end of the output slot.
*/
-void _bmo_slot_buffer_append(BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
- BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
- struct MemArena *arena_dst)
+void _bmo_slot_buffer_append(
+ BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const char *slot_name_dst,
+ BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_name_src,
+ struct MemArena *arena_dst)
{
BMOpSlot *slot_dst = BMO_slot_get(slot_args_dst, slot_name_dst);
BMOpSlot *slot_src = BMO_slot_get(slot_args_src, slot_name_src);
@@ -964,10 +974,11 @@ void _bmo_slot_buffer_append(BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS], const cha
* Copies elements of a certain type, which have a certain flag set
* into an output slot for an operator.
*/
-static void bmo_slot_buffer_from_flag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag,
- const bool test_for_enabled)
+static void bmo_slot_buffer_from_flag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag,
+ const bool test_for_enabled)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
int totelement, i = 0;
@@ -1026,16 +1037,18 @@ static void bmo_slot_buffer_from_flag(BMesh *bm, BMOperator *op,
}
}
-void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag)
+void BMO_slot_buffer_from_enabled_flag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag)
{
bmo_slot_buffer_from_flag(bm, op, slot_args, slot_name, htype, oflag, true);
}
-void BMO_slot_buffer_from_disabled_flag(BMesh *bm, BMOperator *op,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag)
+void BMO_slot_buffer_from_disabled_flag(
+ BMesh *bm, BMOperator *op,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag)
{
bmo_slot_buffer_from_flag(bm, op, slot_args, slot_name, htype, oflag, false);
}
@@ -1046,9 +1059,10 @@ void BMO_slot_buffer_from_disabled_flag(BMesh *bm, BMOperator *op,
* Header Flags elements in a slots buffer, automatically
* using the selection API where appropriate.
*/
-void BMO_slot_buffer_hflag_enable(BMesh *bm,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag, const bool do_flush)
+void BMO_slot_buffer_hflag_enable(
+ BMesh *bm,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag, const bool do_flush)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
BMElem **data = (BMElem **)slot->data.buf;
@@ -1082,9 +1096,10 @@ void BMO_slot_buffer_hflag_enable(BMesh *bm,
* Removes flags from elements in a slots buffer, automatically
* using the selection API where appropriate.
*/
-void BMO_slot_buffer_hflag_disable(BMesh *bm,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const char hflag, const bool do_flush)
+void BMO_slot_buffer_hflag_disable(
+ BMesh *bm,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const char hflag, const bool do_flush)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
BMElem **data = (BMElem **)slot->data.buf;
@@ -1116,9 +1131,10 @@ void BMO_slot_buffer_hflag_disable(BMesh *bm,
*
* Flags elements in a slots buffer
*/
-void BMO_slot_buffer_flag_enable(BMesh *bm,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag)
+void BMO_slot_buffer_flag_enable(
+ BMesh *bm,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
BMHeader **data = slot->data.p;
@@ -1140,9 +1156,10 @@ void BMO_slot_buffer_flag_enable(BMesh *bm,
*
* Removes flags from elements in a slots buffer
*/
-void BMO_slot_buffer_flag_disable(BMesh *bm,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char htype, const short oflag)
+void BMO_slot_buffer_flag_disable(
+ BMesh *bm,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char htype, const short oflag)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
BMHeader **data = (BMHeader **)slot->data.buf;
@@ -1394,9 +1411,10 @@ void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char
* \param restrictmask restricts the iteration to certain element types
* (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
* over an element buffer (not a mapping). */
-void *BMO_iter_new(BMOIter *iter,
- BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
- const char restrictmask)
+void *BMO_iter_new(
+ BMOIter *iter,
+ BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name,
+ const char restrictmask)
{
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h
index f39fe29b596..d9961e589da 100644
--- a/source/blender/bmesh/intern/bmesh_operators.h
+++ b/source/blender/bmesh/intern/bmesh_operators.h
@@ -46,6 +46,7 @@ enum {
SUBD_FALLOFF_ROOT,
SUBD_FALLOFF_SHARP,
SUBD_FALLOFF_LIN,
+ SUBD_FALLOFF_INVSQUARE = 7, /* matching PROP_INVSQUARE */
};
enum {
@@ -130,14 +131,15 @@ extern const BMOpDefine *bmo_opdefines[];
extern const int bmo_opdefines_total;
/*------specific operator helper functions-------*/
-void BM_mesh_esubdivide(BMesh *bm, const char edge_hflag,
- const float smooth, const short smooth_falloff, const bool use_smooth_even,
- const float fractal, const float along_normal,
- const int numcuts,
- const int seltype, const int cornertype,
- const short use_single_edge, const short use_grid_fill,
- const short use_only_quads,
- const int seed);
+void BM_mesh_esubdivide(
+ BMesh *bm, const char edge_hflag,
+ const float smooth, const short smooth_falloff, const bool use_smooth_even,
+ const float fractal, const float along_normal,
+ const int numcuts,
+ const int seltype, const int cornertype,
+ const short use_single_edge, const short use_grid_fill,
+ const short use_only_quads,
+ const int seed);
#include "intern/bmesh_operator_api_inline.h"
diff --git a/source/blender/bmesh/intern/bmesh_operators_private.h b/source/blender/bmesh/intern/bmesh_operators_private.h
index 979f7d2640a..8b9c25bf95c 100644
--- a/source/blender/bmesh/intern/bmesh_operators_private.h
+++ b/source/blender/bmesh/intern/bmesh_operators_private.h
@@ -54,6 +54,7 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op);
void bmo_create_monkey_exec(BMesh *bm, BMOperator *op);
void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op);
void bmo_create_vert_exec(BMesh *bm, BMOperator *op);
+//void bmo_create_strand_exec(BMesh *bm, BMOperator *op);
void bmo_delete_exec(BMesh *bm, BMOperator *op);
void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op);
void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op);
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index bc06ba2c9b1..d2d31d6a562 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -102,8 +102,9 @@ static float bm_face_calc_poly_normal(const BMFace *f, float n[3])
* Same as #calc_poly_normal and #bm_face_calc_poly_normal
* but takes an array of vertex locations.
*/
-static float bm_face_calc_poly_normal_vertex_cos(BMFace *f, float r_no[3],
- float const (*vertexCos)[3])
+static float bm_face_calc_poly_normal_vertex_cos(
+ BMFace *f, float r_no[3],
+ float const (*vertexCos)[3])
{
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
BMLoop *l_iter = l_first;
@@ -127,8 +128,9 @@ static float bm_face_calc_poly_normal_vertex_cos(BMFace *f, float r_no[3],
/**
* \brief COMPUTE POLY CENTER (BMFace)
*/
-static void bm_face_calc_poly_center_mean_vertex_cos(BMFace *f, float r_cent[3],
- float const (*vertexCos)[3])
+static void bm_face_calc_poly_center_mean_vertex_cos(
+ BMFace *f, float r_cent[3],
+ float const (*vertexCos)[3])
{
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
BMLoop *l_iter = l_first;
@@ -548,8 +550,9 @@ void BM_face_normal_update(BMFace *f)
}
/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
-float BM_face_calc_normal_vcos(BMesh *bm, BMFace *f, float r_no[3],
- float const (*vertexCos)[3])
+float BM_face_calc_normal_vcos(
+ BMesh *bm, BMFace *f, float r_no[3],
+ float const (*vertexCos)[3])
{
BMLoop *l;
@@ -607,8 +610,9 @@ float BM_face_calc_normal_subset(BMLoop *l_first, BMLoop *l_last, float r_no[3])
}
/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
-void BM_face_calc_center_mean_vcos(BMesh *bm, BMFace *f, float r_cent[3],
- float const (*vertexCos)[3])
+void BM_face_calc_center_mean_vcos(
+ BMesh *bm, BMFace *f, float r_cent[3],
+ float const (*vertexCos)[3])
{
/* must have valid index data */
BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h
index 9980b59a298..582b4248c7d 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -36,16 +36,18 @@ void BM_bmesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_loopt
void BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, unsigned int (*r_index)[3]);
float BM_face_calc_normal(const BMFace *f, float r_no[3]) ATTR_NONNULL();
-float BM_face_calc_normal_vcos(BMesh *bm, BMFace *f, float r_no[3],
- float const (*vertexCos)[3]) ATTR_NONNULL();
+float BM_face_calc_normal_vcos(
+ BMesh *bm, BMFace *f, float r_no[3],
+ float const (*vertexCos)[3]) ATTR_NONNULL();
float BM_face_calc_normal_subset(BMLoop *l_first, BMLoop *l_last, float r_no[3]) ATTR_NONNULL();
float BM_face_calc_area(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
float BM_face_calc_perimeter(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BM_face_calc_plane(BMFace *f, float r_plane[3]) ATTR_NONNULL();
void BM_face_calc_center_bounds(BMFace *f, float center[3]) ATTR_NONNULL();
void BM_face_calc_center_mean(BMFace *f, float center[3]) ATTR_NONNULL();
-void BM_face_calc_center_mean_vcos(BMesh *bm, BMFace *f, float r_cent[3],
- float const (*vertexCos)[3]) ATTR_NONNULL();
+void BM_face_calc_center_mean_vcos(
+ BMesh *bm, BMFace *f, float r_cent[3],
+ float const (*vertexCos)[3]) ATTR_NONNULL();
void BM_face_calc_center_mean_weighted(BMFace *f, float center[3]) ATTR_NONNULL();
void BM_face_normal_update(BMFace *f) ATTR_NONNULL();
diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h
index 102a677943b..814015a2a74 100644
--- a/source/blender/bmesh/intern/bmesh_private.h
+++ b/source/blender/bmesh/intern/bmesh_private.h
@@ -54,6 +54,7 @@ int bmesh_elem_check(void *element, const char htype);
#endif
int bmesh_radial_length(const BMLoop *l);
+int bmesh_disk_count_ex(const BMVert *v, const int count_max);
int bmesh_disk_count(const BMVert *v);
/**
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
index c3be768aa09..182bd17c486 100644
--- a/source/blender/bmesh/intern/bmesh_queries.c
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -38,6 +38,8 @@
#include "BLI_linklist.h"
#include "BLI_stackdefines.h"
+#include "BKE_customdata.h"
+
#include "bmesh.h"
#include "intern/bmesh_private.h"
@@ -255,6 +257,36 @@ BMFace *BM_vert_pair_share_face_by_len(
return f_cur;
}
+BMFace *BM_edge_pair_share_face_by_len(
+ BMEdge *e_a, BMEdge *e_b,
+ BMLoop **r_l_a, BMLoop **r_l_b,
+ const bool allow_adjacent)
+{
+ BMLoop *l_cur_a = NULL, *l_cur_b = NULL;
+ BMFace *f_cur = NULL;
+
+ if (e_a->l && e_b->l) {
+ BMIter iter;
+ BMLoop *l_a, *l_b;
+
+ BM_ITER_ELEM (l_a, &iter, e_a, BM_LOOPS_OF_EDGE) {
+ if ((f_cur == NULL) || (l_a->f->len < f_cur->len)) {
+ l_b = BM_face_edge_share_loop(l_a->f, e_b);
+ if (l_b && (allow_adjacent || !BM_loop_is_adjacent(l_a, l_b))) {
+ f_cur = l_a->f;
+ l_cur_a = l_a;
+ l_cur_b = l_b;
+ }
+ }
+ }
+ }
+
+ *r_l_a = l_cur_a;
+ *r_l_b = l_cur_b;
+
+ return f_cur;
+}
+
static float bm_face_calc_split_dot(BMLoop *l_a, BMLoop *l_b)
{
float no[2][3];
@@ -501,10 +533,10 @@ bool BM_verts_in_face(BMVert **varr, int len, BMFace *f)
/**
* Returns whether or not a given edge is part of a given face.
*/
-bool BM_edge_in_face(BMEdge *e, BMFace *f)
+bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
{
if (e->l) {
- BMLoop *l_iter, *l_first;
+ const BMLoop *l_iter, *l_first;
l_iter = l_first = e->l;
do {
@@ -750,6 +782,11 @@ int BM_vert_edge_count(const BMVert *v)
return bmesh_disk_count(v);
}
+int BM_vert_edge_count_ex(const BMVert *v, const int count_max)
+{
+ return bmesh_disk_count_ex(v, count_max);
+}
+
int BM_vert_edge_count_nonwire(const BMVert *v)
{
int count = 0;
@@ -770,13 +807,30 @@ int BM_edge_face_count(const BMEdge *e)
int count = 0;
if (e->l) {
- BMLoop *l_iter;
- BMLoop *l_first;
+ BMLoop *l_iter, *l_first;
l_iter = l_first = e->l;
+ do {
+ count++;
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+
+ return count;
+}
+
+int BM_edge_face_count_ex(const BMEdge *e, const int count_max)
+{
+ int count = 0;
+
+ if (e->l) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = e->l;
do {
count++;
+ if (count == count_max) {
+ break;
+ }
} while ((l_iter = l_iter->radial_next) != l_first);
}
@@ -792,6 +846,21 @@ int BM_vert_face_count(const BMVert *v)
return bmesh_disk_facevert_count(v);
}
+int BM_vert_face_count_ex(const BMVert *v, int count_max)
+{
+ return bmesh_disk_facevert_count_ex(v, count_max);
+}
+
+/**
+ * Return true if the vertex is connected to _any_ faces.
+ *
+ * same as ``BM_vert_face_count(v) != 0`` or ``BM_vert_find_first_loop(v) == NULL``
+ */
+bool BM_vert_face_check(BMVert *v)
+{
+ return v->e && (bmesh_disk_faceedge_find_first(v->e, v) != NULL);
+}
+
/**
* Tests whether or not the vertex is part of a wire edge.
* (ie: has no faces attached to it)
@@ -824,9 +893,9 @@ bool BM_vert_is_wire(const BMVert *v)
*/
bool BM_vert_is_manifold(const BMVert *v)
{
- BMEdge *e, *e_old;
- BMLoop *l;
- int len, count, flag;
+ BMEdge *e_iter, *e_first, *e_prev;
+ BMLoop *l_iter, *l_first;
+ int loop_num = 0, loop_num_region = 0, boundary_num = 0;
if (v->e == NULL) {
/* loose vert */
@@ -834,50 +903,150 @@ bool BM_vert_is_manifold(const BMVert *v)
}
/* count edges while looking for non-manifold edges */
- len = 0;
- e_old = e = v->e;
+ e_first = e_iter = v->e;
+ l_first = e_iter->l ? e_iter->l : NULL;
do {
/* loose edge or edge shared by more than two faces,
* edges with 1 face user are OK, otherwise we could
* use BM_edge_is_manifold() here */
- if (e->l == NULL || bmesh_radial_length(e->l) > 2) {
+ if (e_iter->l == NULL || (e_iter->l != e_iter->l->radial_next->radial_next)) {
return false;
}
- len++;
- } while ((e = bmesh_disk_edge_next(e, v)) != e_old);
-
- count = 1;
- flag = 1;
- e = NULL;
- e_old = v->e;
- l = e_old->l;
- while (e != e_old) {
- l = (l->v == v) ? l->prev : l->next;
- e = l->e;
- count++; /* count the edges */
-
- if (flag && l->radial_next == l) {
- /* we've hit the edge of an open mesh, reset once */
- flag = 0;
- count = 1;
- e_old = e;
- e = NULL;
- l = e_old->l;
- }
- else if (l->radial_next == l) {
- /* break the loop */
- e = e_old;
+
+ /* count radial loops */
+ if (e_iter->l->v == v) {
+ loop_num += 1;
+ }
+
+ if (!BM_edge_is_boundary(e_iter)) {
+ /* non boundary check opposite loop */
+ if (e_iter->l->radial_next->v == v) {
+ loop_num += 1;
+ }
}
else {
- l = l->radial_next;
+ /* start at the boundary */
+ l_first = e_iter->l;
+ boundary_num += 1;
+ /* >2 boundaries cant be manifold */
+ if (boundary_num == 3) {
+ return false;
+ }
}
- }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
- if (count < len) {
- /* vert shared by multiple regions */
- return false;
+ e_first = l_first->e;
+ l_first = (l_first->v == v) ? l_first : l_first->next;
+ BLI_assert(l_first->v == v);
+
+ l_iter = l_first;
+ e_prev = e_first;
+
+ do {
+ loop_num_region += 1;
+ } while (((l_iter = BM_vert_step_fan_loop(l_iter, &e_prev)) != l_first) && (l_iter != NULL));
+
+ return (loop_num == loop_num_region);
+}
+
+#define LOOP_VISIT _FLAG_WALK
+#define EDGE_VISIT _FLAG_WALK
+
+static int bm_loop_region_count__recursive(BMEdge *e, BMVert *v)
+{
+ BMLoop *l_iter, *l_first;
+ int count = 0;
+
+ BLI_assert(!BM_ELEM_API_FLAG_TEST(e, EDGE_VISIT));
+ BM_ELEM_API_FLAG_ENABLE(e, EDGE_VISIT);
+
+ l_iter = l_first = e->l;
+ do {
+ if (l_iter->v == v) {
+ BMEdge *e_other = l_iter->prev->e;
+ if (!BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) {
+ BM_ELEM_API_FLAG_ENABLE(l_iter, LOOP_VISIT);
+ count += 1;
+ }
+ if (!BM_ELEM_API_FLAG_TEST(e_other, EDGE_VISIT)) {
+ count += bm_loop_region_count__recursive(e_other, v);
+ }
+ }
+ else if (l_iter->next->v == v) {
+ BMEdge *e_other = l_iter->next->e;
+ if (!BM_ELEM_API_FLAG_TEST(l_iter->next, LOOP_VISIT)) {
+ BM_ELEM_API_FLAG_ENABLE(l_iter->next, LOOP_VISIT);
+ count += 1;
+ }
+ if (!BM_ELEM_API_FLAG_TEST(e_other, EDGE_VISIT)) {
+ count += bm_loop_region_count__recursive(e_other, v);
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+
+ return count;
+}
+
+static int bm_loop_region_count__clear(BMLoop *l)
+{
+ int count = 0;
+ BMEdge *e_iter, *e_first;
+
+ /* clear flags */
+ e_iter = e_first = l->e;
+ do {
+ BM_ELEM_API_FLAG_DISABLE(e_iter, EDGE_VISIT);
+ if (e_iter->l) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = e_iter->l;
+ do {
+ if (l_iter->v == l->v) {
+ BM_ELEM_API_FLAG_DISABLE(l_iter, LOOP_VISIT);
+ count += 1;
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, l->v)) != e_first);
+
+ return count;
+}
+
+/**
+ * The number of loops connected to this loop (not including disconnected regions).
+ */
+int BM_loop_region_loops_count_ex(BMLoop *l, int *r_loop_total)
+{
+ const int count = bm_loop_region_count__recursive(l->e, l->v);
+ const int count_total = bm_loop_region_count__clear(l);
+ if (r_loop_total) {
+ *r_loop_total = count_total;
}
+ return count;
+}
+
+#undef LOOP_VISIT
+#undef EDGE_VISIT
+
+int BM_loop_region_loops_count(BMLoop *l)
+{
+ return BM_loop_region_loops_count_ex(l, NULL);
+}
+/**
+ * A version of #BM_vert_is_manifold
+ * which only checks if we're connected to multiple isolated regions.
+ */
+bool BM_vert_is_manifold_region(const BMVert *v)
+{
+ BMLoop *l_first = BM_vert_find_first_loop((BMVert *)v);
+ if (l_first) {
+ int count, count_total;
+ count = BM_loop_region_loops_count_ex(l_first, &count_total);
+ return (count == count_total);
+ }
return true;
}
@@ -902,6 +1071,53 @@ bool BM_edge_is_convex(const BMEdge *e)
return true;
}
+/**
+ * \return true when loop customdata is contiguous.
+ */
+bool BM_edge_is_contiguous_loop_cd(
+ const BMEdge *e,
+ const int cd_loop_type, const int cd_loop_offset)
+{
+ BLI_assert(cd_loop_offset != -1);
+
+ if (e->l && e->l->radial_next != e->l) {
+ const BMLoop *l_base_v1 = e->l;
+ const BMLoop *l_base_v2 = e->l->next;
+ const void *l_base_cd_v1 = BM_ELEM_CD_GET_VOID_P(l_base_v1, cd_loop_offset);
+ const void *l_base_cd_v2 = BM_ELEM_CD_GET_VOID_P(l_base_v2, cd_loop_offset);
+ const BMLoop *l_iter = e->l->radial_next;
+ do {
+ const BMLoop *l_iter_v1;
+ const BMLoop *l_iter_v2;
+ const void *l_iter_cd_v1;
+ const void *l_iter_cd_v2;
+
+ if (l_iter->v == l_base_v1->v) {
+ l_iter_v1 = l_iter;
+ l_iter_v2 = l_iter->next;
+ }
+ else {
+ l_iter_v1 = l_iter->next;
+ l_iter_v2 = l_iter;
+ }
+ BLI_assert((l_iter_v1->v == l_base_v1->v) &&
+ (l_iter_v2->v == l_base_v2->v));
+
+ l_iter_cd_v1 = BM_ELEM_CD_GET_VOID_P(l_iter_v1, cd_loop_offset);
+ l_iter_cd_v2 = BM_ELEM_CD_GET_VOID_P(l_iter_v2, cd_loop_offset);
+
+
+ if ((CustomData_data_equals(cd_loop_type, l_base_cd_v1, l_iter_cd_v1) == 0) ||
+ (CustomData_data_equals(cd_loop_type, l_base_cd_v2, l_iter_cd_v2) == 0))
+ {
+ return false;
+ }
+
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ }
+ return true;
+}
+
bool BM_vert_is_boundary(const BMVert *v)
{
if (v->e) {
@@ -1147,8 +1363,9 @@ BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e)
* \note This is in fact quite a simple check, mainly include this function so the intent is more obvious.
* We know these 2 verts will _always_ make up the loops edge
*/
-void BM_edge_ordered_verts_ex(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2,
- const BMLoop *edge_loop)
+void BM_edge_ordered_verts_ex(
+ const BMEdge *edge, BMVert **r_v1, BMVert **r_v2,
+ const BMLoop *edge_loop)
{
BLI_assert(edge_loop->e == edge);
(void)edge; /* quiet warning in release build */
@@ -1183,7 +1400,7 @@ bool BM_loop_is_convex(const BMLoop *l)
*
* \return angle in radians
*/
-float BM_loop_calc_face_angle(BMLoop *l)
+float BM_loop_calc_face_angle(const BMLoop *l)
{
return angle_v3v3v3(l->prev->v->co,
l->v->co,
@@ -1198,7 +1415,7 @@ float BM_loop_calc_face_angle(BMLoop *l)
* \param l The loop to calculate the normal at
* \param r_normal Resulting normal
*/
-void BM_loop_calc_face_normal(BMLoop *l, float r_normal[3])
+void BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
{
if (normal_tri_v3(r_normal,
l->prev->v->co,
@@ -1220,7 +1437,7 @@ void BM_loop_calc_face_normal(BMLoop *l, float r_normal[3])
* \param l The loop to calculate the direction at
* \param r_dir Resulting direction
*/
-void BM_loop_calc_face_direction(BMLoop *l, float r_dir[3])
+void BM_loop_calc_face_direction(const BMLoop *l, float r_dir[3])
{
float v_prev[3];
float v_next[3];
@@ -1244,7 +1461,7 @@ void BM_loop_calc_face_direction(BMLoop *l, float r_dir[3])
* \param l The loop to calculate the tangent at
* \param r_tangent Resulting tangent
*/
-void BM_loop_calc_face_tangent(BMLoop *l, float r_tangent[3])
+void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3])
{
float v_prev[3];
float v_next[3];
@@ -1356,7 +1573,7 @@ void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_ta
*
* \returns the angle in radians
*/
-float BM_vert_calc_edge_angle_ex(BMVert *v, const float fallback)
+float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback)
{
BMEdge *e1, *e2;
@@ -1378,7 +1595,7 @@ float BM_vert_calc_edge_angle_ex(BMVert *v, const float fallback)
}
}
-float BM_vert_calc_edge_angle(BMVert *v)
+float BM_vert_calc_edge_angle(const BMVert *v)
{
return BM_vert_calc_edge_angle_ex(v, DEG2RADF(90.0f));
}
@@ -1387,14 +1604,14 @@ float BM_vert_calc_edge_angle(BMVert *v)
* \note this isn't optimal to run on an array of verts,
* see 'solidify_add_thickness' for a function which runs on an array.
*/
-float BM_vert_calc_shell_factor(BMVert *v)
+float BM_vert_calc_shell_factor(const BMVert *v)
{
BMIter iter;
BMLoop *l;
float accum_shell = 0.0f;
float accum_angle = 0.0f;
- BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ BM_ITER_ELEM (l, &iter, (BMVert *)v, BM_LOOPS_OF_VERT) {
const float face_angle = BM_loop_calc_face_angle(l);
accum_shell += shell_v3v3_normalized_to_dist(v->no, l->f->no) * face_angle;
accum_angle += face_angle;
@@ -1409,15 +1626,15 @@ float BM_vert_calc_shell_factor(BMVert *v)
}
/* alternate version of #BM_vert_calc_shell_factor which only
* uses 'hflag' faces, but falls back to all if none found. */
-float BM_vert_calc_shell_factor_ex(BMVert *v, const float no[3], const char hflag)
+float BM_vert_calc_shell_factor_ex(const BMVert *v, const float no[3], const char hflag)
{
BMIter iter;
- BMLoop *l;
+ const BMLoop *l;
float accum_shell = 0.0f;
float accum_angle = 0.0f;
int tot_sel = 0, tot = 0;
- BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ BM_ITER_ELEM (l, &iter, (BMVert *)v, BM_LOOPS_OF_VERT) {
if (BM_elem_flag_test(l->f, hflag)) { /* <-- main difference to BM_vert_calc_shell_factor! */
const float face_angle = BM_loop_calc_face_angle(l);
accum_shell += shell_v3v3_normalized_to_dist(no, l->f->no) * face_angle;
@@ -1446,15 +1663,15 @@ float BM_vert_calc_shell_factor_ex(BMVert *v, const float no[3], const char hfla
* \note quite an obscure function.
* used in bmesh operators that have a relative scale options,
*/
-float BM_vert_calc_mean_tagged_edge_length(BMVert *v)
+float BM_vert_calc_mean_tagged_edge_length(const BMVert *v)
{
BMIter iter;
BMEdge *e;
int tot;
float length = 0.0f;
- BM_ITER_ELEM_INDEX (e, &iter, v, BM_EDGES_OF_VERT, tot) {
- BMVert *v_other = BM_edge_other_vert(e, v);
+ BM_ITER_ELEM_INDEX (e, &iter, (BMVert *)v, BM_EDGES_OF_VERT, tot) {
+ const BMVert *v_other = BM_edge_other_vert(e, v);
if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
length += BM_edge_calc_length(e);
}
@@ -1600,85 +1817,59 @@ BMEdge *BM_edge_find_double(BMEdge *e)
*/
bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface)
{
- BMVert *v_search = varr[0]; /* we can search any of the verts in the array */
- BMIter liter;
- BMLoop *l_search;
-
-
-#if 0
- BM_ITER_ELEM (f, &viter, v_search, BM_FACES_OF_VERT) {
- if (f->len == len) {
- if (BM_verts_in_face(varr, len, f)) {
- if (r_existface) {
- *r_existface = f;
- }
- return true;
- }
- }
- }
-
- if (r_existface) {
- *r_existface = NULL;
- }
- return false;
-
-#else
-
- /* faster to do the flagging once, and inline */
- bool is_init = false;
- bool is_found = false;
- int i;
-
-
- BM_ITER_ELEM (l_search, &liter, v_search, BM_LOOPS_OF_VERT) {
- if (l_search->f->len == len) {
- if (is_init == false) {
- is_init = true;
- for (i = 0; i < len; i++) {
- BLI_assert(!BM_ELEM_API_FLAG_TEST(varr[i], _FLAG_OVERLAP));
- BM_ELEM_API_FLAG_ENABLE(varr[i], _FLAG_OVERLAP);
- }
- }
+ if (varr[0]->e) {
+ BMEdge *e_iter, *e_first;
+ e_iter = e_first = varr[0]->e;
- is_found = true;
-
- {
- BMLoop *l_iter;
-
- /* skip ourselves */
- l_iter = l_search->next;
+ /* would normally use BM_LOOPS_OF_VERT, but this runs so often,
+ * its faster to iterate on the data directly */
+ do {
+ if (e_iter->l) {
+ BMLoop *l_iter_radial, *l_first_radial;
+ l_iter_radial = l_first_radial = e_iter->l;
do {
- if (!BM_ELEM_API_FLAG_TEST(l_iter->v, _FLAG_OVERLAP)) {
- is_found = false;
- break;
+ if ((l_iter_radial->v == varr[0]) &&
+ (l_iter_radial->f->len == len))
+ {
+ /* the fist 2 verts match, now check the remaining (len - 2) faces do too
+ * winding isn't known, so check in both directions */
+ int i_walk = 2;
+
+ if (l_iter_radial->next->v == varr[1]) {
+ BMLoop *l_walk = l_iter_radial->next->next;
+ do {
+ if (l_walk->v != varr[i_walk]) {
+ break;
+ }
+ } while ((l_walk = l_walk->next), ++i_walk != len);
+ }
+ else if (l_iter_radial->prev->v == varr[1]) {
+ BMLoop *l_walk = l_iter_radial->prev->prev;
+ do {
+ if (l_walk->v != varr[i_walk]) {
+ break;
+ }
+ } while ((l_walk = l_walk->prev), ++i_walk != len);
+ }
+
+ if (i_walk == len) {
+ if (r_existface) {
+ *r_existface = l_iter_radial->f;
+ }
+ return true;
+ }
}
- } while ((l_iter = l_iter->next) != l_search);
- }
+ } while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial);
- if (is_found) {
- if (r_existface) {
- *r_existface = l_search->f;
- }
- break;
}
- }
- }
-
- if (is_found == false) {
- if (r_existface) {
- *r_existface = NULL;
- }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, varr[0])) != e_first);
}
- if (is_init == true) {
- for (i = 0; i < len; i++) {
- BM_ELEM_API_FLAG_DISABLE(varr[i], _FLAG_OVERLAP);
- }
+ if (r_existface) {
+ *r_existface = NULL;
}
-
- return is_found;
-#endif
+ return false;
}
@@ -1773,8 +1964,8 @@ bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len)
if (/* non-boundary edge */
BM_elem_flag_test(e, BM_ELEM_INTERNAL_TAG) == false &&
/* ...using boundary verts */
- BM_elem_flag_test(e->v1, BM_ELEM_INTERNAL_TAG) == true &&
- BM_elem_flag_test(e->v2, BM_ELEM_INTERNAL_TAG) == true)
+ BM_elem_flag_test(e->v1, BM_ELEM_INTERNAL_TAG) &&
+ BM_elem_flag_test(e->v2, BM_ELEM_INTERNAL_TAG))
{
int tot_face_tag = 0;
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
@@ -2117,9 +2308,10 @@ float BM_mesh_calc_volume(BMesh *bm, bool is_signed)
* (having both set is supported too).
* \return The number of groups found.
*/
-int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
- BMElemFilterFunc filter_fn, void *user_data,
- const char hflag_test, const char htype_step)
+int BM_mesh_calc_face_groups(
+ BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
+ BMElemFilterFunc filter_fn, void *user_data,
+ const char hflag_test, const char htype_step)
{
#ifdef DEBUG
int group_index_len = 1;
@@ -2274,9 +2466,10 @@ int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_inde
* \note Unlike #BM_mesh_calc_face_groups there is no 'htype_step' argument,
* since we always walk over verts.
*/
-int BM_mesh_calc_edge_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
- BMElemFilterFunc filter_fn, void *user_data,
- const char hflag_test)
+int BM_mesh_calc_edge_groups(
+ BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
+ BMElemFilterFunc filter_fn, void *user_data,
+ const char hflag_test)
{
#ifdef DEBUG
int group_index_len = 1;
@@ -2301,7 +2494,7 @@ int BM_mesh_calc_edge_groups(BMesh *bm, int *r_groups_array, int (**r_group_inde
BMEdge *e;
int i;
- STACK_INIT(group_array, bm->totface);
+ STACK_INIT(group_array, bm->totedge);
/* init the array */
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
@@ -2405,6 +2598,9 @@ float bmesh_subd_falloff_calc(const int falloff, float val)
break;
case SUBD_FALLOFF_LIN:
break;
+ case SUBD_FALLOFF_INVSQUARE:
+ val = val * (2.0f - val);
+ break;
default:
BLI_assert(0);
break;
diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h
index 4ee5588ba0b..f96d99fd452 100644
--- a/source/blender/bmesh/intern/bmesh_queries.h
+++ b/source/blender/bmesh/intern/bmesh_queries.h
@@ -31,7 +31,7 @@ bool BM_vert_in_face(BMVert *v, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNU
int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_verts_in_face(BMVert **varr, int len, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_edge_in_face(BMEdge *e, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_edge_in_face(const BMEdge *e, const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_in_loop(const BMEdge *e, const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -64,32 +64,54 @@ BMFace *BM_vert_pair_share_face_by_angle(
BMLoop **r_l_a, BMLoop **r_l_b,
const bool allow_adjacent) ATTR_NONNULL();
+BMFace *BM_edge_pair_share_face_by_len(
+ BMEdge *e_a, BMEdge *e_b,
+ BMLoop **r_l_a, BMLoop **r_l_b,
+ const bool allow_adjacent) ATTR_NONNULL();
+
int BM_vert_edge_count_nonwire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+#define BM_vert_edge_count_is_equal(v, n) (BM_vert_edge_count_ex(v, (n) + 1) == n)
+#define BM_vert_edge_count_is_over(v, n) (BM_vert_edge_count_ex(v, (n) + 1) == (n) + 1)
+int BM_vert_edge_count_ex(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BM_vert_edge_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+#define BM_edge_face_count_is_equal(e, n) (BM_edge_face_count_ex(e, (n) + 1) == n)
+#define BM_edge_face_count_is_over(e, n) (BM_edge_face_count_ex(e, (n) + 1) == (n) + 1)
+int BM_edge_face_count_ex(const BMEdge *e, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BM_edge_face_count(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+#define BM_vert_face_count_is_equal(v, n) (BM_vert_face_count_ex(v, (n) + 1) == n)
+#define BM_vert_face_count_is_over(v, n) (BM_vert_face_count_ex(v, (n) + 1) == (n) + 1)
+int BM_vert_face_count_ex(const BMVert *v, int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BM_vert_face_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_edge_pair(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_vert_face_check(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_manifold(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_vert_is_manifold_region(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_boundary(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_edge_is_convex(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_edge_is_contiguous_loop_cd(
+ const BMEdge *e,
+ const int cd_loop_type, const int cd_loop_offset)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+int BM_loop_region_loops_count_ex(BMLoop *l, int *r_loop_total) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+int BM_loop_region_loops_count(BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
bool BM_loop_is_convex(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
float BM_loop_point_side_of_loop_test(const BMLoop *l, const float co[3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_loop_calc_face_angle(BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void BM_loop_calc_face_normal(BMLoop *l, float r_normal[3]) ATTR_NONNULL();
-void BM_loop_calc_face_direction(BMLoop *l, float r_normal[3]);
-void BM_loop_calc_face_tangent(BMLoop *l, float r_tangent[3]);
+float BM_loop_calc_face_angle(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
+void BM_loop_calc_face_direction(const BMLoop *l, float r_normal[3]);
+void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3]);
float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
float BM_edge_calc_face_angle(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -97,11 +119,11 @@ float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, const float fallback)
float BM_edge_calc_face_angle_signed(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3]) ATTR_NONNULL();
-float BM_vert_calc_edge_angle(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_vert_calc_edge_angle_ex(BMVert *v, const float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_vert_calc_shell_factor(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_vert_calc_shell_factor_ex(BMVert *v, const float no[3], const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_vert_calc_mean_tagged_edge_length(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_vert_calc_edge_angle(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_vert_calc_shell_factor(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_vert_calc_shell_factor_ex(const BMVert *v, const float no[3], const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_vert_calc_mean_tagged_edge_length(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMLoop *BM_face_find_shortest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMLoop *BM_face_find_longest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -132,8 +154,9 @@ BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v) ATTR_WARN_UNUSED_RESULT AT
BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2) ATTR_NONNULL();
-void BM_edge_ordered_verts_ex(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2,
- const BMLoop *edge_loop) ATTR_NONNULL();
+void BM_edge_ordered_verts_ex(
+ const BMEdge *edge, BMVert **r_v1, BMVert **r_v2,
+ const BMLoop *edge_loop) ATTR_NONNULL();
bool BM_vert_is_all_edge_flag_test(const BMVert *v, const char hflag, const bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_all_face_flag_test(const BMVert *v, const char hflag, const bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -147,12 +170,16 @@ bool BM_face_is_normal_valid(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNU
float BM_mesh_calc_volume(BMesh *bm, bool is_signed) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
- BMElemFilterFunc filter_fn, void *user_data,
- const char hflag_test, const char htype_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
-int BM_mesh_calc_edge_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
- BMElemFilterFunc filter_fn, void *user_data,
- const char hflag_test) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+int BM_mesh_calc_face_groups(
+ BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
+ BMElemFilterFunc filter_fn, void *user_data,
+ const char hflag_test, const char htype_step)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+int BM_mesh_calc_edge_groups(
+ BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
+ BMElemFilterFunc filter_fn, void *user_data,
+ const char hflag_test)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
/* not really any good place to put this */
float bmesh_subd_falloff_calc(const int falloff, float val) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/bmesh/intern/bmesh_queries_inline.h b/source/blender/bmesh/intern/bmesh_queries_inline.h
index 1ca56beb746..430ba10fb42 100644
--- a/source/blender/bmesh/intern/bmesh_queries_inline.h
+++ b/source/blender/bmesh/intern/bmesh_queries_inline.h
@@ -30,6 +30,7 @@
* Returns whether or not a given vertex is
* is part of a given edge.
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v)
{
return (ELEM(v, e->v1, e->v2));
@@ -38,6 +39,7 @@ BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v)
/**
* Returns whether or not a given edge is part of a given loop.
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE bool BM_edge_in_loop(const BMEdge *e, const BMLoop *l)
{
return (l->e == e || l->prev->e == e);
@@ -47,6 +49,7 @@ BLI_INLINE bool BM_edge_in_loop(const BMEdge *e, const BMLoop *l)
* Returns whether or not two vertices are in
* a given edge
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3)
BLI_INLINE bool BM_verts_in_edge(const BMVert *v1, const BMVert *v2, const BMEdge *e)
{
return ((e->v1 == v1 && e->v2 == v2) ||
@@ -57,6 +60,7 @@ BLI_INLINE bool BM_verts_in_edge(const BMVert *v1, const BMVert *v2, const BMEdg
* Given a edge and one of its vertices, returns
* the other vertex.
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE BMVert *BM_edge_other_vert(BMEdge *e, const BMVert *v)
{
if (e->v1 == v) {
@@ -72,6 +76,7 @@ BLI_INLINE BMVert *BM_edge_other_vert(BMEdge *e, const BMVert *v)
* Tests whether or not the edge is part of a wire.
* (ie: has no faces attached to it)
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e)
{
return (e->l == NULL);
@@ -83,6 +88,7 @@ BLI_INLINE bool BM_edge_is_wire(const BMEdge *e)
*/
#if 1 /* fast path for checking manifold */
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e)
{
const BMLoop *l = e->l;
@@ -100,6 +106,7 @@ BLI_INLINE int BM_edge_is_manifold(BMEdge *e)
* Tests that the edge is manifold and
* that both its faces point the same way.
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e)
{
const BMLoop *l = e->l;
@@ -115,6 +122,7 @@ BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e)
*/
#if 1 /* fast path for checking boundary */
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e)
{
const BMLoop *l = e->l;
@@ -130,6 +138,7 @@ BLI_INLINE int BM_edge_is_boundary(BMEdge *e)
/**
* Tests whether one loop is next to another within the same face.
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b)
{
BLI_assert(l_a->f == l_b->f);
@@ -140,6 +149,7 @@ BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b)
/**
* Check if we have a single wire edge user.
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE bool BM_vert_is_wire_endpoint(const BMVert *v)
{
const BMEdge *e = v->e;
diff --git a/source/blender/bmesh/intern/bmesh_strands.c b/source/blender/bmesh/intern/bmesh_strands.c
new file mode 100644
index 00000000000..ae76c4761ad
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_strands.c
@@ -0,0 +1,145 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Lukas Toenne.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_strands.c
+ * \ingroup bmesh
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_mempool.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+/*
+ * STRANDS OF MESH CALLBACKS
+ */
+
+void bmstranditer__strands_of_mesh_begin(struct BMIter__elem_of_mesh *iter)
+{
+ BLI_mempool_iternew(iter->pooliter.pool, &iter->pooliter);
+}
+
+void *bmstranditer__strands_of_mesh_step(struct BMIter__elem_of_mesh *iter)
+{
+ BMVert *v;
+
+ do {
+ v = BLI_mempool_iterstep(&iter->pooliter);
+ } while (v && !BM_strands_vert_is_root(v));
+
+ return v;
+}
+
+/*
+ * VERTS OF STRAND CALLBACKS
+ */
+
+/* BMIter__vert_of_strand is not included in the union in BMIter, just make sure it is big enough */
+BLI_STATIC_ASSERT(sizeof(BMIter__vert_of_strand) <= sizeof(BMIter), "BMIter must be at least as large as BMIter__vert_of_strand")
+
+void bmstranditer__verts_of_strand_begin(struct BMIter__vert_of_strand *iter)
+{
+ iter->e_next = iter->v_next->e;
+}
+
+void *bmstranditer__verts_of_strand_step(struct BMIter__vert_of_strand *iter)
+{
+ BMVert *v_curr = iter->v_next;
+
+ if (iter->e_next) {
+ BMEdge *e_first = iter->e_next;
+
+ /* select the other vertex of the current edge */
+ iter->v_next = (iter->v_next == iter->e_next->v1 ? iter->e_next->v2 : iter->e_next->v1);
+
+ /* select the next edge of the current vertex */
+ iter->e_next = bmesh_disk_edge_next(iter->e_next, iter->v_next);
+ if (iter->e_next == e_first) {
+ /* only one edge means the last segment, terminate */
+ iter->e_next = NULL;
+ }
+ }
+ else
+ iter->v_next = NULL; /* last vertex, terminate */
+
+ return v_curr;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int BM_strands_count(BMesh *bm)
+{
+ BMVert *v;
+ BMIter iter;
+
+ int count = 0;
+ BM_ITER_STRANDS(v, &iter, bm, BM_STRANDS_OF_MESH) {
+ ++count;
+ }
+
+ return count;
+}
+
+int BM_strands_keys_count(BMVert *root)
+{
+ BMVert *v;
+ BMIter iter;
+
+ int count = 0;
+ BM_ITER_STRANDS_ELEM(v, &iter, root, BM_VERTS_OF_STRAND) {
+ ++count;
+ }
+
+ return count;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Create a new strand */
+BMVert *BM_strands_create(BMesh *bm, int len, bool set_defaults)
+{
+ float co[3] = {0.0f, 0.0f, 0.0f};
+
+ BMVert *root, *v = NULL, *vprev;
+ int k;
+
+ for (k = 0; k < len; ++k) {
+ vprev = v;
+ v = BM_vert_create(bm, co, NULL, set_defaults ? BM_CREATE_NOP : BM_CREATE_SKIP_CD);
+
+ zero_v3(v->no);
+
+ /* root */
+ if (k == 0) {
+ root = v;
+ }
+ else {
+ /*BMEdge *e =*/ BM_edge_create(bm, vprev, v, NULL, set_defaults ? BM_CREATE_NOP : BM_CREATE_SKIP_CD);
+ }
+ }
+
+ return root;
+}
diff --git a/source/blender/bmesh/intern/bmesh_strands.h b/source/blender/bmesh/intern/bmesh_strands.h
new file mode 100644
index 00000000000..cd4267f0bb3
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_strands.h
@@ -0,0 +1,215 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Lukas Toenne.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_STRANDS_H__
+#define __BMESH_STRANDS_H__
+
+/** \file blender/bmesh/intern/bmesh_strands.h
+ * \ingroup bmesh
+ */
+
+#include "BLI_utildefines.h"
+
+#include "bmesh.h"
+#include "bmesh_queries.h"
+#include "bmesh_structure.h"
+
+/* True if v is the root of a strand */
+BLI_INLINE bool BM_strands_vert_is_root(BMVert *v)
+{
+ BMEdge *e_first = v->e;
+ BMEdge *e_next;
+
+ if (!e_first)
+ return true; /* single vertex is both root and tip */
+ e_next = bmesh_disk_edge_next(e_first, v);
+
+ /* with a single edge, the vertex is either first or last of the curve;
+ * first vertex is defined as the root
+ */
+ if (e_next == e_first) {
+ if (e_first->v1 == v)
+ return true;
+ }
+ return false;
+}
+
+/* True if v is the tip of a strand */
+BLI_INLINE bool BM_strands_vert_is_tip(BMVert *v)
+{
+ BMEdge *e_first = v->e;
+ BMEdge *e_next;
+
+ if (!e_first)
+ return true; /* single vertex is both root and tip */
+ e_next = bmesh_disk_edge_next(e_first, v);
+
+ /* with a single edge, the vertex is either first or last of the curve;
+ * last vertex is defined as the tip
+ */
+ if (e_next == e_first) {
+ if (e_first->v2 == v)
+ return true;
+ }
+ return false;
+}
+
+/* Next vertex on a strand */
+BLI_INLINE BMVert *BM_strands_vert_next(BMVert *v)
+{
+ BMEdge *e_first = v->e;
+ BMEdge *e_next;
+
+ /* one of the edges leads to the previous vertex */
+ if (e_first) {
+ if (e_first->v1 == v)
+ return e_first->v2;
+
+ e_next = bmesh_disk_edge_next(e_first, v);
+ if (e_next->v1 == v)
+ return e_next->v2;
+ }
+ return NULL;
+}
+
+/* Previous vertex on a strand */
+BLI_INLINE BMVert *BM_strands_vert_prev(BMVert *v)
+{
+ BMEdge *e_first = v->e;
+ BMEdge *e_next;
+
+ /* one of the edges leads to the previous vertex */
+ if (e_first) {
+ if (e_first->v2 == v)
+ return e_first->v1;
+
+ e_next = bmesh_disk_edge_next(e_first, v);
+ if (e_next->v2 == v)
+ return e_next->v1;
+ }
+ return NULL;
+}
+
+int BM_strands_count(BMesh *bm);
+int BM_strands_keys_count(BMVert *root);
+
+/* Create a new strand */
+struct BMVert *BM_strands_create(struct BMesh *bm, int len, bool set_defaults);
+
+/* ==== Iterators ==== */
+
+typedef enum BMStrandsIterType {
+ BM_STRANDS_OF_MESH,
+ BM_VERTS_OF_STRAND,
+} BMStrandsIterType;
+
+#define BM_ITER_STRANDS(ele, iter, bm, itype) \
+ for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_strand_iter_new(iter, bm, itype, NULL); \
+ ele; \
+ BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter))
+
+#define BM_ITER_STRANDS_INDEX(ele, iter, bm, itype, indexvar) \
+ for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_strand_iter_new(iter, bm, itype, NULL), indexvar = 0; \
+ ele; \
+ BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter), (indexvar)++)
+
+#define BM_ITER_STRANDS_ELEM(ele, iter, data, itype) \
+ for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_strand_iter_new(iter, NULL, itype, data); \
+ ele; \
+ BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter))
+
+#define BM_ITER_STRANDS_ELEM_INDEX(ele, iter, data, itype, indexvar) \
+ for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_strand_iter_new(iter, NULL, itype, data), indexvar = 0; \
+ ele; \
+ BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BM_iter_step(iter), (indexvar)++)
+
+typedef struct BMIter__vert_of_strand {
+ BMVert *v_next;
+ BMEdge *e_next;
+} BMIter__vert_of_strand;
+
+void bmstranditer__strands_of_mesh_begin(struct BMIter__elem_of_mesh *iter);
+void *bmstranditer__strands_of_mesh_step(struct BMIter__elem_of_mesh *iter);
+
+void bmstranditer__verts_of_strand_begin(struct BMIter__vert_of_strand *iter);
+void *bmstranditer__verts_of_strand_step(struct BMIter__vert_of_strand *iter);
+
+BLI_INLINE bool BM_strand_iter_init(BMIter *iter, BMesh *bm, const char itype, void *data)
+{
+ /* int argtype; */
+ iter->itype = itype;
+
+ /* inlining optimizes out this switch when called with the defined type */
+ switch ((BMStrandsIterType)itype) {
+ case BM_STRANDS_OF_MESH:
+ BLI_assert(bm != NULL);
+ BLI_assert(data == NULL);
+ iter->begin = (BMIter__begin_cb)bmstranditer__strands_of_mesh_begin;
+ iter->step = (BMIter__step_cb)bmstranditer__strands_of_mesh_step;
+ iter->data.elem_of_mesh.pooliter.pool = bm->vpool;
+ break;
+ case BM_VERTS_OF_STRAND: {
+ BMVert *root;
+
+ BLI_assert(data != NULL);
+ BLI_assert(((BMElem *)data)->head.htype == BM_VERT);
+ root = (BMVert *)data;
+ BLI_assert(BM_strands_vert_is_root(root));
+ iter->begin = (BMIter__begin_cb)bmstranditer__verts_of_strand_begin;
+ iter->step = (BMIter__step_cb)bmstranditer__verts_of_strand_step;
+ ((BMIter__vert_of_strand *)(&iter->data))->v_next = root;
+ break;
+ }
+ default:
+ /* fallback to regular bmesh iterator */
+ return BM_iter_init(iter, bm, itype, data);
+ break;
+ }
+
+ iter->begin(iter);
+
+ return true;
+}
+
+/**
+ * \brief Iterator New
+ *
+ * Takes a bmesh iterator structure and fills
+ * it with the appropriate function pointers based
+ * upon its type and then calls BMeshIter_step()
+ * to return the first element of the iterator.
+ *
+ */
+BLI_INLINE void *BM_strand_iter_new(BMIter *iter, BMesh *bm, const char itype, void *data)
+{
+ if (LIKELY(BM_strand_iter_init(iter, bm, itype, data))) {
+ return BM_iter_step(iter);
+ }
+ else {
+ return NULL;
+ }
+}
+
+#define BM_strand_iter_new(iter, bm, itype, data) \
+ (BM_ITER_CHECK_TYPE_DATA(data), BM_strand_iter_new(iter, bm, itype, data))
+
+#endif /* __BMESH_STRANDS_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_strands_conv.c b/source/blender/bmesh/intern/bmesh_strands_conv.c
new file mode 100644
index 00000000000..50ea50c9299
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_strands_conv.c
@@ -0,0 +1,1314 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Lukas Toenne.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_strands_conv.c
+ * \ingroup bmesh
+ *
+ * BM mesh conversion functions.
+ */
+
+#include "DNA_cache_library_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_key_types.h"
+#include "DNA_strands_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "BKE_cache_library.h"
+#include "BKE_customdata.h"
+#include "BKE_key.h"
+#include "BKE_main.h"
+#include "BKE_mesh_sample.h"
+#include "BKE_strands.h"
+#include "BKE_particle.h"
+
+#include "bmesh.h"
+#include "intern/bmesh_private.h" /* for element checking */
+
+const char *CD_HAIR_SEGMENT_LENGTH = "HAIR_SEGMENT_LENGTH";
+const char *CD_HAIR_MASS = "HAIR_MASS";
+const char *CD_HAIR_WEIGHT = "HAIR_WEIGHT";
+const char *CD_HAIR_ROOT_LOCATION = "HAIR_ROOT_LOCATION";
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * Currently this is only used for Python scripts
+ * which may fail to keep matching UV/TexFace layers.
+ *
+ * \note This should only perform any changes in exceptional cases,
+ * if we need this to be faster we could inline #BM_data_layer_add and only
+ * call #update_data_blocks once at the end.
+ */
+void BM_strands_cd_validate(BMesh *UNUSED(bm))
+{
+}
+
+void BM_strands_cd_flag_ensure(BMesh *bm, const char cd_flag)
+{
+ const char cd_flag_all = BM_strands_cd_flag_from_bmesh(bm) | cd_flag;
+ BM_strands_cd_flag_apply(bm, cd_flag_all);
+}
+
+void BM_strands_cd_flag_apply(BMesh *bm, const char UNUSED(cd_flag))
+{
+ /* CustomData_bmesh_init_pool() must run first */
+ BLI_assert(bm->vdata.totlayer == 0 || bm->vdata.pool != NULL);
+ BLI_assert(bm->edata.totlayer == 0 || bm->edata.pool != NULL);
+
+ if (CustomData_get_named_layer_index(&bm->vdata, CD_PROP_FLT, CD_HAIR_MASS) < 0) {
+ BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_FLT, CD_HAIR_MASS);
+ }
+ if (CustomData_get_named_layer_index(&bm->vdata, CD_PROP_FLT, CD_HAIR_WEIGHT) < 0) {
+ BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_FLT, CD_HAIR_WEIGHT);
+ }
+ if (CustomData_get_named_layer_index(&bm->vdata, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION) < 0) {
+ BM_data_layer_add_named(bm, &bm->vdata, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION);
+ }
+ if (CustomData_get_named_layer_index(&bm->vdata, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH) < 0) {
+ BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH);
+ }
+}
+
+char BM_strands_cd_flag_from_bmesh(BMesh *UNUSED(bm))
+{
+ char cd_flag = 0;
+ return cd_flag;
+}
+
+/* ------------------------------------------------------------------------- */
+/* CacheLibrary */
+
+static KeyBlock *bm_set_shapekey_from_strands_key(BMesh *bm, Strands *strands, Key *key, int act_key_nr)
+{
+ int totvert = strands->totverts;
+ KeyBlock *actkey, *block;
+ int i, j;
+
+ if (!key) {
+ return NULL;
+ }
+
+ if (act_key_nr != 0)
+ actkey = BLI_findlink(&key->block, act_key_nr - 1);
+ else
+ actkey = NULL;
+
+ CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0);
+
+ if (actkey && actkey->totelem == totvert) {
+ bm->shapenr = act_key_nr;
+ }
+
+ for (i = 0, block = key->block.first; block; block = block->next, i++) {
+ CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY,
+ CD_ASSIGN, NULL, 0, block->name);
+
+ j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i);
+ bm->vdata.layers[j].uid = block->uid;
+ }
+
+ return actkey;
+}
+
+/* create vertex and edge data for BMesh based on strand data */
+static void bm_make_strands(BMesh *bm, Strands *strands, Key *key, struct DerivedMesh *UNUSED(emitter_dm), float mat[4][4], float (*keyco)[3], int cd_shape_keyindex_offset)
+{
+ KeyBlock *block;
+ StrandIterator it_strand;
+
+ int vindex, eindex;
+ BMVert *v = NULL, *v_prev;
+ BMEdge *e;
+
+ vindex = 0;
+ eindex = 0;
+ for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+ StrandVertexIterator it_vert;
+
+ for (BKE_strand_vertex_iter_init(&it_vert, &it_strand); BKE_strand_vertex_iter_valid(&it_vert); BKE_strand_vertex_iter_next(&it_vert)) {
+ float co[3];
+
+ copy_v3_v3(co, keyco ? keyco[vindex] : it_vert.vertex->co);
+ /* transform to duplicator local space */
+ mul_m4_v3(mat, co);
+
+ v_prev = v;
+ v = BM_vert_create(bm, co, NULL, BM_CREATE_SKIP_CD);
+ BM_elem_index_set(v, vindex); /* set_ok */
+
+ /* transfer flag */
+// v->head.hflag = BM_vert_flag_from_mflag(mvert->flag & ~SELECT);
+
+ /* this is necessary for selection counts to work properly */
+// if (hkey->editflag & SELECT) {
+// BM_vert_select_set(bm, v, true);
+// }
+
+// normal_short_to_float_v3(v->no, mvert->no);
+
+ /* Copy Custom Data */
+// CustomData_to_bmesh_block(&me->vdata, &bm->vdata, vindex, &v->head.data, true);
+ CustomData_bmesh_set_default(&bm->vdata, &v->head.data);
+
+// BM_elem_float_data_named_set(&bm->vdata, v, CD_PROP_FLT, CD_HAIR_MASS, mass);
+ BM_elem_float_data_named_set(&bm->vdata, v, CD_PROP_FLT, CD_HAIR_WEIGHT, it_vert.vertex->weight);
+
+ /* root */
+ BM_elem_meshsample_data_named_set(&bm->vdata, v, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION, &it_strand.curve->msurf);
+
+ /* set shapekey data */
+ if (key) {
+ int k;
+
+ /* set shape key original index */
+ if (cd_shape_keyindex_offset != -1)
+ BM_ELEM_CD_SET_INT(v, cd_shape_keyindex_offset, vindex);
+
+ for (block = key->block.first, k = 0; block; block = block->next, k++) {
+ float *co = CustomData_bmesh_get_n(&bm->vdata, v->head.data, CD_SHAPEKEY, k);
+
+ if (co) {
+ mul_v3_m4v3(co, mat, ((float *)block->data) + 3 * vindex);
+ }
+ }
+ }
+
+ vindex += 1;
+
+ if (it_vert.index > 0) {
+ e = BM_edge_create(bm, v_prev, v, NULL, BM_CREATE_SKIP_CD);
+ BM_elem_index_set(e, eindex); /* set_ok; one less edge than vertices for each particle */
+
+ /* transfer flags */
+// e->head.hflag = BM_edge_flag_from_mflag(medge->flag & ~SELECT);
+
+ /* this is necessary for selection counts to work properly */
+// if (medge->flag & SELECT) {
+// BM_edge_select_set(bm, e, true);
+// }
+
+ /* Copy Custom Data */
+// CustomData_to_bmesh_block(&me->edata, &bm->edata, eindex, &e->head.data, true);
+ CustomData_bmesh_set_default(&bm->edata, &e->head.data);
+
+ eindex += 1;
+ }
+ }
+
+ }
+
+ bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE); /* added in order, clear dirty flag */
+}
+
+/**
+ * \brief ParticleSystem -> BMesh
+ */
+void BM_strands_bm_from_strands(BMesh *bm, Strands *strands, float mat[4][4], Key *key, struct DerivedMesh *emitter_dm,
+ const bool set_key, int act_key_nr)
+{
+ KeyBlock *actkey;
+ float (*keyco)[3] = NULL;
+ int totvert, totedge;
+
+ int cd_shape_keyindex_offset;
+
+ /* free custom data */
+ /* this isnt needed in most cases but do just incase */
+ CustomData_free(&bm->vdata, bm->totvert);
+ CustomData_free(&bm->edata, bm->totedge);
+ CustomData_free(&bm->ldata, bm->totloop);
+ CustomData_free(&bm->pdata, bm->totface);
+
+ totvert = strands->totverts;
+ totedge = strands->totverts - strands->totcurves;
+
+ if (!strands || !totvert || !totedge) {
+ if (strands) { /*no verts? still copy customdata layout*/
+ CustomData_bmesh_init_pool(&bm->vdata, totvert, BM_VERT);
+ CustomData_bmesh_init_pool(&bm->edata, totedge, BM_EDGE);
+ CustomData_bmesh_init_pool(&bm->ldata, 0, BM_LOOP);
+ CustomData_bmesh_init_pool(&bm->pdata, 0, BM_FACE);
+ }
+ return; /* sanity check */
+ }
+
+ actkey = bm_set_shapekey_from_strands_key(bm, strands, key, act_key_nr);
+ if (actkey)
+ keyco = actkey->data;
+
+ CustomData_bmesh_init_pool(&bm->vdata, totvert, BM_VERT);
+ CustomData_bmesh_init_pool(&bm->edata, totedge, BM_EDGE);
+
+ BM_strands_cd_flag_apply(bm, 0);
+
+ cd_shape_keyindex_offset = key ? CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX) : -1;
+
+ bm_make_strands(bm, strands, key, emitter_dm, mat, set_key ? keyco : NULL, cd_shape_keyindex_offset);
+
+#if 0 /* TODO */
+ if (me->mselect && me->totselect != 0) {
+
+ BMVert **vert_array = MEM_mallocN(sizeof(BMVert *) * bm->totvert, "VSelConv");
+ BMEdge **edge_array = MEM_mallocN(sizeof(BMEdge *) * bm->totedge, "ESelConv");
+ BMFace **face_array = MEM_mallocN(sizeof(BMFace *) * bm->totface, "FSelConv");
+ MSelect *msel;
+
+#pragma omp parallel sections if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
+ {
+#pragma omp section
+ { BM_iter_as_array(bm, BM_VERTS_OF_MESH, NULL, (void **)vert_array, bm->totvert); }
+#pragma omp section
+ { BM_iter_as_array(bm, BM_EDGES_OF_MESH, NULL, (void **)edge_array, bm->totedge); }
+#pragma omp section
+ { BM_iter_as_array(bm, BM_FACES_OF_MESH, NULL, (void **)face_array, bm->totface); }
+ }
+
+ for (i = 0, msel = me->mselect; i < me->totselect; i++, msel++) {
+ switch (msel->type) {
+ case ME_VSEL:
+ BM_select_history_store(bm, (BMElem *)vert_array[msel->index]);
+ break;
+ case ME_ESEL:
+ BM_select_history_store(bm, (BMElem *)edge_array[msel->index]);
+ break;
+ case ME_FSEL:
+ BM_select_history_store(bm, (BMElem *)face_array[msel->index]);
+ break;
+ }
+ }
+
+ MEM_freeN(vert_array);
+ MEM_freeN(edge_array);
+ MEM_freeN(face_array);
+ }
+ else {
+ me->totselect = 0;
+ if (me->mselect) {
+ MEM_freeN(me->mselect);
+ me->mselect = NULL;
+ }
+ }
+#endif
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if 0
+/**
+ * \brief BMesh -> Mesh
+ */
+static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert)
+{
+ const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
+ BMVert **vertMap = NULL;
+ BMVert *eve;
+ int i = 0;
+ BMIter iter;
+
+ /* caller needs to ensure this */
+ BLI_assert(ototvert > 0);
+
+ vertMap = MEM_callocN(sizeof(*vertMap) * ototvert, "vertMap");
+ if (cd_shape_keyindex_offset != -1) {
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
+ if ((keyi != ORIGINDEX_NONE) && (keyi < ototvert)) {
+ vertMap[keyi] = eve;
+ }
+ }
+ }
+ else {
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (i < ototvert) {
+ vertMap[i] = eve;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ return vertMap;
+}
+
+BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
+{
+ /* this is a cheap way to set the edge draw, its not precise and will
+ * pick the first 2 faces an edge uses.
+ * The dot comparison is a little arbitrary, but set so that a 5 subd
+ * IcoSphere won't vanish but subd 6 will (as with pre-bmesh blender) */
+
+
+ if ( /* (med->flag & ME_EDGEDRAW) && */ /* assume to be true */
+ (e->l && (e->l != e->l->radial_next)) &&
+ (dot_v3v3(e->l->f->no, e->l->radial_next->f->no) > 0.9995f))
+ {
+ med->flag &= ~ME_EDGEDRAW;
+ }
+ else {
+ med->flag |= ME_EDGEDRAW;
+ }
+}
+#endif
+
+static void bm_strands_make_strand(BMesh *bm, BMVert *root, Strands *UNUSED(strands), float imat[4][4], Key *UNUSED(key),
+ struct DerivedMesh *emitter_dm, struct BVHTreeFromMesh *UNUSED(emitter_bvhtree),
+ StrandIterator *it_strand)
+{
+ int numverts = BM_strands_keys_count(root);
+
+ BMVert *v;
+ BMIter iter;
+ StrandVertexIterator it_vert;
+
+ it_strand->curve->numverts = numverts;
+ /* init root matrix, fully constructed below for non-degenerate strands */
+ unit_m3(it_strand->curve->root_matrix);
+
+ BKE_strand_vertex_iter_init(&it_vert, it_strand);
+ BM_ITER_STRANDS_ELEM(v, &iter, root, BM_VERTS_OF_STRAND) {
+ BLI_assert(BKE_strand_vertex_iter_valid(&it_vert));
+
+ /* root */
+ if (it_vert.index == 0) {
+ float loc[3], nor[3], tang[3];
+ BM_elem_meshsample_data_named_get(&bm->vdata, v, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION, &it_strand->curve->msurf);
+ BKE_mesh_sample_eval(emitter_dm, &it_strand->curve->msurf, loc, nor, tang);
+
+ /* construct root matrix */
+ copy_v3_v3(it_strand->curve->root_matrix[2], nor);
+ copy_v3_v3(it_strand->curve->root_matrix[0], tang);
+ cross_v3_v3v3(it_strand->curve->root_matrix[1], it_strand->curve->root_matrix[2], it_strand->curve->root_matrix[0]);
+
+ /* transform from edit space (duplicator local space) back to the original object space */
+ mul_mat3_m4_v3(imat, it_strand->curve->root_matrix[0]);
+ mul_mat3_m4_v3(imat, it_strand->curve->root_matrix[1]);
+ mul_mat3_m4_v3(imat, it_strand->curve->root_matrix[2]);
+ }
+
+ /* transform from edit space (duplicator local space) back to the original object space */
+ mul_v3_m4v3(it_vert.vertex->co, imat, v->co);
+ it_vert.vertex->time = numverts > 0 ? (float)it_vert.index / (float)(numverts - 1) : 0.0f;
+
+ if (it_vert.index == 0) {
+ /* weight 1.0 is used for pinning hair roots in particles */
+ it_vert.vertex->weight = 1.0f;
+ }
+ else {
+ it_vert.vertex->weight = BM_elem_float_data_named_get(&bm->vdata, v, CD_PROP_FLT, CD_HAIR_WEIGHT);
+ }
+
+ BKE_strand_vertex_iter_next(&it_vert);
+
+ BM_CHECK_ELEMENT(v);
+ }
+}
+
+/**
+ * returns customdata shapekey index from a keyblock or -1
+ * \note could split this out into a more generic function */
+static int bm_shape_layer_index_from_kb(BMesh *bm, KeyBlock *currkey)
+{
+ int i;
+ int j = 0;
+
+ for (i = 0; i < bm->vdata.totlayer; i++) {
+ if (bm->vdata.layers[i].type == CD_SHAPEKEY) {
+ if (currkey->uid == bm->vdata.layers[i].uid) {
+ return j;
+ }
+ j++;
+ }
+ }
+ return -1;
+}
+
+/* go through and find any shapekey customdata layers
+ * that might not have corresponding KeyBlocks, and add them if
+ * necessary */
+static void bm_strands_add_missing_shapekeys(BMesh *bm, Key *key)
+{
+ KeyBlock *currkey;
+ int i;
+
+ for (i = 0; i < bm->vdata.totlayer; i++) {
+ const CustomDataLayer *layer = &bm->vdata.layers[i];
+ if (layer->type != CD_SHAPEKEY)
+ continue;
+
+ for (currkey = key->block.first; currkey; currkey = currkey->next) {
+ if (currkey->uid == layer->uid)
+ break;
+ }
+
+ if (!currkey) {
+ currkey = BKE_keyblock_add(key, layer->name);
+ currkey->uid = layer->uid;
+ }
+ }
+}
+
+/* returns offset of the edit against the active shape, so other shapes can compensate accordingly to avoid deformation */
+static void bm_strands_get_basiskey_offset(BMesh *bm, Strands *strands, Key *key, int cd_shape_keyindex_offset, float (**r_offset)[3])
+{
+ *r_offset = NULL;
+
+ /* only need offsets for relative shape keys */
+ if (key->type == KEY_RELATIVE) {
+
+ KeyBlock *actkey = BLI_findlink(&key->block, bm->shapenr - 1);
+ /* unlikely, but the active key may not be valid if the bmesh and the mesh are out of sync */
+ if (!actkey)
+ return;
+
+ /* only if active key is a base */
+ if (BKE_keyblock_is_basis(key, bm->shapenr - 1) && cd_shape_keyindex_offset >= 0) {
+ float (*fp)[3] = actkey->data;
+ float (*ofs)[3] = MEM_callocN(sizeof(float) * 3 * bm->totvert, "currkey->data");
+ BMIter iter;
+ BMVert *eve;
+ StrandsVertex *svert;
+ int i;
+
+ svert = strands->verts;
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
+
+ if (keyi != ORIGINDEX_NONE) {
+ sub_v3_v3v3(ofs[i], svert->co, fp[keyi]);
+ }
+ else {
+ /* if there are new vertices in the mesh, we can't propagate the offset
+ * because it will only work for the existing vertices and not the new
+ * ones, creating a mess when doing e.g. subdivide + translate */
+ MEM_freeN(ofs);
+ ofs = NULL;
+ break;
+ }
+
+ svert++;
+ }
+
+ *r_offset = ofs;
+ }
+ }
+}
+
+static float *bm_strands_apply_keyblock(BMesh *bm, Strands *strands, StrandsVertex *oldverts, float imat[4][4], Key *key, int cd_shape_keyindex_offset,
+ KeyBlock *kb, KeyBlock *actkb, float (*oldkey)[3], float (*offset)[3])
+{
+ const bool apply_offset = (offset && (kb != actkb) && (bm->shapenr - 1 == kb->relative));
+ const int shape_layer_index = bm_shape_layer_index_from_kb(bm, kb);
+ const int cd_shape_offset = CustomData_get_n_offset(&bm->vdata, CD_SHAPEKEY, shape_layer_index);
+
+ float *newkey, *fp;
+ BMIter iter;
+ BMVert *eve;
+ StrandsVertex *svert;
+ int keyi;
+ float (*ofs_pt)[3] = offset;
+
+ fp = newkey = MEM_callocN(key->elemsize * bm->totvert, "currkey->data");
+
+ svert = strands->verts;
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+
+ if (kb == actkb) {
+ copy_v3_v3(fp, eve->co);
+
+ if (actkb != key->refkey) { /* important see bug [#30771] */
+ if (cd_shape_keyindex_offset != -1) {
+ if (oldverts) {
+ keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
+ if (keyi != ORIGINDEX_NONE && keyi < kb->totelem) { /* valid old vertex */
+ copy_v3_v3(svert->co, oldverts[keyi].co);
+ }
+ }
+ }
+ }
+ }
+ else if (shape_layer_index != -1) {
+ /* in most cases this runs */
+ copy_v3_v3(fp, BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset));
+ }
+ else if ((oldkey != NULL) &&
+ (cd_shape_keyindex_offset != -1) &&
+ ((keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset)) != ORIGINDEX_NONE) &&
+ (keyi < kb->totelem))
+ {
+ /* old method of reconstructing keys via vertice's original key indices,
+ * currently used if the new method above fails (which is theoretically
+ * possible in certain cases of undo) */
+ copy_v3_v3(fp, oldkey[keyi]);
+ }
+ else {
+ /* fail! fill in with dummy value */
+ copy_v3_v3(fp, svert->co);
+ }
+
+ /* propagate edited basis offsets to other shapes */
+ if (apply_offset) {
+ add_v3_v3(fp, *ofs_pt++);
+ }
+
+ /* transform from edit space (duplicator local space) back to the original object space */
+ mul_m4_v3(imat, fp);
+
+ fp += 3;
+ svert++;
+ }
+
+ return newkey;
+}
+
+static void bm_strands_apply_shapekeys(BMesh *bm, Strands *strands, StrandsVertex *oldverts, float imat[4][4], Key *key)
+{
+ const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
+ KeyBlock *actkb = BLI_findlink(&key->block, bm->shapenr - 1);
+ KeyBlock *kb;
+ float (*offset)[3] = NULL;
+
+ bm_strands_add_missing_shapekeys(bm, key);
+
+ if (oldverts)
+ bm_strands_get_basiskey_offset(bm, strands, key, cd_shape_keyindex_offset, &offset);
+
+ for (kb = key->block.first; kb; kb = kb->next) {
+ float *newkey;
+
+ newkey = bm_strands_apply_keyblock(bm, strands, oldverts, imat, key, cd_shape_keyindex_offset, kb, actkb, kb->data, offset);
+
+ kb->totelem = bm->totvert;
+ if (kb->data) {
+ MEM_freeN(kb->data);
+ }
+ kb->data = newkey;
+ }
+
+ if (offset)
+ MEM_freeN(offset);
+}
+
+Strands *BM_strands_bm_to_strands(BMesh *bm, Strands *strands, float mat[4][4], Key *key, struct DerivedMesh *emitter_dm, struct BVHTreeFromMesh *emitter_bvhtree)
+{
+ Strands *oldstrands;
+ int ntotcurves;
+ float imat[4][4];
+
+ BMVert *root;
+ BMIter iter;
+ StrandIterator it_strand;
+
+ ntotcurves = BM_strands_count(bm);
+
+ /* lets save the old strands just in case we are actually working on
+ * a key ... we now do processing of the keys at the end */
+ oldstrands = strands;
+
+ invert_m4_m4(imat, mat);
+
+ strands = BKE_strands_new(ntotcurves, bm->totvert);
+
+// strands->cd_flag = BM_strands_cd_flag_from_bmesh(bm);
+
+ BKE_strand_iter_init(&it_strand, strands);
+ BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) {
+ BLI_assert(BKE_strand_iter_valid(&it_strand));
+
+ bm_strands_make_strand(bm, root, strands, imat, key, emitter_dm, emitter_bvhtree, &it_strand);
+
+ BKE_strand_iter_next(&it_strand);
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
+
+ BKE_strands_ensure_normals(strands);
+
+
+#if 0 // TODO
+ {
+ BMEditSelection *selected;
+ me->totselect = BLI_listbase_count(&(bm->selected));
+
+ if (me->mselect) MEM_freeN(me->mselect);
+
+ me->mselect = MEM_callocN(sizeof(MSelect) * me->totselect, "Mesh selection history");
+
+
+ for (i = 0, selected = bm->selected.first; selected; i++, selected = selected->next) {
+ if (selected->htype == BM_VERT) {
+ me->mselect[i].type = ME_VSEL;
+
+ }
+ else if (selected->htype == BM_EDGE) {
+ me->mselect[i].type = ME_ESEL;
+
+ }
+ else if (selected->htype == BM_FACE) {
+ me->mselect[i].type = ME_FSEL;
+ }
+
+ me->mselect[i].index = BM_elem_index_get(selected->ele);
+ }
+ }
+#endif
+
+ if (key) {
+ bm_strands_apply_shapekeys(bm, strands, oldstrands ? oldstrands->verts : NULL, imat, key);
+ }
+
+ if (oldstrands) {
+ BKE_strands_free(oldstrands);
+ }
+
+ return strands;
+}
+
+/* ------------------------------------------------------------------------- */
+/* ParticleSystem */
+
+int BM_strands_count_psys_keys(ParticleSystem *psys)
+{
+ ParticleData *pa;
+ int p;
+ int totkeys = 0;
+
+ for (p = 0, pa = psys->particles; p < psys->totpart; ++p, ++pa)
+ totkeys += pa->totkey;
+
+ return totkeys;
+}
+
+#if 0
+static KeyBlock *bm_set_shapekey_from_psys(BMesh *bm, ParticleSystem *psys, int totvert, int act_key_nr)
+{
+ KeyBlock *actkey, *block;
+ int i, j;
+
+ if (!psys->key) {
+ return NULL;
+ }
+
+ if (act_key_nr != 0)
+ actkey = BLI_findlink(&psys->key->block, act_key_nr - 1);
+ else
+ actkey = NULL;
+
+ CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0);
+
+ /* check if we need to generate unique ids for the shapekeys.
+ * this also exists in the file reading code, but is here for
+ * a sanity check */
+ if (!psys->key->uidgen) {
+ fprintf(stderr,
+ "%s had to generate shape key uid's in a situation we shouldn't need to! "
+ "(bmesh internal error)\n",
+ __func__);
+
+ psys->key->uidgen = 1;
+ for (block = psys->key->block.first; block; block = block->next) {
+ block->uid = psys->key->uidgen++;
+ }
+ }
+
+ if (actkey && actkey->totelem == totvert) {
+ bm->shapenr = act_key_nr;
+ }
+
+ for (i = 0, block = psys->key->block.first; block; block = block->next, i++) {
+ CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY,
+ CD_ASSIGN, NULL, 0, block->name);
+
+ j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i);
+ bm->vdata.layers[j].uid = block->uid;
+ }
+
+ return actkey;
+}
+#endif
+
+/* create vertex and edge data for BMesh based on particle hair keys */
+static void bm_make_particles(BMesh *bm, Object *ob, ParticleSystem *psys, struct DerivedMesh *emitter_dm, float (*keyco)[3], int cd_shape_keyindex_offset)
+{
+// KeyBlock *block;
+ ParticleData *pa;
+ HairKey *hkey;
+ int p, k;
+
+ int vindex, eindex;
+ BMVert *v = NULL, *v_prev;
+ BMEdge *e;
+
+ float hairmat[4][4];
+
+ /* XXX currently all particles and keys have the same mass, this may change */
+ float mass = psys->part->mass;
+
+ vindex = 0;
+ eindex = 0;
+ for (p = 0, pa = psys->particles; p < psys->totpart; ++p, ++pa) {
+
+ /* hair keys are in a local "hair space", but edit data should be in object space */
+ psys_mat_hair_to_object(ob, emitter_dm, psys->part->from, pa, hairmat);
+
+ for (k = 0, hkey = pa->hair; k < pa->totkey; ++k, ++hkey) {
+ float co[3];
+
+ copy_v3_v3(co, keyco ? keyco[vindex] : hkey->co);
+ mul_m4_v3(hairmat, co);
+
+ v_prev = v;
+ v = BM_vert_create(bm, co, NULL, BM_CREATE_SKIP_CD);
+ BM_elem_index_set(v, vindex); /* set_ok */
+
+ /* transfer flag */
+// v->head.hflag = BM_vert_flag_from_mflag(mvert->flag & ~SELECT);
+
+ /* this is necessary for selection counts to work properly */
+// if (hkey->editflag & SELECT) {
+// BM_vert_select_set(bm, v, true);
+// }
+
+// normal_short_to_float_v3(v->no, mvert->no);
+
+ /* Copy Custom Data */
+// CustomData_to_bmesh_block(&me->vdata, &bm->vdata, vindex, &v->head.data, true);
+ CustomData_bmesh_set_default(&bm->vdata, &v->head.data);
+
+ BM_elem_float_data_named_set(&bm->vdata, v, CD_PROP_FLT, CD_HAIR_MASS, mass);
+ BM_elem_float_data_named_set(&bm->vdata, v, CD_PROP_FLT, CD_HAIR_WEIGHT, hkey->weight);
+
+ /* root */
+ if (k == 0) {
+ MSurfaceSample root_loc;
+ if (BKE_mesh_sample_from_particle(&root_loc, psys, emitter_dm, pa)) {
+ BM_elem_meshsample_data_named_set(&bm->vdata, v, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION, &root_loc);
+ }
+ }
+
+#if 0
+ /* set shapekey data */
+ if (psys->key) {
+ /* set shape key original index */
+ if (cd_shape_keyindex_offset != -1) BM_ELEM_CD_SET_INT(v, cd_shape_keyindex_offset, vindex);
+
+ for (block = psys->key->block.first, j = 0; block; block = block->next, j++) {
+ float *co = CustomData_bmesh_get_n(&bm->vdata, v->head.data, CD_SHAPEKEY, j);
+
+ if (co) {
+ copy_v3_v3(co, ((float *)block->data) + 3 * vindex);
+ }
+ }
+ }
+#else
+ (void)cd_shape_keyindex_offset;
+#endif
+
+ vindex += 1;
+
+ if (k > 0) {
+ e = BM_edge_create(bm, v_prev, v, NULL, BM_CREATE_SKIP_CD);
+ BM_elem_index_set(e, eindex); /* set_ok; one less edge than vertices for each particle */
+
+ /* transfer flags */
+// e->head.hflag = BM_edge_flag_from_mflag(medge->flag & ~SELECT);
+
+ /* this is necessary for selection counts to work properly */
+// if (medge->flag & SELECT) {
+// BM_edge_select_set(bm, e, true);
+// }
+
+ /* Copy Custom Data */
+// CustomData_to_bmesh_block(&me->edata, &bm->edata, eindex, &e->head.data, true);
+ CustomData_bmesh_set_default(&bm->edata, &e->head.data);
+
+ eindex += 1;
+ }
+
+ } /* hair keys */
+
+ } /* particles */
+
+ bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE); /* added in order, clear dirty flag */
+}
+
+/**
+ * \brief ParticleSystem -> BMesh
+ */
+void BM_strands_bm_from_psys(BMesh *bm, Object *ob, ParticleSystem *psys, struct DerivedMesh *emitter_dm,
+ const bool set_key, int act_key_nr)
+{
+ // KeyBlock *actkey;
+ float (*keyco)[3] = NULL;
+ int totvert, totedge;
+
+ int cd_shape_keyindex_offset;
+
+ /* free custom data */
+ /* this isnt needed in most cases but do just incase */
+ CustomData_free(&bm->vdata, bm->totvert);
+ CustomData_free(&bm->edata, bm->totedge);
+ CustomData_free(&bm->ldata, bm->totloop);
+ CustomData_free(&bm->pdata, bm->totface);
+
+ totvert = BM_strands_count_psys_keys(psys);
+ totedge = totvert - psys->totpart;
+
+ if (!psys || !totvert || !totedge) {
+ if (psys) { /*no verts? still copy customdata layout*/
+ CustomData_bmesh_init_pool(&bm->vdata, totvert, BM_VERT);
+ CustomData_bmesh_init_pool(&bm->edata, totedge, BM_EDGE);
+ CustomData_bmesh_init_pool(&bm->ldata, 0, BM_LOOP);
+ CustomData_bmesh_init_pool(&bm->pdata, 0, BM_FACE);
+ }
+ return; /* sanity check */
+ }
+
+#if 0
+ actkey = bm_set_shapekey_from_psys(bm, psys, totvert, act_key_nr);
+ if (actkey)
+ keyco = actkey->data;
+#else
+ (void)act_key_nr;
+#endif
+
+ CustomData_bmesh_init_pool(&bm->vdata, totvert, BM_VERT);
+ CustomData_bmesh_init_pool(&bm->edata, totedge, BM_EDGE);
+
+ BM_strands_cd_flag_apply(bm, /*psys->cd_flag*/0);
+
+ cd_shape_keyindex_offset = /*psys->key ? CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX) :*/ -1;
+
+ bm_make_particles(bm, ob, psys, emitter_dm, set_key ? keyco : NULL, cd_shape_keyindex_offset);
+
+
+#if 0 /* TODO */
+ if (me->mselect && me->totselect != 0) {
+
+ BMVert **vert_array = MEM_mallocN(sizeof(BMVert *) * bm->totvert, "VSelConv");
+ BMEdge **edge_array = MEM_mallocN(sizeof(BMEdge *) * bm->totedge, "ESelConv");
+ BMFace **face_array = MEM_mallocN(sizeof(BMFace *) * bm->totface, "FSelConv");
+ MSelect *msel;
+
+#pragma omp parallel sections if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
+ {
+#pragma omp section
+ { BM_iter_as_array(bm, BM_VERTS_OF_MESH, NULL, (void **)vert_array, bm->totvert); }
+#pragma omp section
+ { BM_iter_as_array(bm, BM_EDGES_OF_MESH, NULL, (void **)edge_array, bm->totedge); }
+#pragma omp section
+ { BM_iter_as_array(bm, BM_FACES_OF_MESH, NULL, (void **)face_array, bm->totface); }
+ }
+
+ for (i = 0, msel = me->mselect; i < me->totselect; i++, msel++) {
+ switch (msel->type) {
+ case ME_VSEL:
+ BM_select_history_store(bm, (BMElem *)vert_array[msel->index]);
+ break;
+ case ME_ESEL:
+ BM_select_history_store(bm, (BMElem *)edge_array[msel->index]);
+ break;
+ case ME_FSEL:
+ BM_select_history_store(bm, (BMElem *)face_array[msel->index]);
+ break;
+ }
+ }
+
+ MEM_freeN(vert_array);
+ MEM_freeN(edge_array);
+ MEM_freeN(face_array);
+ }
+ else {
+ me->totselect = 0;
+ if (me->mselect) {
+ MEM_freeN(me->mselect);
+ me->mselect = NULL;
+ }
+ }
+#endif
+}
+
+#if 0
+/**
+ * \brief BMesh -> Mesh
+ */
+static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert)
+{
+ const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
+ BMVert **vertMap = NULL;
+ BMVert *eve;
+ int i = 0;
+ BMIter iter;
+
+ /* caller needs to ensure this */
+ BLI_assert(ototvert > 0);
+
+ vertMap = MEM_callocN(sizeof(*vertMap) * ototvert, "vertMap");
+ if (cd_shape_keyindex_offset != -1) {
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
+ if ((keyi != ORIGINDEX_NONE) && (keyi < ototvert)) {
+ vertMap[keyi] = eve;
+ }
+ }
+ }
+ else {
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (i < ototvert) {
+ vertMap[i] = eve;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ return vertMap;
+}
+
+/**
+ * returns customdata shapekey index from a keyblock or -1
+ * \note could split this out into a more generic function */
+static int bm_to_mesh_shape_layer_index_from_kb(BMesh *bm, KeyBlock *currkey)
+{
+ int i;
+ int j = 0;
+
+ for (i = 0; i < bm->vdata.totlayer; i++) {
+ if (bm->vdata.layers[i].type == CD_SHAPEKEY) {
+ if (currkey->uid == bm->vdata.layers[i].uid) {
+ return j;
+ }
+ j++;
+ }
+ }
+ return -1;
+}
+
+BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
+{
+ /* this is a cheap way to set the edge draw, its not precise and will
+ * pick the first 2 faces an edge uses.
+ * The dot comparison is a little arbitrary, but set so that a 5 subd
+ * IcoSphere won't vanish but subd 6 will (as with pre-bmesh blender) */
+
+
+ if ( /* (med->flag & ME_EDGEDRAW) && */ /* assume to be true */
+ (e->l && (e->l != e->l->radial_next)) &&
+ (dot_v3v3(e->l->f->no, e->l->radial_next->f->no) > 0.9995f))
+ {
+ med->flag &= ~ME_EDGEDRAW;
+ }
+ else {
+ med->flag |= ME_EDGEDRAW;
+ }
+}
+#endif
+
+static void make_particle_hair(BMesh *bm, BMVert *root, Object *ob, ParticleSystem *psys, struct DerivedMesh *emitter_dm, struct BVHTreeFromMesh *emitter_bvhtree, struct ParticleData *pa)
+{
+ int totkey = BM_strands_keys_count(root);
+ HairKey *hair;
+
+ BMVert *v;
+ BMIter iter;
+ HairKey *hkey;
+ int k;
+
+ float inv_hairmat[4][4];
+
+ pa->alive = PARS_ALIVE;
+ pa->flag = 0;
+
+ pa->time = 0.0f;
+ pa->lifetime = 100.0f;
+ pa->dietime = 100.0f;
+
+ pa->size = psys->part->size;
+
+ // TODO define other particle stuff ...
+
+ hair = MEM_callocN(totkey * sizeof(HairKey), "hair keys");
+
+ hkey = hair;
+ k = 0;
+ BM_ITER_STRANDS_ELEM(v, &iter, root, BM_VERTS_OF_STRAND) {
+ /* root */
+ if (k == 0) {
+ MSurfaceSample root_loc;
+ BM_elem_meshsample_data_named_get(&bm->vdata, v, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION, &root_loc);
+ if (!BKE_mesh_sample_to_particle(&root_loc, psys, emitter_dm, emitter_bvhtree, pa)) {
+ pa->num = 0;
+ pa->num_dmcache = DMCACHE_NOTFOUND;
+ zero_v4(pa->fuv);
+ pa->foffset = 0.0f;
+ }
+
+ /* edit data is in object space, hair keys must be converted back into "hair space" */
+ psys_mat_hair_to_object(ob, emitter_dm, psys->part->from, pa, inv_hairmat);
+ invert_m4(inv_hairmat);
+ }
+
+ mul_v3_m4v3(hkey->co, inv_hairmat, v->co);
+ mul_v3_m4v3(hkey->world_co, ob->obmat, v->co);
+
+ hkey->time = totkey > 0 ? (float)k / (float)(totkey - 1) : 0.0f;
+ if (k == 0) {
+ /* weight 1.0 is used for pinning hair roots in particles */
+ hkey->weight = 1.0f;
+ }
+ else {
+ hkey->weight = BM_elem_float_data_named_get(&bm->vdata, v, CD_PROP_FLT, CD_HAIR_WEIGHT);
+ }
+
+ ++hkey;
+ ++k;
+
+ BM_CHECK_ELEMENT(v);
+ }
+
+ if (pa->hair)
+ MEM_freeN(pa->hair);
+
+ pa->hair = hair;
+ pa->totkey = totkey;
+}
+
+void BM_strands_bm_to_psys(BMesh *bm, Object *ob, ParticleSystem *psys, struct DerivedMesh *emitter_dm, struct BVHTreeFromMesh *emitter_bvhtree)
+{
+ ParticleData *particles, *oldparticles;
+ int ototpart, ntotpart;
+
+ BMVert *root;
+ BMIter iter;
+ ParticleData *pa;
+ int p;
+
+ ototpart = psys->totpart;
+
+ ntotpart = BM_strands_count(bm);
+
+ /* new particles block */
+ if (bm->totvert == 0) particles = NULL;
+ else particles = MEM_callocN(ntotpart * sizeof(ParticleData), "particles");
+
+ /* lets save the old particles just in case we are actually working on
+ * a key ... we now do processing of the keys at the end */
+ oldparticles = psys->particles;
+
+ psys->totpart = ntotpart;
+
+// psys->cd_flag = BM_strands_cd_flag_from_bmesh(bm);
+
+ pa = particles;
+ p = 0;
+ BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) {
+
+ make_particle_hair(bm, root, ob, psys, emitter_dm, emitter_bvhtree, pa);
+
+ ++pa;
+ ++p;
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
+
+
+#if 0 // TODO
+ {
+ BMEditSelection *selected;
+ me->totselect = BLI_listbase_count(&(bm->selected));
+
+ if (me->mselect) MEM_freeN(me->mselect);
+
+ me->mselect = MEM_callocN(sizeof(MSelect) * me->totselect, "Mesh selection history");
+
+
+ for (i = 0, selected = bm->selected.first; selected; i++, selected = selected->next) {
+ if (selected->htype == BM_VERT) {
+ me->mselect[i].type = ME_VSEL;
+
+ }
+ else if (selected->htype == BM_EDGE) {
+ me->mselect[i].type = ME_ESEL;
+
+ }
+ else if (selected->htype == BM_FACE) {
+ me->mselect[i].type = ME_FSEL;
+ }
+
+ me->mselect[i].index = BM_elem_index_get(selected->ele);
+ }
+ }
+#endif
+
+#if 0 // TODO
+ /* see comment below, this logic is in twice */
+
+ if (me->key) {
+ const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
+
+ KeyBlock *currkey;
+ KeyBlock *actkey = BLI_findlink(&me->key->block, bm->shapenr - 1);
+
+ float (*ofs)[3] = NULL;
+
+ /* go through and find any shapekey customdata layers
+ * that might not have corresponding KeyBlocks, and add them if
+ * necessary */
+ j = 0;
+ for (i = 0; i < bm->vdata.totlayer; i++) {
+ if (bm->vdata.layers[i].type != CD_SHAPEKEY)
+ continue;
+
+ for (currkey = me->key->block.first; currkey; currkey = currkey->next) {
+ if (currkey->uid == bm->vdata.layers[i].uid)
+ break;
+ }
+
+ if (!currkey) {
+ currkey = BKE_keyblock_add(me->key, bm->vdata.layers[i].name);
+ currkey->uid = bm->vdata.layers[i].uid;
+ }
+
+ j++;
+ }
+
+
+ /* editing the base key should update others */
+ if ((me->key->type == KEY_RELATIVE) && /* only need offsets for relative shape keys */
+ (actkey != NULL) && /* unlikely, but the active key may not be valid if the
+ * bmesh and the mesh are out of sync */
+ (oldverts != NULL)) /* not used here, but 'oldverts' is used later for applying 'ofs' */
+ {
+ const bool act_is_basis = BKE_keyblock_is_basis(me->key, bm->shapenr - 1);
+
+ /* active key is a base */
+ if (act_is_basis && (cd_shape_keyindex_offset != -1)) {
+ float (*fp)[3] = actkey->data;
+
+ ofs = MEM_callocN(sizeof(float) * 3 * bm->totvert, "currkey->data");
+ mvert = me->mvert;
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
+
+ if (keyi != ORIGINDEX_NONE) {
+ sub_v3_v3v3(ofs[i], mvert->co, fp[keyi]);
+ }
+ else {
+ /* if there are new vertices in the mesh, we can't propagate the offset
+ * because it will only work for the existing vertices and not the new
+ * ones, creating a mess when doing e.g. subdivide + translate */
+ MEM_freeN(ofs);
+ ofs = NULL;
+ break;
+ }
+
+ mvert++;
+ }
+ }
+ }
+
+ for (currkey = me->key->block.first; currkey; currkey = currkey->next) {
+ const bool apply_offset = (ofs && (currkey != actkey) && (bm->shapenr - 1 == currkey->relative));
+ int cd_shape_offset;
+ int keyi;
+ float (*ofs_pt)[3] = ofs;
+ float *newkey, (*oldkey)[3], *fp;
+
+ j = bm_to_mesh_shape_layer_index_from_kb(bm, currkey);
+ cd_shape_offset = CustomData_get_n_offset(&bm->vdata, CD_SHAPEKEY, j);
+
+
+ fp = newkey = MEM_callocN(me->key->elemsize * bm->totvert, "currkey->data");
+ oldkey = currkey->data;
+
+ mvert = me->mvert;
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+
+ if (currkey == actkey) {
+ copy_v3_v3(fp, eve->co);
+
+ if (actkey != me->key->refkey) { /* important see bug [#30771] */
+ if (cd_shape_keyindex_offset != -1) {
+ if (oldverts) {
+ keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
+ if (keyi != ORIGINDEX_NONE && keyi < currkey->totelem) { /* valid old vertex */
+ copy_v3_v3(mvert->co, oldverts[keyi].co);
+ }
+ }
+ }
+ }
+ }
+ else if (j != -1) {
+ /* in most cases this runs */
+ copy_v3_v3(fp, BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset));
+ }
+ else if ((oldkey != NULL) &&
+ (cd_shape_keyindex_offset != -1) &&
+ ((keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset)) != ORIGINDEX_NONE) &&
+ (keyi < currkey->totelem))
+ {
+ /* old method of reconstructing keys via vertice's original key indices,
+ * currently used if the new method above fails (which is theoretically
+ * possible in certain cases of undo) */
+ copy_v3_v3(fp, oldkey[keyi]);
+ }
+ else {
+ /* fail! fill in with dummy value */
+ copy_v3_v3(fp, mvert->co);
+ }
+
+ /* propagate edited basis offsets to other shapes */
+ if (apply_offset) {
+ add_v3_v3(fp, *ofs_pt++);
+ }
+
+ fp += 3;
+ mvert++;
+ }
+
+ currkey->totelem = bm->totvert;
+ if (currkey->data) {
+ MEM_freeN(currkey->data);
+ }
+ currkey->data = newkey;
+ }
+
+ if (ofs) MEM_freeN(ofs);
+ }
+#else
+ psys->particles = particles;
+#endif
+
+ if (oldparticles) {
+ ParticleData *pa;
+ int p;
+ for (p = 0, pa = oldparticles; p < ototpart; ++p, ++pa)
+ if (pa->hair)
+ MEM_freeN(pa->hair);
+ MEM_freeN(oldparticles);
+ }
+}
diff --git a/source/blender/bmesh/intern/bmesh_strands_conv.h b/source/blender/bmesh/intern/bmesh_strands_conv.h
new file mode 100644
index 00000000000..aa18b779b17
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_strands_conv.h
@@ -0,0 +1,67 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_STRANDS_CONV_H__
+#define __BMESH_STRANDS_CONV_H__
+
+/** \file blender/bmesh/intern/bmesh_strands_conv.h
+ * \ingroup bmesh
+ */
+
+struct BMesh;
+struct Mesh;
+struct Object;
+struct ParticleSystem;
+struct DerivedMesh;
+struct BVHTreeFromMesh;
+struct Strands;
+struct Key;
+
+extern const char *CD_HAIR_SEGMENT_LENGTH;
+extern const char *CD_HAIR_MASS;
+extern const char *CD_HAIR_WEIGHT;
+extern const char *CD_HAIR_ROOT_LOCATION;
+
+void BM_strands_cd_validate(struct BMesh *bm);
+void BM_strands_cd_flag_ensure(struct BMesh *bm, const char cd_flag);
+void BM_strands_cd_flag_apply(struct BMesh *bm, const char cd_flag);
+char BM_strands_cd_flag_from_bmesh(struct BMesh *bm);
+
+void BM_strands_bm_from_strands(struct BMesh *bm, struct Strands *strands, float mat[4][4], struct Key *key, struct DerivedMesh *emitter_dm, const bool set_key, int act_key_nr);
+struct Strands *BM_strands_bm_to_strands(struct BMesh *bm, struct Strands *strands, float mat[4][4], struct Key *key, struct DerivedMesh *emitter_dm, struct BVHTreeFromMesh *emitter_bvhtree);
+
+int BM_strands_count_psys_keys(struct ParticleSystem *psys);
+void BM_strands_bm_from_psys(struct BMesh *bm, struct Object *ob, struct ParticleSystem *psys, struct DerivedMesh *emitter_dm,
+ const bool set_key, int act_key_nr);
+void BM_strands_bm_to_psys(struct BMesh *bm, struct Object *ob, struct ParticleSystem *psys, struct DerivedMesh *emitter_dm, struct BVHTreeFromMesh *emitter_bvhtree);
+
+#define BMALLOC_TEMPLATE_FROM_STRANDS(strands) { (CHECK_TYPE_INLINE(strands, Strands *), \
+ strands->totverts), (strands->totverts - strands->totcurves), 0, 0 }
+#define BMALLOC_TEMPLATE_FROM_PSYS(psys) { (CHECK_TYPE_INLINE(psys, ParticleSystem *), \
+ BM_strands_count_psys_keys(psys)), (BM_strands_count_psys_keys(psys) - (psys)->totpart), 0, 0 }
+
+#endif /* __BMESH_STRANDS_CONV_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c
index 3e8002c0192..cb302139a4c 100644
--- a/source/blender/bmesh/intern/bmesh_structure.c
+++ b/source/blender/bmesh/intern/bmesh_structure.c
@@ -40,19 +40,56 @@
* MISC utility functions.
*/
-bool bmesh_edge_swapverts(BMEdge *e, BMVert *v_orig, BMVert *v_new)
+void bmesh_disk_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src)
{
- if (e->v1 == v_orig) {
- e->v1 = v_new;
+ if (e->v1 == v_src) {
+ e->v1 = v_dst;
e->v1_disk_link.next = e->v1_disk_link.prev = NULL;
- return true;
}
- else if (e->v2 == v_orig) {
- e->v2 = v_new;
+ else if (e->v2 == v_src) {
+ e->v2 = v_dst;
e->v2_disk_link.next = e->v2_disk_link.prev = NULL;
- return true;
}
- return false;
+ else {
+ BLI_assert(0);
+ }
+}
+
+/**
+ * Handles all connected data, use with care.
+ *
+ * Assumes caller has setup correct state before the swap is done.
+ */
+void bmesh_edge_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src)
+{
+ /* swap out loops */
+ if (e->l) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = e->l;
+ do {
+ if (l_iter->v == v_src) {
+ l_iter->v = v_dst;
+ }
+ else if (l_iter->next->v == v_src) {
+ l_iter->next->v = v_dst;
+ }
+ else {
+ BLI_assert(l_iter->prev->v != v_src);
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+
+ /* swap out edges */
+ bmesh_disk_vert_replace(e, v_dst, v_src);
+}
+
+void bmesh_disk_vert_replace(BMEdge *e, BMVert *v_dst, BMVert *v_src)
+{
+ BLI_assert(e->v1 == v_src || e->v2 == v_src);
+ bmesh_disk_edge_remove(e, v_src); /* remove e from tv's disk cycle */
+ bmesh_disk_vert_swap(e, v_dst, v_src); /* swap out tv for v_new in e */
+ bmesh_disk_edge_append(e, v_dst); /* add e to v_dst's disk cycle */
+ BLI_assert(e->v1 != e->v2);
}
/**
@@ -88,6 +125,7 @@ bool bmesh_edge_swapverts(BMEdge *e, BMVert *v_orig, BMVert *v_new)
* the disk cycle has no problems dealing with non-manifold conditions involving faces.
*
* Functions relating to this cycle:
+ * - #bmesh_disk_vert_replace
* - #bmesh_disk_edge_append
* - #bmesh_disk_edge_remove
* - #bmesh_disk_edge_next
@@ -206,13 +244,29 @@ int bmesh_disk_count(const BMVert *v)
return count;
}
+int bmesh_disk_count_ex(const BMVert *v, const int count_max)
+{
+ int count = 0;
+ if (v->e) {
+ BMEdge *e_first, *e_iter;
+ e_iter = e_first = v->e;
+ do {
+ count++;
+ if (count == count_max) {
+ break;
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
+ }
+ return count;
+}
+
bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v)
{
BMEdge *e_iter;
if (!BM_vert_in_edge(e, v))
return false;
- if (bmesh_disk_count(v) != len || len == 0)
+ if (bmesh_disk_count_ex(v, len + 1) != len || len == 0)
return false;
e_iter = e;
@@ -236,9 +290,9 @@ bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v)
int bmesh_disk_facevert_count(const BMVert *v)
{
/* is there an edge on this vert at all */
+ int count = 0;
if (v->e) {
BMEdge *e_first, *e_iter;
- int count = 0;
/* first, loop around edge */
e_first = e_iter = v->e;
@@ -247,11 +301,29 @@ int bmesh_disk_facevert_count(const BMVert *v)
count += bmesh_radial_facevert_count(e_iter->l, v);
}
} while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
- return count;
}
- else {
- return 0;
+ return count;
+}
+
+int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max)
+{
+ /* is there an edge on this vert at all */
+ int count = 0;
+ if (v->e) {
+ BMEdge *e_first, *e_iter;
+
+ /* first, loop around edge */
+ e_first = e_iter = v->e;
+ do {
+ if (e_iter->l) {
+ count += bmesh_radial_facevert_count_ex(e_iter->l, v, count_max - count);
+ if (count == count_max) {
+ break;
+ }
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
}
+ return count;
}
/**
@@ -456,6 +528,23 @@ int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v)
return count;
}
+int bmesh_radial_facevert_count_ex(const BMLoop *l, const BMVert *v, const int count_max)
+{
+ const BMLoop *l_iter;
+ int count = 0;
+ l_iter = l;
+ do {
+ if (l_iter->v == v) {
+ count++;
+ if (count == count_max) {
+ break;
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != l);
+
+ return count;
+}
+
/**
* \brief RADIAL CHECK FACE VERT
*
diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h
index 29868194bbf..07f94796bb2 100644
--- a/source/blender/bmesh/intern/bmesh_structure.h
+++ b/source/blender/bmesh/intern/bmesh_structure.h
@@ -49,6 +49,7 @@ BLI_INLINE BMEdge *bmesh_disk_edge_next_safe(const BMEdge *e, const BMVert *v) A
BLI_INLINE BMEdge *bmesh_disk_edge_prev_safe(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE BMEdge *bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int bmesh_disk_facevert_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -60,6 +61,7 @@ void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) ATTR_NONNULL(1);
* bmesh_radial_loop_next(BMLoop *l) / prev.
* just use member access l->radial_next, l->radial_prev now */
+int bmesh_radial_facevert_count_ex(const BMLoop *l, const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMLoop *bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -68,7 +70,9 @@ BMLoop *bmesh_radial_faceloop_find_vert(const BMFace *f, const BMVert *v) ATTR_W
bool bmesh_radial_validate(int radlen, BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* EDGE UTILITIES */
-bool bmesh_edge_swapverts(BMEdge *e, BMVert *v_orig, BMVert *v_new) ATTR_NONNULL();
+void bmesh_disk_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
+void bmesh_edge_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
+void bmesh_disk_vert_replace(BMEdge *e, BMVert *v_dst, BMVert *v_src) ATTR_NONNULL();
BMEdge *bmesh_disk_edge_exists(const BMVert *v1, const BMVert *v2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
diff --git a/source/blender/bmesh/intern/bmesh_structure_inline.h b/source/blender/bmesh/intern/bmesh_structure_inline.h
index 5b7e890f5ea..64292194ae7 100644
--- a/source/blender/bmesh/intern/bmesh_structure_inline.h
+++ b/source/blender/bmesh/intern/bmesh_structure_inline.h
@@ -27,6 +27,7 @@
#ifndef __BMESH_STRUCTURE_INLINE_H__
#define __BMESH_STRUCTURE_INLINE_H__
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE BMDiskLink *bmesh_disk_edge_link_from_vert(const BMEdge *e, const BMVert *v)
{
BLI_assert(BM_vert_in_edge(e, v));
@@ -40,6 +41,7 @@ BLI_INLINE BMDiskLink *bmesh_disk_edge_link_from_vert(const BMEdge *e, const BMV
*
* \return Pointer to the next edge in the disk cycle for the vertex v.
*/
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE BMEdge *bmesh_disk_edge_next_safe(const BMEdge *e, const BMVert *v)
{
if (v == e->v1)
@@ -49,6 +51,7 @@ BLI_INLINE BMEdge *bmesh_disk_edge_next_safe(const BMEdge *e, const BMVert *v)
return NULL;
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE BMEdge *bmesh_disk_edge_prev_safe(const BMEdge *e, const BMVert *v)
{
if (v == e->v1)
@@ -58,11 +61,13 @@ BLI_INLINE BMEdge *bmesh_disk_edge_prev_safe(const BMEdge *e, const BMVert *v)
return NULL;
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE BMEdge *bmesh_disk_edge_next(const BMEdge *e, const BMVert *v)
{
return BM_DISK_EDGE_NEXT(e, v);
}
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v)
{
return BM_DISK_EDGE_PREV(e, v);
diff --git a/source/blender/bmesh/intern/bmesh_walkers.c b/source/blender/bmesh/intern/bmesh_walkers.c
index 20b56632099..d16eb572540 100644
--- a/source/blender/bmesh/intern/bmesh_walkers.c
+++ b/source/blender/bmesh/intern/bmesh_walkers.c
@@ -74,10 +74,11 @@ void *BMW_begin(BMWalker *walker, void *start)
* a given type. The elements visited are filtered
* by the bitmask 'searchmask'.
*/
-void BMW_init(BMWalker *walker, BMesh *bm, int type,
- short mask_vert, short mask_edge, short mask_face,
- BMWFlag flag,
- int layer)
+void BMW_init(
+ BMWalker *walker, BMesh *bm, int type,
+ short mask_vert, short mask_edge, short mask_face,
+ BMWFlag flag,
+ int layer)
{
memset(walker, 0, sizeof(BMWalker));
diff --git a/source/blender/bmesh/intern/bmesh_walkers.h b/source/blender/bmesh/intern/bmesh_walkers.h
index d551ea9fba9..f5a801a31c3 100644
--- a/source/blender/bmesh/intern/bmesh_walkers.h
+++ b/source/blender/bmesh/intern/bmesh_walkers.h
@@ -76,10 +76,11 @@ typedef struct BMWalker {
/* initialize a walker. searchmask restricts some (not all) walkers to
* elements with a specific tool flag set. flags is specific to each walker.*/
-void BMW_init(struct BMWalker *walker, BMesh *bm, int type,
- short mask_vert, short mask_edge, short mask_face,
- BMWFlag flag,
- int layer);
+void BMW_init(
+ struct BMWalker *walker, BMesh *bm, int type,
+ short mask_vert, short mask_edge, short mask_face,
+ BMWFlag flag,
+ int layer);
void *BMW_begin(BMWalker *walker, void *start);
void *BMW_step(struct BMWalker *walker);
void BMW_end(struct BMWalker *walker);
@@ -92,6 +93,11 @@ void BMW_state_remove(BMWalker *walker);
void *BMW_walk(BMWalker *walker);
void BMW_reset(BMWalker *walker);
+#define BMW_ITER(ele, walker, data) \
+ for (BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMW_begin(walker, (BM_CHECK_TYPE_ELEM(data), data)); \
+ ele; \
+ BM_CHECK_TYPE_ELEM_ASSIGN(ele) = BMW_step(walker))
+
/*
* example of usage, walking over an island of tool flagged faces:
*
@@ -108,8 +114,10 @@ void BMW_reset(BMWalker *walker);
enum {
BMW_VERT_SHELL,
+ BMW_LOOP_SHELL,
+ BMW_LOOP_SHELL_WIRE,
BMW_FACE_SHELL,
- BMW_LOOP,
+ BMW_EDGELOOP,
BMW_FACELOOP,
BMW_EDGERING,
BMW_EDGEBOUNDARY,
diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c
index b7bf80b0e3f..0fb70b2b733 100644
--- a/source/blender/bmesh/intern/bmesh_walkers_impl.c
+++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c
@@ -223,6 +223,266 @@ static void *bmw_VertShellWalker_step(BMWalker *walker)
/** \} */
+/** \name LoopShell Walker
+ * \{
+ *
+ * Starts at any element on the mesh and walks over the 'shell' it belongs
+ * to via visiting connected loops.
+ *
+ * \note this is mainly useful to loop over a shell delimited by edges.
+ */
+static void bmw_LoopShellWalker_visitLoop(BMWalker *walker, BMLoop *l)
+{
+ BMwLoopShellWalker *shellWalk = NULL;
+
+ if (BLI_gset_haskey(walker->visit_set, l)) {
+ return;
+ }
+
+ shellWalk = BMW_state_add(walker);
+ shellWalk->curloop = l;
+ BLI_gset_insert(walker->visit_set, l);
+}
+
+static void bmw_LoopShellWalker_begin(BMWalker *walker, void *data)
+{
+ BMIter iter;
+ BMHeader *h = data;
+
+ if (UNLIKELY(h == NULL)) {
+ return;
+ }
+
+ switch (h->htype) {
+ case BM_LOOP:
+ {
+ /* starting the walk at a vert, add all the edges
+ * to the worklist */
+ BMLoop *l = (BMLoop *)h;
+ bmw_LoopShellWalker_visitLoop(walker, l);
+ break;
+ }
+
+ case BM_VERT:
+ {
+ BMVert *v = (BMVert *)h;
+ BMLoop *l;
+ BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ bmw_LoopShellWalker_visitLoop(walker, l);
+ }
+ break;
+ }
+ case BM_EDGE:
+ {
+ BMEdge *e = (BMEdge *)h;
+ BMLoop *l;
+ BM_ITER_ELEM (l, &iter, e, BM_LOOPS_OF_EDGE) {
+ bmw_LoopShellWalker_visitLoop(walker, l);
+ }
+ break;
+ }
+ case BM_FACE:
+ {
+ BMFace *f = (BMFace *)h;
+ BMLoop *l = BM_FACE_FIRST_LOOP(f);
+ /* walker will handle other loops within the face */
+ bmw_LoopShellWalker_visitLoop(walker, l);
+ break;
+ }
+ default:
+ BLI_assert(0);
+ }
+}
+
+static void *bmw_LoopShellWalker_yield(BMWalker *walker)
+{
+ BMwLoopShellWalker *shellWalk = BMW_current_state(walker);
+ return shellWalk->curloop;
+}
+
+static void bmw_LoopShellWalker_step_impl(BMWalker *walker, BMLoop *l)
+{
+ BMEdge *e_edj_pair[2];
+ int i;
+
+ /* seems paranoid, but one caller also walks edges */
+ BLI_assert(l->head.htype == BM_LOOP);
+
+ bmw_LoopShellWalker_visitLoop(walker, l->next);
+ bmw_LoopShellWalker_visitLoop(walker, l->prev);
+
+ e_edj_pair[0] = l->e;
+ e_edj_pair[1] = l->prev->e;
+
+ for (i = 0; i < 2; i++) {
+ BMEdge *e = e_edj_pair[i];
+ if (bmw_mask_check_edge(walker, e)) {
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = e->l;
+ do {
+ BMLoop *l_radial = (l_iter->v == l->v) ? l_iter : l_iter->next;
+ BLI_assert(l_radial->v == l->v);
+ if (l != l_radial) {
+ bmw_LoopShellWalker_visitLoop(walker, l_radial);
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+ }
+}
+
+static void *bmw_LoopShellWalker_step(BMWalker *walker)
+{
+ BMwLoopShellWalker *swalk, owalk;
+ BMLoop *l;
+
+ BMW_state_remove_r(walker, &owalk);
+ swalk = &owalk;
+
+ l = swalk->curloop;
+ bmw_LoopShellWalker_step_impl(walker, l);
+
+ return l;
+}
+
+/** \} */
+
+/** \name LoopShell & 'Wire' Walker
+ * \{
+ *
+ * Piggyback ontop of #BMwLoopShellWalker, but also walk over wire edges
+ * This isn't elegant but users expect it when selecting linked,
+ * so we can support delimiters _and_ walking over wire edges.
+ *
+ * Details:
+ * - can yield edges (as well as loops)
+ * - only step over wire edges.
+ * - verts and edges are stored in `visit_set_alt`.
+ */
+
+static void bmw_LoopShellWalker_visitEdgeWire(BMWalker *walker, BMEdge *e)
+{
+ BMwLoopShellWireWalker *shellWalk = NULL;
+
+ BLI_assert(BM_edge_is_wire(e));
+
+ if (BLI_gset_haskey(walker->visit_set_alt, e)) {
+ return;
+ }
+
+ shellWalk = BMW_state_add(walker);
+ shellWalk->curelem = (BMElem *)e;
+ BLI_gset_insert(walker->visit_set_alt, e);
+}
+
+static void bmw_LoopShellWireWalker_visitVert(BMWalker *walker, BMVert *v, const BMEdge *e_from)
+{
+ BMEdge *e;
+
+ BLI_assert(v->head.htype == BM_VERT);
+
+ if (BLI_gset_haskey(walker->visit_set_alt, v)) {
+ return;
+ }
+
+ e = v->e;
+ do {
+ if (BM_edge_is_wire(e) && (e != e_from)) {
+ BMVert *v_other;
+ BMIter iter;
+ BMLoop *l;
+
+ bmw_LoopShellWalker_visitEdgeWire(walker, e);
+
+ /* check if we step onto a non-wire vertex */
+ v_other = BM_edge_other_vert(e, v);
+ BM_ITER_ELEM (l, &iter, v_other, BM_LOOPS_OF_VERT) {
+ bmw_LoopShellWalker_visitLoop(walker, l);
+ }
+ }
+ } while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
+
+ BLI_gset_insert(walker->visit_set_alt, v);
+}
+
+static void bmw_LoopShellWireWalker_begin(BMWalker *walker, void *data)
+{
+ BMHeader *h = data;
+
+ if (UNLIKELY(h == NULL)) {
+ return;
+ }
+
+ bmw_LoopShellWalker_begin(walker, data);
+
+ switch (h->htype) {
+ case BM_LOOP:
+ {
+ BMLoop *l = (BMLoop *)h;
+ bmw_LoopShellWireWalker_visitVert(walker, l->v, NULL);
+ break;
+ }
+
+ case BM_VERT:
+ {
+ BMVert *v = (BMVert *)h;
+ bmw_LoopShellWireWalker_visitVert(walker, v, NULL);
+ break;
+ }
+ case BM_EDGE:
+ {
+ BMEdge *e = (BMEdge *)h;
+ if (BM_edge_is_wire(e)) {
+ bmw_LoopShellWalker_visitEdgeWire(walker, e);
+ }
+ break;
+ }
+ case BM_FACE:
+ {
+ /* wire verts will be walked over */
+ break;
+ }
+ default:
+ BLI_assert(0);
+ }
+}
+
+static void *bmw_LoopShellWireWalker_yield(BMWalker *walker)
+{
+ BMwLoopShellWireWalker *shellWalk = BMW_current_state(walker);
+ return shellWalk->curelem;
+}
+
+static void *bmw_LoopShellWireWalker_step(BMWalker *walker)
+{
+ BMwLoopShellWireWalker *swalk, owalk;
+
+ BMW_state_remove_r(walker, &owalk);
+ swalk = &owalk;
+
+ if (swalk->curelem->head.htype == BM_LOOP) {
+ BMLoop *l = (BMLoop *)swalk->curelem;
+
+ bmw_LoopShellWalker_step_impl(walker, l);
+
+ bmw_LoopShellWireWalker_visitVert(walker, l->v, NULL);
+
+ return l;
+ }
+ else {
+ BMEdge *e = (BMEdge *)swalk->curelem;
+
+ BLI_assert(e->head.htype == BM_EDGE);
+
+ bmw_LoopShellWireWalker_visitVert(walker, e->v1, e);
+ bmw_LoopShellWireWalker_visitVert(walker, e->v2, e);
+
+ return e;
+ }
+}
+
+/** \} */
+
/** \name FaceShell Walker
* \{
@@ -543,9 +803,9 @@ static bool bm_edge_is_single(BMEdge *e)
(BM_edge_is_boundary(e->l->next->e) || BM_edge_is_boundary(e->l->prev->e)));
}
-static void bmw_LoopWalker_begin(BMWalker *walker, void *data)
+static void bmw_EdgeLoopWalker_begin(BMWalker *walker, void *data)
{
- BMwLoopWalker *lwalk = NULL, owalk, *owalk_pt;
+ BMwEdgeLoopWalker *lwalk = NULL, owalk, *owalk_pt;
BMEdge *e = data;
BMVert *v;
const int vert_edge_count[2] = {
@@ -593,7 +853,7 @@ static void bmw_LoopWalker_begin(BMWalker *walker, void *data)
/* rewind */
while ((owalk_pt = BMW_current_state(walker))) {
- owalk = *((BMwLoopWalker *)owalk_pt);
+ owalk = *((BMwEdgeLoopWalker *)owalk_pt);
BMW_walk(walker);
}
@@ -606,16 +866,16 @@ static void bmw_LoopWalker_begin(BMWalker *walker, void *data)
BLI_gset_insert(walker->visit_set, owalk.cur);
}
-static void *bmw_LoopWalker_yield(BMWalker *walker)
+static void *bmw_EdgeLoopWalker_yield(BMWalker *walker)
{
- BMwLoopWalker *lwalk = BMW_current_state(walker);
+ BMwEdgeLoopWalker *lwalk = BMW_current_state(walker);
return lwalk->cur;
}
-static void *bmw_LoopWalker_step(BMWalker *walker)
+static void *bmw_EdgeLoopWalker_step(BMWalker *walker)
{
- BMwLoopWalker *lwalk, owalk;
+ BMwEdgeLoopWalker *lwalk, owalk;
BMEdge *e, *nexte = NULL;
BMLoop *l;
BMVert *v;
@@ -1248,6 +1508,26 @@ static BMWalker bmw_VertShellWalker_Type = {
BM_EDGE, /* valid restrict masks */
};
+static BMWalker bmw_LoopShellWalker_Type = {
+ BM_FACE | BM_LOOP | BM_EDGE | BM_VERT,
+ bmw_LoopShellWalker_begin,
+ bmw_LoopShellWalker_step,
+ bmw_LoopShellWalker_yield,
+ sizeof(BMwLoopShellWalker),
+ BMW_BREADTH_FIRST,
+ BM_EDGE, /* valid restrict masks */
+};
+
+static BMWalker bmw_LoopShellWireWalker_Type = {
+ BM_FACE | BM_LOOP | BM_EDGE | BM_VERT,
+ bmw_LoopShellWireWalker_begin,
+ bmw_LoopShellWireWalker_step,
+ bmw_LoopShellWireWalker_yield,
+ sizeof(BMwLoopShellWireWalker),
+ BMW_BREADTH_FIRST,
+ BM_EDGE, /* valid restrict masks */
+};
+
static BMWalker bmw_FaceShellWalker_Type = {
BM_EDGE,
bmw_FaceShellWalker_begin,
@@ -1278,12 +1558,12 @@ static BMWalker bmw_IslandWalker_Type = {
BM_EDGE | BM_FACE, /* valid restrict masks */
};
-static BMWalker bmw_LoopWalker_Type = {
+static BMWalker bmw_EdgeLoopWalker_Type = {
BM_EDGE,
- bmw_LoopWalker_begin,
- bmw_LoopWalker_step,
- bmw_LoopWalker_yield,
- sizeof(BMwLoopWalker),
+ bmw_EdgeLoopWalker_begin,
+ bmw_EdgeLoopWalker_step,
+ bmw_EdgeLoopWalker_yield,
+ sizeof(BMwEdgeLoopWalker),
BMW_DEPTH_FIRST,
0, /* valid restrict masks */ /* could add flags here but so far none are used */
};
@@ -1340,8 +1620,10 @@ static BMWalker bmw_ConnectedVertexWalker_Type = {
BMWalker *bm_walker_types[] = {
&bmw_VertShellWalker_Type, /* BMW_VERT_SHELL */
+ &bmw_LoopShellWalker_Type, /* BMW_LOOP_SHELL */
+ &bmw_LoopShellWireWalker_Type, /* BMW_LOOP_SHELL_WIRE */
&bmw_FaceShellWalker_Type, /* BMW_FACE_SHELL */
- &bmw_LoopWalker_Type, /* BMW_LOOP */
+ &bmw_EdgeLoopWalker_Type, /* BMW_EDGELOOP */
&bmw_FaceLoopWalker_Type, /* BMW_FACELOOP */
&bmw_EdgeringWalker_Type, /* BMW_EDGERING */
&bmw_EdgeboundaryWalker_Type, /* BMW_EDGEBOUNDARY */
diff --git a/source/blender/bmesh/intern/bmesh_walkers_private.h b/source/blender/bmesh/intern/bmesh_walkers_private.h
index 82d1e760db7..66d812b45d0 100644
--- a/source/blender/bmesh/intern/bmesh_walkers_private.h
+++ b/source/blender/bmesh/intern/bmesh_walkers_private.h
@@ -45,6 +45,16 @@ typedef struct BMwShellWalker {
BMEdge *curedge;
} BMwShellWalker;
+typedef struct BMwLoopShellWalker {
+ BMwGenericWalker header;
+ BMLoop *curloop;
+} BMwLoopShellWalker;
+
+typedef struct BMwLoopShellWireWalker {
+ BMwGenericWalker header;
+ BMElem *curelem;
+} BMwLoopShellWireWalker;
+
typedef struct BMwIslandboundWalker {
BMwGenericWalker header;
BMLoop *base;
@@ -57,14 +67,14 @@ typedef struct BMwIslandWalker {
BMFace *cur;
} BMwIslandWalker;
-typedef struct BMwLoopWalker {
+typedef struct BMwEdgeLoopWalker {
BMwGenericWalker header;
BMEdge *cur, *start;
BMVert *lastv, *startv;
BMFace *f_hub;
bool is_boundary; /* boundary looping changes behavior */
bool is_single; /* single means the edge verts are only connected to 1 face */
-} BMwLoopWalker;
+} BMwEdgeLoopWalker;
typedef struct BMwFaceLoopWalker {
BMwGenericWalker header;
diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c
index 6002dcf2c0d..b4570e03c83 100644
--- a/source/blender/bmesh/operators/bmo_bridge.c
+++ b/source/blender/bmesh/operators/bmo_bridge.c
@@ -87,8 +87,9 @@ static void bm_vert_loop_pair(BMesh *bm, BMVert *v1, BMVert *v2, BMLoop **l1, BM
}
/* el_b can have any offset */
-static float bm_edgeloop_offset_length(LinkData *el_a, LinkData *el_b,
- LinkData *el_b_first, const float len_max)
+static float bm_edgeloop_offset_length(
+ LinkData *el_a, LinkData *el_b,
+ LinkData *el_b_first, const float len_max)
{
float len = 0.0f;
BLI_assert(el_a->prev == NULL); /* must be first */
@@ -137,10 +138,11 @@ static bool bm_edge_test_cb(BMEdge *e, void *bm_v)
return BMO_elem_flag_test((BMesh *)bm_v, e, EDGE_MARK);
}
-static void bridge_loop_pair(BMesh *bm,
- struct BMEdgeLoopStore *el_store_a,
- struct BMEdgeLoopStore *el_store_b,
- const bool use_merge, const float merge_factor, const int twist_offset)
+static void bridge_loop_pair(
+ BMesh *bm,
+ struct BMEdgeLoopStore *el_store_a,
+ struct BMEdgeLoopStore *el_store_b,
+ const bool use_merge, const float merge_factor, const int twist_offset)
{
const float eps = 0.00001f;
LinkData *el_a_first, *el_b_first;
diff --git a/source/blender/bmesh/operators/bmo_connect_concave.c b/source/blender/bmesh/operators/bmo_connect_concave.c
index a00f65bd10f..107aead6994 100644
--- a/source/blender/bmesh/operators/bmo_connect_concave.c
+++ b/source/blender/bmesh/operators/bmo_connect_concave.c
@@ -79,8 +79,8 @@ static bool bm_face_split_by_concave(
struct Heap *pf_heap, struct EdgeHash *pf_ehash)
{
const int f_base_len = f_base->len;
- int faces_array_tot = f_base->len - 3;
- int edges_array_tot = f_base->len - 3;
+ int faces_array_tot = f_base_len - 3;
+ int edges_array_tot = f_base_len - 3;
BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot);
const int quad_method = 0, ngon_method = 0; /* beauty */
diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c
index fbc128b375f..cf0e233fe6c 100644
--- a/source/blender/bmesh/operators/bmo_connect_pair.c
+++ b/source/blender/bmesh/operators/bmo_connect_pair.c
@@ -152,8 +152,9 @@ static void min_dist_dir_update(MinDistDir *dist, const float dist_dir[3])
/** \} */
-static int state_isect_co_pair(const PathContext *pc,
- const float co_a[3], const float co_b[3])
+static int state_isect_co_pair(
+ const PathContext *pc,
+ const float co_a[3], const float co_b[3])
{
const float diff_a = dot_m3_v3_row_x((float (*)[3])pc->matrix, co_a) - pc->axis_sep;
const float diff_b = dot_m3_v3_row_x((float (*)[3])pc->matrix, co_b) - pc->axis_sep;
@@ -169,15 +170,17 @@ static int state_isect_co_pair(const PathContext *pc,
}
}
-static int state_isect_co_exact(const PathContext *pc,
- const float co[3])
+static int state_isect_co_exact(
+ const PathContext *pc,
+ const float co[3])
{
const float diff = dot_m3_v3_row_x((float (*)[3])pc->matrix, co) - pc->axis_sep;
return (fabsf(diff) <= CONNECT_EPS);
}
-static float state_calc_co_pair_fac(const PathContext *pc,
- const float co_a[3], const float co_b[3])
+static float state_calc_co_pair_fac(
+ const PathContext *pc,
+ const float co_a[3], const float co_b[3])
{
float diff_a, diff_b, diff_tot;
@@ -187,9 +190,10 @@ static float state_calc_co_pair_fac(const PathContext *pc,
return (diff_tot > FLT_EPSILON) ? (diff_a / diff_tot) : 0.5f;
}
-static void state_calc_co_pair(const PathContext *pc,
- const float co_a[3], const float co_b[3],
- float r_co[3])
+static void state_calc_co_pair(
+ const PathContext *pc,
+ const float co_a[3], const float co_b[3],
+ float r_co[3])
{
const float fac = state_calc_co_pair_fac(pc, co_a, co_b);
interp_v3_v3v3(r_co, co_a, co_b, fac);
@@ -213,8 +217,9 @@ static bool state_link_find(const PathLinkState *state, BMElem *ele)
return false;
}
-static void state_link_add(PathContext *pc, PathLinkState *state,
- BMElem *ele, BMElem *ele_from)
+static void state_link_add(
+ PathContext *pc, PathLinkState *state,
+ BMElem *ele, BMElem *ele_from)
{
PathLink *step_new = BLI_mempool_alloc(pc->link_pool);
BLI_assert(ele != ele_from);
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index ecb41363761..ac0466a74d2 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -494,7 +494,7 @@ void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op)
static void bm_mesh_edge_collapse_flagged(BMesh *bm, const int flag, const short oflag)
{
- BMO_op_callf(bm, flag, "collapse edges=%fe", oflag);
+ BMO_op_callf(bm, flag, "collapse edges=%fe uvs=%b", oflag, true);
}
void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c
index a5a6480c187..33048e6c86e 100644
--- a/source/blender/bmesh/operators/bmo_dupe.c
+++ b/source/blender/bmesh/operators/bmo_dupe.c
@@ -44,9 +44,10 @@
*
* Copy an existing vertex from one bmesh to another.
*/
-static BMVert *bmo_vert_copy(BMOperator *op,
- BMOpSlot *slot_vertmap_out,
- BMesh *bm_dst, BMesh *bm_src, BMVert *v_src, GHash *vhash)
+static BMVert *bmo_vert_copy(
+ BMOperator *op,
+ BMOpSlot *slot_vertmap_out,
+ BMesh *bm_dst, BMesh *bm_src, BMVert *v_src, GHash *vhash)
{
BMVert *v_dst;
@@ -72,12 +73,13 @@ static BMVert *bmo_vert_copy(BMOperator *op,
*
* Copy an existing edge from one bmesh to another.
*/
-static BMEdge *bmo_edge_copy(BMOperator *op,
- BMOpSlot *slot_edgemap_out,
- BMOpSlot *slot_boundarymap_out,
- BMesh *bm_dst, BMesh *bm_src,
- BMEdge *e_src,
- GHash *vhash, GHash *ehash)
+static BMEdge *bmo_edge_copy(
+ BMOperator *op,
+ BMOpSlot *slot_edgemap_out,
+ BMOpSlot *slot_boundarymap_out,
+ BMesh *bm_dst, BMesh *bm_src,
+ BMEdge *e_src,
+ GHash *vhash, GHash *ehash)
{
BMEdge *e_dst;
BMVert *e_dst_v1, *e_dst_v2;
@@ -131,11 +133,12 @@ static BMEdge *bmo_edge_copy(BMOperator *op,
*
* Copy an existing face from one bmesh to another.
*/
-static BMFace *bmo_face_copy(BMOperator *op,
- BMOpSlot *slot_facemap_out,
- BMesh *bm_dst, BMesh *bm_src,
- BMFace *f_src,
- GHash *vhash, GHash *ehash)
+static BMFace *bmo_face_copy(
+ BMOperator *op,
+ BMOpSlot *slot_facemap_out,
+ BMesh *bm_dst, BMesh *bm_src,
+ BMFace *f_src,
+ GHash *vhash, GHash *ehash)
{
BMFace *f_dst;
BMVert **vtar = BLI_array_alloca(vtar, f_src->len);
diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c
index aa92c3054cd..435b9e60949 100644
--- a/source/blender/bmesh/operators/bmo_extrude.c
+++ b/source/blender/bmesh/operators/bmo_extrude.c
@@ -39,6 +39,8 @@
#include "intern/bmesh_operators_private.h" /* own include */
+#define USE_EDGE_REGION_FLAGS
+
enum {
EXT_INPUT = 1,
EXT_KEEP = 2,
@@ -287,6 +289,39 @@ void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EXT_KEEP);
}
+#ifdef USE_EDGE_REGION_FLAGS
+/**
+ * When create an edge for an extruded face region
+ * check surrounding edge flags before creating a new edge.
+ */
+static bool bm_extrude_region_edge_flag(const BMVert *v, char r_e_hflag[2])
+{
+ BMEdge *e_iter;
+ const char hflag_enable = BM_ELEM_SEAM;
+ const char hflag_disable = BM_ELEM_SMOOTH;
+ bool ok = false;
+
+ r_e_hflag[0] = 0x0;
+ r_e_hflag[1] = 0xff;
+
+ /* clear flags on both disks */
+ e_iter = v->e;
+ do {
+ if (e_iter->l && !BM_edge_is_boundary(e_iter)) {
+ r_e_hflag[0] |= e_iter->head.hflag;
+ r_e_hflag[1] &= e_iter->head.hflag;
+ ok = true;
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != v->e);
+
+ if (ok) {
+ r_e_hflag[0] &= hflag_enable;
+ r_e_hflag[1] = hflag_disable & ~r_e_hflag[1];
+ }
+ return ok;
+}
+#endif /* USE_EDGE_REGION_FLAGS */
+
void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
{
BMOperator dupeop, delop;
@@ -413,6 +448,9 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
slot_edges_exclude = BMO_slot_get(op->slots_in, "edges_exclude");
for (e = BMO_iter_new(&siter, dupeop.slots_out, "boundary_map.out", 0); e; e = BMO_iter_step(&siter)) {
BMVert *f_verts[4];
+#ifdef USE_EDGE_REGION_FLAGS
+ BMEdge *f_edges[4];
+#endif
/* this should always be wire, so this is mainly a speedup to avoid map lookup */
if (BM_edge_is_wire(e) && BMO_slot_map_contains(slot_edges_exclude, e)) {
@@ -465,8 +503,38 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
f_verts[3] = e_new->v2;
}
- /* not sure what to do about example face, pass NULL for now */
+#ifdef USE_EDGE_REGION_FLAGS
+ /* handle new edges */
+ f_edges[0] = e;
+ f_edges[2] = e_new;
+
+ f_edges[1] = BM_edge_exists(f_verts[1], f_verts[2]);
+ if (f_edges[1] == NULL) {
+ char e_hflag[2];
+ bool e_hflag_ok = bm_extrude_region_edge_flag(f_verts[2], e_hflag);
+ f_edges[1] = BM_edge_create(bm, f_verts[1], f_verts[2], NULL, BM_CREATE_NOP);
+ if (e_hflag_ok) {
+ BM_elem_flag_enable(f_edges[1], e_hflag[0]);
+ BM_elem_flag_disable(f_edges[1], e_hflag[1]);
+ }
+ }
+
+ f_edges[3] = BM_edge_exists(f_verts[3], f_verts[0]);
+ if (f_edges[3] == NULL) {
+ char e_hflag[2];
+ bool e_hflag_ok = bm_extrude_region_edge_flag(f_verts[3], e_hflag);
+ f_edges[3] = BM_edge_create(bm, f_verts[3], f_verts[0], NULL, BM_CREATE_NOP);
+ if (e_hflag_ok) {
+ BM_elem_flag_enable(f_edges[3], e_hflag[0]);
+ BM_elem_flag_disable(f_edges[3], e_hflag[1]);
+ }
+ }
+
+ f = BM_face_create(bm, f_verts, f_edges, 4, NULL, BM_CREATE_NOP);
+#else
f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true);
+#endif
+
bm_extrude_copy_face_loop_attributes(bm, f);
}
diff --git a/source/blender/bmesh/operators/bmo_fill_attribute.c b/source/blender/bmesh/operators/bmo_fill_attribute.c
index d9f50ac891c..85bca744d86 100644
--- a/source/blender/bmesh/operators/bmo_fill_attribute.c
+++ b/source/blender/bmesh/operators/bmo_fill_attribute.c
@@ -61,8 +61,9 @@ static bool bm_loop_is_face_untag(BMElem *ele, void *UNUSED(user_data))
/**
* Copy all attributes from adjacent untagged faces.
*/
-static void bm_face_copy_shared_all(BMesh *bm, BMLoop *l,
- const bool use_normals, const bool use_data)
+static void bm_face_copy_shared_all(
+ BMesh *bm, BMLoop *l,
+ const bool use_normals, const bool use_data)
{
BMLoop *l_other = l->radial_next;
BMFace *f = l->f, *f_other;
@@ -90,8 +91,9 @@ static void bm_face_copy_shared_all(BMesh *bm, BMLoop *l,
/**
* Flood fill attributes.
*/
-static unsigned int bmesh_face_attribute_fill(BMesh *bm,
- const bool use_normals, const bool use_data)
+static unsigned int bmesh_face_attribute_fill(
+ BMesh *bm,
+ const bool use_normals, const bool use_data)
{
BLI_LINKSTACK_DECLARE(loop_queue_prev, BMLoop *);
BLI_LINKSTACK_DECLARE(loop_queue_next, BMLoop *);
diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c
index dd954adcd55..fd1e91a0b30 100644
--- a/source/blender/bmesh/operators/bmo_fill_grid.c
+++ b/source/blender/bmesh/operators/bmo_fill_grid.c
@@ -114,8 +114,9 @@ static void quad_verts_to_barycentric_tri(
/**
* Assign a loop pair from 2 verts (which _must_ share an edge)
*/
-static void bm_loop_pair_from_verts(BMVert *v_a, BMVert *v_b,
- BMLoop *l_pair[2])
+static void bm_loop_pair_from_verts(
+ BMVert *v_a, BMVert *v_b,
+ BMLoop *l_pair[2])
{
BMEdge *e = BM_edge_exists(v_a, v_b);
if (e->l) {
@@ -185,8 +186,9 @@ static void bm_loop_interp_from_grid_boundary_2(BMesh *bm, BMLoop *l, BMLoop *l_
/**
* Avoids calling #barycentric_weights_v2_quad often by caching weights into an array.
*/
-static void barycentric_weights_v2_grid_cache(const unsigned int xtot, const unsigned int ytot,
- float (*weight_table)[4])
+static void barycentric_weights_v2_grid_cache(
+ const unsigned int xtot, const unsigned int ytot,
+ float (*weight_table)[4])
{
float x_step = 1.0f / (float)(xtot - 1);
float y_step = 1.0f / (float)(ytot - 1);
@@ -216,9 +218,10 @@ static void barycentric_weights_v2_grid_cache(const unsigned int xtot, const uns
*
* \param v_grid 2d array of verts, all boundary verts must be set, we fill in the middle.
*/
-static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const unsigned int xtot, unsigned const int ytot,
- const short mat_nr, const bool use_smooth,
- const bool use_flip, const bool use_interp_simple)
+static void bm_grid_fill_array(
+ BMesh *bm, BMVert **v_grid, const unsigned int xtot, unsigned const int ytot,
+ const short mat_nr, const bool use_smooth,
+ const bool use_flip, const bool use_interp_simple)
{
const bool use_vert_interp = CustomData_has_interp(&bm->vdata);
const bool use_loop_interp = CustomData_has_interp(&bm->ldata);
@@ -485,10 +488,11 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const unsigned int xt
#undef XY
}
-static void bm_grid_fill(BMesh *bm,
- struct BMEdgeLoopStore *estore_a, struct BMEdgeLoopStore *estore_b,
- struct BMEdgeLoopStore *estore_rail_a, struct BMEdgeLoopStore *estore_rail_b,
- const short mat_nr, const bool use_smooth, const bool use_interp_simple)
+static void bm_grid_fill(
+ BMesh *bm,
+ struct BMEdgeLoopStore *estore_a, struct BMEdgeLoopStore *estore_b,
+ struct BMEdgeLoopStore *estore_rail_a, struct BMEdgeLoopStore *estore_rail_b,
+ const short mat_nr, const bool use_smooth, const bool use_interp_simple)
{
#define USE_FLIP_DETECT
diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c
index fb99c9777d0..2dfad5a1f47 100644
--- a/source/blender/bmesh/operators/bmo_hull.c
+++ b/source/blender/bmesh/operators/bmo_hull.c
@@ -67,8 +67,9 @@ typedef struct HullTriangle {
/*************************** Hull Triangles ***************************/
-static void hull_add_triangle(BMesh *bm, GSet *hull_triangles, BLI_mempool *pool,
- BMVert *v1, BMVert *v2, BMVert *v3)
+static void hull_add_triangle(
+ BMesh *bm, GSet *hull_triangles, BLI_mempool *pool,
+ BMVert *v1, BMVert *v2, BMVert *v3)
{
HullTriangle *t;
int i;
@@ -189,8 +190,9 @@ static LinkData *final_edges_find_link(ListBase *adj, BMVert *v)
return NULL;
}
-static int hull_final_edges_lookup(HullFinalEdges *final_edges,
- BMVert *v1, BMVert *v2)
+static int hull_final_edges_lookup(
+ HullFinalEdges *final_edges,
+ BMVert *v1, BMVert *v2)
{
ListBase *adj;
@@ -259,8 +261,9 @@ static void hull_final_edges_free(HullFinalEdges *final_edges)
/**************************** Final Output ****************************/
-static void hull_remove_overlapping(BMesh *bm, GSet *hull_triangles,
- HullFinalEdges *final_edges)
+static void hull_remove_overlapping(
+ BMesh *bm, GSet *hull_triangles,
+ HullFinalEdges *final_edges)
{
GSetIterator hull_iter;
@@ -296,8 +299,9 @@ static void hull_remove_overlapping(BMesh *bm, GSet *hull_triangles,
}
}
-static void hull_mark_interior_elements(BMesh *bm, BMOperator *op,
- HullFinalEdges *final_edges)
+static void hull_mark_interior_elements(
+ BMesh *bm, BMOperator *op,
+ HullFinalEdges *final_edges)
{
BMEdge *e;
BMFace *f;
@@ -425,8 +429,9 @@ static int hull_input_vert_count(BMOperator *op)
return count;
}
-static BMVert **hull_input_verts_copy(BMOperator *op,
- const int num_input_verts)
+static BMVert **hull_input_verts_copy(
+ BMOperator *op,
+ const int num_input_verts)
{
BMOIter oiter;
BMVert *v;
@@ -441,8 +446,9 @@ static BMVert **hull_input_verts_copy(BMOperator *op,
return input_verts;
}
-static float (*hull_verts_for_bullet(BMVert **input_verts,
- const int num_input_verts))[3]
+static float (*hull_verts_for_bullet(
+ BMVert **input_verts,
+ const int num_input_verts))[3]
{
float (*coords)[3] = MEM_callocN(sizeof(*coords) * num_input_verts, __func__);
int i;
@@ -454,9 +460,10 @@ static float (*hull_verts_for_bullet(BMVert **input_verts,
return coords;
}
-static BMVert **hull_verts_from_bullet(plConvexHull hull,
- BMVert **input_verts,
- const int num_input_verts)
+static BMVert **hull_verts_from_bullet(
+ plConvexHull hull,
+ BMVert **input_verts,
+ const int num_input_verts)
{
const int num_verts = plConvexHullNumVertices(hull);
BMVert **hull_verts = MEM_mallocN(sizeof(*hull_verts) *
@@ -478,9 +485,10 @@ static BMVert **hull_verts_from_bullet(plConvexHull hull,
return hull_verts;
}
-static void hull_from_bullet(BMesh *bm, BMOperator *op,
- GSet *hull_triangles,
- BLI_mempool *pool)
+static void hull_from_bullet(
+ BMesh *bm, BMOperator *op,
+ GSet *hull_triangles,
+ BLI_mempool *pool)
{
int *fvi = NULL;
BLI_array_declare(fvi);
@@ -529,6 +537,9 @@ static void hull_from_bullet(BMesh *bm, BMOperator *op,
}
BLI_array_free(fvi);
+
+ plConvexHullDelete(hull);
+
MEM_freeN(hull_verts);
MEM_freeN(coords);
MEM_freeN(input_verts);
diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c
index 27e140eb990..3d899bdef28 100644
--- a/source/blender/bmesh/operators/bmo_inset.c
+++ b/source/blender/bmesh/operators/bmo_inset.c
@@ -974,7 +974,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
v_glue = v_split;
}
else {
- BM_vert_splice(bm, v_split, v_glue);
+ BM_vert_splice(bm, v_glue, v_split);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c
index 6562f26062f..841a68fbbe5 100644
--- a/source/blender/bmesh/operators/bmo_join_triangles.c
+++ b/source/blender/bmesh/operators/bmo_join_triangles.c
@@ -42,163 +42,230 @@
#include "intern/bmesh_operators_private.h" /* own include */
-#define FACE_OUT (1 << 0)
-
/* assumes edges are validated before reaching this poin */
-static float measure_facepair(const float v1[3], const float v2[3],
- const float v3[3], const float v4[3], float limit)
+static float quad_calc_error(
+ const float v1[3], const float v2[3],
+ const float v3[3], const float v4[3])
{
/* gives a 'weight' to a pair of triangles that join an edge to decide how good a join they would make */
/* Note: this is more complicated than it needs to be and should be cleaned up.. */
- float n1[3], n2[3], measure = 0.0f, angle1, angle2, diff;
- float edgeVec1[3], edgeVec2[3], edgeVec3[3], edgeVec4[3];
- float minarea, maxarea, areaA, areaB;
-
- /* First Test: Normal difference */
- normal_tri_v3(n1, v1, v2, v3);
- normal_tri_v3(n2, v1, v3, v4);
- angle1 = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2);
-
- normal_tri_v3(n1, v2, v3, v4);
- normal_tri_v3(n2, v4, v1, v2);
- angle2 = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2);
-
- measure += (angle1 + angle2) * 0.5f;
- if (measure > limit) {
- return measure;
+ float error = 0.0f;
+
+ /* Normal difference */
+ {
+ float n1[3], n2[3];
+ float angle_a, angle_b;
+ float diff;
+
+ normal_tri_v3(n1, v1, v2, v3);
+ normal_tri_v3(n2, v1, v3, v4);
+ angle_a = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2);
+
+ normal_tri_v3(n1, v2, v3, v4);
+ normal_tri_v3(n2, v4, v1, v2);
+ angle_b = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2);
+
+ diff = (angle_a + angle_b) / (float)(M_PI * 2);
+
+ error += diff;
}
- /* Second test: Colinearity */
- sub_v3_v3v3(edgeVec1, v1, v2);
- sub_v3_v3v3(edgeVec2, v2, v3);
- sub_v3_v3v3(edgeVec3, v3, v4);
- sub_v3_v3v3(edgeVec4, v4, v1);
-
- normalize_v3(edgeVec1);
- normalize_v3(edgeVec2);
- normalize_v3(edgeVec3);
- normalize_v3(edgeVec4);
-
- /* a completely skinny face is 'pi' after halving */
- diff = 0.25f * (fabsf(angle_normalized_v3v3(edgeVec1, edgeVec2) - (float)M_PI_2) +
- fabsf(angle_normalized_v3v3(edgeVec2, edgeVec3) - (float)M_PI_2) +
- fabsf(angle_normalized_v3v3(edgeVec3, edgeVec4) - (float)M_PI_2) +
- fabsf(angle_normalized_v3v3(edgeVec4, edgeVec1) - (float)M_PI_2));
-
- if (!diff) {
- return 0.0;
+ /* Colinearity */
+ {
+ float edge_vecs[4][3];
+ float diff;
+
+ sub_v3_v3v3(edge_vecs[0], v1, v2);
+ sub_v3_v3v3(edge_vecs[1], v2, v3);
+ sub_v3_v3v3(edge_vecs[2], v3, v4);
+ sub_v3_v3v3(edge_vecs[3], v4, v1);
+
+ normalize_v3(edge_vecs[0]);
+ normalize_v3(edge_vecs[1]);
+ normalize_v3(edge_vecs[2]);
+ normalize_v3(edge_vecs[3]);
+
+ /* a completely skinny face is 'pi' after halving */
+ diff = (fabsf(angle_normalized_v3v3(edge_vecs[0], edge_vecs[1]) - (float)M_PI_2) +
+ fabsf(angle_normalized_v3v3(edge_vecs[1], edge_vecs[2]) - (float)M_PI_2) +
+ fabsf(angle_normalized_v3v3(edge_vecs[2], edge_vecs[3]) - (float)M_PI_2) +
+ fabsf(angle_normalized_v3v3(edge_vecs[3], edge_vecs[0]) - (float)M_PI_2)) / (float)(M_PI * 2);
+
+ error += diff;
}
- measure += diff;
- if (measure > limit) {
- return measure;
+ /* Concavity */
+ {
+ float area_min, area_max, area_a, area_b;
+ float diff;
+
+ area_a = area_tri_v3(v1, v2, v3) + area_tri_v3(v1, v3, v4);
+ area_b = area_tri_v3(v2, v3, v4) + area_tri_v3(v4, v1, v2);
+
+ area_min = min_ff(area_a, area_b);
+ area_max = max_ff(area_a, area_b);
+
+ diff = area_max ? (1.0 - (area_min / area_max)) : 1.0f;
+
+ error += diff;
}
- /* Third test: Concavity */
- areaA = area_tri_v3(v1, v2, v3) + area_tri_v3(v1, v3, v4);
- areaB = area_tri_v3(v2, v3, v4) + area_tri_v3(v4, v1, v2);
+ return error;
+}
+
+static void bm_edge_to_quad_verts(const BMEdge *e, const BMVert *r_v_quad[4])
+{
+ BLI_assert(e->l->f->len == 3 && e->l->radial_next->f->len == 3);
+ BLI_assert(BM_edge_is_manifold(e));
+ r_v_quad[0] = e->l->v;
+ r_v_quad[1] = e->l->prev->v;
+ r_v_quad[2] = e->l->next->v;
+ r_v_quad[3] = e->l->radial_next->prev->v;
+}
- if (areaA <= areaB) minarea = areaA;
- else minarea = areaB;
+/* cache customdata delimiters */
+struct DelimitData_CD {
+ int cd_type;
+ int cd_size;
+ int cd_offset;
+ int cd_offset_end;
+};
- if (areaA >= areaB) maxarea = areaA;
- else maxarea = areaB;
+struct DelimitData {
+ unsigned int do_seam : 1;
+ unsigned int do_sharp : 1;
+ unsigned int do_mat : 1;
+ unsigned int do_angle_face : 1;
+ unsigned int do_angle_shape : 1;
- if (!maxarea) measure += 1;
- else measure += (1 - (minarea / maxarea));
+ float angle_face;
+ float angle_face__cos;
- return measure;
+ float angle_shape;
+
+ struct DelimitData_CD cdata[4];
+ int cdata_len;
+};
+
+static bool bm_edge_is_contiguous_loop_cd_all(
+ const BMEdge *e, const struct DelimitData_CD *delimit_data)
+{
+ int cd_offset;
+ for (cd_offset = delimit_data->cd_offset;
+ cd_offset < delimit_data->cd_offset_end;
+ cd_offset += delimit_data->cd_size)
+ {
+ if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_type, cd_offset) == false) {
+ return false;
+ }
+ }
+
+ return true;
}
-#define T2QUV_LIMIT 0.005f
-#define T2QCOL_LIMIT 3
+static bool bm_edge_delimit_cdata(
+ CustomData *ldata, CustomDataType type,
+ struct DelimitData_CD *r_delim_cd)
+{
+ const int layer_len = CustomData_number_of_layers(ldata, type);
+ r_delim_cd->cd_type = type;
+ r_delim_cd->cd_size = CustomData_sizeof(r_delim_cd->cd_type);
+ r_delim_cd->cd_offset = CustomData_get_n_offset(ldata, type, 0);
+ r_delim_cd->cd_offset_end = r_delim_cd->cd_size * layer_len;
+ return (r_delim_cd->cd_offset != -1);
+}
-static bool bm_edge_faces_cmp(BMesh *bm, BMEdge *e, const bool do_uv, const bool do_tf, const bool do_vcol)
+static float bm_edge_is_delimit(
+ const BMEdge *e,
+ const struct DelimitData *delimit_data)
{
- /* first get loops */
- BMLoop *l[4];
-
- l[0] = e->l;
- l[2] = e->l->radial_next;
-
- /* match up loops on each side of an edge corresponding to each vert */
- if (l[0]->v == l[2]->v) {
- l[1] = l[0]->next;
- l[3] = l[1]->next;
+ BMFace *f_a = e->l->f, *f_b = e->l->radial_next->f;
+#if 0
+ const bool is_contig = BM_edge_is_contiguous(e);
+ float angle;
+#endif
+
+ if ((delimit_data->do_seam) &&
+ (BM_elem_flag_test(e, BM_ELEM_SEAM)))
+ {
+ goto fail;
}
- else {
- l[1] = l[0]->next;
- l[3] = l[2];
- l[2] = l[3]->next;
+ if ((delimit_data->do_sharp) &&
+ (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0))
+ {
+ goto fail;
}
- /* Test UV's */
- if (do_uv) {
- const MLoopUV *luv[4] = {
- CustomData_bmesh_get(&bm->ldata, l[0]->head.data, CD_MLOOPUV),
- CustomData_bmesh_get(&bm->ldata, l[1]->head.data, CD_MLOOPUV),
- CustomData_bmesh_get(&bm->ldata, l[2]->head.data, CD_MLOOPUV),
- CustomData_bmesh_get(&bm->ldata, l[3]->head.data, CD_MLOOPUV),
- };
-
- /* do UV */
- if (luv[0] && (!compare_v2v2(luv[0]->uv, luv[2]->uv, T2QUV_LIMIT) ||
- !compare_v2v2(luv[1]->uv, luv[3]->uv, T2QUV_LIMIT)))
- {
- return false;
+ if ((delimit_data->do_mat) &&
+ (f_a->mat_nr != f_b->mat_nr))
+ {
+ goto fail;
+ }
+
+ if (delimit_data->do_angle_face) {
+ if (dot_v3v3(f_a->no, f_b->no) < delimit_data->angle_face__cos) {
+ goto fail;
}
}
- if (do_tf) {
- const MTexPoly *tp[2] = {
- CustomData_bmesh_get(&bm->pdata, l[0]->f->head.data, CD_MTEXPOLY),
- CustomData_bmesh_get(&bm->pdata, l[1]->f->head.data, CD_MTEXPOLY),
- };
+ if (delimit_data->do_angle_shape) {
+ const BMVert *verts[4];
+ bm_edge_to_quad_verts(e, verts);
- if (tp[0] && (tp[0]->tpage != tp[1]->tpage)) {
- return false;
+ /* if we're checking the shape at all, a flipped face is out of the question */
+ if (is_quad_flip_v3(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co)) {
+ goto fail;
+ }
+ else {
+ float edge_vecs[4][3];
+
+ sub_v3_v3v3(edge_vecs[0], verts[0]->co, verts[1]->co);
+ sub_v3_v3v3(edge_vecs[1], verts[1]->co, verts[2]->co);
+ sub_v3_v3v3(edge_vecs[2], verts[2]->co, verts[3]->co);
+ sub_v3_v3v3(edge_vecs[3], verts[3]->co, verts[0]->co);
+
+ normalize_v3(edge_vecs[0]);
+ normalize_v3(edge_vecs[1]);
+ normalize_v3(edge_vecs[2]);
+ normalize_v3(edge_vecs[3]);
+
+ if ((fabsf(angle_normalized_v3v3(edge_vecs[0], edge_vecs[1]) - (float)M_PI_2) > delimit_data->angle_shape) ||
+ (fabsf(angle_normalized_v3v3(edge_vecs[1], edge_vecs[2]) - (float)M_PI_2) > delimit_data->angle_shape) ||
+ (fabsf(angle_normalized_v3v3(edge_vecs[2], edge_vecs[3]) - (float)M_PI_2) > delimit_data->angle_shape) ||
+ (fabsf(angle_normalized_v3v3(edge_vecs[3], edge_vecs[0]) - (float)M_PI_2) > delimit_data->angle_shape))
+ {
+ goto fail;
+ }
}
}
- /* Test Vertex Colors */
- if (do_vcol) {
- const MLoopCol *lcol[4] = {
- CustomData_bmesh_get(&bm->ldata, l[0]->head.data, CD_MLOOPCOL),
- CustomData_bmesh_get(&bm->ldata, l[1]->head.data, CD_MLOOPCOL),
- CustomData_bmesh_get(&bm->ldata, l[2]->head.data, CD_MLOOPCOL),
- CustomData_bmesh_get(&bm->ldata, l[3]->head.data, CD_MLOOPCOL),
- };
-
- if (lcol[0]) {
- if (!compare_rgb_uchar((unsigned char *)&lcol[0]->r, (unsigned char *)&lcol[2]->r, T2QCOL_LIMIT) ||
- !compare_rgb_uchar((unsigned char *)&lcol[1]->r, (unsigned char *)&lcol[3]->r, T2QCOL_LIMIT))
- {
- return false;
+ if (delimit_data->cdata_len) {
+ int i;
+ for (i = 0; i < delimit_data->cdata_len; i++) {
+ if (!bm_edge_is_contiguous_loop_cd_all(e, &delimit_data->cdata[i])) {
+ goto fail;
}
}
}
+ return false;
+
+fail:
return true;
}
-#define EDGE_MARK 1
-#define EDGE_CHOSEN 2
-
-#define FACE_MARK 1
-#define FACE_INPUT 2
-
+#define EDGE_MARK (1 << 0)
+#define EDGE_CHOSEN (1 << 1)
+#define FACE_OUT (1 << 0)
+#define FACE_MARK (1 << 1)
+#define FACE_INPUT (1 << 2)
void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
{
- const bool do_sharp = BMO_slot_bool_get(op->slots_in, "cmp_sharp");
- const bool do_uv = BMO_slot_bool_get(op->slots_in, "cmp_uvs");
- const bool do_tf = do_uv; /* texture face, make make its own option eventually */
- const bool do_vcol = BMO_slot_bool_get(op->slots_in, "cmp_vcols");
- const bool do_mat = BMO_slot_bool_get(op->slots_in, "cmp_materials");
- const float limit = BMO_slot_float_get(op->slots_in, "limit");
+ float angle_face, angle_shape;
BMIter iter;
BMOIter siter;
@@ -209,6 +276,44 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
unsigned i, totedge;
unsigned int totedge_tag = 0;
+ struct DelimitData delimit_data = {0};
+
+ delimit_data.do_seam = BMO_slot_bool_get(op->slots_in, "cmp_seam");
+ delimit_data.do_sharp = BMO_slot_bool_get(op->slots_in, "cmp_sharp");
+ delimit_data.do_mat = BMO_slot_bool_get(op->slots_in, "cmp_materials");
+
+ angle_face = BMO_slot_float_get(op->slots_in, "angle_face_threshold");
+ if (angle_face < DEG2RADF(180.0f)) {
+ delimit_data.angle_face = angle_face;
+ delimit_data.angle_face__cos = cosf(angle_face);
+ delimit_data.do_angle_face = true;
+ }
+ else {
+ delimit_data.do_angle_face = false;
+ }
+
+ angle_shape = BMO_slot_float_get(op->slots_in, "angle_shape_threshold");
+ if (angle_shape < DEG2RADF(180.0f)) {
+ delimit_data.angle_shape = angle_shape;
+ delimit_data.do_angle_shape = true;
+ }
+ else {
+ delimit_data.do_angle_shape = false;
+ }
+
+ if (BMO_slot_bool_get(op->slots_in, "cmp_uvs") &&
+ bm_edge_delimit_cdata(&bm->ldata, CD_MLOOPUV, &delimit_data.cdata[delimit_data.cdata_len]))
+ {
+ delimit_data.cdata_len += 1;
+ }
+
+ delimit_data.cdata[delimit_data.cdata_len].cd_offset = -1;
+ if (BMO_slot_bool_get(op->slots_in, "cmp_vcols") &&
+ bm_edge_delimit_cdata(&bm->ldata, CD_MLOOPCOL, &delimit_data.cdata[delimit_data.cdata_len]))
+ {
+ delimit_data.cdata_len += 1;
+ }
+
/* flag all edges of all input face */
BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
if (f->len == 3) {
@@ -220,10 +325,13 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
BMFace *f_a, *f_b;
if (BM_edge_face_pair(e, &f_a, &f_b) &&
- (BMO_elem_flag_test(bm, f_a, FACE_INPUT) && BMO_elem_flag_test(bm, f_b, FACE_INPUT)))
+ (BMO_elem_flag_test(bm, f_a, FACE_INPUT) &&
+ BMO_elem_flag_test(bm, f_b, FACE_INPUT)))
{
- BMO_elem_flag_enable(bm, e, EDGE_MARK);
- totedge_tag++;
+ if (!bm_edge_is_delimit(e, &delimit_data)) {
+ BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ totedge_tag++;
+ }
}
}
@@ -236,36 +344,19 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
i = 0;
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- BMVert *v1, *v2, *v3, *v4;
- BMFace *f_a, *f_b;
- float measure;
+ const BMVert *verts[4];
+ float error;
if (!BMO_elem_flag_test(bm, e, EDGE_MARK))
continue;
- f_a = e->l->f;
- f_b = e->l->radial_next->f;
-
- if (do_sharp && !BM_elem_flag_test(e, BM_ELEM_SMOOTH))
- continue;
-
- if (do_mat && f_a->mat_nr != f_b->mat_nr)
- continue;
-
- if ((do_uv || do_tf || do_vcol) && (bm_edge_faces_cmp(bm, e, do_uv, do_tf, do_vcol) == false))
- continue;
+ bm_edge_to_quad_verts(e, verts);
- v1 = e->l->v;
- v2 = e->l->prev->v;
- v3 = e->l->next->v;
- v4 = e->l->radial_next->prev->v;
+ error = quad_calc_error(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co);
- measure = measure_facepair(v1->co, v2->co, v3->co, v4->co, limit);
- if (measure < limit) {
- jedges[i].data = e;
- jedges[i].sort_value = measure;
- i++;
- }
+ jedges[i].data = e;
+ jedges[i].sort_value = error;
+ i++;
}
totedge = i;
@@ -279,7 +370,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
f_b = e->l->radial_next->f;
/* check if another edge already claimed this face */
- if ((BMO_elem_flag_test(bm, f_a, FACE_MARK) == false) ||
+ if ((BMO_elem_flag_test(bm, f_a, FACE_MARK) == false) &&
(BMO_elem_flag_test(bm, f_b, FACE_MARK) == false))
{
BMO_elem_flag_enable(bm, f_a, FACE_MARK);
@@ -307,39 +398,5 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
}
}
- /* join 2-tri islands */
- BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
- if (BMO_elem_flag_test(bm, e, EDGE_MARK)) {
- BMLoop *l_a, *l_b;
- BMFace *f_a, *f_b;
-
- /* ok, this edge wasn't merged, check if it's
- * in a 2-tri-pair island, and if so merge */
- l_a = e->l;
- l_b = e->l->radial_next;
-
- f_a = l_a->f;
- f_b = l_b->f;
-
- /* check the other 2 edges in both tris are untagged */
- if ((f_a->len == 3 && f_b->len == 3) &&
- (BMO_elem_flag_test(bm, l_a->next->e, EDGE_MARK) == false) &&
- (BMO_elem_flag_test(bm, l_a->prev->e, EDGE_MARK) == false) &&
- (BMO_elem_flag_test(bm, l_b->next->e, EDGE_MARK) == false) &&
- (BMO_elem_flag_test(bm, l_b->prev->e, EDGE_MARK) == false) &&
- /* check for faces that use same verts, this is supported but raises an error
- * and cancels the operation when performed from editmode, since this is only
- * two triangles we only need to compare a single vertex */
- (LIKELY(l_a->prev->v != l_b->prev->v)))
- {
- BMFace *f_new;
- f_new = BM_faces_join_pair(bm, f_a, f_b, e, true);
- if (f_new) {
- BMO_elem_flag_enable(bm, f_new, FACE_OUT);
- }
- }
- }
- }
-
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT);
}
diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c
index 0ef96553d67..f62e445ca18 100644
--- a/source/blender/bmesh/operators/bmo_normals.c
+++ b/source/blender/bmesh/operators/bmo_normals.c
@@ -71,7 +71,7 @@ static bool bmo_recalc_normal_edge_filter_cb(BMElem *ele, void *UNUSED(user_data
*
* To take these spikes into account, use the normals of the faces edges.
*/
- #define USE_FACE_EDGE_NORMAL_TEST
+#define USE_FACE_EDGE_NORMAL_TEST
/**
* The center of the entire island is't necessarily well placed,
diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c
index 871bee64c19..74bcbbaf463 100644
--- a/source/blender/bmesh/operators/bmo_removedoubles.c
+++ b/source/blender/bmesh/operators/bmo_removedoubles.c
@@ -380,8 +380,11 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op)
float min[3], max[3], center[3];
unsigned int i, tot;
BMOpSlot *slot_targetmap;
-
- BMO_op_callf(bm, op->flag, "collapse_uvs edges=%s", op, "edges");
+
+ if (BMO_slot_bool_get(op->slots_in, "uvs")) {
+ BMO_op_callf(bm, op->flag, "collapse_uvs edges=%s", op, "edges");
+ }
+
BMO_op_init(bm, &weldop, op->flag, "weld_verts");
slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap");
@@ -519,8 +522,9 @@ void bmo_collapse_uvs_exec(BMesh *bm, BMOperator *op)
}
-static void bmesh_find_doubles_common(BMesh *bm, BMOperator *op,
- BMOperator *optarget, BMOpSlot *optarget_slot)
+static void bmesh_find_doubles_common(
+ BMesh *bm, BMOperator *op,
+ BMOperator *optarget, BMOpSlot *optarget_slot)
{
BMVert **verts;
int verts_len;
diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c
index 003c27671a5..e3304298647 100644
--- a/source/blender/bmesh/operators/bmo_subdivide.c
+++ b/source/blender/bmesh/operators/bmo_subdivide.c
@@ -80,8 +80,9 @@ static void bmo_subd_init_shape_info(BMesh *bm, SubDParams *params)
}
-typedef void (*subd_pattern_fill_fp)(BMesh *bm, BMFace *face, BMVert **verts,
- const SubDParams *params);
+typedef void (*subd_pattern_fill_fp)(
+ BMesh *bm, BMFace *face, BMVert **verts,
+ const SubDParams *params);
/*
* note: this is a pattern-based edge subdivider.
@@ -163,10 +164,11 @@ static BMEdge *connect_smallest_face(BMesh *bm, BMVert *v_a, BMVert *v_b, BMFace
return NULL;
}
/* calculates offset for co, based on fractal, sphere or smooth settings */
-static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params, float perc,
- BMVert *vsta, BMVert *vend)
+static void alter_co(
+ BMVert *v, BMEdge *UNUSED(e_orig),
+ const SubDParams *params, const float perc,
+ const BMVert *v_a, const BMVert *v_b)
{
- float tvec[3], fac;
float *co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp);
int i;
@@ -178,28 +180,26 @@ static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params
}
else if (params->use_smooth) {
/* we calculate an offset vector vec1[], to be added to *co */
- float len, nor[3], nor1[3], nor2[3], val;
+ float dir[3], tvec[3];
+ float fac, len, val;
- sub_v3_v3v3(nor, vsta->co, vend->co);
- len = 0.5f * normalize_v3(nor);
-
- copy_v3_v3(nor1, vsta->no);
- copy_v3_v3(nor2, vend->no);
+ sub_v3_v3v3(dir, v_a->co, v_b->co);
+ len = M_SQRT1_2 * normalize_v3(dir);
/* cosine angle */
- fac = dot_v3v3(nor, nor1);
- mul_v3_v3fl(tvec, nor1, fac);
+ fac = dot_v3v3(dir, v_a->no);
+ mul_v3_v3fl(tvec, v_a->no, fac);
/* cosine angle */
- fac = -dot_v3v3(nor, nor2);
- madd_v3_v3fl(tvec, nor2, fac);
+ fac = -dot_v3v3(dir, v_b->no);
+ madd_v3_v3fl(tvec, v_b->no, fac);
/* falloff for multi subdivide */
val = fabsf(1.0f - 2.0f * fabsf(0.5f - perc));
val = bmesh_subd_falloff_calc(params->smooth_falloff, val);
if (params->use_smooth_even) {
- val *= BM_vert_calc_shell_factor(v);
+ val *= shell_v3v3_mid_normalized_to_dist(v_a->no, v_b->no);
}
mul_v3_fl(tvec, params->smooth * val * len);
@@ -208,12 +208,13 @@ static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params
}
if (params->use_fractal) {
- const float len = len_v3v3(vsta->co, vend->co);
- float normal[3], co2[3], base1[3], base2[3];
+ float normal[3], co2[3], base1[3], base2[3], tvec[3];
+ const float len = len_v3v3(v_a->co, v_b->co);
+ float fac;
fac = params->fractal * len;
- mid_v3_v3v3(normal, vsta->no, vend->no);
+ mid_v3_v3v3(normal, v_a->no, v_b->no);
ortho_basis_v3v3_v3(base1, base2, normal);
add_v3_v3v3(co2, v->co, params->fractal_ofs);
@@ -234,9 +235,12 @@ static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params
* this by getting the normals and coords for each shape key and
* re-calculate the smooth value for each but this is quite involved.
* for now its ok to simply apply the difference IMHO - campbell */
- sub_v3_v3v3(tvec, v->co, co);
if (params->shape_info.totlayer > 1) {
+ float tvec[3];
+
+ sub_v3_v3v3(tvec, v->co, co);
+
/* skip the last layer since its the temp */
i = params->shape_info.totlayer - 1;
co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset);
@@ -250,19 +254,21 @@ static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params
/* assumes in the edge is the correct interpolated vertices already */
/* percent defines the interpolation, rad and flag are for special options */
/* results in new vertex with correct coordinate, vertex normal and weight group info */
-static BMVert *bm_subdivide_edge_addvert(BMesh *bm, BMEdge *edge, BMEdge *oedge,
- const SubDParams *params, float percent,
- float percent2,
- BMEdge **out, BMVert *vsta, BMVert *vend)
+static BMVert *bm_subdivide_edge_addvert(
+ BMesh *bm, BMEdge *edge, BMEdge *e_orig,
+ const SubDParams *params,
+ const float factor_edge_split, const float factor_subd,
+ BMVert *v_a, BMVert *v_b,
+ BMEdge **r_edge)
{
- BMVert *ev;
+ BMVert *v_new;
- ev = BM_edge_split(bm, edge, edge->v1, out, percent);
+ v_new = BM_edge_split(bm, edge, edge->v1, r_edge, factor_edge_split);
- BMO_elem_flag_enable(bm, ev, ELE_INNER);
+ BMO_elem_flag_enable(bm, v_new, ELE_INNER);
/* offset for smooth or sphere or fractal */
- alter_co(ev, oedge, params, percent2, vsta, vend);
+ alter_co(v_new, e_orig, params, factor_subd, v_a, v_b);
#if 0 //BMESH_TODO
/* clip if needed by mirror modifier */
@@ -279,35 +285,40 @@ static BMVert *bm_subdivide_edge_addvert(BMesh *bm, BMEdge *edge, BMEdge *oedge,
}
#endif
- interp_v3_v3v3(ev->no, vsta->no, vend->no, percent2);
- normalize_v3(ev->no);
+ interp_v3_v3v3(v_new->no, v_a->no, v_b->no, factor_subd);
+ normalize_v3(v_new->no);
- return ev;
+ return v_new;
}
-static BMVert *subdivideedgenum(BMesh *bm, BMEdge *edge, BMEdge *oedge,
- int curpoint, int totpoint, const SubDParams *params,
- BMEdge **newe, BMVert *vsta, BMVert *vend)
+static BMVert *subdivide_edge_num(
+ BMesh *bm, BMEdge *edge, BMEdge *e_orig,
+ int curpoint, int totpoint, const SubDParams *params,
+ BMVert *v_a, BMVert *v_b,
+ BMEdge **r_edge)
{
- BMVert *ev;
- float percent, percent2 = 0.0f;
+ BMVert *v_new;
+ float factor_edge_split, factor_subd;
if (BMO_elem_flag_test(bm, edge, EDGE_PERCENT) && totpoint == 1) {
- percent = BMO_slot_map_float_get(params->slot_edge_percents, edge);
+ factor_edge_split = BMO_slot_map_float_get(params->slot_edge_percents, edge);
+ factor_subd = 0.0f;
}
else {
- percent = 1.0f / (float)(totpoint + 1 - curpoint);
- percent2 = (float)(curpoint + 1) / (float)(totpoint + 1);
-
+ factor_edge_split = 1.0f / (float)(totpoint + 1 - curpoint);
+ factor_subd = (float)(curpoint + 1) / (float)(totpoint + 1);
}
- ev = bm_subdivide_edge_addvert(bm, edge, oedge, params, percent,
- percent2, newe, vsta, vend);
- return ev;
+ v_new = bm_subdivide_edge_addvert(
+ bm, edge, e_orig, params,
+ factor_edge_split, factor_subd,
+ v_a, v_b, r_edge);
+ return v_new;
}
-static void bm_subdivide_multicut(BMesh *bm, BMEdge *edge, const SubDParams *params,
- BMVert *vsta, BMVert *vend)
+static void bm_subdivide_multicut(
+ BMesh *bm, BMEdge *edge, const SubDParams *params,
+ BMVert *v_a, BMVert *v_b)
{
BMEdge *eed = edge, *e_new, e_tmp = *edge;
BMVert *v, v1_tmp = *edge->v1, v2_tmp = *edge->v2, *v1 = edge->v1, *v2 = edge->v2;
@@ -317,7 +328,7 @@ static void bm_subdivide_multicut(BMesh *bm, BMEdge *edge, const SubDParams *par
e_tmp.v2 = &v2_tmp;
for (i = 0; i < numcuts; i++) {
- v = subdivideedgenum(bm, eed, &e_tmp, i, params->numcuts, params, &e_new, vsta, vend);
+ v = subdivide_edge_num(bm, eed, &e_tmp, i, params->numcuts, params, v_a, v_b, &e_new);
BMO_elem_flag_enable(bm, v, SUBD_SPLIT | ELE_SPLIT);
BMO_elem_flag_enable(bm, eed, SUBD_SPLIT | ELE_SPLIT);
@@ -434,7 +445,7 @@ static void quad_2edge_split_innervert(BMesh *bm, BMFace *UNUSED(face), BMVert *
e = connect_smallest_face(bm, verts[i], verts[numcuts + (numcuts - i)], &f_new);
e_tmp = *e;
- v = bm_subdivide_edge_addvert(bm, e, &e_tmp, params, 0.5f, 0.5f, &e_new, e->v1, e->v2);
+ v = bm_subdivide_edge_addvert(bm, e, &e_tmp, params, 0.5f, 0.5f, e->v1, e->v2, &e_new);
if (i != numcuts - 1) {
connect_smallest_face(bm, v_last, v, &f_new);
@@ -577,8 +588,7 @@ static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts
e_tmp = *e;
for (a = 0; a < numcuts; a++) {
- v = subdivideedgenum(bm, e, &e_tmp, a, numcuts, params, &e_new,
- v1, v2);
+ v = subdivide_edge_num(bm, e, &e_tmp, a, numcuts, params, v1, v2, &e_new);
BMESH_ASSERT(v != NULL);
@@ -685,8 +695,7 @@ static void tri_3edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts,
e_tmp.v1 = &v1_tmp;
e_tmp.v2 = &v2_tmp;
for (j = 0; j < i; j++) {
- v = subdivideedgenum(bm, e, &e_tmp, j, i, params, &e_new,
- verts[a], verts[b]);
+ v = subdivide_edge_num(bm, e, &e_tmp, j, i, params, verts[a], verts[b], &e_new);
lines[i + 1][j + 1] = v;
BMO_elem_flag_enable(bm, e_new, ELE_INNER);
@@ -1168,14 +1177,15 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
}
/* editmesh-emulating function */
-void BM_mesh_esubdivide(BMesh *bm, const char edge_hflag,
- const float smooth, const short smooth_falloff, const bool use_smooth_even,
- const float fractal, const float along_normal,
- const int numcuts,
- const int seltype, const int cornertype,
- const short use_single_edge, const short use_grid_fill,
- const short use_only_quads,
- const int seed)
+void BM_mesh_esubdivide(
+ BMesh *bm, const char edge_hflag,
+ const float smooth, const short smooth_falloff, const bool use_smooth_even,
+ const float fractal, const float along_normal,
+ const int numcuts,
+ const int seltype, const int cornertype,
+ const short use_single_edge, const short use_grid_fill,
+ const short use_only_quads,
+ const int seed)
{
BMOperator op;
diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
index c01ad10d716..0e619b4cece 100644
--- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c
+++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
@@ -80,8 +80,9 @@ static unsigned int bm_verts_tag_count(BMesh *bm)
}
#endif
-static float bezier_handle_calc_length_v3(const float co_a[3], const float no_a[3],
- const float co_b[3], const float no_b[3])
+static float bezier_handle_calc_length_v3(
+ const float co_a[3], const float no_a[3],
+ const float co_b[3], const float no_b[3])
{
const float dot = dot_v3v3(no_a, no_b);
/* gives closest approx at a circle with 2 parallel handles */
@@ -538,12 +539,13 @@ static void bm_edgering_pair_store_free(
/* -------------------------------------------------------------------- */
/* Interpolation Function */
-static void bm_edgering_pair_interpolate(BMesh *bm, LoopPairStore *lpair,
- struct BMEdgeLoopStore *el_store_a,
- struct BMEdgeLoopStore *el_store_b,
- ListBase *eloops_ring,
- const int interp_mode, const int cuts, const float smooth,
- const float *falloff_cache)
+static void bm_edgering_pair_interpolate(
+ BMesh *bm, LoopPairStore *lpair,
+ struct BMEdgeLoopStore *el_store_a,
+ struct BMEdgeLoopStore *el_store_b,
+ ListBase *eloops_ring,
+ const int interp_mode, const int cuts, const float smooth,
+ const float *falloff_cache)
{
const int resolu = cuts + 2;
const int dims = 3;
@@ -878,9 +880,10 @@ static bool bm_edgering_pair_order_is_flipped(BMesh *UNUSED(bm),
* Takes 2 edge loops that share edges,
* sort their verts and rotates the list so the lined up.
*/
-static void bm_edgering_pair_order(BMesh *bm,
- struct BMEdgeLoopStore *el_store_a,
- struct BMEdgeLoopStore *el_store_b)
+static void bm_edgering_pair_order(
+ BMesh *bm,
+ struct BMEdgeLoopStore *el_store_a,
+ struct BMEdgeLoopStore *el_store_b)
{
ListBase *lb_a = BM_edgeloop_verts_get(el_store_a);
ListBase *lb_b = BM_edgeloop_verts_get(el_store_b);
@@ -951,11 +954,12 @@ static void bm_edgering_pair_order(BMesh *bm,
*
* \note loops are _not_ aligned.
*/
-static void bm_edgering_pair_subdiv(BMesh *bm,
- struct BMEdgeLoopStore *el_store_a,
- struct BMEdgeLoopStore *el_store_b,
- ListBase *eloops_ring,
- const int cuts)
+static void bm_edgering_pair_subdiv(
+ BMesh *bm,
+ struct BMEdgeLoopStore *el_store_a,
+ struct BMEdgeLoopStore *el_store_b,
+ ListBase *eloops_ring,
+ const int cuts)
{
ListBase *lb_a = BM_edgeloop_verts_get(el_store_a);
// ListBase *lb_b = BM_edgeloop_verts_get(el_store_b);
@@ -1043,11 +1047,12 @@ static void bm_edgering_pair_subdiv(BMesh *bm,
bm_edgeloop_vert_tag(el_store_b, false);
}
-static void bm_edgering_pair_ringsubd(BMesh *bm, LoopPairStore *lpair,
- struct BMEdgeLoopStore *el_store_a,
- struct BMEdgeLoopStore *el_store_b,
- const int interp_mode, const int cuts, const float smooth,
- const float *falloff_cache)
+static void bm_edgering_pair_ringsubd(
+ BMesh *bm, LoopPairStore *lpair,
+ struct BMEdgeLoopStore *el_store_a,
+ struct BMEdgeLoopStore *el_store_b,
+ const int interp_mode, const int cuts, const float smooth,
+ const float *falloff_cache)
{
ListBase eloops_ring = {NULL};
bm_edgering_pair_order(bm, el_store_a, el_store_b);
diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c
index da1991a187d..964d0b1dfc6 100644
--- a/source/blender/bmesh/operators/bmo_utils.c
+++ b/source/blender/bmesh/operators/bmo_utils.c
@@ -208,7 +208,7 @@ static void bmo_region_extend_expand(
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, SEL_ORIG)) {
+ if (!BMO_elem_flag_test(bm, e, SEL_ORIG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
found = true;
break;
}
@@ -221,7 +221,7 @@ static void bmo_region_extend_expand(
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, e, SEL_FLAG)) {
+ if (!BMO_elem_flag_test(bm, e, SEL_FLAG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
BMO_elem_flag_enable(bm, e, SEL_FLAG);
BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
}
@@ -232,7 +232,7 @@ static void bmo_region_extend_expand(
BMFace *f;
BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, f, SEL_FLAG)) {
+ if (!BMO_elem_flag_test(bm, f, SEL_FLAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
bmo_face_flag_set_flush(bm, f, SEL_FLAG, true);
}
}
@@ -243,7 +243,7 @@ static void bmo_region_extend_expand(
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
if (BM_edge_is_wire(e)) {
- if (!BMO_elem_flag_test(bm, e, SEL_FLAG)) {
+ if (!BMO_elem_flag_test(bm, e, SEL_FLAG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
BMO_elem_flag_enable(bm, e, SEL_FLAG);
BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
}
@@ -267,7 +267,9 @@ static void bmo_region_extend_expand(
BMFace *f_other;
BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) {
- if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG)) {
+ if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) &&
+ !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN))
+ {
BMO_elem_flag_enable(bm, f_other, SEL_FLAG);
}
}
@@ -277,7 +279,9 @@ static void bmo_region_extend_expand(
BMFace *f_other;
BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG)) {
+ if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) &&
+ !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN))
+ {
BMO_elem_flag_enable(bm, f_other, SEL_FLAG);
}
}
diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c
index 990a2108bd7..19fe492c670 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.c
+++ b/source/blender/bmesh/tools/bmesh_beautify.c
@@ -274,11 +274,12 @@ BLI_INLINE bool edge_in_array(const BMEdge *e, const BMEdge **edge_array, const
}
/* recalc an edge in the heap (surrounding geometry has changed) */
-static void bm_edge_update_beauty_cost_single(BMEdge *e, Heap *eheap, HeapNode **eheap_table, GSet **edge_state_arr,
- /* only for testing the edge is in the array */
- const BMEdge **edge_array, const int edge_array_len,
+static void bm_edge_update_beauty_cost_single(
+ BMEdge *e, Heap *eheap, HeapNode **eheap_table, GSet **edge_state_arr,
+ /* only for testing the edge is in the array */
+ const BMEdge **edge_array, const int edge_array_len,
- const short flag, const short method)
+ const short flag, const short method)
{
if (edge_in_array(e, edge_array, edge_array_len)) {
const int i = BM_elem_index_get(e);
@@ -316,10 +317,11 @@ static void bm_edge_update_beauty_cost_single(BMEdge *e, Heap *eheap, HeapNode *
}
/* we have rotated an edge, tag other edges and clear this one */
-static void bm_edge_update_beauty_cost(BMEdge *e, Heap *eheap, HeapNode **eheap_table, GSet **edge_state_arr,
- const BMEdge **edge_array, const int edge_array_len,
- /* only for testing the edge is in the array */
- const short flag, const short method)
+static void bm_edge_update_beauty_cost(
+ BMEdge *e, Heap *eheap, HeapNode **eheap_table, GSet **edge_state_arr,
+ const BMEdge **edge_array, const int edge_array_len,
+ /* only for testing the edge is in the array */
+ const short flag, const short method)
{
int i;
@@ -333,7 +335,7 @@ static void bm_edge_update_beauty_cost(BMEdge *e, Heap *eheap, HeapNode **eheap_
BLI_assert(e->l->f->len == 3 &&
e->l->radial_next->f->len == 3);
- BLI_assert(BM_edge_face_count(e) == 2);
+ BLI_assert(BM_edge_face_count_is_equal(e, 2));
for (i = 0; i < 4; i++) {
bm_edge_update_beauty_cost_single(
@@ -389,11 +391,11 @@ void BM_mesh_beautify_fill(
i = BM_elem_index_get(e);
eheap_table[i] = NULL;
- BLI_assert(BM_edge_face_count(e) == 2);
+ BLI_assert(BM_edge_face_count_is_equal(e, 2));
e = BM_edge_rotate(bm, e, false, BM_EDGEROT_CHECK_EXISTS);
- BLI_assert(e == NULL || BM_edge_face_count(e) == 2);
+ BLI_assert(e == NULL || BM_edge_face_count_is_equal(e, 2));
if (LIKELY(e)) {
GSet *e_state_set = edge_state_arr[i];
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 2ef93618e2a..3348afa3bfa 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -57,6 +57,9 @@
/* happens far too often, uncomment for development */
// #define BEVEL_ASSERT_PROJECT
+/* will likely remove the code enabled by this soon, when sure that it is not needed */
+// #define PRE_275_ALGORITHM
+
/* for testing */
// #pragma GCC diagnostic error "-Wpadded"
@@ -187,7 +190,7 @@ typedef struct BevelParams {
bool limit_offset; /* should offsets be limited by collisions? */
const struct MDeformVert *dvert; /* vertex group array, maybe set if vertex_only */
int vertex_group; /* vertex group index, maybe set if vertex_only */
- int mat_nr; /* if >= 0, material number for bevel; else material comes from adjacent faces */
+ int mat_nr; /* if >= 0, material number for bevel; else material comes from adjacent faces */
} BevelParams;
// #pragma GCC diagnostic ignored "-Wpadded"
@@ -244,8 +247,9 @@ static void create_mesh_bmvert(BMesh *bm, VMesh *vm, int i, int j, int k, BMVert
BM_elem_flag_disable(nv->v, BM_ELEM_TAG);
}
-static void copy_mesh_vert(VMesh *vm, int ito, int jto, int kto,
- int ifrom, int jfrom, int kfrom)
+static void copy_mesh_vert(
+ VMesh *vm, int ito, int jto, int kto,
+ int ifrom, int jfrom, int kfrom)
{
NewVert *nvto, *nvfrom;
@@ -361,8 +365,9 @@ static BMFace *boundvert_rep_face(BoundVert *v)
*
* \note ALL face creation goes through this function, this is important to keep!
*/
-static BMFace *bev_create_ngon(BMesh *bm, BMVert **vert_arr, const int totv,
- BMFace **face_arr, BMFace *facerep, int mat_nr, bool do_interp)
+static BMFace *bev_create_ngon(
+ BMesh *bm, BMVert **vert_arr, const int totv,
+ BMFace **face_arr, BMFace *facerep, int mat_nr, bool do_interp)
{
BMIter iter;
BMLoop *l;
@@ -402,15 +407,17 @@ static BMFace *bev_create_ngon(BMesh *bm, BMVert **vert_arr, const int totv,
return f;
}
-static BMFace *bev_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
- BMFace *facerep, int mat_nr, bool do_interp)
+static BMFace *bev_create_quad_tri(
+ BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
+ BMFace *facerep, int mat_nr, bool do_interp)
{
BMVert *varr[4] = {v1, v2, v3, v4};
return bev_create_ngon(bm, varr, v4 ? 4 : 3, NULL, facerep, mat_nr, do_interp);
}
-static BMFace *bev_create_quad_tri_ex(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
- BMFace *f1, BMFace *f2, BMFace *f3, BMFace *f4, int mat_nr)
+static BMFace *bev_create_quad_tri_ex(
+ BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
+ BMFace *f1, BMFace *f2, BMFace *f3, BMFace *f4, int mat_nr)
{
BMVert *varr[4] = {v1, v2, v3, v4};
BMFace *farr[4] = {f1, f2, f3, f4};
@@ -419,8 +426,9 @@ static BMFace *bev_create_quad_tri_ex(BMesh *bm, BMVert *v1, BMVert *v2, BMVert
/* Is Loop layer layer_index contiguous across shared vertex of l1 and l2? */
-static bool contig_ldata_across_loops(BMesh *bm, BMLoop *l1, BMLoop *l2,
- int layer_index)
+static bool contig_ldata_across_loops(
+ BMesh *bm, BMLoop *l1, BMLoop *l2,
+ int layer_index)
{
const int offset = bm->ldata.layers[layer_index].offset;
const int type = bm->ldata.layers[layer_index].type;
@@ -478,7 +486,9 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f
return true;
}
-/* Like bev_create_quad_tri, but when verts straddle an old edge.
+/**
+ * Like bev_create_quad_tri, but when verts straddle an old edge.
+ * <pre>
* e
* |
* v1+---|---+v4
@@ -487,13 +497,16 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f
* v2+---|---+v3
* |
* f1 | f2
+ * </pre>
*
* Most CustomData for loops can be interpolated in their respective
* faces' loops, but for UVs and other 'has_math_cd' layers, only
* do this if the UVs are continuous across the edge e, otherwise pick
* one side (f1, arbitrarily), and interpolate them all on that side.
- * For face data, use f1 (arbitrarily) as face representative. */
-static BMFace *bev_create_quad_straddle(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
+ * For face data, use f1 (arbitrarily) as face representative.
+ */
+static BMFace *bev_create_quad_straddle(
+ BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
BMFace *f1, BMFace *f2, int mat_nr, bool is_seam)
{
BMFace *f, *facerep;
@@ -582,10 +595,42 @@ static bool is_outside_edge(EdgeHalf *e, const float co[3], BMVert **ret_closer_
}
}
+/* co should be approximately on the plane between e1 and e2, which share common vert v
+ * and common face f (which cannot be NULL).
+ * Is it between those edges, sweeping CCW? */
+static bool point_between_edges(float co[3], BMVert *v, BMFace *f, EdgeHalf *e1, EdgeHalf *e2)
+{
+ BMVert *v1, *v2;
+ float dir1[3], dir2[3], dirco[3], no[3];
+ float ang11, ang1co;
+
+ v1 = BM_edge_other_vert(e1->e, v);
+ v2 = BM_edge_other_vert(e2->e, v);
+ sub_v3_v3v3(dir1, v->co, v1->co);
+ sub_v3_v3v3(dir2, v->co, v2->co);
+ sub_v3_v3v3(dirco, v->co, co);
+ normalize_v3(dir1);
+ normalize_v3(dir2);
+ normalize_v3(dirco);
+ ang11 = angle_normalized_v3v3(dir1, dir2);
+ ang1co = angle_normalized_v3v3(dir1, dirco);
+ /* angles are in [0,pi]. need to compare cross product with normal to see if they are reflex */
+ cross_v3_v3v3(no, dir1, dir2);
+ if (dot_v3v3(no, f->no) < 0.0f)
+ ang11 = (float)(M_PI * 2.0) - ang11;
+ cross_v3_v3v3(no, dir1, dirco);
+ if (dot_v3v3(no, f->no) < 0.0f)
+ ang1co = (float)(M_PI * 2.0) - ang1co;
+ return (ang11 - ang1co > -BEVEL_EPSILON_BIG);
+}
+
/*
* Calculate the meeting point between the offset edges for e1 and e2, putting answer in meetco.
* e1 and e2 share vertex v and face f (may be NULL) and viewed from the normal side of
* the bevel vertex, e1 precedes e2 in CCW order.
+ * Except: if edges_between is true, there are edges between e1 and e2 in CCW order so they
+ * don't share a common face. We want the meeting point to be on an existing face so it
+ * should be dropped onto one of the intermediate faces, if possible.
* Offset edge is on right of both edges, where e1 enters v and e2 leave it.
* When offsets are equal, the new point is on the edge bisector, with length offset/sin(angle/2),
* but if the offsets are not equal (allowing for this, as bevel modifier has edge weights that may
@@ -594,16 +639,27 @@ static bool is_outside_edge(EdgeHalf *e, const float co[3], BMVert **ret_closer_
* record the change in offset_l (or offset_r); later we can tell that a change has happened because
* the offset will differ from its original value in offset_l_spec (or offset_r_spec).
*/
-static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float meetco[3])
+static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool edges_between, float meetco[3])
{
- float dir1[3], dir2[3], norm_v[3], norm_perp1[3], norm_perp2[3],
- off1a[3], off1b[3], off2a[3], off2b[3], isect2[3], ang, d;
+ float dir1[3], dir2[3], dir1n[3], dir2p[3], norm_v[3], norm_v1[3], norm_v2[3],
+ norm_perp1[3], norm_perp2[3], off1a[3], off1b[3], off2a[3], off2b[3],
+ isect2[3], dropco[3], plane[4], ang, d;
BMVert *closer_v;
+ EdgeHalf *e, *e1next, *e2prev;
+ BMFace *ff;
+ int isect_kind;
/* get direction vectors for two offset lines */
sub_v3_v3v3(dir1, v->co, BM_edge_other_vert(e1->e, v)->co);
sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, v)->co, v->co);
+ if (edges_between) {
+ e1next = e1->next;
+ e2prev = e2->prev;
+ sub_v3_v3v3(dir1n, BM_edge_other_vert(e1next->e, v)->co, v->co);
+ sub_v3_v3v3(dir2p, v->co, BM_edge_other_vert(e2prev->e, v)->co);
+ }
+
ang = angle_v3v3(dir1, dir2);
if (ang < BEVEL_EPSILON_BIG) {
/* special case: e1 and e2 are parallel; put offset point perp to both, from v.
@@ -643,14 +699,31 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float
* If e1-v-e2 is a reflex angle (viewed from vertex normal side), need to flip.
* Use f->no to figure out which side to look at angle from, as even if
* f is non-planar, will be more accurate than vertex normal */
- cross_v3_v3v3(norm_v, dir2, dir1);
- normalize_v3(norm_v);
- if (dot_v3v3(norm_v, f ? f->no : v->no) < 0.0f)
- negate_v3(norm_v);
+ if (!edges_between) {
+ cross_v3_v3v3(norm_v1, dir2, dir1);
+ normalize_v3(norm_v1);
+ if (dot_v3v3(norm_v1, f ? f->no : v->no) < 0.0f)
+ negate_v3(norm_v1);
+ copy_v3_v3(norm_v2, norm_v1);
+ }
+ else {
+ /* separate faces; get face norms at corners for each separately */
+ cross_v3_v3v3(norm_v1, dir1n, dir1);
+ normalize_v3(norm_v1);
+ f = e1->fnext;
+ if (dot_v3v3(norm_v1, f ? f->no : v->no) < 0.0f)
+ negate_v3(norm_v1);
+ cross_v3_v3v3(norm_v2, dir2, dir2p);
+ normalize_v3(norm_v2);
+ f = e2->fprev;
+ if (dot_v3v3(norm_v2, f ? f->no : v->no) < 0.0f)
+ negate_v3(norm_v2);
+ }
+
/* get vectors perp to each edge, perp to norm_v, and pointing into face */
- cross_v3_v3v3(norm_perp1, dir1, norm_v);
- cross_v3_v3v3(norm_perp2, dir2, norm_v);
+ cross_v3_v3v3(norm_perp1, dir1, norm_v1);
+ cross_v3_v3v3(norm_perp2, dir2, norm_v2);
normalize_v3(norm_perp1);
normalize_v3(norm_perp2);
@@ -662,11 +735,10 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float
madd_v3_v3fl(off2a, norm_perp2, e2->offset_l);
add_v3_v3v3(off2b, off2a, dir2);
- /* intersect the lines; by construction they should be on the same plane and not parallel */
- if (!isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2)) {
-#ifdef BEVEL_ASSERT_PROJECT
- BLI_assert(!"offset_meet failure");
-#endif
+ /* intersect the lines */
+ isect_kind = isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2);
+ if (isect_kind == 0) {
+ /* lines are colinear: we already tested for this, but this used a different epsilon */
copy_v3_v3(meetco, off1a); /* just to do something */
d = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e2->e, v)->co);
if (fabsf(d - e2->offset_l) > BEVEL_EPSILON)
@@ -686,15 +758,38 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float
copy_v3_v3(meetco, closer_v->co);
e1->offset_r = len_v3v3(meetco, v->co);
}
+ if (edges_between && e1->offset_r > 0.0 && e2->offset_l > 0.0) {
+ /* Try to drop meetco to a face between e1 and e2 */
+ if (isect_kind == 2) {
+ /* lines didn't meet in 3d: get average of meetco and isect2 */
+ mid_v3_v3v3(meetco, meetco, isect2);
+ }
+ for (e = e1; e != e2; e = e->next) {
+ ff = e->fnext;
+ if (!ff)
+ continue;
+ plane_from_point_normal_v3(plane, v->co, ff->no);
+ closest_to_plane_v3(dropco, plane, meetco);
+ if (point_between_edges(dropco, v, ff, e, e->next)) {
+ copy_v3_v3(meetco, dropco);
+ break;
+ }
+ }
+ e1->offset_r = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e1->e, v)->co);
+ e2->offset_l = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e2->e, v)->co);
+ }
}
}
}
+/* chosen so that 1/sin(BEVEL_GOOD_ANGLE) is about 4, giving that expansion factor to bevel width */
+#define BEVEL_GOOD_ANGLE 0.25f
+
/* Calculate the meeting point between e1 and e2 (one of which should have zero offsets),
* where e1 precedes e2 in CCW order around their common vertex v (viewed from normal side).
* If r_angle is provided, return the angle between e and emeet in *r_angle.
* If the angle is 0, or it is 180 degrees or larger, there will be no meeting point;
- * return false in that case, else true */
+ * return false in that case, else true. */
static bool offset_meet_edge(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, float meetco[3], float *r_angle)
{
float dir1[3], dir2[3], fno[3], ang, sinang;
@@ -706,7 +801,7 @@ static bool offset_meet_edge(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, float meetc
/* find angle from dir1 to dir2 as viewed from vertex normal side */
ang = angle_normalized_v3v3(dir1, dir2);
- if (ang < BEVEL_EPSILON) {
+ if (fabsf(ang) < BEVEL_GOOD_ANGLE) {
if (r_angle)
*r_angle = 0.0f;
return false;
@@ -717,10 +812,11 @@ static bool offset_meet_edge(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, float meetc
if (r_angle)
*r_angle = ang;
- if (ang - (float)M_PI > BEVEL_EPSILON)
+ if (fabsf(ang - (float)M_PI) < BEVEL_GOOD_ANGLE)
return false;
sinang = sinf(ang);
+
copy_v3_v3(meetco, v->co);
if (e1->offset_r == 0.0f)
madd_v3_v3fl(meetco, dir1, e2->offset_l / sinang);
@@ -729,6 +825,17 @@ static bool offset_meet_edge(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, float meetc
return true;
}
+/* Return true if it will look good to put the meeting point where offset_on_edge_between
+ * would put it. This means that neither side sees a reflex angle */
+static bool good_offset_on_edge_between(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid, BMVert *v)
+{
+ float ang;
+ float meet[3];
+
+ return offset_meet_edge(e1, emid, v, meet, &ang) &&
+ offset_meet_edge(emid, e2, v, meet, &ang);
+}
+
/* Calculate the best place for a meeting point for the offsets from edges e1 and e2
* on the in-between edge emid. Viewed from the vertex normal side, the CCW
* order of these edges is e1, emid, e2.
@@ -737,8 +844,9 @@ static bool offset_meet_edge(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, float meetc
* already, prefer to keep the offset the same on this end.
* Otherwise, pick a point between the two intersection points on emid that minimizes
* the sum of squares of errors from desired offset. */
-static void offset_on_edge_between(BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
- BMVert *v, float meetco[3])
+static void offset_on_edge_between(
+ BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
+ BMVert *v, float meetco[3])
{
float d, ang1, ang2, sina1, sina2, lambda;
float meet1[3], meet2[3];
@@ -787,14 +895,16 @@ static void offset_on_edge_between(BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2,
e2->offset_l = d;
}
+#ifdef PRE_275_ALGORITHM
/* Calculate the best place for a meeting point for the offsets from edges e1 and e2
* when there is an in-between edge emid, and we prefer to have a point that may not
* be on emid if that does a better job of keeping offsets at the user spec.
* Viewed from the vertex normal side, the CCW order of the edges is e1, emid, e2.
* The offset lines may not meet exactly: the lines may be angled so that they can't meet.
* In that case, pick the offset_on_edge_between. */
-static void offset_in_two_planes(BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
- BMVert *v, float meetco[3])
+static void offset_in_two_planes(
+ BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
+ BMVert *v, float meetco[3])
{
float dir1[3], dir2[3], dirmid[3], norm_perp1[3], norm_perp2[3],
off1a[3], off1b[3], off2a[3], off2b[3], isect2[3],
@@ -861,6 +971,7 @@ static void offset_in_two_planes(BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2, Ed
/* else iret == 1 and the lines are coplanar so meetco has the intersection */
}
}
+#endif
/* Offset by e->offset in plane with normal plane_no, on left if left==true,
* else on right. If no is NULL, choose an arbitrary plane different
@@ -909,11 +1020,11 @@ static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3],
/* If there is a bndv->ebev edge, find the mid control point if necessary.
* It is the closest point on the beveled edge to the line segment between
* bndv and bndv->next. */
-static void set_profile_params(BevelParams *bp, BoundVert *bndv)
+static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
{
EdgeHalf *e;
Profile *pro;
- float co1[3], co2[3], co3[3], d1[3], d2[3], d3[3], l;
+ float co1[3], co2[3], co3[3], d1[3], d2[3], l;
bool do_linear_interp;
copy_v3_v3(co1, bndv->nv.co);
@@ -947,18 +1058,37 @@ static void set_profile_params(BevelParams *bp, BoundVert *bndv)
cross_v3_v3v3(pro->plane_no, d1, d2);
l = normalize_v3(pro->plane_no);
if (l <= BEVEL_EPSILON_BIG) {
- /* co1 - midco -co2 are collinear - project plane that contains that line
- * and is perpendicular to the plane containing it and the beveled edge */
- cross_v3_v3v3(d3, d1, pro->proj_dir);
- normalize_v3(d3);
- cross_v3_v3v3(pro->plane_no, d1, d3);
- l = normalize_v3(pro->plane_no);
- if (l <= BEVEL_EPSILON_BIG) {
- /* whole profile is collinear with edge: just interpolate */
+ /* co1 - midco -co2 are collinear.
+ * Should be case that beveled edge is coplanar with two boundary verts.
+ * If the profile is going to lead into unbeveled edges on each side
+ * (that is, both BoundVerts are "on-edge" points on non-beveled edges)
+ * then in order to get curve in multi-segment case, change projection plane
+ * to be that common plane, projection dir to be the plane normal,
+ * and mid to be the original vertex.
+ * Otherwise, we just want to linearly interpolate between co1 and co2.
+ */
+ if (e->prev->is_bev || e->next->is_bev) {
do_linear_interp = true;
}
- /* signal to weld that this is linear */
- pro->super_r = PRO_LINE_R;
+ else {
+ copy_v3_v3(pro->coa, co1);
+ copy_v3_v3(pro->midco, bv->v->co);
+ copy_v3_v3(pro->cob, co2);
+ sub_v3_v3v3(d1, pro->midco, co1);
+ normalize_v3(d1);
+ sub_v3_v3v3(d2, pro->midco, co2);
+ normalize_v3(d2);
+ cross_v3_v3v3(pro->plane_no, d1, d2);
+ l = normalize_v3(pro->plane_no);
+ if (l <= BEVEL_EPSILON_BIG) {
+ /* whole profile is collinear with edge: just interpolate */
+ do_linear_interp = true;
+ }
+ else {
+ copy_v3_v3(pro->plane_co, bv->v->co);
+ copy_v3_v3(pro->proj_dir, pro->plane_no);
+ }
+ }
}
copy_v3_v3(pro->plane_co, co1);
}
@@ -1060,8 +1190,9 @@ static int bev_ccw_test(BMEdge *a, BMEdge *b, BMFace *f)
* and B has the right side as columns - both extended into homogeneous coords.
* So M = B*(Ainverse). Doing Ainverse by hand gives the code below.
*/
-static bool make_unit_square_map(const float va[3], const float vmid[3], const float vb[3],
- float r_mat[4][4])
+static bool make_unit_square_map(
+ const float va[3], const float vmid[3], const float vb[3],
+ float r_mat[4][4])
{
float vo[3], vd[3], vb_vmid[3], va_vmid[3], vddir[3];
@@ -1109,8 +1240,9 @@ static bool make_unit_square_map(const float va[3], const float vmid[3], const f
* and 1/2{va+vb+vc-vd}
* and Blender matrices have cols at m[i][*].
*/
-static void make_unit_cube_map(const float va[3], const float vb[3], const float vc[3],
- const float vd[3], float r_mat[4][4])
+static void make_unit_cube_map(
+ const float va[3], const float vb[3], const float vc[3],
+ const float vd[3], float r_mat[4][4])
{
copy_v3_v3(r_mat[0], va);
sub_v3_v3(r_mat[0], vb);
@@ -1391,6 +1523,325 @@ static void set_bound_vert_seams(BevVert *bv)
} while ((v = v->next) != bv->vmesh->boundstart);
}
+#ifndef PRE_275_ALGORITHM
+/* Is e between two planes where angle between is 180? */
+static bool eh_on_plane(EdgeHalf *e)
+{
+ float dot;
+
+ if (e->fprev && e->fnext) {
+ dot = dot_v3v3(e->fprev->no, e->fnext->no);
+ if (fabsf(dot) <= BEVEL_EPSILON ||
+ fabsf(dot - 1.0f) <= BEVEL_EPSILON)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Calculate the profiles for all the BoundVerts of VMesh vm */
+static void calculate_vm_profiles(BevelParams *bp, BevVert *bv, VMesh *vm)
+{
+ BoundVert *v;
+
+ v = vm->boundstart;
+ do {
+ set_profile_params(bp, bv, v);
+ calculate_profile(bp, v);
+ } while ((v = v->next) != vm->boundstart);
+}
+
+/* Implements build_boundary for vertex-only case */
+static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool construct)
+{
+ VMesh *vm = bv->vmesh;
+ EdgeHalf *efirst, *e;
+ BoundVert *v;
+ float co[3];
+
+ BLI_assert(bp->vertex_only);
+
+ e = efirst = &bv->edges[0];
+ do {
+ slide_dist(e, bv->v, e->offset_l, co);
+ if (construct) {
+ v = add_new_bound_vert(bp->mem_arena, vm, co);
+ v->efirst = v->elast = e;
+ e->leftv = v;
+ }
+ else {
+ adjust_bound_vert(e->leftv, co);
+ }
+ } while ((e = e->next) != efirst);
+
+ calculate_vm_profiles(bp, bv, vm);
+
+ if (construct) {
+ set_bound_vert_seams(bv);
+ if (vm->count == 2)
+ vm->mesh_kind = M_NONE;
+ else if (bp->seg == 1)
+ vm->mesh_kind = M_POLY;
+ else
+ vm->mesh_kind = M_ADJ;
+ }
+}
+
+/* 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. */
+static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf *efirst, bool construct)
+{
+ MemArena *mem_arena = bp->mem_arena;
+ VMesh *vm = bv->vmesh;
+ BoundVert *v;
+ EdgeHalf *e;
+ const float *no;
+ float co[3], d;
+
+ e = efirst;
+ if (bv->edgecount == 2) {
+ /* only 2 edges in, so terminate the edge with an artificial vertex on the unbeveled edge */
+ no = e->fprev ? e->fprev->no : (e->fnext ? e->fnext->no : NULL);
+ offset_in_plane(e, no, true, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = v->elast = v->ebev = e;
+ e->leftv = v;
+ }
+ else {
+ adjust_bound_vert(e->leftv, co);
+ }
+ no = e->fnext ? e->fnext->no : (e->fprev ? e->fprev->no : NULL);
+ offset_in_plane(e, no, false, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = v->elast = e;
+ e->rightv = v;
+ }
+ else {
+ adjust_bound_vert(e->rightv, co);
+ }
+ /* make artifical extra point along unbeveled edge, and form triangle */
+ slide_dist(e->next, bv->v, e->offset_l, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = v->elast = e->next;
+ e->next->leftv = e->next->rightv = v;
+ /* could use M_POLY too, but tri-fan looks nicer)*/
+ vm->mesh_kind = M_TRI_FAN;
+ set_bound_vert_seams(bv);
+ }
+ else {
+ adjust_bound_vert(e->next->leftv, co);
+ }
+ }
+ else {
+ /* More than 2 edges in. Put on-edge verts on all the other edges
+ * and join with the beveled edge to make a poly or adj mesh,
+ * Because e->prev has offset 0, offset_meet will put co on that edge */
+ /* TODO: should do something else if angle between e and e->prev > 180 */
+ offset_meet(e->prev, e, bv->v, e->fprev, false, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = e->prev;
+ v->elast = v->ebev = e;
+ e->leftv = v;
+ e->prev->leftv = v;
+ }
+ else {
+ adjust_bound_vert(e->leftv, co);
+ }
+ e = e->next;
+ offset_meet(e->prev, e, bv->v, e->fprev, false, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = e->prev;
+ v->elast = e;
+ e->leftv = v;
+ e->prev->rightv = v;
+ }
+ else {
+ adjust_bound_vert(e->leftv, co);
+ }
+ d = len_v3v3(bv->v->co, co);
+ for (e = e->next; e->next != efirst; e = e->next) {
+ slide_dist(e, bv->v, d, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = v->elast = e;
+ e->leftv = v;
+ }
+ else {
+ adjust_bound_vert(e->leftv, co);
+ }
+ }
+ }
+ calculate_vm_profiles(bp, bv, vm);
+
+ if (bv->edgecount >= 3) {
+ /* special case: snap profile to plane of adjacent two edges */
+ v = vm->boundstart;
+ BLI_assert(v->ebev != NULL);
+ move_profile_plane(v, v->efirst, v->next->elast);
+ calculate_profile(bp, v);
+ }
+
+ if (construct) {
+ set_bound_vert_seams(bv);
+
+ if (vm->count == 2 && bv->edgecount == 3) {
+ vm->mesh_kind = M_NONE;
+ }
+ else if (vm->count == 3) {
+ vm->mesh_kind = M_TRI_FAN;
+ }
+ else {
+ vm->mesh_kind = M_POLY;
+ }
+ }
+}
+
+/* Make a circular list of BoundVerts for bv, each of which has the coordinates
+ * of a vertex on the boundary of the beveled vertex bv->v.
+ * This may adjust some EdgeHalf widths, and there might have to be
+ * a subsequent pass to make the widths as consistent as possible.
+ * The first time through, construct will be true and we are making the BoundVerts
+ * and setting up the BoundVert and EdgeHalf pointers appropriately.
+ * For a width consistency path, we just recalculate the coordinates of the
+ * BoundVerts. If the other ends have been (re)built already, then we
+ * copy the offsets from there to match, else we use the ideal (user-specified)
+ * widths.
+ * Also, if construct, decide on the mesh pattern that will be used inside the boundary.
+ * Doesn't make the actual BMVerts */
+static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
+{
+ MemArena *mem_arena = bp->mem_arena;
+ EdgeHalf *efirst, *e, *e2, *e3, *enip, *eip, *eother;
+ BoundVert *v;
+ BevVert *bvother;
+ VMesh *vm;
+ float co[3];
+ int nip, nnip;
+
+ /* Current bevel does nothing if only one edge into a vertex */
+ if (bv->edgecount <= 1)
+ return;
+
+ if (bp->vertex_only) {
+ build_boundary_vertex_only(bp, bv, construct);
+ return;
+ }
+
+ vm = bv->vmesh;
+
+ /* Find a beveled edge to be efirst. Then for each edge, try matching widths to other end. */
+ e = efirst = next_bev(bv, NULL);
+ BLI_assert(e->is_bev);
+ do {
+ eother = find_other_end_edge_half(bp, e, &bvother);
+ if (eother && bvother->visited && bp->offset_type != BEVEL_AMT_PERCENT) {
+ /* try to keep bevel even by matching other end offsets */
+ e->offset_l = eother->offset_r;
+ e->offset_r = eother->offset_l;
+ }
+ else {
+ /* reset to user spec */
+ e->offset_l = e->offset_l_spec;
+ e->offset_r = e->offset_r_spec;
+ }
+ } while ((e = e->next) != efirst);
+
+ if (bv->selcount == 1) {
+ /* special case: only one beveled edge in */
+ build_boundary_terminal_edge(bp, bv, efirst, construct);
+ return;
+ }
+
+ /* Here: there is more than one beveled edge.
+ * We make BoundVerts to connect the sides of the beveled edges.
+ * Non-beveled edges in between will just join to the appropriate juncture point. */
+ e = efirst;
+ do {
+ BLI_assert(e->is_bev);
+ /* Make the BoundVert for the right side of e; other side will be made
+ * when the beveled edge to the left of e is handled.
+ * Analyze edges until next beveled edge.
+ * They are either "in plane" (preceding and subsequent faces are coplanar)
+ * or not. The "non-in-plane" edges effect silhouette and we prefer to slide
+ * along one of those if possible. */
+ nip = nnip = 0; /* counts of in-plane / not-in-plane */
+ enip = eip = NULL; /* representatives of each */
+ for (e2 = e->next; !e2->is_bev; e2 = e2->next) {
+ if (eh_on_plane(e2)) {
+ nip++;
+ eip = e2;
+ }
+ else {
+ nnip++;
+ enip = e2;
+ }
+ }
+ if (nip == 0 && nnip == 0) {
+ offset_meet(e, e2, bv->v, e->fnext, false, co);
+ }
+ else if (nnip > 0) {
+ if (nnip == 1 && good_offset_on_edge_between(e, e2, enip, bv->v)) {
+ offset_on_edge_between(bp, e, e2, enip, bv->v, co);
+ }
+ else {
+ offset_meet(e, e2, bv->v, NULL, true, co);
+ }
+ }
+ else {
+ /* nip > 0 and nnip == 0 */
+ if (nip == 1 && good_offset_on_edge_between(e, e2, eip, bv->v)) {
+ offset_on_edge_between(bp, e, e2, eip, bv->v, co);
+ }
+ else {
+ offset_meet(e, e2, bv->v, NULL, true, co);
+ }
+ }
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = e;
+ v->elast = e2;
+ v->ebev = e2;
+ e->rightv = v;
+ e2->leftv = v;
+ for (e3 = e->next; e3 != e2; e3 = e3->next) {
+ e3->leftv = e3->rightv = v;
+ }
+ }
+ else {
+ adjust_bound_vert(e->rightv, co);
+ }
+ e = e2;
+ } while (e != efirst);
+
+ calculate_vm_profiles(bp, bv, vm);
+
+ if (construct) {
+ set_bound_vert_seams(bv);
+
+ if (vm->count == 2) {
+ vm->mesh_kind = M_NONE;
+ }
+ else if (efirst->seg == 1) {
+ vm->mesh_kind = M_POLY;
+ }
+ else {
+ vm->mesh_kind = M_ADJ;
+ }
+ }
+}
+#endif
+
+#ifdef PRE_275_ALGORITHM
+/* This code was used prior to just before the 2.75 Blender release.
+ * It treated multiple non-beveled edges between beveled ones differently */
+
/* Make a circular list of BoundVerts for bv, each of which has the coordinates
* of a vertex on the boundary of the beveled vertex bv->v.
* This may adjust some EdgeHalf widths, and there might have to be
@@ -1474,7 +1925,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
else {
adjust_bound_vert(e->next->leftv, co);
}
- set_profile_params(bp, vm->boundstart);
+ set_profile_params(bp, bv, vm->boundstart);
calculate_profile(bp, vm->boundstart);
return;
}
@@ -1485,7 +1936,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
/* handle only left side of beveled edge e here: next iteration should do right side */
if (e->prev->is_bev) {
BLI_assert(e->prev != e); /* see: wire edge special case */
- offset_meet(e->prev, e, bv->v, e->fprev, co);
+ offset_meet(e->prev, e, bv->v, e->fprev, false, co);
if (construct) {
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = e->prev;
@@ -1522,7 +1973,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
}
else {
/* neither e->prev nor e->prev->prev are beveled: make on-edge on e->prev */
- offset_meet(e->prev, e, bv->v, e->fprev, co);
+ offset_meet(e->prev, e, bv->v, e->fprev, false, co);
if (construct) {
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = e->prev;
@@ -1546,7 +1997,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
}
else if (e->prev->is_bev) {
/* on-edge meet between e->prev and e */
- offset_meet(e->prev, e, bv->v, e->fprev, co);
+ offset_meet(e->prev, e, bv->v, e->fprev, false, co);
if (construct) {
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = e->prev;
@@ -1580,7 +2031,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
v = vm->boundstart;
do {
- set_profile_params(bp, v);
+ set_profile_params(bp, bv, v);
calculate_profile(bp, v);
} while ((v = v->next) != vm->boundstart);
@@ -1623,6 +2074,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
}
}
}
+#endif
/* Do a global pass to try to make offsets as even as possible.
* Consider this graph:
@@ -1842,9 +2294,10 @@ static void vmesh_center(VMesh *vm, float r_cent[3])
}
}
-static void avg4(float co[3],
- const NewVert *v0, const NewVert *v1,
- const NewVert *v2, const NewVert *v3)
+static void avg4(
+ float co[3],
+ const NewVert *v0, const NewVert *v1,
+ const NewVert *v2, const NewVert *v3)
{
add_v3_v3v3(co, v0->co, v1->co);
add_v3_v3(co, v2->co);
@@ -2759,7 +3212,7 @@ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv)
copy_mesh_vert(vm, 1, 0, ns - k, 0, 0, k);
}
- if (BM_vert_face_count(bv->v) == 0) {
+ if (BM_vert_face_check(bv->v) == false) {
e_eg = bv->edges[0].e;
BLI_assert(e_eg != NULL);
for (k = 0; k < ns; k++) {
@@ -3736,10 +4189,11 @@ static float bevel_limit_offset(BMesh *bm, BevelParams *bp)
*
* \warning all tagged edges _must_ be manifold.
*/
-void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type,
- const float segments, const float profile,
- const bool vertex_only, const bool use_weights, const bool limit_offset,
- const struct MDeformVert *dvert, const int vertex_group, const int mat)
+void BM_mesh_bevel(
+ BMesh *bm, const float offset, const int offset_type,
+ const float segments, const float profile,
+ const bool vertex_only, const bool use_weights, const bool limit_offset,
+ const struct MDeformVert *dvert, const int vertex_group, const int mat)
{
BMIter iter;
BMVert *v, *v_next;
diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h
index 52d8faa5401..b4bb6c56b7d 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.h
+++ b/source/blender/bmesh/tools/bmesh_bevel.h
@@ -29,9 +29,10 @@
struct MDeformVert;
-void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type, const float segments,
- const float profile, const bool vertex_only, const bool use_weights,
- const bool limit_offset, const struct MDeformVert *dvert, const int vertex_group,
- const int mat);
+void BM_mesh_bevel(
+ BMesh *bm, const float offset, const int offset_type, const float segments,
+ const float profile, const bool vertex_only, const bool use_weights,
+ const bool limit_offset, const struct MDeformVert *dvert, const int vertex_group,
+ const int mat);
#endif /* __BMESH_BEVEL_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c
index e6e33c905da..fbcf573acd9 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.c
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c
@@ -106,7 +106,7 @@ static int bm_vert_sortval_cb(const void *v_a_v, const void *v_b_v)
if (val_a > val_b) return 1;
else if (val_a < val_b) return -1;
- return 0;
+ else return 0;
}
diff --git a/source/blender/bmesh/tools/bmesh_decimate.h b/source/blender/bmesh/tools/bmesh_decimate.h
index a1b26990587..6415da9a0c2 100644
--- a/source/blender/bmesh/tools/bmesh_decimate.h
+++ b/source/blender/bmesh/tools/bmesh_decimate.h
@@ -27,21 +27,22 @@
* \ingroup bmesh
*/
-void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights, const bool do_triangulate);
+void BM_mesh_decimate_collapse(
+ BMesh *bm, const float factor,
+ float *vweights, float vweight_factor,
+ const bool do_triangulate);
void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool tag_only);
void BM_mesh_decimate_unsubdivide(BMesh *bm, const int iterations);
-void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
- const BMO_Delimit delimit,
- BMVert **vinput_arr, const int vinput_len,
- BMEdge **einput_arr, const int einput_len,
- const short oflag_out);
-void BM_mesh_decimate_dissolve(BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
- const BMO_Delimit delimit);
-
-/* these weights are accumulated so too high values may reach 'inf' too quickly */
-#define BM_MESH_DECIM_WEIGHT_MAX 100000.0f
-#define BM_MESH_DECIM_WEIGHT_EPS (1.0f / BM_MESH_DECIM_WEIGHT_MAX)
+void BM_mesh_decimate_dissolve_ex(
+ BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
+ BMO_Delimit delimit,
+ BMVert **vinput_arr, const int vinput_len,
+ BMEdge **einput_arr, const int einput_len,
+ const short oflag_out);
+void BM_mesh_decimate_dissolve(
+ BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
+ const BMO_Delimit delimit);
#endif /* __BMESH_DECIMATE_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index 811a144fc39..c3533245d9b 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -47,6 +47,12 @@
#define USE_TRIANGULATE
#define USE_VERT_NORMAL_INTERP /* has the advantage that flipped faces don't mess up vertex normals */
+/* if the cost from #BLI_quadric_evaluate is 'noise', fallback to topology */
+#define USE_TOPOLOGY_FALLBACK
+#ifdef USE_TOPOLOGY_FALLBACK
+# define TOPOLOGY_FALLBACK_EPS FLT_EPSILON
+#endif
+
/* these checks are for rare cases that we can't avoid since they are valid meshes still */
#define USE_SAFETY_CHECKS
@@ -77,12 +83,15 @@ static void bm_decim_build_quadrics(BMesh *bm, Quadric *vquadrics)
BMLoop *l_first;
BMLoop *l_iter;
- const float *co = BM_FACE_FIRST_LOOP(f)->v->co;
- const float *no = f->no;
- const float offset = -dot_v3v3(no, co);
+ float center[3];
+ double plane_db[4];
Quadric q;
- BLI_quadric_from_v3_dist(&q, no, offset);
+ BM_face_calc_center_mean(f, center);
+ copy_v3db_v3fl(plane_db, f->no);
+ plane_db[3] = -dot_v3db_v3fl(plane_db, center);
+
+ BLI_quadric_from_plane(&q, plane_db);
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
@@ -94,14 +103,22 @@ static void bm_decim_build_quadrics(BMesh *bm, Quadric *vquadrics)
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (UNLIKELY(BM_edge_is_boundary(e))) {
float edge_vector[3];
- float edge_cross[3];
+ float edge_plane[3];
+ double edge_plane_db[4];
sub_v3_v3v3(edge_vector, e->v2->co, e->v1->co);
f = e->l->f;
- cross_v3_v3v3(edge_cross, edge_vector, f->no);
- if (normalize_v3(edge_cross) > FLT_EPSILON) {
+ cross_v3_v3v3(edge_plane, edge_vector, f->no);
+ copy_v3db_v3fl(edge_plane_db, edge_plane);
+
+ if (normalize_v3_d(edge_plane_db) > FLT_EPSILON) {
Quadric q;
- BLI_quadric_from_v3_dist(&q, edge_cross, -dot_v3v3(edge_cross, e->v1->co));
+ float center[3];
+
+ mid_v3_v3v3(center, e->v1->co, e->v2->co);
+
+ edge_plane_db[3] = -dot_v3db_v3fl(edge_plane_db, center);
+ BLI_quadric_from_plane(&q, edge_plane_db);
BLI_quadric_mul(&q, BOUNDARY_PRESERVE_WEIGHT);
BLI_quadric_add_qu_qu(&vquadrics[BM_elem_index_get(e->v1)], &q);
@@ -112,18 +129,19 @@ static void bm_decim_build_quadrics(BMesh *bm, Quadric *vquadrics)
}
-static void bm_decim_calc_target_co(BMEdge *e, float optimize_co[3],
- const Quadric *vquadrics)
+static void bm_decim_calc_target_co(
+ BMEdge *e, float optimize_co[3],
+ const Quadric *vquadrics)
{
/* compute an edge contraction target for edge 'e'
* this is computed by summing it's vertices quadrics and
* optimizing the result. */
Quadric q;
- BLI_quadric_add_qu_ququ(&q,
- &vquadrics[BM_elem_index_get(e->v1)],
- &vquadrics[BM_elem_index_get(e->v2)]);
-
+ BLI_quadric_add_qu_ququ(
+ &q,
+ &vquadrics[BM_elem_index_get(e->v1)],
+ &vquadrics[BM_elem_index_get(e->v2)]);
if (BLI_quadric_optimize(&q, optimize_co, OPTIMIZE_EPS)) {
return; /* all is good */
@@ -162,13 +180,15 @@ static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_
cross_v3_v3v3(cross_exist, vec_other, vec_exist);
cross_v3_v3v3(cross_optim, vec_other, vec_optim);
- /* normalize isn't really needed, but ensures the value at a unit we can compare against */
- normalize_v3(cross_exist);
- normalize_v3(cross_optim);
+ /* avoid normalize */
+ if (dot_v3v3(cross_exist, cross_optim) <=
+ (len_squared_v3(cross_exist) + len_squared_v3(cross_optim)) * 0.01f)
+ {
+ return true;
+ }
#else
normal_tri_v3(cross_exist, v->co, co_prev, co_next);
normal_tri_v3(cross_optim, optimize_co, co_prev, co_next);
-#endif
/* use a small value rather then zero so we don't flip a face in multiple steps
* (first making it zero area, then flipping again) */
@@ -176,6 +196,8 @@ static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_
//printf("no flip\n");
return true;
}
+#endif
+
}
}
}
@@ -183,9 +205,29 @@ static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_
return false;
}
-static void bm_decim_build_edge_cost_single(BMEdge *e,
- const Quadric *vquadrics, const float *vweights,
- Heap *eheap, HeapNode **eheap_table)
+#ifdef USE_TOPOLOGY_FALLBACK
+/**
+ * when the cost is so small that its not useful (flat surfaces),
+ * fallback to using a 'topology' cost.
+ *
+ * This avoids cases where a flat (or near flat) areas get very un-even geometry.
+ */
+static float bm_decim_build_edge_cost_single_squared__topology(BMEdge *e)
+{
+ return fabsf(dot_v3v3(e->v1->no, e->v2->no)) / min_ff(-len_squared_v3v3(e->v1->co, e->v2->co), -FLT_EPSILON);
+}
+static float bm_decim_build_edge_cost_single__topology(BMEdge *e)
+{
+ return fabsf(dot_v3v3(e->v1->no, e->v2->no)) / min_ff(-len_v3v3(e->v1->co, e->v2->co), -FLT_EPSILON);
+}
+
+#endif /* USE_TOPOLOGY_FALLBACK */
+
+static void bm_decim_build_edge_cost_single(
+ BMEdge *e,
+ const Quadric *vquadrics,
+ const float *vweights, const float vweight_factor,
+ Heap *eheap, HeapNode **eheap_table)
{
const Quadric *q1, *q2;
float optimize_co[3];
@@ -202,8 +244,7 @@ static void bm_decim_build_edge_cost_single(BMEdge *e,
}
else {
/* only collapse tri's */
- eheap_table[BM_elem_index_get(e)] = NULL;
- return;
+ goto clear;
}
}
else if (BM_edge_is_manifold(e)) {
@@ -212,23 +253,11 @@ static void bm_decim_build_edge_cost_single(BMEdge *e,
}
else {
/* only collapse tri's */
- eheap_table[BM_elem_index_get(e)] = NULL;
- return;
+ goto clear;
}
}
else {
- eheap_table[BM_elem_index_get(e)] = NULL;
- return;
- }
-
- if (vweights) {
- if ((vweights[BM_elem_index_get(e->v1)] >= BM_MESH_DECIM_WEIGHT_MAX) &&
- (vweights[BM_elem_index_get(e->v2)] >= BM_MESH_DECIM_WEIGHT_MAX))
- {
- /* skip collapsing this edge */
- eheap_table[BM_elem_index_get(e)] = NULL;
- return;
- }
+ goto clear;
}
/* end sanity check */
@@ -238,36 +267,71 @@ static void bm_decim_build_edge_cost_single(BMEdge *e,
q1 = &vquadrics[BM_elem_index_get(e->v1)];
q2 = &vquadrics[BM_elem_index_get(e->v2)];
- if (vweights == NULL) {
- cost = (BLI_quadric_evaluate(q1, optimize_co) +
- BLI_quadric_evaluate(q2, optimize_co));
- }
- else {
- /* add 1.0 so planar edges are still weighted against */
- cost = (((BLI_quadric_evaluate(q1, optimize_co) + 1.0f) * vweights[BM_elem_index_get(e->v1)]) +
- ((BLI_quadric_evaluate(q2, optimize_co) + 1.0f) * vweights[BM_elem_index_get(e->v2)]));
- }
- // print("COST %.12f\n");
+ cost = (BLI_quadric_evaluate(q1, optimize_co) +
+ BLI_quadric_evaluate(q2, optimize_co));
+
/* note, 'cost' shouldn't be negative but happens sometimes with small values.
* this can cause faces that make up a flat surface to over-collapse, see [#37121] */
cost = fabsf(cost);
+
+#ifdef USE_TOPOLOGY_FALLBACK
+ if (UNLIKELY(cost < TOPOLOGY_FALLBACK_EPS)) {
+ /* subtract existing cost to further differentiate edges from one another
+ *
+ * keep topology cost below 0.0 so their values don't interfere with quadric cost,
+ * (and they get handled first).
+ * */
+ if (vweights == NULL) {
+ cost = bm_decim_build_edge_cost_single_squared__topology(e) - cost;
+ }
+ else {
+ /* with weights we need to use the real length so we can scale them properly */
+ const float e_weight = (vweights[BM_elem_index_get(e->v1)] +
+ vweights[BM_elem_index_get(e->v2)]);
+ cost = bm_decim_build_edge_cost_single__topology(e) - cost;
+ /* note, this is rather arbitrary max weight is 2 here,
+ * allow for skipping edges 4x the length, based on weights */
+ if (e_weight) {
+ cost *= 1.0f + (e_weight * vweight_factor);
+ }
+
+ BLI_assert(cost <= 0.0f);
+ }
+ }
+ else
+#endif
+ if (vweights) {
+ const float e_weight = 2.0f - (vweights[BM_elem_index_get(e->v1)] +
+ vweights[BM_elem_index_get(e->v2)]);
+ if (e_weight) {
+ cost += (BM_edge_calc_length(e) * ((e_weight * vweight_factor)));
+ }
+ }
+
eheap_table[BM_elem_index_get(e)] = BLI_heap_insert(eheap, cost, e);
+ return;
+
+clear:
+ eheap_table[BM_elem_index_get(e)] = NULL;
}
/* use this for degenerate cases - add back to the heap with an invalid cost,
* this way it may be calculated again if surrounding geometry changes */
-static void bm_decim_invalid_edge_cost_single(BMEdge *e,
- Heap *eheap, HeapNode **eheap_table)
+static void bm_decim_invalid_edge_cost_single(
+ BMEdge *e,
+ Heap *eheap, HeapNode **eheap_table)
{
BLI_assert(eheap_table[BM_elem_index_get(e)] == NULL);
eheap_table[BM_elem_index_get(e)] = BLI_heap_insert(eheap, COST_INVALID, e);
}
-static void bm_decim_build_edge_cost(BMesh *bm,
- const Quadric *vquadrics, const float *vweights,
- Heap *eheap, HeapNode **eheap_table)
+static void bm_decim_build_edge_cost(
+ BMesh *bm,
+ const Quadric *vquadrics,
+ const float *vweights, const float vweight_factor,
+ Heap *eheap, HeapNode **eheap_table)
{
BMIter iter;
BMEdge *e;
@@ -275,7 +339,7 @@ static void bm_decim_build_edge_cost(BMesh *bm,
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
eheap_table[i] = NULL; /* keep sanity check happy */
- bm_decim_build_edge_cost_single(e, vquadrics, vweights, eheap, eheap_table);
+ bm_decim_build_edge_cost_single(e, vquadrics, vweights, vweight_factor, eheap, eheap_table);
}
}
@@ -440,10 +504,11 @@ static void bm_decim_triangulate_end(BMesh *bm)
#ifdef USE_CUSTOMDATA
/**
- * \param v is the target to merge into.
+ * \param l: defines the vert to collapse into.
*/
-static void bm_edge_collapse_loop_customdata(BMesh *bm, BMLoop *l, BMVert *v_clear, BMVert *v_other,
- const float customdata_fac)
+static void bm_edge_collapse_loop_customdata(
+ BMesh *bm, BMLoop *l, BMVert *v_clear, BMVert *v_other,
+ const float customdata_fac)
{
/* disable seam check - the seam check would have to be done per layer, its not really that important */
//#define USE_SEAM
@@ -452,8 +517,6 @@ static void bm_edge_collapse_loop_customdata(BMesh *bm, BMLoop *l, BMVert *v_cle
const bool is_manifold = BM_edge_is_manifold(l->e);
int side;
- /* l defines the vert to collapse into */
-
/* first find the loop of 'v_other' thats attached to the face of 'l' */
if (l->v == v_clear) {
l_clear = l;
@@ -695,18 +758,19 @@ static bool bm_edge_collapse_is_degenerate_topology(BMEdge *e_first)
*
* Important - dont add vert/edge/face data on collapsing!
*
- * \param e_clear_other let caller know what edges we remove besides \a e_clear
- * \param customdata_flag merge factor, scales from 0 - 1 ('v_clear' -> 'v_other')
+ * \param r_e_clear_other: Let caller know what edges we remove besides \a e_clear
+ * \param customdata_flag: Merge factor, scales from 0 - 1 ('v_clear' -> 'v_other')
*/
-static bool bm_edge_collapse(BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_e_clear_other[2],
+static bool bm_edge_collapse(
+ BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_e_clear_other[2],
#ifdef USE_CUSTOMDATA
- const CD_UseFlag customdata_flag,
- const float customdata_fac
+ const CD_UseFlag customdata_flag,
+ const float customdata_fac
#else
- const CD_UseFlag UNUSED(customdata_flag),
- const float UNUSED(customdata_fac)
+ const CD_UseFlag UNUSED(customdata_flag),
+ const float UNUSED(customdata_fac)
#endif
- )
+ )
{
BMVert *v_other;
@@ -782,12 +846,12 @@ static bool bm_edge_collapse(BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_
BM_edge_kill(bm, e_clear);
v_other->head.hflag |= v_clear->head.hflag;
- BM_vert_splice(bm, v_clear, v_other);
+ BM_vert_splice(bm, v_other, v_clear);
e_a_other[1]->head.hflag |= e_a_other[0]->head.hflag;
e_b_other[1]->head.hflag |= e_b_other[0]->head.hflag;
- BM_edge_splice(bm, e_a_other[0], e_a_other[1]);
- BM_edge_splice(bm, e_b_other[0], e_b_other[1]);
+ BM_edge_splice(bm, e_a_other[1], e_a_other[0]);
+ BM_edge_splice(bm, e_b_other[1], e_b_other[0]);
// BM_mesh_validate(bm);
@@ -831,10 +895,10 @@ static bool bm_edge_collapse(BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_
BM_edge_kill(bm, e_clear);
v_other->head.hflag |= v_clear->head.hflag;
- BM_vert_splice(bm, v_clear, v_other);
+ BM_vert_splice(bm, v_other, v_clear);
e_a_other[1]->head.hflag |= e_a_other[0]->head.hflag;
- BM_edge_splice(bm, e_a_other[0], e_a_other[1]);
+ BM_edge_splice(bm, e_a_other[1], e_a_other[0]);
// BM_mesh_validate(bm);
@@ -847,14 +911,17 @@ static bool bm_edge_collapse(BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_
/* collapse e the edge, removing e->v2 */
-static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e,
- Quadric *vquadrics, float *vweights,
- Heap *eheap, HeapNode **eheap_table,
- const CD_UseFlag customdata_flag)
+static void bm_decim_edge_collapse(
+ BMesh *bm, BMEdge *e,
+ Quadric *vquadrics,
+ float *vweights, const float vweight_factor,
+ Heap *eheap, HeapNode **eheap_table,
+ const CD_UseFlag customdata_flag)
{
int e_clear_other[2];
BMVert *v_other = e->v1;
- int v_clear_index = BM_elem_index_get(e->v2); /* the vert is removed so only store the index */
+ const int v_other_index = BM_elem_index_get(e->v1);
+ const int v_clear_index = BM_elem_index_get(e->v2); /* the vert is removed so only store the index */
float optimize_co[3];
float customdata_fac;
@@ -897,7 +964,9 @@ static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e,
int i;
if (vweights) {
- vweights[BM_elem_index_get(v_other)] += vweights[v_clear_index];
+ float v_other_weight = interpf(vweights[v_other_index], vweights[v_clear_index], customdata_fac);
+ CLAMP(v_other_weight, 0.0f, 1.0f);
+ vweights[v_other_index] = v_other_weight;
}
e = NULL; /* paranoid safety check */
@@ -914,7 +983,7 @@ static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e,
}
/* update vertex quadric, add kept vertex from killed vertex */
- BLI_quadric_add_qu_qu(&vquadrics[BM_elem_index_get(v_other)], &vquadrics[v_clear_index]);
+ BLI_quadric_add_qu_qu(&vquadrics[v_other_index], &vquadrics[v_clear_index]);
/* update connected normals */
@@ -935,7 +1004,7 @@ static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e,
e_iter = e_first = v_other->e;
do {
BLI_assert(BM_edge_find_double(e_iter) == NULL);
- bm_decim_build_edge_cost_single(e_iter, vquadrics, vweights, eheap, eheap_table);
+ bm_decim_build_edge_cost_single(e_iter, vquadrics, vweights, vweight_factor, eheap, eheap_table);
} while ((e_iter = bmesh_disk_edge_next(e_iter, v_other)) != e_first);
}
@@ -957,7 +1026,7 @@ static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e,
BLI_assert(BM_vert_in_edge(e_outer, l->v) == false);
- bm_decim_build_edge_cost_single(e_outer, vquadrics, vweights, eheap, eheap_table);
+ bm_decim_build_edge_cost_single(e_outer, vquadrics, vweights, vweight_factor, eheap, eheap_table);
}
}
}
@@ -981,7 +1050,11 @@ static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e,
* \param vweights Optional array of vertex aligned weights [0 - 1],
* a vertex group is the usual source for this.
*/
-void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights, const bool do_triangulate)
+void BM_mesh_decimate_collapse(
+ BMesh *bm,
+ const float factor,
+ float *vweights, float vweight_factor,
+ const bool do_triangulate)
{
Heap *eheap; /* edge heap */
HeapNode **eheap_table; /* edge index aligned table pointing to the eheap */
@@ -1009,7 +1082,7 @@ void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights, c
/* build initial edge collapse cost data */
bm_decim_build_quadrics(bm, vquadrics);
- bm_decim_build_edge_cost(bm, vquadrics, vweights, eheap, eheap_table);
+ bm_decim_build_edge_cost(bm, vquadrics, vweights, vweight_factor, eheap, eheap_table);
face_tot_target = bm->totface * factor;
bm->elem_index_dirty |= BM_ALL;
@@ -1031,13 +1104,11 @@ void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights, c
BMEdge *e = BLI_heap_popmin(eheap);
BLI_assert(BM_elem_index_get(e) < tot_edge_orig); /* handy to detect corruptions elsewhere */
- // printf("COST %.10f\n", value);
-
/* under normal conditions wont be accessed again,
* but NULL just incase so we don't use freed node */
eheap_table[BM_elem_index_get(e)] = NULL;
- bm_decim_edge_collapse(bm, e, vquadrics, vweights, eheap, eheap_table, customdata_flag);
+ bm_decim_edge_collapse(bm, e, vquadrics, vweights, vweight_factor, eheap, eheap_table, customdata_flag);
}
diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
index 096349e8e9c..a1460cec7d1 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
@@ -32,6 +32,8 @@
#include "BLI_math.h"
#include "BLI_heap.h"
+#include "BKE_customdata.h"
+
#include "bmesh.h"
#include "bmesh_decimate.h" /* own include */
@@ -59,7 +61,32 @@ static float bm_vert_edge_face_angle(BMVert *v)
#undef ANGLE_TO_UNIT
}
-static float bm_edge_calc_dissolve_error(const BMEdge *e, const BMO_Delimit delimit)
+struct DelimitData {
+ int cd_loop_type;
+ int cd_loop_size;
+ int cd_loop_offset;
+ int cd_loop_offset_end;
+};
+
+static bool bm_edge_is_contiguous_loop_cd_all(
+ const BMEdge *e, const struct DelimitData *delimit_data)
+{
+ int cd_loop_offset;
+ for (cd_loop_offset = delimit_data->cd_loop_offset;
+ cd_loop_offset < delimit_data->cd_loop_offset_end;
+ cd_loop_offset += delimit_data->cd_loop_size)
+ {
+ if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_loop_type, cd_loop_offset) == false) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static float bm_edge_calc_dissolve_error(
+ const BMEdge *e, const BMO_Delimit delimit,
+ const struct DelimitData *delimit_data)
{
const bool is_contig = BM_edge_is_contiguous(e);
float angle;
@@ -74,6 +101,12 @@ static float bm_edge_calc_dissolve_error(const BMEdge *e, const BMO_Delimit deli
goto fail;
}
+ if ((delimit & BMO_DELIM_SHARP) &&
+ (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0))
+ {
+ goto fail;
+ }
+
if ((delimit & BMO_DELIM_MATERIAL) &&
(e->l->f->mat_nr != e->l->radial_next->f->mat_nr))
{
@@ -86,6 +119,12 @@ static float bm_edge_calc_dissolve_error(const BMEdge *e, const BMO_Delimit deli
goto fail;
}
+ if ((delimit & BMO_DELIM_UV) &&
+ (bm_edge_is_contiguous_loop_cd_all(e, delimit_data) == 0))
+ {
+ goto fail;
+ }
+
angle = BM_edge_calc_face_angle(e);
if (is_contig == false) {
angle = (float)M_PI - angle;
@@ -98,17 +137,32 @@ fail:
}
-void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
- const BMO_Delimit delimit,
- BMVert **vinput_arr, const int vinput_len,
- BMEdge **einput_arr, const int einput_len,
- const short oflag_out)
+void BM_mesh_decimate_dissolve_ex(
+ BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
+ BMO_Delimit delimit,
+ BMVert **vinput_arr, const int vinput_len,
+ BMEdge **einput_arr, const int einput_len,
+ const short oflag_out)
{
+ struct DelimitData delimit_data = {0};
const int eheap_table_len = do_dissolve_boundaries ? einput_len : max_ii(einput_len, vinput_len);
void *_heap_table = MEM_mallocN(sizeof(HeapNode *) * eheap_table_len, __func__);
int i;
+ if (delimit & BMO_DELIM_UV) {
+ const int layer_len = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
+ if (layer_len == 0) {
+ delimit &= ~BMO_DELIM_UV;
+ }
+ else {
+ delimit_data.cd_loop_type = CD_MLOOPUV;
+ delimit_data.cd_loop_size = CustomData_sizeof(delimit_data.cd_loop_type);
+ delimit_data.cd_loop_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, 0);
+ delimit_data.cd_loop_offset_end = delimit_data.cd_loop_size * layer_len;
+ }
+ }
+
/* --- first edges --- */
if (1) {
BMEdge **earray;
@@ -133,7 +187,7 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const bool
/* build heap */
for (i = 0; i < einput_len; i++) {
BMEdge *e = einput_arr[i];
- const float cost = bm_edge_calc_dissolve_error(e, delimit);
+ const float cost = bm_edge_calc_dissolve_error(e, delimit, &delimit_data);
eheap_table[i] = BLI_heap_insert(eheap, cost, e);
BM_elem_index_set(e, i); /* set dirty */
}
@@ -169,7 +223,7 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const bool
do {
const int j = BM_elem_index_get(l_iter->e);
if (j != -1 && eheap_table[j]) {
- const float cost = bm_edge_calc_dissolve_error(l_iter->e, delimit);
+ const float cost = bm_edge_calc_dissolve_error(l_iter->e, delimit, &delimit_data);
BLI_heap_remove(eheap, eheap_table[j]);
eheap_table[j] = BLI_heap_insert(eheap, cost, l_iter->e);
}
@@ -189,7 +243,7 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const bool
/* prepare for cleanup */
BM_mesh_elem_index_ensure(bm, BM_VERT);
vert_reverse_lookup = MEM_mallocN(sizeof(int) * bm->totvert, __func__);
- fill_vn_i(vert_reverse_lookup, bm->totvert, -1);
+ copy_vn_i(vert_reverse_lookup, bm->totvert, -1);
for (i = 0; i < vinput_len; i++) {
BMVert *v = vinput_arr[i];
vert_reverse_lookup[BM_elem_index_get(v)] = i;
@@ -316,8 +370,9 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const bool
MEM_freeN(_heap_table);
}
-void BM_mesh_decimate_dissolve(BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
- const BMO_Delimit delimit)
+void BM_mesh_decimate_dissolve(
+ BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
+ const BMO_Delimit delimit)
{
int vinput_len;
int einput_len;
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.c b/source/blender/bmesh/tools/bmesh_edgenet.c
index 1328b81b746..2a1946df7ae 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.c
+++ b/source/blender/bmesh/tools/bmesh_edgenet.c
@@ -166,8 +166,8 @@ static BMFace *bm_edgenet_face_from_path(
{
BMFace *f;
LinkNode *v_lnk;
- unsigned int i;
- unsigned int i_prev;
+ int i;
+ bool ok;
BMVert **vert_arr = BLI_array_alloca(vert_arr, path_len);
BMEdge **edge_arr = BLI_array_alloca(edge_arr, path_len);
@@ -176,11 +176,9 @@ static BMFace *bm_edgenet_face_from_path(
vert_arr[i] = v_lnk->link;
}
- i_prev = path_len - 1;
- for (i = 0; i < path_len; i++) {
- edge_arr[i_prev] = BM_edge_exists(vert_arr[i], vert_arr[i_prev]);
- i_prev = i;
- }
+ ok = BM_edges_from_verts(edge_arr, vert_arr, i);
+ BLI_assert(ok);
+ UNUSED_VARS_NDEBUG(ok);
/* no need for this, we do overlap checks before allowing the path to be used */
#if 0
@@ -448,10 +446,10 @@ static LinkNode *bm_edgenet_path_calc_best(
*
* \param bm The mesh to operate on.
* \param use_edge_tag Only fill tagged edges.
- * \param face_oflag if nonzero, apply all new faces with this bmo flag.
*/
-void BM_mesh_edgenet(BMesh *bm,
- const bool use_edge_tag, const bool use_new_face_tag)
+void BM_mesh_edgenet(
+ BMesh *bm,
+ const bool use_edge_tag, const bool use_new_face_tag)
{
VertNetInfo *vnet_info = MEM_callocN(sizeof(*vnet_info) * (size_t)bm->totvert, __func__);
BLI_mempool *edge_queue_pool = BLI_mempool_create(sizeof(LinkNode), 0, 512, BLI_MEMPOOL_NOP);
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.h b/source/blender/bmesh/tools/bmesh_edgenet.h
index 327a7f5aa23..1ad5cadae7c 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.h
+++ b/source/blender/bmesh/tools/bmesh_edgenet.h
@@ -27,7 +27,8 @@
* \ingroup bmesh
*/
-void BM_mesh_edgenet(BMesh *bm,
- const bool use_edge_tag, const bool use_new_face_tag);
+void BM_mesh_edgenet(
+ BMesh *bm,
+ const bool use_edge_tag, const bool use_new_face_tag);
#endif /* __BMESH_EDGENET_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_edgesplit.c b/source/blender/bmesh/tools/bmesh_edgesplit.c
index 947b77675d8..a59a5c43c82 100644
--- a/source/blender/bmesh/tools/bmesh_edgesplit.c
+++ b/source/blender/bmesh/tools/bmesh_edgesplit.c
@@ -35,70 +35,15 @@
#include "bmesh_edgesplit.h" /* own include */
-
/**
- * Remove the BM_ELEM_TAG flag for edges we cant split
- *
- * un-tag edges not connected to other tagged edges,
- * unless they are on a boundary
+ * \param use_verts Use flagged verts instead of edges.
+ * \param tag_only Only split tagged edges.
+ * \param copy_select Copy selection history.
*/
-static void bm_edgesplit_validate_seams(BMesh *bm)
-{
- BMIter iter;
- BMEdge *e;
-
- unsigned char *vtouch;
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- vtouch = MEM_callocN(sizeof(char) * bm->totvert, __func__);
-
- /* tag all boundary verts so as not to untag an edge which is inbetween only 2 faces [] */
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
-
- /* unrelated to flag assignment in this function - since this is the
- * only place we loop over all edges, disable tag */
- BM_elem_flag_disable(e, BM_ELEM_INTERNAL_TAG);
-
- if (e->l == NULL) {
- BM_elem_flag_disable(e, BM_ELEM_TAG);
- }
- else if (BM_edge_is_boundary(e)) {
- unsigned char *vt;
- vt = &vtouch[BM_elem_index_get(e->v1)]; if (*vt < 2) (*vt)++;
- vt = &vtouch[BM_elem_index_get(e->v2)]; if (*vt < 2) (*vt)++;
-
- /* while the boundary verts need to be tagged,
- * the edge its self can't be split */
- BM_elem_flag_disable(e, BM_ELEM_TAG);
- }
- }
-
- /* single marked edges unconnected to any other marked edges
- * are illegal, go through and unmark them */
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- /* lame, but we don't want the count to exceed 255,
- * so just count to 2, its all we need */
- unsigned char *vt;
- vt = &vtouch[BM_elem_index_get(e->v1)]; if (*vt < 2) (*vt)++;
- vt = &vtouch[BM_elem_index_get(e->v2)]; if (*vt < 2) (*vt)++;
- }
- }
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- if (vtouch[BM_elem_index_get(e->v1)] == 1 &&
- vtouch[BM_elem_index_get(e->v2)] == 1)
- {
- BM_elem_flag_disable(e, BM_ELEM_TAG);
- }
- }
- }
-
- MEM_freeN(vtouch);
-}
-
-void BM_mesh_edgesplit(BMesh *bm, const bool use_verts, const bool tag_only, const bool copy_select)
+void BM_mesh_edgesplit(
+ BMesh *bm,
+ const bool use_verts,
+ const bool tag_only, const bool copy_select)
{
BMIter iter;
BMEdge *e;
@@ -142,43 +87,13 @@ void BM_mesh_edgesplit(BMesh *bm, const bool use_verts, const bool tag_only, con
}
}
- bm_edgesplit_validate_seams(bm);
-
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- /* this flag gets copied so we can be sure duplicate edges get it too (important) */
- BM_elem_flag_enable(e, BM_ELEM_INTERNAL_TAG);
-
- /* keep splitting until each loop has its own edge */
- while (!BM_edge_is_boundary(e)) {
- BMLoop *l_sep = e->l;
- bmesh_edge_separate(bm, e, l_sep, copy_select);
- BLI_assert(l_sep->e != e);
-
- if (use_ese) {
- BMEditSelection *ese = BLI_ghash_lookup(ese_gh, e);
- if (UNLIKELY(ese)) {
- BM_select_history_store_after_notest(bm, ese, l_sep->e);
- }
- }
- }
-
BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
}
}
- if (use_verts) {
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e->v1, BM_ELEM_TAG) == false) {
- BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
- }
- if (BM_elem_flag_test(e->v2, BM_ELEM_TAG) == false) {
- BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
- }
- }
- }
-
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
unsigned int i;
@@ -191,7 +106,7 @@ void BM_mesh_edgesplit(BMesh *bm, const bool use_verts, const bool tag_only, con
BMVert **vtar;
int vtar_len;
- bmesh_vert_separate(bm, v, &vtar, &vtar_len, copy_select);
+ BM_vert_separate_hflag(bm, v, BM_ELEM_TAG, copy_select, &vtar, &vtar_len);
/* first value is always in 'v' */
if (vtar_len > 1) {
@@ -208,13 +123,22 @@ void BM_mesh_edgesplit(BMesh *bm, const bool use_verts, const bool tag_only, con
MEM_freeN(vtar);
}
else {
- bmesh_vert_separate(bm, v, NULL, NULL, copy_select);
+ BM_vert_separate_hflag(bm, v, BM_ELEM_TAG, copy_select, NULL, NULL);
}
}
}
}
}
+#ifndef NDEBUG
+ /* ensure we don't have any double edges! */
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BLI_assert(BM_edge_find_double(e) == NULL);
+ }
+ }
+#endif
+
if (use_ese) {
BLI_ghash_free(ese_gh, NULL, NULL);
}
diff --git a/source/blender/bmesh/tools/bmesh_edgesplit.h b/source/blender/bmesh/tools/bmesh_edgesplit.h
index bd66f6a9e2f..26040077f43 100644
--- a/source/blender/bmesh/tools/bmesh_edgesplit.h
+++ b/source/blender/bmesh/tools/bmesh_edgesplit.h
@@ -27,6 +27,9 @@
* \ingroup bmesh
*/
-void BM_mesh_edgesplit(BMesh *bm, const bool use_verts, const bool tag_only, const bool copy_select);
+void BM_mesh_edgesplit(
+ BMesh *bm,
+ const bool use_verts,
+ const bool tag_only, const bool copy_select);
#endif /* __BMESH_EDGESPLIT_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index 064dbd7405b..fc12bce8563 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -804,7 +804,7 @@ bool BM_mesh_intersect(
s.edgetri_cache = BLI_ghash_new(BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, __func__);
s.edge_verts = BLI_ghash_ptr_new(__func__);
- s.face_edges = BLI_ghash_ptr_new(__func__);
+ s.face_edges = BLI_ghash_int_new(__func__);
s.wire_edges = BLI_gset_ptr_new(__func__);
s.vert_dissolve = NULL;
@@ -1006,7 +1006,7 @@ bool BM_mesh_intersect(
!BM_vert_splice_check_double(v_prev, vi) &&
!BM_vert_pair_share_face_check(v_prev, vi))
{
- BM_vert_splice(bm, v_prev, vi);
+ BM_vert_splice(bm, vi, v_prev);
}
else {
copy_v3_v3(v_prev->co, vi->co);
@@ -1040,8 +1040,8 @@ bool BM_mesh_intersect(
}
}
- splice_ls = MEM_mallocN((unsigned int)BLI_gset_size(s.wire_edges) * sizeof(*splice_ls), __func__);
- STACK_INIT(splice_ls, (unsigned int)BLI_gset_size(s.wire_edges));
+ splice_ls = MEM_mallocN(BLI_gset_size(s.wire_edges) * sizeof(*splice_ls), __func__);
+ STACK_INIT(splice_ls, BLI_gset_size(s.wire_edges));
for (node = s.vert_dissolve; node; node = node->next) {
BMEdge *e_pair[2];
@@ -1228,7 +1228,7 @@ bool BM_mesh_intersect(
if (!BM_edge_exists(UNPACK2(splice_ls[i])) &&
!BM_vert_splice_check_double(UNPACK2(splice_ls[i])))
{
- BM_vert_splice(bm, UNPACK2(splice_ls[i]));
+ BM_vert_splice(bm, splice_ls[i][1], splice_ls[i][0]);
}
}
}
@@ -1267,10 +1267,8 @@ bool BM_mesh_intersect(
face_edges_split(bm, f, e_ls_base);
}
}
-#else
- (void)totface_orig;
#endif /* USE_NET */
-
+ (void)totface_orig;
#ifdef USE_SEPARATE
if (use_separate) {
diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c
index 8ae3507a738..6633803414b 100644
--- a/source/blender/bmesh/tools/bmesh_path.c
+++ b/source/blender/bmesh/tools/bmesh_path.c
@@ -126,7 +126,7 @@ LinkNode *BM_mesh_calc_path_vert(
verts_prev = MEM_callocN(sizeof(*verts_prev) * totvert, __func__);
cost = MEM_mallocN(sizeof(*cost) * totvert, __func__);
- fill_vn_fl(cost, totvert, 1e20f);
+ copy_vn_fl(cost, totvert, 1e20f);
/*
* Arrays are now filled as follows:
@@ -252,7 +252,7 @@ LinkNode *BM_mesh_calc_path_edge(
edges_prev = MEM_callocN(sizeof(*edges_prev) * totedge, "SeamPathPrevious");
cost = MEM_mallocN(sizeof(*cost) * totedge, "SeamPathCost");
- fill_vn_fl(cost, totedge, 1e20f);
+ copy_vn_fl(cost, totedge, 1e20f);
/*
* Arrays are now filled as follows:
@@ -378,7 +378,7 @@ LinkNode *BM_mesh_calc_path_face(
faces_prev = MEM_callocN(sizeof(*faces_prev) * totface, __func__);
cost = MEM_mallocN(sizeof(*cost) * totface, __func__);
- fill_vn_fl(cost, totface, 1e20f);
+ copy_vn_fl(cost, totface, 1e20f);
/*
* Arrays are now filled as follows:
diff --git a/source/blender/bmesh/tools/bmesh_region_match.c b/source/blender/bmesh/tools/bmesh_region_match.c
index bb7000e5534..72c3bc90599 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.c
+++ b/source/blender/bmesh/tools/bmesh_region_match.c
@@ -190,14 +190,16 @@ static bool ghashutil_bmelem_indexcmp(const void *a, const void *b)
return (a != b);
}
-static GHash *ghash_bmelem_new_ex(const char *info,
- const unsigned int nentries_reserve)
+static GHash *ghash_bmelem_new_ex(
+ const char *info,
+ const unsigned int nentries_reserve)
{
return BLI_ghash_new_ex(ghashutil_bmelem_indexhash, ghashutil_bmelem_indexcmp, info, nentries_reserve);
}
-static GSet *gset_bmelem_new_ex(const char *info,
- const unsigned int nentries_reserve)
+static GSet *gset_bmelem_new_ex(
+ const char *info,
+ const unsigned int nentries_reserve)
{
return BLI_gset_new_ex(ghashutil_bmelem_indexhash, ghashutil_bmelem_indexcmp, info, nentries_reserve);
}
@@ -419,8 +421,8 @@ static void bm_uuidwalk_rehash(
UUID_Int *uuid_store;
unsigned int i;
- unsigned int rehash_store_len_new = (unsigned int)MAX2(BLI_ghash_size(uuidwalk->verts_uuid),
- BLI_ghash_size(uuidwalk->faces_uuid));
+ unsigned int rehash_store_len_new = MAX2(BLI_ghash_size(uuidwalk->verts_uuid),
+ BLI_ghash_size(uuidwalk->faces_uuid));
bm_uuidwalk_rehash_reserve(uuidwalk, rehash_store_len_new);
uuid_store = uuidwalk->cache.rehash_store;
@@ -534,12 +536,13 @@ static void bm_uuidwalk_pass_add(
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
/* fill verts_new */
+ void **val_p;
if (!BLI_ghash_haskey(uuidwalk->verts_uuid, l_iter->v) &&
- !BLI_ghash_haskey(verts_uuid_pass, l_iter->v) &&
+ !BLI_ghash_ensure_p(verts_uuid_pass, l_iter->v, &val_p) &&
(bm_vert_is_uuid_connect(uuidwalk, l_iter->v) == true))
{
const UUID_Int uuid = bm_uuidwalk_calc_vert_uuid(uuidwalk, l_iter->v);
- BLI_ghash_insert(verts_uuid_pass, l_iter->v, (void *)uuid);
+ *val_p = (void *)uuid;
}
/* fill faces_step_next */
@@ -614,15 +617,16 @@ static unsigned int bm_uuidwalk_init_from_edge(
/* turning an array into LinkNode's seems odd,
* but this is just for initialization,
* elsewhere using LinkNode's makes more sense */
- for (i = 0; i < f_arr_len; i++) {
+ for (i = 0; i < f_arr_len; ) {
LinkNode *faces_pass = NULL;
+ const unsigned int i_init = i;
const int f_len = f_arr[i]->len;
do {
BLI_linklist_prepend_pool(&faces_pass, f_arr[i++], uuidwalk->link_pool);
} while (i < f_arr_len && (f_len == f_arr[i]->len));
- bm_uuidwalk_pass_add(uuidwalk, faces_pass, i);
+ bm_uuidwalk_pass_add(uuidwalk, faces_pass, i - i_init);
BLI_linklist_free_pool(faces_pass, NULL, uuidwalk->link_pool);
fstep_num += 1;
}
@@ -667,13 +671,15 @@ static bool bm_uuidwalk_facestep_begin(
if (!BLI_ghash_haskey(uuidwalk->faces_uuid, f)) {
const UUID_Int uuid = bm_uuidwalk_calc_face_uuid(uuidwalk, f);
UUIDFaceStepItem *fstep_item;
+ void **val_p;
ok = true;
- fstep_item = BLI_ghash_lookup(uuidwalk->cache.faces_from_uuid, (void *)uuid);
- if (UNLIKELY(fstep_item == NULL)) {
- fstep_item = BLI_mempool_alloc(uuidwalk->step_pool_items);
- BLI_ghash_insert(uuidwalk->cache.faces_from_uuid, (void *)uuid, fstep_item);
+ if (BLI_ghash_ensure_p(uuidwalk->cache.faces_from_uuid, (void *)uuid, &val_p)) {
+ fstep_item = *val_p;
+ }
+ else {
+ fstep_item = *val_p = BLI_mempool_alloc(uuidwalk->step_pool_items);
/* add to start, so its handled on the next round of passes */
BLI_addhead(&fstep->items, fstep_item);
@@ -858,7 +864,7 @@ static BMFace **bm_mesh_region_match_pair(
break;
}
- found = ((unsigned int)BLI_ghash_size(w_dst->faces_uuid) == faces_src_region_len);
+ found = (BLI_ghash_size(w_dst->faces_uuid) == faces_src_region_len);
if (found) {
break;
}
@@ -871,7 +877,7 @@ static BMFace **bm_mesh_region_match_pair(
if (found) {
GHashIterator gh_iter;
- const unsigned int faces_result_len = (unsigned int)BLI_ghash_size(w_dst->faces_uuid);
+ const unsigned int faces_result_len = BLI_ghash_size(w_dst->faces_uuid);
unsigned int i;
faces_result = MEM_mallocN(sizeof(*faces_result) * (faces_result_len + 1), __func__);
@@ -1111,9 +1117,10 @@ static BMEdge *bm_face_region_pivot_edge_find(
if (bm_edge_is_region_boundary(e)) {
unsigned int j;
for (j = 0; j < 2; j++) {
- if (!BLI_ghash_haskey(gh, (&e->v1)[j])) {
+ void **val_p;
+ if (!BLI_ghash_ensure_p(gh, (&e->v1)[j], &val_p)) {
SUID_Int v_id = bm_face_region_vert_boundary_id((&e->v1)[j]);
- BLI_ghash_insert(gh, (&e->v1)[j], (void *)v_id);
+ *val_p = (void *)v_id;
BLI_LINKSTACK_PUSH(vert_queue_prev, (&e->v1)[j]);
vert_queue_used += 1;
}
@@ -1137,10 +1144,11 @@ static BMEdge *bm_face_region_pivot_edge_find(
if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
BMVert *v_other = BM_edge_other_vert(e, v);
if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
- if (!BLI_ghash_haskey(gh, v_other)) {
+ void **val_p;
+ if (!BLI_ghash_ensure_p(gh, v_other, &val_p)) {
/* add as negative, so we know not to read from them this pass */
const SUID_Int v_id_other = -bm_face_region_vert_pass_id(gh, v_other);
- BLI_ghash_insert(gh, v_other, (void *)v_id_other);
+ *val_p = (void *)v_id_other;
BLI_LINKSTACK_PUSH(vert_queue_next, v_other);
vert_queue_used += 1;
}
@@ -1451,7 +1459,7 @@ int BM_mesh_region_match(
BMFace **faces_result;
unsigned int faces_result_len_out;
- if (BM_elem_flag_test(e_dst, BM_ELEM_TAG)) {
+ if (BM_elem_flag_test(e_dst, BM_ELEM_TAG) || BM_edge_is_wire(e_dst)) {
continue;
}
diff --git a/source/blender/bmesh/tools/bmesh_triangulate.c b/source/blender/bmesh/tools/bmesh_triangulate.c
index 404776a0769..6f2aaf28179 100644
--- a/source/blender/bmesh/tools/bmesh_triangulate.c
+++ b/source/blender/bmesh/tools/bmesh_triangulate.c
@@ -34,7 +34,6 @@
#include "BLI_utildefines.h"
#include "BLI_alloca.h"
#include "BLI_memarena.h"
-#include "BLI_listbase.h"
#include "BLI_heap.h"
#include "BLI_edgehash.h"
diff --git a/source/blender/bmesh/tools/bmesh_triangulate.h b/source/blender/bmesh/tools/bmesh_triangulate.h
index 550109ffef9..c6a5e04dfb2 100644
--- a/source/blender/bmesh/tools/bmesh_triangulate.h
+++ b/source/blender/bmesh/tools/bmesh_triangulate.h
@@ -30,7 +30,8 @@
#ifndef __BMESH_TRIANGULATE_H__
#define __BMESH_TRIANGULATE_H__
-void BM_mesh_triangulate(BMesh *bm, const int quad_method, const int ngon_method, const bool tag_only,
- BMOperator *op, BMOpSlot *slot_facemap_out);
+void BM_mesh_triangulate(
+ BMesh *bm, const int quad_method, const int ngon_method, const bool tag_only,
+ BMOperator *op, BMOpSlot *slot_facemap_out);
#endif /* __BMESH_TRIANGULATE_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_wireframe.c b/source/blender/bmesh/tools/bmesh_wireframe.c
index 79fea3e5da1..e79ef52797b 100644
--- a/source/blender/bmesh/tools/bmesh_wireframe.c
+++ b/source/blender/bmesh/tools/bmesh_wireframe.c
@@ -55,8 +55,9 @@ static BMLoop *bm_edge_tag_faceloop(BMEdge *e)
return NULL;
}
-static void bm_vert_boundary_tangent(BMVert *v, float r_no[3], float r_no_face[3],
- BMVert **r_va_other, BMVert **r_vb_other)
+static void bm_vert_boundary_tangent(
+ BMVert *v, float r_no[3], float r_no_face[3],
+ BMVert **r_va_other, BMVert **r_vb_other)
{
BMIter iter;
BMEdge *e_iter;
@@ -159,7 +160,7 @@ static bool bm_loop_is_radial_boundary(BMLoop *l_first)
}
/**
- * \param def_nr -1 for no vertex groups.
+ * \param defgrp_index: Vertex group index, -1 for no vertex groups.
*
* \note All edge tags must be cleared.
* \note Behavior matches MOD_solidify.c
diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp
index de4e29a7d48..7bea0b70c95 100644
--- a/source/blender/collada/AnimationExporter.cpp
+++ b/source/blender/collada/AnimationExporter.cpp
@@ -185,7 +185,7 @@ void AnimationExporter::make_anim_frames_from_targets(Object *ob, std::vector<fl
for (con = (bConstraint *)conlist->first; con; con = con->next) {
ListBase targets = {NULL, NULL};
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (!validateConstraints(con)) continue;
@@ -1526,7 +1526,7 @@ void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, i
bool AnimationExporter::validateConstraints(bConstraint *con)
{
bool valid = true;
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
/* these we can skip completely (invalid constraints...) */
if (cti == NULL) valid = false;
if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) valid = false;
@@ -1545,7 +1545,7 @@ void AnimationExporter::calc_ob_mat_at_time(Object *ob, float ctime , float mat[
for (con = (bConstraint *)conlist->first; con; con = con->next) {
ListBase targets = {NULL, NULL};
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (cti && cti->get_constraint_targets) {
bConstraintTarget *ct;
diff --git a/source/blender/collada/AnimationExporter.h b/source/blender/collada/AnimationExporter.h
index 6f675ed6a39..4736361ad13 100644
--- a/source/blender/collada/AnimationExporter.h
+++ b/source/blender/collada/AnimationExporter.h
@@ -103,7 +103,7 @@ protected:
const ExportSettings *export_settings;
void dae_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma = NULL);
-
+
void export_object_constraint_animation(Object *ob);
void export_morph_animation(Object *ob);
@@ -154,7 +154,7 @@ protected:
std::string create_xyz_source(float *v, int tot, const std::string& anim_id);
std::string create_4x4_source(std::vector<float> &frames, Object * ob_arm, Bone *bone, const std::string& anim_id);
-
+
std::string create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents);
std::string fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name);
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index c2ee6170470..bccaf4eddf6 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -588,9 +588,11 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin)
/* and step back to edit mode to fix the leaf nodes */
ED_armature_to_edit(armature);
- connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
- fix_leaf_bones(armature, (Bone *)armature->bonebase.first);
-
+ if (armature->bonebase.first) {
+ /* Do this only if Armature has bones */
+ connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
+ fix_leaf_bones(armature, (Bone *)armature->bonebase.first);
+ }
// exit armature edit mode
ED_armature_from_edit(armature);
ED_armature_edit_free(armature);
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 462b7b6f200..0aff5147060 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -771,9 +771,9 @@ MTex *DocumentImporter::create_texture(COLLADAFW::EffectCommon *ef, COLLADAFW::T
return NULL;
}
- ma->mtex[i] = add_mtex();
+ ma->mtex[i] = BKE_texture_mtex_add();
ma->mtex[i]->texco = TEXCO_UV;
- ma->mtex[i]->tex = add_texture(G.main, "Texture");
+ ma->mtex[i]->tex = BKE_texture_add(G.main, "Texture");
ma->mtex[i]->tex->type = TEX_IMAGE;
ma->mtex[i]->tex->ima = uid_image_map[ima_uid];
diff --git a/source/blender/collada/DocumentImporter.h b/source/blender/collada/DocumentImporter.h
index 5a7df9a41cf..62f76dbc022 100644
--- a/source/blender/collada/DocumentImporter.h
+++ b/source/blender/collada/DocumentImporter.h
@@ -51,7 +51,6 @@
-struct Main;
struct bContext;
/** Importer class. */
diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp
index 28cee05ec4b..7c7c57f3305 100644
--- a/source/blender/collada/GeometryExporter.cpp
+++ b/source/blender/collada/GeometryExporter.cpp
@@ -532,8 +532,8 @@ void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
// each <source> will get id like meshName + "map-channel-1"
int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV);
for (int a = 0; a < num_layers; a++) {
-
- if (!this->export_settings->active_uv_only || a == active_uv_index) {
+ int layer_index = CustomData_get_layer_index_n(&me->ldata, CD_MLOOPUV, a);
+ if (!this->export_settings->active_uv_only || layer_index == active_uv_index) {
MLoopUV *mloops = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, a);
COLLADASW::FloatSourceF source(mSW);
@@ -563,6 +563,11 @@ void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
}
}
+bool operator<(const Normal &a, const Normal &b)
+{
+ /* only needed to sort normal vectors and find() them later in a map.*/
+ return a.x < b.x || (a.x == b.x && (a.y < b.y || (a.y == b.y && a.z < b.z)));
+}
//creates <source> for normals
void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor)
@@ -596,15 +601,25 @@ void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::v
void GeometryExporter::create_normals(std::vector<Normal> &normals, std::vector<BCPolygonNormalsIndices> &polygons_normals, Mesh *me)
{
- std::map<unsigned int, unsigned int> shared_normal_indices;
+ std::map<Normal, unsigned int> shared_normal_indices;
int last_normal_index = -1;
MVert *verts = me->mvert;
MLoop *mloops = me->mloop;
+ float(*lnors)[3] = NULL;
+ bool use_custom_normals = false;
+
+ BKE_mesh_calc_normals_split(me);
+ if (CustomData_has_layer(&me->ldata, CD_NORMAL)) {
+ lnors = (float(*)[3])CustomData_get_layer(&me->ldata, CD_NORMAL);
+ use_custom_normals = true;
+ }
+
for (int poly_index = 0; poly_index < me->totpoly; poly_index++) {
MPoly *mpoly = &me->mpoly[poly_index];
+ bool use_vertex_normals = use_custom_normals || mpoly->flag & ME_SMOOTH;
- if (!(mpoly->flag & ME_SMOOTH)) {
+ if (!use_vertex_normals) {
// For flat faces use face normal as vertex normal:
float vector[3];
@@ -615,25 +630,29 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals, std::vector<
last_normal_index++;
}
-
- MLoop *mloop = mloops + mpoly->loopstart;
BCPolygonNormalsIndices poly_indices;
for (int loop_index = 0; loop_index < mpoly->totloop; loop_index++) {
- unsigned int vertex_index = mloop[loop_index].v;
- if (mpoly->flag & ME_SMOOTH) {
- if (shared_normal_indices.find(vertex_index) != shared_normal_indices.end())
- poly_indices.add_index (shared_normal_indices[vertex_index]);
- else {
+ unsigned int loop_idx = mpoly->loopstart + loop_index;
+ if (use_vertex_normals) {
+ float normalized[3];
- float vector[3];
- normal_short_to_float_v3(vector, verts[vertex_index].no);
+ if (use_custom_normals) {
+ normalize_v3_v3(normalized, lnors[loop_idx]);
+ }
+ else {
+ normal_short_to_float_v3(normalized, verts[mloops[loop_index].v].no);
+ normalize_v3(normalized);
+ }
+ Normal n = { normalized[0], normalized[1], normalized[2] };
- Normal n = { vector[0], vector[1], vector[2] };
- normals.push_back(n);
+ if (shared_normal_indices.find(n) != shared_normal_indices.end()) {
+ poly_indices.add_index(shared_normal_indices[n]);
+ }
+ else {
last_normal_index++;
-
poly_indices.add_index(last_normal_index);
- shared_normal_indices[vertex_index] = last_normal_index;
+ shared_normal_indices[n] = last_normal_index;
+ normals.push_back(n);
}
}
else {
diff --git a/source/blender/collada/GeometryExporter.h b/source/blender/collada/GeometryExporter.h
index 4d54e79d796..69d1067e6f4 100644
--- a/source/blender/collada/GeometryExporter.h
+++ b/source/blender/collada/GeometryExporter.h
@@ -48,6 +48,20 @@
extern Object *bc_get_highest_selected_ancestor_or_self(Object *ob);
+class Normal
+{
+ public:
+ float x;
+ float y;
+ float z;
+
+ friend bool operator< (const Normal &, const Normal &);
+
+};
+
+bool operator< (const Normal &, const Normal &);
+
+
// TODO: optimize UV sets by making indexed list with duplicates removed
class GeometryExporter : COLLADASW::LibraryGeometries
{
@@ -56,10 +70,7 @@ class GeometryExporter : COLLADASW::LibraryGeometries
unsigned int v1, v2, v3, v4;
};
- struct Normal
- {
- float x, y, z;
- };
+ Normal n;
Scene *mScene;
diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp
index a5c1493208b..aac41e2e93c 100644
--- a/source/blender/collada/ImageExporter.cpp
+++ b/source/blender/collada/ImageExporter.cpp
@@ -74,7 +74,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
short image_source = image->source;
bool is_generated = image_source == IMA_SRC_GENERATED;
- bool is_packed = image->packedfile != NULL;
+ bool is_packed = BKE_image_has_packedfile(image);
char export_path[FILE_MAX];
char source_path[FILE_MAX];
diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp
index b50b8b0a302..ac8ac2b9867 100644
--- a/source/blender/collada/SceneExporter.cpp
+++ b/source/blender/collada/SceneExporter.cpp
@@ -150,7 +150,7 @@ void SceneExporter::writeNodes(Object *ob, Scene *sce)
if (!instance_controller_created) {
COLLADASW::InstanceGeometry instGeom(mSW);
instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob, this->export_settings->use_object_instantiation)));
-
+ instGeom.setName(translate_id(id_name(ob)));
InstanceWriter::add_material_bindings(instGeom.getBindMaterial(), ob, this->export_settings->active_uv_only);
instGeom.add();
@@ -210,7 +210,7 @@ void SceneExporter::writeNodes(Object *ob, Scene *sce)
//not ideal: add the target object name as another parameter.
//No real mapping in the .dae
//Need support for multiple target objects also.
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
if (cti && cti->get_constraint_targets) {
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index f15efa89ea6..d669487db28 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -131,7 +131,7 @@ Object *bc_add_object(Scene *scene, int type, const char *name)
{
Object *ob = BKE_object_add_only_object(G.main, type, name);
- ob->data = BKE_object_obdata_add_from_type(G.main, type);
+ ob->data = BKE_object_obdata_add_from_type(G.main, type, name);
ob->lay = scene->lay;
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
@@ -144,6 +144,7 @@ Mesh *bc_get_mesh_copy(Scene *scene, Object *ob, BC_export_mesh_type export_mesh
{
Mesh *tmpmesh;
CustomDataMask mask = CD_MASK_MESH;
+ Mesh *mesh = (Mesh *)ob->data;
DerivedMesh *dm = NULL;
if (apply_modifiers) {
switch (export_mesh_type) {
@@ -165,14 +166,12 @@ Mesh *bc_get_mesh_copy(Scene *scene, Object *ob, BC_export_mesh_type export_mesh
tmpmesh = BKE_mesh_add(G.main, "ColladaMesh"); // name is not important here
DM_to_mesh(dm, tmpmesh, ob, CD_MASK_MESH, true);
+ tmpmesh->flag = mesh->flag;
if (triangulate) {
bc_triangulate_mesh(tmpmesh);
}
-
- // XXX Not sure if we need that for ngon_export as well.
BKE_mesh_tessface_ensure(tmpmesh);
-
return tmpmesh;
}
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 048c974423f..c23aa4ec734 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -119,6 +119,8 @@ set(SRC
nodes/COM_TimeNode.h
nodes/COM_SwitchNode.cpp
nodes/COM_SwitchNode.h
+ nodes/COM_SwitchViewNode.cpp
+ nodes/COM_SwitchViewNode.h
nodes/COM_MovieClipNode.cpp
nodes/COM_MovieClipNode.h
nodes/COM_OutputFileNode.cpp
@@ -370,6 +372,8 @@ set(SRC
operations/COM_CompositorOperation.cpp
operations/COM_OutputFileOperation.h
operations/COM_OutputFileOperation.cpp
+ operations/COM_OutputFileMultiViewOperation.h
+ operations/COM_OutputFileMultiViewOperation.cpp
operations/COM_ViewerOperation.h
operations/COM_ViewerOperation.cpp
operations/COM_PreviewOperation.h
diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h
index 9b22444cf7f..a5d7704a708 100644
--- a/source/blender/compositor/COM_compositor.h
+++ b/source/blender/compositor/COM_compositor.h
@@ -38,7 +38,7 @@ extern "C" {
* @defgroup Node All nodes of the compositor
* @defgroup Operation All operations of the compositor
*
- * @mainpage Introduction of the Blender Compositor
+ * @page Introduction of the Blender Compositor
*
* @section bcomp Blender compositor
* This project redesigns the internals of Blender's compositor. The project has been executed in 2011 by At Mind.
@@ -316,7 +316,8 @@ extern "C" {
* generation in display space
*/
void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rendering,
- const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings);
+ const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
+ const char *viewName);
/**
* @brief Deinitialize the compositor caches and allocated memory.
diff --git a/source/blender/compositor/intern/COM_CompositorContext.h b/source/blender/compositor/intern/COM_CompositorContext.h
index 3fbafa0a029..d7ec653f480 100644
--- a/source/blender/compositor/intern/COM_CompositorContext.h
+++ b/source/blender/compositor/intern/COM_CompositorContext.h
@@ -87,6 +87,11 @@ private:
const ColorManagedViewSettings *m_viewSettings;
const ColorManagedDisplaySettings *m_displaySettings;
+ /**
+ * @brief active rendering view name
+ */
+ const char *m_viewName;
+
public:
/**
* @brief constructor initializes the context with default values.
@@ -180,7 +185,17 @@ public:
* @brief set has this system active openclDevices?
*/
void setHasActiveOpenCLDevices(bool hasAvtiveOpenCLDevices) { this->m_hasActiveOpenCLDevices = hasAvtiveOpenCLDevices; }
-
+
+ /**
+ * @brief get the active rendering view
+ */
+ const char *getViewName() const { return this->m_viewName; }
+
+ /**
+ * @brief set the active rendering view
+ */
+ void setViewName(const char *viewName) { this->m_viewName = viewName; }
+
int getChunksize() const { return this->getbNodeTree()->chunksize; }
void setFastCalculation(bool fastCalculation) {this->m_fastCalculation = fastCalculation;}
diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp
index 99f66bcb5b4..9fa59be4a1c 100644
--- a/source/blender/compositor/intern/COM_Converter.cpp
+++ b/source/blender/compositor/intern/COM_Converter.cpp
@@ -101,6 +101,7 @@ extern "C" {
#include "COM_Stabilize2dNode.h"
#include "COM_SunBeamsNode.h"
#include "COM_SwitchNode.h"
+#include "COM_SwitchViewNode.h"
#include "COM_TextureNode.h"
#include "COM_TimeNode.h"
#include "COM_TonemapNode.h"
@@ -136,6 +137,10 @@ Node *Converter::convert(bNode *b_node)
{
Node *node = NULL;
+ /* ignore undefined nodes with missing or invalid node data */
+ if (!nodeIsRegistered(b_node))
+ return NULL;
+
switch (b_node->type) {
case CMP_NODE_COMPOSITE:
node = new CompositorNode(b_node);
@@ -328,6 +333,9 @@ Node *Converter::convert(bNode *b_node)
case CMP_NODE_SWITCH:
node = new SwitchNode(b_node);
break;
+ case CMP_NODE_SWITCH_VIEW:
+ node = new SwitchViewNode(b_node);
+ break;
case CMP_NODE_GLARE:
node = new GlareNode(b_node);
break;
diff --git a/source/blender/compositor/intern/COM_Debug.cpp b/source/blender/compositor/intern/COM_Debug.cpp
index ffaa4cc45a8..a7b464cde29 100644
--- a/source/blender/compositor/intern/COM_Debug.cpp
+++ b/source/blender/compositor/intern/COM_Debug.cpp
@@ -213,7 +213,7 @@ int DebugInfo::graphviz_legend_color(const char *name, const char *color, char *
return len;
}
-int DebugInfo::graphviz_legend_line(const char *name, const char *color, const char *style, char *str, int maxlen)
+int DebugInfo::graphviz_legend_line(const char * /*name*/, const char * /*color*/, const char * /*style*/, char *str, int maxlen)
{
/* XXX TODO */
int len = 0;
@@ -221,7 +221,7 @@ int DebugInfo::graphviz_legend_line(const char *name, const char *color, const c
return len;
}
-int DebugInfo::graphviz_legend_group(const char *name, const char *color, const char *style, char *str, int maxlen)
+int DebugInfo::graphviz_legend_group(const char *name, const char *color, const char * /*style*/, char *str, int maxlen)
{
int len = 0;
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "<TR><TD>%s</TD><TD CELLPADDING=\"4\"><TABLE BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\"><TR><TD BGCOLOR=\"%s\"></TD></TR></TABLE></TD></TR>\r\n", name, color);
@@ -356,7 +356,7 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
std::string color;
switch (from->getDataType()) {
case COM_DT_VALUE:
- color = "grey";
+ color = "gray";
break;
case COM_DT_VECTOR:
color = "blue";
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp
index 366c97b50c6..39ffa42e03c 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp
@@ -238,7 +238,7 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
chunkOrders[index].determineDistance(hotspots, 1);
}
- sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks - 1]);
+ std::sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks - 1]);
for (index = 0; index < this->m_numberOfChunks; index++) {
chunkOrder[index] = chunkOrders[index].getChunkNumber();
}
@@ -277,7 +277,7 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
chunkOrders[index].determineDistance(hotspots, 9);
}
- sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks]);
+ std::sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks]);
for (index = 0; index < this->m_numberOfChunks; index++) {
chunkOrder[index] = chunkOrders[index].getChunkNumber();
@@ -377,35 +377,6 @@ MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy *mem
return result;
}
-void ExecutionGroup::printBackgroundStats(void)
-{
- uintptr_t mem_in_use, mmap_in_use, peak_memory;
- float megs_used_memory, mmap_used_memory, megs_peak_memory;
- double execution_time;
- char timestr[64];
-
- execution_time = PIL_check_seconds_timer() - this->m_executionStartTime;
-
- mem_in_use = MEM_get_memory_in_use();
- mmap_in_use = MEM_get_mapped_memory_in_use();
- peak_memory = MEM_get_peak_memory();
-
- megs_used_memory = (mem_in_use - mmap_in_use) / (1024.0 * 1024.0);
- mmap_used_memory = (mmap_in_use) / (1024.0 * 1024.0);
- megs_peak_memory = (peak_memory) / (1024.0 * 1024.0);
-
- fprintf(stdout, "Mem:%.2fM (%.2fM, Peak %.2fM) ",
- megs_used_memory, mmap_used_memory, megs_peak_memory);
-
- BLI_timestr(execution_time, timestr, sizeof(timestr));
- printf("| Elapsed %s ", timestr);
- printf("| Tree %s, Tile %u-%u ", this->m_bTree->id.name + 2,
- this->m_chunksFinished, this->m_numberOfChunks);
-
- fputc('\n', stdout);
- fflush(stdout);
-}
-
void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers)
{
if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED)
@@ -430,8 +401,11 @@ void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memo
progress /= this->m_numberOfChunks;
this->m_bTree->progress(this->m_bTree->prh, progress);
- if (G.background)
- printBackgroundStats();
+ char buf[128];
+ BLI_snprintf(buf, sizeof(buf), "Compositing | Tile %u-%u",
+ this->m_chunksFinished,
+ this->m_numberOfChunks);
+ this->m_bTree->stats_draw(this->m_bTree->sdh, buf);
}
}
@@ -459,7 +433,8 @@ void ExecutionGroup::determineChunkRect(rcti *rect, const unsigned int chunkNumb
determineChunkRect(rect, xChunk, yChunk);
}
-MemoryBuffer *ExecutionGroup::allocateOutputBuffer(int chunkNumber, rcti *rect)
+MemoryBuffer *ExecutionGroup::allocateOutputBuffer(int /*chunkNumber*/,
+ rcti *rect)
{
// we asume that this method is only called from complex execution groups.
NodeOperation *operation = this->getOutputOperation();
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h
index 4b6f51c72c0..99365cdd4a8 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.h
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.h
@@ -347,11 +347,6 @@ public:
MemoryBuffer *allocateOutputBuffer(int chunkNumber, rcti *rect);
/**
- * @brief print execution statistics to stdout when running in a background mode
- */
- void printBackgroundStats(void);
-
- /**
* @brief after a chunk is executed the needed resources can be freed or unlocked.
* @param chunknumber
* @param memorybuffers
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cpp
index 0667271f4b1..caeaa07d9f9 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.cpp
@@ -43,8 +43,10 @@ extern "C" {
#endif
ExecutionSystem::ExecutionSystem(RenderData *rd, Scene *scene, bNodeTree *editingtree, bool rendering, bool fastcalculation,
- const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings)
+ const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
+ const char *viewName)
{
+ this->m_context.setViewName(viewName);
this->m_context.setScene(scene);
this->m_context.setbNodeTree(editingtree);
this->m_context.setPreviewHash(editingtree->previews);
@@ -76,6 +78,8 @@ ExecutionSystem::ExecutionSystem(RenderData *rd, Scene *scene, bNodeTree *editin
viewer_border->xmin < viewer_border->xmax &&
viewer_border->ymin < viewer_border->ymax;
+ editingtree->stats_draw(editingtree->sdh, "Compositing | Determining resolution");
+
for (index = 0; index < this->m_groups.size(); index++) {
resolution[0] = 0;
resolution[1] = 0;
@@ -124,6 +128,9 @@ void ExecutionSystem::set_operations(const Operations &operations, const Groups
void ExecutionSystem::execute()
{
+ const bNodeTree *editingtree = this->m_context.getbNodeTree();
+ editingtree->stats_draw(editingtree->sdh, (char *)"Compositing | Initializing execution");
+
DebugInfo::execute_started(this);
unsigned int order = 0;
@@ -178,6 +185,7 @@ void ExecutionSystem::execute()
WorkScheduler::finish();
WorkScheduler::stop();
+ editingtree->stats_draw(editingtree->sdh, (char *)"Compositing | Deinitializing execution");
for (index = 0; index < this->m_operations.size(); index++) {
NodeOperation *operation = this->m_operations[index];
operation->deinitExecution();
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h
index ab903206f0a..41d63fb3a72 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.h
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.h
@@ -27,14 +27,11 @@ class ExecutionGroup;
#include "DNA_color_types.h"
#include "DNA_node_types.h"
-#include <vector>
#include "COM_Node.h"
#include "BKE_text.h"
#include "COM_ExecutionGroup.h"
#include "COM_NodeOperation.h"
-using namespace std;
-
/**
* @page execution Execution model
* In order to get to an efficient model for execution, several steps are being done. these steps are explained below.
@@ -154,7 +151,8 @@ public:
* @param rendering [true false]
*/
ExecutionSystem(RenderData *rd, Scene *scene, bNodeTree *editingtree, bool rendering, bool fastcalculation,
- const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings);
+ const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
+ const char *viewName);
/**
* Destructor
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h
index 322e4bc388b..0b5fc21e69e 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.h
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.h
@@ -222,7 +222,7 @@ public:
int v = y;
this->wrap_pixel(u, v, extend_x, extend_y);
const int offset = (this->m_width * y + x) * this->m_num_channels;
- float* buffer = &this->m_buffer[offset];
+ float *buffer = &this->m_buffer[offset];
memcpy(result, buffer, sizeof(float) * this->m_num_channels);
}
}
diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h
index d9c16615fb6..7c87524b4b3 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.h
+++ b/source/blender/compositor/intern/COM_NodeOperation.h
@@ -161,7 +161,7 @@ public:
*
* @return bool the result of this method
*/
- virtual bool isOutputOperation(bool rendering) const { return false; }
+ virtual bool isOutputOperation(bool /*rendering*/) const { return false; }
virtual int isSingleThreaded() { return false; }
@@ -175,7 +175,8 @@ public:
* @param chunkNumber the chunkNumber to be calculated
* @param memoryBuffers all input MemoryBuffer's needed
*/
- virtual void executeRegion(rcti *rect, unsigned int chunkNumber) {}
+ virtual void executeRegion(rcti * /*rect*/,
+ unsigned int /*chunkNumber*/) {}
/**
* @brief when a chunk is executed by an OpenCLDevice, this method is called
@@ -189,8 +190,11 @@ public:
* @param memoryBuffers all input MemoryBuffer's needed
* @param outputBuffer the outputbuffer to write to
*/
- virtual void executeOpenCLRegion(OpenCLDevice *device, rcti *rect,
- unsigned int chunkNumber, MemoryBuffer **memoryBuffers, MemoryBuffer *outputBuffer) {}
+ virtual void executeOpenCLRegion(OpenCLDevice * /*device*/,
+ rcti * /*rect*/,
+ unsigned int /*chunkNumber*/,
+ MemoryBuffer ** /*memoryBuffers*/,
+ MemoryBuffer * /*outputBuffer*/) {}
/**
* @brief custom handle to add new tasks to the OpenCL command queue in order to execute a chunk on an GPUDevice
@@ -204,10 +208,12 @@ public:
* @param clMemToCleanUp all created cl_mem references must be added to this list. Framework will clean this after execution
* @param clKernelsToCleanUp all created cl_kernel references must be added to this list. Framework will clean this after execution
*/
- virtual void executeOpenCL(OpenCLDevice *device,
- MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
- MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp) {}
+ virtual void executeOpenCL(OpenCLDevice * /*device*/,
+ MemoryBuffer * /*outputMemoryBuffer*/,
+ cl_mem /*clOutputBuffer*/,
+ MemoryBuffer ** /*inputMemoryBuffers*/,
+ list<cl_mem> * /*clMemToCleanUp*/,
+ list<cl_kernel> * /*clKernelsToCleanUp*/) {}
virtual void deinitExecution();
bool isResolutionSet() {
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
index 74c05c3e62e..e899b7b14fd 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
@@ -101,12 +101,12 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
}
}
- add_datatype_conversions();
-
add_operation_input_constants();
resolve_proxies();
+ add_datatype_conversions();
+
determineResolutions();
/* surround complex ops with read/write buffer */
@@ -459,7 +459,8 @@ WriteBufferOperation *NodeOperationBuilder::find_attached_write_buffer_operation
return NULL;
}
-void NodeOperationBuilder::add_input_buffers(NodeOperation *operation, NodeOperationInput *input)
+void NodeOperationBuilder::add_input_buffers(NodeOperation * /*operation*/,
+ NodeOperationInput *input)
{
if (!input->isConnected())
return;
diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cpp b/source/blender/compositor/intern/COM_OpenCLDevice.cpp
index 5960082c2fd..1b7acc9daf6 100644
--- a/source/blender/compositor/intern/COM_OpenCLDevice.cpp
+++ b/source/blender/compositor/intern/COM_OpenCLDevice.cpp
@@ -180,7 +180,7 @@ void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel, MemoryBuffer *outputMemo
bool breaked = false;
for (offsety = 0; offsety < height && (!breaked); offsety += localSize) {
- offset.y = offsety;
+ offset.s[1] = offsety;
if (offsety + localSize < height) {
size[1] = localSize;
}
@@ -195,7 +195,7 @@ void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel, MemoryBuffer *outputMemo
else {
size[0] = width - offsetx;
}
- offset.x = offsetx;
+ offset.s[0] = offsetx;
error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset);
if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); }
diff --git a/source/blender/compositor/intern/COM_SingleThreadedOperation.cpp b/source/blender/compositor/intern/COM_SingleThreadedOperation.cpp
index c300a85bfa3..b17f5d6b429 100644
--- a/source/blender/compositor/intern/COM_SingleThreadedOperation.cpp
+++ b/source/blender/compositor/intern/COM_SingleThreadedOperation.cpp
@@ -33,7 +33,7 @@ void SingleThreadedOperation::initExecution()
initMutex();
}
-void SingleThreadedOperation::executePixel(float output[4], int x, int y, void *data)
+void SingleThreadedOperation::executePixel(float output[4], int x, int y, void * /*data*/)
{
this->m_cachedInstance->readNoCheck(output, x, y);
}
diff --git a/source/blender/compositor/intern/COM_SocketReader.h b/source/blender/compositor/intern/COM_SocketReader.h
index c996ef5bbeb..7ba208ebbf6 100644
--- a/source/blender/compositor/intern/COM_SocketReader.h
+++ b/source/blender/compositor/intern/COM_SocketReader.h
@@ -63,7 +63,10 @@ protected:
* @param y the y-coordinate of the pixel to calculate in image space
* @param inputBuffers chunks that can be read by their ReadBufferOperation.
*/
- virtual void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) {}
+ virtual void executePixelSampled(float /*output*/[4],
+ float /*x*/,
+ float /*y*/,
+ PixelSampler /*sampler*/) { }
/**
* @brief calculate a single pixel
@@ -74,7 +77,7 @@ protected:
* @param inputBuffers chunks that can be read by their ReadBufferOperation.
* @param chunkData chunk specific data a during execution time.
*/
- virtual void executePixel(float output[4], int x, int y, void *chunkData) {
+ virtual void executePixel(float output[4], int x, int y, void * /*chunkData*/) {
executePixelSampled(output, x, y, COM_PS_NEAREST);
}
@@ -88,7 +91,10 @@ protected:
* @param dy
* @param inputBuffers chunks that can be read by their ReadBufferOperation.
*/
- virtual void executePixelFiltered(float output[4], float x, float y, float dx[2], float dy[2], PixelSampler sampler) {}
+ virtual void executePixelFiltered(float /*output*/[4],
+ float /*x*/, float /*y*/,
+ float /*dx*/[2], float /*dy*/[2],
+ PixelSampler /*sampler*/) {}
public:
inline void readSampled(float result[4], float x, float y, PixelSampler sampler) {
@@ -101,12 +107,12 @@ public:
executePixelFiltered(result, x, y, dx, dy, sampler);
}
- virtual void *initializeTileData(rcti *rect) { return 0; }
- virtual void deinitializeTileData(rcti *rect, void *data) {}
+ virtual void *initializeTileData(rcti * /*rect*/) { return 0; }
+ virtual void deinitializeTileData(rcti * /*rect*/, void * /*data*/) {}
virtual ~SocketReader() {}
- virtual MemoryBuffer *getInputMemoryBuffer(MemoryBuffer **memoryBuffers) { return 0; }
+ virtual MemoryBuffer *getInputMemoryBuffer(MemoryBuffer ** /*memoryBuffers*/) { return 0; }
inline const unsigned int getWidth() const { return this->m_width; }
inline const unsigned int getHeight() const { return this->m_height; }
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp
index 673920ef84a..fc6ea1299cf 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.cpp
+++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp
@@ -276,7 +276,10 @@ bool WorkScheduler::hasGPUDevices()
#endif
}
-static void CL_CALLBACK clContextError(const char *errinfo, const void *private_info, size_t cb, void *user_data)
+static void CL_CALLBACK clContextError(const char *errinfo,
+ const void * /*private_info*/,
+ size_t /*cb*/,
+ void * /*user_data*/)
{
printf("OPENCL error: %s\n", errinfo);
}
diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cpp
index ec9ef6c7e68..7f7fc141aca 100644
--- a/source/blender/compositor/intern/COM_compositor.cpp
+++ b/source/blender/compositor/intern/COM_compositor.cpp
@@ -45,7 +45,8 @@ static void intern_freeCompositorCaches()
void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rendering,
const ColorManagedViewSettings *viewSettings,
- const ColorManagedDisplaySettings *displaySettings)
+ const ColorManagedDisplaySettings *displaySettings,
+ const char *viewName)
{
/* initialize mutex, TODO this mutex init is actually not thread safe and
* should be done somewhere as part of blender startup, all the other
@@ -77,11 +78,12 @@ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rende
/* set progress bar to 0% and status to init compositing */
editingtree->progress(editingtree->prh, 0.0);
+ editingtree->stats_draw(editingtree->sdh, (char *)"Compositing");
bool twopass = (editingtree->flag & NTREE_TWO_PASS) > 0 && !rendering;
/* initialize execution system */
if (twopass) {
- ExecutionSystem *system = new ExecutionSystem(rd, scene, editingtree, rendering, twopass, viewSettings, displaySettings);
+ ExecutionSystem *system = new ExecutionSystem(rd, scene, editingtree, rendering, twopass, viewSettings, displaySettings, viewName);
system->execute();
delete system;
@@ -94,7 +96,7 @@ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rende
}
ExecutionSystem *system = new ExecutionSystem(rd, scene, editingtree, rendering, false,
- viewSettings, displaySettings);
+ viewSettings, displaySettings, viewName);
system->execute();
delete system;
diff --git a/source/blender/compositor/nodes/COM_AlphaOverNode.cpp b/source/blender/compositor/nodes/COM_AlphaOverNode.cpp
index 0306d636c8b..e9b99b6aaf1 100644
--- a/source/blender/compositor/nodes/COM_AlphaOverNode.cpp
+++ b/source/blender/compositor/nodes/COM_AlphaOverNode.cpp
@@ -30,7 +30,7 @@
#include "COM_SetValueOperation.h"
#include "DNA_material_types.h" // the ramp types
-void AlphaOverNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void AlphaOverNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *color1Socket = this->getInputSocket(1);
NodeInput *color2Socket = this->getInputSocket(2);
diff --git a/source/blender/compositor/nodes/COM_BokehImageNode.cpp b/source/blender/compositor/nodes/COM_BokehImageNode.cpp
index c75e9b16336..7b7cfc812aa 100644
--- a/source/blender/compositor/nodes/COM_BokehImageNode.cpp
+++ b/source/blender/compositor/nodes/COM_BokehImageNode.cpp
@@ -29,7 +29,7 @@ BokehImageNode::BokehImageNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void BokehImageNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void BokehImageNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
BokehImageOperation *operation = new BokehImageOperation();
operation->setData((NodeBokehImage *)this->getbNode()->storage);
diff --git a/source/blender/compositor/nodes/COM_BrightnessNode.cpp b/source/blender/compositor/nodes/COM_BrightnessNode.cpp
index e684b569945..053f286c66e 100644
--- a/source/blender/compositor/nodes/COM_BrightnessNode.cpp
+++ b/source/blender/compositor/nodes/COM_BrightnessNode.cpp
@@ -29,7 +29,7 @@ BrightnessNode::BrightnessNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void BrightnessNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void BrightnessNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
BrightnessOperation *operation = new BrightnessOperation();
converter.addOperation(operation);
diff --git a/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp b/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp
index f356c74cd49..b04f86dea08 100644
--- a/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp
@@ -30,7 +30,7 @@ ChannelMatteNode::ChannelMatteNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ChannelMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ChannelMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *node = this->getbNode();
diff --git a/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp b/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp
index 90de9358587..6324ca9a3ca 100644
--- a/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp
@@ -30,7 +30,7 @@ ChromaMatteNode::ChromaMatteNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ChromaMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ChromaMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorsnode = getbNode();
diff --git a/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp b/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp
index fc0df046e86..a531493d486 100644
--- a/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp
@@ -32,7 +32,7 @@ ColorBalanceNode::ColorBalanceNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ColorBalanceNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ColorBalanceNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *node = this->getbNode();
NodeColorBalance *n = (NodeColorBalance *)node->storage;
diff --git a/source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp b/source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp
index 728b51b8dc1..e926d131c1a 100644
--- a/source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp
@@ -29,7 +29,7 @@ ColorCorrectionNode::ColorCorrectionNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ColorCorrectionNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ColorCorrectionNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorNode = getbNode();
diff --git a/source/blender/compositor/nodes/COM_ColorCurveNode.cpp b/source/blender/compositor/nodes/COM_ColorCurveNode.cpp
index 6dc936302f4..5a4dc79e6b2 100644
--- a/source/blender/compositor/nodes/COM_ColorCurveNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorCurveNode.cpp
@@ -29,7 +29,7 @@ ColorCurveNode::ColorCurveNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ColorCurveNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ColorCurveNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
if (this->getInputSocket(2)->isLinked() || this->getInputSocket(3)->isLinked()) {
ColorCurveOperation *operation = new ColorCurveOperation();
diff --git a/source/blender/compositor/nodes/COM_ColorMatteNode.cpp b/source/blender/compositor/nodes/COM_ColorMatteNode.cpp
index def3b18e0fe..f7c20894087 100644
--- a/source/blender/compositor/nodes/COM_ColorMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorMatteNode.cpp
@@ -30,7 +30,7 @@ ColorMatteNode::ColorMatteNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ColorMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ColorMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorsnode = getbNode();
diff --git a/source/blender/compositor/nodes/COM_ColorNode.cpp b/source/blender/compositor/nodes/COM_ColorNode.cpp
index 4106cb64798..c3770e79dea 100644
--- a/source/blender/compositor/nodes/COM_ColorNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorNode.cpp
@@ -29,7 +29,7 @@ ColorNode::ColorNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ColorNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ColorNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
SetColorOperation *operation = new SetColorOperation();
NodeOutput *output = this->getOutputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_ColorRampNode.cpp b/source/blender/compositor/nodes/COM_ColorRampNode.cpp
index a61ddffbf35..1feaa88bebb 100644
--- a/source/blender/compositor/nodes/COM_ColorRampNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorRampNode.cpp
@@ -32,7 +32,7 @@ ColorRampNode::ColorRampNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ColorRampNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ColorRampNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *inputSocket = this->getInputSocket(0);
NodeOutput *outputSocket = this->getOutputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_ColorSpillNode.cpp b/source/blender/compositor/nodes/COM_ColorSpillNode.cpp
index 82454ba7979..c3a911e830b 100644
--- a/source/blender/compositor/nodes/COM_ColorSpillNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorSpillNode.cpp
@@ -29,7 +29,7 @@ ColorSpillNode::ColorSpillNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ColorSpillNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ColorSpillNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorsnode = getbNode();
diff --git a/source/blender/compositor/nodes/COM_ColorToBWNode.cpp b/source/blender/compositor/nodes/COM_ColorToBWNode.cpp
index a1616a61b4b..f09c6bac3ee 100644
--- a/source/blender/compositor/nodes/COM_ColorToBWNode.cpp
+++ b/source/blender/compositor/nodes/COM_ColorToBWNode.cpp
@@ -30,7 +30,7 @@ ColorToBWNode::ColorToBWNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ColorToBWNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ColorToBWNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *colorSocket = this->getInputSocket(0);
NodeOutput *valueSocket = this->getOutputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_CombineColorNode.cpp b/source/blender/compositor/nodes/COM_CombineColorNode.cpp
index c7a3baf809d..a39e946fe5f 100644
--- a/source/blender/compositor/nodes/COM_CombineColorNode.cpp
+++ b/source/blender/compositor/nodes/COM_CombineColorNode.cpp
@@ -72,17 +72,17 @@ void CombineColorNode::convertToOperations(NodeConverter &converter, const Compo
}
-NodeOperation *CombineRGBANode::getColorConverter(const CompositorContext &context) const
+NodeOperation *CombineRGBANode::getColorConverter(const CompositorContext &/*context*/) const
{
return NULL; /* no conversion needed */
}
-NodeOperation *CombineHSVANode::getColorConverter(const CompositorContext &context) const
+NodeOperation *CombineHSVANode::getColorConverter(const CompositorContext &/*context*/) const
{
return new ConvertHSVToRGBOperation();
}
-NodeOperation *CombineYCCANode::getColorConverter(const CompositorContext &context) const
+NodeOperation *CombineYCCANode::getColorConverter(const CompositorContext &/*context*/) const
{
ConvertYCCToRGBOperation *operation = new ConvertYCCToRGBOperation();
bNode *editorNode = this->getbNode();
@@ -90,7 +90,7 @@ NodeOperation *CombineYCCANode::getColorConverter(const CompositorContext &conte
return operation;
}
-NodeOperation *CombineYUVANode::getColorConverter(const CompositorContext &context) const
+NodeOperation *CombineYUVANode::getColorConverter(const CompositorContext &/*context*/) const
{
return new ConvertYUVToRGBOperation();
}
diff --git a/source/blender/compositor/nodes/COM_CompositorNode.cpp b/source/blender/compositor/nodes/COM_CompositorNode.cpp
index 933b8d0282b..9e8b40d8af4 100644
--- a/source/blender/compositor/nodes/COM_CompositorNode.cpp
+++ b/source/blender/compositor/nodes/COM_CompositorNode.cpp
@@ -43,6 +43,7 @@ void CompositorNode::convertToOperations(NodeConverter &converter, const Composi
CompositorOperation *compositorOperation = new CompositorOperation();
compositorOperation->setSceneName(context.getScene()->id.name);
compositorOperation->setRenderData(context.getRenderData());
+ compositorOperation->setViewName(context.getViewName());
compositorOperation->setbNodeTree(context.getbNodeTree());
/* alpha socket gives either 1 or a custom alpha value if "use alpha" is enabled */
compositorOperation->setUseAlphaInput(ignore_alpha || alphaSocket->isLinked());
diff --git a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp
index ba31ed6e89c..fbf5dbb6253 100644
--- a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp
+++ b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp
@@ -23,7 +23,7 @@
#include "COM_ConvertOperation.h"
#include "COM_ExecutionSystem.h"
-void ConvertAlphaNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ConvertAlphaNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeOperation *operation = NULL;
bNode *node = this->getbNode();
diff --git a/source/blender/compositor/nodes/COM_CornerPinNode.cpp b/source/blender/compositor/nodes/COM_CornerPinNode.cpp
index ea9f22f2840..5e4e463595a 100644
--- a/source/blender/compositor/nodes/COM_CornerPinNode.cpp
+++ b/source/blender/compositor/nodes/COM_CornerPinNode.cpp
@@ -28,7 +28,7 @@ CornerPinNode::CornerPinNode(bNode *editorNode) : Node(editorNode)
{
}
-void CornerPinNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void CornerPinNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *input_image = this->getInputSocket(0);
/* note: socket order differs between UI node and operations:
diff --git a/source/blender/compositor/nodes/COM_CropNode.cpp b/source/blender/compositor/nodes/COM_CropNode.cpp
index 6c3dc93481b..ee148f41c68 100644
--- a/source/blender/compositor/nodes/COM_CropNode.cpp
+++ b/source/blender/compositor/nodes/COM_CropNode.cpp
@@ -29,7 +29,7 @@ CropNode::CropNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void CropNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void CropNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *node = getbNode();
NodeTwoXYs *cropSettings = (NodeTwoXYs *)node->storage;
diff --git a/source/blender/compositor/nodes/COM_DespeckleNode.cpp b/source/blender/compositor/nodes/COM_DespeckleNode.cpp
index bac6337374f..a21885bf42d 100644
--- a/source/blender/compositor/nodes/COM_DespeckleNode.cpp
+++ b/source/blender/compositor/nodes/COM_DespeckleNode.cpp
@@ -29,7 +29,7 @@ DespeckleNode::DespeckleNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void DespeckleNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void DespeckleNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorNode = this->getbNode();
NodeInput *inputSocket = this->getInputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp b/source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp
index 8870badab09..2cb0e2301ac 100644
--- a/source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp
@@ -30,7 +30,7 @@ DifferenceMatteNode::DifferenceMatteNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void DifferenceMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void DifferenceMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *inputSocket = this->getInputSocket(0);
NodeInput *inputSocket2 = this->getInputSocket(1);
diff --git a/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp b/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp
index 704c704c500..5f3feda5de7 100644
--- a/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp
@@ -31,7 +31,7 @@ DistanceMatteNode::DistanceMatteNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void DistanceMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void DistanceMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorsnode = getbNode();
NodeChroma *storage = (NodeChroma *)editorsnode->storage;
diff --git a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp
index 1f80eeadf83..c67abb1ab99 100644
--- a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp
+++ b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp
@@ -29,7 +29,7 @@ DoubleEdgeMaskNode::DoubleEdgeMaskNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void DoubleEdgeMaskNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void DoubleEdgeMaskNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
DoubleEdgeMaskOperation *operation;
bNode *bnode = this->getbNode();
diff --git a/source/blender/compositor/nodes/COM_FilterNode.cpp b/source/blender/compositor/nodes/COM_FilterNode.cpp
index 9f3a7ae795c..7493f24ba6b 100644
--- a/source/blender/compositor/nodes/COM_FilterNode.cpp
+++ b/source/blender/compositor/nodes/COM_FilterNode.cpp
@@ -32,7 +32,7 @@ FilterNode::FilterNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void FilterNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void FilterNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *inputSocket = this->getInputSocket(0);
NodeInput *inputImageSocket = this->getInputSocket(1);
diff --git a/source/blender/compositor/nodes/COM_FlipNode.cpp b/source/blender/compositor/nodes/COM_FlipNode.cpp
index 1dbcc97143e..0177dc7017a 100644
--- a/source/blender/compositor/nodes/COM_FlipNode.cpp
+++ b/source/blender/compositor/nodes/COM_FlipNode.cpp
@@ -30,7 +30,7 @@ FlipNode::FlipNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void FlipNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void FlipNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *inputSocket = this->getInputSocket(0);
NodeOutput *outputSocket = this->getOutputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_GammaNode.cpp b/source/blender/compositor/nodes/COM_GammaNode.cpp
index 046cd9e9a0d..bf24bee55d3 100644
--- a/source/blender/compositor/nodes/COM_GammaNode.cpp
+++ b/source/blender/compositor/nodes/COM_GammaNode.cpp
@@ -29,7 +29,7 @@ GammaNode::GammaNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void GammaNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void GammaNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
GammaOperation *operation = new GammaOperation();
converter.addOperation(operation);
diff --git a/source/blender/compositor/nodes/COM_GlareNode.cpp b/source/blender/compositor/nodes/COM_GlareNode.cpp
index 0429a1a80cf..7afe1510ae4 100644
--- a/source/blender/compositor/nodes/COM_GlareNode.cpp
+++ b/source/blender/compositor/nodes/COM_GlareNode.cpp
@@ -36,7 +36,7 @@ GlareNode::GlareNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void GlareNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void GlareNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *node = this->getbNode();
NodeGlare *glare = (NodeGlare *)node->storage;
diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp
index 003bc91edd3..e159886bb46 100644
--- a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp
+++ b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp
@@ -36,7 +36,7 @@ HueSaturationValueCorrectNode::HueSaturationValueCorrectNode(bNode *editorNode)
/* pass */
}
-void HueSaturationValueCorrectNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void HueSaturationValueCorrectNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *valueSocket = this->getInputSocket(0);
NodeInput *colorSocket = this->getInputSocket(1);
diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp
index cdec1250c6e..29c296a896d 100644
--- a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp
+++ b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp
@@ -35,7 +35,7 @@ HueSaturationValueNode::HueSaturationValueNode(bNode *editorNode) : Node(editorN
/* pass */
}
-void HueSaturationValueNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void HueSaturationValueNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *valueSocket = this->getInputSocket(0);
NodeInput *colorSocket = this->getInputSocket(1);
diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp
index cb7ccfaedf9..572e63a2ced 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.cpp
+++ b/source/blender/compositor/nodes/COM_ImageNode.cpp
@@ -40,19 +40,19 @@ ImageNode::ImageNode(bNode *editorNode) : Node(editorNode)
}
NodeOperation *ImageNode::doMultilayerCheck(NodeConverter &converter, RenderLayer *rl, Image *image, ImageUser *user,
- int framenumber, int outputsocketIndex, int passindex, DataType datatype) const
+ int framenumber, int outputsocketIndex, int passtype, int view, DataType datatype) const
{
NodeOutput *outputSocket = this->getOutputSocket(outputsocketIndex);
MultilayerBaseOperation *operation = NULL;
switch (datatype) {
case COM_DT_VALUE:
- operation = new MultilayerValueOperation(passindex);
+ operation = new MultilayerValueOperation(passtype, view);
break;
case COM_DT_VECTOR:
- operation = new MultilayerVectorOperation(passindex);
+ operation = new MultilayerVectorOperation(passtype, view);
break;
case COM_DT_COLOR:
- operation = new MultilayerColorOperation(passindex);
+ operation = new MultilayerColorOperation(passtype, view);
break;
default:
break;
@@ -79,7 +79,6 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
int numberOfOutputs = this->getNumberOfOutputSockets();
bool outputStraightAlpha = (editorNode->custom1 & CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT) != 0;
BKE_image_user_frame_calc(imageuser, context.getFramenumber(), 0);
- NodeOperation *combined_operation = NULL;
/* force a load, we assume iuser index will be set OK anyway */
if (image && image->type == IMA_TYPE_MULTILAYER) {
bool is_multilayer_ok = false;
@@ -96,6 +95,9 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
NodeOperation *operation = NULL;
socket = this->getOutputSocket(index);
bNodeSocket *bnodeSocket = socket->getbNodeSocket();
+ RenderPass *rpass = (RenderPass *)BLI_findstring(&rl->passes, bnodeSocket->identifier, offsetof(RenderPass, internal_name));
+ int view = 0;
+
/* Passes in the file can differ from passes stored in sockets (#36755).
* Look up the correct file pass using the socket identifier instead.
*/
@@ -104,47 +106,57 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
int passindex = storage->pass_index;*/
RenderPass *rpass = (RenderPass *)BLI_findlink(&rl->passes, passindex);
#endif
- int passindex;
- RenderPass *rpass;
- if (STREQ(bnodeSocket->identifier, "Alpha")) {
- BLI_assert(combined_operation != NULL);
- NodeOutput *outputSocket = this->getOutputSocket(index);
- SeparateChannelOperation *separate_operation;
- separate_operation = new SeparateChannelOperation();
- separate_operation->setChannel(3);
- converter.addOperation(separate_operation);
- converter.addLink(combined_operation->getOutputSocket(), separate_operation->getInputSocket(0));
- converter.mapOutputSocket(outputSocket, separate_operation->getOutputSocket());
- operation = separate_operation;
+
+ /* returns the image view to use for the current active view */
+ if (BLI_listbase_count_ex(&image->rr->views, 2) > 1) {
+ const int view_image = imageuser->view;
+ const bool is_allview = (view_image == 0); /* if view selected == All (0) */
+
+ if (is_allview) {
+ /* heuristic to match image name with scene names
+ * check if the view name exists in the image */
+ view = BLI_findstringindex(&image->rr->views, context.getViewName(), offsetof(RenderView, name));
+ if (view == -1) view = 0;
+ }
+ else {
+ view = view_image - 1;
+ }
}
- else {
- for (rpass = (RenderPass *)rl->passes.first, passindex = 0; rpass; rpass = rpass->next, ++passindex)
- if (STREQ(rpass->name, bnodeSocket->identifier))
+
+ if (rpass) {
+ switch (rpass->channels) {
+ case 1:
+ operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index,
+ rpass->passtype, view, COM_DT_VALUE);
break;
- if (rpass) {
- imageuser->pass = passindex;
- switch (rpass->channels) {
- case 1:
- operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, passindex, COM_DT_VALUE);
- break;
- /* using image operations for both 3 and 4 channels (RGB and RGBA respectively) */
- /* XXX any way to detect actual vector images? */
- case 3:
- operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, passindex, COM_DT_VECTOR);
- break;
- case 4:
- operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, passindex, COM_DT_COLOR);
- break;
- default:
- /* dummy operation is added below */
- break;
- }
- if (index == 0 && operation) {
- converter.addPreview(operation->getOutputSocket());
- }
- if (STREQ(rpass->chan_id, "RGBA")) {
- combined_operation = operation;
- }
+ /* using image operations for both 3 and 4 channels (RGB and RGBA respectively) */
+ /* XXX any way to detect actual vector images? */
+ case 3:
+ operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index,
+ rpass->passtype, view, COM_DT_VECTOR);
+ break;
+ case 4:
+ operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index,
+ rpass->passtype, view, COM_DT_COLOR);
+ break;
+ default:
+ /* dummy operation is added below */
+ break;
+ }
+ if (index == 0 && operation) {
+ converter.addPreview(operation->getOutputSocket());
+ }
+ if (rpass->passtype == SCE_PASS_COMBINED) {
+ BLI_assert(operation != NULL);
+ BLI_assert(index < numberOfOutputs - 1);
+ NodeOutput *outputSocket = this->getOutputSocket(index + 1);
+ SeparateChannelOperation *separate_operation;
+ separate_operation = new SeparateChannelOperation();
+ separate_operation->setChannel(3);
+ converter.addOperation(separate_operation);
+ converter.addLink(operation->getOutputSocket(), separate_operation->getInputSocket(0));
+ converter.mapOutputSocket(outputSocket, separate_operation->getOutputSocket());
+ index++;
}
}
@@ -168,6 +180,8 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
operation->setImage(image);
operation->setImageUser(imageuser);
operation->setFramenumber(framenumber);
+ operation->setRenderData(context.getRenderData());
+ operation->setViewName(context.getViewName());
converter.addOperation(operation);
if (outputStraightAlpha) {
@@ -190,6 +204,8 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
alphaOperation->setImage(image);
alphaOperation->setImageUser(imageuser);
alphaOperation->setFramenumber(framenumber);
+ alphaOperation->setRenderData(context.getRenderData());
+ alphaOperation->setViewName(context.getViewName());
converter.addOperation(alphaOperation);
converter.mapOutputSocket(alphaImage, alphaOperation->getOutputSocket());
@@ -200,6 +216,8 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
depthOperation->setImage(image);
depthOperation->setImageUser(imageuser);
depthOperation->setFramenumber(framenumber);
+ depthOperation->setRenderData(context.getRenderData());
+ depthOperation->setViewName(context.getViewName());
converter.addOperation(depthOperation);
converter.mapOutputSocket(depthImage, depthOperation->getOutputSocket());
@@ -239,6 +257,7 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
}
if (operation) {
+ /* not supporting multiview for this generic case */
converter.addOperation(operation);
converter.mapOutputSocket(output, operation->getOutputSocket());
}
diff --git a/source/blender/compositor/nodes/COM_ImageNode.h b/source/blender/compositor/nodes/COM_ImageNode.h
index 1daa39a2a1f..267794510e1 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.h
+++ b/source/blender/compositor/nodes/COM_ImageNode.h
@@ -36,7 +36,7 @@ extern "C" {
class ImageNode : public Node {
private:
NodeOperation *doMultilayerCheck(NodeConverter &converter, RenderLayer *rl, Image *image, ImageUser *user,
- int framenumber, int outputsocketIndex, int passindex, DataType datatype) const;
+ int framenumber, int outputsocketIndex, int passtype, int view, DataType datatype) const;
public:
ImageNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
diff --git a/source/blender/compositor/nodes/COM_InpaintNode.cpp b/source/blender/compositor/nodes/COM_InpaintNode.cpp
index 1371cdb5f1d..9e78625684d 100644
--- a/source/blender/compositor/nodes/COM_InpaintNode.cpp
+++ b/source/blender/compositor/nodes/COM_InpaintNode.cpp
@@ -31,7 +31,7 @@ InpaintNode::InpaintNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void InpaintNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void InpaintNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorNode = this->getbNode();
diff --git a/source/blender/compositor/nodes/COM_InvertNode.cpp b/source/blender/compositor/nodes/COM_InvertNode.cpp
index ed4a21132ca..da499d66c2c 100644
--- a/source/blender/compositor/nodes/COM_InvertNode.cpp
+++ b/source/blender/compositor/nodes/COM_InvertNode.cpp
@@ -30,7 +30,7 @@ InvertNode::InvertNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void InvertNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void InvertNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
InvertOperation *operation = new InvertOperation();
bNode *node = this->getbNode();
diff --git a/source/blender/compositor/nodes/COM_LensDistortionNode.cpp b/source/blender/compositor/nodes/COM_LensDistortionNode.cpp
index 32db452e6c2..3d3cc841715 100644
--- a/source/blender/compositor/nodes/COM_LensDistortionNode.cpp
+++ b/source/blender/compositor/nodes/COM_LensDistortionNode.cpp
@@ -30,7 +30,7 @@ LensDistortionNode::LensDistortionNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void LensDistortionNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void LensDistortionNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorNode = this->getbNode();
NodeLensDist *data = (NodeLensDist *)editorNode->storage;
diff --git a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp
index e23ec243ff4..382296a7f3a 100644
--- a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp
+++ b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp
@@ -30,7 +30,7 @@ LuminanceMatteNode::LuminanceMatteNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void LuminanceMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void LuminanceMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *editorsnode = getbNode();
NodeInput *inputSocket = this->getInputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_MapRangeNode.cpp b/source/blender/compositor/nodes/COM_MapRangeNode.cpp
index 2c164cfad32..148ca00205c 100644
--- a/source/blender/compositor/nodes/COM_MapRangeNode.cpp
+++ b/source/blender/compositor/nodes/COM_MapRangeNode.cpp
@@ -30,7 +30,7 @@ MapRangeNode::MapRangeNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void MapRangeNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void MapRangeNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *valueSocket = this->getInputSocket(0);
NodeInput *sourceMinSocket = this->getInputSocket(1);
diff --git a/source/blender/compositor/nodes/COM_MapUVNode.cpp b/source/blender/compositor/nodes/COM_MapUVNode.cpp
index 25ca7b8b8c6..ec38e23ec07 100644
--- a/source/blender/compositor/nodes/COM_MapUVNode.cpp
+++ b/source/blender/compositor/nodes/COM_MapUVNode.cpp
@@ -28,7 +28,7 @@ MapUVNode::MapUVNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void MapUVNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void MapUVNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bNode *node = this->getbNode();
diff --git a/source/blender/compositor/nodes/COM_MapValueNode.cpp b/source/blender/compositor/nodes/COM_MapValueNode.cpp
index d7ee4e6a38b..f04c6a2d316 100644
--- a/source/blender/compositor/nodes/COM_MapValueNode.cpp
+++ b/source/blender/compositor/nodes/COM_MapValueNode.cpp
@@ -30,7 +30,7 @@ MapValueNode::MapValueNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void MapValueNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void MapValueNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
TexMapping *storage = (TexMapping *)this->getbNode()->storage;
diff --git a/source/blender/compositor/nodes/COM_MathNode.cpp b/source/blender/compositor/nodes/COM_MathNode.cpp
index 4cd6964ed3b..eb6bb2caf56 100644
--- a/source/blender/compositor/nodes/COM_MathNode.cpp
+++ b/source/blender/compositor/nodes/COM_MathNode.cpp
@@ -24,7 +24,7 @@
#include "COM_MathBaseOperation.h"
#include "COM_ExecutionSystem.h"
-void MathNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void MathNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
MathBaseOperation *operation = NULL;
diff --git a/source/blender/compositor/nodes/COM_MixNode.cpp b/source/blender/compositor/nodes/COM_MixNode.cpp
index 89010d0e861..0607d6d6705 100644
--- a/source/blender/compositor/nodes/COM_MixNode.cpp
+++ b/source/blender/compositor/nodes/COM_MixNode.cpp
@@ -34,7 +34,7 @@ MixNode::MixNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void MixNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void MixNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *valueSocket = this->getInputSocket(0);
NodeInput *color1Socket = this->getInputSocket(1);
diff --git a/source/blender/compositor/nodes/COM_NormalNode.cpp b/source/blender/compositor/nodes/COM_NormalNode.cpp
index d7c3fd11844..26da61cb9e7 100644
--- a/source/blender/compositor/nodes/COM_NormalNode.cpp
+++ b/source/blender/compositor/nodes/COM_NormalNode.cpp
@@ -31,7 +31,7 @@ NormalNode::NormalNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void NormalNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void NormalNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *inputSocket = this->getInputSocket(0);
NodeOutput *outputSocket = this->getOutputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_NormalizeNode.cpp b/source/blender/compositor/nodes/COM_NormalizeNode.cpp
index f6e919c168f..a13fcd2a301 100644
--- a/source/blender/compositor/nodes/COM_NormalizeNode.cpp
+++ b/source/blender/compositor/nodes/COM_NormalizeNode.cpp
@@ -28,7 +28,7 @@ NormalizeNode::NormalizeNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void NormalizeNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void NormalizeNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NormalizeOperation *operation = new NormalizeOperation();
converter.addOperation(operation);
diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cpp b/source/blender/compositor/nodes/COM_OutputFileNode.cpp
index 92fa74b9a2e..acd2602e216 100644
--- a/source/blender/compositor/nodes/COM_OutputFileNode.cpp
+++ b/source/blender/compositor/nodes/COM_OutputFileNode.cpp
@@ -23,8 +23,11 @@
#include "COM_OutputFileNode.h"
#include "COM_OutputFileOperation.h"
+#include "COM_OutputFileMultiViewOperation.h"
#include "COM_ExecutionSystem.h"
+#include "BKE_scene.h"
+
#include "BLI_path_util.h"
OutputFileNode::OutputFileNode(bNode *editorNode) : Node(editorNode)
@@ -35,6 +38,7 @@ OutputFileNode::OutputFileNode(bNode *editorNode) : Node(editorNode)
void OutputFileNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
{
NodeImageMultiFile *storage = (NodeImageMultiFile *)this->getbNode()->storage;
+ const bool is_multiview = (context.getRenderData()->scemode & R_MULTIVIEW) != 0;
if (!context.isRendering()) {
/* only output files when rendering a sequence -
@@ -46,10 +50,18 @@ void OutputFileNode::convertToOperations(NodeConverter &converter, const Composi
if (storage->format.imtype == R_IMF_IMTYPE_MULTILAYER) {
/* single output operation for the multilayer file */
- OutputOpenExrMultiLayerOperation *outputOperation = new OutputOpenExrMultiLayerOperation(
- context.getRenderData(), context.getbNodeTree(), storage->base_path, storage->format.exr_codec);
+ OutputOpenExrMultiLayerOperation *outputOperation;
+
+ if (is_multiview && storage->format.views_format == R_IMF_VIEWS_MULTIVIEW) {
+ outputOperation = new OutputOpenExrMultiLayerMultiViewOperation(
+ context.getRenderData(), context.getbNodeTree(), storage->base_path, storage->format.exr_codec, context.getViewName());
+ }
+ else {
+ outputOperation = new OutputOpenExrMultiLayerOperation(
+ context.getRenderData(), context.getbNodeTree(), storage->base_path, storage->format.exr_codec, context.getViewName());
+ }
converter.addOperation(outputOperation);
-
+
int num_inputs = getNumberOfInputSockets();
bool previewAdded = false;
for (int i = 0; i < num_inputs; ++i) {
@@ -76,17 +88,31 @@ void OutputFileNode::convertToOperations(NodeConverter &converter, const Composi
NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)input->getbNodeSocket()->storage;
ImageFormatData *format = (sockdata->use_node_format ? &storage->format : &sockdata->format);
char path[FILE_MAX];
-
+
/* combine file path for the input */
BLI_join_dirfile(path, FILE_MAX, storage->base_path, sockdata->path);
-
- OutputSingleLayerOperation *outputOperation = new OutputSingleLayerOperation(
- context.getRenderData(), context.getbNodeTree(), input->getDataType(), format, path,
- context.getViewSettings(), context.getDisplaySettings());
+
+ NodeOperation *outputOperation = NULL;
+
+ if (is_multiview && format->views_format == R_IMF_VIEWS_MULTIVIEW) {
+ outputOperation = new OutputOpenExrSingleLayerMultiViewOperation(
+ context.getRenderData(), context.getbNodeTree(), input->getDataType(), format, path,
+ context.getViewSettings(), context.getDisplaySettings(), context.getViewName());
+ }
+ else if ((!is_multiview) || (format->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ outputOperation = new OutputSingleLayerOperation(
+ context.getRenderData(), context.getbNodeTree(), input->getDataType(), format, path,
+ context.getViewSettings(), context.getDisplaySettings(), context.getViewName());
+ }
+ else { /* R_IMF_VIEWS_STEREO_3D */
+ outputOperation = new OutputStereoOperation(
+ context.getRenderData(), context.getbNodeTree(), input->getDataType(), format, path,
+ sockdata->layer, context.getViewSettings(), context.getDisplaySettings(), context.getViewName());
+ }
+
converter.addOperation(outputOperation);
-
converter.mapInputSocket(input, outputOperation->getInputSocket(0));
-
+
if (!previewAdded) {
converter.addNodeInputPreview(input);
previewAdded = true;
diff --git a/source/blender/compositor/nodes/COM_PixelateNode.cpp b/source/blender/compositor/nodes/COM_PixelateNode.cpp
index da3cd74e771..fe806dbf307 100644
--- a/source/blender/compositor/nodes/COM_PixelateNode.cpp
+++ b/source/blender/compositor/nodes/COM_PixelateNode.cpp
@@ -30,7 +30,7 @@ PixelateNode::PixelateNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void PixelateNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void PixelateNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *inputSocket = this->getInputSocket(0);
NodeOutput *outputSocket = this->getOutputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
index cc66c688379..02bf1ec8cfb 100644
--- a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
+++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
@@ -42,7 +42,8 @@ void RenderLayersNode::testSocketLink(NodeConverter &converter, const Compositor
operation->setScene(scene);
operation->setLayerId(layerId);
operation->setRenderData(context.getRenderData());
-
+ operation->setViewName(context.getViewName());
+
converter.mapOutputSocket(outputSocket, operation->getOutputSocket());
converter.addOperation(operation);
diff --git a/source/blender/compositor/nodes/COM_RotateNode.cpp b/source/blender/compositor/nodes/COM_RotateNode.cpp
index c5fe88b3636..6fd7e357775 100644
--- a/source/blender/compositor/nodes/COM_RotateNode.cpp
+++ b/source/blender/compositor/nodes/COM_RotateNode.cpp
@@ -31,7 +31,7 @@ RotateNode::RotateNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void RotateNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void RotateNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *inputSocket = this->getInputSocket(0);
NodeInput *inputDegreeSocket = this->getInputSocket(1);
diff --git a/source/blender/compositor/nodes/COM_SeparateColorNode.cpp b/source/blender/compositor/nodes/COM_SeparateColorNode.cpp
index a6fa9065364..780ce73d340 100644
--- a/source/blender/compositor/nodes/COM_SeparateColorNode.cpp
+++ b/source/blender/compositor/nodes/COM_SeparateColorNode.cpp
@@ -96,17 +96,17 @@ void SeparateColorNode::convertToOperations(NodeConverter &converter, const Comp
}
-NodeOperation *SeparateRGBANode::getColorConverter(const CompositorContext &context) const
+NodeOperation *SeparateRGBANode::getColorConverter(const CompositorContext &/*context*/) const
{
return NULL; /* no conversion needed */
}
-NodeOperation *SeparateHSVANode::getColorConverter(const CompositorContext &context) const
+NodeOperation *SeparateHSVANode::getColorConverter(const CompositorContext &/*context*/) const
{
return new ConvertRGBToHSVOperation();
}
-NodeOperation *SeparateYCCANode::getColorConverter(const CompositorContext &context) const
+NodeOperation *SeparateYCCANode::getColorConverter(const CompositorContext &/*context*/) const
{
ConvertRGBToYCCOperation *operation = new ConvertRGBToYCCOperation();
bNode *editorNode = this->getbNode();
@@ -114,7 +114,7 @@ NodeOperation *SeparateYCCANode::getColorConverter(const CompositorContext &cont
return operation;
}
-NodeOperation *SeparateYUVANode::getColorConverter(const CompositorContext &context) const
+NodeOperation *SeparateYUVANode::getColorConverter(const CompositorContext &/*context*/) const
{
return new ConvertRGBToYUVOperation();
}
diff --git a/source/blender/compositor/nodes/COM_SetAlphaNode.cpp b/source/blender/compositor/nodes/COM_SetAlphaNode.cpp
index 22ddd5bb157..32c03c695be 100644
--- a/source/blender/compositor/nodes/COM_SetAlphaNode.cpp
+++ b/source/blender/compositor/nodes/COM_SetAlphaNode.cpp
@@ -24,7 +24,7 @@
#include "COM_SetAlphaOperation.h"
#include "COM_ExecutionSystem.h"
-void SetAlphaNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void SetAlphaNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
SetAlphaOperation *operation = new SetAlphaOperation();
diff --git a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp b/source/blender/compositor/nodes/COM_SocketProxyNode.cpp
index 17b00af16d8..465a94e8335 100644
--- a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp
+++ b/source/blender/compositor/nodes/COM_SocketProxyNode.cpp
@@ -46,7 +46,7 @@ SocketProxyNode::SocketProxyNode(bNode *editorNode, bNodeSocket *editorInput, bN
this->addOutputSocket(dt, editorOutput);
}
-void SocketProxyNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void SocketProxyNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeOperationOutput *proxy_output = converter.addInputProxy(getInputSocket(0), m_use_conversion);
converter.mapOutputSocket(getOutputSocket(), proxy_output);
@@ -68,7 +68,7 @@ SocketBufferNode::SocketBufferNode(bNode *editorNode, bNodeSocket *editorInput,
this->addOutputSocket(dt, editorOutput);
}
-void SocketBufferNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void SocketBufferNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeOutput *output = this->getOutputSocket(0);
NodeInput *input = this->getInputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp b/source/blender/compositor/nodes/COM_SplitViewerNode.cpp
index 15eca0a97e5..0f917d317f9 100644
--- a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp
+++ b/source/blender/compositor/nodes/COM_SplitViewerNode.cpp
@@ -22,6 +22,8 @@
#include "COM_SplitViewerNode.h"
#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_scene.h"
#include "COM_SplitOperation.h"
#include "COM_ViewerOperation.h"
@@ -55,6 +57,8 @@ void SplitViewerNode::convertToOperations(NodeConverter &converter, const Compos
viewerOperation->setImageUser(imageUser);
viewerOperation->setViewSettings(context.getViewSettings());
viewerOperation->setDisplaySettings(context.getDisplaySettings());
+ viewerOperation->setRenderData(context.getRenderData());
+ viewerOperation->setViewName(context.getViewName());
/* defaults - the viewer node has these options but not exposed for split view
* we could use the split to define an area of interest on one axis at least */
diff --git a/source/blender/compositor/nodes/COM_SunBeamsNode.cpp b/source/blender/compositor/nodes/COM_SunBeamsNode.cpp
index ed14acabf36..7cf3c90c786 100644
--- a/source/blender/compositor/nodes/COM_SunBeamsNode.cpp
+++ b/source/blender/compositor/nodes/COM_SunBeamsNode.cpp
@@ -27,7 +27,7 @@ SunBeamsNode::SunBeamsNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void SunBeamsNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void SunBeamsNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *inputSocket = this->getInputSocket(0);
NodeOutput *outputSocket = this->getOutputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_SwitchNode.cpp b/source/blender/compositor/nodes/COM_SwitchNode.cpp
index 10f0ee3821d..eb854983d4c 100644
--- a/source/blender/compositor/nodes/COM_SwitchNode.cpp
+++ b/source/blender/compositor/nodes/COM_SwitchNode.cpp
@@ -27,7 +27,7 @@ SwitchNode::SwitchNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void SwitchNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void SwitchNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
bool condition = this->getbNode()->custom1;
diff --git a/source/blender/compositor/nodes/COM_SwitchViewNode.cpp b/source/blender/compositor/nodes/COM_SwitchViewNode.cpp
new file mode 100644
index 00000000000..5a23b8b4d9e
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_SwitchViewNode.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor:
+ * Dalai Felinto
+ */
+
+#include "COM_SwitchViewNode.h"
+#include "BLI_listbase.h"
+
+SwitchViewNode::SwitchViewNode(bNode *editorNode) : Node(editorNode)
+{
+ /* pass */
+}
+
+void SwitchViewNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+{
+ NodeOperationOutput *result;
+ const char *viewName = context.getViewName();
+ bNode *bnode = this->getbNode();
+
+ /* get the internal index of the socket with a matching name */
+ int nr = BLI_findstringindex(&bnode->inputs, viewName, offsetof(bNodeSocket, name));
+ nr = max(nr, 0);
+
+ result = converter.addInputProxy(getInputSocket(nr), false);
+ converter.mapOutputSocket(getOutputSocket(0), result);
+}
diff --git a/source/blender/compositor/nodes/COM_SwitchViewNode.h b/source/blender/compositor/nodes/COM_SwitchViewNode.h
new file mode 100644
index 00000000000..6ab5145bed5
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_SwitchViewNode.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor:
+ * Dalai Felinto
+ */
+
+#ifndef _COM_SwitchViewNode_h_
+#define _COM_SwitchViewNode_h_
+
+#include "COM_Node.h"
+#include "COM_NodeOperation.h"
+#include "DNA_node_types.h"
+/**
+ * @brief SwitchViewNode
+ * @ingroup Node
+ */
+class SwitchViewNode : public Node {
+public:
+ SwitchViewNode(bNode *editorNode);
+ void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
+};
+#endif
diff --git a/source/blender/compositor/nodes/COM_TonemapNode.cpp b/source/blender/compositor/nodes/COM_TonemapNode.cpp
index 5ac73b9f9c2..961139d4855 100644
--- a/source/blender/compositor/nodes/COM_TonemapNode.cpp
+++ b/source/blender/compositor/nodes/COM_TonemapNode.cpp
@@ -29,7 +29,7 @@ TonemapNode::TonemapNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void TonemapNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void TonemapNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeTonemap *data = (NodeTonemap *)this->getbNode()->storage;
diff --git a/source/blender/compositor/nodes/COM_TransformNode.cpp b/source/blender/compositor/nodes/COM_TransformNode.cpp
index f1d5771bab3..148409a6427 100644
--- a/source/blender/compositor/nodes/COM_TransformNode.cpp
+++ b/source/blender/compositor/nodes/COM_TransformNode.cpp
@@ -33,7 +33,7 @@ TransformNode::TransformNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void TransformNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void TransformNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *imageInput = this->getInputSocket(0);
NodeInput *xInput = this->getInputSocket(1);
diff --git a/source/blender/compositor/nodes/COM_ValueNode.cpp b/source/blender/compositor/nodes/COM_ValueNode.cpp
index 62a312da67c..c75d9296807 100644
--- a/source/blender/compositor/nodes/COM_ValueNode.cpp
+++ b/source/blender/compositor/nodes/COM_ValueNode.cpp
@@ -29,7 +29,7 @@ ValueNode::ValueNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ValueNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ValueNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
SetValueOperation *operation = new SetValueOperation();
NodeOutput *output = this->getOutputSocket(0);
diff --git a/source/blender/compositor/nodes/COM_VectorCurveNode.cpp b/source/blender/compositor/nodes/COM_VectorCurveNode.cpp
index 197b2c8bd0c..7222a018fa0 100644
--- a/source/blender/compositor/nodes/COM_VectorCurveNode.cpp
+++ b/source/blender/compositor/nodes/COM_VectorCurveNode.cpp
@@ -29,7 +29,7 @@ VectorCurveNode::VectorCurveNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void VectorCurveNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void VectorCurveNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
VectorCurveOperation *operation = new VectorCurveOperation();
operation->setCurveMapping((CurveMapping *)this->getbNode()->storage);
diff --git a/source/blender/compositor/nodes/COM_ViewLevelsNode.cpp b/source/blender/compositor/nodes/COM_ViewLevelsNode.cpp
index 30f51794e8d..06f12ccc559 100644
--- a/source/blender/compositor/nodes/COM_ViewLevelsNode.cpp
+++ b/source/blender/compositor/nodes/COM_ViewLevelsNode.cpp
@@ -31,7 +31,7 @@ ViewLevelsNode::ViewLevelsNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
-void ViewLevelsNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void ViewLevelsNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
NodeInput *input = this->getInputSocket(0);
if (input->isLinked()) {
diff --git a/source/blender/compositor/nodes/COM_ViewerNode.cpp b/source/blender/compositor/nodes/COM_ViewerNode.cpp
index ff0b8fb1706..ab819ce6e30 100644
--- a/source/blender/compositor/nodes/COM_ViewerNode.cpp
+++ b/source/blender/compositor/nodes/COM_ViewerNode.cpp
@@ -22,6 +22,9 @@
#include "COM_ViewerNode.h"
#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BLI_listbase.h"
+#include "BKE_scene.h"
#include "COM_ViewerOperation.h"
#include "COM_ExecutionSystem.h"
@@ -51,6 +54,8 @@ void ViewerNode::convertToOperations(NodeConverter &converter, const CompositorC
viewerOperation->setCenterY(editorNode->custom4);
/* alpha socket gives either 1 or a custom alpha value if "use alpha" is enabled */
viewerOperation->setUseAlphaInput(ignore_alpha || alphaSocket->isLinked());
+ viewerOperation->setRenderData(context.getRenderData());
+ viewerOperation->setViewName(context.getViewName());
viewerOperation->setViewSettings(context.getViewSettings());
viewerOperation->setDisplaySettings(context.getDisplaySettings());
diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp b/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
index b25e2281467..2e60c2d3e42 100644
--- a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
+++ b/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
@@ -45,7 +45,7 @@ void AntiAliasOperation::initExecution()
NodeOperation::initMutex();
}
-void AntiAliasOperation::executePixel(float output[4], int x, int y, void *data)
+void AntiAliasOperation::executePixel(float output[4], int x, int y, void * /*data*/)
{
if (y < 0 || (unsigned int)y >= this->m_height || x < 0 || (unsigned int)x >= this->m_width) {
output[0] = 0.0f;
@@ -66,7 +66,7 @@ void AntiAliasOperation::deinitExecution()
NodeOperation::deinitMutex();
}
-bool AntiAliasOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool AntiAliasOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
rcti imageInput;
if (this->m_buffer) {
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp b/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
index d5aafc7c2ae..ce42de7a149 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
@@ -92,7 +92,7 @@ float *BlurBaseOperation::make_gausstab(float rad, int size)
}
#ifdef __SSE2__
-__m128 *BlurBaseOperation::convert_gausstab_sse(const float *gausstab, float rad, int size)
+__m128 *BlurBaseOperation::convert_gausstab_sse(const float *gausstab, int size)
{
int n = 2 * size + 1;
__m128 *gausstab_sse = (__m128 *) MEM_mallocN_aligned(sizeof(__m128) * n, 16, "gausstab sse");
@@ -133,6 +133,9 @@ float *BlurBaseOperation::make_dist_fac_inverse(float rad, int size, int falloff
case PROP_SHARP:
val = val * val;
break;
+ case PROP_INVSQUARE:
+ val = val * (2.0f - val);
+ break;
case PROP_LIN:
/* fall-through */
#ifndef NDEBUG
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.h b/source/blender/compositor/operations/COM_BlurBaseOperation.h
index e97dd4d766d..f9f37479c56 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.h
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.h
@@ -39,7 +39,7 @@ protected:
BlurBaseOperation(DataType data_type);
float *make_gausstab(float rad, int size);
#ifdef __SSE2__
- __m128 *convert_gausstab_sse(const float *gaustab, float rad, int size);
+ __m128 *convert_gausstab_sse(const float *gaustab, int size);
#endif
float *make_dist_fac_inverse(float rad, int size, int falloff);
diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp b/source/blender/compositor/operations/COM_BokehBlurOperation.cpp
index 22f6fc33a0d..189483708b5 100644
--- a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_BokehBlurOperation.cpp
@@ -45,7 +45,7 @@ BokehBlurOperation::BokehBlurOperation() : NodeOperation()
this->m_inputBoundingBoxReader = NULL;
}
-void *BokehBlurOperation::initializeTileData(rcti *rect)
+void *BokehBlurOperation::initializeTileData(rcti * /*rect*/)
{
lockMutex();
if (!this->m_sizeavailable) {
@@ -194,7 +194,7 @@ bool BokehBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBuffe
void BokehBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp)
+ list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel kernel = device->COM_clCreateKernel("bokehBlurKernel", NULL);
if (!this->m_sizeavailable) {
diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.cpp b/source/blender/compositor/operations/COM_BokehImageOperation.cpp
index 6617fc62ab8..18846f2a2c5 100644
--- a/source/blender/compositor/operations/COM_BokehImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_BokehImageOperation.cpp
@@ -85,7 +85,7 @@ float BokehImageOperation::isInsideBokeh(float distance, float x, float y)
}
return insideBokeh;
}
-void BokehImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void BokehImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
float shift = this->m_data->lensshift;
float shift2 = shift / 2.0f;
@@ -116,7 +116,7 @@ void BokehImageOperation::deinitExecution()
}
}
-void BokehImageOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+void BokehImageOperation::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
{
resolution[0] = COM_BLUR_BOKEH_PIXELS;
resolution[1] = COM_BLUR_BOKEH_PIXELS;
diff --git a/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp b/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp
index a2954a20e90..d26dcd17750 100644
--- a/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp
+++ b/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp
@@ -24,7 +24,9 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-
+extern "C" {
+#include "IMB_colormanagement.h"
+}
CalculateMeanOperation::CalculateMeanOperation() : NodeOperation()
{
@@ -42,7 +44,9 @@ void CalculateMeanOperation::initExecution()
NodeOperation::initMutex();
}
-void CalculateMeanOperation::executePixel(float output[4], int x, int y, void *data)
+void CalculateMeanOperation::executePixel(float output[4],
+ int /*x*/, int /*y*/,
+ void * /*data*/)
{
output[0] = this->m_result;
}
@@ -53,7 +57,7 @@ void CalculateMeanOperation::deinitExecution()
NodeOperation::deinitMutex();
}
-bool CalculateMeanOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool CalculateMeanOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
rcti imageInput;
if (this->m_iscalculated) {
@@ -96,7 +100,7 @@ void CalculateMeanOperation::calculateMean(MemoryBuffer *tile)
switch (this->m_setting) {
case 1:
{
- sum += rgb_to_bw(&buffer[offset]);
+ sum += IMB_colormanagement_get_luminance(&buffer[offset]);
break;
}
case 2:
diff --git a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp
index 0c67da2d552..6b238e53d7b 100644
--- a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp
+++ b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp
@@ -24,14 +24,18 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-
+extern "C" {
+#include "IMB_colormanagement.h"
+}
CalculateStandardDeviationOperation::CalculateStandardDeviationOperation() : CalculateMeanOperation()
{
/* pass */
}
-void CalculateStandardDeviationOperation::executePixel(float output[4], int x, int y, void *data)
+void CalculateStandardDeviationOperation::executePixel(float output[4],
+ int /*x*/, int /*y*/,
+ void * /*data*/)
{
output[0] = this->m_standardDeviation;
}
@@ -55,7 +59,7 @@ void *CalculateStandardDeviationOperation::initializeTileData(rcti *rect)
switch (this->m_setting) {
case 1: /* rgb combined */
{
- float value = rgb_to_bw(&buffer[offset]);
+ float value = IMB_colormanagement_get_luminance(&buffer[offset]);
sum += (value - mean) * (value - mean);
break;
}
diff --git a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp
index 19209951005..54e0fb41abf 100644
--- a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp
@@ -23,6 +23,10 @@
#include "COM_ColorCorrectionOperation.h"
#include "BLI_math.h"
+extern "C" {
+#include "IMB_colormanagement.h"
+}
+
ColorCorrectionOperation::ColorCorrectionOperation() : NodeOperation()
{
this->addInputSocket(COM_DT_COLOR);
@@ -90,7 +94,7 @@ void ColorCorrectionOperation::executePixelSampled(float output[4], float x, flo
lift += (levelShadows * this->m_data->shadows.lift) + (levelMidtones * this->m_data->midtones.lift) + (levelHighlights * this->m_data->highlights.lift);
float invgamma = 1.0f / gamma;
- float luma = rgb_to_luma_y(inputImageColor);
+ float luma = IMB_colormanagement_get_luminance(inputImageColor);
r = inputImageColor[0];
g = inputImageColor[1];
diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cpp b/source/blender/compositor/operations/COM_CompositorOperation.cpp
index e3438bcbd15..76f74c144f6 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.cpp
+++ b/source/blender/compositor/operations/COM_CompositorOperation.cpp
@@ -52,6 +52,7 @@ CompositorOperation::CompositorOperation() : NodeOperation()
this->m_active = false;
this->m_sceneName[0] = '\0';
+ this->m_viewName = NULL;
}
void CompositorOperation::initExecution()
@@ -81,14 +82,16 @@ void CompositorOperation::deinitExecution()
RenderResult *rr = RE_AcquireResultWrite(re);
if (rr) {
- if (rr->rectf != NULL) {
- MEM_freeN(rr->rectf);
+ RenderView *rv = RE_RenderViewGetByName(rr, this->m_viewName);
+
+ if (rv->rectf != NULL) {
+ MEM_freeN(rv->rectf);
}
- rr->rectf = this->m_outputBuffer;
- if (rr->rectz != NULL) {
- MEM_freeN(rr->rectz);
+ rv->rectf = this->m_outputBuffer;
+ if (rv->rectz != NULL) {
+ MEM_freeN(rv->rectz);
}
- rr->rectz = this->m_depthBuffer;
+ rv->rectz = this->m_depthBuffer;
}
else {
if (this->m_outputBuffer) {
@@ -125,7 +128,7 @@ void CompositorOperation::deinitExecution()
}
-void CompositorOperation::executeRegion(rcti *rect, unsigned int tileNumber)
+void CompositorOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
{
float color[8]; // 7 is enough
float *buffer = this->m_outputBuffer;
diff --git a/source/blender/compositor/operations/COM_CompositorOperation.h b/source/blender/compositor/operations/COM_CompositorOperation.h
index 771c32ffd12..e81ba520695 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.h
+++ b/source/blender/compositor/operations/COM_CompositorOperation.h
@@ -75,13 +75,19 @@ private:
* @brief operation is active for calculating final compo result
*/
bool m_active;
+
+ /**
+ * @brief View name, used for multiview
+ */
+ const char *m_viewName;
public:
CompositorOperation();
const bool isActiveCompositorOutput() const { return this->m_active; }
void executeRegion(rcti *rect, unsigned int tileNumber);
void setSceneName(const char *sceneName) { BLI_strncpy(this->m_sceneName, sceneName, sizeof(this->m_sceneName)); }
+ void setViewName(const char *viewName) { this->m_viewName = viewName; }
void setRenderData(const RenderData *rd) { this->m_rd = rd; }
- bool isOutputOperation(bool rendering) const { return this->isActiveCompositorOutput(); }
+ bool isOutputOperation(bool /*rendering*/) const { return this->isActiveCompositorOutput(); }
void initExecution();
void deinitExecution();
const CompositorPriority getRenderPriority() const { return COM_PRIORITY_MEDIUM; }
diff --git a/source/blender/compositor/operations/COM_ConvertOperation.cpp b/source/blender/compositor/operations/COM_ConvertOperation.cpp
index 977586acb60..8b8e8408208 100644
--- a/source/blender/compositor/operations/COM_ConvertOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvertOperation.cpp
@@ -22,6 +22,9 @@
#include "COM_ConvertOperation.h"
+extern "C" {
+#include "IMB_colormanagement.h"
+}
ConvertBaseOperation::ConvertBaseOperation()
{
@@ -84,7 +87,7 @@ void ConvertColorToBWOperation::executePixelSampled(float output[4], float x, fl
{
float inputColor[4];
this->m_inputOperation->readSampled(inputColor, x, y, sampler);
- output[0] = rgb_to_bw(inputColor);
+ output[0] = IMB_colormanagement_get_luminance(inputColor);
}
diff --git a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp
index 657126d458c..e1ada9a8c39 100644
--- a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp
@@ -28,7 +28,7 @@ ConvolutionEdgeFilterOperation::ConvolutionEdgeFilterOperation() : ConvolutionFi
/* pass */
}
-void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y, void *data)
+void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y, void * /*data*/)
{
float in1[4], in2[4], res1[4] = {0.0}, res2[4] = {0.0};
diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp
index 553a9827ffa..699db11d56e 100644
--- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp
@@ -69,7 +69,7 @@ void ConvolutionFilterOperation::deinitExecution()
}
-void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, void *data)
+void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, void * /*data*/)
{
float in1[4];
float in2[4];
diff --git a/source/blender/compositor/operations/COM_CropOperation.cpp b/source/blender/compositor/operations/COM_CropOperation.cpp
index 9bcc6fb2541..e5427589fce 100644
--- a/source/blender/compositor/operations/COM_CropOperation.cpp
+++ b/source/blender/compositor/operations/COM_CropOperation.cpp
@@ -36,27 +36,28 @@ void CropBaseOperation::updateArea()
SocketReader *inputReference = this->getInputSocketReader(0);
float width = inputReference->getWidth();
float height = inputReference->getHeight();
+ NodeTwoXYs local_settings = *this->m_settings;
if (width > 0.0f && height > 0.0f) {
if (this->m_relative) {
- this->m_settings->x1 = width * this->m_settings->fac_x1;
- this->m_settings->x2 = width * this->m_settings->fac_x2;
- this->m_settings->y1 = height * this->m_settings->fac_y1;
- this->m_settings->y2 = height * this->m_settings->fac_y2;
+ local_settings.x1 = width * local_settings.fac_x1;
+ local_settings.x2 = width * local_settings.fac_x2;
+ local_settings.y1 = height * local_settings.fac_y1;
+ local_settings.y2 = height * local_settings.fac_y2;
}
- if (width <= this->m_settings->x1 + 1)
- this->m_settings->x1 = width - 1;
- if (height <= this->m_settings->y1 + 1)
- this->m_settings->y1 = height - 1;
- if (width <= this->m_settings->x2 + 1)
- this->m_settings->x2 = width - 1;
- if (height <= this->m_settings->y2 + 1)
- this->m_settings->y2 = height - 1;
+ if (width <= local_settings.x1 + 1)
+ local_settings.x1 = width - 1;
+ if (height <= local_settings.y1 + 1)
+ local_settings.y1 = height - 1;
+ if (width <= local_settings.x2 + 1)
+ local_settings.x2 = width - 1;
+ if (height <= local_settings.y2 + 1)
+ local_settings.y2 = height - 1;
- this->m_xmax = max(this->m_settings->x1, this->m_settings->x2) + 1;
- this->m_xmin = min(this->m_settings->x1, this->m_settings->x2);
- this->m_ymax = max(this->m_settings->y1, this->m_settings->y2) + 1;
- this->m_ymin = min(this->m_settings->y1, this->m_settings->y2);
+ this->m_xmax = max(local_settings.x1, local_settings.x2) + 1;
+ this->m_xmin = min(local_settings.x1, local_settings.x2);
+ this->m_ymax = max(local_settings.y1, local_settings.y2) + 1;
+ this->m_ymin = min(local_settings.y1, local_settings.y2);
}
else {
this->m_xmax = 0;
diff --git a/source/blender/compositor/operations/COM_DespeckleOperation.cpp b/source/blender/compositor/operations/COM_DespeckleOperation.cpp
index 186c17845f3..1a827aae67e 100644
--- a/source/blender/compositor/operations/COM_DespeckleOperation.cpp
+++ b/source/blender/compositor/operations/COM_DespeckleOperation.cpp
@@ -52,7 +52,7 @@ BLI_INLINE int color_diff(const float a[3], const float b[3], const float thresh
(fabsf(a[2] - b[2]) > threshold));
}
-void DespeckleOperation::executePixel(float output[4], int x, int y, void *data)
+void DespeckleOperation::executePixel(float output[4], int x, int y, void * /*data*/)
{
float w = 0.0f;
float color_org[4];
diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
index 6d15ef3395b..fc3ec7dd11a 100644
--- a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
+++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
@@ -56,7 +56,7 @@ void DilateErodeThresholdOperation::initExecution()
}
}
-void *DilateErodeThresholdOperation::initializeTileData(rcti *rect)
+void *DilateErodeThresholdOperation::initializeTileData(rcti * /*rect*/)
{
void *buffer = this->m_inputProgram->initializeTileData(NULL);
return buffer;
@@ -180,7 +180,7 @@ void DilateDistanceOperation::initExecution()
}
}
-void *DilateDistanceOperation::initializeTileData(rcti *rect)
+void *DilateDistanceOperation::initializeTileData(rcti * /*rect*/)
{
void *buffer = this->m_inputProgram->initializeTileData(NULL);
return buffer;
@@ -238,7 +238,7 @@ bool DilateDistanceOperation::determineDependingAreaOfInterest(rcti *input, Read
void DilateDistanceOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp)
+ list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel dilateKernel = device->COM_clCreateKernel("dilateKernel", NULL);
@@ -295,7 +295,7 @@ void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *d
void ErodeDistanceOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp)
+ list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel erodeKernel = device->COM_clCreateKernel("erodeKernel", NULL);
@@ -446,7 +446,7 @@ void DilateStepOperation::deinitExecution()
this->m_inputProgram = NULL;
}
-void DilateStepOperation::deinitializeTileData(rcti *rect, void *data)
+void DilateStepOperation::deinitializeTileData(rcti * /*rect*/, void *data)
{
tile_info *tile = (tile_info *)data;
MEM_freeN(tile->buffer);
diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
index 962a95ebd05..732e731fadf 100644
--- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
@@ -66,7 +66,7 @@ void DirectionalBlurOperation::initExecution()
}
-void DirectionalBlurOperation::executePixel(float output[4], int x, int y, void *data)
+void DirectionalBlurOperation::executePixel(float output[4], int x, int y, void * /*data*/)
{
const int iterations = pow(2.0f, this->m_data->iter);
float col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
@@ -104,7 +104,7 @@ void DirectionalBlurOperation::executePixel(float output[4], int x, int y, void
void DirectionalBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp)
+ list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel directionalBlurKernel = device->COM_clCreateKernel("directionalBlurKernel", NULL);
@@ -132,7 +132,7 @@ void DirectionalBlurOperation::deinitExecution()
this->m_inputProgram = NULL;
}
-bool DirectionalBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool DirectionalBlurOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
rcti newInput;
diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.cpp b/source/blender/compositor/operations/COM_DisplaceOperation.cpp
index 7dacc3239c5..6dfef8a0a11 100644
--- a/source/blender/compositor/operations/COM_DisplaceOperation.cpp
+++ b/source/blender/compositor/operations/COM_DisplaceOperation.cpp
@@ -49,15 +49,19 @@ void DisplaceOperation::initExecution()
this->m_height_x4 = this->getHeight() * 4;
}
-void DisplaceOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void DisplaceOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
float xy[2] = { x, y };
float uv[2], deriv[2][2];
pixelTransform(xy, uv, deriv);
-
- /* EWA filtering (without nearest it gets blurry with NO distortion) */
- this->m_inputColorProgram->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1], COM_PS_BILINEAR);
+ if (is_zero_v2(deriv[0]) && is_zero_v2(deriv[1])) {
+ this->m_inputColorProgram->readSampled(output, uv[0], uv[1], COM_PS_BILINEAR);
+ }
+ else {
+ /* EWA filtering (without nearest it gets blurry with NO distortion) */
+ this->m_inputColorProgram->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1], COM_PS_BILINEAR);
+ }
}
bool DisplaceOperation::read_displacement(float x, float y, float xscale, float yscale, const float origin[2], float &r_u, float &r_v)
diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
index 234a61a4c41..76afedf4b2a 100644
--- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
@@ -1237,7 +1237,7 @@ DoubleEdgeMaskOperation::DoubleEdgeMaskOperation() : NodeOperation()
this->setComplex(true);
}
-bool DoubleEdgeMaskOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool DoubleEdgeMaskOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
if (this->m_cachedInstance == NULL) {
rcti newInput;
diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
index 08f520e4271..968319b3f46 100644
--- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
@@ -37,7 +37,7 @@ void FastGaussianBlurOperation::executePixel(float output[4], int x, int y, void
newData->read(output, x, y);
}
-bool FastGaussianBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool FastGaussianBlurOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
rcti newInput;
rcti sizeInput;
@@ -257,7 +257,7 @@ void FastGaussianBlurValueOperation::executePixel(float output[4], int x, int y,
newData->read(output, x, y);
}
-bool FastGaussianBlurValueOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool FastGaussianBlurValueOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
rcti newInput;
diff --git a/source/blender/compositor/operations/COM_FlipOperation.cpp b/source/blender/compositor/operations/COM_FlipOperation.cpp
index 3de2ae9dabc..7ff7d694fa8 100644
--- a/source/blender/compositor/operations/COM_FlipOperation.cpp
+++ b/source/blender/compositor/operations/COM_FlipOperation.cpp
@@ -44,8 +44,8 @@ void FlipOperation::deinitExecution()
void FlipOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
- float nx = this->m_flipX ? this->getWidth() - 1 - x : x;
- float ny = this->m_flipY ? this->getHeight() - 1 - y : y;
+ float nx = this->m_flipX ? ((int)this->getWidth() - 1) - x : x;
+ float ny = this->m_flipY ? ((int)this->getHeight() - 1) - y : y;
this->m_inputOperation->readSampled(output, nx, ny, sampler);
}
@@ -55,16 +55,18 @@ bool FlipOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOper
rcti newInput;
if (this->m_flipX) {
- newInput.xmax = (this->getWidth() - 1 - input->xmin) + 1;
- newInput.xmin = (this->getWidth() - 1 - input->xmax) - 1;
+ const int w = (int)this->getWidth() - 1;
+ newInput.xmax = (w - input->xmin) + 1;
+ newInput.xmin = (w - input->xmax) - 1;
}
else {
newInput.xmin = input->xmin;
newInput.xmax = input->xmax;
}
if (this->m_flipY) {
- newInput.ymax = (this->getHeight() - 1 - input->ymin) + 1;
- newInput.ymin = (this->getHeight() - 1 - input->ymax) - 1;
+ const int h = (int)this->getHeight() - 1;
+ newInput.ymax = (h - input->ymin) + 1;
+ newInput.ymin = (h - input->ymax) - 1;
}
else {
newInput.ymin = input->ymin;
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp
index dde57ab640f..cbe41076b2a 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp
@@ -36,7 +36,7 @@ GaussianAlphaXBlurOperation::GaussianAlphaXBlurOperation() : BlurBaseOperation(C
this->m_falloff = -1; /* intentionally invalid, so we can detect uninitialized values */
}
-void *GaussianAlphaXBlurOperation::initializeTileData(rcti *rect)
+void *GaussianAlphaXBlurOperation::initializeTileData(rcti * /*rect*/)
{
lockMutex();
if (!this->m_sizeavailable) {
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp
index bb5b3c044af..30563e8cc45 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp
@@ -36,7 +36,7 @@ GaussianAlphaYBlurOperation::GaussianAlphaYBlurOperation() : BlurBaseOperation(C
this->m_falloff = -1; /* intentionally invalid, so we can detect uninitialized values */
}
-void *GaussianAlphaYBlurOperation::initializeTileData(rcti *rect)
+void *GaussianAlphaYBlurOperation::initializeTileData(rcti * /*rect*/)
{
lockMutex();
if (!this->m_sizeavailable) {
diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
index dbad51c4329..37d59229e50 100644
--- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
@@ -32,7 +32,7 @@ GaussianBokehBlurOperation::GaussianBokehBlurOperation() : BlurBaseOperation(COM
this->m_gausstab = NULL;
}
-void *GaussianBokehBlurOperation::initializeTileData(rcti *rect)
+void *GaussianBokehBlurOperation::initializeTileData(rcti * /*rect*/)
{
lockMutex();
if (!this->m_sizeavailable) {
@@ -205,7 +205,7 @@ GaussianBlurReferenceOperation::GaussianBlurReferenceOperation() : BlurBaseOpera
this->m_maintabs = NULL;
}
-void *GaussianBlurReferenceOperation::initializeTileData(rcti *rect)
+void *GaussianBlurReferenceOperation::initializeTileData(rcti * /*rect*/)
{
void *buffer = getInputOperation(0)->initializeTileData(NULL);
return buffer;
diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp
index 0838d281de7..29ed4334412 100644
--- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp
@@ -38,7 +38,7 @@ GaussianXBlurOperation::GaussianXBlurOperation() : BlurBaseOperation(COM_DT_COLO
this->m_filtersize = 0;
}
-void *GaussianXBlurOperation::initializeTileData(rcti *rect)
+void *GaussianXBlurOperation::initializeTileData(rcti * /*rect*/)
{
lockMutex();
if (!this->m_sizeavailable) {
@@ -63,7 +63,6 @@ void GaussianXBlurOperation::initExecution()
this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize);
#ifdef __SSE2__
this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab,
- rad,
m_filtersize);
#endif
}
@@ -79,7 +78,6 @@ void GaussianXBlurOperation::updateGauss()
this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize);
#ifdef __SSE2__
this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab,
- rad,
m_filtersize);
#endif
}
@@ -128,7 +126,7 @@ void GaussianXBlurOperation::executePixel(float output[4], int x, int y, void *d
void GaussianXBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp)
+ list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel gaussianXBlurOperationKernel = device->COM_clCreateKernel("gaussianXBlurOperationKernel", NULL);
cl_int filter_size = this->m_filtersize;
diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp
index 6172f954087..4b55333c08c 100644
--- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp
@@ -38,7 +38,7 @@ GaussianYBlurOperation::GaussianYBlurOperation() : BlurBaseOperation(COM_DT_COLO
this->m_filtersize = 0;
}
-void *GaussianYBlurOperation::initializeTileData(rcti *rect)
+void *GaussianYBlurOperation::initializeTileData(rcti * /*rect*/)
{
lockMutex();
if (!this->m_sizeavailable) {
@@ -62,7 +62,6 @@ void GaussianYBlurOperation::initExecution()
this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize);
#ifdef __SSE2__
this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab,
- rad,
m_filtersize);
#endif
}
@@ -78,7 +77,6 @@ void GaussianYBlurOperation::updateGauss()
this->m_gausstab = BlurBaseOperation::make_gausstab(rad, m_filtersize);
#ifdef __SSE2__
this->m_gausstab_sse = BlurBaseOperation::convert_gausstab_sse(this->m_gausstab,
- rad,
m_filtersize);
#endif
}
@@ -130,7 +128,7 @@ void GaussianYBlurOperation::executePixel(float output[4], int x, int y, void *d
void GaussianYBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp)
+ list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel gaussianYBlurOperationKernel = device->COM_clCreateKernel("gaussianYBlurOperationKernel", NULL);
cl_int filter_size = this->m_filtersize;
diff --git a/source/blender/compositor/operations/COM_GlareBaseOperation.cpp b/source/blender/compositor/operations/COM_GlareBaseOperation.cpp
index 98919f1b161..1acbd2ae090 100644
--- a/source/blender/compositor/operations/COM_GlareBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareBaseOperation.cpp
@@ -55,7 +55,7 @@ MemoryBuffer *GlareBaseOperation::createMemoryBuffer(rcti *rect2)
return result;
}
-bool GlareBaseOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool GlareBaseOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
if (isCached()) {
return false;
diff --git a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp b/source/blender/compositor/operations/COM_GlareGhostOperation.cpp
index 69b5bd7d6bf..eea6588a9a6 100644
--- a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareGhostOperation.cpp
@@ -65,7 +65,7 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No
if (isBreaked()) breaked = true;
if (!breaked) FastGaussianBlurOperation::IIR_gauss(tbuf2, s2, 2, 3);
- if (settings->iter & 1) ofs = 0.5f; else ofs = 0.f;
+ ofs = (settings->iter & 1) ? 0.5f : 0.0f;
for (x = 0; x < (settings->iter * 4); x++) {
y = x & 3;
cm[x][0] = cm[x][1] = cm[x][2] = 1;
diff --git a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp b/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp
index 78e1e80cafc..d2bd7cbeeab 100644
--- a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp
@@ -23,6 +23,10 @@
#include "COM_GlareThresholdOperation.h"
#include "BLI_math.h"
+extern "C" {
+#include "IMB_colormanagement.h"
+}
+
GlareThresholdOperation::GlareThresholdOperation() : NodeOperation()
{
this->addInputSocket(COM_DT_COLOR, COM_SC_FIT);
@@ -47,7 +51,7 @@ void GlareThresholdOperation::executePixelSampled(float output[4], float x, floa
const float threshold = this->m_settings->threshold;
this->m_inputProgram->readSampled(output, x, y, sampler);
- if (rgb_to_luma_y(output) >= threshold) {
+ if (IMB_colormanagement_get_luminance(output) >= threshold) {
output[0] -= threshold, output[1] -= threshold, output[2] -= threshold;
output[0] = max(output[0], 0.0f);
output[1] = max(output[1], 0.0f);
diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cpp
index 2733c483146..c55366ab370 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_ImageOperation.cpp
@@ -25,6 +25,7 @@
#include "BLI_listbase.h"
#include "DNA_image_types.h"
#include "BKE_image.h"
+#include "BKE_scene.h"
#include "BLI_math.h"
extern "C" {
@@ -48,6 +49,8 @@ BaseImageOperation::BaseImageOperation() : NodeOperation()
this->m_framenumber = 0;
this->m_depthBuffer = NULL;
this->m_numberOfChannels = 0;
+ this->m_rd = NULL;
+ this->m_viewName = NULL;
}
ImageOperation::ImageOperation() : BaseImageOperation()
{
@@ -65,8 +68,16 @@ ImageDepthOperation::ImageDepthOperation() : BaseImageOperation()
ImBuf *BaseImageOperation::getImBuf()
{
ImBuf *ibuf;
-
- ibuf = BKE_image_acquire_ibuf(this->m_image, this->m_imageUser, NULL);
+ ImageUser iuser = *this->m_imageUser;
+
+ if (this->m_image == NULL)
+ return NULL;
+
+ /* local changes to the original ImageUser */
+ if (BKE_image_is_multilayer(this->m_image) == false)
+ iuser.multi_index = BKE_scene_multiview_view_id_get(this->m_rd, this->m_viewName);
+
+ ibuf = BKE_image_acquire_ibuf(this->m_image, &iuser, NULL);
if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
BKE_image_release_ibuf(this->m_image, ibuf, NULL);
return NULL;
@@ -96,7 +107,7 @@ void BaseImageOperation::deinitExecution()
BKE_image_release_ibuf(this->m_image, this->m_buffer, NULL);
}
-void BaseImageOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+void BaseImageOperation::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
{
ImBuf *stackbuf = getImBuf();
@@ -170,7 +181,7 @@ void ImageAlphaOperation::executePixelSampled(float output[4], float x, float y,
}
}
-void ImageDepthOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void ImageDepthOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
if (this->m_depthBuffer == NULL) {
output[0] = 0.0f;
diff --git a/source/blender/compositor/operations/COM_ImageOperation.h b/source/blender/compositor/operations/COM_ImageOperation.h
index 206f1509f60..75222559810 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.h
+++ b/source/blender/compositor/operations/COM_ImageOperation.h
@@ -49,7 +49,9 @@ protected:
int m_imagewidth;
int m_framenumber;
int m_numberOfChannels;
-
+ const RenderData *m_rd;
+ const char *m_viewName;
+
BaseImageOperation();
/**
* Determine the output resolution. The resolution is retrieved from the Renderer
@@ -64,7 +66,8 @@ public:
void deinitExecution();
void setImage(Image *image) { this->m_image = image; }
void setImageUser(ImageUser *imageuser) { this->m_imageUser = imageuser; }
-
+ void setRenderData(const RenderData *rd) { this->m_rd = rd; }
+ void setViewName(const char *viewName) { this->m_viewName = viewName; }
void setFramenumber(int framenumber) { this->m_framenumber = framenumber; }
};
class ImageOperation : public BaseImageOperation {
diff --git a/source/blender/compositor/operations/COM_InpaintOperation.cpp b/source/blender/compositor/operations/COM_InpaintOperation.cpp
index 18611c051d3..43b7b30319d 100644
--- a/source/blender/compositor/operations/COM_InpaintOperation.cpp
+++ b/source/blender/compositor/operations/COM_InpaintOperation.cpp
@@ -241,7 +241,7 @@ void *InpaintSimpleOperation::initializeTileData(rcti *rect)
return this->m_cached_buffer;
}
-void InpaintSimpleOperation::executePixel(float output[4], int x, int y, void *data)
+void InpaintSimpleOperation::executePixel(float output[4], int x, int y, void * /*data*/)
{
this->clamp_xy(x, y);
copy_v4_v4(output, this->get_pixel(x, y));
@@ -268,7 +268,7 @@ void InpaintSimpleOperation::deinitExecution()
this->m_cached_buffer_ready = false;
}
-bool InpaintSimpleOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool InpaintSimpleOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
if (this->m_cached_buffer_ready) {
return false;
diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp b/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp
index 1633d2a2f1d..dd87578ea78 100644
--- a/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp
@@ -267,7 +267,7 @@ void *KeyingScreenOperation::initializeTileData(rcti *rect)
return tile_data;
}
-void KeyingScreenOperation::deinitializeTileData(rcti *rect, void *data)
+void KeyingScreenOperation::deinitializeTileData(rcti * /*rect*/, void *data)
{
TileData *tile_data = (TileData *) data;
@@ -278,7 +278,7 @@ void KeyingScreenOperation::deinitializeTileData(rcti *rect, void *data)
MEM_freeN(tile_data);
}
-void KeyingScreenOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+void KeyingScreenOperation::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
{
resolution[0] = 0;
resolution[1] = 0;
diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cpp b/source/blender/compositor/operations/COM_MapUVOperation.cpp
index bb8fe825c68..ffa48ce3956 100644
--- a/source/blender/compositor/operations/COM_MapUVOperation.cpp
+++ b/source/blender/compositor/operations/COM_MapUVOperation.cpp
@@ -41,7 +41,7 @@ void MapUVOperation::initExecution()
this->m_inputUVProgram = this->getInputSocketReader(1);
}
-void MapUVOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void MapUVOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
float xy[2] = { x, y };
float uv[2], deriv[2][2], alpha;
diff --git a/source/blender/compositor/operations/COM_MaskOperation.cpp b/source/blender/compositor/operations/COM_MaskOperation.cpp
index 8c8ba93327d..220b4e908a6 100644
--- a/source/blender/compositor/operations/COM_MaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_MaskOperation.cpp
@@ -1,4 +1,5 @@
/*
+
* Copyright 2012, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
@@ -127,7 +128,7 @@ void MaskOperation::determineResolution(unsigned int resolution[2], unsigned int
}
}
-void MaskOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void MaskOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
const float xy[2] = {
(x * this->m_maskWidthInv) + this->m_mask_px_ofs[0],
diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
index 447ca1bb4f6..040a0315d69 100644
--- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
@@ -33,7 +33,9 @@ MovieClipAttributeOperation::MovieClipAttributeOperation() : NodeOperation()
this->m_attribute = MCA_X;
}
-void MovieClipAttributeOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void MovieClipAttributeOperation::executePixelSampled(float output[4],
+ float /*x*/, float /*y*/,
+ PixelSampler /*sampler*/)
{
if (!this->m_valueSet) {
float loc[2], scale, angle;
diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.cpp b/source/blender/compositor/operations/COM_MovieClipOperation.cpp
index 9a184ae1216..1e4821f0cd3 100644
--- a/source/blender/compositor/operations/COM_MovieClipOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieClipOperation.cpp
@@ -71,7 +71,7 @@ void MovieClipBaseOperation::deinitExecution()
}
}
-void MovieClipBaseOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+void MovieClipBaseOperation::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
{
resolution[0] = 0;
resolution[1] = 0;
@@ -124,9 +124,7 @@ MovieClipAlphaOperation::MovieClipAlphaOperation() : MovieClipBaseOperation()
void MovieClipAlphaOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
- MovieClipBaseOperation::executePixelSampled(output, x, y, sampler);
- output[0] = output[3];
- output[1] = 0.0f;
- output[2] = 0.0f;
- output[3] = 0.0f;
+ float result[4];
+ MovieClipBaseOperation::executePixelSampled(result, x, y, sampler);
+ output[0] = result[3];
}
diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp b/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
index 50fabb09dbb..4f34d7fb150 100644
--- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
@@ -121,7 +121,7 @@ void MovieDistortionOperation::deinitExecution()
}
-void MovieDistortionOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void MovieDistortionOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
if (this->m_cache != NULL) {
diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
index 23fba5a7999..00be3b1cdde 100644
--- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
@@ -27,18 +27,27 @@ extern "C" {
# include "IMB_imbuf_types.h"
}
-MultilayerBaseOperation::MultilayerBaseOperation(int passindex) : BaseImageOperation()
+MultilayerBaseOperation::MultilayerBaseOperation(int passtype, int view) : BaseImageOperation()
{
- this->m_passId = passindex;
+ this->m_passtype = passtype;
+ this->m_view = view;
}
+
ImBuf *MultilayerBaseOperation::getImBuf()
{
- RenderPass *rpass = (RenderPass *)BLI_findlink(&this->m_renderlayer->passes, this->m_passId);
- if (rpass) {
- this->m_imageUser->pass = m_passId;
- BKE_image_multilayer_index(this->m_image->rr, this->m_imageUser);
- return BaseImageOperation::getImBuf();
+ /* temporarily changes the view to get the right ImBuf */
+ int view = this->m_imageUser->view;
+
+ this->m_imageUser->view = this->m_view;
+ this->m_imageUser->passtype = this->m_passtype;
+
+ if (BKE_image_multilayer_index(this->m_image->rr, this->m_imageUser)) {
+ ImBuf *ibuf = BaseImageOperation::getImBuf();
+ this->m_imageUser->view = view;
+ return ibuf;
}
+
+ this->m_imageUser->view = view;
return NULL;
}
@@ -74,7 +83,7 @@ void MultilayerColorOperation::executePixelSampled(float output[4], float x, flo
}
}
-void MultilayerValueOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void MultilayerValueOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
if (this->m_imageFloatBuffer == NULL) {
output[0] = 0.0f;
@@ -91,7 +100,7 @@ void MultilayerValueOperation::executePixelSampled(float output[4], float x, flo
}
}
-void MultilayerVectorOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void MultilayerVectorOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
if (this->m_imageFloatBuffer == NULL) {
output[0] = 0.0f;
diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.h b/source/blender/compositor/operations/COM_MultilayerImageOperation.h
index 37bee1b6a8c..2e140577d74 100644
--- a/source/blender/compositor/operations/COM_MultilayerImageOperation.h
+++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.h
@@ -29,7 +29,8 @@
class MultilayerBaseOperation : public BaseImageOperation {
private:
- int m_passId;
+ int m_passtype;
+ int m_view;
RenderLayer *m_renderlayer;
protected:
ImBuf *getImBuf();
@@ -37,13 +38,13 @@ public:
/**
* Constructor
*/
- MultilayerBaseOperation(int passindex);
+ MultilayerBaseOperation(int passtype, int view);
void setRenderLayer(RenderLayer *renderlayer) { this->m_renderlayer = renderlayer; }
};
class MultilayerColorOperation : public MultilayerBaseOperation {
public:
- MultilayerColorOperation(int passindex) : MultilayerBaseOperation(passindex) {
+ MultilayerColorOperation(int passtype, int view) : MultilayerBaseOperation(passtype, view) {
this->addOutputSocket(COM_DT_COLOR);
}
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
@@ -51,7 +52,7 @@ public:
class MultilayerValueOperation : public MultilayerBaseOperation {
public:
- MultilayerValueOperation(int passindex) : MultilayerBaseOperation(passindex) {
+ MultilayerValueOperation(int passtype, int view) : MultilayerBaseOperation(passtype, view) {
this->addOutputSocket(COM_DT_VALUE);
}
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
@@ -59,7 +60,7 @@ public:
class MultilayerVectorOperation : public MultilayerBaseOperation {
public:
- MultilayerVectorOperation(int passindex) : MultilayerBaseOperation(passindex) {
+ MultilayerVectorOperation(int passtype, int view) : MultilayerBaseOperation(passtype, view) {
this->addOutputSocket(COM_DT_VECTOR);
}
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
diff --git a/source/blender/compositor/operations/COM_NormalizeOperation.cpp b/source/blender/compositor/operations/COM_NormalizeOperation.cpp
index e0b5893ffbb..504470f1a7e 100644
--- a/source/blender/compositor/operations/COM_NormalizeOperation.cpp
+++ b/source/blender/compositor/operations/COM_NormalizeOperation.cpp
@@ -60,7 +60,7 @@ void NormalizeOperation::deinitExecution()
NodeOperation::deinitMutex();
}
-bool NormalizeOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool NormalizeOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
rcti imageInput;
if (this->m_cachedInstance) return false;
@@ -118,7 +118,7 @@ void *NormalizeOperation::initializeTileData(rcti *rect)
return this->m_cachedInstance;
}
-void NormalizeOperation::deinitializeTileData(rcti *rect, void *data)
+void NormalizeOperation::deinitializeTileData(rcti * /*rect*/, void * /*data*/)
{
/* pass */
}
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
new file mode 100644
index 00000000000..e89af9cc15b
--- /dev/null
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
@@ -0,0 +1,317 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor:
+ * Jeroen Bakker
+ * Monique Dewanchand
+ * Lukas Tönne
+ * Dalai Felinto
+ */
+
+#include "COM_OutputFileOperation.h"
+#include "COM_OutputFileMultiViewOperation.h"
+
+#include <string.h>
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BKE_image.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+
+#include "DNA_color_types.h"
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "IMB_imbuf.h"
+#include "IMB_colormanagement.h"
+#include "IMB_imbuf_types.h"
+}
+
+/************************************ OpenEXR Singlelayer Multiview *****************************************/
+
+OutputOpenExrSingleLayerMultiViewOperation::OutputOpenExrSingleLayerMultiViewOperation(
+ const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path,
+ const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
+ const char *viewName)
+ : OutputSingleLayerOperation(rd, tree, datatype, format, path, viewSettings, displaySettings, viewName)
+{
+}
+
+void *OutputOpenExrSingleLayerMultiViewOperation::get_handle(const char *filename)
+{
+ size_t width = this->getWidth();
+ size_t height = this->getHeight();
+ SceneRenderView *srv;
+
+ if (width != 0 && height != 0) {
+ void *exrhandle;
+
+ exrhandle = IMB_exr_get_handle_name(filename);
+
+ if (!BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName))
+ return exrhandle;
+
+ IMB_exr_clear_channels(exrhandle);
+
+ for (srv = (SceneRenderView *)this->m_rd->views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(this->m_rd, srv) == false)
+ continue;
+
+ IMB_exr_add_view(exrhandle, srv->name);
+ add_exr_channels(exrhandle, NULL, this->m_datatype, srv->name, width, NULL);
+ }
+
+ BLI_make_existing_file(filename);
+
+ /* prepare the file with all the channels */
+
+ if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_format->exr_codec, NULL) == 0) {
+ printf("Error Writing Singlelayer Multiview Openexr\n");
+ IMB_exr_close(exrhandle);
+ }
+ else {
+ IMB_exr_clear_channels(exrhandle);
+ return exrhandle;
+ }
+ }
+ return NULL;
+}
+
+void OutputOpenExrSingleLayerMultiViewOperation::deinitExecution()
+{
+ unsigned int width = this->getWidth();
+ unsigned int height = this->getHeight();
+
+ if (width != 0 && height != 0) {
+ void *exrhandle;
+ Main *bmain = G.main; /* TODO, have this passed along */
+ char filename[FILE_MAX];
+
+ BKE_image_path_from_imtype(
+ filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_OPENEXR,
+ (this->m_rd->scemode & R_EXTENSION) != 0, true, NULL);
+
+ exrhandle = this->get_handle(filename);
+ add_exr_channels(exrhandle, NULL, this->m_datatype, this->m_viewName, width, this->m_outputBuffer);
+
+ /* memory can only be freed after we write all views to the file */
+ this->m_outputBuffer = NULL;
+ this->m_imageInput = NULL;
+
+ /* ready to close the file */
+ if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) {
+ IMB_exr_write_channels(exrhandle);
+
+ /* free buffer memory for all the views */
+ free_exr_channels(exrhandle, this->m_rd, NULL, this->m_datatype);
+
+ /* remove exr handle and data */
+ IMB_exr_close(exrhandle);
+ }
+ }
+}
+
+/************************************ OpenEXR Multilayer Multiview *****************************************/
+
+OutputOpenExrMultiLayerMultiViewOperation::OutputOpenExrMultiLayerMultiViewOperation(
+ const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec, const char *viewName)
+ : OutputOpenExrMultiLayerOperation(rd, tree, path, exr_codec, viewName)
+{
+}
+
+void *OutputOpenExrMultiLayerMultiViewOperation::get_handle(const char *filename)
+{
+ unsigned int width = this->getWidth();
+ unsigned int height = this->getHeight();
+
+ if (width != 0 && height != 0) {
+
+ void *exrhandle;
+ SceneRenderView *srv;
+
+ /* get a new global handle */
+ exrhandle = IMB_exr_get_handle_name(filename);
+
+ if (!BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName))
+ return exrhandle;
+
+ IMB_exr_clear_channels(exrhandle);
+
+ /* check renderdata for amount of views */
+ for (srv = (SceneRenderView *) this->m_rd->views.first; srv; srv = srv->next) {
+
+ if (BKE_scene_multiview_is_render_view_active(this->m_rd, srv) == false)
+ continue;
+
+ IMB_exr_add_view(exrhandle, srv->name);
+
+ for (unsigned int i = 0; i < this->m_layers.size(); ++i)
+ add_exr_channels(exrhandle, this->m_layers[i].name, this->m_layers[i].datatype, srv->name, width, NULL);
+ }
+
+ BLI_make_existing_file(filename);
+
+ /* prepare the file with all the channels for the header */
+ if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec, NULL) == 0) {
+ printf("Error Writing Multilayer Multiview Openexr\n");
+ IMB_exr_close(exrhandle);
+ }
+ else {
+ IMB_exr_clear_channels(exrhandle);
+ return exrhandle;
+ }
+ }
+ return NULL;
+}
+
+void OutputOpenExrMultiLayerMultiViewOperation::deinitExecution()
+{
+ unsigned int width = this->getWidth();
+ unsigned int height = this->getHeight();
+
+ if (width != 0 && height != 0) {
+ void *exrhandle;
+ Main *bmain = G.main; /* TODO, have this passed along */
+ char filename[FILE_MAX];
+
+ BKE_image_path_from_imtype(
+ filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER,
+ (this->m_rd->scemode & R_EXTENSION) != 0, true, NULL);
+
+ exrhandle = this->get_handle(filename);
+
+ for (unsigned int i = 0; i < this->m_layers.size(); ++i)
+ add_exr_channels(exrhandle, this->m_layers[i].name, this->m_layers[i].datatype, this->m_viewName, width, this->m_layers[i].outputBuffer);
+
+ for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ /* memory can only be freed after we write all views to the file */
+ this->m_layers[i].outputBuffer = NULL;
+ this->m_layers[i].imageInput = NULL;
+ }
+
+ /* ready to close the file */
+ if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) {
+ IMB_exr_write_channels(exrhandle);
+
+ /* free buffer memory for all the views */
+ for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
+ free_exr_channels(exrhandle, this->m_rd, this->m_layers[i].name, this->m_layers[i].datatype);
+ }
+
+ IMB_exr_close(exrhandle);
+ }
+ }
+}
+
+
+/******************************** Stereo3D ******************************/
+
+OutputStereoOperation::OutputStereoOperation(
+ const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path,
+ const char *name, const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
+ const char *viewName)
+ : OutputSingleLayerOperation(rd, tree, datatype, format, path, viewSettings, displaySettings, viewName)
+{
+ BLI_strncpy(this->m_name, name, sizeof(this->m_name));
+ this->m_channels = get_datatype_size(datatype);
+}
+
+void *OutputStereoOperation::get_handle(const char *filename)
+{
+ size_t width = this->getWidth();
+ size_t height = this->getHeight();
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ size_t i;
+
+ if (width != 0 && height != 0) {
+ void *exrhandle;
+
+ exrhandle = IMB_exr_get_handle_name(filename);
+
+ if (!BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName))
+ return exrhandle;
+
+ IMB_exr_clear_channels(exrhandle);
+
+ for (i = 0; i < 2; i++)
+ IMB_exr_add_view(exrhandle, names[i]);
+
+ return exrhandle;
+ }
+ return NULL;
+}
+
+void OutputStereoOperation::deinitExecution()
+{
+ unsigned int width = this->getWidth();
+ unsigned int height = this->getHeight();
+
+ if (width != 0 && height != 0) {
+ void *exrhandle;
+
+ exrhandle = this->get_handle(this->m_path);
+ float *buf = this->m_outputBuffer;
+
+ /* populate single EXR channel with view data */
+ IMB_exr_add_channel(exrhandle, NULL, this->m_name, this->m_viewName, 1, this->m_channels * width * height, buf);
+
+ this->m_imageInput = NULL;
+ this->m_outputBuffer = NULL;
+
+ /* create stereo ibuf */
+ if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) {
+ ImBuf *ibuf[3] = {NULL};
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ Main *bmain = G.main; /* TODO, have this passed along */
+ char filename[FILE_MAX];
+ int i;
+
+ /* get rectf from EXR */
+ for (i = 0; i < 2; i++) {
+ float *rectf = IMB_exr_channel_rect(exrhandle, NULL, this->m_name, names[i]);
+ ibuf[i] = IMB_allocImBuf(width, height, this->m_format->planes, 0);
+
+ ibuf[i]->channels = this->m_channels;
+ ibuf[i]->rect_float = rectf;
+ ibuf[i]->mall |= IB_rectfloat;
+ ibuf[i]->dither = this->m_rd->dither_intensity;
+
+ /* do colormanagement in the individual views, so it doesn't need to do in the stereo */
+ IMB_colormanagement_imbuf_for_write(ibuf[i], true, false, this->m_viewSettings,
+ this->m_displaySettings, this->m_format);
+ IMB_prepare_write_ImBuf(IMB_isfloat(ibuf[i]), ibuf[i]);
+ }
+
+ /* create stereo buffer */
+ ibuf[2] = IMB_stereo3d_ImBuf(this->m_format, ibuf[0], ibuf[1]);
+
+ BKE_image_path_from_imformat(
+ filename, this->m_path, bmain->name, this->m_rd->cfra, this->m_format,
+ (this->m_rd->scemode & R_EXTENSION) != 0, true, NULL);
+
+ BKE_imbuf_write(ibuf[2], filename, this->m_format);
+
+ /* imbuf knows which rects are not part of ibuf */
+ for (i = 0; i < 3; i++)
+ IMB_freeImBuf(ibuf[i]);
+
+ IMB_exr_close(exrhandle);
+ }
+ }
+}
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
new file mode 100644
index 00000000000..25716fdb9e1
--- /dev/null
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor:
+ * Jeroen Bakker
+ * Monique Dewanchand
+ * Lukas Tönne
+ * Dalai Felinto
+ */
+
+#ifndef _COM_OutputFileMultiViewOperation_h
+#define _COM_OutputFileMultiViewOperation_h
+#include "COM_NodeOperation.h"
+
+#include "BLI_rect.h"
+#include "BLI_path_util.h"
+
+#include "DNA_color_types.h"
+#include "DNA_userdef_types.h"
+
+#include "intern/openexr/openexr_multi.h"
+
+class OutputOpenExrSingleLayerMultiViewOperation : public OutputSingleLayerOperation {
+private:
+public:
+ OutputOpenExrSingleLayerMultiViewOperation(const RenderData *rd, const bNodeTree *tree, DataType datatype,
+ ImageFormatData *format, const char *path,
+ const ColorManagedViewSettings *viewSettings,
+ const ColorManagedDisplaySettings *displaySettings,
+ const char *viewName);
+
+ void *get_handle(const char *filename);
+ void deinitExecution();
+};
+
+/* Writes inputs into OpenEXR multilayer channels. */
+class OutputOpenExrMultiLayerMultiViewOperation : public OutputOpenExrMultiLayerOperation {
+private:
+public:
+ OutputOpenExrMultiLayerMultiViewOperation(const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec, const char *viewName);
+
+ void *get_handle(const char *filename);
+ void deinitExecution();
+};
+
+/**/
+class OutputStereoOperation : public OutputSingleLayerOperation {
+private:
+ char m_name[FILE_MAX];
+ size_t m_channels;
+public:
+ OutputStereoOperation(const RenderData *rd, const bNodeTree *tree, DataType datatype,
+ struct ImageFormatData *format, const char *path, const char *name,
+ const ColorManagedViewSettings *viewSettings,
+ const ColorManagedDisplaySettings *displaySettings, const char *viewName);
+ void *get_handle(const char *filename);
+ void deinitExecution();
+};
+
+#endif
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
index 2f92351c00d..b99b0d5b875 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
@@ -29,6 +29,7 @@
#include "BKE_image.h"
#include "BKE_global.h"
#include "BKE_main.h"
+#include "BKE_scene.h"
#include "DNA_color_types.h"
@@ -39,7 +40,60 @@ extern "C" {
# include "IMB_imbuf_types.h"
}
-static int get_datatype_size(DataType datatype)
+void add_exr_channels(void *exrhandle, const char *layerName, const DataType datatype, const char *viewName, const size_t width, float *buf)
+{
+ /* create channels */
+ switch (datatype) {
+ case COM_DT_VALUE:
+ IMB_exr_add_channel(exrhandle, layerName, "V", viewName, 1, width, buf ? buf : NULL);
+ break;
+ case COM_DT_VECTOR:
+ IMB_exr_add_channel(exrhandle, layerName, "X", viewName, 3, 3 * width, buf ? buf : NULL);
+ IMB_exr_add_channel(exrhandle, layerName, "Y", viewName, 3, 3 * width, buf ? buf + 1 : NULL);
+ IMB_exr_add_channel(exrhandle, layerName, "Z", viewName, 3, 3 * width, buf ? buf + 2 : NULL);
+ break;
+ case COM_DT_COLOR:
+ IMB_exr_add_channel(exrhandle, layerName, "R", viewName, 4, 4 * width, buf ? buf : NULL);
+ IMB_exr_add_channel(exrhandle, layerName, "G", viewName, 4, 4 * width, buf ? buf + 1 : NULL);
+ IMB_exr_add_channel(exrhandle, layerName, "B", viewName, 4, 4 * width, buf ? buf + 2 : NULL);
+ IMB_exr_add_channel(exrhandle, layerName, "A", viewName, 4, 4 * width, buf ? buf + 3 : NULL);
+ break;
+ default:
+ break;
+ }
+}
+
+void free_exr_channels(void *exrhandle, const RenderData *rd, const char *layerName, const DataType datatype)
+{
+ SceneRenderView *srv;
+
+ /* check renderdata for amount of views */
+ for (srv = (SceneRenderView *) rd->views.first; srv; srv = srv->next) {
+ float *rect = NULL;
+
+ if (BKE_scene_multiview_is_render_view_active(rd, srv) == false)
+ continue;
+
+ /* the pointer is stored in the first channel of each datatype */
+ switch (datatype) {
+ case COM_DT_VALUE:
+ rect = IMB_exr_channel_rect(exrhandle, layerName, "V", srv->name);
+ break;
+ case COM_DT_VECTOR:
+ rect = IMB_exr_channel_rect(exrhandle, layerName, "X", srv->name);
+ break;
+ case COM_DT_COLOR:
+ rect = IMB_exr_channel_rect(exrhandle, layerName, "R", srv->name);
+ break;
+ default:
+ break;
+ }
+ if (rect)
+ MEM_freeN(rect);
+ }
+}
+
+int get_datatype_size(DataType datatype)
{
switch (datatype) {
case COM_DT_VALUE: return 1;
@@ -94,7 +148,7 @@ static void write_buffer_rect(rcti *rect, const bNodeTree *tree,
OutputSingleLayerOperation::OutputSingleLayerOperation(
const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path,
- const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings)
+ const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings, const char *viewName)
{
this->m_rd = rd;
this->m_tree = tree;
@@ -110,6 +164,7 @@ OutputSingleLayerOperation::OutputSingleLayerOperation(
this->m_viewSettings = viewSettings;
this->m_displaySettings = displaySettings;
+ this->m_viewName = viewName;
}
void OutputSingleLayerOperation::initExecution()
@@ -118,7 +173,7 @@ void OutputSingleLayerOperation::initExecution()
this->m_outputBuffer = init_buffer(this->getWidth(), this->getHeight(), this->m_datatype);
}
-void OutputSingleLayerOperation::executeRegion(rcti *rect, unsigned int tileNumber)
+void OutputSingleLayerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
{
write_buffer_rect(rect, this->m_tree, this->m_imageInput, this->m_outputBuffer, this->getWidth(), this->m_datatype);
}
@@ -131,6 +186,7 @@ void OutputSingleLayerOperation::deinitExecution()
ImBuf *ibuf = IMB_allocImBuf(this->getWidth(), this->getHeight(), this->m_format->planes, 0);
Main *bmain = G.main; /* TODO, have this passed along */
char filename[FILE_MAX];
+ const char *suffix;
ibuf->channels = size;
ibuf->rect_float = this->m_outputBuffer;
@@ -140,10 +196,12 @@ void OutputSingleLayerOperation::deinitExecution()
IMB_colormanagement_imbuf_for_write(ibuf, true, false, m_viewSettings, m_displaySettings,
this->m_format);
+ suffix = BKE_scene_multiview_view_suffix_get(this->m_rd, this->m_viewName);
+
BKE_image_path_from_imformat(
- filename, this->m_path, bmain->name, this->m_rd->cfra,
- this->m_format, (this->m_rd->scemode & R_EXTENSION) != 0, true);
-
+ filename, this->m_path, bmain->name, this->m_rd->cfra, this->m_format,
+ (this->m_rd->scemode & R_EXTENSION) != 0, true, suffix);
+
if (0 == BKE_imbuf_write(ibuf, filename, this->m_format))
printf("Cannot save Node File Output to %s\n", filename);
else
@@ -155,6 +213,7 @@ void OutputSingleLayerOperation::deinitExecution()
this->m_imageInput = NULL;
}
+/******************************* MultiLayer *******************************/
OutputOpenExrLayer::OutputOpenExrLayer(const char *name_, DataType datatype_, bool use_layer_)
{
@@ -168,13 +227,14 @@ OutputOpenExrLayer::OutputOpenExrLayer(const char *name_, DataType datatype_, bo
}
OutputOpenExrMultiLayerOperation::OutputOpenExrMultiLayerOperation(
- const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec)
+ const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec, const char *viewName)
{
this->m_rd = rd;
this->m_tree = tree;
BLI_strncpy(this->m_path, path, sizeof(this->m_path));
this->m_exr_codec = exr_codec;
+ this->m_viewName = viewName;
}
void OutputOpenExrMultiLayerOperation::add_layer(const char *name, DataType datatype, bool use_layer)
@@ -194,7 +254,7 @@ void OutputOpenExrMultiLayerOperation::initExecution()
}
}
-void OutputOpenExrMultiLayerOperation::executeRegion(rcti *rect, unsigned int tileNumber)
+void OutputOpenExrMultiLayerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
{
for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
OutputOpenExrLayer &layer = this->m_layers[i];
@@ -210,56 +270,25 @@ void OutputOpenExrMultiLayerOperation::deinitExecution()
if (width != 0 && height != 0) {
Main *bmain = G.main; /* TODO, have this passed along */
char filename[FILE_MAX];
+ const char *suffix;
void *exrhandle = IMB_exr_get_handle();
-
+
+ suffix = BKE_scene_multiview_view_suffix_get(this->m_rd, this->m_viewName);
BKE_image_path_from_imtype(
filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER,
- (this->m_rd->scemode & R_EXTENSION) != 0, true);
+ (this->m_rd->scemode & R_EXTENSION) != 0, true, suffix);
BLI_make_existing_file(filename);
-
+
for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
OutputOpenExrLayer &layer = this->m_layers[i];
if (!layer.imageInput)
continue; /* skip unconnected sockets */
- char channelname[EXR_TOT_MAXNAME];
- BLI_strncpy(channelname, this->m_layers[i].name, sizeof(channelname) - 2);
- char *channelname_ext = channelname + strlen(channelname);
-
- float *buf = this->m_layers[i].outputBuffer;
-
- /* create channels */
- switch (this->m_layers[i].datatype) {
- case COM_DT_VALUE:
- strcpy(channelname_ext, ".V");
- IMB_exr_add_channel(exrhandle, 0, channelname, 1, width, buf);
- break;
- case COM_DT_VECTOR:
- strcpy(channelname_ext, ".X");
- IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf);
- strcpy(channelname_ext, ".Y");
- IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf + 1);
- strcpy(channelname_ext, ".Z");
- IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf + 2);
- break;
- case COM_DT_COLOR:
- strcpy(channelname_ext, ".R");
- IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf);
- strcpy(channelname_ext, ".G");
- IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 1);
- strcpy(channelname_ext, ".B");
- IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 2);
- strcpy(channelname_ext, ".A");
- IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 3);
- break;
- default:
- break;
- }
-
+ add_exr_channels(exrhandle, this->m_layers[i].name, this->m_layers[i].datatype, "", width, this->m_layers[i].outputBuffer);
}
/* when the filename has no permissions, this can fail */
- if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec)) {
+ if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec, NULL)) {
IMB_exr_write_channels(exrhandle);
}
else {
@@ -279,3 +308,4 @@ void OutputOpenExrMultiLayerOperation::deinitExecution()
}
}
}
+
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.h b/source/blender/compositor/operations/COM_OutputFileOperation.h
index 03278c5b149..58ebf055583 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.h
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.h
@@ -34,7 +34,7 @@
/* Writes the image to a single-layer file. */
class OutputSingleLayerOperation : public NodeOperation {
-private:
+protected:
const RenderData *m_rd;
const bNodeTree *m_tree;
@@ -47,12 +47,14 @@ private:
const ColorManagedViewSettings *m_viewSettings;
const ColorManagedDisplaySettings *m_displaySettings;
+
+ const char *m_viewName;
public:
OutputSingleLayerOperation(const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path,
- const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings);
+ const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings, const char *viewName);
void executeRegion(rcti *rect, unsigned int tileNumber);
- bool isOutputOperation(bool rendering) const { return true; }
+ bool isOutputOperation(bool /*rendering*/) const { return true; }
void initExecution();
void deinitExecution();
const CompositorPriority getRenderPriority() const { return COM_PRIORITY_LOW; }
@@ -75,7 +77,7 @@ struct OutputOpenExrLayer {
/* Writes inputs into OpenEXR multilayer channels. */
class OutputOpenExrMultiLayerOperation : public NodeOperation {
-private:
+protected:
typedef std::vector<OutputOpenExrLayer> LayerList;
const RenderData *m_rd;
@@ -84,14 +86,15 @@ private:
char m_path[FILE_MAX];
char m_exr_codec;
LayerList m_layers;
+ const char *m_viewName;
public:
- OutputOpenExrMultiLayerOperation(const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec);
+ OutputOpenExrMultiLayerOperation(const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec, const char *viewName);
void add_layer(const char *name, DataType datatype, bool use_layer);
void executeRegion(rcti *rect, unsigned int tileNumber);
- bool isOutputOperation(bool rendering) const { return true; }
+ bool isOutputOperation(bool /*rendering*/) const { return true; }
void initExecution();
void deinitExecution();
const CompositorPriority getRenderPriority() const { return COM_PRIORITY_LOW; }
@@ -99,4 +102,8 @@ public:
bool isFileOutputOperation() const { return true; }
};
+void add_exr_channels(void *exrhandle, const char *layerName, const DataType datatype, const char *viewName, const size_t width, float *buf);
+void free_exr_channels(void *exrhandle, const RenderData *rd, const char *layerName, const DataType datatype);
+int get_datatype_size(DataType datatype);
+
#endif
diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
index 8133f392ac6..d7d1c9c0c93 100644
--- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
@@ -100,7 +100,7 @@ void PlaneDistortWarpImageOperation::deinitExecution()
this->m_pixelReader = NULL;
}
-void PlaneDistortWarpImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void PlaneDistortWarpImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
float uv[2];
float deriv[2][2];
@@ -194,7 +194,7 @@ void PlaneDistortMaskOperation::initExecution()
BLI_jitter_init(m_jitter, m_osa);
}
-void PlaneDistortMaskOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void PlaneDistortMaskOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
float point[2];
int inside_counter = 0;
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
index 03205130a74..a56aa0cbaa6 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
@@ -71,7 +71,7 @@ void PlaneTrackCommon::readCornersFromTrack(float corners[4][2], float frame)
}
}
-void PlaneTrackCommon::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+void PlaneTrackCommon::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
{
resolution[0] = 0;
resolution[1] = 0;
diff --git a/source/blender/compositor/operations/COM_PreviewOperation.cpp b/source/blender/compositor/operations/COM_PreviewOperation.cpp
index 69290cd7c3c..aa667884de6 100644
--- a/source/blender/compositor/operations/COM_PreviewOperation.cpp
+++ b/source/blender/compositor/operations/COM_PreviewOperation.cpp
@@ -85,7 +85,7 @@ void PreviewOperation::deinitExecution()
this->m_input = NULL;
}
-void PreviewOperation::executeRegion(rcti *rect, unsigned int tileNumber)
+void PreviewOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
{
int offset;
float color[4];
diff --git a/source/blender/compositor/operations/COM_PreviewOperation.h b/source/blender/compositor/operations/COM_PreviewOperation.h
index 3e97acec7bb..5da7a25ac5d 100644
--- a/source/blender/compositor/operations/COM_PreviewOperation.h
+++ b/source/blender/compositor/operations/COM_PreviewOperation.h
@@ -45,7 +45,7 @@ public:
PreviewOperation(const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings);
void verifyPreview(bNodeInstanceHash *previews, bNodeInstanceKey key);
- bool isOutputOperation(bool rendering) const { return !G.background; }
+ bool isOutputOperation(bool /*rendering*/) const { return !G.background; }
void initExecution();
void deinitExecution();
const CompositorPriority getRenderPriority() const;
diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp
index 7f6079c55aa..02d1809efbb 100644
--- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp
@@ -40,7 +40,7 @@ void ProjectorLensDistortionOperation::initExecution()
this->m_inputProgram = this->getInputSocketReader(0);
}
-void *ProjectorLensDistortionOperation::initializeTileData(rcti *rect)
+void *ProjectorLensDistortionOperation::initializeTileData(rcti * /*rect*/)
{
updateDispersion();
void *buffer = this->m_inputProgram->initializeTileData(NULL);
diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp b/source/blender/compositor/operations/COM_ReadBufferOperation.cpp
index ad4084a7092..bf0f24e06be 100644
--- a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp
+++ b/source/blender/compositor/operations/COM_ReadBufferOperation.cpp
@@ -32,7 +32,7 @@ ReadBufferOperation::ReadBufferOperation(DataType datatype) : NodeOperation()
this->m_buffer = NULL;
}
-void *ReadBufferOperation::initializeTileData(rcti *rect)
+void *ReadBufferOperation::initializeTileData(rcti * /*rect*/)
{
return m_buffer;
}
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
index 409fa68bacf..af176a766ff 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
@@ -23,6 +23,7 @@
#include "COM_RenderLayersProg.h"
#include "BLI_listbase.h"
+#include "BKE_scene.h"
#include "DNA_scene_types.h"
extern "C" {
@@ -57,11 +58,10 @@ void RenderLayersBaseProg::initExecution()
if (srl) {
RenderLayer *rl = RE_GetRenderLayer(rr, srl->name);
- if (rl && rl->rectf) {
- this->m_inputBuffer = RE_RenderLayerGetPass(rl, this->m_renderpass);
-
+ if (rl) {
+ this->m_inputBuffer = RE_RenderLayerGetPass(rl, this->m_renderpass, this->m_viewName);
if (this->m_inputBuffer == NULL && this->m_renderpass == SCE_PASS_COMBINED) {
- this->m_inputBuffer = rl->rectf;
+ this->m_inputBuffer = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, this->m_viewName);
}
}
}
@@ -179,7 +179,7 @@ void RenderLayersBaseProg::deinitExecution()
this->m_inputBuffer = NULL;
}
-void RenderLayersBaseProg::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+void RenderLayersBaseProg::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
{
Scene *sce = this->getScene();
Render *re = (sce) ? RE_GetRender(sce->id.name) : NULL;
@@ -195,7 +195,7 @@ void RenderLayersBaseProg::determineResolution(unsigned int resolution[2], unsig
SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&sce->r.layers, getLayerId());
if (srl) {
RenderLayer *rl = RE_GetRenderLayer(rr, srl->name);
- if (rl && rl->rectf) {
+ if (rl) {
resolution[0] = rl->rectx;
resolution[1] = rl->recty;
}
@@ -269,7 +269,7 @@ RenderLayersDepthProg::RenderLayersDepthProg() : RenderLayersBaseProg(SCE_PASS_Z
this->addOutputSocket(COM_DT_VALUE);
}
-void RenderLayersDepthProg::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void RenderLayersDepthProg::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
int ix = x;
int iy = y;
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.h b/source/blender/compositor/operations/COM_RenderLayersProg.h
index f73d9de3e27..2ddbc968c01 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.h
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.h
@@ -51,7 +51,12 @@ private:
* layerId of the layer where this operation needs to get its data from
*/
short m_layerId;
-
+
+ /**
+ * viewName of the view to use (unless another view is specified by the node
+ */
+ const char *m_viewName;
+
/**
* cached instance to the float buffer inside the layer
*/
@@ -97,6 +102,8 @@ public:
void setRenderData(const RenderData *rd) { this->m_rd = rd; }
void setLayerId(short layerId) { this->m_layerId = layerId; }
short getLayerId() { return this->m_layerId; }
+ void setViewName(const char *viewName) { this->m_viewName = viewName; }
+ const char *getViewName() { return this->m_viewName; }
void initExecution();
void deinitExecution();
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cpp b/source/blender/compositor/operations/COM_ScaleOperation.cpp
index 23e8ce86fd9..117ae743ee7 100644
--- a/source/blender/compositor/operations/COM_ScaleOperation.cpp
+++ b/source/blender/compositor/operations/COM_ScaleOperation.cpp
@@ -279,7 +279,7 @@ bool ScaleFixedSizeOperation::determineDependingAreaOfInterest(rcti *input, Read
return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
}
-void ScaleFixedSizeOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+void ScaleFixedSizeOperation::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2])
{
unsigned int nr[2];
nr[0] = this->m_newWidth;
diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
index ad9b761da45..acd76fa79a8 100644
--- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
@@ -70,7 +70,7 @@ void ScreenLensDistortionOperation::initExecution()
}
}
-void *ScreenLensDistortionOperation::initializeTileData(rcti *rect)
+void *ScreenLensDistortionOperation::initializeTileData(rcti * /*rect*/)
{
void *buffer = this->m_inputProgram->initializeTileData(NULL);
@@ -208,7 +208,7 @@ void ScreenLensDistortionOperation::determineUV(float result[6], float x, float
get_delta(uv_dot, m_k4[2], uv, result + 4);
}
-bool ScreenLensDistortionOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool ScreenLensDistortionOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
rcti newInputValue;
newInputValue.xmin = 0;
diff --git a/source/blender/compositor/operations/COM_SetColorOperation.cpp b/source/blender/compositor/operations/COM_SetColorOperation.cpp
index 94a863e628b..1a362bc55e2 100644
--- a/source/blender/compositor/operations/COM_SetColorOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetColorOperation.cpp
@@ -27,7 +27,9 @@ SetColorOperation::SetColorOperation() : NodeOperation()
this->addOutputSocket(COM_DT_COLOR);
}
-void SetColorOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void SetColorOperation::executePixelSampled(float output[4],
+ float /*x*/, float /*y*/,
+ PixelSampler /*sampler*/)
{
copy_v4_v4(output, this->m_color);
}
diff --git a/source/blender/compositor/operations/COM_SetSamplerOperation.cpp b/source/blender/compositor/operations/COM_SetSamplerOperation.cpp
index be72ffd0336..7057ecb14c1 100644
--- a/source/blender/compositor/operations/COM_SetSamplerOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetSamplerOperation.cpp
@@ -37,7 +37,7 @@ void SetSamplerOperation::deinitExecution()
this->m_reader = NULL;
}
-void SetSamplerOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void SetSamplerOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
this->m_reader->readSampled(output, x, y, this->m_sampler);
}
diff --git a/source/blender/compositor/operations/COM_SetValueOperation.cpp b/source/blender/compositor/operations/COM_SetValueOperation.cpp
index 51e09a63051..b6cfb760a98 100644
--- a/source/blender/compositor/operations/COM_SetValueOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetValueOperation.cpp
@@ -27,7 +27,9 @@ SetValueOperation::SetValueOperation() : NodeOperation()
this->addOutputSocket(COM_DT_VALUE);
}
-void SetValueOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void SetValueOperation::executePixelSampled(float output[4],
+ float /*x*/, float /*y*/,
+ PixelSampler /*sampler*/)
{
output[0] = this->m_value;
}
diff --git a/source/blender/compositor/operations/COM_SetVectorOperation.cpp b/source/blender/compositor/operations/COM_SetVectorOperation.cpp
index 769eaf1d2ed..1b0327683a9 100644
--- a/source/blender/compositor/operations/COM_SetVectorOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetVectorOperation.cpp
@@ -28,7 +28,9 @@ SetVectorOperation::SetVectorOperation() : NodeOperation()
this->addOutputSocket(COM_DT_VECTOR);
}
-void SetVectorOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void SetVectorOperation::executePixelSampled(float output[4],
+ float /*x*/, float /*y*/,
+ PixelSampler /*sampler*/)
{
output[0] = this->m_x;
output[1] = this->m_y;
diff --git a/source/blender/compositor/operations/COM_SplitOperation.cpp b/source/blender/compositor/operations/COM_SplitOperation.cpp
index 367c7eefa25..cd2166591bc 100644
--- a/source/blender/compositor/operations/COM_SplitOperation.cpp
+++ b/source/blender/compositor/operations/COM_SplitOperation.cpp
@@ -56,7 +56,7 @@ void SplitOperation::deinitExecution()
this->m_image2Input = NULL;
}
-void SplitOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void SplitOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
int perc = this->m_xSplit ? this->m_splitPercentage * this->getWidth() / 100.0f : this->m_splitPercentage * this->getHeight() / 100.0f;
bool image1 = this->m_xSplit ? x > perc : y > perc;
diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
index 0ca687ea162..a681583809c 100644
--- a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
+++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
@@ -293,7 +293,7 @@ static void accumulate_line(MemoryBuffer *input, float output[4], const float co
}
}
-void *SunBeamsOperation::initializeTileData(rcti *rect)
+void *SunBeamsOperation::initializeTileData(rcti * /*rect*/)
{
void *buffer = getInputOperation(0)->initializeTileData(NULL);
return buffer;
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cpp b/source/blender/compositor/operations/COM_TextureOperation.cpp
index 1b0485afb8d..2ff6cc047c6 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cpp
+++ b/source/blender/compositor/operations/COM_TextureOperation.cpp
@@ -117,7 +117,7 @@ void TextureBaseOperation::executePixelSampled(float output[4], float x, float y
}
}
-MemoryBuffer *TextureBaseOperation::createMemoryBuffer(rcti *rect2)
+MemoryBuffer *TextureBaseOperation::createMemoryBuffer(rcti * /*rect2*/)
{
int height = getHeight();
int width = getWidth();
diff --git a/source/blender/compositor/operations/COM_TonemapOperation.cpp b/source/blender/compositor/operations/COM_TonemapOperation.cpp
index e8a578fa131..c581d115a2f 100644
--- a/source/blender/compositor/operations/COM_TonemapOperation.cpp
+++ b/source/blender/compositor/operations/COM_TonemapOperation.cpp
@@ -24,6 +24,10 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+extern "C" {
+#include "IMB_colormanagement.h"
+}
+
TonemapOperation::TonemapOperation() : NodeOperation()
{
this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE);
@@ -69,7 +73,7 @@ void PhotoreceptorTonemapOperation::executePixel(float output[4], int x, int y,
this->m_imageReader->read(output, x, y, NULL);
- const float L = rgb_to_luma_y(output);
+ const float L = IMB_colormanagement_get_luminance(output);
float I_l = output[0] + ic * (L - output[0]);
float I_g = avg->cav[0] + ic * (avg->lav - avg->cav[0]);
float I_a = I_l + ia * (I_g - I_l);
@@ -93,7 +97,7 @@ void TonemapOperation::deinitExecution()
NodeOperation::deinitMutex();
}
-bool TonemapOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool TonemapOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
rcti imageInput;
@@ -125,7 +129,7 @@ void *TonemapOperation::initializeTileData(rcti *rect)
float Lav = 0.f;
float cav[4] = {0.0f, 0.0f, 0.0f, 0.0f};
while (p--) {
- float L = rgb_to_luma_y(bc);
+ float L = IMB_colormanagement_get_luminance(bc);
Lav += L;
add_v3_v3(cav, bc);
lsum += logf(MAX2(L, 0.0f) + 1e-5f);
@@ -146,7 +150,7 @@ void *TonemapOperation::initializeTileData(rcti *rect)
return this->m_cachedInstance;
}
-void TonemapOperation::deinitializeTileData(rcti *rect, void *data)
+void TonemapOperation::deinitializeTileData(rcti * /*rect*/, void * /*data*/)
{
/* pass */
}
diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp b/source/blender/compositor/operations/COM_TrackPositionOperation.cpp
index a76e0866d0d..ca169d03fbc 100644
--- a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp
+++ b/source/blender/compositor/operations/COM_TrackPositionOperation.cpp
@@ -102,7 +102,9 @@ void TrackPositionOperation::initExecution()
}
}
-void TrackPositionOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void TrackPositionOperation::executePixelSampled(float output[4],
+ float /*x*/, float /*y*/,
+ PixelSampler /*sampler*/)
{
output[0] = this->m_markerPos[this->m_axis] - this->m_relativePos[this->m_axis];
diff --git a/source/blender/compositor/operations/COM_TranslateOperation.cpp b/source/blender/compositor/operations/COM_TranslateOperation.cpp
index 191388a42fb..fcf99a10a73 100644
--- a/source/blender/compositor/operations/COM_TranslateOperation.cpp
+++ b/source/blender/compositor/operations/COM_TranslateOperation.cpp
@@ -52,7 +52,7 @@ void TranslateOperation::deinitExecution()
}
-void TranslateOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void TranslateOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
{
ensureDelta();
diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
index 4809efd7436..1ec52571be8 100644
--- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
@@ -62,8 +62,7 @@ void VariableSizeBokehBlurOperation::initExecution()
#endif
QualityStepHelper::initExecution(COM_QH_INCREASE);
}
-struct VariableSizeBokehBlurTileData
-{
+struct VariableSizeBokehBlurTileData {
MemoryBuffer *color;
MemoryBuffer *bokeh;
MemoryBuffer *size;
@@ -89,7 +88,7 @@ void *VariableSizeBokehBlurOperation::initializeTileData(rcti *rect)
return data;
}
-void VariableSizeBokehBlurOperation::deinitializeTileData(rcti *rect, void *data)
+void VariableSizeBokehBlurOperation::deinitializeTileData(rcti * /*rect*/, void *data)
{
VariableSizeBokehBlurTileData *result = (VariableSizeBokehBlurTileData *)data;
delete result;
@@ -187,7 +186,7 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y,
void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device,
MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp)
+ list<cl_kernel> * /*clKernelsToCleanUp*/)
{
cl_kernel defocusKernel = device->COM_clCreateKernel("defocusKernel", NULL);
@@ -200,8 +199,8 @@ void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device,
const float max_dim = max(m_width, m_height);
cl_float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
- maxBlur = (cl_int)sizeMemoryBuffer->getMaximumValue() * scalar;
- maxBlur = min(maxBlur, this->m_maxBlur);
+ maxBlur = (cl_int)min_ff(sizeMemoryBuffer->getMaximumValue() * scalar,
+ (float)this->m_maxBlur);
device->COM_clAttachMemoryBufferToKernelParameter(defocusKernel, 0, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram);
device->COM_clAttachMemoryBufferToKernelParameter(defocusKernel, 1, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputBokehProgram);
diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp
index 8dc06ef07d7..36f06e92436 100644
--- a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp
@@ -91,7 +91,7 @@ void *VectorBlurOperation::initializeTileData(rcti *rect)
return this->m_cachedInstance;
}
-bool VectorBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool VectorBlurOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
if (this->m_cachedInstance == NULL) {
rcti newInput;
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cpp b/source/blender/compositor/operations/COM_ViewerOperation.cpp
index 53c0acd781a..96ee5ecbb03 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.cpp
+++ b/source/blender/compositor/operations/COM_ViewerOperation.cpp
@@ -23,6 +23,7 @@
#include "COM_ViewerOperation.h"
#include "BLI_listbase.h"
#include "BKE_image.h"
+#include "BKE_scene.h"
#include "WM_api.h"
#include "WM_types.h"
#include "PIL_time.h"
@@ -57,6 +58,8 @@ ViewerOperation::ViewerOperation() : NodeOperation()
this->m_imageInput = NULL;
this->m_alphaInput = NULL;
this->m_depthInput = NULL;
+ this->m_rd = NULL;
+ this->m_viewName = NULL;
}
void ViewerOperation::initExecution()
@@ -80,7 +83,7 @@ void ViewerOperation::deinitExecution()
this->m_outputBuffer = NULL;
}
-void ViewerOperation::executeRegion(rcti *rect, unsigned int tileNumber)
+void ViewerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
{
float *buffer = this->m_outputBuffer;
float *depthbuffer = this->m_depthBuffer;
@@ -123,8 +126,18 @@ void ViewerOperation::executeRegion(rcti *rect, unsigned int tileNumber)
void ViewerOperation::initImage()
{
Image *ima = this->m_image;
+ ImageUser iuser = *this->m_imageUser;
void *lock;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, this->m_imageUser, &lock);
+ ImBuf *ibuf;
+
+ /* make sure the image has the correct number of views */
+ if (ima && BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName)) {
+ BKE_image_verify_viewer_views(this->m_rd, ima, this->m_imageUser);
+ }
+
+ /* local changes to the original ImageUser */
+ iuser.multi_index = BKE_scene_multiview_view_id_get(this->m_rd, this->m_viewName);
+ ibuf = BKE_image_acquire_ibuf(ima, &iuser, &lock);
if (!ibuf) return;
BLI_lock_thread(LOCK_DRAW_IMAGE);
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.h b/source/blender/compositor/operations/COM_ViewerOperation.h
index dcc7ffa3730..107aee3a82f 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.h
+++ b/source/blender/compositor/operations/COM_ViewerOperation.h
@@ -40,7 +40,9 @@ private:
bool m_doDepthBuffer;
ImBuf *m_ibuf;
bool m_useAlphaInput;
-
+ const RenderData *m_rd;
+ const char *m_viewName;
+
const ColorManagedViewSettings *m_viewSettings;
const ColorManagedDisplaySettings *m_displaySettings;
@@ -53,7 +55,7 @@ public:
void initExecution();
void deinitExecution();
void executeRegion(rcti *rect, unsigned int tileNumber);
- bool isOutputOperation(bool rendering) const { if (G.background) return false; return isActiveViewerOutput(); }
+ bool isOutputOperation(bool /*rendering*/) const { if (G.background) return false; return isActiveViewerOutput(); }
void setImage(Image *image) { this->m_image = image; }
void setImageUser(ImageUser *imageUser) { this->m_imageUser = imageUser; }
const bool isActiveViewerOutput() const { return this->m_active; }
@@ -67,6 +69,8 @@ public:
const CompositorPriority getRenderPriority() const;
bool isViewerOperation() const { return true; }
void setUseAlphaInput(bool value) { this->m_useAlphaInput = value; }
+ void setRenderData(const RenderData *rd) { this->m_rd = rd; }
+ void setViewName(const char *viewName) { this->m_viewName = viewName; }
void setViewSettings(const ColorManagedViewSettings *viewSettings) { this->m_viewSettings = viewSettings; }
void setDisplaySettings(const ColorManagedDisplaySettings *displaySettings) { this->m_displaySettings = displaySettings; }
diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp b/source/blender/compositor/operations/COM_WriteBufferOperation.cpp
index fccff2a33bf..b3c1c00804e 100644
--- a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp
+++ b/source/blender/compositor/operations/COM_WriteBufferOperation.cpp
@@ -57,7 +57,7 @@ void WriteBufferOperation::deinitExecution()
this->m_memoryProxy->free();
}
-void WriteBufferOperation::executeRegion(rcti *rect, unsigned int tileNumber)
+void WriteBufferOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
{
MemoryBuffer *memoryBuffer = this->m_memoryProxy->getBuffer();
float *buffer = memoryBuffer->getBuffer();
@@ -110,7 +110,7 @@ void WriteBufferOperation::executeRegion(rcti *rect, unsigned int tileNumber)
memoryBuffer->setCreatedState();
}
-void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device, rcti *rect, unsigned int chunkNumber,
+void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device, rcti * /*rect*/, unsigned int /*chunkNumber*/,
MemoryBuffer **inputMemoryBuffers, MemoryBuffer *outputBuffer)
{
float *outputFloatBuffer = outputBuffer->getBuffer();
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
new file mode 100644
index 00000000000..dcdb14d0ba0
--- /dev/null
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -0,0 +1,118 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2014, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Joshua Leung, Lukas Toenne
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ intern
+ util
+ ../blenkernel
+ ../blenlib
+ ../bmesh
+ ../makesdna
+ ../makesrna
+ ../modifiers
+ ../windowmanager
+ ../../../intern/atomic
+ ../../../intern/guardedalloc
+)
+
+set(INC_SYS
+)
+
+set(SRC
+ intern/depsgraph.cc
+ intern/depsnode.cc
+ intern/depsnode_component.cc
+ intern/depsnode_operation.cc
+ intern/depsgraph_build.cc
+ intern/depsgraph_build_nodes.cc
+ intern/depsgraph_build_relations.cc
+ intern/depsgraph_debug.cc
+ intern/depsgraph_eval.cc
+ intern/depsgraph_query.cc
+ intern/depsgraph_queue.cc
+ intern/depsgraph_tag.cc
+ intern/depsgraph_type_defines.cc
+ util/depsgraph_util_cycle.cc
+ util/depsgraph_util_pchanmap.cc
+ util/depsgraph_util_transitive.cc
+
+ DEG_depsgraph.h
+ DEG_depsgraph_build.h
+ DEG_depsgraph_debug.h
+ DEG_depsgraph_query.h
+ intern/depsgraph.h
+ intern/depsnode.h
+ intern/depsnode_component.h
+ intern/depsnode_operation.h
+ intern/depsnode_opcodes.h
+ intern/depsgraph_build.h
+ intern/depsgraph_debug.h
+ intern/depsgraph_intern.h
+ intern/depsgraph_queue.h
+ intern/depsgraph_types.h
+
+ util/depsgraph_util_cycle.h
+ util/depsgraph_util_function.h
+ util/depsgraph_util_hash.h
+ util/depsgraph_util_map.h
+ util/depsgraph_util_pchanmap.h
+ util/depsgraph_util_set.h
+ util/depsgraph_util_transitive.h
+)
+
+TEST_UNORDERED_MAP_SUPPORT()
+if(HAVE_STD_UNORDERED_MAP_HEADER)
+ if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
+ add_definitions(-DDEG_STD_UNORDERED_MAP)
+ else()
+ if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ add_definitions(-DDEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ else()
+ add_definitions(-DDEG_NO_UNORDERED_MAP)
+ message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
+ endif()
+ endif()
+else()
+ if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ add_definitions(-DDEG_TR1_UNORDERED_MAP)
+ else()
+ add_definitions(-DDEG_NO_UNORDERED_MAP)
+ message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
+ endif()
+endif()
+
+if(WITH_LEGACY_DEPSGRAPH)
+ add_definitions(-DWITH_LEGACY_DEPSGRAPH)
+endif()
+
+if(WITH_BOOST)
+ list(APPEND INC_SYS
+ ${BOOST_INCLUDE_DIR}
+ )
+ add_definitions(-DHAVE_BOOST_FUNCTION_BINDINGS)
+endif()
+
+blender_add_lib(bf_depsgraph "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
new file mode 100644
index 00000000000..b91f99ecd20
--- /dev/null
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -0,0 +1,215 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/DEG_depsgraph.h
+ * \ingroup depsgraph
+ *
+ * Public API for Depsgraph
+ *
+ * Dependency Graph
+ * ================
+ *
+ * The dependency graph tracks relations between various pieces of data in
+ * a Blender file, but mainly just those which make up scene data. It is used
+ * to determine the set of operations need to ensure that all data has been
+ * correctly evaluated in response to changes, based on dependencies and visibility
+ * of affected data.
+ *
+ *
+ * Evaluation Engine
+ * =================
+ *
+ * The evaluation takes the operation-nodes the Depsgraph has tagged for updating,
+ * and schedules them up for being evaluated/executed such that the all dependency
+ * relationship constraints are satisfied.
+ */
+
+/* ************************************************* */
+/* Forward-defined typedefs for core types
+ * - These are used in all depsgraph code and by all callers of Depsgraph API...
+ */
+
+#ifndef __DEG_DEPSGRAPH_H__
+#define __DEG_DEPSGRAPH_H__
+
+/* Dependency Graph */
+typedef struct Depsgraph Depsgraph;
+
+/* ------------------------------------------------ */
+
+struct EvaluationContext;
+struct Main;
+
+struct PointerRNA;
+struct PropertyRNA;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool DEG_depsgraph_use_legacy(void);
+void DEG_depsgraph_switch_to_legacy(void);
+void DEG_depsgraph_switch_to_new(void);
+
+/* ************************************************ */
+/* Depsgraph API */
+
+/* CRUD ------------------------------------------- */
+
+// Get main depsgraph instance from context!
+
+/* Create new Depsgraph instance */
+// TODO: what args are needed here? What's the building-graph entry point?
+Depsgraph *DEG_graph_new(void);
+
+/* Free Depsgraph itself and all its data */
+void DEG_graph_free(Depsgraph *graph);
+
+/* Node Types Registry ---------------------------- */
+
+/* Register all node types */
+void DEG_register_node_types(void);
+
+/* Free node type registry on exit */
+void DEG_free_node_types(void);
+
+/* Update Tagging -------------------------------- */
+
+/* Tag node(s) associated with states such as time and visibility */
+void DEG_scene_update_flags(Depsgraph *graph, const bool do_time);
+
+/* Update dependency graph when visible scenes/layers changes. */
+void DEG_graph_on_visible_update(struct Main *bmain, struct Scene *scene);
+
+/* Update all dependency graphs when visible scenes/layers changes. */
+void DEG_on_visible_update(struct Main *bmain, const bool do_time);
+
+/* Tag node(s) associated with changed data for later updates */
+void DEG_graph_id_tag_update(struct Main *bmain,
+ Depsgraph *graph,
+ struct ID *id);
+void DEG_graph_data_tag_update(Depsgraph *graph, const struct PointerRNA *ptr);
+void DEG_graph_property_tag_update(Depsgraph *graph, const struct PointerRNA *ptr, const struct PropertyRNA *prop);
+
+/* Tag given ID for an update in all the dependency graphs. */
+void DEG_id_tag_update(struct ID *id, short flag);
+void DEG_id_tag_update_ex(struct Main *bmain,
+ struct ID *id,
+ short flag);
+
+/* Tag given ID type for update.
+ *
+ * Used by all sort of render engines to quickly check if
+ * IDs of a given type need to be checked for update.
+ */
+void DEG_id_type_tag(struct Main *bmain, short idtype);
+
+void DEG_ids_clear_recalc(struct Main *bmain);
+
+/* Update Flushing ------------------------------- */
+
+/* Flush updates */
+void DEG_graph_flush_updates(struct Main *bmain, Depsgraph *graph);
+
+/* Flush updates for all IDs */
+void DEG_ids_flush_tagged(struct Main *bmain);
+
+/* Check if something was changed in the database and inform
+ * editors about this.
+ */
+void DEG_ids_check_recalc(struct Main *bmain,
+ struct Scene *scene,
+ bool time);
+
+/* Clear all update tags
+ * - For aborted updates, or after successful evaluation
+ */
+void DEG_graph_clear_tags(Depsgraph *graph);
+
+/* ************************************************ */
+/* Evaluation Engine API */
+
+/* Evaluation Context ---------------------------- */
+
+/* Create new evaluation context. */
+struct EvaluationContext *DEG_evaluation_context_new(int mode);
+
+/* Initialize evaluation context.
+ * Used by the areas which currently overrides the context or doesn't have
+ * access to a proper one.
+ */
+void DEG_evaluation_context_init(struct EvaluationContext *eval_ctx, int mode);
+
+/* Free evaluation context. */
+void DEG_evaluation_context_free(struct EvaluationContext *eval_ctx);
+
+/* Graph Evaluation ----------------------------- */
+
+/* Frame changed recalculation entry point
+ * < context_type: context to perform evaluation for
+ * < ctime: (frame) new frame to evaluate values on
+ */
+void DEG_evaluate_on_framechange(struct EvaluationContext *eval_ctx,
+ struct Main *bmain,
+ Depsgraph *graph,
+ float ctime,
+ const int layer);
+
+/* Data changed recalculation entry point.
+ * < context_type: context to perform evaluation for
+ * < layers: visible layers bitmask to update the graph for
+ */
+void DEG_evaluate_on_refresh_ex(struct EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ const int layers);
+
+/* Data changed recalculation entry point.
+ * < context_type: context to perform evaluation for
+ */
+void DEG_evaluate_on_refresh(struct EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ struct Scene *scene);
+
+/* Editors Integration -------------------------- */
+
+/* Mechanism to allow editors to be informed of depsgraph updates,
+ * to do their own updates based on changes.
+ */
+
+typedef void (*DEG_EditorUpdateIDCb)(struct Main *bmain, struct ID *id);
+typedef void (*DEG_EditorUpdateSceneCb)(struct Main *bmain,
+ struct Scene *scene,
+ int updated);
+
+/* Set callbacks which are being called when depsgraph changes. */
+void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
+ DEG_EditorUpdateSceneCb scene_func);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __DEG_DEPSGRAPH_H__ */
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
new file mode 100644
index 00000000000..f680c47247a
--- /dev/null
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -0,0 +1,121 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/DEG_depsgraph_build.h
+ * \ingroup depsgraph
+ *
+ * Public API for Depsgraph
+ */
+
+#ifndef __DEG_DEPSGRAPH_BUILD_H__
+#define __DEG_DEPSGRAPH_BUILD_H__
+
+/* ************************************************* */
+
+/* Dependency Graph */
+struct Depsgraph;
+
+/* ------------------------------------------------ */
+
+struct Main;
+struct Scene;
+
+struct PointerRNA;
+struct PropertyRNA;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Graph Building -------------------------------- */
+
+/* Build depsgraph for the given scene, and dump results in given graph container */
+void DEG_graph_build_from_scene(struct Depsgraph *graph, struct Main *bmain, struct Scene *scene);
+
+/* Tag relations from the given graph for update. */
+void DEG_graph_tag_relations_update(struct Depsgraph *graph);
+
+/* Tag all relations in the database for update.*/
+void DEG_relations_tag_update(struct Main *bmain);
+
+/* Create new graph if didn't exist yet,
+ * or update relations if graph was tagged for update.
+ */
+void DEG_scene_relations_update(struct Main *bmain, struct Scene *scene);
+
+/* Rebuild dependency graph only for a given scene. */
+void DEG_scene_relations_rebuild(struct Main *bmain,
+ struct Scene *scene);
+
+/* Delete scene graph. */
+void DEG_scene_graph_free(struct Scene *scene);
+
+/* Add Dependencies ----------------------------- */
+
+/* Handle for components to define their dependencies from callbacks.
+ * This is generated by the depsgraph and passed to dependency callbacks
+ * as a symbolic reference to the current DepsNode.
+ * All relations will be defined in reference to that node.
+ */
+struct DepsNodeHandle;
+
+struct Object;
+
+typedef enum eDepsSceneComponentType {
+ DEG_SCENE_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
+ DEG_SCENE_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters?
+ DEG_SCENE_COMP_SEQUENCER, /* Sequencer Component (Scene Only) */
+} eDepsSceneComponentType;
+
+typedef enum eDepsObjectComponentType {
+ DEG_OB_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
+ DEG_OB_COMP_PROXY, /* Generic "Proxy-Inherit" Component */ // XXX: Also for instancing of subgraphs?
+ DEG_OB_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters?
+ DEG_OB_COMP_TRANSFORM, /* Transform Component (Parenting/Constraints) */
+ DEG_OB_COMP_GEOMETRY, /* Geometry Component (DerivedMesh/Displist) */
+
+ /* Evaluation-Related Outer Types (with Subdata) */
+ DEG_OB_COMP_EVAL_POSE, /* Pose Component - Owner/Container of Bones Eval */
+ DEG_OB_COMP_BONE, /* Bone Component - Child/Subcomponent of Pose */
+
+ DEG_OB_COMP_EVAL_PARTICLES, /* Particle Systems Component */
+ DEG_OB_COMP_SHADING, /* Material Shading Component */
+} eDepsObjectComponentType;
+
+void DEG_add_scene_relation(struct DepsNodeHandle *node, struct Scene *scene, eDepsSceneComponentType component, const char *description);
+void DEG_add_object_relation(struct DepsNodeHandle *node, struct Object *ob, eDepsObjectComponentType component, const char *description);
+void DEG_add_bone_relation(struct DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description);
+
+/* TODO(sergey): Remove once all geometry update is granular. */
+void DEG_add_special_eval_flag(struct Depsgraph *graph, struct ID *id, short flag);
+
+/* ************************************************ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __DEG_DEPSGRAPH_BUILD_H__ */
diff --git a/source/blender/depsgraph/DEG_depsgraph_debug.h b/source/blender/depsgraph/DEG_depsgraph_debug.h
new file mode 100644
index 00000000000..374fad63c34
--- /dev/null
+++ b/source/blender/depsgraph/DEG_depsgraph_debug.h
@@ -0,0 +1,111 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/DEG_depsgraph_debug.h
+ * \ingroup depsgraph
+ *
+ * Public API for Querying and Filtering Depsgraph
+ */
+
+#ifndef __DEG_DEPSGRAPH_DEBUG_H__
+#define __DEG_DEPSGRAPH_DEBUG_H__
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct DepsgraphSettings;
+struct GHash;
+struct ID;
+
+struct Depsgraph;
+struct DepsNode;
+struct DepsRelation;
+
+/* ************************************************ */
+/* Statistics */
+
+typedef struct DepsgraphStatsTimes {
+ float duration_last;
+} DepsgraphStatsTimes;
+
+typedef struct DepsgraphStatsComponent {
+ struct DepsgraphStatsComponent *next, *prev;
+
+ char name[64];
+ DepsgraphStatsTimes times;
+} DepsgraphStatsComponent;
+
+typedef struct DepsgraphStatsID {
+ struct ID *id;
+
+ DepsgraphStatsTimes times;
+ ListBase components;
+} DepsgraphStatsID;
+
+typedef struct DepsgraphStats {
+ struct GHash *id_stats;
+} DepsgraphStats;
+
+struct DepsgraphStats *DEG_stats(void);
+
+void DEG_stats_verify(void);
+
+struct DepsgraphStatsID *DEG_stats_id(struct ID *id);
+
+/* ------------------------------------------------ */
+
+void DEG_stats_simple(const struct Depsgraph *graph,
+ size_t *r_outer,
+ size_t *r_operations,
+ size_t *r_relations);
+
+/* ************************************************ */
+/* Diagram-Based Graph Debugging */
+
+void DEG_debug_graphviz(const struct Depsgraph *graph, FILE *stream, const char *label, bool show_eval);
+
+/* ************************************************ */
+
+/* Compare two dependency graphs. */
+bool DEG_debug_compare(const struct Depsgraph *graph1,
+ const struct Depsgraph *graph2);
+
+/* Check that dependnecies in the graph are really up to date. */
+bool DEG_debug_scene_relations_validate(struct Main *bmain,
+ struct Scene *scene);
+
+
+/* Perform consistency check on the graph. */
+bool DEG_debug_consistency_check(struct Depsgraph *graph);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __DEG_DEPSGRAPH_DEBUG_H__ */
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
new file mode 100644
index 00000000000..60d673d4c5b
--- /dev/null
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -0,0 +1,195 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/DEG_depsgraph_query.h
+ * \ingroup depsgraph
+ *
+ * Public API for Querying and Filtering Depsgraph.
+ */
+
+#ifndef __DEG_DEPSGRAPH_QUERY_H__
+#define __DEG_DEPSGRAPH_QUERY_H__
+
+struct ListBase;
+struct ID;
+
+struct Depsgraph;
+struct DepsNode;
+struct DepsRelation;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ************************************************ */
+/* Type Defines */
+
+/* FilterPredicate Callback
+ *
+ * Defines a callback function which can be supplied to check whether a
+ * node is relevant or not.
+ *
+ * < graph: Depsgraph that we're traversing
+ * < node: The node to check
+ * < userdata: FilterPredicate state data (as needed)
+ * > returns: True if node is relevant
+ */
+typedef bool (*DEG_FilterPredicate)(const struct Depsgraph *graph, const struct DepsNode *node, void *userdata);
+
+
+/* Node Operation
+ *
+ * Performs some action on the given node, provided that the node was
+ * deemed to be relevant to operate on.
+ *
+ * < graph: Depsgraph that we're traversing
+ * < node: The node to perform operation on/with
+ * < userdata: Node Operation's state data (as needed)
+ * > returns: True if traversal should be aborted at this point
+ */
+typedef bool (*DEG_NodeOperation)(const struct Depsgraph *graph, struct DepsNode *node, void *userdata);
+
+/* ************************************************ */
+/* Low-Level Filtering API */
+
+/* Create a filtered copy of the given graph which contains only the
+ * nodes which fulfill the criteria specified using the FilterPredicate
+ * passed in.
+ *
+ * < graph: The graph to be copied and filtered
+ * < filter: FilterPredicate used to check which nodes should be included
+ * (If null, full graph is copied as-is)
+ * < userdata: State data for filter (as necessary)
+ *
+ * > returns: a full copy of all the relevant nodes - the matching subgraph
+ */
+// XXX: is there any need for extra settings/options for how the filtering goes?
+Depsgraph *DEG_graph_filter(const struct Depsgraph *graph, DEG_FilterPredicate *filter, void *userdata);
+
+
+/* Traverse nodes in graph which are deemed relevant,
+ * performing the provided operation on the nodes.
+ *
+ * < graph: The graph to perform operations on
+ * < filter: FilterPredicate used to check which nodes should be included
+ * (If null, all nodes are considered valid targets)
+ * < filter_data: Custom state data for FilterPredicate
+ * (Note: This can be the same as op_data, where appropriate)
+ * < op: NodeOperation to perform on each node
+ * (If null, no graph traversal is performed for efficiency)
+ * < op_data: Custom state data for NodeOperation
+ * (Note: This can be the same as filter_data, where appropriate)
+ */
+void DEG_graph_traverse(const struct Depsgraph *graph,
+ DEG_FilterPredicate *filter, void *filter_data,
+ DEG_NodeOperation *op, void *op_data);
+
+/* ************************************************ */
+/* Node-Based Operations */
+// XXX: do we want to be able to attach conditional requirements here?
+
+/* Find an (outer) node matching given conditions
+ * ! Assumes that there will only be one such node, or that only the first one matters
+ *
+ * < graph: a dependency graph which may or may not contain a node matching these requirements
+ * < query: query conditions for the criteria that the node must satisfy
+ */
+//DepsNode *DEG_node_find(const Depsgraph *graph, DEG_QueryConditions *query);
+
+/* Topology Queries (Direct) ---------------------- */
+
+/* Get list of nodes which directly depend on given node
+ *
+ * > result: list to write results to
+ * < node: the node to find the children/dependents of
+ */
+void DEG_node_get_children(struct ListBase *result, const struct DepsNode *node);
+
+
+/* Get list of nodes which given node directly depends on
+ *
+ * > result: list to write results to
+ * < node: the node to find the dependencies of
+ */
+void DEG_node_get_dependencies(struct ListBase *result, const struct DepsNode *node);
+
+
+/* Topology Queries (Subgraph) -------------------- */
+// XXX: given that subgraphs potentially involve many interconnected nodes, we currently
+// just spit out a copy of the subgraph which matches. This works well for the cases
+// where these are used - mostly for efficient updating of subsets of the nodes.
+
+// XXX: allow supplying a filter predicate to provide further filtering/pruning?
+
+
+/* Get all descendants of a node
+ *
+ * That is, get the subgraph / subset of nodes which are dependent
+ * on the results of the given node.
+ */
+Depsgraph *DEG_node_get_descendants(const struct Depsgraph *graph, const struct DepsNode *node);
+
+
+/* Get all ancestors of a node
+ *
+ * That is, get the subgraph / subset of nodes which the given node
+ * is dependent on in order to be evaluated.
+ */
+Depsgraph *DEG_node_get_ancestors(const struct Depsgraph *graph, const struct DepsNode *node);
+
+/* ************************************************ */
+/* Higher-Level Queries */
+
+/* Get ID-blocks which would be affected if specified ID is modified
+ * < only_direct: True = Only ID-blocks with direct relationships to ID-block will be returned
+ *
+ * > result: (LinkData : ID) a list of ID-blocks matching the specified criteria
+ * > returns: number of matching ID-blocks
+ */
+size_t DEG_query_affected_ids(struct ListBase *result, const struct ID *id, const bool only_direct);
+
+
+/* Get ID-blocks which are needed to update/evaluate specified ID
+ * < only_direct: True = Only ID-blocks with direct relationships to ID-block will be returned
+ *
+ * > result: (LinkData : ID) a list of ID-blocks matching the specified criteria
+ * > returns: number of matching ID-blocks
+ */
+size_t DEG_query_required_ids(struct ListBase *result, const struct ID *id, const bool only_direct);
+
+/* ************************************************ */
+
+/* Check if given ID type was tagged for update. */
+bool DEG_id_type_tagged(struct Main *bmain, short idtype);
+
+/* Get additional evaluation flags for the given ID. */
+short DEG_get_eval_flags_for_id(struct Depsgraph *graph, struct ID *id);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __DEG_DEPSGRAPH_QUERY_H__ */
diff --git a/source/blender/depsgraph/SConscript b/source/blender/depsgraph/SConscript
new file mode 100644
index 00000000000..dd0552e19a2
--- /dev/null
+++ b/source/blender/depsgraph/SConscript
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+#
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2013, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Nathan Letwory, Joshua Leung.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+Import('env')
+
+sources = env.Glob('intern/*.cc') + env.Glob('util/*.cc')
+
+incs = [
+ '.',
+ './intern',
+ './util',
+ '#/intern/atomic',
+ '#/intern/guardedalloc',
+ '../bmesh',
+ '../blenlib',
+ '../blenkernel',
+ '../makesdna',
+ '../makesrna',
+ '../modifiers',
+ '../windowmanager',
+ ]
+
+defs = []
+
+if env['WITH_BF_BOOST']:
+ incs.append(env['BF_BOOST_INC'])
+ defs.append('HAVE_BOOST_FUNCTION_BINDINGS')
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
+ incs.append(env['BF_PTHREADS_INC'])
+
+
+if env['WITH_UNORDERED_MAP_SUPPORT']:
+ if env['UNORDERED_MAP_HEADER'] == 'unordered_map':
+ if env['UNORDERED_MAP_NAMESPACE'] == 'std':
+ defs.append('DEG_STD_UNORDERED_MAP')
+ elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
+ defs.append('DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE')
+ elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
+ defs.append('DEG_TR1_UNORDERED_MAP')
+else:
+ print("-- Replacing unordered_map/set with map/set (warning: slower!)")
+ defs.append('DEG_NO_UNORDERED_MAP')
+
+if env['WITH_BF_LEGACY_DEPSGRAPH']:
+ defs.append('WITH_LEGACY_DEPSGRAPH')
+
+env.BlenderLib(libname='bf_depsgraph', sources=sources,
+ includes=incs, defines=defs,
+ libtype=['core', 'player'], priority=[200, 40])
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
new file mode 100644
index 00000000000..e9b2a06cf7b
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -0,0 +1,473 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph.cc
+ * \ingroup depsgraph
+ *
+ * Core routines for how the Depsgraph works.
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+
+extern "C" {
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_sequence_types.h"
+
+#include "RNA_access.h"
+}
+
+#include "DEG_depsgraph.h"
+#include "depsgraph.h" /* own include */
+#include "depsnode.h"
+#include "depsnode_operation.h"
+#include "depsnode_component.h"
+#include "depsgraph_intern.h"
+
+static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL;
+static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL;
+
+Depsgraph::Depsgraph()
+ : root_node(NULL),
+ need_update(false),
+ layers((1 << 20) - 1)
+{
+ BLI_spin_init(&lock);
+}
+
+Depsgraph::~Depsgraph()
+{
+ /* Free root node - it won't have been freed yet... */
+ clear_id_nodes();
+ clear_subgraph_nodes();
+ if (this->root_node != NULL) {
+ OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
+ }
+ BLI_spin_end(&lock);
+}
+
+/* Query Conditions from RNA ----------------------- */
+
+static bool pointer_to_id_node_criteria(const PointerRNA *ptr,
+ const PropertyRNA *prop,
+ ID **id)
+{
+ if (!ptr->type)
+ return false;
+
+ if (!prop) {
+ if (RNA_struct_is_ID(ptr->type)) {
+ *id = (ID *)ptr->data;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
+ const PropertyRNA *prop,
+ ID **id,
+ eDepsNode_Type *type,
+ string *subdata)
+{
+ if (!ptr->type)
+ return false;
+
+ /* Set default values for returns. */
+ *id = (ID *)ptr->id.data; /* For obvious reasons... */
+ *subdata = ""; /* Default to no subdata (e.g. bone) name
+ * lookup in most cases. */
+
+ /* Handling of commonly known scenarios... */
+ if (ptr->type == &RNA_PoseBone) {
+ bPoseChannel *pchan = (bPoseChannel *)ptr->data;
+
+ /* Bone - generally, we just want the bone component... */
+ *type = DEPSNODE_TYPE_BONE;
+ *subdata = pchan->name;
+
+ return true;
+ }
+ else if (ptr->type == &RNA_Bone) {
+ Bone *bone = (Bone *)ptr->data;
+
+ /* armature-level bone, but it ends up going to bone component anyway */
+ // TODO: the ID in thise case will end up being bArmature, not Object as needed!
+ *type = DEPSNODE_TYPE_BONE;
+ *subdata = bone->name;
+ //*id = ...
+
+ return true;
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
+ Object *ob = (Object *)ptr->id.data;
+ bConstraint *con = (bConstraint *)ptr->data;
+
+ /* object or bone? */
+ if (BLI_findindex(&ob->constraints, con) != -1) {
+ /* object transform */
+ // XXX: for now, we can't address the specific constraint or the constraint stack...
+ *type = DEPSNODE_TYPE_TRANSFORM;
+ return true;
+ }
+ else if (ob->pose) {
+ bPoseChannel *pchan;
+ for (pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (BLI_findindex(&pchan->constraints, con) != -1) {
+ /* bone transforms */
+ *type = DEPSNODE_TYPE_BONE;
+ *subdata = pchan->name;
+ return true;
+ }
+ }
+ }
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
+ //ModifierData *md = (ModifierData *)ptr->data;
+
+ /* Modifier */
+ /* NOTE: subdata is not the same as "operation name",
+ * so although we have unique ops for modifiers,
+ * we can't lump them together
+ */
+ *type = DEPSNODE_TYPE_BONE;
+ //*subdata = md->name;
+
+ return true;
+ }
+ else if (ptr->type == &RNA_Object) {
+ //Object *ob = (Object *)ptr->data;
+
+ /* Transforms props? */
+ if (prop) {
+ const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
+
+ if (strstr(prop_identifier, "location") ||
+ strstr(prop_identifier, "rotation") ||
+ strstr(prop_identifier, "scale"))
+ {
+ *type = DEPSNODE_TYPE_TRANSFORM;
+ return true;
+ }
+ }
+ // ...
+ }
+ else if (ptr->type == &RNA_ShapeKey) {
+ Key *key = (Key *)ptr->id.data;
+
+ /* ShapeKeys are currently handled as geometry on the geometry that owns it */
+ *id = key->from; // XXX
+ *type = DEPSNODE_TYPE_PARAMETERS;
+
+ return true;
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
+ Sequence *seq = (Sequence *)ptr->data;
+ /* Sequencer strip */
+ *type = DEPSNODE_TYPE_SEQUENCER;
+ *subdata = seq->name; // xxx?
+ return true;
+ }
+
+ if (prop) {
+ /* All unknown data effectively falls under "parameter evaluation" */
+ *type = DEPSNODE_TYPE_PARAMETERS;
+ return true;
+ }
+
+ return false;
+}
+
+/* Convenience wrapper to find node given just pointer + property. */
+DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr,
+ const PropertyRNA *prop) const
+{
+ ID *id;
+ eDepsNode_Type type;
+ string name;
+
+ /* Get querying conditions. */
+ if (pointer_to_id_node_criteria(ptr, prop, &id)) {
+ return find_id_node(id);
+ }
+ else if (pointer_to_component_node_criteria(ptr, prop, &id, &type, &name)) {
+ IDDepsNode *id_node = find_id_node(id);
+ if (id_node)
+ return id_node->find_component(type, name);
+ }
+
+ return NULL;
+}
+
+/* Node Management ---------------------------- */
+
+RootDepsNode *Depsgraph::add_root_node()
+{
+ if (!root_node) {
+ DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_ROOT);
+ root_node = (RootDepsNode *)factory->create_node(NULL, "", "Root (Scene)");
+ }
+ return root_node;
+}
+
+TimeSourceDepsNode *Depsgraph::find_time_source(const ID *id) const
+{
+ /* Search for one attached to a particular ID? */
+ if (id) {
+ /* Check if it was added as a component
+ * (as may be done for subgraphs needing timeoffset).
+ */
+ IDDepsNode *id_node = find_id_node(id);
+ if (id_node) {
+ // XXX: review this
+// return id_node->find_component(DEPSNODE_TYPE_TIMESOURCE);
+ }
+ BLI_assert(!"Not implemented yet");
+ }
+ else {
+ /* Use "official" timesource. */
+ return root_node->time_source;
+ }
+ return NULL;
+}
+
+SubgraphDepsNode *Depsgraph::add_subgraph_node(const ID *id)
+{
+ DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_SUBGRAPH);
+ SubgraphDepsNode *subgraph_node =
+ (SubgraphDepsNode *)factory->create_node(id, "", id->name + 2);
+
+ /* Add to subnodes list. */
+ this->subgraphs.insert(subgraph_node);
+
+ /* if there's an ID associated, add to ID-nodes lookup too */
+ if (id) {
+#if 0
+ /* XXX subgraph node is NOT a true IDDepsNode - what is this supposed to do? */
+ // TODO: what to do if subgraph's ID has already been added?
+ BLI_assert(!graph->find_id_node(id));
+ graph->id_hash[id] = this;
+#endif
+ }
+
+ return subgraph_node;
+}
+
+void Depsgraph::remove_subgraph_node(SubgraphDepsNode *subgraph_node)
+{
+ subgraphs.erase(subgraph_node);
+ OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
+}
+
+void Depsgraph::clear_subgraph_nodes()
+{
+ for (Subgraphs::iterator it = subgraphs.begin();
+ it != subgraphs.end();
+ ++it)
+ {
+ SubgraphDepsNode *subgraph_node = *it;
+ OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
+ }
+ subgraphs.clear();
+}
+
+IDDepsNode *Depsgraph::find_id_node(const ID *id) const
+{
+ IDNodeMap::const_iterator it = this->id_hash.find(id);
+ return it != this->id_hash.end() ? it->second : NULL;
+}
+
+IDDepsNode *Depsgraph::add_id_node(ID *id, const string &name)
+{
+ IDDepsNode *id_node = find_id_node(id);
+ if (!id_node) {
+ DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_ID_REF);
+ id_node = (IDDepsNode *)factory->create_node(id, "", name);
+ id->flag |= LIB_DOIT;
+ /* register */
+ this->id_hash[id] = id_node;
+ }
+ return id_node;
+}
+
+void Depsgraph::remove_id_node(const ID *id)
+{
+ IDDepsNode *id_node = find_id_node(id);
+ if (id_node) {
+ /* unregister */
+ this->id_hash.erase(id);
+ OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
+ }
+}
+
+void Depsgraph::clear_id_nodes()
+{
+ for (IDNodeMap::const_iterator it = id_hash.begin();
+ it != id_hash.end();
+ ++it)
+ {
+ IDDepsNode *id_node = it->second;
+ OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
+ }
+ id_hash.clear();
+}
+
+/* Add new relationship between two nodes. */
+DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from,
+ OperationDepsNode *to,
+ eDepsRelation_Type type,
+ const char *description)
+{
+ /* Create new relation, and add it to the graph. */
+ DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, type, description);
+ return rel;
+}
+
+/* Add new relation between two nodes */
+DepsRelation *Depsgraph::add_new_relation(DepsNode *from, DepsNode *to,
+ eDepsRelation_Type type,
+ const char *description)
+{
+ /* Create new relation, and add it to the graph. */
+ DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, type, description);
+ return rel;
+}
+
+/* ************************ */
+/* Relationships Management */
+
+DepsRelation::DepsRelation(DepsNode *from,
+ DepsNode *to,
+ eDepsRelation_Type type,
+ const char *description)
+ : from(from),
+ to(to),
+ name(description),
+ type(type),
+ flag(0)
+{
+#ifndef NDEBUG
+/*
+ for (OperationDepsNode::Relations::const_iterator it = from->outlinks.begin();
+ it != from->outlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+ if (rel->from == from &&
+ rel->to == to &&
+ rel->type == type &&
+ rel->name == description)
+ {
+ BLI_assert(!"Duplicated relation, should not happen!");
+ }
+ }
+*/
+#endif
+
+ /* Hook it up to the nodes which use it. */
+ from->outlinks.insert(this);
+ to->inlinks.insert(this);
+}
+
+DepsRelation::~DepsRelation()
+{
+ /* Sanity check. */
+ BLI_assert(this->from && this->to);
+ /* Remove it from the nodes that use it. */
+ this->from->outlinks.erase(this);
+ this->to->inlinks.erase(this);
+}
+
+/* Low level tagging -------------------------------------- */
+
+/* Tag a specific node as needing updates. */
+void Depsgraph::add_entry_tag(OperationDepsNode *node)
+{
+ /* Sanity check. */
+ if (!node)
+ return;
+
+ /* Add to graph-level set of directly modified nodes to start searching from.
+ * NOTE: this is necessary since we have several thousand nodes to play with...
+ */
+ this->entry_tags.insert(node);
+}
+
+void Depsgraph::clear_all_nodes()
+{
+ clear_id_nodes();
+ clear_subgraph_nodes();
+ id_hash.clear();
+ if (this->root_node) {
+ OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
+ root_node = NULL;
+ }
+}
+
+/* **************** */
+/* Public Graph API */
+
+/* Initialize a new Depsgraph */
+Depsgraph *DEG_graph_new()
+{
+ return OBJECT_GUARDED_NEW(Depsgraph);
+}
+
+/* Free graph's contents and graph itself */
+void DEG_graph_free(Depsgraph *graph)
+{
+ OBJECT_GUARDED_DELETE(graph, Depsgraph);
+}
+
+/* Set callbacks which are being called when depsgraph changes. */
+void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
+ DEG_EditorUpdateSceneCb scene_func)
+{
+ deg_editor_update_id_cb = id_func;
+ deg_editor_update_scene_cb = scene_func;
+}
+
+void deg_editors_id_update(Main *bmain, ID *id)
+{
+ if (deg_editor_update_id_cb != NULL) {
+ deg_editor_update_id_cb(bmain, id);
+ }
+}
+
+void deg_editors_scene_update(Main *bmain, Scene *scene, bool updated)
+{
+ if (deg_editor_update_scene_cb != NULL) {
+ deg_editor_update_scene_cb(bmain, scene, updated);
+ }
+}
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
new file mode 100644
index 00000000000..9533fbd10d5
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -0,0 +1,224 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph.h
+ * \ingroup depsgraph
+ *
+ * Datatypes for internal use in the Depsgraph
+ *
+ * All of these datatypes are only really used within the "core" depsgraph.
+ * In particular, node types declared here form the structure of operations
+ * in the graph.
+ */
+
+#ifndef __DEPSGRAPH_H__
+#define __DEPSGRAPH_H__
+
+#include "BLI_threads.h" /* for SpinLock */
+
+#include "depsgraph_types.h"
+
+#include "depsgraph_util_map.h"
+#include "depsgraph_util_set.h"
+
+struct PointerRNA;
+struct PropertyRNA;
+
+struct DepsNode;
+struct RootDepsNode;
+struct TimeSourceDepsNode;
+struct IDDepsNode;
+struct SubgraphDepsNode;
+struct ComponentDepsNode;
+struct OperationDepsNode;
+
+/* *************************** */
+/* Relationships Between Nodes */
+
+/* Settings/Tags on Relationship */
+typedef enum eDepsRelation_Flag {
+ /* "touched" tag is used when filtering, to know which to collect */
+ DEPSREL_FLAG_TEMP_TAG = (1 << 0),
+
+ /* "cyclic" link - when detecting cycles, this relationship was the one
+ * which triggers a cyclic relationship to exist in the graph
+ */
+ DEPSREL_FLAG_CYCLIC = (1 << 1),
+} eDepsRelation_Flag;
+
+/* B depends on A (A -> B) */
+struct DepsRelation {
+ /* the nodes in the relationship (since this is shared between the nodes) */
+ DepsNode *from; /* A */
+ DepsNode *to; /* B */
+
+ /* relationship attributes */
+ const char *name; /* label for debugging */
+
+ eDepsRelation_Type type; /* type */
+ int flag; /* (eDepsRelation_Flag) */
+
+ DepsRelation(DepsNode *from,
+ DepsNode *to,
+ eDepsRelation_Type type,
+ const char *description);
+
+ ~DepsRelation();
+};
+
+/* ********* */
+/* Depsgraph */
+
+/* Dependency Graph object */
+struct Depsgraph {
+ typedef unordered_map<const ID *, IDDepsNode *> IDNodeMap;
+ typedef unordered_set<SubgraphDepsNode *> Subgraphs;
+ typedef unordered_set<OperationDepsNode *> EntryTags;
+ typedef vector<OperationDepsNode *> OperationNodes;
+
+ Depsgraph();
+ ~Depsgraph();
+
+ /**
+ * Find node which matches the specified description.
+ *
+ * \param id: ID block that is associated with this
+ * \param subdata: identifier used for sub-ID data (e.g. bone)
+ * \param type: type of node we're dealing with
+ * \param name: custom identifier assigned to node
+ *
+ * \return A node matching the required characteristics if it exists
+ * or NULL if no such node exists in the graph.
+ */
+ DepsNode *find_node(const ID *id,
+ eDepsNode_Type type,
+ const string &subdata,
+ const string &name);
+
+ /**
+ * Convenience wrapper to find node given just pointer + property.
+ *
+ * \param ptr: pointer to the data that node will represent
+ * \param prop: optional property affected - providing this effectively results in inner nodes being returned
+ *
+ * \return A node matching the required characteristics if it exists
+ * or NULL if no such node exists in the graph
+ */
+ DepsNode *find_node_from_pointer(const PointerRNA *ptr, const PropertyRNA *prop) const;
+
+ RootDepsNode *add_root_node();
+
+ TimeSourceDepsNode *find_time_source(const ID *id = NULL) const;
+
+ SubgraphDepsNode *add_subgraph_node(const ID *id);
+ void remove_subgraph_node(SubgraphDepsNode *subgraph_node);
+ void clear_subgraph_nodes();
+
+ IDDepsNode *find_id_node(const ID *id) const;
+ IDDepsNode *add_id_node(ID *id, const string &name = "");
+ void remove_id_node(const ID *id);
+ void clear_id_nodes();
+
+ /* Add new relationship between two nodes. */
+ DepsRelation *add_new_relation(OperationDepsNode *from,
+ OperationDepsNode *to,
+ eDepsRelation_Type type,
+ const char *description);
+
+ DepsRelation *add_new_relation(DepsNode *from,
+ DepsNode *to,
+ eDepsRelation_Type type,
+ const char *description);
+
+ /* Tag a specific node as needing updates. */
+ void add_entry_tag(OperationDepsNode *node);
+
+ /* Clear storage used by all nodes. */
+ void clear_all_nodes();
+
+ /* Core Graph Functionality ........... */
+
+ /* <ID : IDDepsNode> mapping from ID blocks to nodes representing these blocks
+ * (for quick lookups). */
+ IDNodeMap id_hash;
+
+ /* "root" node - the one where all evaluation enters from. */
+ RootDepsNode *root_node;
+
+ /* Subgraphs referenced in tree. */
+ Subgraphs subgraphs;
+
+ /* Indicates whether relations needs to be updated. */
+ bool need_update;
+
+ /* Quick-Access Temp Data ............. */
+
+ /* Nodes which have been tagged as "directly modified". */
+ EntryTags entry_tags;
+
+ /* Convenience Data ................... */
+
+ /* XXX: should be collected after building (if actually needed?) */
+ /* All operation nodes, sorted in order of single-thread traversal order. */
+ OperationNodes operations;
+
+ /* Spin lock for threading-critical operations.
+ * Mainly used by graph evaluation.
+ */
+ SpinLock lock;
+
+ /* Layers Visibility .................. */
+
+ /* Visible layers bitfield, used for skipping invisible objects updates. */
+ int layers;
+
+ // XXX: additional stuff like eval contexts, mempools for allocating nodes from, etc.
+};
+
+/**
+ * Helper macros for iterating over set of relationship links
+ * incident on each node.
+ *
+ * \note it is safe to perform removal operations here...
+ *
+ * relations_set[in]: (DepsNode::Relations) set of relationships (in/out links)
+ * relation[out]: (DepsRelation *) identifier where DepsRelation that we're
+ * currently accessing comes up
+ */
+#define DEPSNODE_RELATIONS_ITER_BEGIN(relations_set_, relation_) \
+ { \
+ OperationDepsNode::Relations::const_iterator __rel_iter = relations_set_.begin(); \
+ while (__rel_iter != relations_set_.end()) { \
+ DepsRelation *relation_ = *__rel_iter; \
+ ++__rel_iter; \
+
+ /* ... code for iterator body can be written here ... */
+
+#define DEPSNODE_RELATIONS_ITER_END \
+ } \
+ } ((void)0)
+
+#endif /* __DEPSGRAPH_H__ */
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
new file mode 100644
index 00000000000..7a2ee2c416a
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -0,0 +1,370 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_build.cc
+ * \ingroup depsgraph
+ *
+ * Methods for constructing depsgraph.
+ */
+
+#include <stack>
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_blenlib.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_group_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_node_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_object_types.h"
+#include "DNA_rigidbody_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_animsys.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_effect.h"
+#include "BKE_fcurve.h"
+#include "BKE_group.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mball.h"
+#include "BKE_modifier.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_rigidbody.h"
+#include "BKE_sound.h"
+#include "BKE_texture.h"
+#include "BKE_tracking.h"
+#include "BKE_world.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_build.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+} /* extern "C" */
+
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsgraph_debug.h"
+#include "depsnode_operation.h"
+#include "depsgraph_types.h"
+#include "depsgraph_build.h"
+#include "depsgraph_intern.h"
+
+#include "depsgraph_util_cycle.h"
+#include "depsgraph_util_transitive.h"
+
+/* ****************** */
+/* External Build API */
+
+static eDepsNode_Type deg_build_scene_component_type(eDepsSceneComponentType component)
+{
+ switch (component) {
+ case DEG_SCENE_COMP_PARAMETERS: return DEPSNODE_TYPE_PARAMETERS;
+ case DEG_SCENE_COMP_ANIMATION: return DEPSNODE_TYPE_ANIMATION;
+ case DEG_SCENE_COMP_SEQUENCER: return DEPSNODE_TYPE_SEQUENCER;
+ }
+ return DEPSNODE_TYPE_UNDEFINED;
+}
+
+static eDepsNode_Type deg_build_object_component_type(eDepsObjectComponentType component)
+{
+ switch (component) {
+ case DEG_OB_COMP_PARAMETERS: return DEPSNODE_TYPE_PARAMETERS;
+ case DEG_OB_COMP_PROXY: return DEPSNODE_TYPE_PROXY;
+ case DEG_OB_COMP_ANIMATION: return DEPSNODE_TYPE_ANIMATION;
+ case DEG_OB_COMP_TRANSFORM: return DEPSNODE_TYPE_TRANSFORM;
+ case DEG_OB_COMP_GEOMETRY: return DEPSNODE_TYPE_GEOMETRY;
+ case DEG_OB_COMP_EVAL_POSE: return DEPSNODE_TYPE_EVAL_POSE;
+ case DEG_OB_COMP_BONE: return DEPSNODE_TYPE_BONE;
+ case DEG_OB_COMP_EVAL_PARTICLES: return DEPSNODE_TYPE_EVAL_PARTICLES;
+ case DEG_OB_COMP_SHADING: return DEPSNODE_TYPE_SHADING;
+ }
+ return DEPSNODE_TYPE_UNDEFINED;
+}
+
+void DEG_add_scene_relation(DepsNodeHandle *handle, struct Scene *scene, eDepsSceneComponentType component, const char *description)
+{
+ eDepsNode_Type type = deg_build_scene_component_type(component);
+ ComponentKey comp_key(&scene->id, type);
+ handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+}
+
+void DEG_add_object_relation(DepsNodeHandle *handle, struct Object *ob, eDepsObjectComponentType component, const char *description)
+{
+ eDepsNode_Type type = deg_build_object_component_type(component);
+ ComponentKey comp_key(&ob->id, type);
+ handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+}
+
+void DEG_add_bone_relation(DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description)
+{
+ eDepsNode_Type type = deg_build_object_component_type(component);
+ ComponentKey comp_key(&ob->id, type, bone_name);
+
+ // XXX: "Geometry Eval" might not always be true, but this only gets called from modifier building now
+ handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+}
+
+void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag)
+{
+ if (graph == NULL) {
+ BLI_assert(!"Graph should always be valid");
+ return;
+ }
+ IDDepsNode *id_node = graph->find_id_node(id);
+ if (id_node == NULL) {
+ BLI_assert(!"ID should always be valid");
+ return;
+ }
+ id_node->eval_flags |= flag;
+}
+
+/* ********************** */
+/* Utilities for Builders */
+
+/* Get unique identifier for FCurves and Drivers */
+string deg_fcurve_id_name(const FCurve *fcu)
+{
+ char index_buf[32];
+ sprintf(index_buf, "[%d]", fcu->array_index);
+
+ return string(fcu->rna_path) + index_buf;
+}
+
+static void deg_graph_build_finalize(Depsgraph *graph)
+{
+ std::stack<OperationDepsNode *> stack;
+
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ node->done = 0;
+ node->num_links_pending = 0;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
+ it_rel != node->inlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if ((rel->from->type == DEPSNODE_TYPE_OPERATION) &&
+ (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
+ {
+ ++node->num_links_pending;
+ }
+ }
+ if (node->num_links_pending == 0) {
+ stack.push(node);
+ }
+ IDDepsNode *id_node = node->owner->owner;
+ id_node->id->flag |= LIB_DOIT;
+ }
+
+ while (!stack.empty()) {
+ OperationDepsNode *node = stack.top();
+ if (node->done == 0 && node->outlinks.size() != 0) {
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
+ it_rel != node->outlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
+ BLI_assert(to->num_links_pending > 0);
+ --to->num_links_pending;
+ }
+ if (to->num_links_pending == 0) {
+ stack.push(to);
+ }
+ }
+ }
+ node->done = 1;
+ }
+ else {
+ stack.pop();
+ IDDepsNode *id_node = node->owner->owner;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
+ it_rel != node->outlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ IDDepsNode *id_to = to->owner->owner;
+ id_node->layers |= id_to->layers;
+ }
+ }
+
+ /* Re-tag ID for update if it was tagged before the relations
+ * update tag.
+ */
+ ID *id = id_node->id;
+ if (id->flag & LIB_ID_RECALC_ALL &&
+ id->flag & LIB_DOIT)
+ {
+ id_node->tag_update(graph);
+ id->flag &= ~LIB_DOIT;
+ }
+ }
+ }
+}
+
+/* ******************** */
+/* Graph Building API's */
+
+/* Build depsgraph for the given scene, and dump results in given graph container */
+// XXX: assume that this is called from outside, given the current scene as the "main" scene
+void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
+{
+ /* 1) Generate all the nodes in the graph first */
+ DepsgraphNodeBuilder node_builder(bmain, graph);
+ /* create root node for scene first
+ * - this way it should be the first in the graph,
+ * reflecting its role as the entrypoint
+ */
+ node_builder.add_root_node();
+ node_builder.build_scene(bmain, scene);
+
+ /* 2) Hook up relationships between operations - to determine evaluation order */
+ DepsgraphRelationBuilder relation_builder(graph);
+ /* hook scene up to the root node as entrypoint to graph */
+ /* XXX what does this relation actually mean?
+ * it doesnt add any operations anyway and is not clear what part of the scene is to be connected.
+ */
+ //relation_builder.add_relation(RootKey(), IDKey(scene), DEPSREL_TYPE_ROOT_TO_ACTIVE, "Root to Active Scene");
+ relation_builder.build_scene(bmain, scene);
+
+ /* Detect and solve cycles. */
+ deg_graph_detect_cycles(graph);
+
+ /* 3) Simplify the graph by removing redundant relations (to optimise traversal later) */
+ // TODO: it would be useful to have an option to disable this in cases where it is causing trouble
+ if (G.debug_value == 799) {
+ deg_graph_transitive_reduction(graph);
+ }
+
+ /* 4) Flush visibility layer and re-schedule nodes for update. */
+ deg_graph_build_finalize(graph);
+
+#if 0
+ if (!DEG_debug_consistency_check(graph)) {
+ printf("Consistency validation failed, ABORTING!\n");
+ abort();
+ }
+#endif
+}
+
+/* Tag graph relations for update. */
+void DEG_graph_tag_relations_update(Depsgraph *graph)
+{
+ graph->need_update = true;
+}
+
+/* Tag all relations for update. */
+void DEG_relations_tag_update(Main *bmain)
+{
+ for (Scene *scene = (Scene *)bmain->scene.first;
+ scene != NULL;
+ scene = (Scene *)scene->id.next)
+ {
+ if (scene->depsgraph != NULL) {
+ DEG_graph_tag_relations_update(scene->depsgraph);
+ }
+ }
+}
+
+/* Create new graph if didn't exist yet,
+ * or update relations if graph was tagged for update.
+ */
+void DEG_scene_relations_update(Main *bmain, Scene *scene)
+{
+ if (scene->depsgraph == NULL) {
+ /* Rebuild graph from scratch and exit. */
+ scene->depsgraph = DEG_graph_new();
+ DEG_graph_build_from_scene(scene->depsgraph, bmain, scene);
+ return;
+ }
+
+ Depsgraph *graph = scene->depsgraph;
+ if (!graph->need_update) {
+ /* Graph is up to date, nothing to do. */
+ return;
+ }
+
+ /* Clear all previous nodes and operations. */
+ graph->clear_all_nodes();
+ graph->operations.clear();
+ graph->entry_tags.clear();
+
+ /* Build new nodes and relations. */
+ DEG_graph_build_from_scene(graph, bmain, scene);
+
+ graph->need_update = false;
+}
+
+/* Rebuild dependency graph only for a given scene. */
+void DEG_scene_relations_rebuild(Main *bmain, Scene *scene)
+{
+ if (scene->depsgraph != NULL) {
+ DEG_graph_tag_relations_update(scene->depsgraph);
+ }
+ DEG_scene_relations_update(bmain, scene);
+}
+
+void DEG_scene_graph_free(Scene *scene)
+{
+ if (scene->depsgraph) {
+ DEG_graph_free(scene->depsgraph);
+ scene->depsgraph = NULL;
+ }
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_build.h b/source/blender/depsgraph/intern/depsgraph_build.h
new file mode 100644
index 00000000000..4088a3289ef
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_build.h
@@ -0,0 +1,408 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_build.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_BUILD_H__
+#define __DEPSGRAPH_BUILD_H__
+
+struct Base;
+struct bGPdata;
+struct ListBase;
+struct GHash;
+struct ID;
+struct FCurve;
+struct Group;
+struct Key;
+struct Main;
+struct Material;
+struct MTex;
+struct bNodeTree;
+struct Object;
+struct bPoseChannel;
+struct bConstraint;
+struct Scene;
+struct Tex;
+struct World;
+
+struct PropertyRNA;
+
+struct Depsgraph;
+struct DepsNode;
+struct DepsNodeHandle;
+struct RootDepsNode;
+struct SubgraphDepsNode;
+struct IDDepsNode;
+struct TimeSourceDepsNode;
+struct ComponentDepsNode;
+struct OperationDepsNode;
+struct RootPChanMap;
+
+struct DepsgraphNodeBuilder {
+ DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph);
+ ~DepsgraphNodeBuilder();
+
+ RootDepsNode *add_root_node();
+ IDDepsNode *add_id_node(ID *id);
+ TimeSourceDepsNode *add_time_source(ID *id);
+
+ ComponentDepsNode *add_component_node(ID *id, eDepsNode_Type comp_type, const string &comp_name = "");
+
+ OperationDepsNode *add_operation_node(ComponentDepsNode *comp_node, eDepsOperation_Type optype,
+ DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "");
+ OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, const string &comp_name, eDepsOperation_Type optype,
+ DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "");
+ OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, eDepsOperation_Type optype,
+ DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "")
+ {
+ return add_operation_node(id, comp_type, "", optype, op, opcode, description);
+ }
+
+ bool has_operation_node(ID *id, eDepsNode_Type comp_type, const string &comp_name,
+ eDepsOperation_Code opcode, const string &description = "");
+
+ OperationDepsNode *find_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name,
+ eDepsOperation_Code opcode,
+ const string &description = "");
+
+ OperationDepsNode *find_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ eDepsOperation_Code opcode,
+ const string &description = "")
+ {
+ return find_operation_node(id, comp_type, "", opcode, description);
+ }
+
+ void build_scene(Main *bmain, Scene *scene);
+ SubgraphDepsNode *build_subgraph(Group *group);
+ void build_group(Scene *scene, Base *base, Group *group);
+ void build_object(Scene *scene, Base *base, Object *ob);
+ void build_object_transform(Scene *scene, Object *ob);
+ void build_object_constraints(Scene *scene, Object *ob);
+ void build_pose_constraints(Object *ob, bPoseChannel *pchan);
+ void build_rigidbody(Scene *scene);
+ void build_particles(Object *ob);
+ void build_animdata(ID *id);
+ OperationDepsNode *build_driver(ID *id, FCurve *fcurve);
+ void build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con);
+ void build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con);
+ void build_rig(Scene *scene, Object *ob);
+ void build_proxy_rig(Object *ob);
+ void build_shapekeys(Key *key);
+ void build_obdata_geom(Scene *scene, Object *ob);
+ void build_camera(Object *ob);
+ void build_lamp(Object *ob);
+ void build_nodetree(DepsNode *owner_node, bNodeTree *ntree);
+ void build_material(DepsNode *owner_node, Material *ma);
+ void build_texture(DepsNode *owner_node, Tex *tex);
+ void build_texture_stack(DepsNode *owner_node, MTex **texture_stack);
+ void build_world(World *world);
+ void build_compositor(Scene *scene);
+ void build_gpencil(bGPdata *gpd);
+
+private:
+ Main *m_bmain;
+ Depsgraph *m_graph;
+};
+
+struct RootKey
+{
+ RootKey() {}
+};
+
+struct TimeSourceKey
+{
+ TimeSourceKey() : id(NULL) {}
+ TimeSourceKey(ID *id) : id(id) {}
+
+ string identifier() const
+ {
+ return string("TimeSourceKey");
+ }
+
+ ID *id;
+};
+
+struct ComponentKey
+{
+ ComponentKey() :
+ id(NULL), type(DEPSNODE_TYPE_UNDEFINED), name("")
+ {}
+ ComponentKey(ID *id, eDepsNode_Type type, const string &name = "") :
+ id(id), type(type), name(name)
+ {}
+
+ string identifier() const
+ {
+ const char *idname = (id) ? id->name : "<None>";
+
+ char typebuf[5];
+ sprintf(typebuf, "%d", type);
+
+ return string("ComponentKey(") + idname + ", " + typebuf + ", '" + name + "')";
+ }
+
+ ID *id;
+ eDepsNode_Type type;
+ string name;
+};
+
+struct OperationKey
+{
+ OperationKey() :
+ id(NULL), component_type(DEPSNODE_TYPE_UNDEFINED), component_name(""), opcode(DEG_OPCODE_OPERATION), name("")
+ {}
+
+ OperationKey(ID *id, eDepsNode_Type component_type, const string &name) :
+ id(id), component_type(component_type), component_name(""), opcode(DEG_OPCODE_OPERATION), name(name)
+ {}
+ OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, const string &name) :
+ id(id), component_type(component_type), component_name(component_name), opcode(DEG_OPCODE_OPERATION), name(name)
+ {}
+
+ OperationKey(ID *id, eDepsNode_Type component_type, eDepsOperation_Code opcode) :
+ id(id), component_type(component_type), component_name(""), opcode(opcode), name("")
+ {}
+ OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, eDepsOperation_Code opcode) :
+ id(id), component_type(component_type), component_name(component_name), opcode(opcode), name("")
+ {}
+
+ OperationKey(ID *id, eDepsNode_Type component_type, eDepsOperation_Code opcode, const string &name) :
+ id(id), component_type(component_type), component_name(""), opcode(opcode), name(name)
+ {}
+ OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, eDepsOperation_Code opcode, const string &name) :
+ id(id), component_type(component_type), component_name(component_name), opcode(opcode), name(name)
+ {}
+
+ string identifier() const
+ {
+ char typebuf[5];
+ sprintf(typebuf, "%d", component_type);
+
+ return string("OperationKey(") + "t: " + typebuf + ", cn: '" + component_name + "', c: " + DEG_OPNAMES[opcode] + ", n: '" + name + "')";
+ }
+
+
+ ID *id;
+ eDepsNode_Type component_type;
+ string component_name;
+ eDepsOperation_Code opcode;
+ string name;
+};
+
+struct RNAPathKey
+{
+ // Note: see depsgraph_build.cpp for implementation
+ RNAPathKey(ID *id, const char *path);
+
+ RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop) :
+ id(id), ptr(ptr), prop(prop)
+ {}
+
+ string identifier() const
+ {
+ const char *id_name = (id) ? id->name : "<No ID>";
+ const char *prop_name = (prop) ? RNA_property_identifier(prop) : "<No Prop>";
+
+ return string("RnaPathKey(") + "id: " + id_name + ", prop: " + prop_name + "')";
+ }
+
+
+ ID *id;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+};
+
+struct DepsgraphRelationBuilder
+{
+ DepsgraphRelationBuilder(Depsgraph *graph);
+
+ template <typename KeyFrom, typename KeyTo>
+ void add_relation(const KeyFrom &key_from, const KeyTo &key_to,
+ eDepsRelation_Type type, const char *description);
+
+ template <typename KeyTo>
+ void add_relation(const TimeSourceKey &key_from, const KeyTo &key_to,
+ eDepsRelation_Type type, const char *description);
+
+ template <typename KeyType>
+ void add_node_handle_relation(const KeyType &key_from, const DepsNodeHandle *handle,
+ eDepsRelation_Type type, const char *description);
+
+ void build_scene(Main *bmain, Scene *scene);
+ void build_group(Main *bmain, Scene *scene, Object *object, Group *group);
+ void build_object(Main *bmain, Scene *scene, Object *ob);
+ void build_object_parent(Object *ob);
+ void build_constraints(Scene *scene, ID *id, eDepsNode_Type component_type, const char *component_subdata,
+ ListBase *constraints, RootPChanMap *root_map);
+ void build_animdata(ID *id);
+ void build_driver(ID *id, FCurve *fcurve);
+ void build_world(World *world);
+ void build_rigidbody(Scene *scene);
+ void build_particles(Scene *scene, Object *ob);
+ void build_ik_pose(Object *ob, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map);
+ void build_splineik_pose(Object *ob, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map);
+ void build_rig(Scene *scene, Object *ob);
+ void build_proxy_rig(Object *ob);
+ void build_shapekeys(ID *obdata, Key *key);
+ void build_obdata_geom(Main *bmain, Scene *scene, Object *ob);
+ void build_camera(Object *ob);
+ void build_lamp(Object *ob);
+ void build_nodetree(ID *owner, bNodeTree *ntree);
+ void build_material(ID *owner, Material *ma);
+ void build_texture(ID *owner, Tex *tex);
+ void build_texture_stack(ID *owner, MTex **texture_stack);
+ void build_compositor(Scene *scene);
+ void build_gpencil(ID *owner, bGPdata *gpd);
+
+protected:
+ RootDepsNode *find_node(const RootKey &key) const;
+ TimeSourceDepsNode *find_node(const TimeSourceKey &key) const;
+ ComponentDepsNode *find_node(const ComponentKey &key) const;
+ OperationDepsNode *find_node(const OperationKey &key) const;
+ DepsNode *find_node(const RNAPathKey &key) const;
+ OperationDepsNode *has_node(const OperationKey &key) const;
+
+ void add_time_relation(TimeSourceDepsNode *timesrc, DepsNode *node_to, const char *description);
+ void add_operation_relation(OperationDepsNode *node_from, OperationDepsNode *node_to,
+ eDepsRelation_Type type, const char *description);
+
+ template <typename KeyType>
+ DepsNodeHandle create_node_handle(const KeyType &key, const string &default_name = "");
+
+ bool needs_animdata_node(ID *id);
+
+private:
+ Depsgraph *m_graph;
+};
+
+struct DepsNodeHandle
+{
+ DepsNodeHandle(DepsgraphRelationBuilder *builder, OperationDepsNode *node, const string &default_name = "") :
+ builder(builder),
+ node(node),
+ default_name(default_name)
+ {
+ BLI_assert(node != NULL);
+ }
+
+ DepsgraphRelationBuilder *builder;
+ OperationDepsNode *node;
+ const string &default_name;
+};
+
+/* Utilities for Builders ----------------------------------------------------- */
+
+/* Get unique identifier for FCurves and Drivers */
+string deg_fcurve_id_name(const FCurve *fcu);
+
+template <typename KeyFrom, typename KeyTo>
+void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
+ const KeyTo &key_to,
+ eDepsRelation_Type type,
+ const char *description)
+{
+ DepsNode *node_from = find_node(key_from);
+ DepsNode *node_to = find_node(key_to);
+ OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
+ OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
+ if (op_from && op_to) {
+ add_operation_relation(op_from, op_to, type, description);
+ }
+ else {
+ if (!op_from) {
+ /* XXX TODO handle as error or report if needed */
+ fprintf(stderr, "add_relation(%d, %s) - Could not find op_from (%s)\n",
+ type, description, key_from.identifier().c_str());
+ }
+ else {
+ fprintf(stderr, "add_relation(%d, %s) - Failed, but op_from (%s) was ok\n",
+ type, description, key_from.identifier().c_str());
+ }
+ if (!op_to) {
+ /* XXX TODO handle as error or report if needed */
+ fprintf(stderr, "add_relation(%d, %s) - Could not find op_to (%s)\n",
+ type, description, key_to.identifier().c_str());
+ }
+ else {
+ fprintf(stderr, "add_relation(%d, %s) - Failed, but op_to (%s) was ok\n",
+ type, description, key_to.identifier().c_str());
+ }
+ }
+}
+
+template <typename KeyTo>
+void DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from,
+ const KeyTo &key_to,
+ eDepsRelation_Type type,
+ const char *description)
+{
+ (void)type; /* Ignored in release builds. */
+ BLI_assert(type == DEPSREL_TYPE_TIME);
+ TimeSourceDepsNode *time_from = find_node(key_from);
+ DepsNode *node_to = find_node(key_to);
+ OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
+ if (time_from && op_to) {
+ add_time_relation(time_from, op_to, description);
+ }
+ else {
+ }
+}
+
+template <typename KeyType>
+void DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_from,
+ const DepsNodeHandle *handle,
+ eDepsRelation_Type type,
+ const char *description)
+{
+ DepsNode *node_from = find_node(key_from);
+ OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
+ OperationDepsNode *op_to = handle->node->get_entry_operation();
+ if (op_from && op_to) {
+ add_operation_relation(op_from, op_to, type, description);
+ }
+ else {
+ if (!op_from) {
+ /* XXX TODO handle as error or report if needed */
+ }
+ if (!op_to) {
+ /* XXX TODO handle as error or report if needed */
+ }
+ }
+}
+
+template <typename KeyType>
+DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(const KeyType &key,
+ const string &default_name)
+{
+ return DepsNodeHandle(this, find_node(key), default_name);
+}
+
+#endif /* __DEPSGRAPH_BUILD_H__ */
diff --git a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc b/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
new file mode 100644
index 00000000000..c9d2ed35e17
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
@@ -0,0 +1,1201 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_build_nodes.cc
+ * \ingroup depsgraph
+ *
+ * Methods for constructing depsgraph's nodes
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_blenlib.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_group_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_node_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_object_types.h"
+#include "DNA_rigidbody_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_animsys.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_effect.h"
+#include "BKE_fcurve.h"
+#include "BKE_idcode.h"
+#include "BKE_group.h"
+#include "BKE_key.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_mball.h"
+#include "BKE_modifier.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_rigidbody.h"
+#include "BKE_sound.h"
+#include "BKE_texture.h"
+#include "BKE_tracking.h"
+#include "BKE_world.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+} /* extern "C" */
+
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_types.h"
+#include "depsgraph_build.h"
+#include "depsgraph_intern.h"
+
+/* ************ */
+/* Node Builder */
+
+/* **** General purpose functions **** */
+
+DepsgraphNodeBuilder::DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph) :
+ m_bmain(bmain),
+ m_graph(graph)
+{
+}
+
+DepsgraphNodeBuilder::~DepsgraphNodeBuilder()
+{
+}
+
+RootDepsNode *DepsgraphNodeBuilder::add_root_node()
+{
+ return m_graph->add_root_node();
+}
+
+IDDepsNode *DepsgraphNodeBuilder::add_id_node(ID *id)
+{
+ const char *idtype_name = BKE_idcode_to_name(GS(id->name));
+ return m_graph->add_id_node(id, string(id->name + 2) + "[" + idtype_name + "]");
+}
+
+TimeSourceDepsNode *DepsgraphNodeBuilder::add_time_source(ID *id)
+{
+ /* determine which node to attach timesource to */
+ if (id) {
+#if 0 /* XXX TODO */
+ /* get ID node */
+ IDDepsNode id_node = m_graph->find_id_node(id);
+
+ /* depends on what this is... */
+ switch (GS(id->name)) {
+ case ID_SCE: /* Scene - Usually sequencer strip causing time remapping... */
+ {
+ // TODO...
+ }
+ break;
+
+ case ID_GR: /* Group */
+ {
+ // TODO...
+ }
+ break;
+
+ // XXX: time source...
+
+ default: /* Unhandled */
+ printf("%s(): Unhandled ID - %s \n", __func__, id->name);
+ break;
+ }
+#endif
+ }
+ else {
+ /* root-node */
+ RootDepsNode *root_node = m_graph->root_node;
+ if (root_node) {
+ return root_node->add_time_source("Time Source");
+ }
+ }
+
+ return NULL;
+}
+
+ComponentDepsNode *DepsgraphNodeBuilder::add_component_node(
+ ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name)
+{
+ IDDepsNode *id_node = add_id_node(id);
+ ComponentDepsNode *comp_node = id_node->add_component(comp_type, comp_name);
+ comp_node->owner = id_node;
+ return comp_node;
+}
+
+OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
+ ComponentDepsNode *comp_node,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string &description)
+{
+ OperationDepsNode *op_node = comp_node->has_operation(opcode, description);
+ if (op_node == NULL) {
+ op_node = comp_node->add_operation(optype, op, opcode, description);
+ m_graph->operations.push_back(op_node);
+ }
+ else {
+ fprintf(stderr, "add_operation: Operation already exists - %s has %s at %p\n",
+ comp_node->identifier().c_str(),
+ op_node->identifier().c_str(),
+ op_node);
+ BLI_assert(!"Should not happen!");
+ }
+ return op_node;
+}
+
+OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
+ ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string &description)
+{
+ ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name);
+ return add_operation_node(comp_node, optype, op, opcode, description);
+}
+
+bool DepsgraphNodeBuilder::has_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name,
+ eDepsOperation_Code opcode,
+ const string &description)
+{
+ return find_operation_node(id, comp_type, comp_name, opcode, description) != NULL;
+}
+
+OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
+ ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name,
+ eDepsOperation_Code opcode,
+ const string &description)
+{
+ ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name);
+ return comp_node->has_operation(opcode, description);
+}
+
+
+/* **** Build functions for entity nodes **** */
+
+void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
+{
+ /* LIB_DOIT is used to indicate whether node for given ID was already
+ * created or not. This flag is being set in add_id_node(), so functions
+ * shouldn't bother with setting it, they only might query this flag when
+ * needed.
+ */
+ BKE_main_id_tag_all(bmain, false);
+
+ /* scene ID block */
+ add_id_node(&scene->id);
+
+ /* timesource */
+ add_time_source(NULL);
+
+ /* build subgraph for set, and link this in... */
+ // XXX: depending on how this goes, that scene itself could probably store its
+ // own little partial depsgraph?
+ if (scene->set) {
+ build_scene(bmain, scene->set);
+ }
+
+ /* scene objects */
+ for (Base *base = (Base *)scene->base.first; base; base = base->next) {
+ Object *ob = base->object;
+
+ /* object itself */
+ build_object(scene, base, ob);
+
+ /* object that this is a proxy for */
+ // XXX: the way that proxies work needs to be completely reviewed!
+ if (ob->proxy) {
+ build_object(scene, base, ob->proxy);
+ }
+
+ /* Object dupligroup. */
+ if (ob->dup_group) {
+ build_group(scene, base, ob->dup_group);
+ }
+ }
+
+ /* rigidbody */
+ if (scene->rigidbody_world) {
+ build_rigidbody(scene);
+ }
+
+ /* scene's animation and drivers */
+ if (scene->adt) {
+ build_animdata(&scene->id);
+ }
+
+ /* world */
+ if (scene->world) {
+ build_world(scene->world);
+ }
+
+ /* compo nodes */
+ if (scene->nodetree) {
+ build_compositor(scene);
+ }
+
+ /* sequencer */
+ // XXX...
+
+ /* grease pencil */
+ if (scene->gpd) {
+ build_gpencil(scene->gpd);
+ }
+}
+
+void DepsgraphNodeBuilder::build_group(Scene *scene,
+ Base *base,
+ Group *group)
+{
+ ID *group_id = &group->id;
+ if (group_id->flag & LIB_DOIT) {
+ return;
+ }
+ group_id->flag |= LIB_DOIT;
+
+ for (GroupObject *go = (GroupObject *)group->gobject.first;
+ go != NULL;
+ go = go->next)
+ {
+ build_object(scene, base, go->ob);
+ }
+}
+
+SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group)
+{
+ /* sanity checks */
+ if (!group)
+ return NULL;
+
+ /* create new subgraph's data */
+ Depsgraph *subgraph = DEG_graph_new();
+
+ DepsgraphNodeBuilder subgraph_builder(m_bmain, subgraph);
+
+ /* add group objects */
+ for (GroupObject *go = (GroupObject *)group->gobject.first;
+ go != NULL;
+ go = go->next)
+ {
+ /*Object *ob = go->ob;*/
+
+ /* Each "group object" is effectively a separate instance of the underlying
+ * object data. When the group is evaluated, the transform results and/or
+ * some other attributes end up getting overridden by the group
+ */
+ }
+
+ /* create a node for representing subgraph */
+ SubgraphDepsNode *subgraph_node = m_graph->add_subgraph_node(&group->id);
+ subgraph_node->graph = subgraph;
+
+ /* make a copy of the data this node will need? */
+ // XXX: do we do this now, or later?
+ // TODO: need API function which queries graph's ID's hash, and duplicates those blocks thoroughly with all outside links removed...
+
+ return subgraph_node;
+}
+
+void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
+{
+ if (ob->id.flag & LIB_DOIT) {
+ IDDepsNode *id_node = m_graph->find_id_node(&ob->id);
+ id_node->layers = base->lay;
+ return;
+ }
+
+ IDDepsNode *id_node = add_id_node(&ob->id);
+ id_node->layers = base->lay;
+
+ /* standard components */
+ build_object_transform(scene, ob);
+
+
+ /* object data */
+ if (ob->data) {
+ /* type-specific data... */
+ switch (ob->type) {
+ case OB_MESH: /* Geometry */
+ case OB_CURVE:
+ case OB_FONT:
+ case OB_SURF:
+ case OB_MBALL:
+ case OB_LATTICE:
+ {
+ /* TODO(sergey): This way using this object's
+ * properties as driver target works fine.
+ *
+ * Does this depend on other nodes?
+ */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_POST, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+
+ build_obdata_geom(scene, ob);
+ /* TODO(sergey): Only for until we support granular
+ * update of curves.
+ */
+ if (ob->type == OB_FONT) {
+ Curve *curve = (Curve *)ob->data;
+ if (curve->textoncurve) {
+ id_node->eval_flags |= DAG_EVAL_NEED_CURVE_PATH;
+ }
+ }
+ break;
+ }
+
+ case OB_ARMATURE: /* Pose */
+ if (ob->id.lib != NULL && ob->proxy_from != NULL) {
+ build_proxy_rig(ob);
+ }
+ else {
+ build_rig(scene, ob);
+ }
+ break;
+
+ case OB_LAMP: /* Lamp */
+ build_lamp(ob);
+ break;
+
+ case OB_CAMERA: /* Camera */
+ build_camera(ob);
+ break;
+
+ default:
+ {
+ ID *obdata = (ID *)ob->data;
+ if ((obdata->flag & LIB_DOIT) == 0) {
+ build_animdata(obdata);
+ }
+ break;
+ }
+ }
+ }
+
+ /* Build animation data,
+ *
+ * Do it now because it's possible object data will affect
+ * on object's level animation, for example in case of rebuilding
+ * pose for proxy.
+ */
+ build_animdata(&ob->id);
+
+ /* particle systems */
+ if (ob->particlesystem.first) {
+ build_particles(ob);
+ }
+
+ /* grease pencil */
+ if (ob->gpd) {
+ build_gpencil(ob->gpd);
+ }
+}
+
+void DepsgraphNodeBuilder::build_object_transform(Scene *scene, Object *ob)
+{
+ /* local transforms (from transform channels - loc/rot/scale + deltas) */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
+ DEPSOP_TYPE_INIT, function_bind(BKE_object_eval_local_transform, _1, scene, ob),
+ DEG_OPCODE_TRANSFORM_LOCAL);
+
+ /* object parent */
+ if (ob->parent) {
+ add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_parent, _1, scene, ob),
+ DEG_OPCODE_TRANSFORM_PARENT);
+ }
+
+ /* object constraints */
+ if (ob->constraints.first) {
+ build_object_constraints(scene, ob);
+ }
+
+ /* Temporary uber-update node, which does everything.
+ * It is for the being we're porting old dependencies into the new system.
+ * We'll get rid of this node as soon as all the granular update functions
+ * are filled in.
+ *
+ * TODO(sergey): Get rid of this node.
+ */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_uber_transform, _1, scene, ob),
+ DEG_OPCODE_OBJECT_UBEREVAL);
+
+ /* object transform is done */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
+ DEPSOP_TYPE_POST, function_bind(BKE_object_eval_done, _1, ob),
+ DEG_OPCODE_TRANSFORM_FINAL);
+}
+
+/**
+ * Constraints Graph Notes
+ *
+ * For constraints, we currently only add a operation node to the Transform
+ * or Bone components (depending on whichever type of owner we have).
+ * This represents the entire constraints stack, which is for now just
+ * executed as a single monolithic block. At least initially, this should
+ * be sufficient for ensuring that the porting/refactoring process remains
+ * manageable.
+ *
+ * However, when the time comes for developing "node-based" constraints,
+ * we'll need to split this up into pre/post nodes for "constraint stack
+ * evaluation" + operation nodes for each constraint (i.e. the contents
+ * of the loop body used in the current "solve_constraints()" operation).
+ *
+ * -- Aligorith, August 2013
+ */
+void DepsgraphNodeBuilder::build_object_constraints(Scene *scene, Object *ob)
+{
+ /* create node for constraint stack */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_constraints, _1, scene, ob),
+ DEG_OPCODE_TRANSFORM_CONSTRAINTS);
+}
+
+void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan)
+{
+ /* create node for constraint stack */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan),
+ DEG_OPCODE_BONE_CONSTRAINTS);
+}
+
+/**
+ * Build graph nodes for AnimData block
+ * \param id: ID-Block which hosts the AnimData
+ */
+void DepsgraphNodeBuilder::build_animdata(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+
+ if (adt == NULL)
+ return;
+
+ /* animation */
+ if (adt->action || adt->nla_tracks.first || adt->drivers.first) {
+ // XXX: Hook up specific update callbacks for special properties which may need it...
+
+ /* actions and NLA - as a single unit for now, as it gets complicated to schedule otherwise */
+ if ((adt->action) || (adt->nla_tracks.first)) {
+ /* create the node */
+ add_operation_node(id, DEPSNODE_TYPE_ANIMATION,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_animsys_eval_animdata, _1, id),
+ DEG_OPCODE_ANIMATION, id->name);
+
+ // TODO: for each channel affected, we might also want to add some support for running RNA update callbacks on them
+ // (which will be needed for proper handling of drivers later)
+ }
+
+ /* drivers */
+ for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) {
+ /* create driver */
+ build_driver(id, fcu);
+ }
+ }
+}
+
+/**
+ * Build graph node(s) for Driver
+ * \param id: ID-Block that driver is attached to
+ * \param fcu: Driver-FCurve
+ */
+OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu)
+{
+ ChannelDriver *driver = fcu->driver;
+
+ /* Create data node for this driver */
+ /* TODO(sergey): Avoid creating same operation multiple times,
+ * in the future we need to avoid lookup of the operation as well
+ * and use some tagging magic instead.
+ */
+ OperationDepsNode *driver_op = find_operation_node(id,
+ DEPSNODE_TYPE_PARAMETERS,
+ DEG_OPCODE_DRIVER,
+ deg_fcurve_id_name(fcu));
+
+ if (driver_op == NULL) {
+ driver_op = add_operation_node(id, DEPSNODE_TYPE_PARAMETERS,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_animsys_eval_driver, _1, id, fcu),
+ DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu));
+ }
+
+ /* tag "scripted expression" drivers as needing Python (due to GIL issues, etc.) */
+ if (driver->type == DRIVER_TYPE_PYTHON) {
+ driver_op->flag |= DEPSOP_FLAG_USES_PYTHON;
+ }
+
+ /* return driver node created */
+ return driver_op;
+}
+
+/* Recursively build graph for world */
+void DepsgraphNodeBuilder::build_world(World *world)
+{
+ ID *world_id = &world->id;
+ if (world_id->flag & LIB_DOIT) {
+ return;
+ }
+
+ /* world itself */
+ IDDepsNode *world_node = add_id_node(world_id); /* world shading/params? */
+
+ build_animdata(world_id);
+
+ /* TODO: other settings? */
+
+ /* textures */
+ build_texture_stack(world_node, world->mtex);
+
+ /* world's nodetree */
+ if (world->nodetree) {
+ build_nodetree(world_node, world->nodetree);
+ }
+}
+
+/* Rigidbody Simulation - Scene Level */
+void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
+{
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+
+ /**
+ * Rigidbody Simulation Nodes
+ * ==========================
+ *
+ * There are 3 nodes related to Rigidbody Simulation:
+ * 1) "Initialize/Rebuild World" - this is called sparingly, only when the simulation
+ * needs to be rebuilt (mainly after file reload, or moving back to start frame)
+ * 2) "Do Simulation" - perform a simulation step - interleaved between the evaluation
+ * steps for clusters of objects (i.e. between those affected and/or not affected by
+ * the sim for instance)
+ *
+ * 3) "Pull Results" - grab the specific transforms applied for a specific object -
+ * performed as part of object's transform-stack building
+ */
+
+ /* create nodes ------------------------------------------------------------------------ */
+ /* XXX: is this the right component, or do we want to use another one instead? */
+
+ /* init/rebuild operation */
+ /*OperationDepsNode *init_node =*/ add_operation_node(&scene->id, DEPSNODE_TYPE_TRANSFORM,
+ DEPSOP_TYPE_REBUILD, function_bind(BKE_rigidbody_rebuild_sim, _1, scene),
+ DEG_OPCODE_RIGIDBODY_REBUILD);
+
+ /* do-sim operation */
+ // XXX: what happens if we need to split into several groups?
+ OperationDepsNode *sim_node = add_operation_node(&scene->id, DEPSNODE_TYPE_TRANSFORM,
+ DEPSOP_TYPE_SIM, function_bind(BKE_rigidbody_eval_simulation, _1, scene),
+ DEG_OPCODE_RIGIDBODY_SIM);
+
+ /* XXX: For now, the sim node is the only one that really matters here. If any other
+ * sims get added later, we may have to remove these hacks...
+ */
+ sim_node->owner->entry_operation = sim_node;
+ sim_node->owner->exit_operation = sim_node;
+
+
+ /* objects - simulation participants */
+ if (rbw->group) {
+ for (GroupObject *go = (GroupObject *)rbw->group->gobject.first; go; go = go->next) {
+ Object *ob = go->ob;
+
+ if (!ob || (ob->type != OB_MESH))
+ continue;
+
+ /* 2) create operation for flushing results */
+ /* object's transform component - where the rigidbody operation lives */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_rigidbody_object_sync_transforms, _1, scene, ob),
+ DEG_OPCODE_TRANSFORM_RIGIDBODY);
+ }
+ }
+}
+
+void DepsgraphNodeBuilder::build_particles(Object *ob)
+{
+ /**
+ * Particle Systems Nodes
+ * ======================
+ *
+ * There are two types of nodes associated with representing
+ * particle systems:
+ * 1) Component (EVAL_PARTICLES) - This is the particle-system
+ * evaluation context for an object. It acts as the container
+ * for all the nodes associated with a particular set of particle
+ * systems.
+ * 2) Particle System Eval Operation - This operation node acts as a
+ * blackbox evaluation step for one particle system referenced by
+ * the particle systems stack. All dependencies link to this operation.
+ */
+
+ /* component for all particle systems */
+ ComponentDepsNode *psys_comp = add_component_node(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES);
+
+ /* particle systems */
+ for (ParticleSystem *psys = (ParticleSystem *)ob->particlesystem.first; psys; psys = psys->next) {
+ ParticleSettings *part = psys->part;
+
+ /* particle settings */
+ // XXX: what if this is used more than once!
+ build_animdata(&part->id);
+
+ /* this particle system */
+ // TODO: for now, this will just be a placeholder "ubereval" node
+ add_operation_node(psys_comp,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_particle_system_eval, _1, ob, psys),
+ DEG_OPCODE_PSYS_EVAL,
+ psys->name);
+ }
+
+ /* pointcache */
+ // TODO...
+}
+
+/* IK Solver Eval Steps */
+void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
+{
+ bKinematicConstraint *data = (bKinematicConstraint *)con->data;
+
+ /* Find the chain's root. */
+ bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
+
+ if (has_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
+ DEG_OPCODE_POSE_IK_SOLVER))
+ {
+ return;
+ }
+
+ /* Operation node for evaluating/running IK Solver. */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
+ DEPSOP_TYPE_SIM, function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan),
+ DEG_OPCODE_POSE_IK_SOLVER);
+}
+
+/* Spline IK Eval Steps */
+void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
+{
+ bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
+
+ /* Find the chain's root. */
+ bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
+
+ /* Operation node for evaluating/running Spline IK Solver.
+ * Store the "root bone" of this chain in the solver, so it knows where to start.
+ */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
+ DEPSOP_TYPE_SIM, function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan),
+ DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
+}
+
+/* Pose/Armature Bones Graph */
+void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
+{
+ bArmature *arm = (bArmature *)ob->data;
+
+ /* animation and/or drivers linking posebones to base-armature used to define them
+ * NOTE: AnimData here is really used to control animated deform properties,
+ * which ideally should be able to be unique across different instances.
+ * Eventually, we need some type of proxy/isolation mechanism in-between here
+ * to ensure that we can use same rig multiple times in same scene...
+ */
+ build_animdata(&arm->id);
+
+ /* Rebuild pose if not up to date. */
+ if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
+ BKE_pose_rebuild(ob, arm);
+ /* XXX: Without this animation gets lost in certain circumstances
+ * after loading file. Need to investigate further since it does
+ * not happen with simple scenes..
+ */
+ if (ob->adt) {
+ ob->adt->recalc |= ADT_RECALC_ANIM;
+ }
+ }
+
+ /**
+ * Pose Rig Graph
+ * ==============
+ *
+ * Pose Component:
+ * - Mainly used for referencing Bone components.
+ * - This is where the evaluation operations for init/exec/cleanup
+ * (ik) solvers live, and are later hooked up (so that they can be
+ * interleaved during runtime) with bone-operations they depend on/affect.
+ * - init_pose_eval() and cleanup_pose_eval() are absolute first and last
+ * steps of pose eval process. ALL bone operations must be performed
+ * between these two...
+ *
+ * Bone Component:
+ * - Used for representing each bone within the rig
+ * - Acts to encapsulate the evaluation operations (base matrix + parenting,
+ * and constraint stack) so that they can be easily found.
+ * - Everything else which depends on bone-results hook up to the component only
+ * so that we can redirect those to point at either the the post-IK/
+ * post-constraint/post-matrix steps, as needed.
+ */
+
+ /* pose eval context */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
+ DEPSOP_TYPE_INIT, function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_INIT);
+
+ add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
+ DEPSOP_TYPE_POST, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE);
+
+ /* bones */
+ for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* node for bone eval */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_INIT, NULL, // XXX: BKE_pose_eval_bone_local
+ DEG_OPCODE_BONE_LOCAL);
+
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan), // XXX: BKE_pose_eval_bone_pose
+ DEG_OPCODE_BONE_POSE_PARENT);
+
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_OUT, NULL, /* NOTE: dedicated noop for easier relationship construction */
+ DEG_OPCODE_BONE_READY);
+
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_POST, function_bind(BKE_pose_bone_done, _1, pchan),
+ DEG_OPCODE_BONE_DONE);
+
+ /* constraints */
+ if (pchan->constraints.first != NULL) {
+ build_pose_constraints(ob, pchan);
+ }
+
+ /**
+ * IK Solvers...
+ *
+ * - These require separate processing steps are pose-level
+ * to be executed between chains of bones (i.e. once the
+ * base transforms of a bunch of bones is done)
+ *
+ * Unsolved Issues:
+ * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
+ * - Animated chain-lengths are a problem...
+ */
+ for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) {
+ switch (con->type) {
+ case CONSTRAINT_TYPE_KINEMATIC:
+ build_ik_pose(scene, ob, pchan, con);
+ break;
+
+ case CONSTRAINT_TYPE_SPLINEIK:
+ build_splineik_pose(scene, ob, pchan, con);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+}
+
+void DepsgraphNodeBuilder::build_proxy_rig(Object *ob)
+{
+ ID *obdata = (ID *)ob->data;
+ build_animdata(obdata);
+
+ add_operation_node(&ob->id,
+ DEPSNODE_TYPE_EVAL_POSE,
+ DEPSOP_TYPE_INIT,
+ function_bind(BKE_pose_eval_proxy_copy, _1, ob),
+ DEG_OPCODE_POSE_INIT);
+
+ for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first;
+ pchan != NULL;
+ pchan = pchan->next)
+ {
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_INIT, NULL,
+ DEG_OPCODE_BONE_LOCAL);
+
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_BONE_READY);
+
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_POST, NULL,
+ DEG_OPCODE_BONE_DONE);
+ }
+
+ add_operation_node(&ob->id,
+ DEPSNODE_TYPE_EVAL_POSE,
+ DEPSOP_TYPE_POST,
+ NULL,
+ DEG_OPCODE_POSE_DONE);
+}
+
+/* Shapekeys */
+void DepsgraphNodeBuilder::build_shapekeys(Key *key)
+{
+ build_animdata(&key->id);
+}
+
+/* ObData Geometry Evaluation */
+// XXX: what happens if the datablock is shared!
+void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
+{
+ ID *obdata = (ID *)ob->data;
+
+ /* Temporary uber-update node, which does everything.
+ * It is for the being we're porting old dependencies into the new system.
+ * We'll get rid of this node as soon as all the granular update functions
+ * are filled in.
+ *
+ * TODO(sergey): Get rid of this node.
+ */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_POST, function_bind(BKE_object_eval_uber_data, _1, scene, ob),
+ DEG_OPCODE_GEOMETRY_UBEREVAL);
+
+ add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Eval Init");
+
+ // TODO: "Done" operation
+
+ /* ShapeKeys */
+ Key *key = BKE_key_from_object(ob);
+ if (key)
+ build_shapekeys(key);
+
+ /* Modifiers */
+ if (ob->modifiers.first) {
+ ModifierData *md;
+
+ for (md = (ModifierData *)ob->modifiers.first; md; md = md->next) {
+ add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_modifier, _1, scene, ob, md),
+ DEG_OPCODE_GEOMETRY_MODIFIER, md->name);
+ }
+ }
+
+ /* materials */
+ if (ob->totcol) {
+ int a;
+
+ for (a = 1; a <= ob->totcol; a++) {
+ Material *ma = give_current_material(ob, a);
+
+ if (ma) {
+ // XXX?!
+ ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY);
+ build_material(geom_node, ma);
+ }
+ }
+ }
+
+ /* geometry collision */
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_LATTICE)) {
+ // add geometry collider relations
+ }
+
+ if (obdata->flag & LIB_DOIT) {
+ return;
+ }
+
+ build_animdata(obdata);
+
+ /* nodes for result of obdata's evaluation, and geometry evaluation on object */
+ switch (ob->type) {
+ case OB_MESH:
+ {
+ //Mesh *me = (Mesh *)ob->data;
+
+ /* evaluation operations */
+ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT, function_bind(BKE_mesh_eval_geometry, _1, (Mesh *)obdata),
+ DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ break;
+ }
+
+ case OB_MBALL:
+ {
+ Object *mom = BKE_mball_basis_find(scene, ob);
+
+ /* motherball - mom depends on children! */
+ if (mom == ob) {
+ /* metaball evaluation operations */
+ /* NOTE: only the motherball gets evaluated! */
+ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT, function_bind(BKE_mball_eval_geometry, _1, (MetaBall *)obdata),
+ DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ }
+ break;
+ }
+
+ case OB_CURVE:
+ case OB_FONT:
+ {
+ /* curve evaluation operations */
+ /* - calculate curve geometry (including path) */
+ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT, function_bind(BKE_curve_eval_geometry, _1, (Curve *)obdata),
+ DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+
+ /* - calculate curve path - this is used by constraints, etc. */
+ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_curve_eval_path, _1, (Curve *)obdata),
+ DEG_OPCODE_GEOMETRY_PATH, "Path");
+ break;
+ }
+
+ case OB_SURF: /* Nurbs Surface */
+ {
+ /* nurbs evaluation operations */
+ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT, function_bind(BKE_curve_eval_geometry, _1, (Curve *)obdata),
+ DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ break;
+ }
+
+ case OB_LATTICE: /* Lattice */
+ {
+ /* lattice evaluation operations */
+ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT, function_bind(BKE_lattice_eval_geometry, _1, (Lattice *)obdata),
+ DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ break;
+ }
+ }
+
+ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_POST, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Eval Done");
+
+ /* Parameters for driver sources. */
+ add_operation_node(obdata, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+}
+
+/* Cameras */
+void DepsgraphNodeBuilder::build_camera(Object *ob)
+{
+ /* TODO: Link scene-camera links in somehow... */
+ Camera *cam = (Camera *)ob->data;
+ ID *camera_id = &cam->id;
+ if (camera_id->flag & LIB_DOIT) {
+ return;
+ }
+
+ build_animdata(&cam->id);
+
+ add_operation_node(camera_id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+
+ if (cam->dof_ob != NULL) {
+ /* TODO(sergey): For now parametrs are on object level. */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_PARAMETERS,
+ DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Camera DOF");
+ }
+}
+
+/* Lamps */
+void DepsgraphNodeBuilder::build_lamp(Object *ob)
+{
+ Lamp *la = (Lamp *)ob->data;
+ ID *lamp_id = &la->id;
+ if (lamp_id->flag & LIB_DOIT) {
+ return;
+ }
+
+ build_animdata(&la->id);
+
+ /* node for obdata */
+ ComponentDepsNode *param_node = add_component_node(lamp_id, DEPSNODE_TYPE_PARAMETERS);
+
+ /* TODO(sergey): Is it really how we're supposed to work with drivers? */
+ add_operation_node(lamp_id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+
+ /* lamp's nodetree */
+ if (la->nodetree) {
+ build_nodetree(param_node, la->nodetree);
+ }
+
+ /* textures */
+ build_texture_stack(param_node, la->mtex);
+}
+
+void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree)
+{
+ if (!ntree)
+ return;
+
+ /* nodetree itself */
+ ID *ntree_id = &ntree->id;
+
+ build_animdata(ntree_id);
+
+ /* Parameters for drivers. */
+ add_operation_node(ntree_id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+
+ /* nodetree's nodes... */
+ for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) {
+ if (bnode->id) {
+ if (GS(bnode->id->name) == ID_MA) {
+ build_material(owner_node, (Material *)bnode->id);
+ }
+ else if (bnode->type == ID_TE) {
+ build_texture(owner_node, (Tex *)bnode->id);
+ }
+ else if (bnode->type == NODE_GROUP) {
+ bNodeTree *ntree = (bNodeTree *)bnode->id;
+ if ((ntree_id->flag & LIB_DOIT) == 0) {
+ build_nodetree(owner_node, ntree);
+ }
+ }
+ }
+ }
+
+ // TODO: link from nodetree to owner_component?
+}
+
+/* Recursively build graph for material */
+void DepsgraphNodeBuilder::build_material(DepsNode *owner_node, Material *ma)
+{
+ ID *ma_id = &ma->id;
+ if (ma_id->flag & LIB_DOIT) {
+ return;
+ }
+
+ /* material itself */
+ add_id_node(ma_id);
+
+ add_operation_node(ma_id, DEPSNODE_TYPE_SHADING,
+ DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Material Update");
+
+ /* material animation */
+ build_animdata(ma_id);
+
+ /* textures */
+ build_texture_stack(owner_node, ma->mtex);
+
+ /* material's nodetree */
+ build_nodetree(owner_node, ma->nodetree);
+}
+
+/* Texture-stack attached to some shading datablock */
+void DepsgraphNodeBuilder::build_texture_stack(DepsNode *owner_node, MTex **texture_stack)
+{
+ int i;
+
+ /* for now assume that all texture-stacks have same number of max items */
+ for (i = 0; i < MAX_MTEX; i++) {
+ MTex *mtex = texture_stack[i];
+ if (mtex && mtex->tex)
+ build_texture(owner_node, mtex->tex);
+ }
+}
+
+/* Recursively build graph for texture */
+void DepsgraphNodeBuilder::build_texture(DepsNode *owner_node, Tex *tex)
+{
+ ID *tex_id = &tex->id;
+ if (tex_id->flag & LIB_DOIT) {
+ return;
+ }
+ tex_id->flag |= LIB_DOIT;
+ /* texture itself */
+ build_animdata(tex_id);
+ /* texture's nodetree */
+ build_nodetree(owner_node, tex->nodetree);
+}
+
+void DepsgraphNodeBuilder::build_compositor(Scene *scene)
+{
+ /* For now, just a plain wrapper? */
+ // TODO: create compositing component?
+ // XXX: component type undefined!
+ //graph->get_node(&scene->id, NULL, DEPSNODE_TYPE_COMPOSITING, NULL);
+
+ /* for now, nodetrees are just parameters; compositing occurs in internals of renderer... */
+ ComponentDepsNode *owner_node = add_component_node(&scene->id, DEPSNODE_TYPE_PARAMETERS);
+ build_nodetree(owner_node, scene->nodetree);
+}
+
+void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd)
+{
+ ID *gpd_id = &gpd->id;
+
+ /* gpencil itself */
+ // XXX: what about multiple users of same datablock? This should only get added once
+ add_id_node(gpd_id);
+
+ /* The main reason Grease Pencil is included here is because the animation (and drivers)
+ * need to be hosted somewhere...
+ */
+ build_animdata(gpd_id);
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_build_relations.cc b/source/blender/depsgraph/intern/depsgraph_build_relations.cc
new file mode 100644
index 00000000000..f51f51987d7
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_build_relations.cc
@@ -0,0 +1,1841 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_build_relations.cc
+ * \ingroup depsgraph
+ *
+ * Methods for constructing depsgraph
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_blenlib.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_group_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_node_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_object_types.h"
+#include "DNA_rigidbody_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_animsys.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_effect.h"
+#include "BKE_fcurve.h"
+#include "BKE_group.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mball.h"
+#include "BKE_modifier.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_rigidbody.h"
+#include "BKE_sound.h"
+#include "BKE_texture.h"
+#include "BKE_tracking.h"
+#include "BKE_world.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+} /* extern "C" */
+
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_build.h"
+#include "depsgraph_debug.h"
+#include "depsgraph_intern.h"
+#include "depsgraph_types.h"
+
+#include "depsgraph_util_pchanmap.h"
+
+/* ***************** */
+/* Relations Builder */
+
+/* **** General purpose functions **** */
+
+RNAPathKey::RNAPathKey(ID *id, const char *path) :
+ id(id)
+{
+ /* create ID pointer for root of path lookup */
+ PointerRNA id_ptr;
+ RNA_id_pointer_create(id, &id_ptr);
+ /* try to resolve path... */
+ int index;
+ if (!RNA_path_resolve_full(&id_ptr, path, &this->ptr, &this->prop, &index)) {
+ this->ptr = PointerRNA_NULL;
+ this->prop = NULL;
+ }
+}
+
+DepsgraphRelationBuilder::DepsgraphRelationBuilder(Depsgraph *graph) :
+ m_graph(graph)
+{
+}
+
+RootDepsNode *DepsgraphRelationBuilder::find_node(const RootKey &key) const
+{
+ (void)key;
+ BLI_assert(!"Doesn't seem to be correct");
+ return m_graph->root_node;
+}
+
+TimeSourceDepsNode *DepsgraphRelationBuilder::find_node(
+ const TimeSourceKey &key) const
+{
+ if (key.id) {
+ /* XXX TODO */
+ return NULL;
+ }
+ else {
+ return m_graph->root_node->time_source;
+ }
+}
+
+ComponentDepsNode *DepsgraphRelationBuilder::find_node(
+ const ComponentKey &key) const
+{
+ IDDepsNode *id_node = m_graph->find_id_node(key.id);
+ if (!id_node) {
+ fprintf(stderr, "find_node component: Could not find ID %s\n",
+ (key.id != NULL) ? key.id->name : "<null>");
+ return NULL;
+ }
+
+ ComponentDepsNode *node = id_node->find_component(key.type, key.name);
+ return node;
+}
+
+OperationDepsNode *DepsgraphRelationBuilder::find_node(
+ const OperationKey &key) const
+{
+ IDDepsNode *id_node = m_graph->find_id_node(key.id);
+ if (!id_node) {
+ fprintf(stderr, "find_node operation: Could not find ID\n");
+ return NULL;
+ }
+
+ ComponentDepsNode *comp_node = id_node->find_component(key.component_type,
+ key.component_name);
+ if (!comp_node) {
+ fprintf(stderr, "find_node operation: Could not find component\n");
+ return NULL;
+ }
+
+ OperationDepsNode *op_node = comp_node->find_operation(key.opcode, key.name);
+ if (!op_node) {
+ fprintf(stderr, "find_node_operation: Failed for (%s, '%s')\n",
+ DEG_OPNAMES[key.opcode], key.name.c_str());
+ }
+ return op_node;
+}
+
+DepsNode *DepsgraphRelationBuilder::find_node(const RNAPathKey &key) const
+{
+ return m_graph->find_node_from_pointer(&key.ptr, key.prop);
+}
+
+OperationDepsNode *DepsgraphRelationBuilder::has_node(
+ const OperationKey &key) const
+{
+ IDDepsNode *id_node = m_graph->find_id_node(key.id);
+ if (!id_node) {
+ return NULL;
+ }
+ ComponentDepsNode *comp_node = id_node->find_component(key.component_type,
+ key.component_name);
+ if (!comp_node) {
+ return NULL;
+ }
+ return comp_node->has_operation(key.opcode, key.name);
+}
+
+void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc,
+ DepsNode *node_to,
+ const char *description)
+{
+ if (timesrc && node_to) {
+ m_graph->add_new_relation(timesrc, node_to, DEPSREL_TYPE_TIME, description);
+ }
+ else {
+ DEG_DEBUG_PRINTF("add_time_relation(%p = %s, %p = %s, %s) Failed\n",
+ timesrc, (timesrc) ? timesrc->identifier().c_str() : "<None>",
+ node_to, (node_to) ? node_to->identifier().c_str() : "<None>",
+ description);
+ }
+}
+
+void DepsgraphRelationBuilder::add_operation_relation(
+ OperationDepsNode *node_from,
+ OperationDepsNode *node_to,
+ eDepsRelation_Type type,
+ const char *description)
+{
+ if (node_from && node_to) {
+ m_graph->add_new_relation(node_from, node_to, type, description);
+ }
+ else {
+ DEG_DEBUG_PRINTF("add_operation_relation(%p = %s, %p = %s, %d, %s) Failed\n",
+ node_from, (node_from) ? node_from->identifier().c_str() : "<None>",
+ node_to, (node_to) ? node_to->identifier().c_str() : "<None>",
+ type, description);
+ }
+}
+
+/* **** Functions to build relations between entities **** */
+
+void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
+{
+ /* LIB_DOIT is used to indicate whether node for given ID was already
+ * created or not.
+ */
+ BKE_main_id_tag_all(bmain, false);
+
+ if (scene->set) {
+ // TODO: link set to scene, especially our timesource...
+ }
+
+ /* scene objects */
+ for (Base *base = (Base *)scene->base.first; base; base = base->next) {
+ Object *ob = base->object;
+
+ /* object itself */
+ build_object(bmain, scene, ob);
+
+ /* object that this is a proxy for */
+ if (ob->proxy) {
+ build_object(bmain, scene, ob->proxy);
+ /* TODO(sergey): This is an inverted relation, matches old depsgraph
+ * behavior and need to be investigated if it still need to be inverted.
+ */
+ ComponentKey ob_pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
+ ComponentKey proxy_pose_key(&ob->proxy->id, DEPSNODE_TYPE_EVAL_POSE);
+ add_relation(ob_pose_key, proxy_pose_key, DEPSREL_TYPE_TRANSFORM, "Proxy");
+ }
+
+ /* Object dupligroup. */
+ if (ob->dup_group) {
+ build_group(bmain, scene, ob, ob->dup_group);
+ }
+ }
+
+ /* rigidbody */
+ if (scene->rigidbody_world) {
+ build_rigidbody(scene);
+ }
+
+ /* scene's animation and drivers */
+ if (scene->adt) {
+ build_animdata(&scene->id);
+ }
+
+ /* world */
+ if (scene->world) {
+ build_world(scene->world);
+ }
+
+ /* compo nodes */
+ if (scene->nodetree) {
+ build_compositor(scene);
+ }
+
+ /* grease pencil */
+ if (scene->gpd) {
+ build_gpencil(&scene->id, scene->gpd);
+ }
+}
+
+void DepsgraphRelationBuilder::build_group(Main *bmain,
+ Scene *scene,
+ Object *object,
+ Group *group)
+{
+ ID *group_id = &group->id;
+ bool group_done = (group_id->flag & LIB_DOIT) != 0;
+ OperationKey object_local_transform_key(&object->id,
+ DEPSNODE_TYPE_TRANSFORM,
+ DEG_OPCODE_TRANSFORM_LOCAL);
+ for (GroupObject *go = (GroupObject *)group->gobject.first;
+ go != NULL;
+ go = go->next)
+ {
+ if (!group_done) {
+ build_object(bmain, scene, go->ob);
+ }
+ ComponentKey dupli_transform_key(&go->ob->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(dupli_transform_key,
+ object_local_transform_key,
+ DEPSREL_TYPE_TRANSFORM,
+ "Dupligroup");
+ }
+ group_id->flag |= LIB_DOIT;
+}
+
+void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *ob)
+{
+ if (ob->id.flag & LIB_DOIT) {
+ return;
+ }
+
+ /* Object Transforms */
+ eDepsOperation_Code base_op = (ob->parent) ? DEG_OPCODE_TRANSFORM_PARENT : DEG_OPCODE_TRANSFORM_LOCAL;
+ OperationKey base_op_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, base_op);
+
+ OperationKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL);
+ OperationKey parent_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_PARENT);
+ OperationKey final_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
+
+ OperationKey ob_ubereval_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_OBJECT_UBEREVAL);
+
+ /* parenting */
+ if (ob->parent) {
+ /* parent relationship */
+ build_object_parent(ob);
+
+ /* local -> parent */
+ add_relation(local_transform_key, parent_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "[ObLocal -> ObParent]");
+ }
+
+ /* object constraints */
+ if (ob->constraints.first) {
+ OperationKey constraint_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_CONSTRAINTS);
+
+ /* constraint relations */
+ // TODO: provide base op
+ // XXX: this is broken
+ build_constraints(scene, &ob->id, DEPSNODE_TYPE_TRANSFORM, "", &ob->constraints, NULL);
+
+ /* operation order */
+ add_relation(base_op_key, constraint_key, DEPSREL_TYPE_COMPONENT_ORDER, "[ObBase-> Constraint Stack]");
+ add_relation(constraint_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "[ObConstraints -> Done]");
+
+ // XXX
+ add_relation(constraint_key, ob_ubereval_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval");
+ add_relation(ob_ubereval_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval");
+ }
+ else {
+ /* operation order */
+ add_relation(base_op_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "Object Transform");
+
+ // XXX
+ add_relation(base_op_key, ob_ubereval_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval");
+ add_relation(ob_ubereval_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval");
+ }
+
+
+ /* AnimData */
+ build_animdata(&ob->id);
+
+ // XXX: This should be hooked up by the build_animdata code
+ if (ob->adt && (ob->adt->action || ob->adt->nla_tracks.first)) {
+ ComponentKey adt_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
+ add_relation(adt_key, local_transform_key, DEPSREL_TYPE_OPERATION, "Object Animation");
+ }
+
+
+ /* object data */
+ if (ob->data) {
+ ID *obdata_id = (ID *)ob->data;
+
+ /* ob data animation */
+ build_animdata(obdata_id);
+
+ /* type-specific data... */
+ switch (ob->type) {
+ case OB_MESH: /* Geometry */
+ case OB_CURVE:
+ case OB_FONT:
+ case OB_SURF:
+ case OB_MBALL:
+ case OB_LATTICE:
+ {
+ build_obdata_geom(bmain, scene, ob);
+ break;
+ }
+
+
+ case OB_ARMATURE: /* Pose */
+ if (ob->id.lib != NULL && ob->proxy_from != NULL) {
+ build_proxy_rig(ob);
+ }
+ else {
+ build_rig(scene, ob);
+ }
+ break;
+
+ case OB_LAMP: /* Lamp */
+ build_lamp(ob);
+ break;
+
+ case OB_CAMERA: /* Camera */
+ build_camera(ob);
+ break;
+ }
+ }
+
+ /* particle systems */
+ if (ob->particlesystem.first) {
+ build_particles(scene, ob);
+ }
+
+ /* grease pencil */
+ if (ob->gpd) {
+ build_gpencil(&ob->id, ob->gpd);
+ }
+}
+
+void DepsgraphRelationBuilder::build_object_parent(Object *ob)
+{
+ /* XXX: for now, need to use the component key (not just direct to the parent op), or else the matrix doesn't get reset */
+ // XXX: @sergey - it would be good if we got that backwards flushing working when tagging for updates
+ //OperationKey ob_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_PARENT);
+ ComponentKey ob_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
+
+ /* type-specific links */
+ switch (ob->partype) {
+ case PARSKEL: /* Armature Deform (Virtual Modifier) */
+ {
+ ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(parent_key, ob_key, DEPSREL_TYPE_STANDARD, "Armature Deform Parent");
+ break;
+ }
+
+ case PARVERT1: /* Vertex Parent */
+ case PARVERT3:
+ {
+ ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(parent_key, ob_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Vertex Parent");
+ /* XXX not sure what this is for or how you could be done properly - lukas */
+ //parent_node->customdata_mask |= CD_MASK_ORIGINDEX;
+
+ ComponentKey transform_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(transform_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Vertex Parent TFM");
+ break;
+ }
+
+ case PARBONE: /* Bone Parent */
+ {
+ ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_BONE, ob->parsubstr);
+ add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Bone Parent");
+ break;
+ }
+
+ default:
+ {
+ if (ob->parent->type == OB_LATTICE) {
+ /* Lattice Deform Parent - Virtual Modifier */
+ // XXX: no virtual modifiers should be left!
+ ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
+ ComponentKey geom_key(&ob->parent->id, DEPSNODE_TYPE_GEOMETRY);
+
+ add_relation(parent_key, ob_key, DEPSREL_TYPE_STANDARD, "Lattice Deform Parent");
+ add_relation(geom_key, ob_key, DEPSREL_TYPE_STANDARD, "Lattice Deform Parent Geom");
+ }
+ else if (ob->parent->type == OB_CURVE) {
+ Curve *cu = (Curve *)ob->parent->data;
+
+ if (cu->flag & CU_PATH) {
+ /* Follow Path */
+ ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Curve Follow Parent");
+
+ ComponentKey transform_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(transform_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Curve Follow TFM");
+ }
+ else {
+ /* Standard Parent */
+ ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Curve Parent");
+ }
+ }
+ else {
+ /* Standard Parent */
+ ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Parent");
+ }
+ break;
+ }
+ }
+
+ /* exception case: parent is duplivert */
+ if ((ob->type == OB_MBALL) && (ob->parent->transflag & OB_DUPLIVERTS)) {
+ //dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Duplivert");
+ }
+}
+
+void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode_Type component_type, const char *component_subdata,
+ ListBase *constraints, RootPChanMap *root_map)
+{
+ OperationKey constraint_op_key(id, component_type, component_subdata,
+ (component_type == DEPSNODE_TYPE_BONE) ? DEG_OPCODE_BONE_CONSTRAINTS : DEG_OPCODE_TRANSFORM_CONSTRAINTS);
+
+ /* add dependencies for each constraint in turn */
+ for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+
+ /* invalid constraint type... */
+ if (cti == NULL)
+ continue;
+
+ /* special case for camera tracking -- it doesn't use targets to define relations */
+ // TODO: we can now represent dependencies in a much richer manner, so review how this is done...
+ if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) {
+ bool depends_on_camera = false;
+
+ if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
+ bFollowTrackConstraint *data = (bFollowTrackConstraint *)con->data;
+
+ if (((data->clip) || (data->flag & FOLLOWTRACK_ACTIVECLIP)) && data->track[0])
+ depends_on_camera = true;
+
+ if (data->depth_ob) {
+ // DAG_RL_DATA_OB | DAG_RL_OB_OB
+ ComponentKey depth_key(&data->depth_ob->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(depth_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+ }
+ else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
+ depends_on_camera = true;
+ }
+
+ if (depends_on_camera && scene->camera) {
+ // DAG_RL_DATA_OB | DAG_RL_OB_OB
+ ComponentKey camera_key(&scene->camera->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(camera_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+
+ /* tracker <-> constraints */
+ // FIXME: actually motionclip dependency on results of motionclip block here...
+ //dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation");
+ }
+ else if (cti->get_constraint_targets) {
+ ListBase targets = {NULL, NULL};
+ cti->get_constraint_targets(con, &targets);
+
+ for (bConstraintTarget *ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
+ if (!ct->tar)
+ continue;
+
+ if (ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) {
+ /* ignore IK constraints - these are handled separately (on pose level) */
+ }
+ else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) {
+ /* these constraints require path geometry data... */
+ ComponentKey target_key(&ct->tar->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(target_key, constraint_op_key, DEPSREL_TYPE_GEOMETRY_EVAL, cti->name); // XXX: type = geom_transform
+ // TODO: path dependency
+ }
+ else if ((ct->tar->type == OB_ARMATURE) && (ct->subtarget[0])) {
+ /* bone */
+ if (&ct->tar->id == id) {
+ /* same armature */
+ eDepsOperation_Code target_key_opcode;
+
+ /* Using "done" here breaks in-chain deps, while using "ready" here breaks most production rigs instead...
+ * So, we do a compromise here, and only do this when an IK chain conflict may occur
+ */
+ if (root_map->has_common_root(component_subdata, ct->subtarget)) {
+ target_key_opcode = DEG_OPCODE_BONE_READY;
+ }
+ else {
+ target_key_opcode = DEG_OPCODE_BONE_DONE;
+ }
+
+ OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_BONE, ct->subtarget, target_key_opcode);
+ add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+ else {
+ /* different armature - we can safely use the result of that */
+ OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_BONE, ct->subtarget, DEG_OPCODE_BONE_DONE);
+ add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+ }
+ else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) {
+ /* vertex group */
+ /* NOTE: for now, we don't need to represent vertex groups separately... */
+ ComponentKey target_key(&ct->tar->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(target_key, constraint_op_key, DEPSREL_TYPE_GEOMETRY_EVAL, cti->name);
+
+ if (ct->tar->type == OB_MESH) {
+ //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) {
+ /* Constraints which requires the target object surface. */
+ ComponentKey target_key(&ct->tar->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+
+ /* NOTE: obdata eval now doesn't necessarily depend on the object's transform... */
+ ComponentKey target_transform_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(target_transform_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+ else {
+ /* standard object relation */
+ // TODO: loc vs rot vs scale?
+ if (&ct->tar->id == id) {
+ /* Constraint targetting own object:
+ * - This case is fine IFF we're dealing with a bone constraint pointing to
+ * its own armature. In that case, it's just transform -> bone.
+ * - If however it is a real self targetting case, just make it depend on the
+ * previous constraint (or the pre-constraint state)...
+ */
+ if ((ct->tar->type == OB_ARMATURE) && (component_type == DEPSNODE_TYPE_BONE)) {
+ OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
+ add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+ else {
+ OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL);
+ add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+ }
+ else {
+ /* normal object dependency */
+ OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
+ add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+ }
+
+ /* Constraints which needs world's matrix for transform.
+ * TODO(sergey): More constraints here?
+ */
+ if (ELEM(con->type,
+ CONSTRAINT_TYPE_ROTLIKE,
+ CONSTRAINT_TYPE_SIZELIKE,
+ CONSTRAINT_TYPE_LOCLIKE,
+ CONSTRAINT_TYPE_TRANSLIKE))
+ {
+ /* TODO(sergey): Add used space check. */
+ ComponentKey target_transform_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(target_transform_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 1);
+ }
+ }
+}
+
+void DepsgraphRelationBuilder::build_animdata(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+
+ if (adt == NULL)
+ return;
+
+ ComponentKey adt_key(id, DEPSNODE_TYPE_ANIMATION);
+
+ /* animation */
+ if (adt->action || adt->nla_tracks.first) {
+ /* wire up dependency to time source */
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, adt_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Animation]");
+
+ // XXX: Hook up specific update callbacks for special properties which may need it...
+
+ // XXX: animdata "hierarchy" - top-level overrides need to go after lower-down
+ }
+
+ /* drivers */
+ for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) {
+ OperationKey driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu));
+
+ /* create the driver's relations to targets */
+ build_driver(id, fcu);
+
+ /* prevent driver from occurring before own animation... */
+ if (adt->action || adt->nla_tracks.first) {
+ add_relation(adt_key, driver_key, DEPSREL_TYPE_OPERATION,
+ "[AnimData Before Drivers]");
+ }
+ }
+}
+
+void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
+{
+ ChannelDriver *driver = fcu->driver;
+ OperationKey driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu));
+ bPoseChannel *pchan = NULL;
+
+ /* create dependency between driver and data affected by it */
+ /* - direct property relationship... */
+ //RNAPathKey affected_key(id, fcu->rna_path);
+ //add_relation(driver_key, affected_key, DEPSREL_TYPE_DRIVER, "[Driver -> Data] DepsRel");
+
+ /* driver -> data components (for interleaved evaluation - bones/constraints/modifiers) */
+ // XXX: this probably should probably be moved out into a separate function
+ if (strstr(fcu->rna_path, "pose.bones[") != NULL) {
+ /* interleaved drivers during bone eval */
+ // TODO: ideally, if this is for a constraint, it goes to said constraint
+ Object *ob = (Object *)id;
+ char *bone_name;
+
+ bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
+ pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
+
+ if (bone_name) {
+ MEM_freeN(bone_name);
+ bone_name = NULL;
+ }
+
+ if (pchan) {
+ OperationKey bone_key(id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
+ add_relation(driver_key, bone_key, DEPSREL_TYPE_DRIVER, "[Driver -> Bone]");
+ }
+ else {
+ fprintf(stderr,
+ "Couldn't find bone name for driver path - '%s'\n",
+ fcu->rna_path);
+ }
+ }
+ else if (GS(id->name) == ID_AR && strstr(fcu->rna_path, "bones[")) {
+ /* drivers on armature-level bone settings (i.e. bbone stuff),
+ * which will affect the evaluation of corresponding pose bones
+ */
+ IDDepsNode *arm_node = m_graph->find_id_node(id);
+ char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
+
+ if (arm_node && bone_name) {
+ /* find objects which use this, and make their eval callbacks depend on this */
+ DEPSNODE_RELATIONS_ITER_BEGIN(arm_node->outlinks, rel)
+ {
+ IDDepsNode *to_node = (IDDepsNode *)rel->to;
+
+ /* we only care about objects with pose data which use this... */
+ if (GS(to_node->id->name) == ID_OB) {
+ Object *ob = (Object *)to_node->id;
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name); // NOTE: ob->pose may be NULL
+
+ if (pchan) {
+ OperationKey bone_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
+ add_relation(driver_key, bone_key, DEPSREL_TYPE_DRIVER, "[Arm Bone -> Driver -> Bone]");
+ }
+ }
+ }
+ DEPSNODE_RELATIONS_ITER_END;
+
+ /* free temp data */
+ MEM_freeN(bone_name);
+ bone_name = NULL;
+ }
+ else {
+ fprintf(stderr,
+ "Couldn't find armature bone name for driver path - '%s'\n",
+ fcu->rna_path);
+ }
+ }
+ else if (GS(id->name) == ID_OB && strstr(fcu->rna_path, "modifiers[")) {
+ /* modifier driver - connect directly to the modifier */
+ char *modifier_name = BLI_str_quoted_substrN(fcu->rna_path, "modifiers[");
+ if (modifier_name) {
+ OperationKey modifier_key(id,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEG_OPCODE_GEOMETRY_MODIFIER,
+ modifier_name);
+ if (has_node(modifier_key)) {
+ add_relation(driver_key, modifier_key, DEPSREL_TYPE_DRIVER, "[Driver -> Modifier]");
+ }
+ else {
+ printf("Unexisting driver RNA path: %s\n", fcu->rna_path);
+ }
+
+ MEM_freeN(modifier_name);
+ }
+ }
+ else if (GS(id->name) == ID_KE && strstr(fcu->rna_path, "key_blocks[")) {
+ /* shape key driver - hook into the base geometry operation */
+ // XXX: double check where this points
+ Key *shape_key = (Key *)id;
+
+ ComponentKey geometry_key(shape_key->from, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(driver_key, geometry_key, DEPSREL_TYPE_DRIVER, "[Driver -> ShapeKey Geom]");
+ }
+ else {
+ if (GS(id->name) == ID_OB) {
+ /* assume that driver affects a transform... */
+ OperationKey local_transform_key(id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL);
+ add_relation(driver_key, local_transform_key, DEPSREL_TYPE_OPERATION, "[Driver -> Transform]");
+ }
+ }
+
+ /* ensure that affected prop's update callbacks will be triggered once done */
+ // TODO: implement this once the functionality to add these links exists in RNA
+ // XXX: the data itself could also set this, if it were to be truly initialised later?
+
+ /* loop over variables to get the target relationships */
+ for (DriverVar *dvar = (DriverVar *)driver->variables.first; dvar; dvar = dvar->next) {
+ /* only used targets */
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ if (dtar->id == NULL)
+ continue;
+
+ /* special handling for directly-named bones */
+ if ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (dtar->pchan_name[0])) {
+ Object *ob = (Object *)dtar->id;
+ bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
+ if (target_pchan != NULL) {
+ /* get node associated with bone */
+ // XXX: watch the space!
+ /* Some cases can't use final bone transform, for example:
+ * - Driving the bone with itself (addressed here)
+ * - Relations inside an IK chain (TODO?)
+ */
+ if (dtar->id == id &&
+ pchan != NULL &&
+ STREQ(pchan->name, target_pchan->name))
+ {
+ continue;
+ }
+ OperationKey target_key(dtar->id, DEPSNODE_TYPE_BONE, target_pchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(target_key, driver_key, DEPSREL_TYPE_DRIVER_TARGET, "[Bone Target -> Driver]");
+ }
+ }
+ else if (dtar->flag & DTAR_FLAG_STRUCT_REF) {
+ /* get node associated with the object's transforms */
+ OperationKey target_key(dtar->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
+ add_relation(target_key, driver_key, DEPSREL_TYPE_DRIVER_TARGET, "[Target -> Driver]");
+ }
+ else if (dtar->rna_path && strstr(dtar->rna_path, "pose.bones[")) {
+ /* workaround for ensuring that local bone transforms don't end up
+ * having to wait for pose eval to finish (to prevent cycles)
+ */
+ Object *ob = (Object *)dtar->id;
+ char *bone_name = BLI_str_quoted_substrN(dtar->rna_path, "pose.bones[");
+ bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
+ if (bone_name) {
+ MEM_freeN(bone_name);
+ bone_name = NULL;
+ }
+ if (target_pchan) {
+ if (dtar->id == id &&
+ pchan != NULL &&
+ STREQ(pchan->name, target_pchan->name))
+ {
+ continue;
+ }
+ OperationKey bone_key(dtar->id, DEPSNODE_TYPE_BONE, target_pchan->name, DEG_OPCODE_BONE_LOCAL);
+ add_relation(bone_key, driver_key, DEPSREL_TYPE_DRIVER, "[RNA Bone -> Driver]");
+ }
+ }
+ else {
+ /* 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]");
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END
+ }
+}
+
+void DepsgraphRelationBuilder::build_world(World *world)
+{
+ ID *world_id = &world->id;
+ if (world_id->flag & LIB_DOIT) {
+ return;
+ }
+ world_id->flag |= LIB_DOIT;
+
+ build_animdata(world_id);
+
+ /* TODO: other settings? */
+
+ /* textures */
+ build_texture_stack(world_id, world->mtex);
+
+ /* world's nodetree */
+ build_nodetree(world_id, world->nodetree);
+}
+
+void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
+{
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+
+ OperationKey init_key(&scene->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_RIGIDBODY_REBUILD);
+ OperationKey sim_key(&scene->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_RIGIDBODY_SIM);
+
+ /* rel between the two sim-nodes */
+ add_relation(init_key, sim_key, DEPSREL_TYPE_OPERATION, "Rigidbody [Init -> SimStep]");
+
+ /* set up dependencies between these operations and other builtin nodes --------------- */
+
+ /* time dependency */
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, init_key, DEPSREL_TYPE_TIME, "TimeSrc -> Rigidbody Reset/Rebuild (Optional)");
+ add_relation(time_src_key, sim_key, DEPSREL_TYPE_TIME, "TimeSrc -> Rigidbody Sim Step");
+
+ /* objects - simulation participants */
+ if (rbw->group) {
+ for (GroupObject *go = (GroupObject *)rbw->group->gobject.first; go; go = go->next) {
+ Object *ob = go->ob;
+ if (!ob || ob->type != OB_MESH)
+ continue;
+
+ /* hook up evaluation order...
+ * 1) flushing rigidbody results follows base transforms being applied
+ * 2) rigidbody flushing can only be performed after simulation has been run
+ *
+ * 3) simulation needs to know base transforms to figure out what to do
+ * XXX: there's probably a difference between passive and active
+ * - passive don't change, so may need to know full transform...
+ */
+ OperationKey rbo_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
+
+ eDepsOperation_Code trans_opcode = ob->parent ? DEG_OPCODE_TRANSFORM_PARENT : DEG_OPCODE_TRANSFORM_LOCAL;
+ OperationKey trans_op(&ob->id, DEPSNODE_TYPE_TRANSFORM, trans_opcode);
+
+ add_relation(trans_op, rbo_key, DEPSREL_TYPE_OPERATION, "Base Ob Transform -> RBO Sync");
+ add_relation(sim_key, rbo_key, DEPSREL_TYPE_COMPONENT_ORDER, "Rigidbody Sim Eval -> RBO Sync");
+
+ /* if constraints exist, those depend on the result of the rigidbody sim
+ * - This allows constraints to modify the result of the sim (i.e. clamping)
+ * while still allowing the sim to depend on some changes to the objects.
+ * Also, since constraints are hooked up to the final nodes, this link
+ * means that we can also fit in there too...
+ * - Later, it might be good to include a constraint in the stack allowing us
+ * to control whether rigidbody eval gets interleaved into the constraint stack
+ */
+ if (ob->constraints.first) {
+ OperationKey constraint_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_CONSTRAINTS);
+ add_relation(rbo_key, constraint_key, DEPSREL_TYPE_COMPONENT_ORDER, "RBO Sync -> Ob Constraints");
+ }
+ else {
+ /* final object transform depends on rigidbody */
+ OperationKey done_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
+ add_relation(rbo_key, done_key, DEPSREL_TYPE_COMPONENT_ORDER, "RBO Sync -> Done");
+
+ // XXX: ubereval will be removed eventually, but we still need it in the meantime
+ OperationKey uber_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_OBJECT_UBEREVAL);
+ add_relation(rbo_key, uber_key, DEPSREL_TYPE_COMPONENT_ORDER, "RBO Sync -> Uber (Temp)");
+ }
+
+
+ /* needed to get correct base values */
+ add_relation(trans_op, sim_key, DEPSREL_TYPE_OPERATION, "Base Ob Transform -> Rigidbody Sim Eval");
+ }
+ }
+
+ /* constraints */
+ if (rbw->constraints) {
+ for (GroupObject *go = (GroupObject *)rbw->constraints->gobject.first; go; go = go->next) {
+ Object *ob = go->ob;
+ if (!ob || !ob->rigidbody_constraint)
+ continue;
+
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+
+ /* final result of the constraint object's transform controls how the
+ * constraint affects the physics sim for these objects
+ */
+ ComponentKey trans_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
+ OperationKey ob1_key(&rbc->ob1->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
+ OperationKey ob2_key(&rbc->ob2->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
+
+ /* - constrained-objects sync depends on the constraint-holder */
+ add_relation(trans_key, ob1_key, DEPSREL_TYPE_TRANSFORM, "RigidBodyConstraint -> RBC.Object_1");
+ add_relation(trans_key, ob2_key, DEPSREL_TYPE_TRANSFORM, "RigidBodyConstraint -> RBC.Object_2");
+
+ /* - ensure that sim depends on this constraint's transform */
+ add_relation(trans_key, sim_key, DEPSREL_TYPE_TRANSFORM, "RigidBodyConstraint Transform -> RB Simulation");
+ }
+ }
+}
+
+void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob)
+{
+ TimeSourceKey time_src_key;
+ OperationKey obdata_ubereval_key(&ob->id,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEG_OPCODE_GEOMETRY_UBEREVAL);
+
+ /* particle systems */
+ for (ParticleSystem *psys = (ParticleSystem *)ob->particlesystem.first; psys; psys = psys->next) {
+ ParticleSettings *part = psys->part;
+
+ /* particle settings */
+ build_animdata(&part->id);
+
+ /* this particle system */
+ OperationKey psys_key(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PSYS_EVAL, psys->name);
+
+ /* XXX: if particle system is later re-enabled, we must do full rebuild? */
+ if (!psys_check_enabled(ob, psys))
+ continue;
+
+ /* TODO(sergey): Are all particle systems depends on time?
+ * Hair without dynamics i.e.
+ */
+ add_relation(time_src_key, psys_key,
+ DEPSREL_TYPE_TIME,
+ "TimeSrc -> PSys");
+
+ /* TODO(sergey): Currently particle update is just a placeholder,
+ * hook it to the ubereval node so particle system is getting updated
+ * on playback.
+ */
+ add_relation(psys_key,
+ obdata_ubereval_key,
+ DEPSREL_TYPE_OPERATION,
+ "PSys -> UberEval");
+
+#if 0
+ if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) {
+ ParticleTarget *pt;
+
+ for (pt = psys->targets.first; pt; pt = pt->next) {
+ if (pt->ob && BLI_findlink(&pt->ob->particlesystem, pt->psys - 1)) {
+ node2 = dag_get_node(dag, pt->ob);
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Particle Targets");
+ }
+ }
+ }
+
+ if (part->ren_as == PART_DRAW_OB && part->dup_ob) {
+ node2 = dag_get_node(dag, part->dup_ob);
+ /* note that this relation actually runs in the wrong direction, the problem
+ * is that dupli system all have this (due to parenting), and the render
+ * engine instancing assumes particular ordering of objects in list */
+ dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Object Visualization");
+ if (part->dup_ob->type == OB_MBALL)
+ dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Object Visualization");
+ }
+
+ if (part->ren_as == PART_DRAW_GR && part->dup_group) {
+ for (go = part->dup_group->gobject.first; go; go = go->next) {
+ node2 = dag_get_node(dag, go->ob);
+ dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Particle Group Visualization");
+ }
+ }
+#endif
+
+ /* effectors */
+ ListBase *effectors = pdInitEffectors_ex(scene, ob, psys, ob->lay, part->effector_weights, false);
+
+ if (effectors) {
+ for (EffectorCache *eff = (EffectorCache *)effectors->first; eff; eff = eff->next) {
+ if (eff->psys) {
+ // XXX: DAG_RL_DATA_DATA | DAG_RL_OB_DATA
+ ComponentKey eff_key(&eff->ob->id, DEPSNODE_TYPE_GEOMETRY); // xxx: particles instead?
+ add_relation(eff_key, psys_key, DEPSREL_TYPE_STANDARD, "Particle Field");
+ }
+ }
+ }
+
+ pdEndEffectors(&effectors);
+
+ /* boids */
+ if (part->boids) {
+ BoidRule *rule = NULL;
+ BoidState *state = NULL;
+
+ for (state = (BoidState *)part->boids->states.first; state; state = state->next) {
+ for (rule = (BoidRule *)state->rules.first; rule; rule = rule->next) {
+ Object *ruleob = NULL;
+ if (rule->type == eBoidRuleType_Avoid)
+ ruleob = ((BoidRuleGoalAvoid *)rule)->ob;
+ else if (rule->type == eBoidRuleType_FollowLeader)
+ ruleob = ((BoidRuleFollowLeader *)rule)->ob;
+
+ if (ruleob) {
+ ComponentKey ruleob_key(&ruleob->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(ruleob_key, psys_key, DEPSREL_TYPE_TRANSFORM, "Boid Rule");
+ }
+ }
+ }
+ }
+ }
+
+ /* pointcache */
+ // TODO...
+}
+
+/* IK Solver Eval Steps */
+void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map)
+{
+ bKinematicConstraint *data = (bKinematicConstraint *)con->data;
+
+ /* attach owner to IK Solver too
+ * - assume that owner is always part of chain
+ * - see notes on direction of rel below...
+ */
+ bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
+ OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER);
+
+ /* IK target */
+ // XXX: this should get handled as part of the constraint code
+ if (data->tar != NULL) {
+ /* TODO(sergey): For until we'll store partial matricies in the depsgraph,
+ * we create dependency between target object and pose eval component.
+ *
+ * This way we ensuring the whole subtree is updated from scratch without
+ * need of intermediate matricies. This is an overkill, but good enough for
+ * testing IK solver.
+ */
+ // FIXME: geometry targets...
+ ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
+ if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
+ /* TODO(sergey): This is only for until granular update stores intermediate result. */
+ if (data->tar != ob) {
+ /* different armature - can just read the results */
+ ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget);
+ add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ }
+ else {
+ /* same armature - we'll use the ready state only, just in case this bone is in the chain we're solving */
+ OperationKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget, DEG_OPCODE_BONE_DONE);
+ add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ }
+ }
+ else if (ELEM(data->tar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) {
+ /* vertex group target */
+ /* NOTE: for now, we don't need to represent vertex groups separately... */
+ ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
+
+ if (data->tar->type == OB_MESH) {
+ //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
+ }
+ else {
+ /* Standard Object Target */
+ ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ }
+
+ if ((data->tar == ob) && (data->subtarget[0])) {
+ /* Prevent target's constraints from linking to anything from same
+ * chain that it controls.
+ */
+ root_map->add_bone(data->subtarget, rootchan->name);
+ }
+ }
+
+ /* Pole Target */
+ // XXX: this should get handled as part of the constraint code
+ if (data->poletar != NULL) {
+ if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
+ // XXX: same armature issues - ready vs done?
+ ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->subtarget);
+ add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ }
+ else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) {
+ /* vertex group target */
+ /* NOTE: for now, we don't need to represent vertex groups separately... */
+ ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
+
+ if (data->poletar->type == OB_MESH) {
+ //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
+ }
+ else {
+ ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ }
+ }
+
+ DEG_DEBUG_PRINTF("\nStarting IK Build: pchan = %s, target = (%s, %s), segcount = %d\n",
+ pchan->name, data->tar->id.name, data->subtarget, data->rootbone);
+
+ bPoseChannel *parchan = pchan;
+ /* exclude tip from chain? */
+ if (!(data->flag & CONSTRAINT_IK_TIP)) {
+ OperationKey tip_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
+ parchan->name, DEG_OPCODE_BONE_LOCAL);
+ add_relation(solver_key, tip_transforms_key,
+ DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
+ parchan = pchan->parent;
+ }
+
+ root_map->add_bone(parchan->name, rootchan->name);
+
+ OperationKey parchan_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
+ parchan->name, DEG_OPCODE_BONE_READY);
+ add_relation(parchan_transforms_key, solver_key,
+ DEPSREL_TYPE_TRANSFORM, "IK Solver Owner");
+
+ /* Walk to the chain's root */
+ //size_t segcount = 0;
+ int segcount = 0;
+
+ while (parchan) {
+ /* Make IK-solver dependent on this bone's result,
+ * since it can only run after the standard results
+ * of the bone are know. Validate links step on the
+ * bone will ensure that users of this bone only
+ * grab the result with IK solver results...
+ */
+ if (parchan != pchan) {
+ OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
+ add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Parent");
+
+ OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
+ }
+ parchan->flag |= POSE_DONE;
+
+ OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
+
+ root_map->add_bone(parchan->name, rootchan->name);
+
+ /* continue up chain, until we reach target number of items... */
+ DEG_DEBUG_PRINTF(" %d = %s\n", segcount, parchan->name);
+ segcount++;
+ if ((segcount == data->rootbone) || (segcount > 255)) break; /* 255 is weak */
+
+ parchan = parchan->parent;
+ }
+
+ OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+ add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
+}
+
+/* Spline IK Eval Steps */
+void DepsgraphRelationBuilder::build_splineik_pose(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map)
+{
+ bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
+ bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
+ OperationKey transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
+ OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
+
+ /* attach owner to IK Solver too
+ * - assume that owner is always part of chain
+ * - see notes on direction of rel below...
+ */
+ add_relation(transforms_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Owner");
+
+ /* attach path dependency to solver */
+ if (data->tar) {
+ /* TODO(sergey): For until we'll store partial matricies in the depsgraph,
+ * we create dependency between target object and pose eval component.
+ * See IK pose for a bit more information.
+ */
+ // TODO: the bigggest point here is that we need the curve PATH and not just the general geometry...
+ ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
+ ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
+ add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, "[Curve.Path -> Spline IK] DepsRel");
+ }
+
+ pchan->flag |= POSE_DONE;
+ OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Result");
+
+ root_map->add_bone(pchan->name, rootchan->name);
+
+ /* Walk to the chain's root */
+ //size_t segcount = 0;
+ int segcount = 0;
+
+ for (bPoseChannel *parchan = pchan->parent; parchan; parchan = parchan->parent) {
+ /* Make Spline IK solver dependent on this bone's result,
+ * since it can only run after the standard results
+ * of the bone are know. Validate links step on the
+ * bone will ensure that users of this bone only
+ * grab the result with IK solver results...
+ */
+ if (parchan != pchan) {
+ OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
+ add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Update");
+
+ OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
+ }
+ parchan->flag |= POSE_DONE;
+
+ OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Result");
+
+ root_map->add_bone(parchan->name, rootchan->name);
+
+ /* continue up chain, until we reach target number of items... */
+ segcount++;
+ if ((segcount == data->chainlen) || (segcount > 255)) break; /* 255 is weak */
+ }
+
+ OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+ add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
+}
+
+/* Pose/Armature Bones Graph */
+void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
+{
+ /* Armature-Data */
+ // TODO: selection status?
+
+ /* attach links between pose operations */
+ OperationKey init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
+ OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+
+ add_relation(init_key, flush_key, DEPSREL_TYPE_COMPONENT_ORDER, "[Pose Init -> Pose Cleanup]");
+
+ if (ob->adt && (ob->adt->action || ob->adt->nla_tracks.first)) {
+ ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
+ add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation");
+ }
+
+ /* IK Solvers...
+ * - These require separate processing steps are pose-level
+ * to be executed between chains of bones (i.e. once the
+ * base transforms of a bunch of bones is done)
+ *
+ * - We build relations for these before the dependencies
+ * between ops in the same component as it is necessary
+ * to check whether such bones are in the same IK chain
+ * (or else we get weird issues with either in-chain
+ * references, or with bones being parented to IK'd bones)
+ *
+ * Unsolved Issues:
+ * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
+ * - Animated chain-lengths are a problem...
+ */
+ RootPChanMap root_map;
+ bool pose_depends_on_local_transform = false;
+ for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) {
+ switch (con->type) {
+ case CONSTRAINT_TYPE_KINEMATIC:
+ build_ik_pose(ob, pchan, con, &root_map);
+ pose_depends_on_local_transform = true;
+ break;
+
+ case CONSTRAINT_TYPE_SPLINEIK:
+ build_splineik_pose(ob, pchan, con, &root_map);
+ pose_depends_on_local_transform = true;
+ break;
+
+ /* Constraints which needs world's matrix for transform.
+ * TODO(sergey): More constraints here?
+ */
+ case CONSTRAINT_TYPE_ROTLIKE:
+ case CONSTRAINT_TYPE_SIZELIKE:
+ case CONSTRAINT_TYPE_LOCLIKE:
+ case CONSTRAINT_TYPE_TRANSLIKE:
+ /* TODO(sergey): Add used space check. */
+ pose_depends_on_local_transform = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ //root_map.print_debug();
+
+ if (pose_depends_on_local_transform) {
+ /* TODO(sergey): Once partial updates are possible use relation between
+ * object transform and solver itself in it's build function.
+ */
+ ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
+ ComponentKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(local_transform_key, pose_key, DEPSREL_TYPE_TRANSFORM, "Local Transforms");
+ }
+
+
+ /* links between operations for each bone */
+ for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
+ OperationKey bone_pose_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT);
+ OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
+ OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
+
+ pchan->flag &= ~POSE_DONE;
+
+ /* pose init to bone local */
+ add_relation(init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "PoseEval Source-Bone Link");
+
+ /* local to pose parenting operation */
+ add_relation(bone_local_key, bone_pose_key, DEPSREL_TYPE_OPERATION, "Bone Local - PoseSpace Link");
+
+ /* parent relation */
+ if (pchan->parent != NULL) {
+ eDepsOperation_Code parent_key_opcode;
+
+ /* NOTE: this difference in handling allows us to prevent lockups while ensuring correct poses for separate chains */
+ if (root_map.has_common_root(pchan->name, pchan->parent->name)) {
+ parent_key_opcode = DEG_OPCODE_BONE_READY;
+ }
+ else {
+ parent_key_opcode = DEG_OPCODE_BONE_DONE;
+ }
+
+ OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->parent->name, parent_key_opcode);
+ add_relation(parent_key, bone_pose_key, DEPSREL_TYPE_TRANSFORM, "[Parent Bone -> Child Bone]");
+ }
+
+ /* constraints */
+ if (pchan->constraints.first != NULL) {
+ /* constraints stack and constraint dependencies */
+ build_constraints(scene, &ob->id, DEPSNODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map);
+
+ /* pose -> constraints */
+ OperationKey constraints_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS);
+ add_relation(bone_pose_key, constraints_key, DEPSREL_TYPE_OPERATION, "Constraints Stack");
+
+ /* constraints -> ready */
+ // TODO: when constraint stack is exploded, this step should occur before the first IK solver
+ add_relation(constraints_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Constraints -> Ready");
+ }
+ else {
+ /* pose -> ready */
+ add_relation(bone_pose_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Pose -> Ready");
+ }
+
+ /* bone ready -> done
+ * NOTE: For bones without IK, this is all that's needed.
+ * For IK chains however, an additional rel is created from IK to done,
+ * with transitive reduction removing this one...
+ */
+ add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
+
+ /* assume that all bones must be done for the pose to be ready (for deformers) */
+ add_relation(bone_done_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
+ }
+}
+
+void DepsgraphRelationBuilder::build_proxy_rig(Object *ob)
+{
+ OperationKey pose_init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
+ OperationKey pose_done_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+ for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first;
+ pchan != NULL;
+ pchan = pchan->next)
+ {
+ OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
+ OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
+ OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(pose_init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "Pose Init -> Bone Local");
+ add_relation(bone_local_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Local -> Ready");
+ add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
+ add_relation(bone_done_key, pose_done_key, DEPSREL_TYPE_OPERATION, "Bone Done -> Pose Done");
+ }
+}
+
+/* Shapekeys */
+void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key)
+{
+ ComponentKey obdata_key(obdata, DEPSNODE_TYPE_GEOMETRY);
+
+ /* attach animdata to geometry */
+ build_animdata(&key->id);
+
+ if (key->adt) {
+ // TODO: this should really be handled in build_animdata, since many of these cases will need it
+ if (key->adt->action || key->adt->nla_tracks.first) {
+ ComponentKey adt_key(&key->id, DEPSNODE_TYPE_ANIMATION);
+ add_relation(adt_key, obdata_key, DEPSREL_TYPE_OPERATION, "Animation");
+ }
+
+ /* NOTE: individual shapekey drivers are handled above already */
+ }
+
+ /* attach to geometry */
+ // XXX: aren't shapekeys now done as a pseudo-modifier on object?
+ //ComponentKey key_key(&key->id, DEPSNODE_TYPE_GEOMETRY); // FIXME: this doesn't exist
+ //add_relation(key_key, obdata_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Shapekeys");
+}
+
+/**
+ * ObData Geometry Evaluation
+ * ==========================
+ *
+ * The evaluation of geometry on objects is as follows:
+ * - The actual evaluated of the derived geometry (e.g. DerivedMesh, DispList, etc.)
+ * occurs in the Geometry component of the object which references this. This includes
+ * modifiers, and the temporary "ubereval" for geometry.
+ * - Therefore, each user of a piece of shared geometry data ends up evaluating its own
+ * version of the stuff, complete with whatever modifiers it may use.
+ *
+ * - The datablocks for the geometry data - "obdata" (e.g. ID_ME, ID_CU, ID_LT, etc.) are used for
+ * 1) calculating the bounding boxes of the geometry data,
+ * 2) aggregating inward links from other objects (e.g. for text on curve, etc.)
+ * and also for the links coming from the shapekey datablocks
+ * - Animation/Drivers affecting the parameters of the geometry are made to trigger
+ * updates on the obdata geometry component, which then trigger downstream
+ * re-evaluation of the individual instances of this geometry.
+ */
+// TODO: Materials and lighting should probably get their own component, instead of being lumped under geometry?
+void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Object *ob)
+{
+ ID *obdata = (ID *)ob->data;
+
+ /* Init operation of object-level geometry evaluation. */
+ OperationKey geom_init_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Eval Init");
+
+ /* get nodes for result of obdata's evaluation, and geometry evaluation on object */
+ ComponentKey obdata_geom_key(obdata, DEPSNODE_TYPE_GEOMETRY);
+ ComponentKey geom_key(&ob->id, DEPSNODE_TYPE_GEOMETRY);
+
+ /* link components to each other */
+ add_relation(obdata_geom_key, geom_key, DEPSREL_TYPE_DATABLOCK, "Object Geometry Base Data");
+
+ /* Modifiers */
+ if (ob->modifiers.first) {
+ ModifierData *md;
+ OperationKey prev_mod_key;
+
+ for (md = (ModifierData *)ob->modifiers.first; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type);
+ OperationKey mod_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_MODIFIER, md->name);
+
+ if (md->prev) {
+ /* Stack relation: modifier depends on previous modifier in the stack */
+ add_relation(prev_mod_key, mod_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Modifier Stack");
+ }
+ else {
+ /* Stack relation: first modifier depends on the geometry. */
+ add_relation(geom_init_key, mod_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Modifier Stack");
+ }
+
+ if (mti->updateDepsgraph) {
+ DepsNodeHandle handle = create_node_handle(mod_key);
+ mti->updateDepsgraph(md, bmain, scene, ob, &handle);
+ }
+
+ if (BKE_object_modifier_use_time(ob, md)) {
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, mod_key, DEPSREL_TYPE_TIME, "Time Source");
+ }
+
+ prev_mod_key = mod_key;
+ }
+ }
+
+ /* materials */
+ if (ob->totcol) {
+ int a;
+
+ for (a = 1; a <= ob->totcol; a++) {
+ Material *ma = give_current_material(ob, a);
+
+ if (ma)
+ build_material(&ob->id, ma);
+ }
+ }
+
+ /* geometry collision */
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_LATTICE)) {
+ // add geometry collider relations
+ }
+
+ /* Make sure uber update is the last in the dependencies.
+ *
+ * TODO(sergey): Get rid of this node.
+ */
+ if (ob->type != OB_ARMATURE) {
+ /* Armatures does no longer require uber node. */
+ OperationKey obdata_ubereval_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_UBEREVAL);
+ if (ob->modifiers.last) {
+ ModifierData *md = (ModifierData *)ob->modifiers.last;
+ OperationKey mod_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_MODIFIER, md->name);
+ add_relation(mod_key, obdata_ubereval_key, DEPSREL_TYPE_OPERATION, "Object Geometry UberEval");
+ }
+ else {
+ add_relation(geom_init_key, obdata_ubereval_key, DEPSREL_TYPE_OPERATION, "Object Geometry UberEval");
+ }
+ }
+
+ if (obdata->flag & LIB_DOIT) {
+ return;
+ }
+ obdata->flag |= LIB_DOIT;
+
+ /* Link object data evaluation node to exit operation. */
+ OperationKey obdata_geom_eval_key(obdata, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ OperationKey obdata_geom_done_key(obdata, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Eval Done");
+ add_relation(obdata_geom_eval_key, obdata_geom_done_key, DEPSREL_TYPE_DATABLOCK, "ObData Geom Eval Done");
+
+ /* type-specific node/links */
+ switch (ob->type) {
+ case OB_MESH:
+ break;
+
+ case OB_MBALL:
+ {
+ Object *mom = BKE_mball_basis_find(scene, ob);
+
+ /* motherball - mom depends on children! */
+ if (mom != ob) {
+ /* non-motherball -> cannot be directly evaluated! */
+ ComponentKey mom_key(&mom->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(geom_key, mom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Metaball Motherball");
+ }
+ break;
+ }
+
+ case OB_CURVE:
+ case OB_FONT:
+ {
+ Curve *cu = (Curve *)obdata;
+
+ /* curve's dependencies */
+ // XXX: these needs geom data, but where is geom stored?
+ if (cu->bevobj) {
+ ComponentKey bevob_key(&cu->bevobj->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(bevob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Bevel");
+ }
+ if (cu->taperobj) {
+ ComponentKey taperob_key(&cu->taperobj->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(taperob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Taper");
+ }
+ if (ob->type == OB_FONT) {
+ if (cu->textoncurve) {
+ ComponentKey textoncurve_key(&cu->taperobj->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(textoncurve_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Text on Curve");
+ }
+ }
+ break;
+ }
+
+ case OB_SURF: /* Nurbs Surface */
+ {
+ break;
+ }
+
+ case OB_LATTICE: /* Lattice */
+ {
+ break;
+ }
+ }
+
+ /* ShapeKeys */
+ Key *key = BKE_key_from_object(ob);
+ if (key) {
+ build_shapekeys(obdata, key);
+ }
+
+ if (needs_animdata_node(obdata)) {
+ ComponentKey animation_key(obdata, DEPSNODE_TYPE_ANIMATION);
+ ComponentKey parameters_key(obdata, DEPSNODE_TYPE_PARAMETERS);
+ add_relation(animation_key, parameters_key,
+ DEPSREL_TYPE_COMPONENT_ORDER, "Geom Parameters");
+ }
+}
+
+/* Cameras */
+// TODO: Link scene-camera links in somehow...
+void DepsgraphRelationBuilder::build_camera(Object *ob)
+{
+ Camera *cam = (Camera *)ob->data;
+ ID *camera_id = &cam->id;
+ if (camera_id->flag & LIB_DOIT) {
+ return;
+ }
+ camera_id->flag |= LIB_DOIT;
+
+ ComponentKey parameters_key(camera_id, DEPSNODE_TYPE_PARAMETERS);
+
+ if (needs_animdata_node(camera_id)) {
+ ComponentKey animation_key(camera_id, DEPSNODE_TYPE_ANIMATION);
+ add_relation(animation_key, parameters_key,
+ DEPSREL_TYPE_COMPONENT_ORDER, "Camera Parameters");
+ }
+
+ /* DOF */
+ if (cam->dof_ob) {
+ ComponentKey ob_param_key(&ob->id, DEPSNODE_TYPE_PARAMETERS);
+ ComponentKey dof_ob_key(&cam->dof_ob->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(dof_ob_key, ob_param_key, DEPSREL_TYPE_TRANSFORM, "Camera DOF");
+ }
+}
+
+/* Lamps */
+void DepsgraphRelationBuilder::build_lamp(Object *ob)
+{
+ Lamp *la = (Lamp *)ob->data;
+ ID *lamp_id = &la->id;
+ if (lamp_id->flag & LIB_DOIT) {
+ return;
+ }
+ lamp_id->flag |= LIB_DOIT;
+
+ ComponentKey parameters_key(lamp_id, DEPSNODE_TYPE_PARAMETERS);
+
+ if (needs_animdata_node(lamp_id)) {
+ ComponentKey animation_key(lamp_id, DEPSNODE_TYPE_ANIMATION);
+ add_relation(animation_key, parameters_key,
+ DEPSREL_TYPE_COMPONENT_ORDER, "Lamp Parameters");
+ }
+
+ /* lamp's nodetree */
+ if (la->nodetree) {
+ build_nodetree(lamp_id, la->nodetree);
+ ComponentKey nodetree_key(&la->nodetree->id, DEPSNODE_TYPE_PARAMETERS);
+ add_relation(nodetree_key, parameters_key,
+ DEPSREL_TYPE_COMPONENT_ORDER, "NTree->Lamp Parameters");
+ }
+
+ /* textures */
+ build_texture_stack(lamp_id, la->mtex);
+}
+
+void DepsgraphRelationBuilder::build_nodetree(ID *owner, bNodeTree *ntree)
+{
+ if (!ntree)
+ return;
+
+ ID *ntree_id = &ntree->id;
+
+ build_animdata(ntree_id);
+
+ /* nodetree's nodes... */
+ for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) {
+ if (bnode->id) {
+ if (GS(bnode->id->name) == ID_MA) {
+ build_material(owner, (Material *)bnode->id);
+ }
+ else if (bnode->type == ID_TE) {
+ build_texture(owner, (Tex *)bnode->id);
+ }
+ else if (bnode->type == NODE_GROUP) {
+ bNodeTree *ntree = (bNodeTree *)bnode->id;
+ if ((ntree_id->flag & LIB_DOIT) == 0) {
+ build_nodetree(owner, ntree);
+ ntree_id->flag |= LIB_DOIT;
+ }
+ }
+ }
+ }
+
+ if (needs_animdata_node(ntree_id)) {
+ ComponentKey parameters_key(ntree_id, DEPSNODE_TYPE_PARAMETERS);
+ ComponentKey animation_key(ntree_id, DEPSNODE_TYPE_ANIMATION);
+ add_relation(animation_key, parameters_key,
+ DEPSREL_TYPE_COMPONENT_ORDER, "NTree Parameters");
+ }
+
+ // TODO: link from nodetree to owner_component?
+}
+
+/* Recursively build graph for material */
+void DepsgraphRelationBuilder::build_material(ID *owner, Material *ma)
+{
+ ID *ma_id = &ma->id;
+ if (ma_id->flag & LIB_DOIT) {
+ return;
+ }
+ ma_id->flag |= LIB_DOIT;
+
+ /* animation */
+ build_animdata(ma_id);
+
+ /* textures */
+ build_texture_stack(owner, ma->mtex);
+
+ /* material's nodetree */
+ build_nodetree(owner, ma->nodetree);
+}
+
+/* Recursively build graph for texture */
+void DepsgraphRelationBuilder::build_texture(ID *owner, Tex *tex)
+{
+ ID *tex_id = &tex->id;
+ if (tex_id->flag & LIB_DOIT) {
+ return;
+ }
+ tex_id->flag |= LIB_DOIT;
+
+ /* texture itself */
+ build_animdata(tex_id);
+
+ /* texture's nodetree */
+ build_nodetree(owner, tex->nodetree);
+}
+
+/* Texture-stack attached to some shading datablock */
+void DepsgraphRelationBuilder::build_texture_stack(ID *owner, MTex **texture_stack)
+{
+ int i;
+
+ /* for now assume that all texture-stacks have same number of max items */
+ for (i = 0; i < MAX_MTEX; i++) {
+ MTex *mtex = texture_stack[i];
+ if (mtex && mtex->tex)
+ build_texture(owner, mtex->tex);
+ }
+}
+
+void DepsgraphRelationBuilder::build_compositor(Scene *scene)
+{
+ /* For now, just a plain wrapper? */
+ build_nodetree(&scene->id, scene->nodetree);
+}
+
+void DepsgraphRelationBuilder::build_gpencil(ID *UNUSED(owner), bGPdata *gpd)
+{
+ /* animation */
+ build_animdata(&gpd->id);
+
+ // TODO: parent object (when that feature is implemented)
+}
+
+bool DepsgraphRelationBuilder::needs_animdata_node(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt != NULL) {
+ return adt->action != NULL;
+ }
+ return false;
+}
+
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
new file mode 100644
index 00000000000..59351495df0
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -0,0 +1,1193 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_debug.cc
+ * \ingroup depsgraph
+ *
+ * Implementation of tools for debugging the depsgraph
+ */
+
+//#include <stdlib.h>
+#include <string.h>
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_ghash.h"
+#include "BLI_string.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_build.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+} /* extern "C" */
+
+#include "depsgraph_debug.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_intern.h"
+
+/* ****************** */
+/* Graphviz Debugging */
+
+static SpinLock lock;
+
+#define NL "\r\n"
+
+/* Only one should be enabled, defines whether graphviz nodes
+ * get colored by individual types or classes.
+ */
+#define COLOR_SCHEME_NODE_CLASS 1
+//#define COLOR_SCHEME_NODE_TYPE 2
+
+static const char *deg_debug_graphviz_fontname = "helvetica";
+static float deg_debug_graphviz_graph_label_size = 20.0f;
+static float deg_debug_graphviz_node_label_size = 14.0f;
+static const int deg_debug_max_colors = 12;
+#if 0
+static const char *deg_debug_colors_dark[] = {
+ "#6e8997", "#144f77", "#76945b",
+ "#216a1d", "#a76665", "#971112",
+ "#a87f49", "#0a9540", "#86768e",
+ "#462866", "#a9a965", "#753b1a",
+};
+#endif
+#ifdef COLOR_SCHEME_NODE_TYPE
+static const char *deg_debug_colors[] = {
+ "#a6cee3", "#1f78b4", "#b2df8a",
+ "#33a02c", "#fb9a99", "#e31a1c",
+ "#fdbf6f", "#ff7f00", "#cab2d6",
+ "#6a3d9a", "#ffff99", "#b15928",
+};
+#endif
+static const char *deg_debug_colors_light[] = {
+ "#8dd3c7", "#ffffb3", "#bebada",
+ "#fb8072", "#80b1d3", "#fdb462",
+ "#b3de69", "#fccde5", "#d9d9d9",
+ "#bc80bd", "#ccebc5", "#ffed6f",
+};
+
+#ifdef COLOR_SCHEME_NODE_TYPE
+static const int deg_debug_node_type_color_map[][2] = {
+ {DEPSNODE_TYPE_ROOT, 0},
+ {DEPSNODE_TYPE_TIMESOURCE, 1},
+ {DEPSNODE_TYPE_ID_REF, 2},
+ {DEPSNODE_TYPE_SUBGRAPH, 3},
+
+ /* Outer Types */
+ {DEPSNODE_TYPE_PARAMETERS, 4},
+ {DEPSNODE_TYPE_PROXY, 5},
+ {DEPSNODE_TYPE_ANIMATION, 6},
+ {DEPSNODE_TYPE_TRANSFORM, 7},
+ {DEPSNODE_TYPE_GEOMETRY, 8},
+ {DEPSNODE_TYPE_SEQUENCER, 9},
+ {DEPSNODE_TYPE_SHADING, 10},
+ {-1, 0}
+};
+#endif
+
+#if 0 /* unused */
+static const int deg_debug_relation_type_color_map[][2] = {
+ {DEPSREL_TYPE_STANDARD, 0},
+ {DEPSREL_TYPE_ROOT_TO_ACTIVE, 1},
+ {DEPSREL_TYPE_DATABLOCK, 2},
+ {DEPSREL_TYPE_TIME, 3},
+ {DEPSREL_TYPE_COMPONENT_ORDER, 4},
+ {DEPSREL_TYPE_OPERATION, 5},
+ {DEPSREL_TYPE_DRIVER, 6},
+ {DEPSREL_TYPE_DRIVER_TARGET, 7},
+ {DEPSREL_TYPE_TRANSFORM, 8},
+ {DEPSREL_TYPE_GEOMETRY_EVAL, 9},
+ {DEPSREL_TYPE_UPDATE, 10},
+ {DEPSREL_TYPE_UPDATE_UI, 11},
+ {-1, 0}
+};
+#endif
+
+static int deg_debug_node_color_index(const DepsNode *node)
+{
+#ifdef COLOR_SCHEME_NODE_CLASS
+ /* Some special types. */
+ switch (node->type) {
+ case DEPSNODE_TYPE_ID_REF:
+ return 5;
+ case DEPSNODE_TYPE_OPERATION:
+ {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->is_noop())
+ return 8;
+ }
+
+ default:
+ break;
+ }
+ /* Do others based on class. */
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_OPERATION:
+ return 4;
+ case DEPSNODE_CLASS_COMPONENT:
+ return 1;
+ default:
+ return 9;
+ }
+#endif
+
+#ifdef COLOR_SCHEME_NODE_TYPE
+ const int (*pair)[2];
+ for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
+ if ((*pair)[0] == node->type) {
+ return (*pair)[1];
+ }
+ }
+ return -1;
+#endif
+}
+
+struct DebugContext {
+ FILE *file;
+ bool show_tags;
+ bool show_eval_priority;
+};
+
+static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) ATTR_PRINTF_FORMAT(2, 3);
+static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(ctx.file, fmt, args);
+ va_end(args);
+}
+
+static void deg_debug_graphviz_legend_color(const DebugContext &ctx,
+ const char *name,
+ const char *color)
+{
+ deg_debug_fprintf(ctx, "<TR>");
+ deg_debug_fprintf(ctx, "<TD>%s</TD>", name);
+ deg_debug_fprintf(ctx, "<TD BGCOLOR=\"%s\"></TD>", color);
+ deg_debug_fprintf(ctx, "</TR>" NL);
+}
+
+#if 0
+static void deg_debug_graphviz_legend_line(const DebugContext &ctx,
+ const char *name,
+ const char *color,
+ const char *style)
+{
+ /* XXX TODO */
+ deg_debug_fprintf(ctx, "" NL);
+}
+
+static void deg_debug_graphviz_legend_cluster(const DebugContext &ctx,
+ const char *name,
+ const char *color,
+ const char *style)
+{
+ deg_debug_fprintf(ctx, "<TR>");
+ deg_debug_fprintf(ctx, "<TD>%s</TD>", name);
+ deg_debug_fprintf(ctx, "<TD CELLPADDING=\"4\"><TABLE BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">");
+ deg_debug_fprintf(ctx, "<TR><TD BGCOLOR=\"%s\"></TD></TR>", color);
+ deg_debug_fprintf(ctx, "</TABLE></TD>");
+ deg_debug_fprintf(ctx, "</TR>" NL);
+}
+#endif
+
+static void deg_debug_graphviz_legend(const DebugContext &ctx)
+{
+ deg_debug_fprintf(ctx, "{" NL);
+ deg_debug_fprintf(ctx, "rank = sink;" NL);
+ deg_debug_fprintf(ctx, "Legend [shape=none, margin=0, label=<" NL);
+ deg_debug_fprintf(ctx, " <TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">" NL);
+ deg_debug_fprintf(ctx, "<TR><TD COLSPAN=\"2\"><B>Legend</B></TD></TR>" NL);
+
+#ifdef COLOR_SCHEME_NODE_CLASS
+ const char **colors = deg_debug_colors_light;
+ deg_debug_graphviz_legend_color(ctx, "Operation", colors[4]);
+ deg_debug_graphviz_legend_color(ctx, "Component", colors[1]);
+ deg_debug_graphviz_legend_color(ctx, "ID Node", colors[5]);
+ deg_debug_graphviz_legend_color(ctx, "NOOP", colors[8]);
+#endif
+
+#ifdef COLOR_SCHEME_NODE_TYPE
+ const int (*pair)[2];
+ for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
+ DepsNodeFactory *nti = DEG_get_node_factory((eDepsNode_Type)(*pair)[0]);
+ deg_debug_graphviz_legend_color(ctx,
+ nti->tname().c_str(),
+ deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]);
+ }
+#endif
+
+ deg_debug_fprintf(ctx, "</TABLE>" NL);
+ deg_debug_fprintf(ctx, ">" NL);
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, "}" NL);
+}
+
+#if 0 /* unused */
+static int deg_debug_relation_type_color_index(eDepsRelation_Type type)
+{
+ const int (*pair)[2];
+ for (pair = deg_debug_relation_type_color_map; (*pair)[0] >= 0; ++pair) {
+ if ((*pair)[0] == type) {
+ return (*pair)[1];
+ }
+ }
+ return -1;
+}
+#endif
+
+static void deg_debug_graphviz_node_color(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *color_default = "black";
+ const char *color_modified = "orangered4";
+ const char *color_update = "dodgerblue3";
+ const char *color = color_default;
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
+ color = color_modified;
+ }
+ else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ color = color_update;
+ }
+ }
+ }
+ deg_debug_fprintf(ctx, "\"%s\"", color);
+}
+
+static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ float penwidth_default = 1.0f;
+ float penwidth_modified = 4.0f;
+ float penwidth_update = 4.0f;
+ float penwidth = penwidth_default;
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
+ penwidth = penwidth_modified;
+ }
+ else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ penwidth = penwidth_update;
+ }
+ }
+ }
+ deg_debug_fprintf(ctx, "\"%f\"", penwidth);
+}
+
+static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *defaultcolor = "gainsboro";
+ int color_index = deg_debug_node_color_index(node);
+ const char *fillcolor = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors];
+ deg_debug_fprintf(ctx, "\"%s\"", fillcolor);
+}
+
+#if 0 /* implementation using stripes, a bit too noisy ... */
+static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *defaultcolor = "gainsboro";
+ const char *color_needs_update = "orange";
+ const int num_stripes = 10;
+ int color_index = deg_debug_node_color_index(node);
+ const char *base_color = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors];
+ if (ctx.show_tags &&
+ (node->flag & (DEPSNODE_FLAG_DIRECTLY_MODIFIED | DEPSNODE_FLAG_NEEDS_UPDATE))) {
+ deg_debug_fprintf(ctx, "\"");
+ for (int i = 0; i < num_stripes; ++i) {
+ if (i > 0) {
+ deg_debug_fprintf(ctx, ":");
+ }
+ deg_debug_fprintf(ctx, "%s:%s", base_color, color_needs_update);
+ }
+ deg_debug_fprintf(ctx, "\"");
+ }
+ else {
+ deg_debug_fprintf(ctx, "\"%s\"", base_color);
+ }
+}
+#endif
+
+static void deg_debug_graphviz_relation_color(const DebugContext &ctx,
+ const DepsRelation *UNUSED(rel))
+{
+ const char *defaultcolor = "black";
+#if 0 /* disabled for now, edge colors are hardly distinguishable */
+ int color = deg_debug_relation_type_color_index(rel->type);
+ if (color < 0) {
+ deg_debug_fprintf(ctx, "%s", defaultcolor);
+ }
+ else {
+ deg_debug_fprintf(ctx, "\"%s\"", deg_debug_colors_dark[color % deg_debug_max_colors]);
+ }
+#else
+ deg_debug_fprintf(ctx, "%s", defaultcolor);
+#endif
+}
+
+static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNode *node)
+{
+ const char *base_style = "filled"; /* default style */
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) {
+ base_style = "striped";
+ }
+ }
+ }
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_GENERIC:
+ deg_debug_fprintf(ctx, "\"%s\"", base_style);
+ break;
+ case DEPSNODE_CLASS_COMPONENT:
+ deg_debug_fprintf(ctx, "\"%s\"", base_style);
+ break;
+ case DEPSNODE_CLASS_OPERATION:
+ deg_debug_fprintf(ctx, "\"%s,rounded\"", base_style);
+ break;
+ }
+}
+
+static void deg_debug_graphviz_node_single(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *shape = "box";
+ string name = node->identifier();
+ float priority = -1.0f;
+ if (node->type == DEPSNODE_TYPE_ID_REF) {
+ IDDepsNode *id_node = (IDDepsNode *)node;
+ char buf[256];
+ BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
+ name += buf;
+ }
+ if (ctx.show_eval_priority && node->tclass == DEPSNODE_CLASS_OPERATION) {
+ priority = ((OperationDepsNode *)node)->eval_priority;
+ }
+ deg_debug_fprintf(ctx, "// %s\n", name.c_str());
+ deg_debug_fprintf(ctx, "\"node_%p\"", node);
+ deg_debug_fprintf(ctx, "[");
+// deg_debug_fprintf(ctx, "label=<<B>%s</B>>", name);
+ if (priority >= 0.0f) {
+ deg_debug_fprintf(ctx, "label=<%s<BR/>(<I>%.2f</I>)>",
+ name.c_str(),
+ priority);
+ }
+ else {
+ deg_debug_fprintf(ctx, "label=<%s>", name.c_str());
+ }
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_node_label_size);
+ deg_debug_fprintf(ctx, ",shape=%s", shape);
+ deg_debug_fprintf(ctx, ",style="); deg_debug_graphviz_node_style(ctx, node);
+ deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_node_color(ctx, node);
+ deg_debug_fprintf(ctx, ",fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node);
+ deg_debug_fprintf(ctx, ",penwidth="); deg_debug_graphviz_node_penwidth(ctx, node);
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ string name = node->identifier().c_str();
+ if (node->type == DEPSNODE_TYPE_ID_REF) {
+ IDDepsNode *id_node = (IDDepsNode *)node;
+ char buf[256];
+ BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
+ name += buf;
+ }
+ deg_debug_fprintf(ctx, "// %s\n", name.c_str());
+ deg_debug_fprintf(ctx, "subgraph \"cluster_%p\" {" NL, node);
+// deg_debug_fprintf(ctx, "label=<<B>%s</B>>;" NL, name);
+ deg_debug_fprintf(ctx, "label=<%s>;" NL, name.c_str());
+ deg_debug_fprintf(ctx, "fontname=\"%s\";" NL, deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, "fontsize=%f;" NL, deg_debug_graphviz_node_label_size);
+ deg_debug_fprintf(ctx, "style="); deg_debug_graphviz_node_style(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "color="); deg_debug_graphviz_node_color(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "penwidth="); deg_debug_graphviz_node_penwidth(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ /* dummy node, so we can add edges between clusters */
+ deg_debug_fprintf(ctx, "\"node_%p\"", node);
+ deg_debug_fprintf(ctx, "[");
+ deg_debug_fprintf(ctx, "shape=%s", "point");
+ deg_debug_fprintf(ctx, ",style=%s", "invis");
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_node_cluster_end(const DebugContext &ctx)
+{
+ deg_debug_fprintf(ctx, "}" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
+ const Depsgraph *graph);
+static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
+ const Depsgraph *graph);
+
+static void deg_debug_graphviz_node(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ switch (node->type) {
+ case DEPSNODE_TYPE_ID_REF:
+ {
+ const IDDepsNode *id_node = (const IDDepsNode *)node;
+ if (id_node->components.empty()) {
+ deg_debug_graphviz_node_single(ctx, node);
+ }
+ else {
+ deg_debug_graphviz_node_cluster_begin(ctx, node);
+ for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
+ it != id_node->components.end();
+ ++it)
+ {
+ const ComponentDepsNode *comp = it->second;
+ deg_debug_graphviz_node(ctx, comp);
+ }
+ deg_debug_graphviz_node_cluster_end(ctx);
+ }
+ break;
+ }
+ case DEPSNODE_TYPE_SUBGRAPH:
+ {
+ SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
+ if (sub_node->graph) {
+ deg_debug_graphviz_node_cluster_begin(ctx, node);
+ deg_debug_graphviz_graph_nodes(ctx, sub_node->graph);
+ deg_debug_graphviz_node_cluster_end(ctx);
+ }
+ else {
+ deg_debug_graphviz_node_single(ctx, node);
+ }
+ break;
+ }
+ case DEPSNODE_TYPE_PARAMETERS:
+ case DEPSNODE_TYPE_ANIMATION:
+ case DEPSNODE_TYPE_TRANSFORM:
+ case DEPSNODE_TYPE_PROXY:
+ case DEPSNODE_TYPE_GEOMETRY:
+ case DEPSNODE_TYPE_SEQUENCER:
+ case DEPSNODE_TYPE_EVAL_POSE:
+ case DEPSNODE_TYPE_BONE:
+ case DEPSNODE_TYPE_SHADING:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ if (!comp_node->operations.empty()) {
+ deg_debug_graphviz_node_cluster_begin(ctx, node);
+ for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
+ it != comp_node->operations.end();
+ ++it)
+ {
+ const DepsNode *op_node = it->second;
+ deg_debug_graphviz_node(ctx, op_node);
+ }
+ deg_debug_graphviz_node_cluster_end(ctx);
+ }
+ else {
+ deg_debug_graphviz_node_single(ctx, node);
+ }
+ break;
+ }
+ default:
+ deg_debug_graphviz_node_single(ctx, node);
+ break;
+ }
+}
+
+static bool deg_debug_graphviz_is_cluster(const DepsNode *node)
+{
+ switch (node->type) {
+ case DEPSNODE_TYPE_ID_REF:
+ {
+ const IDDepsNode *id_node = (const IDDepsNode *)node;
+ return !id_node->components.empty();
+ }
+ case DEPSNODE_TYPE_SUBGRAPH:
+ {
+ SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
+ return sub_node->graph != NULL;
+ }
+ case DEPSNODE_TYPE_PARAMETERS:
+ case DEPSNODE_TYPE_ANIMATION:
+ case DEPSNODE_TYPE_TRANSFORM:
+ case DEPSNODE_TYPE_PROXY:
+ case DEPSNODE_TYPE_GEOMETRY:
+ case DEPSNODE_TYPE_SEQUENCER:
+ case DEPSNODE_TYPE_EVAL_POSE:
+ case DEPSNODE_TYPE_BONE:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ return !comp_node->operations.empty();
+ }
+ default:
+ return false;
+ }
+}
+
+static bool deg_debug_graphviz_is_owner(const DepsNode *node,
+ const DepsNode *other)
+{
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_COMPONENT:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ if (comp_node->owner == other)
+ return true;
+ break;
+ }
+ case DEPSNODE_CLASS_OPERATION:
+ {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->owner == other)
+ return true;
+ else if (op_node->owner->owner == other)
+ return true;
+ break;
+ }
+ default: break;
+ }
+ return false;
+}
+
+static void deg_debug_graphviz_node_relations(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ DEPSNODE_RELATIONS_ITER_BEGIN(node->inlinks, rel)
+ {
+ const DepsNode *tail = rel->to; /* same as node */
+ const DepsNode *head = rel->from;
+ deg_debug_fprintf(ctx, "// %s -> %s\n",
+ head->identifier().c_str(),
+ tail->identifier().c_str());
+ deg_debug_fprintf(ctx, "\"node_%p\"", head);
+ deg_debug_fprintf(ctx, " -> ");
+ deg_debug_fprintf(ctx, "\"node_%p\"", tail);
+
+ deg_debug_fprintf(ctx, "[");
+ deg_debug_fprintf(ctx, "label=\"%s\"", rel->name);
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_relation_color(ctx, rel);
+ /* NOTE: edge from node to own cluster is not possible and gives graphviz
+ * warning, avoid this here by just linking directly to the invisible
+ * placeholder node
+ */
+ if (deg_debug_graphviz_is_cluster(tail) && !deg_debug_graphviz_is_owner(head, tail)) {
+ deg_debug_fprintf(ctx, ",ltail=\"cluster_%p\"", tail);
+ }
+ if (deg_debug_graphviz_is_cluster(head) && !deg_debug_graphviz_is_owner(tail, head)) {
+ deg_debug_fprintf(ctx, ",lhead=\"cluster_%p\"", head);
+ }
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+ }
+ DEPSNODE_RELATIONS_ITER_END;
+
+#if 0
+ if (node->tclass == DEPSNODE_CLASS_COMPONENT) {
+ const ComponentDepsNode *comp_node = (const ComponentDepsNode *)node;
+ for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
+ it != comp_node->operations.end();
+ ++it)
+ {
+ OperationDepsNode *op_node = it->second;
+ deg_debug_graphviz_node_relations(ctx, op_node);
+ }
+ }
+ else if (node->type == DEPSNODE_TYPE_ID_REF) {
+ const IDDepsNode *id_node = (const IDDepsNode *)node;
+ for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
+ it != id_node->components.end();
+ ++it)
+ {
+ const ComponentDepsNode *comp = it->second;
+ deg_debug_graphviz_node_relations(ctx, comp);
+ }
+ }
+ else if (node->type == DEPSNODE_TYPE_SUBGRAPH) {
+ SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
+ if (sub_node->graph) {
+ deg_debug_graphviz_graph_relations(ctx, sub_node->graph);
+ }
+ }
+#endif
+}
+
+static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
+ const Depsgraph *graph)
+{
+ if (graph->root_node) {
+ deg_debug_graphviz_node(ctx, graph->root_node);
+ }
+ for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
+ it != graph->id_hash.end();
+ ++it)
+ {
+ DepsNode *node = it->second;
+ deg_debug_graphviz_node(ctx, node);
+ }
+ TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ if (time_source != NULL) {
+ deg_debug_graphviz_node(ctx, time_source);
+ }
+}
+
+static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
+ const Depsgraph *graph)
+{
+#if 0
+ if (graph->root_node) {
+ deg_debug_graphviz_node_relations(ctx, graph->root_node);
+ }
+ for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
+ it != graph->id_hash.end();
+ ++it)
+ {
+ DepsNode *id_node = it->second;
+ deg_debug_graphviz_node_relations(ctx, id_node);
+ }
+#else
+ /* XXX not in use yet */
+// for (Depsgraph::OperationNodes::const_iterator it = graph->all_opnodes.begin();
+// it != graph->all_opnodes.end();
+// ++it)
+// {
+// OperationDepsNode *op_node = *it;
+// deg_debug_graphviz_node_relations(ctx, op_node);
+// }
+ for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
+ it != graph->id_hash.end();
+ ++it)
+ {
+ IDDepsNode *id_node = it->second;
+ for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
+ it != id_node->components.end();
+ ++it)
+ {
+ ComponentDepsNode *comp_node = it->second;
+ for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
+ it != comp_node->operations.end();
+ ++it)
+ {
+ OperationDepsNode *op_node = it->second;
+ deg_debug_graphviz_node_relations(ctx, op_node);
+ }
+ }
+ }
+
+ TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ if (time_source != NULL) {
+ deg_debug_graphviz_node_relations(ctx, time_source);
+ }
+#endif
+}
+
+void DEG_debug_graphviz(const Depsgraph *graph, FILE *f, const char *label, bool show_eval)
+{
+#if 0 /* generate shaded color set */
+ static char colors[][3] = {{0xa6, 0xce, 0xe3},{0x1f, 0x78, 0xb4},{0xb2, 0xdf, 0x8a},{0x33, 0xa0, 0x2c},
+ {0xfb, 0x9a, 0x99},{0xe3, 0x1a, 0x1c},{0xfd, 0xbf, 0x6f},{0xff, 0x7f, 0x00},
+ {0xca, 0xb2, 0xd6},{0x6a, 0x3d, 0x9a},{0xff, 0xff, 0x99},{0xb1, 0x59, 0x28}};
+ int i;
+ const float factor = 0.666f;
+ for (i=0; i < 12; ++i)
+ printf("\"#%x%x%x\"\n", (char)(colors[i][0] * factor), (char)(colors[i][1] * factor), (char)(colors[i][2] * factor));
+#endif
+
+ if (!graph) {
+ return;
+ }
+
+ DebugContext ctx;
+ ctx.file = f;
+ ctx.show_tags = show_eval;
+ ctx.show_eval_priority = show_eval;
+
+ deg_debug_fprintf(ctx, "digraph depgraph {" NL);
+ deg_debug_fprintf(ctx, "rankdir=LR;" NL);
+ deg_debug_fprintf(ctx, "graph [");
+ deg_debug_fprintf(ctx, "compound=true");
+ deg_debug_fprintf(ctx, ",labelloc=\"t\"");
+ deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_graph_label_size);
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, ",label=\"%s\"", label);
+ deg_debug_fprintf(ctx, ",splines=ortho");
+ deg_debug_fprintf(ctx, ",overlap=scalexy"); // XXX: only when using neato
+ deg_debug_fprintf(ctx, "];" NL);
+
+ deg_debug_graphviz_graph_nodes(ctx, graph);
+ deg_debug_graphviz_graph_relations(ctx, graph);
+
+ deg_debug_graphviz_legend(ctx);
+
+ deg_debug_fprintf(ctx, "}" NL);
+}
+
+#undef NL
+
+/* ************************************************ */
+
+static string get_component_name(eDepsNode_Type type, const string &name = "")
+{
+ DepsNodeFactory *factory = DEG_get_node_factory(type);
+ if (name.empty()) {
+ return string(factory->tname());
+ }
+ else {
+ return string(factory->tname()) + " | " + name;
+ }
+}
+
+static void times_clear(DepsgraphStatsTimes &times)
+{
+ times.duration_last = 0.0f;
+}
+
+static void times_add(DepsgraphStatsTimes &times, float time)
+{
+ times.duration_last += time;
+}
+
+void DepsgraphDebug::eval_begin(const EvaluationContext *UNUSED(eval_ctx))
+{
+ /* TODO(sergey): Stats are currently globally disabled. */
+ /* verify_stats(); */
+ reset_stats();
+}
+
+void DepsgraphDebug::eval_end(const EvaluationContext *UNUSED(eval_ctx))
+{
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
+}
+
+void DepsgraphDebug::eval_step(const EvaluationContext *UNUSED(eval_ctx),
+ const char *message)
+{
+#ifdef DEG_DEBUG_BUILD
+ if (deg_debug_eval_cb)
+ deg_debug_eval_cb(deg_debug_eval_userdata, message);
+#else
+ (void)message; /* Ignored. */
+#endif
+}
+
+void DepsgraphDebug::task_started(Depsgraph *graph,
+ const OperationDepsNode *node)
+{
+ if (stats) {
+ BLI_spin_lock(&graph->lock);
+
+ ComponentDepsNode *comp = node->owner;
+ ID *id = comp->owner->id;
+
+ DepsgraphStatsID *id_stats = get_id_stats(id, true);
+ times_clear(id_stats->times);
+
+ /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
+ if (0) {
+ /* XXX component name usage needs cleanup! currently mixes identifier and description strings! */
+ DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, comp->name), true);
+ times_clear(comp_stats->times);
+ }
+
+ BLI_spin_unlock(&graph->lock);
+ }
+}
+
+void DepsgraphDebug::task_completed(Depsgraph *graph,
+ const OperationDepsNode *node,
+ double time)
+{
+ if (stats) {
+ BLI_spin_lock(&graph->lock);
+
+ ComponentDepsNode *comp = node->owner;
+ ID *id = comp->owner->id;
+
+ DepsgraphStatsID *id_stats = get_id_stats(id, true);
+ times_add(id_stats->times, time);
+
+ /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
+ if (0) {
+ /* XXX component name usage needs cleanup! currently mixes identifier and description strings! */
+ DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, comp->name), true);
+ times_add(comp_stats->times, time);
+ }
+
+ BLI_spin_unlock(&graph->lock);
+ }
+}
+
+/* ********** */
+/* Statistics */
+
+DepsgraphStats *DepsgraphDebug::stats = NULL;
+
+/* GHash callback */
+static void deg_id_stats_free(void *val)
+{
+ DepsgraphStatsID *id_stats = (DepsgraphStatsID *)val;
+
+ if (id_stats) {
+ BLI_freelistN(&id_stats->components);
+ MEM_freeN(id_stats);
+ }
+}
+
+void DepsgraphDebug::stats_init()
+{
+ if (!stats) {
+ stats = (DepsgraphStats *)MEM_callocN(sizeof(DepsgraphStats), "Depsgraph Stats");
+ stats->id_stats = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "Depsgraph ID Stats Hash");
+ }
+}
+
+void DepsgraphDebug::stats_free()
+{
+ if (stats) {
+ BLI_ghash_free(stats->id_stats, NULL, deg_id_stats_free);
+ MEM_freeN(stats);
+ stats = NULL;
+ }
+}
+
+void DepsgraphDebug::verify_stats()
+{
+ stats_init();
+}
+
+void DepsgraphDebug::reset_stats()
+{
+ if (!stats) {
+ return;
+ }
+
+ /* XXX this doesn't work, will immediately clear all info,
+ * since most depsgraph updates have none or very few updates to handle.
+ *
+ * Could consider clearing only zero-user ID blocks here
+ */
+// BLI_ghash_clear(stats->id_stats, NULL, deg_id_stats_free);
+}
+
+DepsgraphStatsID *DepsgraphDebug::get_id_stats(ID *id, bool create)
+{
+ DepsgraphStatsID *id_stats = (DepsgraphStatsID *)BLI_ghash_lookup(stats->id_stats, id);
+
+ if (!id_stats && create) {
+ id_stats = (DepsgraphStatsID *)MEM_callocN(sizeof(DepsgraphStatsID), "Depsgraph ID Stats");
+ id_stats->id = id;
+
+ BLI_ghash_insert(stats->id_stats, id, id_stats);
+ }
+
+ return id_stats;
+}
+
+DepsgraphStatsComponent *DepsgraphDebug::get_component_stats(
+ DepsgraphStatsID *id_stats,
+ const string &name,
+ bool create)
+{
+ DepsgraphStatsComponent *comp_stats;
+ for (comp_stats = (DepsgraphStatsComponent *)id_stats->components.first;
+ comp_stats != NULL;
+ comp_stats = comp_stats->next)
+ {
+ if (STREQ(comp_stats->name, name.c_str()))
+ break;
+ }
+ if (!comp_stats && create) {
+ comp_stats = (DepsgraphStatsComponent *)MEM_callocN(sizeof(DepsgraphStatsComponent), "Depsgraph Component Stats");
+ BLI_strncpy(comp_stats->name, name.c_str(), sizeof(comp_stats->name));
+ BLI_addtail(&id_stats->components, comp_stats);
+ }
+ return comp_stats;
+}
+
+/* ------------------------------------------------ */
+
+DepsgraphStats *DEG_stats(void)
+{
+ return DepsgraphDebug::stats;
+}
+
+void DEG_stats_verify()
+{
+ DepsgraphDebug::verify_stats();
+}
+
+DepsgraphStatsID *DEG_stats_id(ID *id)
+{
+ if (!DepsgraphDebug::stats) {
+ return NULL;
+ }
+ return DepsgraphDebug::get_id_stats(id, false);
+}
+
+bool DEG_debug_compare(const struct Depsgraph *graph1,
+ const struct Depsgraph *graph2)
+{
+ BLI_assert(graph1 != NULL);
+ BLI_assert(graph2 != NULL);
+ if (graph1->operations.size() != graph2->operations.size()) {
+ return false;
+ }
+ /* TODO(sergey): Currently we only do real stupid check,
+ * which is fast but which isn't 100% reliable.
+ *
+ * Would be cool to make it more robust, but it's good enough
+ * for now. Also, proper graph check is actually NP-complex
+ * problem..
+ */
+ return true;
+}
+
+bool DEG_debug_scene_relations_validate(Main *bmain,
+ Scene *scene)
+{
+ Depsgraph *depsgraph = DEG_graph_new();
+ bool valid = true;
+ DEG_graph_build_from_scene(depsgraph, bmain, scene);
+ if (!DEG_debug_compare(depsgraph, scene->depsgraph)) {
+ fprintf(stderr, "ERROR! Depsgraph wasn't tagged for update when it should have!\n");
+ BLI_assert(!"This should not happen!");
+ valid = false;
+ }
+ DEG_graph_free(depsgraph);
+ return valid;
+}
+
+bool DEG_debug_consistency_check(Depsgraph *graph)
+{
+ /* Validate links exists in both directions. */
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
+ it_rel != node->outlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+
+ int counter1 = 0;
+ for (OperationDepsNode::Relations::const_iterator tmp_rel = node->outlinks.begin();
+ tmp_rel != node->outlinks.end();
+ ++tmp_rel)
+ {
+ if (*tmp_rel == rel) {
+ ++counter1;
+ }
+ }
+
+ int counter2 = 0;
+ for (OperationDepsNode::Relations::const_iterator tmp_rel = rel->to->inlinks.begin();
+ tmp_rel != rel->to->inlinks.end();
+ ++tmp_rel)
+ {
+ if (*tmp_rel == rel) {
+ ++counter2;
+ }
+ }
+
+ if (counter1 != counter2) {
+ printf("Relation exists in outgoing direction but not in incoming (%d vs. %d).\n",
+ counter1, counter2);
+ return false;
+ }
+ }
+ }
+
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
+ it_rel != node->inlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+
+ int counter1 = 0;
+ for (OperationDepsNode::Relations::const_iterator tmp_rel = node->inlinks.begin();
+ tmp_rel != node->inlinks.end();
+ ++tmp_rel)
+ {
+ if (*tmp_rel == rel) {
+ ++counter1;
+ }
+ }
+
+ int counter2 = 0;
+ for (OperationDepsNode::Relations::const_iterator tmp_rel = rel->from->outlinks.begin();
+ tmp_rel != rel->from->outlinks.end();
+ ++tmp_rel)
+ {
+ if (*tmp_rel == rel) {
+ ++counter2;
+ }
+ }
+
+ if (counter1 != counter2) {
+ printf("Relation exists in incoming direction but not in outcoming (%d vs. %d).\n",
+ counter1, counter2);
+ }
+ }
+ }
+
+ /* Validate node valency calculated in both directions. */
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ node->num_links_pending = 0;
+ node->done = 0;
+ }
+
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ if (node->done) {
+ printf("Node %s is twice in the operations!\n",
+ node->identifier().c_str());
+ return false;
+ }
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
+ it_rel != node->outlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ BLI_assert(to->num_links_pending < to->inlinks.size());
+ ++to->num_links_pending;
+ }
+ }
+ node->done = 1;
+ }
+
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ int num_links_pending = 0;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
+ it_rel != node->inlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ ++num_links_pending;
+ }
+ }
+ if (node->num_links_pending != num_links_pending) {
+ printf("Valency mismatch: %s, %u != %d\n",
+ node->identifier().c_str(),
+ node->num_links_pending, num_links_pending);
+ printf("Number of inlinks: %d\n", (int)node->inlinks.size());
+ return false;
+ }
+ }
+ return true;
+}
+
+/* ------------------------------------------------ */
+
+/**
+ * Obtain simple statistics about the complexity of the depsgraph
+ * \param[out] r_outer The number of outer nodes in the graph
+ * \param[out] r_operations The number of operation nodes in the graph
+ * \param[out] r_relations The number of relations between (executable) nodes in the graph
+ */
+void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer,
+ size_t *r_operations, size_t *r_relations)
+{
+ /* number of operations */
+ if (r_operations) {
+ /* All operations should be in this list, allowing us to count the total
+ * number of nodes.
+ */
+ *r_operations = graph->operations.size();
+ }
+
+ /* Count number of outer nodes and/or relations between these. */
+ if (r_outer || r_relations) {
+ size_t tot_outer = 0;
+ size_t tot_rels = 0;
+
+ for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
+ it != graph->id_hash.end();
+ ++it)
+ {
+ IDDepsNode *id_node = it->second;
+ tot_outer++;
+ for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
+ it != id_node->components.end();
+ ++it)
+ {
+ ComponentDepsNode *comp_node = it->second;
+ tot_outer++;
+ for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
+ it != comp_node->operations.end();
+ ++it)
+ {
+ OperationDepsNode *op_node = it->second;
+ tot_rels += op_node->inlinks.size();
+ }
+ }
+ }
+
+ TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ if (time_source != NULL) {
+ tot_rels += time_source->inlinks.size();
+ }
+
+ if (r_relations) *r_relations = tot_rels;
+ if (r_outer) *r_outer = tot_outer;
+ }
+}
+
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.h b/source/blender/depsgraph/intern/depsgraph_debug.h
new file mode 100644
index 00000000000..64b97855f57
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_debug.h
@@ -0,0 +1,87 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_debug.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_DEBUG_H__
+#define __DEPSGRAPH_DEBUG_H__
+
+#include "depsgraph_types.h"
+
+extern "C" {
+#include "BKE_global.h"
+}
+
+struct DepsgraphStats;
+struct DepsgraphStatsID;
+struct DepsgraphStatsComponent;
+struct DepsgraphSettings;
+struct EvaluationContext;
+struct OperationDepsNode;
+
+struct Depsgraph;
+
+struct DepsgraphDebug {
+ static DepsgraphStats *stats;
+
+ static void stats_init();
+ static void stats_free();
+
+ static void verify_stats();
+ static void reset_stats();
+
+ static void eval_begin(const EvaluationContext *eval_ctx);
+ static void eval_end(const EvaluationContext *eval_ctx);
+ static void eval_step(const EvaluationContext *eval_ctx,
+ const char *message);
+
+ static void task_started(Depsgraph *graph, const OperationDepsNode *node);
+ static void task_completed(Depsgraph *graph,
+ const OperationDepsNode *node,
+ double time);
+
+ static DepsgraphStatsID *get_id_stats(ID *id, bool create);
+ static DepsgraphStatsComponent *get_component_stats(DepsgraphStatsID *id_stats,
+ const string &name,
+ bool create);
+ static DepsgraphStatsComponent *get_component_stats(ID *id,
+ const string &name,
+ bool create)
+ {
+ return get_component_stats(get_id_stats(id, create), name, create);
+ }
+};
+
+#define DEG_DEBUG_PRINTF(...) \
+ { \
+ if (G.debug & G_DEBUG_DEPSGRAPH) { \
+ fprintf(stderr, __VA_ARGS__); \
+ } \
+ } \
+
+#endif /* __DEPSGRAPH_DEBUG_H__ */
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
new file mode 100644
index 00000000000..17096931e57
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -0,0 +1,394 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_eval.cc
+ * \ingroup depsgraph
+ *
+ * Evaluation engine entrypoints for Depsgraph Engine.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_task.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+} /* extern "C" */
+
+#include "atomic_ops.h"
+
+#include "depsgraph.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_debug.h"
+
+#ifdef WITH_LEGACY_DEPSGRAPH
+static bool use_legacy_depsgraph = true;
+#endif
+
+bool DEG_depsgraph_use_legacy(void)
+{
+#ifdef DISABLE_NEW_DEPSGRAPH
+ return true;
+#elif defined(WITH_LEGACY_DEPSGRAPH)
+ return use_legacy_depsgraph;
+#else
+ BLI_assert(!"Should not be used with new depsgraph");
+ return false;
+#endif
+}
+
+void DEG_depsgraph_switch_to_legacy(void)
+{
+#ifdef WITH_LEGACY_DEPSGRAPH
+ use_legacy_depsgraph = true;
+#else
+ BLI_assert(!"Should not be used with new depsgraph");
+#endif
+}
+
+void DEG_depsgraph_switch_to_new(void)
+{
+#ifdef WITH_LEGACY_DEPSGRAPH
+ use_legacy_depsgraph = false;
+#else
+ BLI_assert(!"Should not be used with new depsgraph");
+#endif
+}
+
+/* ****************** */
+/* Evaluation Context */
+
+/* Create new evaluation context. */
+EvaluationContext *DEG_evaluation_context_new(int mode)
+{
+ EvaluationContext *eval_ctx =
+ (EvaluationContext *)MEM_callocN(sizeof(EvaluationContext),
+ "EvaluationContext");
+ eval_ctx->mode = mode;
+ return eval_ctx;
+}
+
+/**
+ * Initialize evaluation context.
+ * Used by the areas which currently overrides the context or doesn't have
+ * access to a proper one.
+ */
+void DEG_evaluation_context_init(EvaluationContext *eval_ctx, int mode)
+{
+ eval_ctx->mode = mode;
+}
+
+/* Free evaluation context. */
+void DEG_evaluation_context_free(EvaluationContext *eval_ctx)
+{
+ MEM_freeN(eval_ctx);
+}
+
+/* ********************** */
+/* Evaluation Entrypoints */
+
+/* Forward declarations. */
+static void schedule_children(TaskPool *pool,
+ Depsgraph *graph,
+ OperationDepsNode *node,
+ const int layers);
+
+struct DepsgraphEvalState {
+ EvaluationContext *eval_ctx;
+ Depsgraph *graph;
+ int layers;
+};
+
+static void deg_task_run_func(TaskPool *pool,
+ void *taskdata,
+ int UNUSED(threadid))
+{
+ DepsgraphEvalState *state = (DepsgraphEvalState *)BLI_task_pool_userdata(pool);
+ OperationDepsNode *node = (OperationDepsNode *)taskdata;
+
+ if (!node->is_noop()) {
+ /* Get context. */
+ // TODO: who initialises this? "Init" operations aren't able to initialise it!!!
+ /* TODO(sergey): Wedon't use component contexts at this moment. */
+ /* ComponentDepsNode *comp = node->owner; */
+ BLI_assert(node->owner != NULL);
+
+ /* Take note of current time. */
+ double start_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_started(state->graph, node);
+
+ /* Should only be the case for NOOPs, which never get to this point. */
+ BLI_assert(node->evaluate);
+
+ /* Perform operation. */
+ node->evaluate(state->eval_ctx);
+
+ /* Note how long this took. */
+ double end_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_completed(state->graph,
+ node,
+ end_time - start_time);
+ }
+
+ schedule_children(pool, state->graph, node, state->layers);
+}
+
+static void calculate_pending_parents(Depsgraph *graph, int layers)
+{
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ IDDepsNode *id_node = node->owner->owner;
+
+ node->num_links_pending = 0;
+ node->scheduled = false;
+
+ /* count number of inputs that need updates */
+ if ((id_node->layers & layers) != 0 &&
+ (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
+ {
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
+ it_rel != node->inlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION &&
+ (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
+ {
+ OperationDepsNode *from = (OperationDepsNode *)rel->from;
+ IDDepsNode *id_from_node = from->owner->owner;
+ if ((id_from_node->layers & layers) != 0 &&
+ (from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
+ {
+ ++node->num_links_pending;
+ }
+ }
+ }
+ }
+ }
+}
+
+static void calculate_eval_priority(OperationDepsNode *node)
+{
+ if (node->done) {
+ return;
+ }
+ node->done = 1;
+
+ if (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ /* XXX standard cost of a node, could be estimated somewhat later on */
+ const float cost = 1.0f;
+ /* NOOP nodes have no cost */
+ node->eval_priority = node->is_noop() ? cost : 0.0f;
+
+ for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
+ it != node->outlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ BLI_assert(to->type == DEPSNODE_TYPE_OPERATION);
+ calculate_eval_priority(to);
+ node->eval_priority += to->eval_priority;
+ }
+ }
+ else {
+ node->eval_priority = 0.0f;
+ }
+}
+
+static void schedule_graph(TaskPool *pool,
+ Depsgraph *graph,
+ const int layers)
+{
+ BLI_spin_lock(&graph->lock);
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ IDDepsNode *id_node = node->owner->owner;
+ if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) &&
+ node->num_links_pending == 0 &&
+ (id_node->layers & layers) != 0)
+ {
+ BLI_task_pool_push(pool, deg_task_run_func, node, false, TASK_PRIORITY_LOW);
+ node->scheduled = true;
+ }
+ }
+ BLI_spin_unlock(&graph->lock);
+}
+
+static void schedule_children(TaskPool *pool,
+ Depsgraph *graph,
+ OperationDepsNode *node,
+ const int layers)
+{
+ for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
+ it != node->outlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+ OperationDepsNode *child = (OperationDepsNode *)rel->to;
+ BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
+
+ if (child->scheduled) {
+ /* Happens when having cyclic dependencies. */
+ continue;
+ }
+
+ IDDepsNode *id_child = child->owner->owner;
+ if ((id_child->layers & layers) != 0 &&
+ (child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
+ {
+ if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
+ BLI_assert(child->num_links_pending > 0);
+ atomic_sub_uint32(&child->num_links_pending, 1);
+ }
+
+ if (child->num_links_pending == 0) {
+ BLI_spin_lock(&graph->lock);
+ bool need_schedule = !child->scheduled;
+ child->scheduled = true;
+ BLI_spin_unlock(&graph->lock);
+
+ if (need_schedule) {
+ BLI_task_pool_push(pool, deg_task_run_func, child, false, TASK_PRIORITY_LOW);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Evaluate all nodes tagged for updating,
+ * \warning This is usually done as part of main loop, but may also be
+ * called from frame-change update.
+ *
+ * \note Time sources should be all valid!
+ */
+void DEG_evaluate_on_refresh_ex(EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ const int layers)
+{
+ /* Generate base evaluation context, upon which all the others are derived. */
+ // TODO: this needs both main and scene access...
+
+ /* Nothing to update, early out. */
+ if (graph->entry_tags.size() == 0) {
+ return;
+ }
+
+ /* Set time for the current graph evaluation context. */
+ TimeSourceDepsNode *time_src = graph->find_time_source();
+ eval_ctx->ctime = time_src->cfra;
+
+ /* XXX could use a separate pool for each eval context */
+ DepsgraphEvalState state;
+ state.eval_ctx = eval_ctx;
+ state.graph = graph;
+ state.layers = layers;
+
+ TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &state);
+
+ if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
+ BLI_pool_set_num_threads(task_pool, 1);
+ }
+
+ calculate_pending_parents(graph, layers);
+
+ /* Clear tags. */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ node->done = 0;
+ }
+
+ /* Calculate priority for operation nodes. */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ calculate_eval_priority(node);
+ }
+
+ DepsgraphDebug::eval_begin(eval_ctx);
+
+ schedule_graph(task_pool, graph, layers);
+
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+
+ DepsgraphDebug::eval_end(eval_ctx);
+
+ /* Clear any uncleared tags - just in case. */
+ DEG_graph_clear_tags(graph);
+}
+
+/* Evaluate all nodes tagged for updating. */
+void DEG_evaluate_on_refresh(EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ Scene *scene)
+{
+ /* Update time on primary timesource. */
+ TimeSourceDepsNode *tsrc = graph->find_time_source();
+ tsrc->cfra = BKE_scene_frame_get(scene);;
+
+ DEG_evaluate_on_refresh_ex(eval_ctx, graph, graph->layers);
+}
+
+/* Frame-change happened for root scene that graph belongs to. */
+void DEG_evaluate_on_framechange(EvaluationContext *eval_ctx,
+ Main *bmain,
+ Depsgraph *graph,
+ float ctime,
+ const int layers)
+{
+ /* Update time on primary timesource. */
+ TimeSourceDepsNode *tsrc = graph->find_time_source();
+ tsrc->cfra = ctime;
+
+ tsrc->tag_update(graph);
+
+ DEG_graph_flush_updates(bmain, graph);
+
+ /* Perform recalculation updates. */
+ DEG_evaluate_on_refresh_ex(eval_ctx, graph, layers);
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h
new file mode 100644
index 00000000000..7fdc2454564
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_intern.h
@@ -0,0 +1,168 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_intern.h
+ * \ingroup depsgraph
+ *
+ * API's for internal use in the Depsgraph
+ * - Also, defines for "Node Type Info"
+ */
+
+#ifndef __DEPSGRAPH_INTERN_H__
+#define __DEPSGRAPH_INTERN_H__
+
+#include <cstdlib>
+
+#include "MEM_guardedalloc.h"
+
+#include "depsgraph.h"
+#include "depsnode.h"
+
+struct Main;
+struct Group;
+struct Scene;
+
+/* Graph Building ======================================================== */
+
+/**
+ * Build depsgraph for the given group, and dump results in given graph container
+ * This is usually used for building subgraphs for groups to use...
+ */
+void DEG_graph_build_from_group(Depsgraph *graph, struct Main *bmain, struct Group *group);
+
+/* Build subgraph for group */
+DepsNode *DEG_graph_build_group_subgraph(Depsgraph *graph_main, struct Main *bmain, struct Group *group);
+
+/* Graph Copying ========================================================= */
+/* (Part of the Filtering API) */
+
+/**
+ * Depsgraph Copying Context (dcc)
+ *
+ * Keeps track of node relationships/links/etc. during the copy
+ * operation so that they can be safely remapped...
+ */
+typedef struct DepsgraphCopyContext {
+ struct GHash *nodes_hash; /* <DepsNode, DepsNode> mapping from src node to dst node */
+ struct GHash *rels_hash; // XXX: same for relationships?
+
+ // XXX: filtering criteria...
+} DepsgraphCopyContext;
+
+/* Internal Filtering API ---------------------------------------------- */
+
+/* Create filtering context */
+// XXX: needs params for conditions?
+DepsgraphCopyContext *DEG_filter_init(void);
+
+/* Free filtering context once filtering is done */
+void DEG_filter_cleanup(DepsgraphCopyContext *dcc);
+
+
+/* Data Copy Operations ------------------------------------------------ */
+
+/**
+ * Make a (deep) copy of provided node and it's little subgraph
+ * \warning Newly created node is not added to the existing graph
+ * \param dcc: Context info for helping resolve links
+ */
+DepsNode *DEG_copy_node(DepsgraphCopyContext *dcc, const DepsNode *src);
+
+/* Node Types Handling ================================================= */
+
+/* "Typeinfo" for Node Types ------------------------------------------- */
+
+/* Typeinfo Struct (nti) */
+struct DepsNodeFactory {
+ virtual eDepsNode_Type type() const = 0;
+ virtual eDepsNode_Class tclass() const = 0;
+ virtual const char *tname() const = 0;
+
+ virtual DepsNode *create_node(const ID *id, const string &subdata, const string &name) const = 0;
+ virtual DepsNode *copy_node(DepsgraphCopyContext *dcc, const DepsNode *copy) const = 0;
+};
+
+template <class NodeType>
+struct DepsNodeFactoryImpl : public DepsNodeFactory {
+ eDepsNode_Type type() const { return NodeType::typeinfo.type; }
+ eDepsNode_Class tclass() const { return NodeType::typeinfo.tclass; }
+ const char *tname() const { return NodeType::typeinfo.tname; }
+
+ DepsNode *create_node(const ID *id, const string &subdata, const string &name) const
+ {
+ DepsNode *node = OBJECT_GUARDED_NEW(NodeType);
+
+ /* populate base node settings */
+ node->type = type();
+ node->tclass = tclass();
+
+ if (!name.empty())
+ /* set name if provided ... */
+ node->name = name;
+ else
+ /* ... otherwise use default type name */
+ node->name = tname();
+
+ node->init(id, subdata);
+
+ return node;
+ }
+
+ virtual DepsNode *copy_node(DepsgraphCopyContext *dcc, const DepsNode *copy) const
+ {
+ BLI_assert(copy->type == type());
+ DepsNode *node = OBJECT_GUARDED_NEW(NodeType);
+
+ /* populate base node settings */
+ node->type = type();
+ node->tclass = tclass();
+ // XXX: need to review the name here, as we can't have exact duplicates...
+ node->name = copy->name;
+
+ node->copy(dcc, static_cast<const NodeType *>(copy));
+
+ return node;
+ }
+};
+
+/* Typeinfo Management -------------------------------------------------- */
+
+/* Register typeinfo */
+void DEG_register_node_typeinfo(DepsNodeFactory *factory);
+
+/* Get typeinfo for specified type */
+DepsNodeFactory *DEG_get_node_factory(const eDepsNode_Type type);
+
+/* Get typeinfo for provided node */
+DepsNodeFactory *DEG_node_get_factory(const DepsNode *node);
+
+/* Editors Integration -------------------------------------------------- */
+
+void deg_editors_id_update(struct Main *bmain, struct ID *id);
+
+void deg_editors_scene_update(struct Main *bmain, struct Scene *scene, bool updated);
+
+#endif /* __DEPSGRAPH_INTERN_H__ */
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
new file mode 100644
index 00000000000..73193747b93
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -0,0 +1,217 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_query.cc
+ * \ingroup depsgraph
+ *
+ * Implementation of Querying and Filtering API's
+ */
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+#include "BKE_main.h"
+
+#include "DEG_depsgraph_query.h"
+} /* extern "C" */
+
+#include "depsgraph_queue.h"
+#include "depsnode.h"
+#include "depsnode_operation.h"
+#include "depsgraph_intern.h"
+
+/* ************************* */
+/* Low-Level Graph Traversal */
+
+#if 0
+/* Prepare for graph traversal, by tagging nodes, etc. */
+static void DEG_graph_traverse_begin(Depsgraph * /*graph*/)
+{
+ /* go over all nodes, initialising the valence counts */
+ // XXX: this will end up being O(|V|), which is bad when we're just updating a few nodes...
+}
+
+/* Perform a traversal of graph from given starting node (in execution order) */
+// TODO: additional flags for controlling the process?
+void DEG_graph_traverse_from_node(Depsgraph *graph, OperationDepsNode *start_node,
+ DEG_FilterPredicate filter, void *filter_data,
+ DEG_NodeOperation op, void *operation_data)
+{
+ DepsgraphQueue *q;
+
+ /* sanity checks */
+ if (ELEM(NULL, graph, start_node, op))
+ return;
+
+ /* add node as starting node to be evaluated, with value of 0 */
+ q = DEG_queue_new();
+
+ start_node->num_links_pending = 0;
+ DEG_queue_push(q, start_node, 0.0f);
+
+ /* while we still have nodes in the queue, grab and work on next one */
+ do {
+ /* grab item at front of queue */
+ // XXX: in practice, we may need to wait until one becomes available...
+ OperationDepsNode *node = (OperationDepsNode *)DEG_queue_pop(q);
+
+ /* perform operation on node */
+ op(graph, node, operation_data);
+
+ /* schedule up operations which depend on this */
+ DEPSNODE_RELATIONS_ITER_BEGIN(node->outlinks, rel)
+ {
+ /* ensure that relationship is not tagged for ignoring (i.e. cyclic, etc.) */
+ // TODO: cyclic refs should probably all get clustered towards the end, so that we can just stop on the first one
+ if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
+ OperationDepsNode *child_node = (OperationDepsNode *)rel->to;
+
+ /* only visit node if the filtering function agrees */
+ if ((filter == NULL) || filter(graph, child_node, filter_data)) {
+ /* schedule up node... */
+ child_node->num_links_pending--;
+ DEG_queue_push(q, child_node, (float)child_node->num_links_pending);
+ }
+ }
+ }
+ DEPSNODE_RELATIONS_ITER_END;
+ } while (DEG_queue_is_empty(q) == false);
+
+ /* cleanup */
+ DEG_queue_free(q);
+}
+#endif
+
+/* ************************************************************** */
+/* Filtering API - Basically, making a copy of the existing graph */
+
+/* Create filtering context */
+// TODO: allow passing in a number of criteria?
+DepsgraphCopyContext *DEG_filter_init()
+{
+ DepsgraphCopyContext *dcc = (DepsgraphCopyContext *)MEM_callocN(sizeof(DepsgraphCopyContext), "DepsgraphCopyContext");
+
+ /* init hashes for easy lookups */
+ dcc->nodes_hash = BLI_ghash_ptr_new("Depsgraph Filter NodeHash");
+ dcc->rels_hash = BLI_ghash_ptr_new("Depsgraph Filter Relationship Hash"); // XXX?
+
+ /* store filtering criteria? */
+ // xxx...
+
+ return dcc;
+}
+
+/* Cleanup filtering context */
+void DEG_filter_cleanup(DepsgraphCopyContext *dcc)
+{
+ /* sanity check */
+ if (dcc == NULL)
+ return;
+
+ /* free hashes - contents are weren't copied, so are ok... */
+ BLI_ghash_free(dcc->nodes_hash, NULL, NULL);
+ BLI_ghash_free(dcc->rels_hash, NULL, NULL);
+
+ /* clear filtering criteria */
+ // ...
+
+ /* free dcc itself */
+ MEM_freeN(dcc);
+}
+
+/* -------------------------------------------------- */
+
+/* Create a copy of provided node */
+// FIXME: the handling of sub-nodes and links will need to be subject to filtering options...
+// XXX: perhaps this really shouldn't be exposed, as it will just be a sub-step of the evaluation process?
+DepsNode *DEG_copy_node(DepsgraphCopyContext *dcc, const DepsNode *src)
+{
+ /* sanity check */
+ if (src == NULL)
+ return NULL;
+
+ DepsNodeFactory *factory = DEG_get_node_factory(src->type);
+ BLI_assert(factory != NULL);
+ DepsNode *dst = factory->copy_node(dcc, src);
+
+ /* add this node-pair to the hash... */
+ BLI_ghash_insert(dcc->nodes_hash, (DepsNode *)src, dst);
+
+#if 0 /* XXX TODO */
+ /* now, fix up any links in standard "node header" (i.e. DepsNode struct, that all
+ * all others are derived from) that are now corrupt
+ */
+ {
+ /* relationships to other nodes... */
+ // FIXME: how to handle links? We may only have partial set of all nodes still?
+ // XXX: the exact details of how to handle this are really part of the querying API...
+
+ // XXX: BUT, for copying subgraphs, we'll need to define an API for doing this stuff anyways
+ // (i.e. for resolving and patching over links that exist within subtree...)
+ dst->inlinks.clear();
+ dst->outlinks.clear();
+
+ /* clear traversal data */
+ dst->num_links_pending = 0;
+ dst->lasttime = 0;
+ }
+
+ /* fix links */
+ // XXX...
+#endif
+
+ /* return copied node */
+ return dst;
+}
+
+bool DEG_id_type_tagged(Main *bmain, short idtype)
+{
+ return bmain->id_tag_update[((unsigned char *)&idtype)[0]] != 0;
+}
+
+short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id)
+{
+ if (graph == NULL) {
+ /* Happens when converting objects to mesh from a python script
+ * after modifying scene graph.
+ *
+ * Currently harmless because it's only called for temporary
+ * objects which are out of the DAG anyway.
+ */
+ return 0;
+ }
+
+ IDDepsNode *id_node = graph->find_id_node(id);
+ if (id_node == NULL) {
+ /* TODO(sergey): Does it mean we need to check set scene? */
+ return 0;
+ }
+
+ return id_node->eval_flags;
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_queue.cc b/source/blender/depsgraph/intern/depsgraph_queue.cc
new file mode 100644
index 00000000000..da60d73bc46
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_queue.cc
@@ -0,0 +1,177 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_queue.cc
+ * \ingroup depsgraph
+ *
+ * Implementation of special queue type for use in Depsgraph traversals.
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_heap.h"
+#include "BLI_ghash.h"
+} /* extern "C" */
+
+#include "depsgraph_queue.h"
+
+/* ****************************** */
+/* Depsgraph Queue implementation */
+
+/* Data Management ----------------------------------------- */
+
+DepsgraphQueue *DEG_queue_new(void)
+{
+ DepsgraphQueue *q = (DepsgraphQueue *)MEM_callocN(sizeof(DepsgraphQueue), "DEG_queue_new()");
+
+ /* init data structures for use here */
+ q->pending_heap = BLI_heap_new();
+ q->pending_hash = BLI_ghash_ptr_new("DEG Queue Pending Hash");
+
+ q->ready_heap = BLI_heap_new();
+
+ /* init settings */
+ q->idx = 0;
+ q->tot = 0;
+
+ /* return queue */
+ return q;
+}
+
+void DEG_queue_free(DepsgraphQueue *q)
+{
+ /* free data structures */
+ BLI_assert(BLI_heap_size(q->pending_heap) == 0);
+ BLI_assert(BLI_heap_size(q->ready_heap) == 0);
+ BLI_assert(BLI_ghash_size(q->pending_hash) == 0);
+
+ BLI_heap_free(q->pending_heap, NULL);
+ BLI_heap_free(q->ready_heap, NULL);
+ BLI_ghash_free(q->pending_hash, NULL, NULL);
+
+ /* free queue itself */
+ MEM_freeN(q);
+}
+
+/* Statistics --------------------------------------------- */
+
+/* Get the number of nodes which are we should visit, but are not able to yet */
+size_t DEG_queue_num_pending(DepsgraphQueue *q)
+{
+ return BLI_heap_size(q->pending_heap);
+}
+
+/* Get the number of nodes which are now ready to be visited */
+size_t DEG_queue_num_ready(DepsgraphQueue *q)
+{
+ return BLI_heap_size(q->ready_heap);
+}
+
+/* Get total size of queue */
+size_t DEG_queue_size(DepsgraphQueue *q)
+{
+ return DEG_queue_num_pending(q) + DEG_queue_num_ready(q);
+}
+
+/* Check if queue has any items in it (still passing through) */
+bool DEG_queue_is_empty(DepsgraphQueue *q)
+{
+ return DEG_queue_size(q) == 0;
+}
+
+/* Queue Operations --------------------------------------- */
+
+/**
+ * Add DepsNode to the queue
+ * \param dnode: ``(DepsNode *)`` node to add to the queue
+ * Each node is only added once to the queue; Subsequent pushes
+ * merely update its status (e.g. moving it from "pending" to "ready")
+ * \param cost: new "num_links_pending" count for node *after* it has encountered
+ * via an outlink from the node currently being visited
+ * (i.e. we're one of the dependencies which may now be able to be processed)
+ */
+void DEG_queue_push(DepsgraphQueue *q, void *dnode, float cost)
+{
+ HeapNode *hnode = NULL;
+
+ /* Shortcut: Directly add to ready if node isn't waiting on anything now... */
+ if (cost == 0) {
+ /* node is now ready to be visited - schedule it up for such */
+ if (BLI_ghash_haskey(q->pending_hash, dnode)) {
+ /* remove from pending queue - we're moving it to the scheduling queue */
+ hnode = (HeapNode *)BLI_ghash_lookup(q->pending_hash, dnode);
+ BLI_heap_remove(q->pending_heap, hnode);
+
+ BLI_ghash_remove(q->pending_hash, dnode, NULL, NULL);
+ }
+
+ /* schedule up node using latest count (of ready nodes) */
+ BLI_heap_insert(q->ready_heap, (float)q->idx, dnode);
+ q->idx++;
+ }
+ else {
+ /* node is still waiting on some other ancestors,
+ * so add it to the pending heap in the meantime...
+ */
+ // XXX: is this even necessary now?
+ if (BLI_ghash_haskey(q->pending_hash, dnode)) {
+ /* just update cost on pending node */
+ hnode = (HeapNode *)BLI_ghash_lookup(q->pending_hash, dnode);
+ BLI_heap_remove(q->pending_heap, hnode);
+ BLI_heap_insert(q->pending_heap, cost, hnode);
+ }
+ else {
+ /* add new node to pending queue, and increase size of overall queue */
+ hnode = BLI_heap_insert(q->pending_heap, cost, dnode);
+ q->tot++;
+ }
+ }
+}
+
+/* Grab a "ready" node from the queue */
+void *DEG_queue_pop(DepsgraphQueue *q)
+{
+ /* sanity check: if there are no "ready" nodes,
+ * start pulling from "pending" to keep things moving,
+ * but throw a warning so that we know that something's up here...
+ */
+ if (BLI_heap_is_empty(q->ready_heap)) {
+ // XXX: this should never happen
+ // XXX: if/when it does happen, we may want instead to just wait until something pops up here...
+ printf("DepsgraphHeap Warning: No more ready nodes available. Trying from pending (idx = %d, tot = %d, pending = %d, ready = %d)\n",
+ (int)q->idx, (int)q->tot, (int)DEG_queue_num_pending(q), (int)DEG_queue_num_ready(q));
+
+ return BLI_heap_popmin(q->pending_heap);
+ }
+ else {
+ /* only grab "ready" nodes */
+ return BLI_heap_popmin(q->ready_heap);
+ }
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_queue.h b/source/blender/depsgraph/intern/depsgraph_queue.h
new file mode 100644
index 00000000000..b85d46bd173
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_queue.h
@@ -0,0 +1,91 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_queue.h
+ * \ingroup depsgraph
+ *
+ * Defines for special queue type for use in Depsgraph traversals.
+ */
+
+#ifndef __DEPSGRAPH_QUEUE_H__
+#define __DEPSGRAPH_QUEUE_H__
+
+struct DepsNode;
+
+struct Heap;
+struct GHash;
+
+/* *********************************************** */
+/* Dependency Graph Traversal Queue
+ *
+ * There are two parts to this:
+ * a) "Pending" Nodes - This part contains the set of nodes
+ * which are related to those which have been visited
+ * previously, but are not yet ready to actually be visited.
+ * b) "Scheduled" Nodes - These are the nodes whose ancestors
+ * have all been evaluated already, which means that any
+ * or all of them can be picked (in practically in order) to
+ * be visited immediately.
+ *
+ * Internally, the queue makes sure that each node in the graph
+ * only gets added to the queue once. This is because there can
+ * be multiple inlinks to each node given the way that the relations
+ * work.
+ */
+
+/* Depsgraph Queue Type */
+typedef struct DepsgraphQueue {
+ /* Pending */
+ struct Heap *pending_heap; /* (valence:int, DepsNode*) */
+ struct GHash *pending_hash; /* (DepsNode* : HeapNode*>) */
+
+ /* Ready to be visited - fifo */
+ struct Heap *ready_heap; /* (idx:int, DepsNode*) */
+
+ /* Size/Order counts */
+ size_t idx; /* total number of nodes which are/have been ready so far (including those already visited) */
+ size_t tot; /* total number of nodes which have passed through queue; mainly for debug */
+} DepsgraphQueue;
+
+/* ************************** */
+/* Depsgraph Queue Operations */
+
+/* Data management */
+DepsgraphQueue *DEG_queue_new(void);
+void DEG_queue_free(DepsgraphQueue *q);
+
+/* Statistics */
+size_t DEG_queue_num_pending(DepsgraphQueue *q);
+size_t DEG_queue_num_ready(DepsgraphQueue *q);
+
+size_t DEG_queue_size(DepsgraphQueue *q);
+bool DEG_queue_is_empty(DepsgraphQueue *q);
+
+/* Operations */
+void DEG_queue_push(DepsgraphQueue *q, void *dnode, float cost = 0.0f);
+void *DEG_queue_pop(DepsgraphQueue *q);
+
+#endif /* DEPSGRAPH_QUEUE_H */
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
new file mode 100644
index 00000000000..65d75fccad3
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -0,0 +1,541 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_tag.cc
+ * \ingroup depsgraph
+ *
+ * Core routines for how the Depsgraph works.
+ */
+
+#include <stdio.h>
+#include <cstring>
+#include <queue>
+
+extern "C" {
+#include "BLI_utildefines.h"
+
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+
+#define new new_
+#include "BKE_screen.h"
+#undef new
+
+#include "DEG_depsgraph.h"
+} /* extern "C" */
+
+#include "depsgraph_debug.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_intern.h"
+
+/* *********************** */
+/* Update Tagging/Flushing */
+
+/* Legacy depsgraph did some special trickery for things like particle systems
+ * when tagging ID for an update. Ideally that tagging needs to become obsolete
+ * in favor of havng dedicated node for that which gets tagged, but for until
+ * design of those areas is more clear we'll do the same legacy code here.
+ * - sergey -
+ */
+#define DEPSGRAPH_USE_LEGACY_TAGGING
+
+namespace {
+
+/* Data-Based Tagging ------------------------------- */
+
+void lib_id_recalc_tag(Main *bmain, ID *id)
+{
+ id->flag |= LIB_ID_RECALC;
+ DEG_id_type_tag(bmain, GS(id->name));
+}
+
+void lib_id_recalc_data_tag(Main *bmain, ID *id)
+{
+ id->flag |= LIB_ID_RECALC_DATA;
+ DEG_id_type_tag(bmain, GS(id->name));
+}
+
+void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag)
+{
+ if (flag) {
+ /* This bit of code ensures legacy object->recalc flags
+ * are still filled in the same way as it was expected
+ * with the old dependency graph.
+ *
+ * This is because some areas like motion paths and likely
+ * some other physics baking process are doing manual scene
+ * update on all the frames, trying to minimize number of
+ * updates.
+ *
+ * But this flag will also let us to re-construct entry
+ * nodes for update after relations update and after layer
+ * visibility changes.
+ */
+ short idtype = GS(id->name);
+ if (idtype == ID_OB) {
+ Object *object = (Object *)id;
+ object->recalc |= (flag & OB_RECALC_ALL);
+ }
+
+ if (flag & OB_RECALC_OB)
+ lib_id_recalc_tag(bmain, id);
+ if (flag & (OB_RECALC_DATA | PSYS_RECALC))
+ lib_id_recalc_data_tag(bmain, id);
+ }
+ else {
+ lib_id_recalc_tag(bmain, id);
+ }
+}
+
+#ifdef DEPSGRAPH_USE_LEGACY_TAGGING
+void depsgraph_legacy_handle_update_tag(Main *bmain, ID *id, short flag)
+{
+ if (flag) {
+ Object *object;
+ short idtype = GS(id->name);
+ if (idtype == ID_PA) {
+ ParticleSystem *psys;
+ for (object = (Object *)bmain->object.first;
+ object != NULL;
+ object = (Object *)object->id.next)
+ {
+ for (psys = (ParticleSystem *)object->particlesystem.first;
+ psys != NULL;
+ psys = (ParticleSystem *)psys->next)
+ {
+ if (&psys->part->id == id) {
+ DEG_id_tag_update_ex(bmain, &object->id, flag & OB_RECALC_ALL);
+ psys->recalc |= (flag & PSYS_RECALC);
+ }
+ }
+ }
+ }
+ }
+}
+#endif
+
+} /* namespace */
+
+/* Tag all nodes in ID-block for update.
+ * This is a crude measure, but is most convenient for old code.
+ */
+void DEG_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id)
+{
+ IDDepsNode *node = graph->find_id_node(id);
+ lib_id_recalc_tag(bmain, id);
+ if (node != NULL) {
+ node->tag_update(graph);
+ }
+}
+
+/* Tag nodes related to a specific piece of data */
+void DEG_graph_data_tag_update(Depsgraph *graph, const PointerRNA *ptr)
+{
+ DepsNode *node = graph->find_node_from_pointer(ptr, NULL);
+ if (node) {
+ node->tag_update(graph);
+ }
+ else {
+ printf("Missing node in %s\n", __func__);
+ BLI_assert(!"Shouldn't happens since it'll miss crucial update.");
+ }
+}
+
+/* Tag nodes related to a specific property. */
+void DEG_graph_property_tag_update(Depsgraph *graph,
+ const PointerRNA *ptr,
+ const PropertyRNA *prop)
+{
+ DepsNode *node = graph->find_node_from_pointer(ptr, prop);
+ if (node) {
+ node->tag_update(graph);
+ }
+ else {
+ printf("Missing node in %s\n", __func__);
+ BLI_assert(!"Shouldn't happens since it'll miss crucial update.");
+ }
+}
+
+/* Tag given ID for an update in all the dependency graphs. */
+void DEG_id_tag_update(ID *id, short flag)
+{
+ DEG_id_tag_update_ex(G.main, id, flag);
+}
+
+void DEG_id_tag_update_ex(Main *bmain, ID *id, short flag)
+{
+ if (id == NULL) {
+ /* Ideally should not happen, but old depsgraph allowed this. */
+ return;
+ }
+ DEG_DEBUG_PRINTF("%s: id=%s flag=%d\n", __func__, id->name, flag);
+ lib_id_recalc_tag_flag(bmain, id, flag);
+ for (Scene *scene = (Scene *)bmain->scene.first;
+ scene != NULL;
+ scene = (Scene *)scene->id.next)
+ {
+ if (scene->depsgraph) {
+ Depsgraph *graph = scene->depsgraph;
+ if (flag == 0) {
+ /* TODO(sergey): Currently blender is still tagging IDs
+ * for recalc just using flag=0. This isn't totally correct
+ * but we'd better deal with such cases and don't fail.
+ */
+ DEG_graph_id_tag_update(bmain, graph, id);
+ continue;
+ }
+ if (flag & OB_RECALC_DATA && GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ if (object->data != NULL) {
+ DEG_graph_id_tag_update(bmain,
+ graph,
+ (ID *)object->data);
+ }
+ }
+ if (flag & (OB_RECALC_OB | OB_RECALC_DATA)) {
+ DEG_graph_id_tag_update(bmain, graph, id);
+ }
+ }
+ }
+
+#ifdef DEPSGRAPH_USE_LEGACY_TAGGING
+ /* Special handling from the legacy depsgraph.
+ * TODO(sergey): Need to get rid of those once all the areas
+ * are re-formulated in terms of franular nodes.
+ */
+ depsgraph_legacy_handle_update_tag(bmain, id, flag);
+#endif
+}
+
+/* Tag given ID type for update. */
+void DEG_id_type_tag(Main *bmain, short idtype)
+{
+ if (idtype == ID_NT) {
+ /* Stupid workaround so parent datablocks of nested nodetree get looped
+ * over when we loop over tagged datablock types.
+ */
+ DEG_id_type_tag(bmain, ID_MA);
+ DEG_id_type_tag(bmain, ID_TE);
+ DEG_id_type_tag(bmain, ID_LA);
+ DEG_id_type_tag(bmain, ID_WO);
+ DEG_id_type_tag(bmain, ID_SCE);
+ }
+ /* We tag based on first ID type character to avoid
+ * looping over all ID's in case there are no tags.
+ */
+ bmain->id_tag_update[((unsigned char *)&idtype)[0]] = 1;
+}
+
+/* Update Flushing ---------------------------------- */
+
+/* FIFO queue for tagged nodes that need flushing */
+/* XXX This may get a dedicated implementation later if needed - lukas */
+typedef std::queue<OperationDepsNode *> FlushQueue;
+
+/* Flush updates from tagged nodes outwards until all affected nodes are tagged. */
+void DEG_graph_flush_updates(Main *bmain, Depsgraph *graph)
+{
+ /* sanity check */
+ if (graph == NULL)
+ return;
+
+ /* Nothing to update, early out. */
+ if (graph->entry_tags.size() == 0) {
+ return;
+ }
+
+ /* TODO(sergey): With a bit of flag magic we can get rid of this
+ * extra loop.
+ */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ node->scheduled = false;
+ }
+
+ FlushQueue queue;
+ /* Starting from the tagged "entry" nodes, flush outwards... */
+ /* NOTE: Also need to ensure that for each of these, there is a path back to
+ * root, or else they won't be done.
+ * NOTE: Count how many nodes we need to handle - entry nodes may be
+ * component nodes which don't count for this purpose!
+ */
+ for (Depsgraph::EntryTags::const_iterator it = graph->entry_tags.begin();
+ it != graph->entry_tags.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ IDDepsNode *id_node = node->owner->owner;
+ queue.push(node);
+ deg_editors_id_update(bmain, id_node->id);
+ node->scheduled = true;
+ }
+
+ while (!queue.empty()) {
+ OperationDepsNode *node = queue.front();
+ queue.pop();
+
+ IDDepsNode *id_node = node->owner->owner;
+ lib_id_recalc_tag(bmain, id_node->id);
+ /* TODO(sergey): For until we've got proper data nodes in the graph. */
+ lib_id_recalc_data_tag(bmain, id_node->id);
+
+ ID *id = id_node->id;
+ /* This code is used to preserve those areas which does direct
+ * object update,
+ *
+ * Plus it ensures visibility changes and relations and layers
+ * visibility update has proper flags to work with.
+ */
+ if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ ComponentDepsNode *comp_node = node->owner;
+ if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
+ object->recalc |= OB_RECALC_TIME;
+ }
+ else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) {
+ object->recalc |= OB_RECALC_OB;
+ }
+ else {
+ object->recalc |= OB_RECALC_DATA;
+ }
+ }
+
+ /* Flush to nodes along links... */
+ for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
+ it != node->outlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+ OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
+ if (to_node->scheduled == false) {
+ to_node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ queue.push(to_node);
+ to_node->scheduled = true;
+ deg_editors_id_update(bmain, id_node->id);
+ }
+ }
+
+ /* TODO(sergey): For until incremental updates are possible
+ * witin a component at least we tag the whole component
+ * for update.
+ */
+ for (ComponentDepsNode::OperationMap::iterator it = node->owner->operations.begin();
+ it != node->owner->operations.end();
+ ++it)
+ {
+ OperationDepsNode *op = it->second;
+ op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ }
+ }
+}
+
+/* Recursively push updates out to all nodes dependent on this,
+ * until all affected are tagged and/or scheduled up for eval
+ */
+void DEG_ids_flush_tagged(Main *bmain)
+{
+ for (Scene *scene = (Scene *)bmain->scene.first;
+ scene != NULL;
+ scene = (Scene *)scene->id.next)
+ {
+ /* TODO(sergey): Only visible scenes? */
+ if (scene->depsgraph != NULL) {
+ DEG_graph_flush_updates(bmain, scene->depsgraph);
+ }
+ }
+}
+
+/* Clear tags from all operation nodes. */
+void DEG_graph_clear_tags(Depsgraph *graph)
+{
+ /* Go over all operation nodes, clearing tags. */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+
+ /* Clear node's "pending update" settings. */
+ node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE);
+ /* Reset so that it can be bumped up again. */
+ node->num_links_pending = 0;
+ node->scheduled = false;
+ }
+
+ /* Clear any entry tags which haven't been flushed. */
+ graph->entry_tags.clear();
+}
+
+/* Update dependency graph when visible scenes/layers changes. */
+void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
+{
+ Depsgraph *graph = scene->depsgraph;
+ wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
+ int old_layers = graph->layers;
+ if (wm != NULL) {
+ BKE_main_id_flag_listbase(&bmain->scene, LIB_DOIT, true);
+ graph->layers = 0;
+ for (wmWindow *win = (wmWindow *)wm->windows.first;
+ win != NULL;
+ win = (wmWindow *)win->next)
+ {
+ Scene *scene = win->screen->scene;
+ if (scene->id.flag & LIB_DOIT) {
+ graph->layers |= BKE_screen_visible_layers(win->screen, scene);
+ scene->id.flag &= ~LIB_DOIT;
+ }
+ }
+ }
+ else {
+ /* All the layers for background render for now. */
+ graph->layers = (1 << 20) - 1;
+ }
+ if (old_layers != graph->layers) {
+ /* Tag all objects which becomes visible (or which becomes needed for dependencies)
+ * for recalc.
+ *
+ * This is mainly needed on file load only, after that updates of invisible objects
+ * will be stored in the pending list.
+ */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ IDDepsNode *id_node = node->owner->owner;
+ ID *id = id_node->id;
+ if ((id->flag & LIB_ID_RECALC_ALL) != 0 ||
+ (id_node->layers & scene->lay_updated) == 0)
+ {
+ id_node->tag_update(graph);
+ }
+ /* A bit of magic: if object->recalc is set it means somebody tagged
+ * it for update. If corresponding ID recalc flags are zero it means
+ * graph has been evaluated after that and the recalc was skipped
+ * because of visibility check.
+ */
+ if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ if ((id->flag & LIB_ID_RECALC_ALL) == 0 &&
+ (object->recalc & OB_RECALC_ALL) != 0)
+ {
+ id_node->tag_update(graph);
+ ComponentDepsNode *anim_comp =
+ id_node->find_component(DEPSNODE_TYPE_ANIMATION);
+ if (anim_comp != NULL && object->recalc & OB_RECALC_TIME) {
+ anim_comp->tag_update(graph);
+ }
+ }
+ }
+ }
+ }
+ scene->lay_updated |= graph->layers;
+}
+
+void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time))
+{
+ for (Scene *scene = (Scene *)bmain->scene.first;
+ scene != NULL;
+ scene = (Scene *)scene->id.next)
+ {
+ if (scene->depsgraph != NULL) {
+ DEG_graph_on_visible_update(bmain, scene);
+ }
+ }
+}
+
+/* Check if something was changed in the database and inform
+ * editors about this.
+ */
+void DEG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
+ bool updated = false;
+
+ /* Loop over all ID types. */
+ a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ ListBase *lb = lbarray[a];
+ ID *id = (ID *)lb->first;
+
+ /* We tag based on first ID type character to avoid
+ * looping over all ID's in case there are no tags.
+ */
+ if (id && bmain->id_tag_update[(unsigned char)id->name[0]]) {
+ updated = true;
+ break;
+ }
+ }
+
+ deg_editors_scene_update(bmain, scene, (updated || time));
+}
+
+void DEG_ids_clear_recalc(Main *bmain)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ bNodeTree *ntree;
+ int a;
+
+ /* TODO(sergey): Re-implement POST_UPDATE_HANDLER_WORKAROUND using entry_tags
+ * and id_tags storage from the new dependency graph.
+ */
+
+ /* Loop over all ID types. */
+ a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ ListBase *lb = lbarray[a];
+ ID *id = (ID *)lb->first;
+
+ /* We tag based on first ID type character to avoid
+ * looping over all ID's in case there are no tags.
+ */
+ if (id && bmain->id_tag_update[(unsigned char)id->name[0]]) {
+ for (; id; id = (ID *)id->next) {
+ id->flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA);
+
+ /* Some ID's contain semi-datablock nodetree */
+ ntree = ntreeFromID(id);
+ if (ntree != NULL) {
+ ntree->id.flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA);
+ }
+ }
+ }
+ }
+
+ memset(bmain->id_tag_update, 0, sizeof(bmain->id_tag_update));
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
new file mode 100644
index 00000000000..5a3048a4aa3
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
@@ -0,0 +1,102 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_type_defines.cc
+ * \ingroup depsgraph
+ *
+ * Defines and code for core node types.
+ */
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+#include "DEG_depsgraph.h"
+} /* extern "C" */
+
+#include "depsgraph_intern.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+
+/* ************ */
+/* External API */
+
+/* Global type registry */
+
+/**
+ * \note For now, this is a hashtable not array, since the core node types
+ * currently do not have contiguous ID values. Using a hash here gives us
+ * more flexibility, albeit using more memory and also sacrificing a little
+ * speed. Later on, when things stabilise we may turn this back to an array
+ * since there are only just a few node types that an array would cope fine...
+ */
+static GHash *_depsnode_typeinfo_registry = NULL;
+
+/* Registration ------------------------------------------- */
+
+/* Register node type */
+void DEG_register_node_typeinfo(DepsNodeFactory *factory)
+{
+ BLI_assert(factory != NULL);
+ BLI_ghash_insert(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(factory->type()), factory);
+}
+
+/* Register all node types */
+void DEG_register_node_types(void)
+{
+ /* initialise registry */
+ _depsnode_typeinfo_registry = BLI_ghash_int_new("Depsgraph Node Type Registry");
+
+ /* register node types */
+ DEG_register_base_depsnodes();
+ DEG_register_component_depsnodes();
+ DEG_register_operation_depsnodes();
+}
+
+/* Free registry on exit */
+void DEG_free_node_types(void)
+{
+ BLI_ghash_free(_depsnode_typeinfo_registry, NULL, NULL);
+}
+
+/* Getters ------------------------------------------------- */
+
+/* Get typeinfo for specified type */
+DepsNodeFactory *DEG_get_node_factory(const eDepsNode_Type type)
+{
+ /* look up type - at worst, it doesn't exist in table yet, and we fail */
+ return (DepsNodeFactory *)BLI_ghash_lookup(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(type));
+}
+
+/* Get typeinfo for provided node */
+DepsNodeFactory *DEG_node_get_factory(const DepsNode *node)
+{
+ if (!node)
+ return NULL;
+
+ return DEG_get_node_factory(node->type);
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h
new file mode 100644
index 00000000000..3616fe85496
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_types.h
@@ -0,0 +1,173 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_types.h
+ * \ingroup depsgraph
+ *
+ * Datatypes for internal use in the Depsgraph
+ *
+ * All of these datatypes are only really used within the "core" depsgraph.
+ * In particular, node types declared here form the structure of operations
+ * in the graph.
+ */
+
+#ifndef __DEPSGRAPH_TYPES_H__
+#define __DEPSGRAPH_TYPES_H__
+
+#include "depsgraph_util_function.h"
+
+/* TODO(sergey): Ideally we'll just use char* and statically allocated strings
+ * to avoid any possible overhead caused by string (re)allocation/formatting.
+ */
+#include <string>
+#include <vector>
+
+using std::string;
+using std::vector;
+
+struct bAction;
+struct ChannelDriver;
+struct ModifierData;
+struct PointerRNA;
+struct EvaluationContext;
+struct FCurve;
+
+/* Evaluation Operation for atomic operation */
+// XXX: move this to another header that can be exposed?
+typedef function<void(struct EvaluationContext *)> DepsEvalOperationCb;
+
+/* Metatype of Nodes - The general "level" in the graph structure the node serves */
+typedef enum eDepsNode_Class {
+ DEPSNODE_CLASS_GENERIC = 0, /* Types generally unassociated with user-visible entities, but needed for graph functioning */
+
+ DEPSNODE_CLASS_COMPONENT = 1, /* [Outer Node] An "aspect" of evaluating/updating an ID-Block, requiring certain types of evaluation behaviours */
+ DEPSNODE_CLASS_OPERATION = 2, /* [Inner Node] A glorified function-pointer/callback for scheduling up evaluation operations for components, subject to relationship requirements */
+} eDepsNode_Class;
+
+/* Types of Nodes */
+typedef enum eDepsNode_Type {
+ DEPSNODE_TYPE_UNDEFINED = -1, /* fallback type for invalid return value */
+
+ DEPSNODE_TYPE_OPERATION = 0, /* Inner Node (Operation) */
+
+ /* Generic Types */
+ DEPSNODE_TYPE_ROOT = 1, /* "Current Scene" - basically whatever kicks off the evaluation process */
+ DEPSNODE_TYPE_TIMESOURCE = 2, /* Time-Source */
+
+ DEPSNODE_TYPE_ID_REF = 3, /* ID-Block reference - used as landmarks/collection point for components, but not usually part of main graph */
+ DEPSNODE_TYPE_SUBGRAPH = 4, /* Isolated sub-graph - used for keeping instanced data separate from instances using them */
+
+ /* Outer Types */
+ DEPSNODE_TYPE_PARAMETERS = 11, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
+ DEPSNODE_TYPE_PROXY = 12, /* Generic "Proxy-Inherit" Component */ // XXX: Also for instancing of subgraphs?
+ DEPSNODE_TYPE_ANIMATION = 13, /* Animation Component */ // XXX: merge in with parameters?
+ DEPSNODE_TYPE_TRANSFORM = 14, /* Transform Component (Parenting/Constraints) */
+ DEPSNODE_TYPE_GEOMETRY = 15, /* Geometry Component (DerivedMesh/Displist) */
+ DEPSNODE_TYPE_SEQUENCER = 16, /* Sequencer Component (Scene Only) */
+
+ /* Evaluation-Related Outer Types (with Subdata) */
+ DEPSNODE_TYPE_EVAL_POSE = 21, /* Pose Component - Owner/Container of Bones Eval */
+ DEPSNODE_TYPE_BONE = 22, /* Bone Component - Child/Subcomponent of Pose */
+
+ DEPSNODE_TYPE_EVAL_PARTICLES = 23, /* Particle Systems Component */
+ DEPSNODE_TYPE_SHADING = 24, /* Material Shading Component */
+} eDepsNode_Type;
+
+/* Identifiers for common operations (as an enum) */
+typedef enum eDepsOperation_Code {
+#define DEF_DEG_OPCODE(label) DEG_OPCODE_##label,
+#include "depsnode_opcodes.h"
+#undef DEF_DEG_OPCODE
+} eDepsOperation_Code;
+
+/* String defines for these opcodes, defined in depsnode_operation.cpp */
+extern const char *DEG_OPNAMES[];
+
+
+/* Type of operation */
+typedef enum eDepsOperation_Type {
+ /* Primary operation types */
+ DEPSOP_TYPE_INIT = 0, /* initialise evaluation data */
+ DEPSOP_TYPE_EXEC = 1, /* standard evaluation step */
+ DEPSOP_TYPE_POST = 2, /* cleanup evaluation data + flush results */
+
+ /* Additional operation types */
+ DEPSOP_TYPE_OUT = 3, /* indicator for outputting a temporary result that other components can use */ // XXX?
+ DEPSOP_TYPE_SIM = 4, /* indicator for things like IK Solvers and Rigidbody Sim steps which modify final results of separate entities at once */
+ DEPSOP_TYPE_REBUILD = 5, /* rebuild internal evaluation data - used for Rigidbody Reset and Armature Rebuild-On-Load */
+} eDepsOperation_Type;
+
+/* Types of relationships between nodes
+ *
+ * This is used to provide additional hints to use when filtering
+ * the graph, so that we can go without doing more extensive
+ * data-level checks...
+ */
+typedef enum eDepsRelation_Type {
+ /* reationship type unknown/irrelevant */
+ DEPSREL_TYPE_STANDARD = 0,
+
+ /* root -> active scene or entity (screen, image, etc.) */
+ DEPSREL_TYPE_ROOT_TO_ACTIVE,
+
+ /* general datablock dependency */
+ DEPSREL_TYPE_DATABLOCK,
+
+ /* time dependency */
+ DEPSREL_TYPE_TIME,
+
+ /* component depends on results of another */
+ DEPSREL_TYPE_COMPONENT_ORDER,
+
+ /* relationship is just used to enforce ordering of operations
+ * (e.g. "init()" callback done before "exec() and "cleanup()")
+ */
+ DEPSREL_TYPE_OPERATION,
+
+ /* relationship results from a property driver affecting property */
+ DEPSREL_TYPE_DRIVER,
+
+ /* relationship is something driver depends on */
+ DEPSREL_TYPE_DRIVER_TARGET,
+
+ /* relationship is used for transform stack
+ * (e.g. parenting, user transforms, constraints)
+ */
+ DEPSREL_TYPE_TRANSFORM,
+
+ /* relationship is used for geometry evaluation
+ * (e.g. metaball "motherball" or modifiers)
+ */
+ DEPSREL_TYPE_GEOMETRY_EVAL,
+
+ /* relationship is used to trigger a post-change validity updates */
+ DEPSREL_TYPE_UPDATE,
+
+ /* relationship is used to trigger editor/screen updates */
+ DEPSREL_TYPE_UPDATE_UI,
+} eDepsRelation_Type;
+
+#endif /* __DEPSGRAPH_TYPES_H__ */
diff --git a/source/blender/depsgraph/intern/depsnode.cc b/source/blender/depsgraph/intern/depsnode.cc
new file mode 100644
index 00000000000..1736aadf999
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode.cc
@@ -0,0 +1,316 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsnode.cc
+ * \ingroup depsgraph
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "BLI_utildefines.h"
+
+extern "C" {
+#include "DNA_ID.h"
+#include "DNA_anim_types.h"
+
+#include "BKE_animsys.h"
+
+#include "DEG_depsgraph.h"
+}
+
+#include "depsnode.h" /* own include */
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_intern.h"
+
+/* *************** */
+/* Node Management */
+
+/* Add ------------------------------------------------ */
+
+DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type, const char *tname)
+{
+ this->type = type;
+ if (type == DEPSNODE_TYPE_OPERATION)
+ this->tclass = DEPSNODE_CLASS_OPERATION;
+ else if (type < DEPSNODE_TYPE_PARAMETERS)
+ this->tclass = DEPSNODE_CLASS_GENERIC;
+ else
+ this->tclass = DEPSNODE_CLASS_COMPONENT;
+ this->tname = tname;
+}
+
+DepsNode::DepsNode()
+{
+ this->name[0] = '\0';
+}
+
+DepsNode::~DepsNode()
+{
+ /* free links
+ * note: deleting relations will remove them from the node relations set,
+ * but only touch the same position as we are using here, which is safe.
+ */
+ DEPSNODE_RELATIONS_ITER_BEGIN(this->inlinks, rel)
+ {
+ OBJECT_GUARDED_DELETE(rel, DepsRelation);
+ }
+ DEPSNODE_RELATIONS_ITER_END;
+
+ DEPSNODE_RELATIONS_ITER_BEGIN(this->outlinks, rel)
+ {
+ OBJECT_GUARDED_DELETE(rel, DepsRelation);
+ }
+ DEPSNODE_RELATIONS_ITER_END;
+}
+
+
+/* Generic identifier for Depsgraph Nodes. */
+string DepsNode::identifier() const
+{
+ char typebuf[7];
+ sprintf(typebuf, "(%d)", type);
+
+ return string(typebuf) + " : " + name;
+}
+
+/* ************* */
+/* Generic Nodes */
+
+/* Time Source Node ============================================== */
+
+void TimeSourceDepsNode::tag_update(Depsgraph *graph)
+{
+ for (DepsNode::Relations::const_iterator it = outlinks.begin();
+ it != outlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+ DepsNode *node = rel->to;
+ node->tag_update(graph);
+ }
+}
+
+
+/* Root Node ============================================== */
+
+RootDepsNode::RootDepsNode() : scene(NULL), time_source(NULL)
+{
+}
+
+RootDepsNode::~RootDepsNode()
+{
+ OBJECT_GUARDED_DELETE(time_source, TimeSourceDepsNode);
+}
+
+TimeSourceDepsNode *RootDepsNode::add_time_source(const string &name)
+{
+ if (!time_source) {
+ DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_TIMESOURCE);
+ time_source = (TimeSourceDepsNode *)factory->create_node(NULL, "", name);
+ /*time_source->owner = this;*/ // XXX
+ }
+ return time_source;
+}
+
+DEG_DEPSNODE_DEFINE(RootDepsNode, DEPSNODE_TYPE_ROOT, "Root DepsNode");
+static DepsNodeFactoryImpl<RootDepsNode> DNTI_ROOT;
+
+/* Time Source Node ======================================= */
+
+DEG_DEPSNODE_DEFINE(TimeSourceDepsNode, DEPSNODE_TYPE_TIMESOURCE, "Time Source");
+static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE;
+
+/* ID Node ================================================ */
+
+/* Initialize 'id' node - from pointer data given. */
+void IDDepsNode::init(const ID *id, const string &UNUSED(subdata))
+{
+ /* Store ID-pointer. */
+ BLI_assert(id != NULL);
+ this->id = (ID *)id;
+ this->layers = (1 << 20) - 1;
+ this->eval_flags = 0;
+
+ /* NOTE: components themselves are created if/when needed.
+ * This prevents problems with components getting added
+ * twice if an ID-Ref needs to be created to house it...
+ */
+}
+
+/* Free 'id' node. */
+IDDepsNode::~IDDepsNode()
+{
+ clear_components();
+}
+
+/* Copy 'id' node. */
+void IDDepsNode::copy(DepsgraphCopyContext *dcc, const IDDepsNode *src)
+{
+ (void)src; /* Ignored. */
+ /* Iterate over items in original hash, adding them to new hash. */
+ for (IDDepsNode::ComponentMap::const_iterator it = this->components.begin();
+ it != this->components.end();
+ ++it)
+ {
+ /* Get current <type : component> mapping. */
+ ComponentIDKey c_key = it->first;
+ DepsNode *old_component = it->second;
+
+ /* Make a copy of component. */
+ ComponentDepsNode *component = (ComponentDepsNode *)DEG_copy_node(dcc, old_component);
+
+ /* Add new node to hash... */
+ this->components[c_key] = component;
+ }
+
+ // TODO: perform a second loop to fix up links?
+ BLI_assert(!"Not expected to be used");
+}
+
+ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type,
+ const string &name) const
+{
+ ComponentIDKey key(type, name);
+ ComponentMap::const_iterator it = components.find(key);
+ return it != components.end() ? it->second : NULL;
+}
+
+ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
+ const string &name)
+{
+ ComponentIDKey key(type, name);
+ ComponentDepsNode *comp_node = find_component(type, name);
+ if (!comp_node) {
+ DepsNodeFactory *factory = DEG_get_node_factory(type);
+ comp_node = (ComponentDepsNode *)factory->create_node(this->id, "", name);
+
+ /* Register. */
+ this->components[key] = comp_node;
+ comp_node->owner = this;
+ }
+ return comp_node;
+}
+
+void IDDepsNode::remove_component(eDepsNode_Type type, const string &name)
+{
+ ComponentIDKey key(type, name);
+ ComponentDepsNode *comp_node = find_component(type, name);
+ if (comp_node) {
+ /* Unregister. */
+ this->components.erase(key);
+ OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
+ }
+}
+
+void IDDepsNode::clear_components()
+{
+ for (ComponentMap::const_iterator it = components.begin();
+ it != components.end();
+ ++it)
+ {
+ ComponentDepsNode *comp_node = it->second;
+ OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
+ }
+ components.clear();
+}
+
+void IDDepsNode::tag_update(Depsgraph *graph)
+{
+ for (ComponentMap::const_iterator it = components.begin();
+ it != components.end();
+ ++it)
+ {
+ ComponentDepsNode *comp_node = it->second;
+ /* TODO(sergey): What about drievrs? */
+ bool do_component_tag = comp_node->type != DEPSNODE_TYPE_ANIMATION;
+ if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
+ AnimData *adt = BKE_animdata_from_id(id);
+ BLI_assert(adt != NULL);
+ if (adt->recalc & ADT_RECALC_ANIM) {
+ do_component_tag = true;
+ }
+ }
+ if (do_component_tag) {
+ comp_node->tag_update(graph);
+ }
+ }
+}
+
+DEG_DEPSNODE_DEFINE(IDDepsNode, DEPSNODE_TYPE_ID_REF, "ID Node");
+static DepsNodeFactoryImpl<IDDepsNode> DNTI_ID_REF;
+
+/* Subgraph Node ========================================== */
+
+/* Initialize 'subgraph' node - from pointer data given. */
+void SubgraphDepsNode::init(const ID *id, const string &UNUSED(subdata))
+{
+ /* Store ID-ref if provided. */
+ this->root_id = (ID *)id;
+
+ /* NOTE: graph will need to be added manually,
+ * as we don't have any way of passing this down.
+ */
+}
+
+/* Free 'subgraph' node */
+SubgraphDepsNode::~SubgraphDepsNode()
+{
+ /* Only free if graph not shared, of if this node is the first
+ * reference to it...
+ */
+ // XXX: prune these flags a bit...
+ if ((this->flag & SUBGRAPH_FLAG_FIRSTREF) || !(this->flag & SUBGRAPH_FLAG_SHARED)) {
+ /* Free the referenced graph. */
+ DEG_graph_free(this->graph);
+ this->graph = NULL;
+ }
+}
+
+/* Copy 'subgraph' node - Assume that the subgraph doesn't get copied for now... */
+void SubgraphDepsNode::copy(DepsgraphCopyContext * /*dcc*/,
+ const SubgraphDepsNode * /*src*/)
+{
+ //const SubgraphDepsNode *src_node = (const SubgraphDepsNode *)src;
+ //SubgraphDepsNode *dst_node = (SubgraphDepsNode *)dst;
+
+ /* for now, subgraph itself isn't copied... */
+ BLI_assert(!"Not expected to be used");
+}
+
+DEG_DEPSNODE_DEFINE(SubgraphDepsNode, DEPSNODE_TYPE_SUBGRAPH, "Subgraph Node");
+static DepsNodeFactoryImpl<SubgraphDepsNode> DNTI_SUBGRAPH;
+
+
+void DEG_register_base_depsnodes()
+{
+ DEG_register_node_typeinfo(&DNTI_ROOT);
+ DEG_register_node_typeinfo(&DNTI_TIMESOURCE);
+
+ DEG_register_node_typeinfo(&DNTI_ID_REF);
+ DEG_register_node_typeinfo(&DNTI_SUBGRAPH);
+}
diff --git a/source/blender/depsgraph/intern/depsnode.h b/source/blender/depsgraph/intern/depsnode.h
new file mode 100644
index 00000000000..53826ae8e71
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode.h
@@ -0,0 +1,248 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsnode.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSNODE_H__
+#define __DEPSNODE_H__
+
+#include "depsgraph_types.h"
+
+#include "depsgraph_util_hash.h"
+#include "depsgraph_util_map.h"
+#include "depsgraph_util_set.h"
+
+struct ID;
+struct Scene;
+
+struct Depsgraph;
+struct DepsRelation;
+struct DepsgraphCopyContext;
+struct OperationDepsNode;
+
+/* *********************************** */
+/* Base-Defines for Nodes in Depsgraph */
+
+/* All nodes in Depsgraph are descended from this. */
+struct DepsNode {
+ /* Helper class for static typeinfo in subclasses. */
+ struct TypeInfo {
+ TypeInfo(eDepsNode_Type type, const char *tname);
+
+ eDepsNode_Type type;
+ eDepsNode_Class tclass;
+ const char *tname;
+ };
+
+ /* Identifier - mainly for debugging purposes. */
+ string name;
+
+ /* Structural type of node. */
+ eDepsNode_Type type;
+
+ /* Type of data/behaviour represented by node... */
+ eDepsNode_Class tclass;
+
+ /* Relationships between nodes
+ * The reason why all depsgraph nodes are descended from this type (apart
+ * from basic serialization benefits - from the typeinfo) is that we can have
+ * relationships between these nodes!
+ */
+ typedef unordered_set<DepsRelation *> Relations;
+
+ /* Nodes which this one depends on. */
+ Relations inlinks;
+
+ /* Nodes which depend on this one. */
+ Relations outlinks;
+
+ /* Generic tag for traversal algorithms */
+ int done;
+
+ /* Methods. */
+
+ DepsNode();
+ virtual ~DepsNode();
+
+ virtual string identifier() const;
+ string full_identifier() const;
+
+ virtual void init(const ID * /*id*/,
+ const string &/*subdata*/) {}
+ virtual void copy(DepsgraphCopyContext * /*dcc*/,
+ const DepsNode * /*src*/) {}
+
+ virtual void tag_update(Depsgraph * /*graph*/) {}
+
+ virtual OperationDepsNode *get_entry_operation() { return NULL; }
+ virtual OperationDepsNode *get_exit_operation() { return NULL; }
+};
+
+/* Macros for common static typeinfo. */
+#define DEG_DEPSNODE_DECLARE \
+ static const DepsNode::TypeInfo typeinfo
+#define DEG_DEPSNODE_DEFINE(NodeType, type_, tname_) \
+ const DepsNode::TypeInfo NodeType::typeinfo = DepsNode::TypeInfo(type_, tname_)
+
+/* Generic Nodes ======================= */
+
+struct ComponentDepsNode;
+struct IDDepsNode;
+
+/* Time Source Node. */
+struct TimeSourceDepsNode : public DepsNode {
+ /* New "current time". */
+ float cfra;
+
+ /* time-offset relative to the "official" time source that this one has. */
+ float offset;
+
+ // TODO: evaluate() operation needed
+
+ void tag_update(Depsgraph *graph);
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+/* Root Node. */
+struct RootDepsNode : public DepsNode {
+ RootDepsNode();
+ ~RootDepsNode();
+
+ TimeSourceDepsNode *add_time_source(const string &name = "");
+
+ /* scene that this corresponds to */
+ Scene *scene;
+
+ /* Entrypoint node for time-changed. */
+ TimeSourceDepsNode *time_source;
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+/* ID-Block Reference */
+struct IDDepsNode : public DepsNode {
+ struct ComponentIDKey {
+ ComponentIDKey(eDepsNode_Type type, const string &name = "")
+ : type(type), name(name) {}
+
+ bool operator== (const ComponentIDKey &other) const
+ {
+ return type == other.type && name == other.name;
+ }
+
+ eDepsNode_Type type;
+ string name;
+ };
+
+ /* XXX can't specialize std::hash for this purpose, because ComponentIDKey is
+ * a nested type ...
+ *
+ * http://stackoverflow.com/a/951245
+ */
+ struct component_key_hash {
+ bool operator() (const ComponentIDKey &key) const
+ {
+ return hash_combine(hash<int>()(key.type), hash<string>()(key.name));
+ }
+ };
+
+ typedef unordered_map<ComponentIDKey,
+ ComponentDepsNode *,
+ component_key_hash> ComponentMap;
+
+ void init(const ID *id, const string &subdata);
+ void copy(DepsgraphCopyContext *dcc, const IDDepsNode *src);
+ ~IDDepsNode();
+
+ ComponentDepsNode *find_component(eDepsNode_Type type,
+ const string &name = "") const;
+ ComponentDepsNode *add_component(eDepsNode_Type type,
+ const string &name = "");
+ void remove_component(eDepsNode_Type type, const string &name = "");
+ void clear_components();
+
+ void tag_update(Depsgraph *graph);
+
+ /* ID Block referenced. */
+ ID *id;
+
+ /* Hash to make it faster to look up components. */
+ ComponentMap components;
+
+ /* Layers of this node with accumulated layers of it's output relations. */
+ int layers;
+
+ /* Additional flags needed for scene evaluation.
+ * TODO(sergey): Only needed for until really granular updates
+ * of all the entities.
+ */
+ int eval_flags;
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+/* Subgraph Reference. */
+struct SubgraphDepsNode : public DepsNode {
+ void init(const ID *id, const string &subdata);
+ void copy(DepsgraphCopyContext *dcc, const SubgraphDepsNode *src);
+ ~SubgraphDepsNode();
+
+ /* Instanced graph. */
+ Depsgraph *graph;
+
+ /* ID-block at root of subgraph (if applicable). */
+ ID *root_id;
+
+ /* Number of nodes which use/reference this subgraph - if just 1, it may be
+ * possible to merge into main,
+ */
+ size_t num_users;
+
+ /* (eSubgraphRef_Flag) assorted settings for subgraph node. */
+ int flag;
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+/* Flags for subgraph node */
+typedef enum eSubgraphRef_Flag {
+ /* Subgraph referenced is shared with another reference, so shouldn't
+ * free on exit.
+ */
+ SUBGRAPH_FLAG_SHARED = (1 << 0),
+
+ /* Node is first reference to subgraph, so it can be freed when we are
+ * removed.
+ */
+ SUBGRAPH_FLAG_FIRSTREF = (1 << 1),
+} eSubgraphRef_Flag;
+
+void DEG_register_base_depsnodes();
+
+#endif /* __DEPSNODE_H__ */
diff --git a/source/blender/depsgraph/intern/depsnode_component.cc b/source/blender/depsgraph/intern/depsnode_component.cc
new file mode 100644
index 00000000000..1d939c6580d
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode_component.cc
@@ -0,0 +1,318 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsnode_component.cc
+ * \ingroup depsgraph
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+extern "C" {
+#include "BLI_utildefines.h"
+
+#include "DNA_object_types.h"
+
+#include "BKE_action.h"
+} /* extern "C" */
+
+#include "depsnode_component.h" /* own include */
+#include "depsnode_operation.h"
+#include "depsgraph_intern.h"
+
+/* *********** */
+/* Outer Nodes */
+
+/* Standard Component Methods ============================= */
+
+ComponentDepsNode::ComponentDepsNode() :
+ entry_operation(NULL),
+ exit_operation(NULL)
+{
+}
+
+/* Initialize 'component' node - from pointer data given */
+void ComponentDepsNode::init(const ID * /*id*/,
+ const string & /*subdata*/)
+{
+ /* hook up eval context? */
+ // XXX: maybe this needs a special API?
+}
+
+/* Copy 'component' node */
+void ComponentDepsNode::copy(DepsgraphCopyContext * /*dcc*/,
+ const ComponentDepsNode * /*src*/)
+{
+#if 0 // XXX: remove all this
+ /* duplicate list of operation nodes */
+ this->operations.clear();
+
+ for (OperationMap::const_iterator it = src->operations.begin(); it != src->operations.end(); ++it) {
+ const string &pchan_name = it->first;
+ OperationDepsNode *src_op = it->second;
+
+ /* recursive copy */
+ DepsNodeFactory *factory = DEG_node_get_factory(src_op);
+ OperationDepsNode *dst_op = (OperationDepsNode *)factory->copy_node(dcc, src_op);
+ this->operations[pchan_name] = dst_op;
+
+ /* fix links... */
+ // ...
+ }
+
+ /* copy evaluation contexts */
+ //
+#endif
+ BLI_assert(!"Not expected to be called");
+}
+
+/* Free 'component' node */
+ComponentDepsNode::~ComponentDepsNode()
+{
+ clear_operations();
+}
+
+string ComponentDepsNode::identifier() const
+{
+ string &idname = this->owner->name;
+
+ char typebuf[7];
+ sprintf(typebuf, "(%d)", type);
+
+ return string(typebuf) + name + " : " + idname;
+}
+
+OperationDepsNode *ComponentDepsNode::find_operation(OperationIDKey key) const
+{
+ OperationMap::const_iterator it = this->operations.find(key);
+
+ if (it != this->operations.end()) {
+ return it->second;
+ }
+ else {
+ fprintf(stderr, "%s: find_operation(%s) failed\n",
+ this->identifier().c_str(), key.identifier().c_str());
+ BLI_assert(!"Request for non-existing operation, should not happen");
+ return NULL;
+ }
+}
+
+OperationDepsNode *ComponentDepsNode::find_operation(eDepsOperation_Code opcode, const string &name) const
+{
+ OperationIDKey key(opcode, name);
+ return find_operation(key);
+}
+
+OperationDepsNode *ComponentDepsNode::has_operation(OperationIDKey key) const
+{
+ OperationMap::const_iterator it = this->operations.find(key);
+ if (it != this->operations.end()) {
+ return it->second;
+ }
+ return NULL;
+}
+
+OperationDepsNode *ComponentDepsNode::has_operation(eDepsOperation_Code opcode,
+ const string &name) const
+{
+ OperationIDKey key(opcode, name);
+ return has_operation(key);
+}
+
+OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &name)
+{
+ OperationDepsNode *op_node = has_operation(opcode, name);
+ if (!op_node) {
+ DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_OPERATION);
+ op_node = (OperationDepsNode *)factory->create_node(this->owner->id, "", name);
+
+ /* register opnode in this component's operation set */
+ OperationIDKey key(opcode, name);
+ this->operations[key] = op_node;
+
+ /* set as entry/exit node of component (if appropriate) */
+ if (optype == DEPSOP_TYPE_INIT) {
+ BLI_assert(this->entry_operation == NULL);
+ this->entry_operation = op_node;
+ }
+ else if (optype == DEPSOP_TYPE_POST) {
+ // XXX: review whether DEPSOP_TYPE_OUT is better than DEPSOP_TYPE_POST, or maybe have both?
+ BLI_assert(this->exit_operation == NULL);
+ this->exit_operation = op_node;
+ }
+
+ /* set backlink */
+ op_node->owner = this;
+ }
+ else {
+ fprintf(stderr, "add_operation: Operation already exists - %s has %s at %p\n",
+ this->identifier().c_str(), op_node->identifier().c_str(), op_node);
+ BLI_assert(!"Should not happen!");
+ }
+
+ /* attach extra data */
+ op_node->evaluate = op;
+ op_node->optype = optype;
+ op_node->opcode = opcode;
+ op_node->name = name;
+
+ return op_node;
+}
+
+void ComponentDepsNode::remove_operation(eDepsOperation_Code opcode, const string &name)
+{
+ OperationDepsNode *op_node = find_operation(opcode, name);
+ if (op_node) {
+ /* unregister */
+ this->operations.erase(OperationIDKey(opcode, name));
+ OBJECT_GUARDED_DELETE(op_node, OperationDepsNode);
+ }
+}
+
+void ComponentDepsNode::clear_operations()
+{
+ for (OperationMap::const_iterator it = operations.begin(); it != operations.end(); ++it) {
+ OperationDepsNode *op_node = it->second;
+ OBJECT_GUARDED_DELETE(op_node, OperationDepsNode);
+ }
+ operations.clear();
+}
+
+void ComponentDepsNode::tag_update(Depsgraph *graph)
+{
+ OperationDepsNode *entry_op = get_entry_operation();
+ if (entry_op != NULL && entry_op->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ return;
+ }
+ for (OperationMap::const_iterator it = operations.begin(); it != operations.end(); ++it) {
+ OperationDepsNode *op_node = it->second;
+ op_node->tag_update(graph);
+ }
+}
+
+OperationDepsNode *ComponentDepsNode::get_entry_operation()
+{
+ if (entry_operation)
+ return entry_operation;
+ else if (operations.size() == 1)
+ return operations.begin()->second;
+ return NULL;
+}
+
+OperationDepsNode *ComponentDepsNode::get_exit_operation()
+{
+ if (exit_operation)
+ return exit_operation;
+ else if (operations.size() == 1)
+ return operations.begin()->second;
+ return NULL;
+}
+
+/* Parameter Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(ParametersComponentDepsNode, DEPSNODE_TYPE_PARAMETERS, "Parameters Component");
+static DepsNodeFactoryImpl<ParametersComponentDepsNode> DNTI_PARAMETERS;
+
+/* Animation Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(AnimationComponentDepsNode, DEPSNODE_TYPE_ANIMATION, "Animation Component");
+static DepsNodeFactoryImpl<AnimationComponentDepsNode> DNTI_ANIMATION;
+
+/* Transform Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(TransformComponentDepsNode, DEPSNODE_TYPE_TRANSFORM, "Transform Component");
+static DepsNodeFactoryImpl<TransformComponentDepsNode> DNTI_TRANSFORM;
+
+/* Proxy Component Defines ================================ */
+
+DEG_DEPSNODE_DEFINE(ProxyComponentDepsNode, DEPSNODE_TYPE_PROXY, "Proxy Component");
+static DepsNodeFactoryImpl<ProxyComponentDepsNode> DNTI_PROXY;
+
+/* Geometry Component Defines ============================= */
+
+DEG_DEPSNODE_DEFINE(GeometryComponentDepsNode, DEPSNODE_TYPE_GEOMETRY, "Geometry Component");
+static DepsNodeFactoryImpl<GeometryComponentDepsNode> DNTI_GEOMETRY;
+
+/* Sequencer Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(SequencerComponentDepsNode, DEPSNODE_TYPE_SEQUENCER, "Sequencer Component");
+static DepsNodeFactoryImpl<SequencerComponentDepsNode> DNTI_SEQUENCER;
+
+/* Pose Component ========================================= */
+
+DEG_DEPSNODE_DEFINE(PoseComponentDepsNode, DEPSNODE_TYPE_EVAL_POSE, "Pose Eval Component");
+static DepsNodeFactoryImpl<PoseComponentDepsNode> DNTI_EVAL_POSE;
+
+/* Bone Component ========================================= */
+
+/* Initialize 'bone component' node - from pointer data given */
+void BoneComponentDepsNode::init(const ID *id, const string &subdata)
+{
+ /* generic component-node... */
+ ComponentDepsNode::init(id, subdata);
+
+ /* name of component comes is bone name */
+ /* TODO(sergey): This sets name to an empty string because subdata is
+ * empty. Is it a bug?
+ */
+ //this->name = subdata;
+
+ /* bone-specific node data */
+ Object *ob = (Object *)id;
+ this->pchan = BKE_pose_channel_find_name(ob->pose, subdata.c_str());
+}
+
+DEG_DEPSNODE_DEFINE(BoneComponentDepsNode, DEPSNODE_TYPE_BONE, "Bone Component");
+static DepsNodeFactoryImpl<BoneComponentDepsNode> DNTI_BONE;
+
+/* Particles Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(ParticlesComponentDepsNode, DEPSNODE_TYPE_EVAL_PARTICLES, "Particles Component");
+static DepsNodeFactoryImpl<ParticlesComponentDepsNode> DNTI_EVAL_PARTICLES;
+
+/* Shading Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(ShadingComponentDepsNode, DEPSNODE_TYPE_SHADING, "Shading Component");
+static DepsNodeFactoryImpl<ShadingComponentDepsNode> DNTI_SHADING;
+
+
+/* Node Types Register =================================== */
+
+void DEG_register_component_depsnodes()
+{
+ DEG_register_node_typeinfo(&DNTI_PARAMETERS);
+ DEG_register_node_typeinfo(&DNTI_PROXY);
+ DEG_register_node_typeinfo(&DNTI_ANIMATION);
+ DEG_register_node_typeinfo(&DNTI_TRANSFORM);
+ DEG_register_node_typeinfo(&DNTI_GEOMETRY);
+ DEG_register_node_typeinfo(&DNTI_SEQUENCER);
+
+ DEG_register_node_typeinfo(&DNTI_EVAL_POSE);
+ DEG_register_node_typeinfo(&DNTI_BONE);
+
+ DEG_register_node_typeinfo(&DNTI_EVAL_PARTICLES);
+ DEG_register_node_typeinfo(&DNTI_SHADING);
+}
diff --git a/source/blender/depsgraph/intern/depsnode_component.h b/source/blender/depsgraph/intern/depsnode_component.h
new file mode 100644
index 00000000000..e3550bb2371
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode_component.h
@@ -0,0 +1,201 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsnode_component.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSNODE_COMPONENT_H__
+#define __DEPSNODE_COMPONENT_H__
+
+#include "depsnode.h"
+
+#include "depsgraph_util_hash.h"
+#include "depsgraph_util_map.h"
+#include "depsgraph_util_set.h"
+
+struct ID;
+struct bPoseChannel;
+
+struct Depsgraph;
+struct DepsgraphCopyContext;
+struct EvaluationContext;
+struct OperationDepsNode;
+struct BoneComponentDepsNode;
+
+
+/* ID Component - Base type for all components */
+struct ComponentDepsNode : public DepsNode {
+ /* Key used to look up operations within a component */
+ struct OperationIDKey
+ {
+ eDepsOperation_Code opcode;
+ string name;
+
+
+ OperationIDKey() :
+ opcode(DEG_OPCODE_OPERATION), name("")
+ {}
+ OperationIDKey(eDepsOperation_Code opcode) :
+ opcode(opcode), name("")
+ {}
+ OperationIDKey(eDepsOperation_Code opcode, const string &name) :
+ opcode(opcode), name(name)
+ {}
+
+ string identifier() const
+ {
+ char codebuf[5];
+ sprintf(codebuf, "%d", opcode);
+
+ return string("OperationIDKey(") + codebuf + ", " + name + ")";
+ }
+
+ bool operator==(const OperationIDKey &other) const
+ {
+ return (opcode == other.opcode) && (name == other.name);
+ }
+ };
+
+ /* XXX can't specialize std::hash for this purpose, because ComponentKey is a nested type ...
+ * http://stackoverflow.com/a/951245
+ */
+ struct operation_key_hash {
+ bool operator() (const OperationIDKey &key) const
+ {
+ return hash_combine(hash<int>()(key.opcode), hash<string>()(key.name));
+ }
+ };
+
+ /* Typedef for container of operations */
+ typedef unordered_map<OperationIDKey, OperationDepsNode *, operation_key_hash> OperationMap;
+
+
+ ComponentDepsNode();
+ ~ComponentDepsNode();
+
+ void init(const ID *id, const string &subdata);
+ void copy(DepsgraphCopyContext *dcc, const ComponentDepsNode *src);
+
+ string identifier() const;
+
+ /* Find an existing operation, will throw an assert() if it does not exist. */
+ OperationDepsNode *find_operation(OperationIDKey key) const;
+ OperationDepsNode *find_operation(eDepsOperation_Code opcode, const string &name) const;
+
+ /* Check operation exists and return it. */
+ OperationDepsNode *has_operation(OperationIDKey key) const;
+ OperationDepsNode *has_operation(eDepsOperation_Code opcode, const string &name) const;
+
+ /**
+ * Create a new node for representing an operation and add this to graph
+ * \warning If an existing node is found, it will be modified. This helps when node may
+ * have been partially created earlier (e.g. parent ref before parent item is added)
+ *
+ * \param type: Operation node type (corresponding to context/component that it operates in)
+ * \param optype: Role that operation plays within component (i.e. where in eval process)
+ * \param op: The operation to perform
+ * \param name: Identifier for operation - used to find/locate it again
+ */
+ OperationDepsNode *add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &name);
+
+ void remove_operation(eDepsOperation_Code opcode, const string &name);
+ void clear_operations();
+
+ void tag_update(Depsgraph *graph);
+
+ /* Evaluation Context Management .................. */
+
+ /* Initialize component's evaluation context used for the specified purpose */
+ virtual bool eval_context_init(EvaluationContext * /*eval_ctx*/) { return false; }
+ /* Free data in component's evaluation context which is used for the specified purpose
+ * NOTE: this does not free the actual context in question
+ */
+ virtual void eval_context_free(EvaluationContext * /*eval_ctx*/) {}
+
+ OperationDepsNode *get_entry_operation();
+ OperationDepsNode *get_exit_operation();
+
+ IDDepsNode *owner;
+
+ OperationMap operations; /* inner nodes for this component */
+ OperationDepsNode *entry_operation;
+ OperationDepsNode *exit_operation;
+
+ // XXX: a poll() callback to check if component's first node can be started?
+};
+
+/* ---------------------------------------- */
+
+struct ParametersComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct AnimationComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct TransformComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct ProxyComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct GeometryComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct SequencerComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct PoseComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+/* Bone Component */
+struct BoneComponentDepsNode : public ComponentDepsNode {
+ void init(const ID *id, const string &subdata);
+
+ struct bPoseChannel *pchan; /* the bone that this component represents */
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct ParticlesComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct ShadingComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+
+void DEG_register_component_depsnodes();
+
+#endif /* __DEPSNODE_COMPONENT_H__ */
diff --git a/source/blender/depsgraph/intern/depsnode_opcodes.h b/source/blender/depsgraph/intern/depsnode_opcodes.h
new file mode 100644
index 00000000000..b81822c0ac5
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode_opcodes.h
@@ -0,0 +1,145 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsnode_opcodes.h
+ * \ingroup depsgraph
+ *
+ * \par OpCodes for OperationDepsNodes
+ *
+ * This file defines all the "operation codes" (opcodes) used to identify
+ * common operation node types. The intention of these defines is to have
+ * a fast and reliable way of identifying the relevant nodes within a component
+ * without having to use fragile dynamic strings.
+ *
+ * This file is meant to be used like UI_icons.h. That is, before including
+ * the file, the host file must define the DEG_OPCODE(_label) macro, which
+ * is responsible for converting the define into whatever form is suitable.
+ * Therefore, it intentionally doesn't have header guards.
+ */
+
+
+/* Example macro define: */
+/* #define DEF_DEG_OPCODE(label) DEG_OPCODE_##label, */
+
+/* Generic Operations ------------------------------ */
+
+/* Placeholder for operations which don't need special mention */
+DEF_DEG_OPCODE(OPERATION)
+
+// XXX: Placeholder while porting depsgraph code
+DEF_DEG_OPCODE(PLACEHOLDER)
+
+DEF_DEG_OPCODE(NOOP)
+
+/* Animation, Drivers, etc. ------------------------ */
+
+/* NLA + Action */
+DEF_DEG_OPCODE(ANIMATION)
+
+/* Driver */
+DEF_DEG_OPCODE(DRIVER)
+
+/* Proxy Inherit? */
+//DEF_DEG_OPCODE(PROXY)
+
+/* Transform --------------------------------------- */
+
+/* Transform entry point - local transforms only */
+DEF_DEG_OPCODE(TRANSFORM_LOCAL)
+
+/* Parenting */
+DEF_DEG_OPCODE(TRANSFORM_PARENT)
+
+/* Constraints */
+DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS)
+//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS_INIT)
+//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINT)
+//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS_DONE)
+
+/* Rigidbody Sim - Perform Sim */
+DEF_DEG_OPCODE(RIGIDBODY_REBUILD)
+DEF_DEG_OPCODE(RIGIDBODY_SIM)
+
+/* Rigidbody Sim - Copy Results to Object */
+DEF_DEG_OPCODE(TRANSFORM_RIGIDBODY)
+
+/* Transform exitpoint */
+DEF_DEG_OPCODE(TRANSFORM_FINAL)
+
+/* XXX: ubereval is for temporary porting purposes only */
+DEF_DEG_OPCODE(OBJECT_UBEREVAL)
+
+/* Geometry ---------------------------------------- */
+
+/* XXX: Placeholder - UberEval */
+DEF_DEG_OPCODE(GEOMETRY_UBEREVAL)
+
+/* Modifier */
+DEF_DEG_OPCODE(GEOMETRY_MODIFIER)
+
+/* Curve Objects - Path Calculation (used for path-following tools) */
+DEF_DEG_OPCODE(GEOMETRY_PATH)
+
+/* Pose -------------------------------------------- */
+
+/* Init IK Trees, etc. */
+DEF_DEG_OPCODE(POSE_INIT)
+
+/* Free IK Trees + Compute Deform Matrices */
+DEF_DEG_OPCODE(POSE_DONE)
+
+/* IK/Spline Solvers */
+DEF_DEG_OPCODE(POSE_IK_SOLVER)
+DEF_DEG_OPCODE(POSE_SPLINE_IK_SOLVER)
+
+/* Bone -------------------------------------------- */
+
+/* Bone local transforms - Entrypoint */
+DEF_DEG_OPCODE(BONE_LOCAL)
+
+/* Pose-space conversion (includes parent + restpose) */
+DEF_DEG_OPCODE(BONE_POSE_PARENT)
+
+/* Constraints */
+DEF_DEG_OPCODE(BONE_CONSTRAINTS)
+//DEF_DEG_OPCODE(BONE_CONSTRAINTS_INIT)
+//DEF_DEG_OPCODE(BONE_CONSTRAINT)
+//DEF_DEG_OPCODE(BONE_CONSTRAINTS_DONE)
+
+/* Bone transforms are ready
+ * - "READY" This (internal) noop is used to signal that all pre-IK operations are done.
+ * Its role is to help mediate situations where cyclic relations may otherwise form
+ * (i.e. one bone in chain targetting another in same chain)
+ * - "DONE" This noop is used to signal that the bone's final pose transform can be read by others
+ */
+// TODO: deform mats could get calculated in the final_transform ops...
+DEF_DEG_OPCODE(BONE_READY)
+DEF_DEG_OPCODE(BONE_DONE)
+
+/* Particles --------------------------------------- */
+
+/* XXX: placeholder - Particle System eval */
+DEF_DEG_OPCODE(PSYS_EVAL)
diff --git a/source/blender/depsgraph/intern/depsnode_operation.cc b/source/blender/depsgraph/intern/depsnode_operation.cc
new file mode 100644
index 00000000000..6aeb163356b
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode_operation.cc
@@ -0,0 +1,104 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsnode_operation.cc
+ * \ingroup depsgraph
+ */
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+} /* extern "C" */
+
+#include "depsnode_operation.h" /* own include */
+#include "depsnode_component.h"
+#include "depsgraph.h"
+#include "depsgraph_intern.h"
+
+/* ******************************************************************* */
+/* OpNode Identifiers Array - Exported to other depsgraph files too... */
+
+/* identifiers for operations */
+const char *DEG_OPNAMES[] = {
+#define DEF_DEG_OPCODE(label) #label,
+#include "depsnode_opcodes.h"
+#undef DEF_DEG_OPCODE
+
+ "<Invalid>"
+};
+
+/* *********** */
+/* Inner Nodes */
+
+OperationDepsNode::OperationDepsNode() :
+ eval_priority(0.0f),
+ flag(0)
+{
+}
+
+OperationDepsNode::~OperationDepsNode()
+{
+}
+
+string OperationDepsNode::identifier() const
+{
+ BLI_assert((opcode > 0) && (opcode < ARRAY_SIZE(DEG_OPNAMES)));
+ return string(DEG_OPNAMES[opcode]) + "(" + name + ")";
+}
+
+/* Full node identifier, including owner name.
+ * used for logging and debug prints.
+ */
+string OperationDepsNode::full_identifier() const
+{
+ string owner_str = "";
+ if (owner->type == DEPSNODE_TYPE_BONE) {
+ owner_str = owner->owner->name + "." + owner->name;
+ }
+ else {
+ owner_str = owner->owner->name;
+ }
+ return owner_str + "." + identifier();
+}
+
+void OperationDepsNode::tag_update(Depsgraph *graph)
+{
+ if (flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ return;
+ }
+ /* Tag for update, but also note that this was the source of an update. */
+ flag |= (DEPSOP_FLAG_NEEDS_UPDATE | DEPSOP_FLAG_DIRECTLY_MODIFIED);
+ graph->add_entry_tag(this);
+}
+
+DEG_DEPSNODE_DEFINE(OperationDepsNode, DEPSNODE_TYPE_OPERATION, "Operation");
+static DepsNodeFactoryImpl<OperationDepsNode> DNTI_OPERATION;
+
+void DEG_register_operation_depsnodes()
+{
+ DEG_register_node_typeinfo(&DNTI_OPERATION);
+}
diff --git a/source/blender/depsgraph/intern/depsnode_operation.h b/source/blender/depsgraph/intern/depsnode_operation.h
new file mode 100644
index 00000000000..1119e10805d
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode_operation.h
@@ -0,0 +1,90 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsnode_operation.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSNODE_OPERATION_H__
+#define __DEPSNODE_OPERATION_H__
+
+#include "depsnode.h"
+
+struct ID;
+
+struct Depsgraph;
+struct DepsgraphCopyContext;
+
+/* Flags for Depsgraph Nodes */
+typedef enum eDepsOperation_Flag {
+ /* node needs to be updated */
+ DEPSOP_FLAG_NEEDS_UPDATE = (1 << 0),
+
+ /* node was directly modified, causing need for update */
+ /* XXX: intention is to make it easier to tell when we just need to take subgraphs */
+ DEPSOP_FLAG_DIRECTLY_MODIFIED = (1 << 1),
+
+ /* Operation is evaluated using CPython; has GIL and security implications... */
+ DEPSOP_FLAG_USES_PYTHON = (1 << 2),
+} eDepsOperation_Flag;
+
+/* Atomic Operation - Base type for all operations */
+struct OperationDepsNode : public DepsNode {
+
+
+ OperationDepsNode();
+ ~OperationDepsNode();
+
+ string identifier() const;
+ string full_identifier() const;
+
+ void tag_update(Depsgraph *graph);
+
+ bool is_noop() const { return (bool)evaluate == false; }
+
+ OperationDepsNode *get_entry_operation() { return this; }
+ OperationDepsNode *get_exit_operation() { return this; }
+
+ ComponentDepsNode *owner; /* component that contains the operation */
+
+ DepsEvalOperationCb evaluate; /* callback for operation */
+
+
+ uint32_t num_links_pending; /* how many inlinks are we still waiting on before we can be evaluated... */
+ float eval_priority;
+ bool scheduled;
+
+ short optype; /* (eDepsOperation_Type) stage of evaluation */
+ int opcode; /* (eDepsOperation_Code) identifier for the operation being performed */
+
+ int flag; /* (eDepsOperation_Flag) extra settings affecting evaluation */
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+void DEG_register_operation_depsnodes();
+
+#endif /* __DEPSNODE_OPERATION_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_cycle.cc b/source/blender/depsgraph/util/depsgraph_util_cycle.cc
new file mode 100644
index 00000000000..5eae8c087ad
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_cycle.cc
@@ -0,0 +1,140 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_cycle.cc
+ * \ingroup depsgraph
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <stack>
+
+extern "C" {
+#include "BLI_utildefines.h"
+
+#include "DNA_ID.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+}
+
+#include "depsgraph_util_cycle.h"
+#include "depsgraph.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+
+struct StackEntry {
+ OperationDepsNode *node;
+ StackEntry *from;
+ DepsRelation *via_relation;
+};
+
+void deg_graph_detect_cycles(Depsgraph *graph)
+{
+ /* Not is not visited at all during traversal. */
+ const int NODE_NOT_VISITED = 0;
+ /* Node has been visited during traversal and not in current stack. */
+ const int NODE_VISITED = 1;
+ /* Node has been visited during traversal and is in current stack. */
+ const int NODE_IN_STACK = 2;
+
+ std::stack<StackEntry> traversal_stack;
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ bool has_inlinks = false;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
+ it_rel != node->inlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ has_inlinks = true;
+ }
+ }
+ if (has_inlinks == false) {
+ StackEntry entry;
+ entry.node = node;
+ entry.from = NULL;
+ entry.via_relation = NULL;
+ traversal_stack.push(entry);
+ node->done = NODE_IN_STACK;
+ }
+ else {
+ node->done = NODE_NOT_VISITED;
+ }
+ }
+
+ while (!traversal_stack.empty()) {
+ StackEntry &entry = traversal_stack.top();
+ OperationDepsNode *node = entry.node;
+ bool all_child_traversed = true;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
+ it_rel != node->outlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ if (to->done == NODE_IN_STACK) {
+ printf("Dependency cycle detected:\n");
+ printf(" '%s' depends on '%s' through '%s'\n",
+ to->full_identifier().c_str(),
+ node->full_identifier().c_str(),
+ rel->name);
+
+ StackEntry *current = &entry;
+ while (current->node != to) {
+ BLI_assert(current != NULL);
+ printf(" '%s' depends on '%s' through '%s'\n",
+ current->node->full_identifier().c_str(),
+ current->from->node->full_identifier().c_str(),
+ current->via_relation->name);
+ current = current->from;
+ }
+ /* TODO(sergey): So called roussian rlette cycle solver. */
+ rel->flag |= DEPSREL_FLAG_CYCLIC;
+ }
+ else if (to->done == NODE_NOT_VISITED) {
+ StackEntry new_entry;
+ new_entry.node = to;
+ new_entry.from = &entry;
+ new_entry.via_relation = rel;
+ traversal_stack.push(new_entry);
+ to->done = NODE_IN_STACK;
+ all_child_traversed = false;
+ break;
+ }
+ }
+ }
+ if (all_child_traversed) {
+ node->done = NODE_VISITED;
+ traversal_stack.pop();
+ }
+ }
+}
diff --git a/source/blender/depsgraph/util/depsgraph_util_cycle.h b/source/blender/depsgraph/util/depsgraph_util_cycle.h
new file mode 100644
index 00000000000..fac38b61057
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_cycle.h
@@ -0,0 +1,37 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_cycle.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_UTIL_CYCLE_H__
+#define __DEPSGRAPH_UTIL_CYCLE_H__
+
+struct Depsgraph;
+
+void deg_graph_detect_cycles(Depsgraph *graph);
+
+#endif /* __DEPSGRAPH_UTIL_CYCLE_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_function.h b/source/blender/depsgraph/util/depsgraph_util_function.h
new file mode 100644
index 00000000000..a4301833408
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_function.h
@@ -0,0 +1,112 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s):
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_function.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_UTIL_FUNCTION_H__
+#define __DEPSGRAPH_UTIL_FUNCTION_H__
+
+#if (__cplusplus > 199711L)
+
+#include <functional>
+
+using std::function;
+using namespace std::placeholders;
+#define function_bind std::bind
+
+#elif defined(HAVE_BOOST_FUNCTION_BINDINGS)
+
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+
+using boost::function;
+#define function_bind boost::bind
+
+#else
+
+#pragma message("No available function binding implementation. Using stub instead, disabling new depsgraph")
+
+#ifndef WITH_LEGACY_DEPSGRAPH
+# error "Unable to build new depsgraph and legacy one is disabled."
+#endif
+
+#define DISABLE_NEW_DEPSGRAPH
+
+#include <cstdlib>
+
+template<typename T>
+class function {
+public:
+ function() {};
+ function(void *) {}
+ operator bool() const { return false; }
+ bool operator== (void *) { return false; }
+
+ template<typename T1>
+ void operator() (T1) {
+ BLI_assert(!"Should not be used");
+ }
+};
+
+class Wrap {
+public:
+ Wrap() {}
+ template <typename T>
+ Wrap(T /*arg*/) {}
+};
+
+template <typename T>
+void *function_bind(T func,
+ Wrap arg1 = Wrap(),
+ Wrap arg2 = Wrap(),
+ Wrap arg3 = Wrap(),
+ Wrap arg4 = Wrap(),
+ Wrap arg5 = Wrap(),
+ Wrap arg6 = Wrap(),
+ Wrap arg7 = Wrap())
+{
+ BLI_assert(!"Should not be used");
+ (void)func;
+ (void)arg1;
+ (void)arg2;
+ (void)arg3;
+ (void)arg4;
+ (void)arg5;
+ (void)arg6;
+ (void)arg7;
+ return NULL;
+}
+
+#define _1 Wrap()
+#define _2 Wrap()
+#define _3 Wrap()
+#define _4 Wrap()
+
+#endif
+
+#endif /* __DEPSGRAPH_UTIL_FUNCTION_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_hash.h b/source/blender/depsgraph/util/depsgraph_util_hash.h
new file mode 100644
index 00000000000..bc75627a026
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_hash.h
@@ -0,0 +1,72 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Brecht van Lommel
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_hash.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_UTIL_HASH_H__
+#define __DEPSGRAPH_UTIL_HASH_H__
+
+#if defined(DEG_NO_UNORDERED_MAP)
+# define DEG_HASH_NAMESPACE_BEGIN
+# define DEG_HASH_NAMESPACE_END
+#endif
+
+#if defined(DEG_TR1_UNORDERED_MAP)
+# include <tr1/unordered_map>
+# define DEG_HASH_NAMESPACE_BEGIN namespace std { namespace tr1 {
+# define DEG_HASH_NAMESPACE_END } }
+using std::tr1::hash;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP)
+# include <unordered_map>
+# define DEG_HASH_NAMESPACE_BEGIN namespace std {
+# define DEG_HASH_NAMESPACE_END }
+using std::hash;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+# include <unordered_map>
+# define DEG_HASH_NAMESPACE_BEGIN namespace std { namespace tr1 {
+# define DEG_HASH_NAMESPACE_END } }
+using std::tr1::hash;
+#endif
+
+#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
+ !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
+# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
+ DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
+#endif
+
+/* XXX this might require 2 different variants for sizeof(size_t) (32 vs 64 bit) */
+inline size_t hash_combine(size_t hash_a, size_t hash_b)
+{
+ return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
+}
+
+#endif /* __DEPSGRAPH_UTIL_HASH_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_map.h b/source/blender/depsgraph/util/depsgraph_util_map.h
new file mode 100644
index 00000000000..0eae1d79e34
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_map.h
@@ -0,0 +1,67 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Brecht van Lommel
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_map.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_UTIL_MAP_H__
+#define __DEPSGRAPH_UTIL_MAP_H__
+
+#include <map>
+
+#include "depsgraph_util_hash.h"
+
+using std::map;
+using std::pair;
+
+#if defined(DEG_NO_UNORDERED_MAP)
+# include <map>
+typedef std::map unordered_map;
+#endif
+
+#if defined(DEG_TR1_UNORDERED_MAP)
+# include <tr1/unordered_map>
+using std::tr1::unordered_map;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP)
+# include <unordered_map>
+using std::unordered_map;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+# include <unordered_map>
+using std::tr1::unordered_map;
+#endif
+
+#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
+ !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
+# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
+ DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
+#endif
+
+#endif /* __DEPSGRAPH_UTIL_MAP_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_pchanmap.cc b/source/blender/depsgraph/util/depsgraph_util_pchanmap.cc
new file mode 100644
index 00000000000..80b37ec622d
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_pchanmap.cc
@@ -0,0 +1,136 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_pchanmap.cc
+ * \ingroup depsgraph
+ */
+
+#include "depsgraph_util_pchanmap.h"
+
+#include <stdio.h>
+#include <string.h>
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+}
+
+static void free_rootpchanmap_valueset(void *val)
+{
+ /* Just need to free the set itself - the names stored are all references. */
+ GSet *values = (GSet *)val;
+ BLI_gset_free(values, NULL);
+}
+
+RootPChanMap::RootPChanMap()
+{
+ /* Just create empty map. */
+ m_map = BLI_ghash_str_new("RootPChanMap");
+}
+
+RootPChanMap::~RootPChanMap()
+{
+ /* Free the map, and all the value sets. */
+ BLI_ghash_free(m_map, NULL, free_rootpchanmap_valueset);
+}
+
+/* Debug contents of map */
+void RootPChanMap::print_debug()
+{
+ GHashIterator it1;
+ GSetIterator it2;
+
+ printf("Root PChan Map:\n");
+ GHASH_ITER(it1, m_map) {
+ const char *item = (const char *)BLI_ghashIterator_getKey(&it1);
+ GSet *values = (GSet *)BLI_ghashIterator_getValue(&it1);
+
+ printf(" %s : { ", item);
+ GSET_ITER(it2, values) {
+ const char *val = (const char *)BLI_gsetIterator_getKey(&it2);
+ printf("%s, ", val);
+ }
+ printf("}\n");
+ }
+}
+
+/* Add a mapping. */
+void RootPChanMap::add_bone(const char *bone, const char *root)
+{
+ if (BLI_ghash_haskey(m_map, bone)) {
+ /* Add new entry, but only add the root if it doesn't already
+ * exist in there.
+ */
+ GSet *values = (GSet *)BLI_ghash_lookup(m_map, bone);
+ BLI_gset_add(values, (void *)root);
+ }
+ else {
+ /* Create new set and mapping. */
+ GSet *values = BLI_gset_new(BLI_ghashutil_strhash_p,
+ BLI_ghashutil_strcmp,
+ "RootPChanMap Value Set");
+ BLI_ghash_insert(m_map, (void *)bone, (void *)values);
+
+ /* Add new entry now. */
+ BLI_gset_insert(values, (void *)root);
+ }
+}
+
+/* Check if there's a common root bone between two bones. */
+bool RootPChanMap::has_common_root(const char *bone1, const char *bone2)
+{
+ /* Ensure that both are in the map... */
+ if (BLI_ghash_haskey(m_map, bone1) == false) {
+ //fprintf("RootPChanMap: bone1 '%s' not found (%s => %s)\n", bone1, bone1, bone2);
+ //print_debug();
+ return false;
+ }
+
+ if (BLI_ghash_haskey(m_map, bone2) == false) {
+ //fprintf("RootPChanMap: bone2 '%s' not found (%s => %s)\n", bone2, bone1, bone2);
+ //print_debug();
+ return false;
+ }
+
+ GSet *bone1_roots = (GSet *)BLI_ghash_lookup(m_map, (void *)bone1);
+ GSet *bone2_roots = (GSet *)BLI_ghash_lookup(m_map, (void *)bone2);
+
+ GSetIterator it1, it2;
+ GSET_ITER(it1, bone1_roots) {
+ GSET_ITER(it2, bone2_roots) {
+ const char *v1 = (const char *)BLI_gsetIterator_getKey(&it1);
+ const char *v2 = (const char *)BLI_gsetIterator_getKey(&it2);
+
+ if (strcmp(v1, v2) == 0) {
+ //fprintf("RootPchanMap: %s in common for %s => %s\n", v1, bone1, bone2);
+ return true;
+ }
+ }
+ }
+
+ //fprintf("RootPChanMap: No common root found (%s => %s)\n", bone1, bone2);
+ return false;
+}
diff --git a/source/blender/depsgraph/util/depsgraph_util_pchanmap.h b/source/blender/depsgraph/util/depsgraph_util_pchanmap.h
new file mode 100644
index 00000000000..b7f4c495933
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_pchanmap.h
@@ -0,0 +1,59 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_pchanmap.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_UTIL_PCHANMAP_H__
+#define __DEPSGRAPH_UTIL_PCHANMAP_H__
+
+struct RootPChanMap {
+ /* ctor and dtor - Create and free the internal map respectively. */
+ RootPChanMap();
+ ~RootPChanMap();
+
+ /* Debug contents of map. */
+ void print_debug();
+
+ /* Add a mapping. */
+ void add_bone(const char *bone, const char *root);
+
+ /* Check if there's a common root bone between two bones. */
+ bool has_common_root(const char *bone1, const char *bone2);
+
+private:
+ /* The actual map:
+ * - Keys are "strings" (const char *) - not dynamically allocated.
+ * - Values are "sets" (const char *) - not dynamically allocated.
+ *
+ * We don't use the C++ maps here, as it's more convenient to use
+ * Blender's GHash and be able to compare by-value instead of by-ref.
+ */
+ struct GHash *m_map;
+};
+
+#endif /* __DEPSGRAPH_UTIL_PCHANMAP_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_set.h b/source/blender/depsgraph/util/depsgraph_util_set.h
new file mode 100644
index 00000000000..008ec6b74ca
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_set.h
@@ -0,0 +1,66 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Brecht van Lommel
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_set.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_UTIL_SET_H__
+#define __DEPSGRAPH_UTIL_SET_H__
+
+#include <set>
+
+#include "depsgraph_util_hash.h"
+
+using std::set;
+
+#if defined(DEG_NO_UNORDERED_MAP)
+# include <set>
+typedef std::set unordered_set;
+#endif
+
+#if defined(DEG_TR1_UNORDERED_MAP)
+# include <tr1/unordered_set>
+using std::tr1::unordered_set;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP)
+# include <unordered_set>
+using std::unordered_set;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+# include <unordered_set>
+using std::tr1::unordered_set;
+#endif
+
+#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
+ !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
+# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
+ DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
+#endif
+
+#endif /* __DEPSGRAPH_UTIL_SET_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_transitive.cc b/source/blender/depsgraph/util/depsgraph_util_transitive.cc
new file mode 100644
index 00000000000..98192a9540f
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_transitive.cc
@@ -0,0 +1,139 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Lukas Toenne,
+ * Sergey Sharybin,
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_transitive.cc
+ * \ingroup depsgraph
+ */
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "DNA_ID.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+}
+
+#include "depsgraph_util_transitive.h"
+#include "depsgraph.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+
+/* -------------------------------------------------- */
+
+/* Performs a transitive reduction to remove redundant relations.
+ * http://en.wikipedia.org/wiki/Transitive_reduction
+ *
+ * XXX The current implementation is somewhat naive and has O(V*E) worst case
+ * runtime.
+ * A more optimized algorithm can be implemented later, e.g.
+ *
+ * http://www.sciencedirect.com/science/article/pii/0304397588900321/pdf?md5=3391e309b708b6f9cdedcd08f84f4afc&pid=1-s2.0-0304397588900321-main.pdf
+ *
+ * Care has to be taken to make sure the algorithm can handle the cyclic case
+ * too! (unless we can to prevent this case early on).
+ */
+
+enum {
+ OP_VISITED = 1,
+ OP_REACHABLE = 2,
+};
+
+static void deg_graph_tag_paths_recursive(DepsNode *node)
+{
+ if (node->done & OP_VISITED)
+ return;
+ node->done |= OP_VISITED;
+
+ for (OperationDepsNode::Relations::const_iterator it = node->inlinks.begin();
+ it != node->inlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+
+ deg_graph_tag_paths_recursive(rel->from);
+ /* Do this only in inlinks loop, so the target node does not get
+ * flagged.
+ */
+ rel->from->done |= OP_REACHABLE;
+ }
+}
+
+void deg_graph_transitive_reduction(Depsgraph *graph)
+{
+ for (Depsgraph::OperationNodes::const_iterator it_target = graph->operations.begin();
+ it_target != graph->operations.end();
+ ++it_target)
+ {
+ OperationDepsNode *target = *it_target;
+
+ /* Clear tags. */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ node->done = 0;
+ }
+
+ /* mark nodes from which we can reach the target
+ * start with children, so the target node and direct children are not
+ * flagged.
+ */
+ target->done |= OP_VISITED;
+ for (OperationDepsNode::Relations::const_iterator it = target->inlinks.begin();
+ it != target->inlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+
+ deg_graph_tag_paths_recursive(rel->from);
+ }
+
+ /* Eemove redundant paths to the target. */
+ for (DepsNode::Relations::const_iterator it_rel = target->inlinks.begin();
+ it_rel != target->inlinks.end();
+ )
+ {
+ DepsRelation *rel = *it_rel;
+ /* Increment in advance, so we can safely remove the relation. */
+ ++it_rel;
+
+ if (rel->from->type == DEPSNODE_TYPE_TIMESOURCE) {
+ /* HACK: time source nodes don't get "done" flag set/cleared. */
+ /* TODO: there will be other types in future, so iterators above
+ * need modifying.
+ */
+ }
+ else if (rel->from->done & OP_REACHABLE) {
+ OBJECT_GUARDED_DELETE(rel, DepsRelation);
+ }
+ }
+ }
+}
diff --git a/source/blender/depsgraph/util/depsgraph_util_transitive.h b/source/blender/depsgraph/util/depsgraph_util_transitive.h
new file mode 100644
index 00000000000..a80a1d783d7
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_transitive.h
@@ -0,0 +1,38 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Lukas Toenne
+ * Sergey Sharybin,
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/depsgraph_util_transitive.h
+ * \ingroup depsgraph
+ */
+
+#ifndef __DEPSGRAPH_UTIL_TRANSITIVE_H__
+#define __DEPSGRAPH_UTIL_TRANSITIVE_H__
+
+struct Depsgraph;
+
+void deg_graph_transitive_reduction(Depsgraph *graph);
+
+#endif /* __DEPSGRAPH_UTIL_TRANSITIVE_H__ */
diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt
index 084006ce277..ec9ae775ad0 100644
--- a/source/blender/editors/CMakeLists.txt
+++ b/source/blender/editors/CMakeLists.txt
@@ -23,6 +23,7 @@ if(WITH_BLENDER)
add_subdirectory(armature)
add_subdirectory(curve)
add_subdirectory(gpencil)
+ add_subdirectory(hair)
add_subdirectory(interface)
add_subdirectory(io)
add_subdirectory(mask)
diff --git a/source/blender/editors/SConscript b/source/blender/editors/SConscript
index 1ea2bc0e4ef..0ef04739e9f 100644
--- a/source/blender/editors/SConscript
+++ b/source/blender/editors/SConscript
@@ -41,6 +41,7 @@ SConscript(['datafiles/SConscript',
'object/SConscript',
'curve/SConscript',
'gpencil/SConscript',
+ 'hair/SConscript',
'physics/SConscript',
'render/SConscript',
'sound/SConscript',
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 37c40052275..10af5b84509 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -110,7 +110,7 @@ static void acf_generic_root_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUS
/* backdrop for top-level widgets (Scene and Object only) */
static void acf_generic_root_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
@@ -136,7 +136,7 @@ static void acf_generic_dataexpand_color(bAnimContext *UNUSED(ac), bAnimListElem
/* backdrop for data expanders under top-level Scene/Object */
static void acf_generic_dataexpand_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
float color[3];
@@ -177,7 +177,7 @@ static bool acf_show_channel_colors(bAnimContext *ac)
/* get backdrop color for generic channels */
static void acf_generic_channel_color(bAnimContext *ac, bAnimListElem *ale, float r_color[3])
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
bActionGroup *grp = NULL;
short indent = (acf->get_indent_level) ? acf->get_indent_level(ac, ale) : 0;
bool showGroupColors = acf_show_channel_colors(ac);
@@ -217,7 +217,7 @@ static void acf_generic_channel_color(bAnimContext *ac, bAnimListElem *ale, floa
/* backdrop for generic channels */
static void acf_generic_channel_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
float color[3];
@@ -269,7 +269,7 @@ static short acf_generic_indention_flexible(bAnimContext *UNUSED(ac), bAnimListE
/* basic offset for channels derived from indention */
static short acf_generic_basic_offset(bAnimContext *ac, bAnimListElem *ale)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
if (acf && acf->get_indent_level)
return acf->get_indent_level(ac, ale) * INDENT_STEP_SIZE;
@@ -409,7 +409,7 @@ static void acf_summary_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(al
/* backdrop for summary widget */
static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
float color[3];
@@ -790,7 +790,7 @@ static void acf_group_color(bAnimContext *ac, bAnimListElem *ale, float r_color[
/* backdrop for group widget */
static void acf_group_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
@@ -865,7 +865,11 @@ static int acf_group_setting_flag(bAnimContext *ac, eAnimChannel_Settings settin
case ACHANNEL_SETTING_MUTE: /* muted */
return AGRP_MUTED;
-
+
+ case ACHANNEL_SETTING_MOD_OFF: /* muted */
+ *neg = 1;
+ return AGRP_MODIFIERS_OFF;
+
case ACHANNEL_SETTING_PROTECT: /* protected */
return AGRP_PROTECTED;
@@ -983,6 +987,10 @@ static int acf_fcurve_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settin
case ACHANNEL_SETTING_VISIBLE: /* visibility - graph editor */
return FCURVE_VISIBLE;
+ case ACHANNEL_SETTING_MOD_OFF:
+ *neg = 1;
+ return FCURVE_MOD_OFF;
+
default: /* unsupported */
return 0;
}
@@ -1017,6 +1025,149 @@ static bAnimChannelType ACF_FCURVE =
acf_fcurve_setting_ptr /* pointer for setting */
};
+/* NLA Control FCurves Expander ----------------------- */
+
+/* get backdrop color for nla controls widget */
+static void acf_nla_controls_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), float r_color[3])
+{
+ // TODO: give this its own theme setting?
+ UI_GetThemeColorShade3fv(TH_GROUP, 55, r_color);
+}
+
+/* backdrop for nla controls expander widget */
+static void acf_nla_controls_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
+{
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ View2D *v2d = &ac->ar->v2d;
+ short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0;
+ short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
+ float color[3];
+
+ /* set backdrop drawing color */
+ acf->get_backdrop_color(ac, ale, color);
+ glColor3fv(color);
+
+ /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */
+ UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
+ UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 5);
+}
+
+/* name for nla controls expander entries */
+static void acf_nla_controls_name(bAnimListElem *UNUSED(ale), char *name)
+{
+ BLI_strncpy(name, IFACE_("NLA Strip Controls"), ANIM_CHAN_NAME_SIZE);
+}
+
+/* check if some setting exists for this channel */
+static bool acf_nla_controls_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting)
+{
+ /* for now, all settings are supported, though some are only conditionally */
+ switch (setting) {
+ /* supported */
+ case ACHANNEL_SETTING_EXPAND:
+ return true;
+
+ // TOOD: selected?
+
+ default: /* unsupported */
+ return false;
+ }
+}
+
+/* get the appropriate flag(s) for the setting when it is valid */
+static int acf_nla_controls_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg)
+{
+ /* clear extra return data first */
+ *neg = false;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ *neg = true;
+ return ADT_NLA_SKEYS_COLLAPSED;
+
+ default:
+ /* this shouldn't happen */
+ return 0;
+ }
+}
+
+/* get pointer to the setting */
+static void *acf_nla_controls_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings UNUSED(setting), short *type)
+{
+ AnimData *adt = (AnimData *)ale->data;
+
+ /* all flags are just in adt->flag for now... */
+ return GET_ACF_FLAG_PTR(adt->flag, type);
+}
+
+static int acf_nla_controls_icon(bAnimListElem *UNUSED(ale))
+{
+ return ICON_NLA;
+}
+
+/* NLA Control FCurves Expander type define */
+static bAnimChannelType ACF_NLACONTROLS =
+{
+ "NLA Controls Expander", /* type name */
+ ACHANNEL_ROLE_EXPANDER, /* role */
+
+ acf_nla_controls_color, /* backdrop color */
+ acf_nla_controls_backdrop, /* backdrop */
+ acf_generic_indention_0, /* indent level */
+ acf_generic_group_offset, /* offset */
+
+ acf_nla_controls_name, /* name */
+ NULL, /* name prop */
+ acf_nla_controls_icon, /* icon */
+
+ acf_nla_controls_setting_valid, /* has setting */
+ acf_nla_controls_setting_flag, /* flag for setting */
+ acf_nla_controls_setting_ptr /* pointer for setting */
+};
+
+
+/* NLA Control F-Curve -------------------------------- */
+
+/* name for nla control fcurve entries */
+static void acf_nla_curve_name(bAnimListElem *ale, char *name)
+{
+ NlaStrip *strip = ale->owner;
+ FCurve *fcu = ale->data;
+ PropertyRNA *prop;
+
+ /* try to get RNA property that this shortened path (relative to the strip) refers to */
+ prop = RNA_struct_type_find_property(&RNA_NlaStrip, fcu->rna_path);
+ if (prop) {
+ /* "name" of this strip displays the UI identifier + the name of the NlaStrip */
+ BLI_snprintf(name, 256, "%s (%s)", RNA_property_ui_name(prop), strip->name);
+ }
+ else {
+ /* unknown property... */
+ BLI_snprintf(name, 256, "%s[%d]", fcu->rna_path, fcu->array_index);
+ }
+}
+
+
+/* NLA Control F-Curve type define */
+static bAnimChannelType ACF_NLACURVE =
+{
+ "NLA Control F-Curve", /* type name */
+ ACHANNEL_ROLE_CHANNEL, /* role */
+
+ acf_generic_channel_color, /* backdrop color */
+ acf_generic_channel_backdrop, /* backdrop */
+ acf_generic_indention_1, /* indent level */
+ acf_generic_group_offset, /* offset */
+
+ acf_nla_curve_name, /* name */
+ acf_fcurve_name_prop, /* name prop */
+ NULL, /* icon */
+
+ acf_fcurve_setting_valid, /* has setting */
+ acf_fcurve_setting_flag, /* flag for setting */
+ acf_fcurve_setting_ptr /* pointer for setting */
+};
+
/* Object Action Expander ------------------------------------------- */
// TODO: just get this from RNA?
@@ -3063,7 +3214,7 @@ static void acf_nlaaction_color(bAnimContext *UNUSED(ac), bAnimListElem *ale, fl
/* backdrop for nla action channel */
static void acf_nlaaction_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
AnimData *adt = ale->adt;
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
@@ -3222,6 +3373,9 @@ static void ANIM_init_channel_typeinfo_data(void)
animchannelTypeInfo[type++] = &ACF_GROUP; /* Group */
animchannelTypeInfo[type++] = &ACF_FCURVE; /* F-Curve */
+ animchannelTypeInfo[type++] = &ACF_NLACONTROLS; /* NLA Control FCurve Expander */
+ animchannelTypeInfo[type++] = &ACF_NLACURVE; /* NLA Control FCurve Channel */
+
animchannelTypeInfo[type++] = &ACF_FILLACTD; /* Object Action Expander */
animchannelTypeInfo[type++] = &ACF_FILLDRIVERS; /* Drivers Expander */
@@ -3256,7 +3410,7 @@ static void ANIM_init_channel_typeinfo_data(void)
}
/* Get type info from given channel type */
-bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
+const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
{
/* santiy checks */
if (ale == NULL)
@@ -3277,7 +3431,7 @@ bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale)
/* Print debug info string for the given channel */
void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* print indents */
for (; indent_level > 0; indent_level--)
@@ -3309,7 +3463,7 @@ void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level)
*/
short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* 1) check that the setting exists for the current context */
if ((acf) && (!acf->has_setting || acf->has_setting(ac, ale, setting))) {
@@ -3382,7 +3536,7 @@ short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChanne
*/
void ANIM_channel_setting_set(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* 1) check that the setting exists for the current context */
if ((acf) && (!acf->has_setting || acf->has_setting(ac, ale, setting))) {
@@ -3430,10 +3584,26 @@ void ANIM_channel_setting_set(bAnimContext *ac, bAnimListElem *ale, eAnimChannel
// width of rename textboxes
#define RENAME_TEXT_WIDTH (5 * U.widget_unit)
+
+/* Helper - Check if a channel needs renaming */
+static bool achannel_is_being_renamed(const bAnimContext *ac, const bAnimChannelType *acf, size_t channel_index)
+{
+ if (acf->name_prop && ac->ads) {
+ /* if rename index matches, this channel is being renamed */
+ if (ac->ads->renameIndex == channel_index + 1) {
+ return true;
+ }
+ }
+
+ /* not being renamed */
+ return false;
+}
+
+
/* Draw the given channel */
-void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
+void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc, size_t channel_index)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
short selected, offset;
float y, ymid, ytext;
@@ -3491,7 +3661,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
if (ac->sl) {
if ((ac->spacetype == SPACE_IPO) && acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) {
/* for F-Curves, draw color-preview of curve behind checkbox */
- if (ale->type == ANIMTYPE_FCURVE) {
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
FCurve *fcu = (FCurve *)ale->data;
/* F-Curve channels need to have a special 'color code' box drawn, which is colored with whatever
@@ -3518,8 +3688,8 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
}
/* step 5) draw name ............................................... */
- /* TODO: when renaming, we might not want to draw this, especially if name happens to be longer than channel */
- if (acf->name) {
+ /* Don't draw this if renaming... */
+ if (acf->name && !achannel_is_being_renamed(ac, acf, channel_index)) {
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
char name[ANIM_CHAN_NAME_SIZE]; /* hopefully this will be enough! */
@@ -3537,7 +3707,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
UI_fontstyle_draw_simple(fstyle, offset, ytext, name);
/* draw red underline if channel is disabled */
- if ((ale->type == ANIMTYPE_FCURVE) && (ale->flag & FCURVE_DISABLED)) {
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE) && (ale->flag & FCURVE_DISABLED)) {
/* FIXME: replace hardcoded color here, and check on extents! */
glColor3f(1.0f, 0.0f, 0.0f);
glLineWidth(2.0);
@@ -3604,7 +3774,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
* (only only F-Curves really can support them for now)
* - slider should start before the toggles (if they're visible) to keep a clean line down the side
*/
- if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_SHAPEKEY)) {
+ if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE, ANIMTYPE_SHAPEKEY)) {
/* adjust offset */
offset += SLIDER_WIDTH;
}
@@ -3771,12 +3941,51 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
MEM_freeN(rna_path);
}
+/* callback for NLA Control Curve widget sliders - insert keyframes */
+static void achannel_setting_slider_nla_curve_cb(bContext *C, void *UNUSED(id_poin), void *fcu_poin)
+{
+ /* ID *id = (ID *)id_poin; */
+ FCurve *fcu = (FCurve *)fcu_poin;
+
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+
+ ReportList *reports = CTX_wm_reports(C);
+ Scene *scene = CTX_data_scene(C);
+ short flag = 0;
+ bool done = false;
+ float cfra;
+
+ /* get current frame - *no* NLA mapping should be done */
+ cfra = (float)CFRA;
+
+ /* get flags for keyframing */
+ flag = ANIM_get_keyframing_flags(scene, 1);
+
+ /* get pointer and property from the slider - this should all match up with the NlaStrip required... */
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ if (fcu && prop) {
+ /* set the special 'replace' flag if on a keyframe */
+ if (fcurve_frame_has_keyframe(fcu, cfra, 0))
+ flag |= INSERTKEY_REPLACE;
+
+ /* insert a keyframe for this F-Curve */
+ done = insert_keyframe_direct(reports, ptr, prop, fcu, cfra, flag);
+
+ if (done)
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ }
+}
+
/* Draw a widget for some setting */
-static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChannelType *acf,
+static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAnimChannelType *acf,
uiBlock *block, int xpos, int ypos, int setting)
{
short ptrsize, butType;
bool negflag;
+ bool usetoggle = true;
int flag, icon;
void *ptr;
const char *tooltip;
@@ -3793,12 +4002,18 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
//icon = ((enabled) ? ICON_VISIBLE_IPO_ON : ICON_VISIBLE_IPO_OFF);
icon = ICON_VISIBLE_IPO_OFF;
- if (ale->type == ANIMTYPE_FCURVE)
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE))
tooltip = TIP_("F-Curve is visible in Graph Editor for editing");
else
tooltip = TIP_("Channels are visible in Graph Editor for editing");
break;
-
+
+ case ACHANNEL_SETTING_MOD_OFF: /* modifiers disabled */
+ icon = ICON_MODIFIER;
+ usetoggle = false;
+ tooltip = TIP_("F-Curve modifiers are disabled");
+ break;
+
case ACHANNEL_SETTING_EXPAND: /* expanded triangle */
//icon = ((enabled) ? ICON_TRIA_DOWN : ICON_TRIA_RIGHT);
icon = ICON_TRIA_RIGHT;
@@ -3828,7 +4043,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
//icon = ((enabled) ? ICON_MUTE_IPO_ON : ICON_MUTE_IPO_OFF);
icon = ICON_MUTE_IPO_OFF;
- if (ale->type == ANIMTYPE_FCURVE) {
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
tooltip = TIP_("Does F-Curve contribute to result");
}
else if ((ac) && (ac->spacetype == SPACE_NLA) && (ale->type != ANIMTYPE_NLATRACK)) {
@@ -3859,11 +4074,18 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
}
/* type of button */
- if (negflag)
- butType = UI_BTYPE_ICON_TOGGLE_N;
- else
- butType = UI_BTYPE_ICON_TOGGLE;
-
+ if (usetoggle) {
+ if (negflag)
+ butType = UI_BTYPE_ICON_TOGGLE_N;
+ else
+ butType = UI_BTYPE_ICON_TOGGLE;
+ }
+ else {
+ if (negflag)
+ butType = UI_BTYPE_TOGGLE_N;
+ else
+ butType = UI_BTYPE_TOGGLE;
+ }
/* draw button for setting */
if (ptr && flag) {
switch (ptrsize) {
@@ -3891,6 +4113,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
case ACHANNEL_SETTING_PROTECT: /* General - protection flags */
case ACHANNEL_SETTING_MUTE: /* General - muting flags */
case ACHANNEL_SETTING_PINNED: /* NLA Actions - 'map/nomap' */
+ case ACHANNEL_SETTING_MOD_OFF:
UI_but_funcN_set(but, achannel_setting_flush_widget_cb, MEM_dupallocN(ale), SET_INT_IN_POINTER(setting));
break;
@@ -3912,7 +4135,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
/* Draw UI widgets the given channel */
void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListElem *ale, uiBlock *block, float yminc, float ymaxc, size_t channel_index)
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
View2D *v2d = &ac->ar->v2d;
float y, ymid /*, ytext*/;
short offset;
@@ -3991,36 +4214,32 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
}
/* step 4) draw text - check if renaming widget is in use... */
- if (acf->name_prop && ac->ads) {
- float channel_height = ymaxc - yminc;
+ if (achannel_is_being_renamed(ac, acf, channel_index)) {
+ PointerRNA ptr = {{NULL}};
+ PropertyRNA *prop = NULL;
- /* if rename index matches, add widget for this */
- if (ac->ads->renameIndex == channel_index + 1) {
- PointerRNA ptr = {{NULL}};
- PropertyRNA *prop = NULL;
+ /* draw renaming widget if we can get RNA pointer for it
+ * NOTE: property may only be available in some cases, even if we have
+ * a callback available (e.g. broken F-Curve rename)
+ */
+ if (acf->name_prop(ale, &ptr, &prop)) {
+ const float channel_height = ymaxc - yminc;
+ uiBut *but;
- /* draw renaming widget if we can get RNA pointer for it
- * NOTE: property may only be available in some cases, even if we have
- * a callback available (e.g. broken F-Curve rename)
- */
- if (acf->name_prop(ale, &ptr, &prop)) {
- uiBut *but;
-
- UI_block_emboss_set(block, UI_EMBOSS);
-
- but = uiDefButR(block, UI_BTYPE_TEXT, 1, "", offset + 3, yminc, RENAME_TEXT_WIDTH, channel_height,
- &ptr, RNA_property_identifier(prop), -1, 0, 0, -1, -1, NULL);
-
- /* copy what outliner does here, see outliner_buttons */
- if (UI_but_active_only(C, ac->ar, block, but) == false) {
- ac->ads->renameIndex = 0;
-
- /* send notifiers */
- WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_RENAME, NULL);
- }
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ but = uiDefButR(block, UI_BTYPE_TEXT, 1, "", offset + 3, yminc, RENAME_TEXT_WIDTH, channel_height,
+ &ptr, RNA_property_identifier(prop), -1, 0, 0, -1, -1, NULL);
+
+ /* copy what outliner does here, see outliner_buttons */
+ if (UI_but_active_only(C, ac->ar, block, but) == false) {
+ ac->ads->renameIndex = 0;
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ /* send notifiers */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_RENAME, NULL);
}
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
}
}
@@ -4062,7 +4281,13 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
offset += ICON_WIDTH;
draw_setting_widget(ac, ale, acf, block, (int)v2d->cur.xmax - offset, ymid, ACHANNEL_SETTING_MUTE);
}
-
+
+ /* modifiers disable */
+ if (acf->has_setting(ac, ale, ACHANNEL_SETTING_MOD_OFF)) {
+ offset += ICON_WIDTH;
+ draw_setting_widget(ac, ale, acf, block, (int)v2d->cur.xmax - offset, ymid, ACHANNEL_SETTING_MOD_OFF);
+ }
+
/* ----------- */
/* pinned... */
@@ -4097,7 +4322,7 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
* and wouldn't be able to auto-keyframe...
* - slider should start before the toggles (if they're visible) to keep a clean line down the side
*/
- if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_SHAPEKEY)) {
+ if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE, ANIMTYPE_SHAPEKEY)) {
/* adjust offset */
// TODO: make slider width dynamic, so that they can be easier to use when the view is wide enough
offset += SLIDER_WIDTH;
@@ -4105,7 +4330,28 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
/* need backdrop behind sliders... */
UI_block_emboss_set(block, UI_EMBOSS);
- if (ale->id) { /* Slider using RNA Access -------------------- */
+ if (ale->owner) { /* Slider using custom RNA Access ---------- */
+ if (ale->type == ANIMTYPE_NLACURVE) {
+ NlaStrip *strip = (NlaStrip *)ale->owner;
+ FCurve *fcu = (FCurve *)ale->data;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ /* create RNA pointers */
+ RNA_pointer_create(ale->id, &RNA_NlaStrip, strip, &ptr);
+ prop = RNA_struct_find_property(&ptr, fcu->rna_path);
+
+ /* create property slider */
+ if (prop) {
+ uiBut *but;
+
+ /* create the slider button, and assign relevant callback to ensure keyframes are inserted... */
+ but = uiDefAutoButR(block, &ptr, prop, fcu->array_index, "", ICON_NONE, (int)v2d->cur.xmax - offset, ymid, SLIDER_WIDTH, (int)ymaxc - yminc);
+ UI_but_func_set(but, achannel_setting_slider_nla_curve_cb, ale->id, ale->data);
+ }
+ }
+ }
+ else if (ale->id) { /* Slider using RNA Access --------------- */
PointerRNA id_ptr, ptr;
PropertyRNA *prop;
char *rna_path = NULL;
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index d8ad6506186..d08a32c6e6b 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -34,6 +34,7 @@
#include "MEM_guardedalloc.h"
+#include "BKE_depsgraph.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
@@ -101,6 +102,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
break;
}
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)ale->data;
@@ -157,6 +159,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
break;
}
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)channel_data;
fcu->flag |= FCURVE_ACTIVE;
@@ -255,6 +258,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
sel = ACHANNEL_SETFLAG_CLEAR;
break;
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
if (ale->flag & FCURVE_SELECTED)
sel = ACHANNEL_SETFLAG_CLEAR;
break;
@@ -339,6 +343,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
break;
}
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)ale->data;
@@ -444,7 +449,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
return;
}
else {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale_setting);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale_setting);
if (acf == NULL) {
printf("ERROR: no channel info for the changed channel\n");
@@ -473,7 +478,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
{
/* go backwards in the list, until the highest-ranking element (by indention has been covered) */
for (ale = match->prev; ale; ale = ale->prev) {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
int level;
/* if no channel info was found, skip, since this type might not have any useful info */
@@ -517,7 +522,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
{
/* go forwards in the list, until the lowest-ranking element (by indention has been covered) */
for (ale = match->next; ale; ale = ale->next) {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
int level;
/* if no channel info was found, skip, since this type might not have any useful info */
@@ -847,6 +852,7 @@ static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *sr
break;
}
case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)channel;
@@ -1191,6 +1197,40 @@ static void rearrange_action_channels(bAnimContext *ac, bAction *act, eRearrange
/* ------------------- */
+static void rearrange_nla_control_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
+{
+ ListBase anim_data_visible = {NULL, NULL};
+
+ NlaTrack *nlt;
+ NlaStrip *strip;
+
+ /* get rearranging function */
+ AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
+
+ if (rearrange_func == NULL)
+ return;
+
+ /* skip if these curves aren't being shown */
+ if (adt->flag & ADT_NLA_SKEYS_COLLAPSED)
+ return;
+
+ /* Filter visible data. */
+ rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLACURVE);
+
+ /* we cannot rearrange between strips, but within each strip, we can rearrange those curves */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ rearrange_animchannel_islands(&strip->fcurves, rearrange_func, mode, ANIMTYPE_NLACURVE,
+ &anim_data_visible);
+ }
+ }
+
+ /* free temp data */
+ BLI_freelistN(&anim_data_visible);
+}
+
+/* ------------------- */
+
static void rearrange_gpencil_channels(bAnimContext *ac, eRearrangeAnimChan_Mode mode)
{
ListBase anim_data = {NULL, NULL};
@@ -1278,13 +1318,29 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
rearrange_driver_channels(&ac, adt, mode);
break;
+ case ANIMCONT_ACTION: /* Single Action only... */
case ANIMCONT_SHAPEKEY: // DOUBLE CHECK ME...
- default: /* some collection of actions */
+ {
if (adt->action)
rearrange_action_channels(&ac, adt->action, mode);
else if (G.debug & G_DEBUG)
printf("Animdata has no action\n");
break;
+ }
+
+ default: /* DopeSheet/Graph Editor - Some Actions + NLA Control Curves */
+ {
+ /* NLA Control Curves */
+ if (adt->nla_tracks.first)
+ rearrange_nla_control_channels(&ac, adt, mode);
+
+ /* Action */
+ if (adt->action)
+ rearrange_action_channels(&ac, adt->action, mode);
+ else if (G.debug & G_DEBUG)
+ printf("Animdata has no action\n");
+ break;
+ }
}
}
@@ -1602,6 +1658,27 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
ANIM_fcurve_delete_from_animdata(&ac, adt, fcu);
break;
}
+ case ANIMTYPE_NLACURVE:
+ {
+ /* NLA Control Curve - Deleting it should disable the corresponding setting... */
+ NlaStrip *strip = (NlaStrip *)ale->owner;
+ FCurve *fcu = (FCurve *)ale->data;
+
+ if (STREQ(fcu->rna_path, "strip_time")) {
+ strip->flag &= ~NLASTRIP_FLAG_USR_TIME;
+ }
+ else if (STREQ(fcu->rna_path, "influence")) {
+ strip->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE;
+ }
+ else {
+ printf("ERROR: Trying to delete NLA Control Curve for unknown property '%s'\n", fcu->rna_path);
+ }
+
+ /* unlink and free the F-Curve */
+ BLI_remlink(&strip->fcurves, fcu);
+ free_fcurve(fcu);
+ break;
+ }
case ANIMTYPE_GPLAYER:
{
/* Grease Pencil layer */
@@ -1631,7 +1708,8 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-
+ DAG_relations_tag_update(CTX_data_main(C));
+
return OPERATOR_FINISHED;
}
@@ -2041,7 +2119,7 @@ static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op))
/* remove AnimData? */
if (action_empty && nla_empty && drivers_empty) {
- BKE_free_animdata(id);
+ BKE_animdata_free(id);
}
}
@@ -2420,12 +2498,13 @@ static void ANIM_OT_channels_select_border(wmOperatorType *ot)
/* ******************* Rename Operator ***************************** */
/* Allow renaming some channels by clicking on them */
-static void rename_anim_channels(bAnimContext *ac, int channel_index)
+static bool rename_anim_channels(bAnimContext *ac, int channel_index)
{
ListBase anim_data = {NULL, NULL};
- bAnimChannelType *acf;
+ const bAnimChannelType *acf;
bAnimListElem *ale;
int filter;
+ bool success = false;
/* get the channel that was clicked on */
/* filter channels */
@@ -2440,7 +2519,7 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", channel_index);
ANIM_animdata_freelist(&anim_data);
- return;
+ return false;
}
/* check that channel can be renamed */
@@ -2460,6 +2539,7 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
*/
if (ac->ads) {
ac->ads->renameIndex = channel_index + 1;
+ success = true;
}
}
}
@@ -2467,22 +2547,18 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
/* free temp data and tag for refresh */
ANIM_animdata_freelist(&anim_data);
ED_region_tag_redraw(ac->ar);
+ return success;
}
-static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static int animchannels_channel_get(bAnimContext *ac, const int mval[2])
{
- bAnimContext ac;
ARegion *ar;
View2D *v2d;
int channel_index;
float x, y;
- /* get editor data */
- if (ANIM_animdata_get_context(C, &ac) == 0)
- return OPERATOR_CANCELLED;
-
/* get useful pointers from animation context data */
- ar = ac.ar;
+ ar = ac->ar;
v2d = &ar->v2d;
/* figure out which channel user clicked in
@@ -2490,20 +2566,36 @@ static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const
* so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
* ACHANNEL_HEIGHT_HALF.
*/
- UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y);
+ UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
- if (ac.datatype == ANIMCONT_NLA) {
- SpaceNla *snla = (SpaceNla *)ac.sl;
+ if (ac->datatype == ANIMCONT_NLA) {
+ SpaceNla *snla = (SpaceNla *)ac->sl;
UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index);
}
else {
UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
}
-
+
+ return channel_index;
+}
+
+static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ bAnimContext ac;
+ int channel_index;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ channel_index = animchannels_channel_get(&ac, event->mval);
+
/* handle click */
- rename_anim_channels(&ac, channel_index);
-
- return OPERATOR_FINISHED;
+ if (rename_anim_channels(&ac, channel_index))
+ return OPERATOR_FINISHED;
+ else
+ /* allow event to be handled by selectall operator */
+ return OPERATOR_PASS_THROUGH;
}
static void ANIM_OT_channels_rename(wmOperatorType *ot)
@@ -2727,7 +2819,8 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
}
- case ANIMTYPE_FCURVE:
+ case ANIMTYPE_FCURVE:
+ case ANIMTYPE_NLACURVE:
{
FCurve *fcu = (FCurve *)ale->data;
@@ -2744,7 +2837,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
/* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */
if (fcu->flag & FCURVE_SELECTED)
- ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
+ ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
@@ -2767,6 +2860,19 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
break;
}
+ case ANIMTYPE_NLACONTROLS:
+ {
+ AnimData *adt = (AnimData *)ale->data;
+
+ /* toggle expand
+ * - Although the triangle widget already allows this, since there's nothing else that can be done here now,
+ * let's just use it for easier expand/collapse for now
+ */
+ adt->flag ^= ADT_NLA_SKEYS_COLLAPSED;
+
+ notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
+ break;
+ }
case ANIMTYPE_GPDATABLOCK:
{
bGPdata *gpd = (bGPdata *)ale->data;
@@ -2918,6 +3024,105 @@ static void ANIM_OT_channels_click(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+static bool select_anim_channel_keys(bAnimContext *ac, int channel_index, bool extend)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+ bool success = false;
+ FCurve *fcu;
+ int i;
+
+ /* get the channel that was clicked on */
+ /* filter channels */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* get channel from index */
+ ale = BLI_findlink(&anim_data, channel_index);
+ if (ale == NULL) {
+ /* channel not found */
+ if (G.debug & G_DEBUG)
+ printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", channel_index);
+
+ ANIM_animdata_freelist(&anim_data);
+ return false;
+ }
+
+ fcu = (FCurve *)ale->key_data;
+ success = (fcu != NULL);
+
+ ANIM_animdata_freelist(&anim_data);
+
+ /* F-Curve may not have any keyframes */
+ if (fcu && fcu->bezt) {
+ BezTriple *bezt;
+
+ if (!extend) {
+ filter = (ANIMFILTER_DATA_VISIBLE);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu_inner = (FCurve *)ale->key_data;
+
+ if (fcu_inner) {
+ for (i = 0, bezt = fcu_inner->bezt; i < fcu_inner->totvert; i++, bezt++) {
+ bezt->f2 = bezt->f1 = bezt->f3 = 0;
+ }
+ }
+ }
+
+ ANIM_animdata_freelist(&anim_data);
+ }
+
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ bezt->f2 = bezt->f1 = bezt->f3 = SELECT;
+ }
+ }
+
+ /* free temp data and tag for refresh */
+ ED_region_tag_redraw(ac->ar);
+ return success;
+}
+
+static int animchannels_channel_select_keys_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ bAnimContext ac;
+ int channel_index;
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ channel_index = animchannels_channel_get(&ac, event->mval);
+
+ /* handle click */
+ if (select_anim_channel_keys(&ac, channel_index, extend)) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else
+ /* allow event to be handled by selectall operator */
+ return OPERATOR_PASS_THROUGH;
+}
+
+static void ANIM_OT_channel_select_keys(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Select Channel keyframes";
+ ot->idname = "ANIM_OT_channel_select_keys";
+ ot->description = "Select all keyframes of channel under mouse";
+
+ /* api callbacks */
+ ot->invoke = animchannels_channel_select_keys_invoke;
+ ot->poll = animedit_poll_channels_active;
+
+ prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
/* ************************************************************************** */
/* Operator Registration */
@@ -2927,8 +3132,9 @@ void ED_operatortypes_animchannels(void)
WM_operatortype_append(ANIM_OT_channels_select_border);
WM_operatortype_append(ANIM_OT_channels_click);
+ WM_operatortype_append(ANIM_OT_channel_select_keys);
WM_operatortype_append(ANIM_OT_channels_rename);
-
+
WM_operatortype_append(ANIM_OT_channels_find);
WM_operatortype_append(ANIM_OT_channels_setting_enable);
@@ -2968,7 +3174,9 @@ void ED_keymap_animchannels(wmKeyConfig *keyconf)
/* rename */
WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
-
+ WM_keymap_add_item(keymap, "ANIM_OT_channel_select_keys", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
+ RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channel_select_keys", LEFTMOUSE, KM_DBL_CLICK, KM_SHIFT, 0)->ptr, "extend", true);
+
/* find (i.e. a shortcut for setting the name filter) */
WM_keymap_add_item(keymap, "ANIM_OT_channels_find", FKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index eb57907c9ec..a38f5dbc8ea 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -73,8 +73,10 @@ void ANIM_list_elem_update(Scene *scene, bAnimListElem *ale)
/* tag AnimData for refresh so that other views will update in realtime with these changes */
adt = BKE_animdata_from_id(id);
- if (adt)
+ if (adt) {
adt->recalc |= ADT_RECALC_ANIM;
+ DAG_id_tag_update(id, OB_RECALC_TIME);
+ }
/* update data */
fcu = (ale->datatype == ALE_FCURVE) ? ale->key_data : NULL;
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 0e052279796..d5945425576 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -34,16 +34,25 @@
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_mask_types.h"
#include "BLI_math.h"
#include "BLI_timecode.h"
+#include "BLI_utildefines.h"
+#include "BLI_rect.h"
+#include "BLI_dlrbTree.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_nla.h"
+#include "BKE_mask.h"
#include "ED_anim_api.h"
#include "ED_keyframes_edit.h"
+#include "ED_keyframes_draw.h"
#include "RNA_access.h"
@@ -173,10 +182,14 @@ AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
if (G.is_rendering) return NULL;
/* handling depends on the type of animation-context we've got */
- if (ale)
- return ale->adt;
- else
- return NULL;
+ if (ale) {
+ /* NLA Control Curves occur on NLA strips, and shouldn't be subjected to this kind of mapping */
+ if (ale->type != ANIMTYPE_NLACURVE)
+ return ale->adt;
+ }
+
+ /* cannot handle... */
+ return NULL;
}
/* ------------------- */
@@ -262,19 +275,26 @@ short ANIM_get_normalization_flags(bAnimContext *ac)
return 0;
}
-static float normalzation_factor_get(FCurve *fcu, short flag)
+static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, float *r_offset)
{
- float factor = 1.0f;
+ float factor = 1.0f, offset = 0.0f;
if (flag & ANIM_UNITCONV_RESTORE) {
+ if (r_offset)
+ *r_offset = fcu->prev_offset;
+
return 1.0f / fcu->prev_norm_factor;
}
if (flag & ANIM_UNITCONV_NORMALIZE_FREEZE) {
+ if (r_offset)
+ *r_offset = fcu->prev_offset;
return fcu->prev_norm_factor;
}
if (G.moving & G_TRANSFORM_FCURVES) {
+ if (r_offset)
+ *r_offset = fcu->prev_offset;
return fcu->prev_norm_factor;
}
@@ -283,32 +303,65 @@ static float normalzation_factor_get(FCurve *fcu, short flag)
BezTriple *bezt;
int i;
float max_coord = -FLT_MAX;
+ float min_coord = FLT_MAX;
+ float range;
if (fcu->totvert < 1) {
return 1.0f;
}
- for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- max_coord = max_ff(max_coord, fabsf(bezt->vec[0][1]));
- max_coord = max_ff(max_coord, fabsf(bezt->vec[1][1]));
- max_coord = max_ff(max_coord, fabsf(bezt->vec[2][1]));
+ if (PRVRANGEON) {
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (IN_RANGE_INCL(bezt->vec[1][0], scene->r.psfra, scene->r.pefra)) {
+ max_coord = max_ff(max_coord, bezt->vec[0][1]);
+ max_coord = max_ff(max_coord, bezt->vec[1][1]);
+ max_coord = max_ff(max_coord, bezt->vec[2][1]);
+
+ min_coord = min_ff(min_coord, bezt->vec[0][1]);
+ min_coord = min_ff(min_coord, bezt->vec[1][1]);
+ min_coord = min_ff(min_coord, bezt->vec[2][1]);
+ }
+ }
+ }
+ else {
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ max_coord = max_ff(max_coord, bezt->vec[0][1]);
+ max_coord = max_ff(max_coord, bezt->vec[1][1]);
+ max_coord = max_ff(max_coord, bezt->vec[2][1]);
+
+ min_coord = min_ff(min_coord, bezt->vec[0][1]);
+ min_coord = min_ff(min_coord, bezt->vec[1][1]);
+ min_coord = min_ff(min_coord, bezt->vec[2][1]);
+ }
}
- if (max_coord > FLT_EPSILON) {
- factor = 1.0f / max_coord;
+ range = max_coord - min_coord;
+
+ if (range > FLT_EPSILON) {
+ factor = 2.0f / range;
}
+ offset = -min_coord - range / 2.0f;
}
+
+ if (r_offset) {
+ *r_offset = offset;
+ }
+
fcu->prev_norm_factor = factor;
+ fcu->prev_offset = offset;
return factor;
}
/* Get unit conversion factor for given ID + F-Curve */
-float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag)
+float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset)
{
if (flag & ANIM_UNITCONV_NORMALIZE) {
- return normalzation_factor_get(fcu, flag);
+ return normalization_factor_get(scene, fcu, flag, r_offset);
}
+ if (r_offset)
+ *r_offset = 0.0f;
+
/* sanity checks */
if (id && fcu && fcu->rna_path) {
PointerRNA ptr, id_ptr;
@@ -336,4 +389,137 @@ float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag
return 1.0f;
}
+static bool find_prev_next_keyframes(struct bContext *C, int *nextfra, int *prevfra)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Mask *mask = CTX_data_edit_mask(C);
+ bDopeSheet ads = {NULL};
+ DLRBT_Tree keys;
+ ActKeyColumn *aknext, *akprev;
+ float cfranext, cfraprev;
+ bool donenext = false, doneprev = false;
+ int nextcount = 0, prevcount = 0;
+
+ cfranext = cfraprev = (float)(CFRA);
+
+ /* init binarytree-list for getting keyframes */
+ BLI_dlrbTree_init(&keys);
+
+ /* seed up dummy dopesheet context with flags to perform necessary filtering */
+ if ((scene->flag & SCE_KEYS_NO_SELONLY) == 0) {
+ /* only selected channels are included */
+ ads.filterflag |= ADS_FILTER_ONLYSEL;
+ }
+
+ /* populate tree with keyframe nodes */
+ scene_to_keylist(&ads, scene, &keys, NULL);
+
+ if (ob)
+ ob_to_keylist(&ads, ob, &keys, NULL);
+
+ gpencil_to_keylist(&ads, gpd, &keys);
+
+ if (mask) {
+ MaskLayer *masklay = BKE_mask_layer_active(mask);
+ mask_to_keylist(&ads, masklay, &keys);
+ }
+
+ /* build linked-list for searching */
+ BLI_dlrbTree_linkedlist_sync(&keys);
+
+ /* find matching keyframe in the right direction */
+ do {
+ aknext = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfranext);
+
+ if (aknext) {
+ if (CFRA == (int)aknext->cfra) {
+ /* make this the new starting point for the search and ignore */
+ cfranext = aknext->cfra;
+ }
+ else {
+ /* this changes the frame, so set the frame and we're done */
+ if (++nextcount == U.view_frame_keyframes)
+ donenext = true;
+ }
+ cfranext = aknext->cfra;
+ }
+ } while ((aknext != NULL) && (donenext == false));
+
+ do {
+ akprev = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfraprev);
+
+ if (akprev) {
+ if (CFRA == (int)akprev->cfra) {
+ /* make this the new starting point for the search */
+ }
+ else {
+ /* this changes the frame, so set the frame and we're done */
+ if (++prevcount == U.view_frame_keyframes)
+ doneprev = true;
+ }
+ cfraprev = akprev->cfra;
+ }
+ } while ((akprev != NULL) && (doneprev == false));
+
+ /* free temp stuff */
+ BLI_dlrbTree_free(&keys);
+
+ /* any success? */
+ if (doneprev || donenext) {
+ if (doneprev)
+ *prevfra = cfraprev;
+ else
+ *prevfra = CFRA - (cfranext - CFRA);
+
+ if (donenext)
+ *nextfra = cfranext;
+ else
+ *nextfra = CFRA + (CFRA - cfraprev);
+
+ return true;
+ }
+
+ return false;
+}
+
+void ANIM_center_frame(struct bContext *C, int smooth_viewtx)
+{
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ float w = BLI_rctf_size_x(&ar->v2d.cur);
+ rctf newrct;
+ int nextfra, prevfra;
+
+ switch (U.view_frame_type) {
+ case ZOOM_FRAME_MODE_SECONDS:
+ newrct.xmax = scene->r.cfra + U.view_frame_seconds * FPS + 1;
+ newrct.xmin = scene->r.cfra - U.view_frame_seconds * FPS - 1;
+ newrct.ymax = ar->v2d.cur.ymax;
+ newrct.ymin = ar->v2d.cur.ymin;
+ break;
+
+ /* hardest case of all, look for all keyframes around frame and display those */
+ case ZOOM_FRAME_MODE_KEYFRAMES:
+ if (find_prev_next_keyframes(C, &nextfra, &prevfra)) {
+ newrct.xmax = nextfra;
+ newrct.xmin = prevfra;
+ newrct.ymax = ar->v2d.cur.ymax;
+ newrct.ymin = ar->v2d.cur.ymin;
+ break;
+ }
+ /* else drop through, keep range instead */
+
+ case ZOOM_FRAME_MODE_KEEP_RANGE:
+ default:
+ newrct.xmax = scene->r.cfra + (w / 2);
+ newrct.xmin = scene->r.cfra - (w / 2);
+ newrct.ymax = ar->v2d.cur.ymax;
+ newrct.ymin = ar->v2d.cur.ymin;
+ break;
+ }
+
+ UI_view2d_smooth_view(C, ar, &newrct, smooth_viewtx);
+}
/* *************************************************** */
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 09c8af8c1b4..7739848e0d4 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -424,6 +424,7 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
* - adtOk: line or block of code to execute for AnimData-blocks case (usually ANIMDATA_ADD_ANIMDATA)
* - nlaOk: line or block of code to execute for NLA tracks+strips case
* - driversOk: line or block of code to execute for Drivers case
+ * - nlaKeysOk: line or block of code for NLA Strip Keyframes case
* - keysOk: line or block of code for Keyframes case
*
* The checks for the various cases are as follows:
@@ -434,9 +435,10 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
* converted to a new NLA strip, and the filtering options allow this
* 2C) allow non-animated datablocks to be included so that datablocks can be added
* 3) drivers: include drivers from animdata block (for Drivers mode in Graph Editor)
- * 4) normal keyframes: only when there is an active action
+ * 4A) nla strip keyframes: these are the per-strip controls for time and influence
+ * 4B) normal keyframes: only when there is an active action
*/
-#define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, keysOk) \
+#define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, nlaKeysOk, keysOk) \
{ \
if ((id)->adt) { \
if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || !((id)->adt->flag & ADT_CURVES_NOT_VISIBLE)) { \
@@ -457,6 +459,9 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
} \
} \
else { \
+ if (ANIMDATA_HAS_NLA(id)) { \
+ nlaKeysOk \
+ } \
if (ANIMDATA_HAS_KEYS(id)) { \
keysOk \
} \
@@ -787,6 +792,16 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
ale->adt = BKE_animdata_from_id(data);
break;
}
+ case ANIMTYPE_NLACONTROLS:
+ {
+ AnimData *adt = (AnimData *)data;
+
+ ale->flag = adt->flag;
+
+ ale->key_data = NULL;
+ ale->datatype = ALE_NONE;
+ break;
+ }
case ANIMTYPE_GROUP:
{
bActionGroup *agrp = (bActionGroup *)data;
@@ -978,7 +993,7 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id
static bool skip_fcurve_with_name(bDopeSheet *ads, FCurve *fcu, ID *owner_id)
{
bAnimListElem ale_dummy = {NULL};
- bAnimChannelType *acf;
+ const bAnimChannelType *acf;
/* create a dummy wrapper for the F-Curve */
ale_dummy.type = ANIMTYPE_FCURVE;
@@ -1287,7 +1302,7 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
* - active track should still get shown though (even though it has disabled flag set)
*/
// FIXME: the channels after should still get drawn, just 'differently', and after an active-action channel
- if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && !(nlt->flag & NLATRACK_ACTIVE))
+ if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && (adt->act_track != nlt))
continue;
/* only work with this channel and its subchannels if it is editable */
@@ -1296,6 +1311,30 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
if (ANIMCHANNEL_SELOK(SEL_NLT(nlt))) {
/* only include if this track is active */
if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) {
+ /* name based filtering... */
+ if (((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) && (owner_id)) {
+ bool track_ok = false, strip_ok = false;
+
+ /* check if the name of the track, or the strips it has are ok... */
+ track_ok = BLI_strcasestr(nlt->name, ads->searchstr);
+
+ if (track_ok == false) {
+ NlaStrip *strip;
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ if (BLI_strcasestr(strip->name, ads->searchstr)) {
+ strip_ok = true;
+ break;
+ }
+ }
+ }
+
+ /* skip if both fail this test... */
+ if (!track_ok && !strip_ok) {
+ continue;
+ }
+ }
+
+ /* add the track now that it has passed all our tests */
ANIMCHANNEL_NEW_CHANNEL(nlt, ANIMTYPE_NLATRACK, owner_id);
}
}
@@ -1306,6 +1345,80 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
return items;
}
+/* Include the control FCurves per NLA Strip in the channel list
+ * NOTE: This is includes the expander too...
+ */
+static size_t animfilter_nla_controls(ListBase *anim_data, bDopeSheet *ads, AnimData *adt, int filter_mode, ID *owner_id)
+{
+ ListBase tmp_data = {NULL, NULL};
+ size_t tmp_items = 0;
+ size_t items = 0;
+
+ /* add control curves from each NLA strip... */
+ /* NOTE: ANIMTYPE_FCURVES are created here, to avoid duplicating the code needed */
+ BEGIN_ANIMFILTER_SUBCHANNELS(((adt->flag & ADT_NLA_SKEYS_COLLAPSED) == 0))
+ {
+ NlaTrack *nlt;
+ NlaStrip *strip;
+
+ /* for now, we only go one level deep - so controls on grouped FCurves are not handled */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ ListBase strip_curves = {NULL, NULL};
+ size_t strip_items = 0;
+
+ /* create the raw items */
+ strip_items += animfilter_fcurves(&strip_curves, ads, strip->fcurves.first, NULL, filter_mode, owner_id);
+
+ /* change their types and add extra data
+ * - There is no point making a separate copy of animfilter_fcurves for this now/yet,
+ * unless we later get per-element control curves for other stuff too
+ */
+ if (strip_items) {
+ bAnimListElem *ale, *ale_n = NULL;
+
+ for (ale = strip_curves.first; ale; ale = ale_n) {
+ ale_n = ale->next;
+
+ /* change the type to being a FCurve for editing NLA strip controls */
+ BLI_assert(ale->type == ANIMTYPE_FCURVE);
+
+ ale->type = ANIMTYPE_NLACURVE;
+ ale->owner = strip;
+
+ ale->adt = NULL; /* XXX: This way, there are no problems with time mapping errors */
+ }
+ }
+
+ /* add strip curves to the set of channels inside the group being collected */
+ BLI_movelisttolist(&tmp_data, &strip_curves);
+ BLI_assert(BLI_listbase_is_empty(&strip_curves));
+ tmp_items += strip_items;
+ }
+ }
+ }
+ END_ANIMFILTER_SUBCHANNELS;
+
+ /* did we find anything? */
+ if (tmp_items) {
+ /* add the expander as a channel first */
+ if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
+ /* currently these channels cannot be selected, so they should be skipped */
+ if ((filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL)) == 0) {
+ ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_NLACONTROLS, owner_id);
+ }
+ }
+
+ /* now add the list of collected channels */
+ BLI_movelisttolist(anim_data, &tmp_data);
+ BLI_assert(BLI_listbase_is_empty(&tmp_data));
+ items += tmp_items;
+ }
+
+ /* return the numebr of items added to the list */
+ return items;
+}
+
/* determine what animation data from AnimData block should get displayed */
static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *id, int filter_mode)
{
@@ -1333,6 +1446,9 @@ static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDope
{ /* Drivers */
items += animfilter_fcurves(anim_data, ads, adt->drivers.first, NULL, filter_mode, id);
},
+ { /* NLA Control Keyframes */
+ items += animfilter_nla_controls(anim_data, ads, adt, filter_mode, id);
+ },
{ /* Keyframes */
items += animfilter_action(ac, anim_data, ads, adt->action, filter_mode, id);
}
@@ -2215,6 +2331,7 @@ static size_t animdata_filter_ds_obanim(bAnimContext *ac, ListBase *anim_data, b
cdata = adt;
expanded = EXPANDED_DRVD(adt);
},
+ { /* NLA Strip Controls - no dedicated channel for now (XXX) */ },
{ /* Keyframes */
type = ANIMTYPE_FILLACTD;
cdata = adt->action;
@@ -2392,6 +2509,7 @@ static size_t animdata_filter_ds_scene(bAnimContext *ac, ListBase *anim_data, bD
cdata = adt;
expanded = EXPANDED_DRVD(adt);
},
+ { /* NLA Strip Controls - no dedicated channel for now (XXX) */ },
{ /* Keyframes */
type = ANIMTYPE_FILLACTD;
cdata = adt->action;
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 140b7e0b117..45663371ae3 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -266,8 +266,20 @@ void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short only_sel)
{
TimeMarker *marker;
- if (markers == NULL)
+ if (lb) {
+ /* Clear the list first, since callers have no way of knowing
+ * whether this terminated early otherwise. This may lead
+ * to crashes if the user didn't clear the memory first.
+ */
+ lb->first = lb->last = NULL;
+ }
+ else {
+ return;
+ }
+
+ if (markers == NULL) {
return;
+ }
for (marker = markers->first; marker; marker = marker->next)
add_marker_to_cfra_elem(lb, marker, only_sel);
@@ -487,6 +499,23 @@ static int ed_markers_poll_selected_markers(bContext *C)
return ED_markers_get_first_selected(markers) != NULL;
}
+static int ed_markers_poll_selected_no_locked_markers(bContext *C)
+{
+ ListBase *markers = ED_context_get_markers(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ if (ts->lock_markers)
+ return 0;
+
+ /* first things first: markers can only exist in timeline views */
+ if (ED_operator_animview_active(C) == 0)
+ return 0;
+
+ /* check if some marker is selected */
+ return ED_markers_get_first_selected(markers) != NULL;
+}
+
+
/* special poll() which checks if there are any markers at all first */
static int ed_markers_poll_markers_exist(bContext *C)
{
@@ -929,11 +958,11 @@ static void MARKER_OT_move(wmOperatorType *ot)
ot->exec = ed_marker_move_exec;
ot->invoke = ed_marker_move_invoke_wrapper;
ot->modal = ed_marker_move_modal;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
ot->cancel = ed_marker_move_cancel;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
/* rna storage */
RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
@@ -1022,7 +1051,7 @@ static void MARKER_OT_duplicate(wmOperatorType *ot)
ot->exec = ed_marker_duplicate_exec;
ot->invoke = ed_marker_duplicate_invoke_wrapper;
ot->modal = ed_marker_move_modal;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
ot->cancel = ed_marker_move_cancel;
/* flags */
@@ -1352,7 +1381,7 @@ static void MARKER_OT_delete(wmOperatorType *ot)
/* api callbacks */
ot->invoke = ed_marker_delete_invoke_wrapper;
ot->exec = ed_marker_delete_exec;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1400,7 +1429,7 @@ static void MARKER_OT_rename(wmOperatorType *ot)
/* api callbacks */
ot->invoke = ed_marker_rename_invoke_wrapper;
ot->exec = ed_marker_rename_exec;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1428,6 +1457,11 @@ static int ed_marker_make_links_scene_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ if (scene_to->toolsettings->lock_markers) {
+ BKE_report(op->reports, RPT_ERROR, "Target scene has locked markers");
+ return OPERATOR_CANCELLED;
+ }
+
/* copy markers */
for (marker = markers->first; marker; marker = marker->next) {
if (marker->flag & SELECT) {
@@ -1509,7 +1543,7 @@ static void MARKER_OT_camera_bind(wmOperatorType *ot)
/* api callbacks */
ot->exec = ed_marker_camera_bind_exec;
ot->invoke = ed_markers_opwrap_invoke;
- ot->poll = ed_markers_poll_selected_markers;
+ ot->poll = ed_markers_poll_selected_no_locked_markers;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index cbcbc8743f1..86b368fe0d2 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -60,6 +60,8 @@
#include "anim_intern.h"
+#include "MEM_guardedalloc.h"
+
/* ********************** frame change operator ***************************/
/* Check if the operator can be run from the current context */
@@ -90,10 +92,11 @@ static int change_frame_poll(bContext *C)
}
/* Set the new frame number */
-static void change_frame_apply(bContext *C, wmOperator *op)
+static void change_frame_apply(bContext *C, wmOperator *op, bool final)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ARegion *ar_op = CTX_wm_region(C);
int frame = RNA_int_get(op->ptr, "frame");
bool do_snap = RNA_boolean_get(op->ptr, "snap");
@@ -107,8 +110,44 @@ static void change_frame_apply(bContext *C, wmOperator *op)
SUBFRA = 0.0f;
/* do updates */
- sound_seek_scene(bmain, scene);
- WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
+
+ if (final) {
+ BKE_sound_seek_scene(bmain, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
+ }
+ else
+ {
+ bScreen *screen = CTX_wm_screen(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *window;
+ ScrArea *sa;
+
+ BKE_sound_seek_scene(bmain, scene);
+
+ ED_update_for_newframe(bmain, scene, 1);
+
+ for (window = wm->windows.first; window; window = window->next) {
+ for (sa = window->screen->areabase.first; sa; sa = sa->next) {
+ ARegion *ar;
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ bool redraw = false;
+ if (ar == ar_op) {
+ redraw = true;
+ }
+ else if (ED_match_region_with_redraws(sa->spacetype, ar->regiontype, screen->redraws_flag)) {
+ redraw = true;
+ }
+
+ if (redraw) {
+ ED_region_tag_redraw(ar);
+ }
+ }
+
+ if (ED_match_area_with_refresh(sa->spacetype, SPACE_TIME))
+ ED_area_tag_refresh(sa);
+ }
+ }
+ }
}
/* ---- */
@@ -116,8 +155,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
/* Non-modal callback for running operator without user input */
static int change_frame_exec(bContext *C, wmOperator *op)
{
- change_frame_apply(C, op);
-
+ change_frame_apply(C, op, true);
return OPERATOR_FINISHED;
}
@@ -154,13 +192,35 @@ static void change_frame_seq_preview_begin(bContext *C, const wmEvent *event)
}
}
}
-static void change_frame_seq_preview_end(bContext *C)
+
+typedef struct ChangeFrameData {
+ wmTimer *timer;
+ double last_duration;
+ int frame;
+ int last_frame;
+} ChangeFrameData;
+
+static void change_frame_seq_preview_end(bContext *C, wmOperator *op)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+
if (ED_sequencer_special_preview_get() != NULL) {
Scene *scene = CTX_data_scene(C);
ED_sequencer_special_preview_clear();
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
+
+ if (op->customdata) {
+ ChangeFrameData *data = op->customdata;
+ WM_event_remove_timer(wm, win, data->timer);
+ MEM_freeN(data);
+ op->customdata = NULL;
+ /* add here too to take care of cancelling */
+ if (win->screen)
+ win->screen->scrubbing = false;
+ }
+
}
/* Modal Operator init */
@@ -170,11 +230,22 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event
* as user could click on a single frame (jump to frame) as well as
* click-dragging over a range (modal scrubbing).
*/
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+ Scene *scene = CTX_data_scene(C);
+ ChangeFrameData *data = MEM_callocN(sizeof(ChangeFrameData), "changeframedata");
+
+ data->timer = WM_event_add_timer(wm, win, TIMER, FRA2TIME(1.0));
+
RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
+ op->customdata = data;
change_frame_seq_preview_begin(C, event);
- change_frame_apply(C, op);
+ if (win->screen)
+ win->screen->scrubbing = true;
+
+ change_frame_apply(C, op, false);
/* add temp handler */
WM_event_add_modal_handler(C, op);
@@ -182,24 +253,43 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event
return OPERATOR_RUNNING_MODAL;
}
-static void change_frame_cancel(bContext *C, wmOperator *UNUSED(op))
+static void change_frame_cancel(bContext *C, wmOperator *op)
{
- change_frame_seq_preview_end(C);
+ change_frame_seq_preview_end(C, op);
}
/* Modal event handling of frame changing */
static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ChangeFrameData *data = op->customdata;
+ wmWindow *win = CTX_wm_window(C);
+
int ret = OPERATOR_RUNNING_MODAL;
/* execute the events */
switch (event->type) {
case ESCKEY:
+ WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
+ if (win->screen)
+ win->screen->scrubbing = false;
+ BKE_sound_seek_scene(bmain, scene);
ret = OPERATOR_FINISHED;
break;
case MOUSEMOVE:
- RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
- change_frame_apply(C, op);
+ data->frame = frame_from_event(C, event);
+ break;
+
+ case TIMER:
+ if (data->timer->duration - data->last_duration > FRA2TIME(1)) {
+ if (data->frame != data->last_frame) {
+ RNA_int_set(op->ptr, "frame", data->frame);
+ change_frame_apply(C, op, false);
+ data->last_frame = data->frame;
+ data->last_duration = data->timer->duration;
+ }
+ }
break;
case LEFTMOUSE:
@@ -208,8 +298,14 @@ static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* we check for either mouse-button to end, as checking for ACTIONMOUSE (which is used to init
* the modal op) doesn't work for some reason
*/
- if (event->val == KM_RELEASE)
+ if (event->val == KM_RELEASE) {
+ if (win->screen)
+ win->screen->scrubbing = false;
+ data->frame = frame_from_event(C, event);
+ RNA_int_set(op->ptr, "frame", data->frame);
+ change_frame_apply(C, op, true);
ret = OPERATOR_FINISHED;
+ }
break;
case LEFTCTRLKEY:
@@ -224,7 +320,7 @@ static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (ret != OPERATOR_RUNNING_MODAL) {
- change_frame_seq_preview_end(C);
+ change_frame_seq_preview_end(C, op);
}
return ret;
@@ -247,7 +343,7 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
ot->poll = change_frame_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
/* rna */
ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 67ba82f1858..b2a34d7c317 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -42,6 +42,7 @@
#include "DNA_texture_types.h"
#include "BKE_animsys.h"
+#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_context.h"
#include "BKE_report.h"
@@ -84,7 +85,7 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
if ((adt == NULL) && (add))
- adt = BKE_id_add_animdata(id);
+ adt = BKE_animdata_add_id(id);
if (adt == NULL) {
/* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
return NULL;
@@ -450,7 +451,7 @@ static int add_driver_button_exec(bContext *C, wmOperator *op)
if (success) {
/* send updates */
UI_context_update_anim_flag(C);
-
+ DAG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
}
@@ -504,7 +505,7 @@ static int remove_driver_button_exec(bContext *C, wmOperator *op)
if (success) {
/* send updates */
UI_context_update_anim_flag(C);
-
+ DAG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
}
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index bcdad1c93ad..2c0018b000d 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -78,7 +78,7 @@
static void validate_fmodifier_cb(bContext *UNUSED(C), void *fcm_v, void *UNUSED(arg))
{
FModifier *fcm = (FModifier *)fcm_v;
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
/* call the verify callback on the modifier if applicable */
if (fmi && fmi->verify_data)
@@ -555,7 +555,7 @@ static void draw_modifier__stepped(uiLayout *layout, ID *id, FModifier *fcm, sho
void ANIM_uiTemplate_fmodifier_draw(uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm)
{
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
uiLayout *box, *row, *sub, *col;
uiBlock *block;
uiBut *but;
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index d2dbe961b42..9e38dd5507d 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -528,7 +528,7 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel,
}
/* NOTE: we don't use the straight alpha from the theme, or else effects such as
- * greying out protected/muted channels doesn't work correctly!
+ * graying out protected/muted channels doesn't work correctly!
*/
inner_col[3] *= alpha;
glColor4fv(inner_col);
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 932a00d1687..5d2c0077dee 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -179,17 +179,37 @@ void duplicate_fcurve_keys(FCurve *fcu)
/* **************************************************** */
/* Various Tools */
-/* Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only */
-void clean_fcurve(FCurve *fcu, float thresh)
+static void copy_bezt_ipo(BezTriple *bezdst, BezTriple *bezsrc)
{
+ bezdst->back = bezsrc->back;
+ bezdst->ipo = bezsrc->ipo;
+ bezdst->easing = bezsrc->easing;
+ bezdst->amplitude = bezsrc->amplitude;
+ bezdst->period = bezsrc->period;
+ bezdst->h1 = bezsrc->h1;
+ bezdst->h2 = bezsrc->h2;
+ bezdst->vec[0][0] = bezsrc->vec[0][0];
+ bezdst->vec[0][1] = bezsrc->vec[0][1];
+ bezdst->vec[2][0] = bezsrc->vec[2][0];
+ bezdst->vec[2][1] = bezsrc->vec[2][1];
+}
+
+/* Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only
+ * optionally clears up curve if one keyframe with default value remains */
+void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, bool cleardefault)
+{
+ FCurve *fcu = (FCurve *)ale->key_data;
BezTriple *old_bezts, *bezt, *beztn;
BezTriple *lastb;
int totCount, i;
/* check if any points */
- if ((fcu == NULL) || (fcu->bezt == NULL) || (fcu->totvert <= 1))
+ if ((fcu == NULL) || (fcu->bezt == NULL) || (fcu->totvert == 0) ||
+ (!cleardefault && fcu->totvert == 1))
+ {
return;
-
+ }
+
/* make a copy of the old BezTriples, and clear F-Curve */
old_bezts = fcu->bezt;
totCount = fcu->totvert;
@@ -199,13 +219,17 @@ void clean_fcurve(FCurve *fcu, float thresh)
/* now insert first keyframe, as it should be ok */
bezt = old_bezts;
insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], 0);
+ if (!(bezt->f2 & SELECT)) {
+ lastb = fcu->bezt;
+ lastb->f1 = lastb->f2 = lastb->f3 = 0;
+ }
/* Loop through BezTriples, comparing them. Skip any that do
* not fit the criteria for "ok" points.
*/
for (i = 1; i < totCount; i++) {
float prev[2], cur[2], next[2];
-
+
/* get BezTriples and their values */
if (i < (totCount - 1)) {
beztn = (old_bezts + (i + 1));
@@ -217,10 +241,18 @@ void clean_fcurve(FCurve *fcu, float thresh)
}
lastb = (fcu->bezt + (fcu->totvert - 1));
bezt = (old_bezts + i);
-
+
/* get references for quicker access */
prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1];
cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];
+
+ if (!(bezt->f2 & SELECT)) {
+ insert_vert_fcurve(fcu, cur[0], cur[1], INSERTKEY_FAST);
+ copy_bezt_ipo((fcu->bezt + (fcu->totvert - 1)), bezt);
+ lastb = (fcu->bezt + (fcu->totvert - 1));
+ lastb->f1 = lastb->f2 = lastb->f3 = 0;
+ continue;
+ }
/* check if current bezt occurs at same time as last ok */
if (IS_EQT(cur[0], prev[0], thresh)) {
@@ -228,14 +260,15 @@ void clean_fcurve(FCurve *fcu, float thresh)
* if there is a considerable distance between the points, and also if the
* current is further away than the next one is to the previous.
*/
- if (beztn && (IS_EQT(cur[0], next[0], thresh)) &&
+ if (beztn && (IS_EQT(cur[0], next[0], thresh)) &&
(IS_EQT(next[1], prev[1], thresh) == 0))
{
/* only add if current is further away from previous */
if (cur[1] > next[1]) {
if (IS_EQT(cur[1], prev[1], thresh) == 0) {
/* add new keyframe */
- insert_vert_fcurve(fcu, cur[0], cur[1], 0);
+ insert_vert_fcurve(fcu, cur[0], cur[1], INSERTKEY_FAST);
+ copy_bezt_ipo((fcu->bezt + (fcu->totvert - 1)), bezt);
}
}
}
@@ -243,7 +276,8 @@ void clean_fcurve(FCurve *fcu, float thresh)
/* only add if values are a considerable distance apart */
if (IS_EQT(cur[1], prev[1], thresh) == 0) {
/* add new keyframe */
- insert_vert_fcurve(fcu, cur[0], cur[1], 0);
+ insert_vert_fcurve(fcu, cur[0], cur[1], INSERTKEY_FAST);
+ copy_bezt_ipo((fcu->bezt + (fcu->totvert - 1)), bezt);
}
}
}
@@ -253,26 +287,60 @@ void clean_fcurve(FCurve *fcu, float thresh)
/* does current have same value as previous and next? */
if (IS_EQT(cur[1], prev[1], thresh) == 0) {
/* add new keyframe*/
- insert_vert_fcurve(fcu, cur[0], cur[1], 0);
+ insert_vert_fcurve(fcu, cur[0], cur[1], INSERTKEY_FAST);
+ copy_bezt_ipo((fcu->bezt + (fcu->totvert - 1)), bezt);
}
else if (IS_EQT(cur[1], next[1], thresh) == 0) {
/* add new keyframe */
- insert_vert_fcurve(fcu, cur[0], cur[1], 0);
+ insert_vert_fcurve(fcu, cur[0], cur[1], INSERTKEY_FAST);
+ copy_bezt_ipo((fcu->bezt + (fcu->totvert - 1)), bezt);
}
}
else {
/* add if value doesn't equal that of previous */
if (IS_EQT(cur[1], prev[1], thresh) == 0) {
/* add new keyframe */
- insert_vert_fcurve(fcu, cur[0], cur[1], 0);
+ insert_vert_fcurve(fcu, cur[0], cur[1], INSERTKEY_FAST);
+ copy_bezt_ipo((fcu->bezt + (fcu->totvert - 1)), bezt);
}
}
}
}
-
+
+ /* skip doing this, handles should be already sorted since we are copying in forward order only */
+ /* calchandles_fcurve(fcu); */
+
/* now free the memory used by the old BezTriples */
if (old_bezts)
MEM_freeN(old_bezts);
+
+ /* final step, if there is just one key in fcurve, check if it's
+ * the default value and if is, remove fcurve completely. */
+ if (cleardefault && fcu->totvert == 1) {
+ float default_value = 0.0f;
+ PointerRNA id_ptr, ptr;
+ PropertyRNA *prop;
+ RNA_id_pointer_create(ale->id, &id_ptr);
+
+ /* get property to read from, and get value as appropriate */
+ if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
+ if (RNA_property_type(prop) == PROP_FLOAT)
+ default_value = RNA_property_float_get_default_index(&ptr, prop, fcu->array_index);
+ }
+
+ if (fcu->bezt->vec[1][1] == default_value) {
+ clear_fcurve_keys(fcu);
+
+ /* check if curve is really unused and if it is, return signal for deletion */
+ if ((list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0) &&
+ (fcu->driver == NULL))
+ {
+ AnimData *adt = ale->adt;
+ ANIM_fcurve_delete_from_animdata(ac, adt, fcu);
+ ale->key_data = NULL;
+ }
+ }
+ }
}
/* ---------------- */
@@ -548,24 +616,15 @@ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
* storing the relevant information here helps avoiding crashes if we undo-repaste */
if ((aci->id_type == ID_OB) && (((Object *)aci->id)->type == OB_ARMATURE) && aci->rna_path) {
Object *ob = (Object *)aci->id;
- char *str_start;
-
- if ((str_start = strstr(aci->rna_path, "pose.bones["))) {
- bPoseChannel *pchan;
- int length = 0;
- char *str_end;
-
- str_start += 12;
- str_end = strchr(str_start, '\"');
- length = str_end - str_start;
- str_start[length] = 0;
- pchan = BKE_pose_channel_find_name(ob->pose, str_start);
- str_start[length] = '\"';
-
- if (pchan) {
- aci->is_bone = true;
- }
+ bPoseChannel *pchan;
+ char *bone_name;
+
+ bone_name = BLI_str_quoted_substrN(aci->rna_path, "pose.bones[");
+ pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
+ if (pchan) {
+ aci->is_bone = true;
}
+ if (bone_name) MEM_freeN(bone_name);
}
BLI_addtail(&animcopybuf, aci);
@@ -624,22 +683,22 @@ static void flip_names(tAnimCopybufItem *aci, char **name)
char bname_new[MAX_VGROUP_NAME];
char *str_iter, *str_end;
int length, prefix_l, postfix_l;
-
+
str_start += 12;
prefix_l = str_start - aci->rna_path;
-
+
str_end = strchr(str_start, '\"');
-
+
length = str_end - str_start;
postfix_l = strlen(str_end);
-
+
/* more ninja stuff, temporary substitute with NULL terminator */
str_start[length] = 0;
BKE_deform_flip_side_name(bname_new, str_start, false);
str_start[length] = '\"';
-
+
str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1), "flipped_path");
-
+
BLI_strncpy(str_iter, aci->rna_path, prefix_l + 1);
str_iter += prefix_l;
BLI_strncpy(str_iter, bname_new, length + 1);
@@ -774,7 +833,7 @@ static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float
/* First de-select existing FCurve's keyframes */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- bezt->f2 &= ~SELECT;
+ BEZ_DESEL(bezt);
}
/* mix mode with existing data */
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 7e2ce4cd3f1..cd7a326ffd5 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -130,7 +130,7 @@ bAction *verify_adt_action(ID *id, short add)
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
if ((adt == NULL) && (add))
- adt = BKE_id_add_animdata(id);
+ adt = BKE_animdata_add_id(id);
if (adt == NULL) {
/* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
printf("ERROR: Couldn't add AnimData (ID = %s)\n", (id) ? (id->name) : "<None>");
@@ -152,6 +152,10 @@ bAction *verify_adt_action(ID *id, short add)
* to the wrong places
*/
adt->action->idroot = GS(id->name);
+
+ /* tag depsgraph to be rebuilt to include time dependency */
+ /* XXX: we probably should have bmain passed down, but that involves altering too many API's */
+ DAG_relations_tag_update(G.main);
}
/* return the action */
@@ -1696,7 +1700,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
char *path;
float cfra = (float)CFRA;
short success = 0;
- int a, index, length;
+ int index;
const bool all = RNA_boolean_get(op->ptr, "all");
short flag = 0;
@@ -1707,33 +1711,35 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if ((ptr.id.data && ptr.data && prop) && RNA_property_animateable(&ptr, prop)) {
- path = RNA_path_from_ID_to_property(&ptr, prop);
-
- if (path) {
- if (all) {
- length = RNA_property_array_length(&ptr, prop);
-
- if (length) index = 0;
- else length = 1;
- }
- else
- length = 1;
-
- for (a = 0; a < length; a++)
- success += insert_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index + a, cfra, flag);
-
- MEM_freeN(path);
- }
- else if (ptr.type == &RNA_NlaStrip) {
- /* handle special vars for NLA-strips */
+ if (ptr.type == &RNA_NlaStrip) {
+ /* Handle special properties for NLA Strips, whose F-Curves are stored on the
+ * strips themselves. These are stored separately or else the properties will
+ * not have any effect.
+ */
NlaStrip *strip = (NlaStrip *)ptr.data;
FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), flag);
- success += insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, 0);
+ success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, 0);
}
else {
- BKE_report(op->reports, RPT_WARNING,
- "Failed to resolve path to property, try manually specifying this using a Keying Set instead");
+ /* standard properties */
+ path = RNA_path_from_ID_to_property(&ptr, prop);
+
+ if (path) {
+ if (all) {
+ /* -1 indicates operating on the entire array (or the property itself otherwise) */
+ index = -1;
+ }
+
+ success = insert_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, cfra, flag);
+
+ MEM_freeN(path);
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING,
+ "Failed to resolve path to property, "
+ "try manually specifying this using a Keying Set instead");
+ }
}
}
else {
@@ -1788,7 +1794,7 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
char *path;
float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
short success = 0;
- int a, index, length;
+ int index;
const bool all = RNA_boolean_get(op->ptr, "all");
/* try to insert keyframe using property retrieved from UI */
@@ -1799,17 +1805,11 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
if (path) {
if (all) {
- length = RNA_property_array_length(&ptr, prop);
-
- if (length) index = 0;
- else length = 1;
+ /* -1 indicates operating on the entire array (or the property itself otherwise) */
+ index = -1;
}
- else
- length = 1;
-
- for (a = 0; a < length; a++)
- success += delete_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index + a, cfra, 0);
+ success = delete_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, cfra, 0);
MEM_freeN(path);
}
else if (G.debug & G_DEBUG)
@@ -1858,7 +1858,7 @@ static int clear_key_button_exec(bContext *C, wmOperator *op)
PropertyRNA *prop = NULL;
char *path;
short success = 0;
- int a, index, length;
+ int index;
const bool all = RNA_boolean_get(op->ptr, "all");
/* try to insert keyframe using property retrieved from UI */
@@ -1869,17 +1869,11 @@ static int clear_key_button_exec(bContext *C, wmOperator *op)
if (path) {
if (all) {
- length = RNA_property_array_length(&ptr, prop);
-
- if (length) index = 0;
- else length = 1;
+ /* -1 indicates operating on the entire array (or the property itself otherwise) */
+ index = -1;
}
- else
- length = 1;
-
- for (a = 0; a < length; a++)
- success += clear_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index + a, 0);
+ success += clear_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, 0);
MEM_freeN(path);
}
else if (G.debug & G_DEBUG)
diff --git a/source/blender/editors/armature/BIF_retarget.h b/source/blender/editors/armature/BIF_retarget.h
index 21e85b6fe89..aa56f847f00 100644
--- a/source/blender/editors/armature/BIF_retarget.h
+++ b/source/blender/editors/armature/BIF_retarget.h
@@ -40,7 +40,6 @@ struct bContext;
struct EditBone;
-struct RigJoint;
struct RigGraph;
struct RigNode;
struct RigArc;
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 22aaeccc4a8..e3a69a89a57 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -43,6 +43,7 @@
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_idprop.h"
+#include "BKE_deform.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -89,7 +90,7 @@ EditBone *ED_armature_edit_bone_add_primitive(Object *obedit_arm, float length,
bArmature *arm = obedit_arm->data;
EditBone *bone;
- ED_armature_deselect_all(obedit_arm, 0);
+ ED_armature_deselect_all(obedit_arm);
/* Create a bone */
bone = ED_armature_edit_bone_add(arm, "Bone");
@@ -144,7 +145,7 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op))
to_root = 1;
}
- ED_armature_deselect_all(obedit, 0);
+ ED_armature_deselect_all(obedit);
/* we re-use code for mirror editing... */
flipbone = NULL;
@@ -282,12 +283,8 @@ static EditBone *get_named_editbone(ListBase *edbo, const char *name)
* */
void preEditBoneDuplicate(ListBase *editbones)
{
- EditBone *eBone;
-
/* clear temp */
- for (eBone = editbones->first; eBone; eBone = eBone->next) {
- eBone->temp = NULL;
- }
+ ED_armature_ebone_listbase_temp_clear(editbones);
}
/*
@@ -311,7 +308,7 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Obj
/* does this constraint have a subtarget in
* this armature?
*/
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -327,8 +324,8 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Obj
* so, update the constraint to point at the
* duplicate of the old subtarget.
*/
- if (oldtarget->temp) {
- newtarget = (EditBone *) oldtarget->temp;
+ if (oldtarget->temp.ebone) {
+ newtarget = oldtarget->temp.ebone;
BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
}
}
@@ -357,8 +354,8 @@ EditBone *duplicateEditBoneObjects(EditBone *curBone, const char *name, ListBase
/* Copy data from old bone to new bone */
memcpy(eBone, curBone, sizeof(EditBone));
- curBone->temp = eBone;
- eBone->temp = curBone;
+ curBone->temp.ebone = eBone;
+ eBone->temp.ebone = curBone;
if (name != NULL) {
BLI_strncpy(eBone->name, name, sizeof(eBone->name));
@@ -398,13 +395,11 @@ EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editb
return duplicateEditBoneObjects(curBone, name, editbones, ob, ob);
}
-/* previously adduplicate_armature */
static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
bArmature *arm;
- EditBone *eBone = NULL;
- EditBone *curBone;
- EditBone *firstDup = NULL; /* The beginning of the duplicated bones in the edbo list */
+ EditBone *ebone_iter;
+ EditBone *ebone_first_dupe = NULL; /* The beginning of the duplicated bones in the edbo list */
Object *obedit = CTX_data_edit_object(C);
arm = obedit->data;
@@ -419,77 +414,80 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op))
/* Select mirrored bones */
if (arm->flag & ARM_MIRROR_EDIT) {
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
- eBone = ED_armature_bone_get_mirrored(arm->edbo, curBone);
- if (eBone)
- eBone->flag |= BONE_SELECTED;
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED))
+ {
+ EditBone *ebone;
+
+ ebone = ED_armature_bone_get_mirrored(arm->edbo, ebone_iter);
+ if (ebone) {
+ ebone->flag |= BONE_SELECTED;
}
}
}
}
- /* Find the selected bones and duplicate them as needed */
- for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
-
- eBone = duplicateEditBone(curBone, curBone->name, arm->edbo, obedit);
-
- if (!firstDup)
- firstDup = eBone;
+ /* Find the selected bones and duplicate them as needed */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED))
+ {
+ EditBone *ebone;
+ ebone = duplicateEditBone(ebone_iter, ebone_iter->name, arm->edbo, obedit);
+
+ if (!ebone_first_dupe) {
+ ebone_first_dupe = ebone;
}
}
}
- /* Run though the list and fix the pointers */
- for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
- eBone = (EditBone *) curBone->temp;
-
- if (!curBone->parent) {
- /* If this bone has no parent,
- * Set the duplicate->parent to NULL
- */
- eBone->parent = NULL;
- }
- else if (curBone->parent->temp) {
- /* If this bone has a parent that was duplicated,
- * Set the duplicate->parent to the curBone->parent->temp
- */
- eBone->parent = (EditBone *)curBone->parent->temp;
- }
- else {
- /* If this bone has a parent that IS not selected,
- * Set the duplicate->parent to the curBone->parent
- */
- eBone->parent = (EditBone *) curBone->parent;
- eBone->flag &= ~BONE_CONNECTED;
- }
-
- /* Lets try to fix any constraint subtargets that might
- * have been duplicated
+ /* Run though the list and fix the pointers */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED))
+ {
+ EditBone *ebone = ebone_iter->temp.ebone;
+
+ if (!ebone_iter->parent) {
+ /* If this bone has no parent,
+ * Set the duplicate->parent to NULL
+ */
+ ebone->parent = NULL;
+ }
+ else if (ebone_iter->parent->temp.ebone) {
+ /* If this bone has a parent that was duplicated,
+ * Set the duplicate->parent to the curBone->parent->temp
+ */
+ ebone->parent = ebone_iter->parent->temp.ebone;
+ }
+ else {
+ /* If this bone has a parent that IS not selected,
+ * Set the duplicate->parent to the curBone->parent
*/
- updateDuplicateSubtarget(eBone, arm->edbo, obedit);
+ ebone->parent = (EditBone *) ebone_iter->parent;
+ ebone->flag &= ~BONE_CONNECTED;
}
+
+ /* Lets try to fix any constraint subtargets that might
+ * have been duplicated
+ */
+ updateDuplicateSubtarget(ebone, arm->edbo, obedit);
}
}
/* correct the active bone */
- if (arm->act_edbone) {
- eBone = arm->act_edbone;
- if (eBone->temp)
- arm->act_edbone = eBone->temp;
+ if (arm->act_edbone && arm->act_edbone->temp.ebone) {
+ arm->act_edbone = arm->act_edbone->temp.ebone;
}
- /* Deselect the old bones and select the new ones */
- for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone))
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ /* Deselect the old bones and select the new ones */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter)) {
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
}
ED_armature_validate_active(arm);
@@ -515,6 +513,214 @@ void ARMATURE_OT_duplicate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/**
+ * near duplicate of #armature_duplicate_selected_exec,
+ * except for parenting part (keep in sync)
+ */
+static int armature_symmetrize_exec(bContext *C, wmOperator *op)
+{
+ bArmature *arm;
+ EditBone *ebone_iter;
+ EditBone *ebone_first_dupe = NULL; /* The beginning of the duplicated mirrored bones in the edbo list */
+
+ Object *obedit = CTX_data_edit_object(C);
+ const int direction = RNA_enum_get(op->ptr, "direction");
+ const int axis = 0;
+
+ arm = obedit->data;
+
+ /* cancel if nothing selected */
+ if (CTX_DATA_COUNT(C, selected_bones) == 0)
+ return OPERATOR_CANCELLED;
+
+ ED_armature_sync_selection(arm->edbo); // XXX why is this needed?
+
+ preEditBoneDuplicate(arm->edbo);
+
+ /* Select mirrored bones */
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED))
+ {
+ char name_flip[MAX_VGROUP_NAME];
+
+ BKE_deform_flip_side_name(name_flip, ebone_iter->name, false);
+
+ if (STREQ(name_flip, ebone_iter->name)) {
+ /* if the name matches, we don't have the potential to be mirrored, just skip */
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ EditBone *ebone = ED_armature_bone_find_name(arm->edbo, name_flip);
+
+ if (ebone) {
+ if ((ebone->flag & BONE_SELECTED) == 0) {
+ /* simple case, we're selected, the other bone isn't! */
+ ebone_iter->temp.ebone = ebone;
+ }
+ else {
+ /* complicated - choose which direction to copy */
+ float axis_delta;
+
+ axis_delta = ebone->head[axis] - ebone_iter->head[axis];
+ if (axis_delta == 0.0f) {
+ axis_delta = ebone->tail[axis] - ebone_iter->tail[axis];
+ }
+
+ if (axis_delta == 0.0f) {
+ /* both mirrored bones exist and point to eachother and overlap exactly.
+ *
+ * in this case theres no well defined solution, so de-select both and skip.
+ */
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ EditBone *ebone_src, *ebone_dst;
+ if (((axis_delta < 0.0f) ? -1 : 1) == direction) {
+ ebone_src = ebone;
+ ebone_dst = ebone_iter;
+ }
+ else {
+ ebone_src = ebone_iter;
+ ebone_dst = ebone;
+ }
+
+ ebone_src->temp.ebone = ebone_dst;
+ ebone_dst->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Find the selected bones and duplicate them as needed, with mirrored name */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED) &&
+ /* will be set if the mirror bone already exists (no need to make a new one) */
+ (ebone_iter->temp.ebone == NULL))
+ {
+ char name_flip[MAX_VGROUP_NAME];
+
+ BKE_deform_flip_side_name(name_flip, ebone_iter->name, false);
+
+ /* bones must have a side-suffix */
+ if (!STREQ(name_flip, ebone_iter->name)) {
+ EditBone *ebone;
+
+ ebone = duplicateEditBone(ebone_iter, name_flip, arm->edbo, obedit);
+
+ if (!ebone_first_dupe) {
+ ebone_first_dupe = ebone;
+ }
+ }
+ }
+ }
+
+ /* Run though the list and fix the pointers */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (ebone_iter->temp.ebone) {
+ /* copy all flags except for ... */
+ const int flag_copy = ((int)~0) & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+
+ EditBone *ebone = ebone_iter->temp.ebone;
+
+ /* copy flags incase bone is pre-existing data */
+ ebone->flag = (ebone->flag & ~flag_copy) | (ebone_iter->flag & flag_copy);
+
+ if (ebone_iter->parent == NULL) {
+ /* If this bone has no parent,
+ * Set the duplicate->parent to NULL
+ */
+ ebone->parent = NULL;
+ ebone->flag &= ~BONE_CONNECTED;
+ }
+ else {
+ /* the parent may have been duplicated, if not lookup the mirror parent */
+ EditBone *ebone_parent =
+ (ebone_iter->parent->temp.ebone ?
+ ebone_iter->parent->temp.ebone : ED_armature_bone_get_mirrored(arm->edbo, ebone_iter->parent));
+
+ if (ebone_parent == NULL) {
+ /* If the mirror lookup failed, (but the current bone has a parent)
+ * then we can assume the parent has no L/R but is a center bone.
+ * So just use the same parent for both.
+ */
+ ebone_parent = ebone_iter->parent;
+ ebone->flag &= ~BONE_CONNECTED;
+ }
+
+ ebone->parent = ebone_parent;
+ }
+
+ /* Lets try to fix any constraint subtargets that might
+ * have been duplicated
+ */
+ updateDuplicateSubtarget(ebone, arm->edbo, obedit);
+ }
+ }
+
+ transform_armature_mirror_update(obedit);
+
+ /* Selected bones now have their 'temp' pointer set,
+ * so we don't need this anymore */
+
+ /* Deselect the old bones and select the new ones */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter)) {
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+
+ /* New bones will be selected, but some of the bones may already exist */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ EditBone *ebone = ebone_iter->temp.ebone;
+ if (ebone && EBONE_SELECTABLE(arm, ebone)) {
+ ED_armature_ebone_select_set(ebone, true);
+ }
+ }
+
+ /* correct the active bone */
+ if (arm->act_edbone && arm->act_edbone->temp.ebone) {
+ arm->act_edbone = arm->act_edbone->temp.ebone;
+ }
+
+ ED_armature_validate_active(arm);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+/* following conventions from #MESH_OT_symmetrize */
+void ARMATURE_OT_symmetrize(wmOperatorType *ot)
+{
+ /* subset of 'symmetrize_direction_items' */
+ static EnumPropertyItem arm_symmetrize_direction_items[] = {
+ {-1, "NEGATIVE_X", 0, "-X to +X", ""},
+ {+1, "POSITIVE_X", 0, "+X to -X", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Symmetrize";
+ ot->idname = "ARMATURE_OT_symmetrize";
+ ot->description = "Enforce symmetry, make copies of the selection or use existing";
+
+ /* api callbacks */
+ ot->exec = armature_symmetrize_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(
+ ot->srna, "direction", arm_symmetrize_direction_items, -1,
+ "Direction", "Which sides to copy from and to (when both are selected)");
+}
+
/* ------------------------------------------ */
/* previously extrude_armature */
@@ -704,7 +910,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op)
mul_m3_m3m3(totmat, obmat, viewmat);
invert_m3_m3(imat, totmat);
- ED_armature_deselect_all(obedit, 0);
+ ED_armature_deselect_all(obedit);
/* Create a bone */
bone = ED_armature_edit_bone_add(obedit->data, name);
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index 88c52989c07..d4df77753eb 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -578,6 +578,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ListBase points = {NULL, NULL};
+ EditBone *newbone = NULL;
int count;
/* sanity checks */
@@ -610,94 +611,97 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
float curs[3];
/* Get Points - selected joint */
- ebp = (EditBonePoint *)points.first;
+ ebp = points.first;
/* Get points - cursor (tail) */
invert_m4_m4(obedit->imat, obedit->obmat);
mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
/* Create a bone */
- /* newbone = */ add_points_bone(obedit, ebp->vec, curs);
+ newbone = add_points_bone(obedit, ebp->vec, curs);
}
else if (count == 2) {
- EditBonePoint *ebp, *ebp2;
+ EditBonePoint *ebp_a, *ebp_b;
float head[3], tail[3];
short headtail = 0;
/* check that the points don't belong to the same bone */
- ebp = (EditBonePoint *)points.first;
- ebp2 = ebp->next;
+ ebp_a = (EditBonePoint *)points.first;
+ ebp_b = ebp_a->next;
- if ((ebp->head_owner == ebp2->tail_owner) && (ebp->head_owner != NULL)) {
- BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
- BLI_freelistN(&points);
- return OPERATOR_CANCELLED;
- }
- if ((ebp->tail_owner == ebp2->head_owner) && (ebp->tail_owner != NULL)) {
+ if (((ebp_a->head_owner == ebp_b->tail_owner) && (ebp_a->head_owner != NULL)) ||
+ ((ebp_a->tail_owner == ebp_b->head_owner) && (ebp_a->tail_owner != NULL)))
+ {
BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
BLI_freelistN(&points);
return OPERATOR_CANCELLED;
}
/* find which one should be the 'head' */
- if ((ebp->head_owner && ebp2->head_owner) || (ebp->tail_owner && ebp2->tail_owner)) {
- /* rule: whichever one is closer to 3d-cursor */
- float curs[3];
- float vecA[3], vecB[3];
- float distA, distB;
-
- /* get cursor location */
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
-
- /* get distances */
- sub_v3_v3v3(vecA, ebp->vec, curs);
- sub_v3_v3v3(vecB, ebp2->vec, curs);
- distA = len_v3(vecA);
- distB = len_v3(vecB);
-
- /* compare distances - closer one therefore acts as direction for bone to go */
- headtail = (distA < distB) ? 2 : 1;
+ if ((ebp_a->head_owner && ebp_b->head_owner) || (ebp_a->tail_owner && ebp_b->tail_owner)) {
+ /* use active, nice predictable */
+ if (arm->act_edbone && ELEM(arm->act_edbone, ebp_a->head_owner, ebp_a->tail_owner)) {
+ headtail = 1;
+ }
+ else if (arm->act_edbone && ELEM(arm->act_edbone, ebp_b->head_owner, ebp_b->tail_owner)) {
+ headtail = 2;
+ }
+ else {
+ /* rule: whichever one is closer to 3d-cursor */
+ float curs[3];
+ float dist_sq_a, dist_sq_b;
+
+ /* get cursor location */
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
+
+ /* get distances */
+ dist_sq_a = len_squared_v3v3(ebp_a->vec, curs);
+ dist_sq_b = len_squared_v3v3(ebp_b->vec, curs);
+
+ /* compare distances - closer one therefore acts as direction for bone to go */
+ headtail = (dist_sq_a < dist_sq_b) ? 2 : 1;
+ }
}
- else if (ebp->head_owner) {
+ else if (ebp_a->head_owner) {
headtail = 1;
}
- else if (ebp2->head_owner) {
+ else if (ebp_b->head_owner) {
headtail = 2;
}
/* assign head/tail combinations */
if (headtail == 2) {
- copy_v3_v3(head, ebp->vec);
- copy_v3_v3(tail, ebp2->vec);
+ copy_v3_v3(head, ebp_a->vec);
+ copy_v3_v3(tail, ebp_b->vec);
}
else if (headtail == 1) {
- copy_v3_v3(head, ebp2->vec);
- copy_v3_v3(tail, ebp->vec);
+ copy_v3_v3(head, ebp_b->vec);
+ copy_v3_v3(tail, ebp_a->vec);
}
/* add new bone and parent it to the appropriate end */
if (headtail) {
- EditBone *newbone = add_points_bone(obedit, head, tail);
+ newbone = add_points_bone(obedit, head, tail);
/* do parenting (will need to set connected flag too) */
if (headtail == 2) {
/* ebp tail or head - tail gets priority */
- if (ebp->tail_owner)
- newbone->parent = ebp->tail_owner;
+ if (ebp_a->tail_owner)
+ newbone->parent = ebp_a->tail_owner;
else
- newbone->parent = ebp->head_owner;
+ newbone->parent = ebp_a->head_owner;
}
else {
- /* ebp2 tail or head - tail gets priority */
- if (ebp2->tail_owner)
- newbone->parent = ebp2->tail_owner;
+ /* ebp_b tail or head - tail gets priority */
+ if (ebp_b->tail_owner)
+ newbone->parent = ebp_b->tail_owner;
else
- newbone->parent = ebp2->head_owner;
+ newbone->parent = ebp_b->head_owner;
}
/* don't set for bone connecting two head points of bones */
- if (ebp->tail_owner || ebp2->tail_owner) {
+ if (ebp_a->tail_owner || ebp_b->tail_owner) {
newbone->flag |= BONE_CONNECTED;
}
}
@@ -708,6 +712,12 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
BLI_freelistN(&points);
return OPERATOR_CANCELLED;
}
+
+ if (newbone) {
+ ED_armature_deselect_all(obedit);
+ arm->act_edbone = newbone;
+ newbone->flag |= BONE_TIPSEL;
+ }
/* updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
@@ -1254,7 +1264,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
}
else {
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 2c64c9aa345..0607bc49515 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -72,6 +72,7 @@ void ARMATURE_OT_shortest_path_pick(struct wmOperatorType *ot);
void ARMATURE_OT_delete(struct wmOperatorType *ot);
void ARMATURE_OT_duplicate(struct wmOperatorType *ot);
+void ARMATURE_OT_symmetrize(struct wmOperatorType *ot);
void ARMATURE_OT_extrude(struct wmOperatorType *ot);
void ARMATURE_OT_hide(struct wmOperatorType *ot);
void ARMATURE_OT_reveal(struct wmOperatorType *ot);
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index a8b5f888597..eedff896315 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -104,7 +104,7 @@ static void constraint_bone_name_fix(Object *ob, ListBase *conlist, const char *
bConstraintTarget *ct;
for (curcon = conlist->first; curcon; curcon = curcon->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
ListBase targets = {NULL, NULL};
/* constraint targets */
@@ -270,7 +270,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
// XXX: the ID here is for armatures, but most bone drivers are actually on the object instead...
{
- BKE_all_animdata_fix_paths_rename(&arm->id, "pose.bones", oldname, newname);
+ BKE_animdata_fix_paths_rename_all(&arm->id, "pose.bones", oldname, newname);
}
/* correct view locking */
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index c80953d6737..ea435e3e4fa 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -66,6 +66,7 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(ARMATURE_OT_delete);
WM_operatortype_append(ARMATURE_OT_duplicate);
+ WM_operatortype_append(ARMATURE_OT_symmetrize);
WM_operatortype_append(ARMATURE_OT_extrude);
WM_operatortype_append(ARMATURE_OT_hide);
WM_operatortype_append(ARMATURE_OT_reveal);
@@ -275,7 +276,7 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "ARMATURE_OT_merge", MKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_split", YKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_separate", PKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
+ WM_keymap_add_item(keymap, "ARMATURE_OT_separate", PKEY, KM_PRESS, 0, 0);
/* set flags */
WM_keymap_add_menu(keymap, "VIEW3D_MT_bone_options_toggle", WKEY, KM_PRESS, KM_SHIFT, 0);
@@ -411,5 +412,6 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
/* menus */
WM_keymap_add_menu(keymap, "VIEW3D_MT_pose_specials", WKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_pose_propagate", PKEY, KM_PRESS, KM_ALT, 0);
}
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 53989dd783c..8cda6f6db77 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -78,7 +78,7 @@ static void joined_armature_fix_links_constraints(
bConstraint *con;
for (con = lb->first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -380,7 +380,7 @@ int join_armature_exec(bContext *C, wmOperator *op)
if (base->object->adt) {
if (ob->adt == NULL) {
/* no animdata, so just use a copy of the whole thing */
- ob->adt = BKE_copy_animdata(base->object->adt, false);
+ ob->adt = BKE_animdata_copy(base->object->adt, false);
}
else {
/* merge in data - we'll fix the drivers manually */
@@ -391,7 +391,7 @@ int join_armature_exec(bContext *C, wmOperator *op)
if (curarm->adt) {
if (arm->adt == NULL) {
/* no animdata, so just use a copy of the whole thing */
- arm->adt = BKE_copy_animdata(curarm->adt, false);
+ arm->adt = BKE_animdata_copy(curarm->adt, false);
}
else {
/* merge in data - we'll fix the drivers manually */
@@ -435,7 +435,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm)
if (ob->type == OB_ARMATURE) {
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -473,7 +473,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm)
/* fix object-level constraints */
if (ob != origArm) {
for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -548,7 +548,7 @@ static void separate_armature_bones(Object *ob, short sel)
for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
if (ebo->parent == curbone) {
ebo->parent = NULL;
- ebo->temp = NULL; /* this is needed to prevent random crashes with in ED_armature_from_edit */
+ ebo->temp.p = NULL; /* this is needed to prevent random crashes with in ED_armature_from_edit */
ebo->flag &= ~BONE_CONNECTED;
}
}
@@ -641,6 +641,9 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
ED_armature_to_edit(obedit->data);
+ /* parents tips remain selected when connected children are removed. */
+ ED_armature_deselect_all(obedit);
+
BKE_report(op->reports, RPT_INFO, "Separated bones");
/* note, notifier might evolve */
@@ -660,6 +663,7 @@ void ARMATURE_OT_separate(wmOperatorType *ot)
ot->description = "Isolate selected bones into a separate armature";
/* callbacks */
+ ot->invoke = WM_operator_confirm;
ot->exec = separate_armature_exec;
ot->poll = ED_operator_editarmature;
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 581dd00e285..5aa2c628252 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -54,9 +54,9 @@
#include "armature_intern.h"
-/* utility macros fro storing a temp int in the bone (selection flag) */
-#define EBONE_PREV_FLAG_GET(ebone) ((void)0, (GET_INT_FROM_POINTER((ebone)->temp)))
-#define EBONE_PREV_FLAG_SET(ebone, val) ((ebone)->temp = SET_INT_IN_POINTER(val))
+/* utility macros for storing a temp int in the bone (selection flag) */
+#define EBONE_PREV_FLAG_GET(ebone) ((void)0, (ebone)->temp.i)
+#define EBONE_PREV_FLAG_SET(ebone, val) ((ebone)->temp.i = val)
/* **************** PoseMode & EditMode Selection Buffer Queries *************************** */
@@ -388,61 +388,14 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
return NULL;
}
-
-
-/* toggle==0: deselect
- * toggle==1: swap (based on test)
- * toggle==2: swap (no test), CURRENTLY UNUSED
- */
-void ED_armature_deselect_all(Object *obedit, int toggle)
+void ED_armature_deselect_all(Object *obedit)
{
bArmature *arm = obedit->data;
- EditBone *eBone;
- int sel = 1;
-
- if (toggle == 1) {
- /* Determine if there are any selected bones
- * and therefore whether we are selecting or deselecting */
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- // if (arm->layer & eBone->layer) {
- if (eBone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
- sel = 0;
- break;
- }
- // }
- }
- }
- else {
- sel = toggle;
- }
+ EditBone *ebone;
- /* Set the flags */
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- if (sel == 2) {
- /* invert selection of bone */
- if (EBONE_VISIBLE(arm, eBone)) {
- eBone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (arm->act_edbone == eBone)
- arm->act_edbone = NULL;
- }
- }
- else if (sel == 1) {
- /* select bone */
- if (EBONE_VISIBLE(arm, eBone)) {
- eBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (eBone->parent)
- eBone->parent->flag |= (BONE_TIPSEL);
- }
- }
- else {
- /* deselect bone */
- eBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (arm->act_edbone == eBone)
- arm->act_edbone = NULL;
- }
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
}
-
- ED_armature_sync_selection(arm->edbo);
}
void ED_armature_deselect_all_visible(Object *obedit)
@@ -489,8 +442,9 @@ bool mouse_armature(bContext *C, const int mval[2], bool extend, bool deselect,
nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, 1, &selmask);
if (nearBone) {
- if (!extend && !deselect && !toggle)
- ED_armature_deselect_all(obedit, 0);
+ if (!extend && !deselect && !toggle) {
+ ED_armature_deselect_all(obedit);
+ }
/* by definition the non-root connected bones have no root point drawn,
* so a root selection needs to be delivered to the parent tip */
@@ -731,7 +685,7 @@ static void armature_select_more_less(Object *ob, bool more)
}
}
}
- ebone->temp = NULL;
+ ebone->temp.p = NULL;
}
ED_armature_sync_selection(arm->edbo);
@@ -962,75 +916,78 @@ void ARMATURE_OT_select_similar(wmOperatorType *ot)
/* ********************* select hierarchy operator ************** */
-/* Get the first available child of an editbone */
-static EditBone *editbone_get_child(bArmature *arm, EditBone *pabone, short use_visibility)
-{
- EditBone *curbone, *chbone = NULL;
-
- for (curbone = arm->edbo->first; curbone; curbone = curbone->next) {
- if (curbone->parent == pabone) {
- if (use_visibility) {
- if ((arm->layer & curbone->layer) && !(pabone->flag & BONE_HIDDEN_A)) {
- chbone = curbone;
- }
- }
- else
- chbone = curbone;
- }
- }
-
- return chbone;
-}
-
static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
Object *ob;
bArmature *arm;
- EditBone *curbone, *pabone, *chbone;
+ EditBone *ebone_active;
int direction = RNA_enum_get(op->ptr, "direction");
const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
+ bool changed = false;
ob = obedit;
arm = (bArmature *)ob->data;
-
- for (curbone = arm->edbo->first; curbone; curbone = curbone->next) {
- /* only work on bone if it is visible and its selection can change */
- if (EBONE_SELECTABLE(arm, curbone)) {
- if (curbone == arm->act_edbone) {
- if (direction == BONE_SELECT_PARENT) {
- if (curbone->parent == NULL) continue;
- else pabone = curbone->parent;
-
- if (EBONE_VISIBLE(arm, pabone)) {
- pabone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_edbone = pabone;
- if (pabone->parent) pabone->parent->flag |= BONE_TIPSEL;
-
- if (!add_to_sel) curbone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- break;
- }
-
+
+ ebone_active = arm->act_edbone;
+ if (ebone_active == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (direction == BONE_SELECT_PARENT) {
+ if (ebone_active->parent) {
+ EditBone *ebone_parent;
+
+ ebone_parent = ebone_active->parent;
+
+ if (EBONE_SELECTABLE(arm, ebone_parent)) {
+ arm->act_edbone = ebone_parent;
+
+ if (!add_to_sel) {
+ ED_armature_ebone_select_set(ebone_active, false);
}
- else { // BONE_SELECT_CHILD
- chbone = editbone_get_child(arm, curbone, 1);
- if (chbone == NULL) continue;
-
- if (EBONE_SELECTABLE(arm, chbone)) {
- chbone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_edbone = chbone;
-
- if (!add_to_sel) {
- curbone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL);
- if (curbone->parent) curbone->parent->flag &= ~BONE_TIPSEL;
+ ED_armature_ebone_select_set(ebone_parent, true);
+
+ changed = true;
+ }
+ }
+
+ }
+ else { /* BONE_SELECT_CHILD */
+ EditBone *ebone_iter, *ebone_child = NULL;
+ int pass;
+
+ /* first pass, only connected bones (the logical direct child) */
+ for (pass = 0; pass < 2 && (ebone_child == NULL); pass++) {
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ /* possible we have multiple children, some invisible */
+ if (EBONE_SELECTABLE(arm, ebone_iter)) {
+ if (ebone_iter->parent == ebone_active) {
+ if ((pass == 1) || (ebone_iter->flag & BONE_CONNECTED)) {
+ ebone_child = ebone_iter;
+ break;
}
- break;
}
}
}
}
+
+ if (ebone_child) {
+ arm->act_edbone = ebone_child;
+
+ if (!add_to_sel) {
+ ED_armature_ebone_select_set(ebone_active, false);
+ }
+ ED_armature_ebone_select_set(ebone_child, true);
+
+ changed = true;
+ }
}
+ if (changed == false) {
+ return OPERATOR_CANCELLED;
+ }
+
ED_armature_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 97f69d86aee..eebdd706ab2 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -488,7 +488,7 @@ static void fix_bonelist_roll(ListBase *bonelist, ListBase *editbonelist)
/* Find the associated editbone */
for (ebone = editbonelist->first; ebone; ebone = ebone->next)
- if ((Bone *)ebone->temp == curBone)
+ if (ebone->temp.bone == curBone)
break;
if (ebone) {
@@ -548,7 +548,7 @@ void ED_armature_from_edit(bArmature *arm)
/* Copy the bones from the editData into the armature */
for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
newBone = MEM_callocN(sizeof(Bone), "bone");
- eBone->temp = newBone; /* Associate the real Bones with the EditBones */
+ eBone->temp.bone = newBone; /* Associate the real Bones with the EditBones */
BLI_strncpy(newBone->name, eBone->name, sizeof(newBone->name));
copy_v3_v3(newBone->arm_head, eBone->head);
@@ -584,9 +584,9 @@ void ED_armature_from_edit(bArmature *arm)
/* Fix parenting in a separate pass to ensure ebone->bone connections
* are valid at this point */
for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- newBone = (Bone *)eBone->temp;
+ newBone = eBone->temp.bone;
if (eBone->parent) {
- newBone->parent = (Bone *)eBone->parent->temp;
+ newBone->parent = eBone->parent->temp.bone;
BLI_addtail(&newBone->parent->childbase, newBone);
{
@@ -695,24 +695,24 @@ static void ED_armature_ebone_listbase_copy(ListBase *lb_dst, ListBase *lb_src)
if (ebone_dst->prop) {
ebone_dst->prop = IDP_CopyProperty(ebone_dst->prop);
}
- ebone_src->temp = ebone_dst;
+ ebone_src->temp.ebone = ebone_dst;
BLI_addtail(lb_dst, ebone_dst);
}
/* set pointers */
for (ebone_dst = lb_dst->first; ebone_dst; ebone_dst = ebone_dst->next) {
if (ebone_dst->parent) {
- ebone_dst->parent = ebone_dst->parent->temp;
+ ebone_dst->parent = ebone_dst->parent->temp.ebone;
}
}
}
-static void ED_armature_ebone_listbase_temp_clear(ListBase *lb)
+void ED_armature_ebone_listbase_temp_clear(ListBase *lb)
{
EditBone *ebone;
/* be sure they don't hang ever */
for (ebone = lb->first; ebone; ebone = ebone->next) {
- ebone->temp = NULL;
+ ebone->temp.p = NULL;
}
}
@@ -733,7 +733,7 @@ static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data))
/* active bone */
if (uarm->act_edbone) {
ebone = uarm->act_edbone;
- arm->act_edbone = ebone->temp;
+ arm->act_edbone = ebone->temp.ebone;
}
else {
arm->act_edbone = NULL;
@@ -755,7 +755,7 @@ static void *editBones_to_undoBones(void *armv, void *UNUSED(obdata))
/* active bone */
if (arm->act_edbone) {
ebone = arm->act_edbone;
- uarm->act_edbone = ebone->temp;
+ uarm->act_edbone = ebone->temp.ebone;
}
ED_armature_ebone_listbase_temp_clear(&uarm->lb);
@@ -785,7 +785,7 @@ static void *get_armature_edit(bContext *C)
void undo_push_armature(bContext *C, const char *name)
{
// XXX solve getdata()
- undo_editmode_push(C, name, get_armature_edit, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL);
+ undo_editmode_push(C, name, CTX_data_edit_object, get_armature_edit, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL);
}
/* *************************************************************** */
diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c
index 5376fc8c79b..2235f9f92cc 100644
--- a/source/blender/editors/armature/editarmature_retarget.c
+++ b/source/blender/editors/armature/editarmature_retarget.c
@@ -707,7 +707,7 @@ static void RIG_reconnectControlBones(RigGraph *rg)
/* DO SOME MAGIC HERE */
for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -832,7 +832,7 @@ static void RIG_reconnectControlBones(RigGraph *rg)
/* DO SOME MAGIC HERE */
for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index b7d14e089cf..c630ea6478a 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -127,12 +127,12 @@ struct LaplacianSystem {
static void laplacian_increase_edge_count(EdgeHash *edgehash, int v1, int v2)
{
- void **p = BLI_edgehash_lookup_p(edgehash, v1, v2);
+ void **p;
- if (p)
+ if (BLI_edgehash_ensure_p(edgehash, v1, v2, &p))
*p = (void *)((intptr_t)*p + (intptr_t)1);
else
- BLI_edgehash_insert(edgehash, v1, v2, (void *)(intptr_t)1);
+ *p = (void *)((intptr_t)1);
}
static int laplacian_edge_count(EdgeHash *edgehash, int v1, int v2)
@@ -1719,7 +1719,7 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind
/* sanity check */
for (b = 0; b < mdb->size3; b++)
if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR)
- if (fabs(mdb->totalphi[b] - 1.0f) > 1e-4)
+ if (fabsf(mdb->totalphi[b] - 1.0f) > 1e-4f)
printf("totalphi deficiency [%s|%d] %d: %.10f\n",
(mdb->tag[b] == MESHDEFORM_TAG_INTERIOR) ? "interior" : "boundary", mdb->semibound[b], mdb->varidx[b], mdb->totalphi[b]);
#endif
diff --git a/source/blender/editors/armature/meshlaplacian.h b/source/blender/editors/armature/meshlaplacian.h
index 820aedc5467..1412136c1a8 100644
--- a/source/blender/editors/armature/meshlaplacian.h
+++ b/source/blender/editors/armature/meshlaplacian.h
@@ -29,11 +29,9 @@
//#define RIGID_DEFORM
-struct Scene;
struct Object;
struct Mesh;
struct bDeformGroup;
-struct MeshDeformModifierData;
#ifdef RIGID_DEFORM
struct EditMesh;
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 549a3854bac..e87c324d7ec 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -436,7 +436,7 @@ static void pose_copy_menu(Scene *scene)
pchan->constflag |= pchanact->constflag;
if (ob->pose)
- ob->pose->flag |= POSE_RECALC;
+ BKE_pose_tag_recalc(bmain, ob->pose);
}
break;
case 6: /* Transform Locks */
@@ -550,7 +550,7 @@ static void pose_copy_menu(Scene *scene)
BKE_pose_update_constraint_flags(ob->pose); /* we could work out the flags but its simpler to do this */
if (ob->pose)
- ob->pose->flag |= POSE_RECALC;
+ BKE_pose_tag_recalc(bmain, ob->pose);
}
DAG_id_tag_update(&ob->id, OB_RECALC_DATA); // and all its relations
@@ -862,7 +862,7 @@ static int pose_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *e
/* loop over the bits for this pchan's layers, adding layers where they're needed */
for (bit = 0; bit < 32; bit++) {
- layers[bit] = (pchan->bone->layer & (1 << bit)) != 0;
+ layers[bit] = (pchan->bone->layer & (1u << bit)) != 0;
}
}
CTX_DATA_END;
@@ -936,8 +936,9 @@ static int armature_bone_layers_invoke(bContext *C, wmOperator *op, const wmEven
/* loop over the bits for this pchan's layers, adding layers where they're needed */
for (bit = 0; bit < 32; bit++) {
- if (ebone->layer & (1 << bit))
+ if (ebone->layer & (1u << bit)) {
layers[bit] = 1;
+ }
}
}
CTX_DATA_END;
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
index 413a74d24b5..4d9df06f33f 100644
--- a/source/blender/editors/armature/pose_group.c
+++ b/source/blender/editors/armature/pose_group.c
@@ -130,6 +130,7 @@ static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U
{
Object *ob = ED_pose_object_from_context(C);
bPose *pose;
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "type");
uiPopupMenu *pup;
uiLayout *layout;
@@ -140,6 +141,17 @@ static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U
if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
pose = ob->pose;
+
+ /* If group index is set, try to use it! */
+ if (RNA_property_is_set(op->ptr, prop)) {
+ const int num_groups = BLI_listbase_count(&pose->agroups);
+ const int group = RNA_property_int_get(op->ptr, prop);
+
+ /* just use the active group index, and call the exec callback for the calling operator */
+ if (group > 0 && group <= num_groups) {
+ return op->type->exec(C, op);
+ }
+ }
/* if there's no active group (or active is invalid), create a new menu to find it */
if (pose->active_group <= 0) {
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 5d5a9bf363c..3bac50ef3ed 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -62,7 +62,7 @@
#include "armature_intern.h"
-/* utility macros fro storing a temp int in the bone (selection flag) */
+/* utility macros for storing a temp int in the bone (selection flag) */
#define PBONE_PREV_FLAG_GET(pchan) ((void)0, (GET_INT_FROM_POINTER((pchan)->temp)))
#define PBONE_PREV_FLAG_SET(pchan, val) ((pchan)->temp = SET_INT_IN_POINTER(val))
@@ -458,7 +458,7 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
{
if (pchan->bone->flag & BONE_SELECTED) {
for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -518,71 +518,67 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
bArmature *arm = ob->data;
- Bone *curbone, *pabone, *chbone;
+ bPoseChannel *pchan_act;
int direction = RNA_enum_get(op->ptr, "direction");
const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
- bool found = false;
+ bool changed = false;
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- curbone = pchan->bone;
-
- if ((curbone->flag & BONE_UNSELECTABLE) == 0) {
- if (curbone == arm->act_bone) {
- if (direction == BONE_SELECT_PARENT) {
- if (pchan->parent == NULL) continue;
- else pabone = pchan->parent->bone;
-
- if (PBONE_SELECTABLE(arm, pabone)) {
- if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
- pabone->flag |= BONE_SELECTED;
- arm->act_bone = pabone;
-
- found = 1;
- break;
- }
+ pchan_act = BKE_pose_channel_active(ob);
+ if (pchan_act == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (direction == BONE_SELECT_PARENT) {
+ if (pchan_act->parent) {
+ Bone *bone_parent;
+ bone_parent = pchan_act->parent->bone;
+
+ if (PBONE_SELECTABLE(arm, bone_parent)) {
+ if (!add_to_sel) {
+ pchan_act->bone->flag &= ~BONE_SELECTED;
}
- else { /* direction == BONE_SELECT_CHILD */
- /* the child member is only assigned to connected bones, see [#30340] */
-#if 0
- if (pchan->child == NULL) continue;
- else chbone = pchan->child->bone;
-#else
- /* instead. find _any_ visible child bone, using the first one is a little arbitrary - campbell */
- chbone = pchan->child ? pchan->child->bone : NULL;
- if (chbone == NULL) {
- bPoseChannel *pchan_child;
-
- for (pchan_child = ob->pose->chanbase.first; pchan_child; pchan_child = pchan_child->next) {
- /* possible we have multiple children, some invisible */
- if (PBONE_SELECTABLE(arm, pchan_child->bone)) {
- if (pchan_child->parent == pchan) {
- chbone = pchan_child->bone;
- break;
- }
- }
- }
- }
+ bone_parent->flag |= BONE_SELECTED;
+ arm->act_bone = bone_parent;
- if (chbone == NULL) continue;
-#endif
-
- if (PBONE_SELECTABLE(arm, chbone)) {
- if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
- chbone->flag |= BONE_SELECTED;
- arm->act_bone = chbone;
-
- found = 1;
- break;
+ changed = true;
+ }
+ }
+ }
+ else { /* direction == BONE_SELECT_CHILD */
+ bPoseChannel *pchan_iter;
+ Bone *bone_child = NULL;
+ int pass;
+
+ /* first pass, only connected bones (the logical direct child) */
+ for (pass = 0; pass < 2 && (bone_child == NULL); pass++) {
+ for (pchan_iter = ob->pose->chanbase.first; pchan_iter; pchan_iter = pchan_iter->next) {
+ /* possible we have multiple children, some invisible */
+ if (PBONE_SELECTABLE(arm, pchan_iter->bone)) {
+ if (pchan_iter->parent == pchan_act) {
+ if ((pass == 1) || (pchan_iter->bone->flag & BONE_CONNECTED)) {
+ bone_child = pchan_iter->bone;
+ break;
+ }
}
}
}
}
+
+ if (bone_child) {
+ arm->act_bone = bone_child;
+
+ if (!add_to_sel) {
+ pchan_act->bone->flag &= ~BONE_SELECTED;
+ }
+ bone_child->flag |= BONE_SELECTED;
+
+ changed = true;
+ }
}
- CTX_DATA_END;
- if (found == 0)
+ if (changed == false) {
return OPERATOR_CANCELLED;
+ }
/* updates */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 5f9f24d23a4..1a1108a2b1c 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -43,6 +43,7 @@
#include "BKE_context.h"
#include "BKE_object.h"
#include "BKE_report.h"
+#include "BKE_unit.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -53,6 +54,7 @@
#include "ED_armature.h"
#include "ED_keyframes_draw.h"
#include "ED_markers.h"
+#include "ED_numinput.h"
#include "ED_screen.h"
#include "armature_intern.h"
@@ -98,6 +100,8 @@ typedef struct tPoseSlideOp {
int flag; /* unused for now, but can later get used for storing runtime settings.... */
float percentage; /* 0-1 value for determining the influence of whatever is relevant */
+
+ NumInput num; /* numeric input */
} tPoseSlideOp;
/* Pose Sliding Modes */
@@ -154,6 +158,12 @@ static int pose_slide_init(bContext *C, wmOperator *op, short mode)
*/
BLI_dlrbTree_init(&pso->keys);
+ /* initialise numeric input */
+ initNumInput(&pso->num);
+ pso->num.idx_max = 0; /* one axis */
+ pso->num.val_flag[0] |= NUM_NO_NEGATIVE;
+ pso->num.unit_type[0] = B_UNIT_NONE; /* percentages don't have any units... */
+
/* return status is whether we've got all the data we were requested to get */
return 1;
}
@@ -201,6 +211,12 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val)
/* next/end */
eVal = evaluate_fcurve(fcu, (float)pso->nextFrame);
+ /* if both values are equal, don't do anything */
+ if (IS_EQF(sVal, eVal)) {
+ (*val) = sVal;
+ return;
+ }
+
/* calculate the relative weights of the endpoints */
if (pso->mode == POSESLIDE_BREAKDOWN) {
/* get weights from the percentage control */
@@ -234,7 +250,7 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val)
* - perform this weighting a number of times given by the percentage...
*/
int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */
-
+
while (iters-- > 0) {
(*val) = (-((sVal * w2) + (eVal * w1)) + ((*val) * 6.0f) ) / 5.0f;
}
@@ -247,7 +263,7 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val)
* - perform this weighting a number of times given by the percentage...
*/
int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */
-
+
while (iters-- > 0) {
(*val) = ( ((sVal * w2) + (eVal * w1)) + ((*val) * 5.0f) ) / 6.0f;
}
@@ -320,6 +336,7 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
if (prop) {
switch (RNA_property_type(prop)) {
+ /* continuous values that can be smoothly interpolated... */
case PROP_FLOAT:
{
float tval = RNA_property_float_get(&ptr, prop);
@@ -327,8 +344,6 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
RNA_property_float_set(&ptr, prop, tval);
break;
}
- case PROP_BOOLEAN:
- case PROP_ENUM:
case PROP_INT:
{
float tval = (float)RNA_property_int_get(&ptr, prop);
@@ -336,6 +351,23 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
RNA_property_int_set(&ptr, prop, (int)tval);
break;
}
+
+ /* values which can only take discrete values */
+ case PROP_BOOLEAN:
+ {
+ float tval = (float)RNA_property_boolean_get(&ptr, prop);
+ pose_slide_apply_val(pso, fcu, &tval);
+ RNA_property_boolean_set(&ptr, prop, (int)tval); // XXX: do we need threshold clamping here?
+ break;
+ }
+ case PROP_ENUM:
+ {
+ /* don't handle this case - these don't usually represent interchangeable
+ * set of values which should be interpolated between
+ */
+ break;
+ }
+
default:
/* cannot handle */
//printf("Cannot Pose Slide non-numerical property\n");
@@ -404,11 +436,11 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
}
else if (pso->mode == POSESLIDE_PUSH) {
float quat_diff[4], quat_orig[4];
-
+
/* calculate the delta transform from the previous to the current */
/* TODO: investigate ways to favour one transform more? */
sub_qt_qtqt(quat_diff, pchan->quat, quat_prev);
-
+
/* make a copy of the original rotation */
copy_qt_qt(quat_orig, pchan->quat);
@@ -418,7 +450,7 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
else {
float quat_interp[4], quat_orig[4];
int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */
-
+
/* perform this blending several times until a satisfactory result is reached */
while (iters-- > 0) {
/* calculate the interpolation between the endpoints */
@@ -512,7 +544,7 @@ static void pose_slide_reset(tPoseSlideOp *pso)
/* draw percentage indicator in header */
static void pose_slide_draw_status(tPoseSlideOp *pso)
{
- char status_str[32];
+ char status_str[256];
char mode_str[32];
switch (pso->mode) {
@@ -532,7 +564,18 @@ static void pose_slide_draw_status(tPoseSlideOp *pso)
break;
}
- BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(pso->percentage * 100.0f));
+ if (hasNumInput(&pso->num)) {
+ Scene *scene = pso->scene;
+ char str_offs[NUM_STR_REP_LEN];
+
+ outputNumInput(&pso->num, str_offs, &scene->unit);
+
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_offs);
+ }
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(pso->percentage * 100.0f));
+ }
+
ED_area_headerprint(pso->sa, status_str);
}
@@ -617,6 +660,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
tPoseSlideOp *pso = op->customdata;
wmWindow *win = CTX_wm_window(C);
+ const bool has_numinput = hasNumInput(&pso->num);
switch (event->type) {
case LEFTMOUSE: /* confirm */
@@ -656,25 +700,54 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
case MOUSEMOVE: /* calculate new position */
{
- /* calculate percentage based on position of mouse (we only use x-axis for now.
- * since this is more convenient for users to do), and store new percentage value
- */
- pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
- RNA_float_set(op->ptr, "percentage", pso->percentage);
-
- /* update percentage indicator in header */
- pose_slide_draw_status(pso);
-
- /* reset transforms (to avoid accumulation errors) */
- pose_slide_reset(pso);
-
- /* apply... */
- pose_slide_apply(C, pso);
+ /* only handle mousemove if not doing numinput */
+ if (has_numinput == false) {
+ /* calculate percentage based on position of mouse (we only use x-axis for now.
+ * since this is more convenient for users to do), and store new percentage value
+ */
+ pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
+ RNA_float_set(op->ptr, "percentage", pso->percentage);
+
+ /* update percentage indicator in header */
+ pose_slide_draw_status(pso);
+
+ /* reset transforms (to avoid accumulation errors) */
+ pose_slide_reset(pso);
+
+ /* apply... */
+ pose_slide_apply(C, pso);
+ }
break;
}
- default: /* unhandled event (maybe it was some view manip? */
- /* allow to pass through */
- return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ default:
+ if ((event->val == KM_PRESS) && handleNumInput(C, &pso->num, event)) {
+ float value;
+
+ /* Grab percentage from numeric input, and store this new value for redo
+ * NOTE: users see ints, while internally we use a 0-1 float
+ */
+ value = pso->percentage * 100.0f;
+ applyNumInput(&pso->num, &value);
+
+ pso->percentage = value / 100.0f;
+ CLAMP(pso->percentage, 0.0f, 1.0f);
+ RNA_float_set(op->ptr, "percentage", pso->percentage);
+
+ /* update percentage indicator in header */
+ pose_slide_draw_status(pso);
+
+ /* reset transforms (to avoid accumulation errors) */
+ pose_slide_reset(pso);
+
+ /* apply... */
+ pose_slide_apply(C, pso);
+ break;
+ }
+ else {
+ /* unhandled event - maybe it was some view manip? */
+ /* allow to pass through */
+ return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ }
}
/* still running... */
@@ -898,6 +971,8 @@ typedef enum ePosePropagate_Termination {
/* stop when we run out of keyframes */
POSE_PROPAGATE_BEFORE_END,
+ /* only do on keyframes that are selected */
+ POSE_PROPAGATE_SELECTED_KEYS,
/* only do on the frames where markers are selected */
POSE_PROPAGATE_SELECTED_MARKERS
} ePosePropagate_Termination;
@@ -1137,6 +1212,11 @@ static void pose_propagate_fcurve(wmOperator *op, Object *ob, FCurve *fcu,
if (ce == NULL)
continue;
}
+ else if (mode == POSE_PROPAGATE_SELECTED_KEYS) {
+ /* only allow if this keyframe is already selected - skip otherwise */
+ if (BEZSELECTED(bezt) == 0)
+ continue;
+ }
/* just flatten handles, since values will now be the same either side... */
/* TODO: perhaps a fade-out modulation of the value is required here (optional once again)? */
@@ -1219,12 +1299,20 @@ static int pose_propagate_exec(bContext *C, wmOperator *op)
void POSE_OT_propagate(wmOperatorType *ot)
{
static EnumPropertyItem terminate_items[] = {
- {POSE_PROPAGATE_SMART_HOLDS, "WHILE_HELD", 0, "While Held", "Propagate pose to all keyframes after current frame that don't change (Default behavior)"},
- {POSE_PROPAGATE_NEXT_KEY, "NEXT_KEY", 0, "To Next Keyframe", "Propagate pose to first keyframe following the current frame only"},
- {POSE_PROPAGATE_LAST_KEY, "LAST_KEY", 0, "To Last Keyframe", "Propagate pose to the last keyframe only (i.e. making action cyclic)"},
- {POSE_PROPAGATE_BEFORE_FRAME, "BEFORE_FRAME", 0, "Before Frame", "Propagate pose to all keyframes between current frame and 'Frame' property"},
- {POSE_PROPAGATE_BEFORE_END, "BEFORE_END", 0, "Before Last Keyframe", "Propagate pose to all keyframes from current frame until no more are found"},
- {POSE_PROPAGATE_SELECTED_MARKERS, "SELECTED_MARKERS", 0, "On Selected Markers", "Propagate pose to all keyframes occurring on frames with Scene Markers after the current frame"},
+ {POSE_PROPAGATE_SMART_HOLDS, "WHILE_HELD", 0, "While Held",
+ "Propagate pose to all keyframes after current frame that don't change (Default behavior)"},
+ {POSE_PROPAGATE_NEXT_KEY, "NEXT_KEY", 0, "To Next Keyframe",
+ "Propagate pose to first keyframe following the current frame only"},
+ {POSE_PROPAGATE_LAST_KEY, "LAST_KEY", 0, "To Last Keyframe",
+ "Propagate pose to the last keyframe only (i.e. making action cyclic)"},
+ {POSE_PROPAGATE_BEFORE_FRAME, "BEFORE_FRAME", 0, "Before Frame",
+ "Propagate pose to all keyframes between current frame and 'Frame' property"},
+ {POSE_PROPAGATE_BEFORE_END, "BEFORE_END", 0, "Before Last Keyframe",
+ "Propagate pose to all keyframes from current frame until no more are found"},
+ {POSE_PROPAGATE_SELECTED_KEYS, "SELECTED_KEYS", 0, "On Selected Keyframes",
+ "Propagate pose to all selected keyframes"},
+ {POSE_PROPAGATE_SELECTED_MARKERS, "SELECTED_MARKERS", 0, "On Selected Markers",
+ "Propagate pose to all keyframes occurring on frames with Scene Markers after the current frame"},
{0, NULL, 0, NULL, NULL}};
/* identifiers */
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index fbf6dccdb38..01e16df9f08 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -320,7 +320,7 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bo
if (selOnly)
paste_ok = ((pchan) && (pchan->bone->flag & BONE_SELECTED));
else
- paste_ok = ((pchan != NULL));
+ paste_ok = (pchan != NULL);
/* continue? */
if (paste_ok) {
diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index 0b449c4334d..1b877c0fba9 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -38,7 +38,6 @@ set(SRC
editcurve.c
editcurve_add.c
editfont.c
- lorem.c
curve_intern.h
)
diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index d54db77754f..579f149ea8b 100644
--- a/source/blender/editors/curve/curve_intern.h
+++ b/source/blender/editors/curve/curve_intern.h
@@ -38,9 +38,6 @@ struct EditNurb;
struct Object;
struct wmOperatorType;
-/* lorem.c */
-extern const char ED_lorem[];
-
/* editfont.c */
enum { DEL_ALL, DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_SELECTION, DEL_NEXT_SEL, DEL_PREV_SEL };
enum { CASE_LOWER, CASE_UPPER };
diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c
index 0f42dc923a4..4bcb16d31ef 100644
--- a/source/blender/editors/curve/curve_ops.c
+++ b/source/blender/editors/curve/curve_ops.c
@@ -54,7 +54,6 @@ void ED_operatortypes_curve(void)
{
WM_operatortype_append(FONT_OT_text_insert);
WM_operatortype_append(FONT_OT_line_break);
- WM_operatortype_append(FONT_OT_insert_lorem);
WM_operatortype_append(FONT_OT_case_toggle);
WM_operatortype_append(FONT_OT_case_set);
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index a4c071d88a7..37a39f7c272 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -327,17 +327,17 @@ static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase)
editnurb->keyindex = gh;
}
-static CVKeyIndex *getCVKeyIndex(EditNurb *editnurb, void *cv)
+static CVKeyIndex *getCVKeyIndex(EditNurb *editnurb, const void *cv)
{
return BLI_ghash_lookup(editnurb->keyindex, cv);
}
-static CVKeyIndex *popCVKeyIndex(EditNurb *editnurb, void *cv)
+static CVKeyIndex *popCVKeyIndex(EditNurb *editnurb, const void *cv)
{
return BLI_ghash_popkey(editnurb->keyindex, cv, NULL);
}
-static BezTriple *getKeyIndexOrig_bezt(EditNurb *editnurb, BezTriple *bezt)
+static BezTriple *getKeyIndexOrig_bezt(EditNurb *editnurb, const BezTriple *bezt)
{
CVKeyIndex *index = getCVKeyIndex(editnurb, bezt);
@@ -370,7 +370,7 @@ static int getKeyIndexOrig_keyIndex(EditNurb *editnurb, void *cv)
return index->key_index;
}
-static void keyIndex_delCV(EditNurb *editnurb, void *cv)
+static void keyIndex_delCV(EditNurb *editnurb, const void *cv)
{
if (!editnurb->keyindex) {
return;
@@ -398,7 +398,7 @@ static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
}
if (nu->bezt) {
- BezTriple *bezt = nu->bezt;
+ const BezTriple *bezt = nu->bezt;
a = nu->pntsu;
while (a--) {
@@ -407,7 +407,7 @@ static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu)
}
}
else {
- BPoint *bp = nu->bp;
+ const BPoint *bp = nu->bp;
a = nu->pntsu * nu->pntsv;
while (a--) {
@@ -1188,7 +1188,7 @@ static int *initialize_index_map(Object *obedit, int *r_old_totvert)
while (a--) {
keyIndex = getCVKeyIndex(editnurb, bezt);
- if (keyIndex) {
+ if (keyIndex && keyIndex->vertex_index + 2 < old_totvert) {
if (keyIndex->switched) {
old_to_new_map[keyIndex->vertex_index] = vertex_index + 2;
old_to_new_map[keyIndex->vertex_index + 1] = vertex_index + 1;
@@ -1538,6 +1538,7 @@ void CURVE_OT_separate(wmOperatorType *ot)
ot->description = "Separate selected points from connected unselected points into a new object";
/* api callbacks */
+ ot->invoke = WM_operator_confirm;
ot->exec = separate_exec;
ot->poll = ED_operator_editsurfcurve;
@@ -4901,6 +4902,10 @@ static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb)
void *p;
} cu_actvert;
+ if (BLI_listbase_is_empty(&editnurb->nurbs)) {
+ return changed;
+ }
+
BKE_curve_nurb_vert_active_get(cu, &cu_actnu, &cu_actvert.p);
BKE_curve_nurb_vert_active_set(cu, NULL, NULL);
@@ -6138,7 +6143,7 @@ void CURVE_OT_select_random(wmOperatorType *ot)
/********************* every nth number of point *******************/
-static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth)
+static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth, int skip, int offset)
{
int a, start;
@@ -6147,7 +6152,8 @@ static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth)
bezt = &nu->bezt[a - 1];
while (a--) {
- if (abs(start - a) % nth) {
+ const int depth = abs(start - a);
+ if ((offset + depth) % (skip + nth) >= skip) {
select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
}
@@ -6155,10 +6161,10 @@ static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth)
}
}
-static void select_nth_bp(Nurb *nu, BPoint *bp, int nth)
+static void select_nth_bp(Nurb *nu, BPoint *bp, int nth, int skip, int offset)
{
int a, startrow, startpnt;
- int dist, row, pnt;
+ int row, pnt;
startrow = (bp - nu->bp) / nu->pntsu;
startpnt = (bp - nu->bp) % nu->pntsu;
@@ -6169,8 +6175,8 @@ static void select_nth_bp(Nurb *nu, BPoint *bp, int nth)
pnt = nu->pntsu - 1;
while (a--) {
- dist = abs(pnt - startpnt) + abs(row - startrow);
- if (dist % nth) {
+ const int depth = abs(pnt - startpnt) + abs(row - startrow);
+ if ((offset + depth) % (skip + nth) >= skip) {
select_bpoint(bp, DESELECT, SELECT, HIDDEN);
}
@@ -6184,7 +6190,7 @@ static void select_nth_bp(Nurb *nu, BPoint *bp, int nth)
}
}
-bool ED_curve_select_nth(Curve *cu, int nth)
+bool ED_curve_select_nth(Curve *cu, int nth, int skip, int offset)
{
Nurb *nu = NULL;
void *vert = NULL;
@@ -6193,10 +6199,10 @@ bool ED_curve_select_nth(Curve *cu, int nth)
return false;
if (nu->bezt) {
- select_nth_bezt(nu, vert, nth);
+ select_nth_bezt(nu, vert, nth, skip, offset);
}
else {
- select_nth_bp(nu, vert, nth);
+ select_nth_bp(nu, vert, nth, skip, offset);
}
return true;
@@ -6205,9 +6211,14 @@ bool ED_curve_select_nth(Curve *cu, int nth)
static int select_nth_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
- int nth = RNA_int_get(op->ptr, "nth");
+ const int nth = RNA_int_get(op->ptr, "nth") - 1;
+ const int skip = RNA_int_get(op->ptr, "skip");
+ int offset = RNA_int_get(op->ptr, "offset");
+
+ /* so input of offset zero ends up being (nth - 1) */
+ offset = mod_i(offset, nth + skip);
- if (!ED_curve_select_nth(obedit->data, nth)) {
+ if (!ED_curve_select_nth(obedit->data, nth, skip, offset)) {
if (obedit->type == OB_SURF) {
BKE_report(op->reports, RPT_ERROR, "Surface has not got active point");
}
@@ -6238,6 +6249,8 @@ void CURVE_OT_select_nth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_int(ot->srna, "nth", 2, 2, INT_MAX, "Nth Selection", "", 2, 100);
+ RNA_def_int(ot->srna, "skip", 1, 1, INT_MAX, "Skip", "", 1, 100);
+ RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "", -100, 100);
}
/********************** add duplicate operator *********************/
@@ -7075,7 +7088,7 @@ static void *get_data(bContext *C)
/* and this is all the undo system needs to know */
void undo_push_curve(bContext *C, const char *name)
{
- undo_editmode_push(C, name, get_data, free_undoCurve, undoCurve_to_editCurve, editCurve_to_undoCurve, NULL);
+ undo_editmode_push(C, name, CTX_data_edit_object, get_data, free_undoCurve, undoCurve_to_editCurve, editCurve_to_undoCurve, NULL);
}
void ED_curve_beztcpy(EditNurb *editnurb, BezTriple *dst, BezTriple *src, int count)
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index 7c53896b969..555a53ae532 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -121,7 +121,7 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type
const float grid = 1.0f;
const int cutype = (type & CU_TYPE); // poly, bezier, nurbs, etc
const int stype = (type & CU_PRIMITIVE);
- const int force_3d = ((Curve *)obedit->data)->flag & CU_3D; /* could be adding to an existing 3D curve */
+ const bool force_3d = (((Curve *)obedit->data)->flag & CU_3D) != 0; /* could be adding to an existing 3D curve */
unit_m4(umat);
unit_m4(viewmat);
@@ -488,9 +488,10 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
if (!isSurf) { /* adding curve */
if (obedit == NULL || obedit->type != OB_CURVE) {
+ const char *name = get_curve_defname(type);
Curve *cu;
- obedit = ED_object_add_type(C, OB_CURVE, loc, rot, true, layer);
+ obedit = ED_object_add_type(C, OB_CURVE, name, loc, rot, true, layer);
newob = true;
cu = (Curve *)obedit->data;
@@ -505,7 +506,8 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
}
else { /* adding surface */
if (obedit == NULL || obedit->type != OB_SURF) {
- obedit = ED_object_add_type(C, OB_SURF, loc, rot, true, layer);
+ const char *name = get_surf_defname(type);
+ obedit = ED_object_add_type(C, OB_SURF, name, loc, rot, true, layer);
newob = true;
}
else {
@@ -513,18 +515,6 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
}
}
- /* rename here, the undo stack checks name for valid undo pushes */
- if (newob) {
- if (obedit->type == OB_CURVE) {
- rename_id((ID *)obedit, get_curve_defname(type));
- rename_id((ID *)obedit->data, get_curve_defname(type));
- }
- else {
- rename_id((ID *)obedit, get_surf_defname(type));
- rename_id((ID *)obedit->data, get_surf_defname(type));
- }
- }
-
/* ED_object_add_type doesnt do an undo, is needed for redo operator on primitive */
if (newob && enter_editmode)
ED_undo_push(C, "Enter Editmode");
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 8393acc6919..a4f5c250b0f 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -275,57 +275,6 @@ static void text_update_edited(bContext *C, Object *obedit, int mode)
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
}
-/********************** insert lorem operator *********************/
-
-static int insert_lorem_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit = CTX_data_edit_object(C);
- const char *p, *p2;
- int i;
- static const char *lastlorem = NULL;
-
- if (lastlorem)
- p = lastlorem;
- else
- p = ED_lorem;
-
- i = rand() / (RAND_MAX / 6) + 4;
-
- for (p2 = p; *p2 && i; p2++) {
- insert_into_textbuf(obedit, *p2);
-
- if (*p2 == '.')
- i--;
- }
-
- lastlorem = p2 + 1;
- if (strlen(lastlorem) < 5)
- lastlorem = ED_lorem;
-
- insert_into_textbuf(obedit, '\n');
- insert_into_textbuf(obedit, '\n');
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void FONT_OT_insert_lorem(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Insert Lorem";
- ot->description = "Insert placeholder text";
- ot->idname = "FONT_OT_insert_lorem";
-
- /* api callbacks */
- ot->exec = insert_lorem_exec;
- ot->poll = ED_operator_editfont;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/* -------------------------------------------------------------------- */
/* Generic Paste Functions */
@@ -577,7 +526,7 @@ static void txt_add_object(bContext *C, TextLine *firstline, int totline, const
int a;
float rot[3] = {0.f, 0.f, 0.f};
- obedit = BKE_object_add(bmain, scene, OB_FONT);
+ obedit = BKE_object_add(bmain, scene, OB_FONT, NULL);
base = scene->basact;
/* seems to assume view align ? TODO - look into this, could be an operator option */
@@ -1417,7 +1366,7 @@ static int insert_text_invoke(bContext *C, wmOperator *op, const wmEvent *event)
accentcode = 0;
}
else if (event->utf8_buf[0]) {
- BLI_strncpy_wchar_from_utf8(inserted_text, event->utf8_buf, 2);
+ inserted_text[0] = BLI_str_utf8_as_unicode(event->utf8_buf);
ascii = inserted_text[0];
insert_into_textbuf(obedit, ascii);
accentcode = 0;
@@ -1930,7 +1879,7 @@ static void *get_undoFont(bContext *C)
/* and this is all the undo system needs to know */
void undo_push_font(bContext *C, const char *name)
{
- undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL);
+ undo_editmode_push(C, name, CTX_data_edit_object, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL);
}
/**
diff --git a/source/blender/editors/curve/lorem.c b/source/blender/editors/curve/lorem.c
deleted file mode 100644
index 59bf3f50dbc..00000000000
--- a/source/blender/editors/curve/lorem.c
+++ /dev/null
@@ -1,658 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/curve/lorem.c
- * \ingroup edcurve
- */
-
-
-#include "BLI_sys_types.h"
-#include "curve_intern.h"
-
-const char ED_lorem[] = {
-76, 111, 114, 101, 109, 32, 105, 112, 115, 117, 109, 32, 100, 111, 108, 111, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 99,
-111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 32, 97, 100, 105, 112, 105, 115, 99, 105, 110, 103, 32, 101, 108, 105, 116, 46, 32, 65, 108, 105,
-113, 117, 97, 109, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 115, 101, 109, 46, 32, 78, 117, 108,
-108, 97, 109, 32, 112, 114, 101, 116, 105, 117, 109, 44, 32, 116, 111, 114, 116, 111, 114, 32, 110, 111, 110, 32, 101, 117, 105, 115, 109, 111, 100, 32,
-118, 97, 114, 105, 117, 115, 44, 32, 110, 117, 108, 108, 97, 32, 111, 100, 105, 111, 32, 115, 111, 100, 97, 108, 101, 115, 32, 110, 117, 108, 108, 97,
-44, 32, 97, 116, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 108, 111, 114, 101, 109, 32, 109, 101, 116, 117, 115, 32, 115, 101, 100, 32, 110, 117,
-108, 108, 97, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 105, 110, 32, 108, 101, 99, 116, 117, 115, 32, 97, 116, 32, 112, 101, 100,
-101, 32, 98, 108, 97, 110, 100, 105, 116, 32, 118, 105, 118, 101, 114, 114, 97, 46, 32, 70, 117, 115, 99, 101, 32, 115, 99, 101, 108, 101, 114, 105,
-115, 113, 117, 101, 32, 105, 112, 115, 117, 109, 32, 110, 101, 99, 32, 101, 110, 105, 109, 46, 32, 70, 117, 115, 99, 101, 32, 101, 117, 105, 115, 109,
-111, 100, 32, 110, 117, 110, 99, 32, 105, 100, 32, 101, 110, 105, 109, 46, 32, 73, 110, 32, 118, 101, 110, 101, 110, 97, 116, 105, 115, 32, 99, 117,
-114, 115, 117, 115, 32, 97, 114, 99, 117, 46, 32, 65, 101, 110, 101, 97, 110, 32, 113, 117, 105, 115, 32, 100, 117, 105, 46, 32, 77, 97, 101, 99,
-101, 110, 97, 115, 32, 108, 97, 111, 114, 101, 101, 116, 46, 32, 78, 117, 108, 108, 97, 32, 116, 101, 109, 112, 111, 114, 44, 32, 97, 114, 99, 117,
-32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 112, 114, 101, 116, 105, 117, 109, 32, 115, 117, 115, 99, 105, 112, 105, 116, 44, 32, 116, 111, 114, 116,
-111, 114, 32, 119, 105, 115, 105, 32, 100, 97, 112, 105, 98, 117, 115, 32, 108, 105, 98, 101, 114, 111, 44, 32, 105, 100, 32, 111, 114, 110, 97, 114,
-101, 32, 102, 101, 108, 105, 115, 32, 105, 112, 115, 117, 109, 32, 115, 117, 115, 99, 105, 112, 105, 116, 32, 112, 117, 114, 117, 115, 46, 32, 77, 97,
-101, 99, 101, 110, 97, 115, 32, 105, 112, 115, 117, 109, 46, 32, 77, 111, 114, 98, 105, 32, 99, 117, 114, 115, 117, 115, 46, 32, 86, 101, 115, 116,
-105, 98, 117, 108, 117, 109, 32, 100, 105, 97, 109, 32, 112, 117, 114, 117, 115, 44, 32, 99, 111, 109, 109, 111, 100, 111, 32, 101, 116, 44, 32, 99,
-111, 110, 118, 97, 108, 108, 105, 115, 32, 101, 117, 44, 32, 112, 111, 115, 117, 101, 114, 101, 32, 97, 116, 44, 32, 108, 105, 103, 117, 108, 97, 46,
-32, 78, 117, 108, 108, 97, 32, 97, 108, 105, 113, 117, 97, 109, 32, 97, 108, 105, 113, 117, 101, 116, 32, 108, 111, 114, 101, 109, 46, 32, 78, 117,
-110, 99, 32, 101, 116, 32, 109, 97, 117, 114, 105, 115, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 101, 115, 116, 32, 98, 105, 98, 101, 110,
-100, 117, 109, 32, 115, 117, 115, 99, 105, 112, 105, 116, 46, 32, 68, 111, 110, 101, 99, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101,
-32, 108, 105, 98, 101, 114, 111, 32, 101, 117, 32, 110, 105, 115, 108, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 101, 103,
-101, 116, 32, 108, 105, 98, 101, 114, 111, 46, 32, 68, 111, 110, 101, 99, 32, 116, 101, 109, 112, 117, 115, 32, 105, 112, 115, 117, 109, 32, 115, 101,
-100, 32, 113, 117, 97, 109, 46, 32, 83, 101, 100, 32, 98, 108, 97, 110, 100, 105, 116, 32, 110, 117, 110, 99, 32, 113, 117, 105, 115, 32, 101, 110,
-105, 109, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 108, 101, 99, 116, 117, 115, 32, 100, 105, 97, 109, 44, 32, 97, 100, 105, 112, 105, 115, 99,
-105, 110, 103, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 44, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 110, 111, 110, 44, 32, 112, 117, 108,
-118, 105, 110, 97, 114, 32, 105, 100, 44, 32, 102, 101, 108, 105, 115, 46, 32, 73, 110, 32, 99, 111, 110, 103, 117, 101, 32, 109, 97, 103, 110, 97,
-32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 117, 114, 110, 97, 46, 32, 78, 117, 110, 99, 32, 110, 111, 110, 32, 97, 117, 103, 117, 101, 32, 115,
-101, 100, 32, 110, 105, 115, 108, 32, 100, 105, 99, 116, 117, 109, 32, 108, 97, 111, 114, 101, 101, 116, 46, 32, 67, 117, 109, 32, 115, 111, 99, 105,
-105, 115, 32, 110, 97, 116, 111, 113, 117, 101, 32, 112, 101, 110, 97, 116, 105, 98, 117, 115, 32, 101, 116, 32, 109, 97, 103, 110, 105, 115, 32, 100,
-105, 115, 32, 112, 97, 114, 116, 117, 114, 105, 101, 110, 116, 32, 109, 111, 110, 116, 101, 115, 44, 32, 110, 97, 115, 99, 101, 116, 117, 114, 32, 114,
-105, 100, 105, 99, 117, 108, 117, 115, 32, 109, 117, 115, 46, 32, 73, 110, 32, 118, 101, 110, 101, 110, 97, 116, 105, 115, 32, 100, 97, 112, 105, 98,
-117, 115, 32, 109, 97, 115, 115, 97, 46, 32, 78, 117, 108, 108, 97, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 115, 97, 112, 105, 101, 110,
-32, 101, 116, 32, 113, 117, 97, 109, 46, 32, 78, 117, 110, 99, 32, 97, 99, 32, 109, 97, 103, 110, 97, 32, 108, 111, 98, 111, 114, 116, 105, 115,
-32, 116, 101, 108, 108, 117, 115, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 112, 111, 115, 117, 101, 114, 101, 46, 32, 67, 114, 97, 115, 32,
-97, 117, 103, 117, 101, 32, 109, 97, 117, 114, 105, 115, 44, 32, 109, 97, 116, 116, 105, 115, 32, 108, 111, 98, 111, 114, 116, 105, 115, 44, 32, 102,
-101, 114, 109, 101, 110, 116, 117, 109, 32, 97, 116, 44, 32, 115, 101, 109, 112, 101, 114, 32, 97, 99, 44, 32, 116, 101, 108, 108, 117, 115, 46, 32,
-67, 114, 97, 115, 32, 118, 105, 116, 97, 101, 32, 108, 105, 103, 117, 108, 97, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 115, 101, 109, 32, 112,
-111, 115, 117, 101, 114, 101, 32, 105, 97, 99, 117, 108, 105, 115, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 99, 111, 110, 100, 105, 109, 101, 110,
-116, 117, 109, 32, 101, 108, 101, 105, 102, 101, 110, 100, 32, 102, 101, 108, 105, 115, 46, 32, 85, 116, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32,
-115, 97, 112, 105, 101, 110, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 112, 111, 116, 101, 110, 116, 105, 46, 32, 77, 97, 117,
-114, 105, 115, 32, 117, 114, 110, 97, 46, 32, 85, 116, 32, 101, 117, 32, 101, 110, 105, 109, 32, 101, 117, 32, 97, 110, 116, 101, 32, 112, 111, 114,
-116, 97, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 46, 32, 65, 101, 110, 101, 97, 110, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117,
-101, 32, 101, 115, 116, 32, 97, 99, 32, 102, 101, 108, 105, 115, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 97, 117, 99, 116,
-111, 114, 46, 32, 78, 117, 110, 99, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 46, 32, 77, 111, 114, 98, 105, 32, 108, 97, 111,
-114, 101, 101, 116, 32, 97, 110, 116, 101, 32, 101, 116, 32, 110, 105, 98, 104, 46, 32, 68, 111, 110, 101, 99, 32, 102, 101, 117, 103, 105, 97, 116,
-32, 97, 114, 99, 117, 32, 101, 103, 101, 116, 32, 101, 110, 105, 109, 46, 32, 77, 111, 114, 98, 105, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32,
-116, 111, 114, 116, 111, 114, 32, 97, 99, 32, 105, 112, 115, 117, 109, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 108, 97, 99, 117, 115, 32, 97,
-114, 99, 117, 44, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 32, 97, 99, 44, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 118, 101, 108, 44,
-32, 112, 111, 115, 117, 101, 114, 101, 32, 105, 100, 44, 32, 101, 115, 116, 46, 32, 80, 114, 111, 105, 110, 32, 99, 111, 109, 109, 111, 100, 111, 32,
-103, 114, 97, 118, 105, 100, 97, 32, 115, 101, 109, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 118,
-101, 104, 105, 99, 117, 108, 97, 32, 108, 105, 98, 101, 114, 111, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 119, 105, 115, 105, 46, 32,
-77, 97, 101, 99, 101, 110, 97, 115, 32, 112, 114, 101, 116, 105, 117, 109, 32, 116, 101, 108, 108, 117, 115, 32, 101, 117, 32, 115, 97, 112, 105, 101,
-110, 46, 32, 78, 117, 110, 99, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 110, 117, 110, 99, 46, 32, 73, 110, 32, 104, 97, 99, 32, 104, 97,
-98, 105, 116, 97, 115, 115, 101, 32, 112, 108, 97, 116, 101, 97, 32, 100, 105, 99, 116, 117, 109, 115, 116, 46, 32, 65, 101, 110, 101, 97, 110, 32,
-100, 105, 99, 116, 117, 109, 32, 110, 101, 113, 117, 101, 32, 115, 101, 100, 32, 116, 111, 114, 116, 111, 114, 46, 32, 68, 111, 110, 101, 99, 32, 101,
-116, 32, 101, 114, 97, 116, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 97, 110, 116, 101, 32, 105, 112, 115, 117, 109, 32, 112, 114,
-105, 109, 105, 115, 32, 105, 110, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 111, 114, 99, 105, 32, 108, 117, 99, 116, 117, 115, 32, 101, 116, 32,
-117, 108, 116, 114, 105, 99, 101, 115, 32, 112, 111, 115, 117, 101, 114, 101, 32, 99, 117, 98, 105, 108, 105, 97, 32, 67, 117, 114, 97, 101, 59, 32,
-83, 101, 100, 32, 106, 117, 115, 116, 111, 32, 116, 117, 114, 112, 105, 115, 44, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 32, 117, 116,
-44, 32, 109, 97, 116, 116, 105, 115, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 111, 114, 110, 97, 114, 101, 32, 114, 117, 116, 114, 117, 109,
-44, 32, 109, 97, 115, 115, 97, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 101, 110, 105,
-109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 118, 101, 108, 105, 116, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 116, 101, 108, 108, 117, 115,
-32, 105, 112, 115, 117, 109, 44, 32, 108, 117, 99, 116, 117, 115, 32, 117, 116, 44, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 32,
-118, 105, 116, 97, 101, 44, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 110, 111, 110, 44, 32, 108, 105, 103, 117, 108, 97, 46, 32, 80, 104,
-97, 115, 101, 108, 108, 117, 115, 32, 108, 97, 99, 105, 110, 105, 97, 32, 119, 105, 115, 105, 32, 97, 116, 32, 101, 115, 116, 46, 32, 68, 111, 110,
-101, 99, 32, 101, 108, 105, 116, 32, 119, 105, 115, 105, 44, 32, 99, 111, 109, 109, 111, 100, 111, 32, 110, 111, 110, 44, 32, 112, 108, 97, 99, 101,
-114, 97, 116, 32, 105, 110, 44, 32, 99, 111, 110, 118, 97, 108, 108, 105, 115, 32, 105, 100, 44, 32, 101, 108, 105, 116, 46, 32, 78, 117, 110, 99,
-32, 100, 111, 108, 111, 114, 32, 100, 111, 108, 111, 114, 44, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 105, 100, 44, 32, 98, 105, 98,
-101, 110, 100, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 108, 97, 99, 105, 110, 105, 97, 32, 105, 100, 44, 32, 101, 114, 97, 116, 46, 32, 67,
-114, 97, 115, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 101, 114, 111, 115, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 115,
-117, 115, 99, 105, 112, 105, 116, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 108, 101, 99, 116, 117, 115, 46, 32, 67, 108, 97, 115, 115, 32, 97,
-112, 116, 101, 110, 116, 32, 116, 97, 99, 105, 116, 105, 32, 115, 111, 99, 105, 111, 115, 113, 117, 32, 97, 100, 32, 108, 105, 116, 111, 114, 97, 32,
-116, 111, 114, 113, 117, 101, 110, 116, 32, 112, 101, 114, 32, 99, 111, 110, 117, 98, 105, 97, 32, 110, 111, 115, 116, 114, 97, 44, 32, 112, 101, 114,
-32, 105, 110, 99, 101, 112, 116, 111, 115, 32, 104, 121, 109, 101, 110, 97, 101, 111, 115, 46, 32, 67, 114, 97, 115, 32, 111, 114, 99, 105, 46, 32,
-80, 114, 97, 101, 115, 101, 110, 116, 32, 109, 97, 115, 115, 97, 32, 117, 114, 110, 97, 44, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 115, 101,
-109, 112, 101, 114, 44, 32, 97, 117, 99, 116, 111, 114, 32, 97, 44, 32, 112, 114, 101, 116, 105, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 116,
-101, 108, 108, 117, 115, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 97, 116, 32, 112, 117, 114, 117, 115, 46, 32, 77, 111, 114, 98, 105,
-32, 116, 111, 114, 116, 111, 114, 32, 113, 117, 97, 109, 44, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 32, 118, 101, 110, 101, 110, 97, 116, 105,
-115, 44, 32, 101, 103, 101, 115, 116, 97, 115, 32, 97, 44, 32, 99, 117, 114, 115, 117, 115, 32, 101, 117, 44, 32, 101, 115, 116, 46, 32, 78, 117,
-110, 99, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 108, 101, 99, 116, 117, 115, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 108, 105, 98, 101,
-114, 111, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 108,
-105, 103, 117, 108, 97, 46, 32, 78, 117, 110, 99, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 112, 111, 115, 117, 101, 114, 101, 32, 97, 114,
-99, 117, 46, 32, 77, 97, 117, 114, 105, 115, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 113, 117, 97, 109, 32, 97, 116, 32, 109, 97, 115, 115,
-97, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 115, 111, 100, 97, 108, 101, 115, 32, 97, 108, 105, 113, 117, 101, 116, 32, 109, 97, 117, 114, 105,
-115, 46, 32, 73, 110, 32, 105, 100, 32, 97, 110, 116, 101, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 118, 97, 114, 105,
-117, 115, 32, 105, 112, 115, 117, 109, 32, 105, 110, 32, 97, 114, 99, 117, 46, 32, 70, 117, 115, 99, 101, 32, 109, 97, 117, 114, 105, 115, 32, 108,
-97, 99, 117, 115, 44, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 97, 99, 44, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 113, 117, 105,
-115, 44, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 108, 117, 99, 116, 117, 115, 44, 32, 112, 101, 100, 101, 46, 32, 83, 101, 100, 32, 119, 105,
-115, 105, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 109, 97, 116, 116, 105, 115, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32,
-104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 115, 101, 109, 32, 110, 101, 99, 32, 112, 117, 114, 117, 115, 46, 32, 80, 114, 111, 105, 110, 32, 105,
-100, 32, 113, 117, 97, 109, 46, 32, 67, 114, 97, 115, 32, 110, 101, 99, 32, 109, 97, 117, 114, 105, 115, 46, 32, 73, 110, 116, 101, 103, 101, 114,
-32, 111, 114, 99, 105, 46, 32, 78, 117, 108, 108, 97, 109, 32, 100, 117, 105, 32, 115, 101, 109, 44, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32,
-115, 101, 100, 44, 32, 101, 103, 101, 115, 116, 97, 115, 32, 113, 117, 105, 115, 44, 32, 99, 117, 114, 115, 117, 115, 32, 105, 110, 44, 32, 109, 97,
-103, 110, 97, 46, 32, 77, 97, 117, 114, 105, 115, 32, 110, 101, 113, 117, 101, 32, 108, 97, 99, 117, 115, 44, 32, 99, 111, 110, 115, 101, 99, 116,
-101, 116, 117, 101, 114, 32, 110, 101, 99, 44, 32, 115, 97, 103, 105, 116, 116, 105, 115, 32, 101, 117, 44, 32, 112, 111, 114, 116, 116, 105, 116, 111,
-114, 32, 101, 103, 101, 116, 44, 32, 100, 117, 105, 46, 32, 70, 117, 115, 99, 101, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 46,
-32, 68, 111, 110, 101, 99, 32, 110, 101, 99, 32, 116, 101, 108, 108, 117, 115, 32, 113, 117, 105, 115, 32, 108, 101, 111, 32, 108, 111, 98, 111, 114,
-116, 105, 115, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 46, 32, 69, 116, 105, 97, 109, 32, 109, 101, 116, 117, 115, 32, 117, 114, 110,
-97, 44, 32, 97, 108, 105, 113, 117, 101, 116, 32, 112, 114, 101, 116, 105, 117, 109, 44, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 101, 117, 44,
-32, 99, 117, 114, 115, 117, 115, 32, 117, 116, 44, 32, 116, 117, 114, 112, 105, 115, 46, 32, 77, 111, 114, 98, 105, 32, 98, 105, 98, 101, 110, 100,
-117, 109, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32, 108, 101, 99, 116, 117, 115, 46, 32, 83, 101, 100, 32, 110, 111, 110, 32, 97, 110, 116, 101,
-32, 118, 105, 116, 97, 101, 32, 97, 114, 99, 117, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 116, 101, 109, 112, 111, 114, 46,
-32, 70, 117, 115, 99, 101, 32, 115, 101, 100, 32, 108, 105, 103, 117, 108, 97, 32, 105, 110, 32, 115, 101, 109, 32, 116, 101, 109, 112, 111, 114, 32,
-105, 109, 112, 101, 114, 100, 105, 101, 116, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 118, 101, 108, 32, 101, 115, 116, 46, 32, 80, 104, 97, 115,
-101, 108, 108, 117, 115, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32,
-110, 105, 98, 104, 46, 32, 67, 108, 97, 115, 115, 32, 97, 112, 116, 101, 110, 116, 32, 116, 97, 99, 105, 116, 105, 32, 115, 111, 99, 105, 111, 115,
-113, 117, 32, 97, 100, 32, 108, 105, 116, 111, 114, 97, 32, 116, 111, 114, 113, 117, 101, 110, 116, 32, 112, 101, 114, 32, 99, 111, 110, 117, 98, 105,
-97, 32, 110, 111, 115, 116, 114, 97, 44, 32, 112, 101, 114, 32, 105, 110, 99, 101, 112, 116, 111, 115, 32, 104, 121, 109, 101, 110, 97, 101, 111, 115,
-46, 32, 83, 101, 100, 32, 118, 101, 108, 32, 108, 101, 111, 32, 110, 101, 99, 32, 101, 114, 111, 115, 32, 98, 108, 97, 110, 100, 105, 116, 32, 105,
-109, 112, 101, 114, 100, 105, 101, 116, 46, 32, 78, 117, 108, 108, 97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 83, 117, 115, 112, 101, 110,
-100, 105, 115, 115, 101, 32, 108, 111, 98, 111, 114, 116, 105, 115, 44, 32, 100, 117, 105, 32, 117, 116, 32, 102, 114, 105, 110, 103, 105, 108, 108, 97,
-32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 44, 32, 106, 117, 115, 116, 111, 32, 112, 117, 114, 117, 115, 32, 117, 108, 108, 97, 109, 99, 111, 114,
-112, 101, 114, 32, 108, 105, 103, 117, 108, 97, 44, 32, 117, 108, 116, 114, 105, 99, 105, 101, 115, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 100,
-111, 108, 111, 114, 32, 101, 110, 105, 109, 32, 105, 110, 32, 108, 105, 98, 101, 114, 111, 46, 32, 83, 101, 100, 32, 101, 108, 101, 109, 101, 110, 116,
-117, 109, 44, 32, 112, 101, 100, 101, 32, 101, 103, 101, 116, 32, 112, 111, 114, 116, 97, 32, 99, 111, 110, 118, 97, 108, 108, 105, 115, 44, 32, 100,
-117, 105, 32, 110, 117, 108, 108, 97, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 112, 101, 100, 101, 44, 32, 101, 103, 101, 116, 32, 118, 101,
-104, 105, 99, 117, 108, 97, 32, 111, 100, 105, 111, 32, 97, 110, 116, 101, 32, 97, 116, 32, 115, 101, 109, 46, 32, 80, 101, 108, 108, 101, 110, 116,
-101, 115, 113, 117, 101, 32, 104, 97, 98, 105, 116, 97, 110, 116, 32, 109, 111, 114, 98, 105, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 115,
-101, 110, 101, 99, 116, 117, 115, 32, 101, 116, 32, 110, 101, 116, 117, 115, 32, 101, 116, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 102, 97,
-109, 101, 115, 32, 97, 99, 32, 116, 117, 114, 112, 105, 115, 32, 101, 103, 101, 115, 116, 97, 115, 46, 32, 83, 101, 100, 32, 117, 108, 108, 97, 109,
-99, 111, 114, 112, 101, 114, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 105, 112, 115, 117, 109, 46, 32, 70, 117, 115, 99, 101, 32, 114, 105,
-115, 117, 115, 32, 110, 105, 98, 104, 44, 32, 97, 99, 99, 117, 109, 115, 97, 110, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 116, 101, 109,
-112, 117, 115, 32, 101, 103, 101, 116, 44, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 97, 99, 44, 32, 110, 101, 113, 117, 101, 46, 32, 83,
-101, 100, 32, 113, 117, 105, 115, 32, 108, 111, 114, 101, 109, 32, 117, 116, 32, 116, 111, 114, 116, 111, 114, 32, 102, 97, 99, 105, 108, 105, 115, 105,
-115, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 46, 32, 70, 117, 115, 99, 101, 32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 113, 117, 97, 109,
-32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 105, 112, 115, 117, 109, 46, 32, 77, 111, 114, 98, 105, 32, 97, 99, 32, 101, 108, 105, 116, 32, 113,
-117, 105, 115, 32, 116, 101, 108, 108, 117, 115, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 98, 108, 97, 110, 100, 105, 116, 46, 32, 77, 97,
-101, 99, 101, 110, 97, 115, 32, 115, 117, 115, 99, 105, 112, 105, 116, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 115, 101, 109,
-46, 32, 78, 97, 109, 32, 115, 101, 100, 32, 101, 114, 111, 115, 32, 118, 101, 108, 32, 108, 97, 99, 117, 115, 32, 108, 111, 98, 111, 114, 116, 105,
-115, 32, 99, 111, 110, 103, 117, 101, 46, 32, 80, 114, 111, 105, 110, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 110, 117, 110, 99, 32, 108, 111,
-98, 111, 114, 116, 105, 115, 32, 111, 114, 99, 105, 46, 32, 68, 111, 110, 101, 99, 32, 101, 103, 101, 115, 116, 97, 115, 32, 101, 110, 105, 109, 32,
-101, 117, 32, 111, 100, 105, 111, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 105, 100, 32, 109, 101, 116, 117, 115, 46, 32, 80, 101,
-108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 97, 117, 99, 116, 111, 114, 44, 32, 115, 101, 109, 32, 118, 97, 114, 105, 117, 115, 32, 108, 117,
-99, 116, 117, 115, 32, 116, 101, 109, 112, 117, 115, 44, 32, 108, 105, 98, 101, 114, 111, 32, 109, 97, 103, 110, 97, 32, 99, 117, 114, 115, 117, 115,
-32, 110, 101, 113, 117, 101, 44, 32, 101, 116, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 100, 105, 97, 109, 32, 100, 105, 97, 109, 32, 113,
-117, 105, 115, 32, 112, 117, 114, 117, 115, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 100,
-111, 108, 111, 114, 46, 32, 78, 117, 108, 108, 97, 32, 105, 110, 32, 109, 97, 103, 110, 97, 46, 32, 67, 114, 97, 115, 32, 105, 100, 32, 100, 105,
-97, 109, 32, 97, 116, 32, 108, 101, 99, 116, 117, 115, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 112, 108, 97, 99, 101, 114, 97, 116, 46, 32,
-78, 117, 110, 99, 32, 112, 111, 114, 116, 97, 32, 112, 111, 115, 117, 101, 114, 101, 32, 115, 97, 112, 105, 101, 110, 46, 32, 69, 116, 105, 97, 109,
-32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 46, 32, 67, 108, 97, 115, 115, 32, 97, 112, 116, 101, 110, 116, 32, 116, 97, 99, 105, 116,
-105, 32, 115, 111, 99, 105, 111, 115, 113, 117, 32, 97, 100, 32, 108, 105, 116, 111, 114, 97, 32, 116, 111, 114, 113, 117, 101, 110, 116, 32, 112, 101,
-114, 32, 99, 111, 110, 117, 98, 105, 97, 32, 110, 111, 115, 116, 114, 97, 44, 32, 112, 101, 114, 32, 105, 110, 99, 101, 112, 116, 111, 115, 32, 104,
-121, 109, 101, 110, 97, 101, 111, 115, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 109,
-105, 32, 115, 101, 100, 32, 116, 111, 114, 116, 111, 114, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32, 101, 108, 101, 105, 102, 101, 110, 100, 32,
-100, 105, 97, 109, 32, 110, 111, 110, 32, 117, 114, 110, 97, 46, 32, 68, 111, 110, 101, 99, 32, 108, 117, 99, 116, 117, 115, 32, 112, 104, 97, 114,
-101, 116, 114, 97, 32, 116, 101, 108, 108, 117, 115, 46, 32, 80, 114, 111, 105, 110, 32, 97, 99, 32, 105, 112, 115, 117, 109, 32, 101, 103, 101, 116,
-32, 108, 105, 98, 101, 114, 111, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 118, 111, 108, 117, 116, 112, 97, 116, 46, 32, 67, 114, 97, 115, 32,
-105, 100, 32, 116, 101, 108, 108, 117, 115, 46, 32, 78, 117, 108, 108, 97, 32, 110, 111, 110, 32, 114, 105, 115, 117, 115, 46, 32, 73, 110, 32, 100,
-111, 108, 111, 114, 46, 32, 70, 117, 115, 99, 101, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 32, 113, 117, 97, 109, 32, 105, 110, 32,
-109, 97, 115, 115, 97, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 112, 111, 114, 116, 97, 46, 32, 77, 111, 114, 98, 105, 32, 117, 116, 32, 100,
-111, 108, 111, 114, 32, 101, 117, 32, 109, 97, 115, 115, 97, 32, 101, 103, 101, 115, 116, 97, 115, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117,
-109, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 46, 32, 73, 110, 32, 104, 97, 99, 32, 104, 97, 98, 105,
-116, 97, 115, 115, 101, 32, 112, 108, 97, 116, 101, 97, 32, 100, 105, 99, 116, 117, 109, 115, 116, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115,
-115, 101, 32, 112, 111, 116, 101, 110, 116, 105, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32, 108, 101, 111, 32,
-105, 110, 32, 116, 111, 114, 116, 111, 114, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 101, 108, 32, 101, 114, 97, 116, 32, 97, 32, 117, 114, 110,
-97, 32, 108, 97, 111, 114, 101, 101, 116, 32, 115, 101, 109, 112, 101, 114, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 117,
-116, 32, 109, 101, 116, 117, 115, 32, 97, 99, 32, 116, 101, 108, 108, 117, 115, 32, 99, 111, 109, 109, 111, 100, 111, 32, 101, 108, 101, 105, 102, 101,
-110, 100, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 113, 117, 105, 115, 32, 117, 114, 110, 97, 46, 32, 67, 117, 114, 97, 98,
-105, 116, 117, 114, 32, 108, 97, 99, 105, 110, 105, 97, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 100, 117, 105, 46, 32, 78, 97, 109, 32,
-110, 101, 99, 32, 97, 110, 116, 101, 46, 32, 73, 110, 32, 105, 100, 32, 101, 110, 105, 109, 46, 32, 65, 101, 110, 101, 97, 110, 32, 109, 97, 116,
-116, 105, 115, 32, 101, 110, 105, 109, 46, 32, 73, 110, 32, 117, 116, 32, 110, 101, 113, 117, 101, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32,
-114, 105, 115, 117, 115, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 46, 32, 83, 117, 115, 112, 101,
-110, 100, 105, 115, 115, 101, 32, 112, 111, 116, 101, 110, 116, 105, 46, 32, 85, 116, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 108, 101,
-99, 116, 117, 115, 32, 118, 105, 116, 97, 101, 32, 116, 111, 114, 116, 111, 114, 46, 32, 68, 117, 105, 115, 32, 118, 101, 108, 105, 116, 46, 32, 78,
-117, 108, 108, 97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32,
-117, 114, 110, 97, 46, 32, 67, 114, 97, 115, 32, 118, 97, 114, 105, 117, 115, 32, 116, 111, 114, 116, 111, 114, 32, 105, 110, 32, 112, 101, 100, 101,
-46, 32, 83, 101, 100, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 108, 97, 99, 105, 110, 105,
-97, 32, 108, 105, 98, 101, 114, 111, 32, 110, 101, 99, 32, 110, 105, 98, 104, 46, 32, 68, 111, 110, 101, 99, 32, 97, 108, 105, 113, 117, 97, 109,
-32, 114, 105, 115, 117, 115, 32, 110, 111, 110, 32, 110, 105, 115, 108, 46, 32, 78, 97, 109, 32, 97, 32, 110, 117, 110, 99, 32, 101, 116, 32, 102,
-101, 108, 105, 115, 32, 116, 101, 109, 112, 111, 114, 32, 102, 101, 117, 103, 105, 97, 116, 46, 32, 78, 117, 110, 99, 32, 109, 101, 116, 117, 115, 46,
-32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 101, 117, 105, 115, 109, 111, 100, 44, 32, 109, 101, 116, 117, 115, 32, 105, 110, 32, 115, 101,
-109, 112, 101, 114, 32, 108, 97, 111, 114, 101, 101, 116, 44, 32, 117, 114, 110, 97, 32, 105, 112, 115, 117, 109, 32, 112, 104, 97, 114, 101, 116, 114,
-97, 32, 108, 111, 114, 101, 109, 44, 32, 115, 101, 100, 32, 117, 108, 116, 114, 105, 99, 105, 101, 115, 32, 109, 97, 103, 110, 97, 32, 108, 111, 114,
-101, 109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 119, 105, 115, 105, 46, 32, 83, 101, 100, 32, 119, 105, 115, 105, 46, 32, 78, 117, 108, 108,
-97, 109, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 101, 108, 105, 116, 32, 115, 101, 100, 32, 110, 105, 115, 108, 46, 32, 80, 104, 97, 115,
-101, 108, 108, 117, 115, 32, 109, 97, 116, 116, 105, 115, 32, 108, 101, 111, 32, 110, 101, 99, 32, 109, 97, 115, 115, 97, 46, 32, 65, 101, 110, 101,
-97, 110, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 46, 32, 67, 114, 97, 115, 32, 119, 105, 115, 105, 32, 101, 114, 97, 116, 44, 32, 108, 111,
-98, 111, 114, 116, 105, 115, 32, 110, 101, 99, 44, 32, 99, 117, 114, 115, 117, 115, 32, 101, 103, 101, 116, 44, 32, 108, 111, 98, 111, 114, 116, 105,
-115, 32, 97, 116, 44, 32, 108, 105, 98, 101, 114, 111, 46, 32, 73, 110, 32, 109, 97, 115, 115, 97, 32, 110, 105, 115, 108, 44, 32, 114, 117, 116,
-114, 117, 109, 32, 110, 111, 110, 44, 32, 99, 117, 114, 115, 117, 115, 32, 110, 101, 99, 44, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 115, 101,
-100, 44, 32, 108, 97, 99, 117, 115, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97,
-46, 32, 67, 114, 97, 115, 32, 101, 117, 105, 115, 109, 111, 100, 44, 32, 110, 101, 113, 117, 101, 32, 97, 99, 32, 115, 117, 115, 99, 105, 112, 105,
-116, 32, 116, 101, 109, 112, 117, 115, 44, 32, 118, 101, 108, 105, 116, 32, 108, 111, 114, 101, 109, 32, 108, 117, 99, 116, 117, 115, 32, 101, 108, 105,
-116, 44, 32, 100, 97, 112, 105, 98, 117, 115, 32, 114, 104, 111, 110, 99, 117, 115, 32, 119, 105, 115, 105, 32, 101, 115, 116, 32, 117, 116, 32, 115,
-101, 109, 46, 32, 80, 114, 111, 105, 110, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 101, 110, 105, 109, 32, 105, 110, 32, 101, 114, 111, 115,
-32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 32, 97, 99, 99, 117, 109, 115, 97, 110, 46, 32, 85, 116, 32, 108, 111, 114, 101, 109, 32, 110, 105,
-115, 108, 44, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 101, 116, 44, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 110, 101, 99, 44, 32,
-108, 97, 99, 105, 110, 105, 97, 32, 105, 110, 44, 32, 100, 111, 108, 111, 114, 46, 32, 68, 117, 105, 115, 32, 110, 101, 99, 32, 113, 117, 97, 109,
-46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 118, 101, 108, 105, 116, 32, 102, 101, 108, 105, 115, 44, 32, 112, 111, 115, 117, 101, 114, 101, 32,
-105, 100, 44, 32, 108, 117, 99, 116, 117, 115, 32, 113, 117, 105, 115, 44, 32, 108, 97, 111, 114, 101, 101, 116, 32, 117, 116, 44, 32, 105, 112, 115,
-117, 109, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 101, 103, 101, 116, 32, 97, 114, 99, 117, 46, 32, 77, 97, 117, 114, 105, 115, 32, 109,
-97, 115, 115, 97, 32, 102, 101, 108, 105, 115, 44, 32, 111, 114, 110, 97, 114, 101, 32, 110, 111, 110, 44, 32, 117, 108, 116, 114, 105, 99, 101, 115,
-32, 105, 100, 44, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 105, 110, 44, 32, 101, 108, 105, 116, 46, 32, 80, 101, 108, 108, 101, 110, 116,
-101, 115, 113, 117, 101, 32, 104, 97, 98, 105, 116, 97, 110, 116, 32, 109, 111, 114, 98, 105, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 115,
-101, 110, 101, 99, 116, 117, 115, 32, 101, 116, 32, 110, 101, 116, 117, 115, 32, 101, 116, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 102, 97,
-109, 101, 115, 32, 97, 99, 32, 116, 117, 114, 112, 105, 115, 32, 101, 103, 101, 115, 116, 97, 115, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115,
-32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 44, 32, 109, 105, 32, 97, 99, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 102, 97, 99, 105, 108,
-105, 115, 105, 115, 44, 32, 108, 105, 98, 101, 114, 111, 32, 101, 110, 105, 109, 32, 115, 117, 115, 99, 105, 112, 105, 116, 32, 108, 101, 111, 44, 32,
-110, 111, 110, 32, 110, 111, 110, 117, 109, 109, 121, 32, 112, 101, 100, 101, 32, 100, 105, 97, 109, 32, 101, 103, 101, 116, 32, 110, 105, 98, 104, 46,
-32, 83, 101, 100, 32, 116, 101, 109, 112, 117, 115, 46, 32, 65, 101, 110, 101, 97, 110, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 115, 117, 115,
-99, 105, 112, 105, 116, 32, 100, 117, 105, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 101, 114, 97, 116, 32, 118, 111, 108, 117, 116, 112, 97, 116,
-46, 32, 85, 116, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 46, 32, 78, 97, 109, 32, 99, 111, 109, 109, 111, 100, 111, 44, 32, 110, 117, 108,
-108, 97, 32, 117, 116, 32, 102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 114, 117, 116, 114, 117, 109, 44, 32, 111, 114, 99, 105, 32, 101, 108, 105,
-116, 32, 118, 105, 118, 101, 114, 114, 97, 32, 100, 105, 97, 109, 44, 32, 118, 105, 116, 97, 101, 32, 109, 111, 108, 108, 105, 115, 32, 111, 100, 105,
-111, 32, 111, 100, 105, 111, 32, 101, 116, 32, 112, 117, 114, 117, 115, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 101, 114, 97, 116, 32, 118, 111,
-108, 117, 116, 112, 97, 116, 46, 32, 83, 101, 100, 32, 97, 108, 105, 113, 117, 101, 116, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 105, 112, 115,
-117, 109, 46, 32, 73, 110, 32, 117, 116, 32, 101, 115, 116, 46, 32, 69, 116, 105, 97, 109, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117, 109,
-46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 116, 111, 114, 116, 111, 114,
-32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 108, 97, 99, 117, 115, 46, 32, 65, 101, 110, 101, 97, 110, 32, 111, 114, 99, 105, 46, 32, 83, 117,
-115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 108, 97, 99, 117, 115, 32, 110, 117, 108, 108, 97, 44, 32, 110, 111, 110, 117, 109, 109, 121, 32, 97,
-44, 32, 100, 105, 99, 116, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 101, 103, 101, 115, 116, 97, 115, 32, 113, 117, 105, 115, 44, 32, 101, 114,
-111, 115, 46, 32, 68, 111, 110, 101, 99, 32, 97, 117, 99, 116, 111, 114, 32, 103, 114, 97, 118, 105, 100, 97, 32, 110, 105, 115, 108, 46, 32, 67,
-114, 97, 115, 32, 97, 99, 32, 101, 115, 116, 32, 114, 117, 116, 114, 117, 109, 32, 97, 117, 103, 117, 101, 32, 112, 117, 108, 118, 105, 110, 97, 114,
-32, 111, 114, 110, 97, 114, 101, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 109, 97, 117, 114, 105, 115, 32, 110, 105, 98, 104, 44, 32,
-118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 105, 110, 44, 32, 114, 104, 111, 110, 99, 117, 115, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 44,
-32, 100, 97, 112, 105, 98, 117, 115, 32, 101, 103, 101, 116, 44, 32, 108, 97, 99, 117, 115, 46, 32, 78, 97, 109, 32, 110, 117, 110, 99, 32, 109,
-97, 117, 114, 105, 115, 44, 32, 115, 117, 115, 99, 105, 112, 105, 116, 32, 97, 116, 44, 32, 117, 108, 116, 114, 105, 99, 105, 101, 115, 32, 97, 44,
-32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 97, 116, 44, 32, 116, 101, 108, 108, 117, 115, 46, 32, 78, 97, 109, 32, 97, 99, 99, 117, 109,
-115, 97, 110, 32, 109, 111, 108, 108, 105, 115, 32, 108, 105, 98, 101, 114, 111, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 99, 111, 110, 100, 105,
-109, 101, 110, 116, 117, 109, 32, 109, 97, 116, 116, 105, 115, 32, 101, 115, 116, 46, 32, 68, 111, 110, 101, 99, 32, 108, 97, 99, 117, 115, 46, 32,
-78, 117, 108, 108, 97, 109, 32, 97, 99, 32, 115, 97, 112, 105, 101, 110, 32, 105, 100, 32, 109, 97, 115, 115, 97, 32, 108, 111, 98, 111, 114, 116,
-105, 115, 32, 109, 111, 108, 101, 115, 116, 105, 101, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 101, 108, 101, 109, 101, 110,
-116, 117, 109, 46, 32, 80, 114, 111, 105, 110, 32, 117, 116, 32, 112, 117, 114, 117, 115, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 101, 116, 32,
-115, 97, 112, 105, 101, 110, 32, 113, 117, 105, 115, 32, 116, 117, 114, 112, 105, 115, 32, 99, 111, 109, 109, 111, 100, 111, 32, 109, 111, 108, 108, 105,
-115, 46, 32, 78, 117, 108, 108, 97, 32, 99, 111, 110, 115, 101, 113, 117, 97, 116, 46, 32, 80, 114, 111, 105, 110, 32, 97, 32, 119, 105, 115, 105,
-32, 117, 116, 32, 116, 101, 108, 108, 117, 115, 32, 98, 108, 97, 110, 100, 105, 116, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 46, 32, 65, 108,
-105, 113, 117, 97, 109, 32, 110, 117, 108, 108, 97, 32, 108, 111, 114, 101, 109, 44, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 97, 99, 44, 32,
-109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 118, 101, 108, 44, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 32, 101, 116, 44, 32, 109, 101, 116,
-117, 115, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 101, 103, 101, 115, 116, 97, 115, 32, 110, 105, 98, 104, 32, 101, 116, 32, 108, 105,
-103, 117, 108, 97, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 100, 105, 97, 109, 32, 111, 100, 105, 111, 44, 32, 108, 97, 99, 105, 110, 105, 97,
-32, 113, 117, 105, 115, 44, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 113, 117, 105, 115, 44, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117,
-100, 105, 110, 32, 117, 116, 44, 32, 101, 114, 111, 115, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 97, 108, 105, 113, 117, 101, 116, 32,
-108, 111, 114, 101, 109, 32, 97, 99, 32, 105, 112, 115, 117, 109, 46, 32, 83, 101, 100, 32, 99, 117, 114, 115, 117, 115, 32, 116, 101, 108, 108, 117,
-115, 32, 97, 99, 32, 111, 114, 99, 105, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 97, 116, 32, 110, 117, 108, 108, 97, 46, 32, 68,
-111, 110, 101, 99, 32, 112, 111, 114, 116, 97, 32, 115, 111, 100, 97, 108, 101, 115, 32, 97, 110, 116, 101, 46, 32, 80, 101, 108, 108, 101, 110, 116,
-101, 115, 113, 117, 101, 32, 104, 97, 98, 105, 116, 97, 110, 116, 32, 109, 111, 114, 98, 105, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 115,
-101, 110, 101, 99, 116, 117, 115, 32, 101, 116, 32, 110, 101, 116, 117, 115, 32, 101, 116, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 102, 97,
-109, 101, 115, 32, 97, 99, 32, 116, 117, 114, 112, 105, 115, 32, 101, 103, 101, 115, 116, 97, 115, 46, 32, 83, 101, 100, 32, 105, 100, 32, 108, 101,
-99, 116, 117, 115, 32, 97, 116, 32, 109, 97, 115, 115, 97, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 116, 114, 105, 115, 116, 105,
-113, 117, 101, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 108, 97, 99, 117, 115,
-46, 32, 73, 110, 32, 104, 97, 99, 32, 104, 97, 98, 105, 116, 97, 115, 115, 101, 32, 112, 108, 97, 116, 101, 97, 32, 100, 105, 99, 116, 117, 109,
-115, 116, 46, 32, 78, 117, 110, 99, 32, 110, 111, 110, 32, 116, 117, 114, 112, 105, 115, 46, 32, 83, 101, 100, 32, 115, 97, 103, 105, 116, 116, 105,
-115, 46, 32, 77, 111, 114, 98, 105, 32, 108, 97, 111, 114, 101, 101, 116, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 32, 100, 117, 105,
-46, 32, 78, 97, 109, 32, 97, 114, 99, 117, 32, 116, 101, 108, 108, 117, 115, 44, 32, 116, 101, 109, 112, 111, 114, 32, 118, 105, 116, 97, 101, 44,
-32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 101, 116, 44, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 32, 117, 116, 44, 32, 118, 101,
-108, 105, 116, 46, 32, 73, 110, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 97, 117, 103, 117, 101, 32, 97, 32, 97, 114, 99, 117, 32, 118, 111,
-108, 117, 116, 112, 97, 116, 32, 115, 117, 115, 99, 105, 112, 105, 116, 46, 32, 68, 111, 110, 101, 99, 32, 100, 105, 99, 116, 117, 109, 32, 117, 108,
-116, 114, 105, 99, 101, 115, 32, 108, 101, 99, 116, 117, 115, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 97, 32, 112, 117, 114, 117, 115,
-32, 101, 116, 32, 111, 114, 99, 105, 32, 100, 105, 99, 116, 117, 109, 32, 108, 97, 99, 105, 110, 105, 97, 46, 32, 85, 116, 32, 108, 101, 111, 46,
-32, 67, 114, 97, 115, 32, 115, 101, 109, 112, 101, 114, 44, 32, 108, 111, 114, 101, 109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 116, 105, 110,
-99, 105, 100, 117, 110, 116, 32, 99, 111, 110, 103, 117, 101, 44, 32, 106, 117, 115, 116, 111, 32, 101, 114, 111, 115, 32, 118, 97, 114, 105, 117, 115,
-32, 112, 101, 100, 101, 44, 32, 105, 110, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 116, 117, 114, 112, 105, 115, 32, 108, 101, 99, 116, 117, 115,
-32, 110, 111, 110, 32, 101, 114, 111, 115, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 113, 117, 97, 109, 46, 32, 83, 117, 115, 112, 101,
-110, 100, 105, 115, 115, 101, 32, 109, 97, 116, 116, 105, 115, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 109, 97, 103, 110, 97,
-46, 32, 65, 101, 110, 101, 97, 110, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 100, 105, 97, 109, 32, 118, 101, 108, 32, 110, 105, 115, 108,
-32, 110, 111, 110, 117, 109, 109, 121, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117, 109, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115,
-101, 32, 118, 101, 108, 32, 100, 111, 108, 111, 114, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 110, 111, 110, 117, 109, 109, 121, 46,
-32, 77, 97, 117, 114, 105, 115, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 32, 115, 101, 109, 112, 101, 114, 32, 97, 110, 116, 101, 46, 32, 77,
-97, 101, 99, 101, 110, 97, 115, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 101, 114, 111, 115, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108,
-117, 109, 32, 97, 99, 32, 100, 111, 108, 111, 114, 46, 32, 70, 117, 115, 99, 101, 32, 114, 105, 115, 117, 115, 32, 109, 101, 116, 117, 115, 44, 32,
-97, 108, 105, 113, 117, 101, 116, 32, 101, 103, 101, 116, 44, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 101, 116, 44, 32, 102, 101, 117, 103,
-105, 97, 116, 32, 118, 101, 108, 44, 32, 111, 114, 99, 105, 46, 32, 85, 116, 32, 97, 116, 32, 110, 117, 110, 99, 32, 105, 100, 32, 97, 110, 116,
-101, 32, 115, 111, 100, 97, 108, 101, 115, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 46, 32, 68, 117, 105, 115, 32, 116, 114, 105, 115, 116, 105,
-113, 117, 101, 32, 109, 97, 116, 116, 105, 115, 32, 97, 110, 116, 101, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 110, 101, 113, 117,
-101, 32, 109, 97, 117, 114, 105, 115, 44, 32, 108, 97, 111, 114, 101, 101, 116, 32, 105, 100, 44, 32, 99, 111, 110, 103, 117, 101, 32, 105, 110, 116,
-101, 114, 100, 117, 109, 44, 32, 97, 108, 105, 113, 117, 101, 116, 32, 117, 116, 44, 32, 100, 105, 97, 109, 46, 32, 78, 117, 108, 108, 97, 32, 118,
-111, 108, 117, 116, 112, 97, 116, 32, 98, 108, 97, 110, 100, 105, 116, 32, 109, 97, 103, 110, 97, 46, 32, 68, 111, 110, 101, 99, 32, 97, 99, 99,
-117, 109, 115, 97, 110, 32, 99, 111, 110, 103, 117, 101, 32, 100, 105, 97, 109, 46, 32, 69, 116, 105, 97, 109, 32, 118, 101, 108, 32, 100, 117, 105,
-32, 101, 103, 101, 116, 32, 110, 105, 115, 108, 32, 116, 101, 109, 112, 111, 114, 32, 118, 97, 114, 105, 117, 115, 46, 32, 67, 114, 97, 115, 32, 100,
-105, 99, 116, 117, 109, 32, 109, 97, 115, 115, 97, 32, 115, 101, 100, 32, 101, 110, 105, 109, 46, 32, 67, 114, 97, 115, 32, 117, 114, 110, 97, 32,
-116, 111, 114, 116, 111, 114, 44, 32, 102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 97, 99, 44, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101,
-114, 32, 105, 110, 44, 32, 101, 117, 105, 115, 109, 111, 100, 32, 118, 101, 108, 44, 32, 97, 114, 99, 117, 46, 32, 77, 111, 114, 98, 105, 32, 112,
-111, 115, 117, 101, 114, 101, 32, 108, 117, 99, 116, 117, 115, 32, 97, 117, 103, 117, 101, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 100, 117, 105,
-32, 100, 117, 105, 44, 32, 97, 100, 105, 112, 105, 115, 99, 105, 110, 103, 32, 105, 110, 44, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 101, 117,
-44, 32, 108, 117, 99, 116, 117, 115, 32, 101, 117, 44, 32, 110, 117, 108, 108, 97, 46, 32, 67, 114, 97, 115, 32, 118, 101, 108, 105, 116, 32, 112,
-101, 100, 101, 44, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 102, 101, 117, 103, 105,
-97, 116, 32, 105, 110, 44, 32, 97, 117, 99, 116, 111, 114, 32, 118, 105, 116, 97, 101, 44, 32, 97, 110, 116, 101, 46, 32, 83, 117, 115, 112, 101,
-110, 100, 105, 115, 115, 101, 32, 100, 105, 99, 116, 117, 109, 32, 102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 109, 97, 117, 114, 105, 115, 46, 32,
-73, 110, 32, 97, 32, 110, 105, 98, 104, 46, 32, 68, 111, 110, 101, 99, 32, 97, 99, 32, 108, 105, 103, 117, 108, 97, 46, 32, 73, 110, 32, 113,
-117, 97, 109, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 118, 105, 116, 97, 101, 32, 117, 114, 110, 97, 32, 117, 108, 116, 114, 105, 99, 105,
-101, 115, 32, 115, 101, 109, 32, 97, 108, 105, 113, 117, 97, 109, 32, 112, 108, 97, 99, 101, 114, 97, 116, 46, 32, 65, 108, 105, 113, 117, 97, 109,
-32, 101, 114, 97, 116, 32, 118, 111, 108, 117, 116, 112, 97, 116, 46, 32, 78, 97, 109, 32, 101, 115, 116, 46, 32, 68, 111, 110, 101, 99, 32, 102,
-97, 117, 99, 105, 98, 117, 115, 32, 115, 111, 100, 97, 108, 101, 115, 32, 109, 101, 116, 117, 115, 46, 32, 85, 116, 32, 99, 111, 110, 103, 117, 101,
-46, 32, 68, 111, 110, 101, 99, 32, 97, 114, 99, 117, 32, 116, 101, 108, 108, 117, 115, 44, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32, 97, 99,
-44, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 97, 99, 44, 32, 109, 111, 108, 108, 105, 115, 32, 115, 101, 100, 44, 32, 108, 101, 99, 116,
-117, 115, 46, 32, 78, 117, 108, 108, 97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 78, 117, 108, 108, 97, 109, 32, 118, 111, 108, 117, 116,
-112, 97, 116, 32, 110, 117, 110, 99, 32, 101, 116, 32, 102, 101, 108, 105, 115, 46, 32, 83, 101, 100, 32, 112, 101, 100, 101, 32, 111, 100, 105, 111,
-44, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 105, 110, 44, 32, 118, 111, 108, 117, 116, 112, 97, 116, 32, 109, 97, 108, 101, 115, 117, 97,
-100, 97, 44, 32, 102, 101, 117, 103, 105, 97, 116, 32, 103, 114, 97, 118, 105, 100, 97, 44, 32, 110, 117, 108, 108, 97, 46, 32, 78, 117, 108, 108,
-97, 32, 97, 108, 105, 113, 117, 97, 109, 32, 112, 101, 100, 101, 32, 118, 105, 116, 97, 101, 32, 97, 114, 99, 117, 46, 32, 80, 114, 111, 105, 110,
-32, 118, 101, 108, 105, 116, 32, 101, 108, 105, 116, 44, 32, 110, 111, 110, 117, 109, 109, 121, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 101,
-108, 101, 109, 101, 110, 116, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 118, 97, 114, 105, 117, 115, 32, 118, 105, 116, 97, 101, 44, 32, 100, 111,
-108, 111, 114, 46, 32, 68, 111, 110, 101, 99, 32, 114, 117, 116, 114, 117, 109, 32, 105, 112, 115, 117, 109, 32, 101, 117, 32, 109, 105, 46, 32, 65,
-108, 105, 113, 117, 97, 109, 32, 101, 116, 32, 115, 101, 109, 46, 32, 73, 110, 32, 97, 100, 105, 112, 105, 115, 99, 105, 110, 103, 32, 114, 104, 111,
-110, 99, 117, 115, 32, 118, 101, 108, 105, 116, 46, 32, 78, 97, 109, 32, 118, 105, 118, 101, 114, 114, 97, 32, 115, 99, 101, 108, 101, 114, 105, 115,
-113, 117, 101, 32, 97, 114, 99, 117, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 115, 101, 109, 46, 32, 83, 101, 100, 32, 116, 105, 110, 99, 105,
-100, 117, 110, 116, 32, 110, 117, 108, 108, 97, 32, 113, 117, 105, 115, 32, 109, 97, 115, 115, 97, 46, 32, 77, 97, 117, 114, 105, 115, 32, 102, 97,
-117, 99, 105, 98, 117, 115, 32, 116, 101, 109, 112, 117, 115, 32, 110, 117, 110, 99, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 99, 111,
-110, 100, 105, 109, 101, 110, 116, 117, 109, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 97, 108, 105, 113, 117, 101, 116, 32, 105, 97, 99,
-117, 108, 105, 115, 32, 115, 97, 112, 105, 101, 110, 46, 32, 78, 117, 110, 99, 32, 114, 104, 111, 110, 99, 117, 115, 44, 32, 111, 100, 105, 111, 32,
-118, 105, 116, 97, 101, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 44, 32, 116, 101, 108, 108, 117, 115,
-32, 108, 105, 98, 101, 114, 111, 32, 99, 111, 109, 109, 111, 100, 111, 32, 105, 112, 115, 117, 109, 44, 32, 117, 116, 32, 115, 111, 108, 108, 105, 99,
-105, 116, 117, 100, 105, 110, 32, 110, 105, 115, 108, 32, 110, 105, 115, 108, 32, 118, 101, 108, 32, 106, 117, 115, 116, 111, 46, 32, 78, 117, 108, 108,
-97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 98, 108, 97, 110, 100, 105, 116, 32, 101, 110, 105,
-109, 32, 117, 116, 32, 106, 117, 115, 116, 111, 46, 32, 80, 114, 111, 105, 110, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 44, 32, 101, 108, 105,
-116, 32, 101, 103, 101, 116, 32, 97, 99, 99, 117, 109, 115, 97, 110, 32, 112, 117, 108, 118, 105, 110, 97, 114, 44, 32, 111, 114, 99, 105, 32, 113,
-117, 97, 109, 32, 97, 117, 99, 116, 111, 114, 32, 110, 101, 113, 117, 101, 44, 32, 115, 101, 100, 32, 99, 111, 110, 118, 97, 108, 108, 105, 115, 32,
-100, 105, 97, 109, 32, 112, 117, 114, 117, 115, 32, 118, 101, 108, 32, 102, 101, 108, 105, 115, 46, 32, 83, 101, 100, 32, 111, 114, 99, 105, 32, 108,
-101, 111, 44, 32, 101, 108, 101, 105, 102, 101, 110, 100, 32, 118, 101, 108, 44, 32, 98, 108, 97, 110, 100, 105, 116, 32, 110, 111, 110, 44, 32, 115,
-101, 109, 112, 101, 114, 32, 101, 117, 44, 32, 112, 117, 114, 117, 115, 46, 32, 80, 114, 111, 105, 110, 32, 98, 105, 98, 101, 110, 100, 117, 109, 44,
-32, 108, 105, 98, 101, 114, 111, 32, 97, 99, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 32, 99, 111, 109, 109, 111, 100, 111, 44,
-32, 101, 114, 111, 115, 32, 115, 97, 112, 105, 101, 110, 32, 98, 108, 97, 110, 100, 105, 116, 32, 110, 105, 115, 108, 44, 32, 101, 117, 32, 101, 108,
-101, 105, 102, 101, 110, 100, 32, 110, 105, 98, 104, 32, 110, 105, 98, 104, 32, 118, 101, 108, 32, 108, 101, 99, 116, 117, 115, 46, 32, 86, 105, 118,
-97, 109, 117, 115, 32, 112, 108, 97, 99, 101, 114, 97, 116, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 111, 100, 105, 111, 32, 100, 111, 108, 111,
-114, 44, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32, 110, 111, 110, 44, 32, 115, 111, 100, 97, 108, 101, 115, 32, 105, 100, 44, 32, 118, 105, 118,
-101, 114, 114, 97, 32, 101, 103, 101, 116, 44, 32, 100, 105, 97, 109, 46, 32, 78, 117, 110, 99, 32, 109, 97, 117, 114, 105, 115, 32, 109, 97, 103,
-110, 97, 44, 32, 101, 103, 101, 115, 116, 97, 115, 32, 113, 117, 105, 115, 44, 32, 102, 101, 117, 103, 105, 97, 116, 32, 105, 100, 44, 32, 102, 101,
-114, 109, 101, 110, 116, 117, 109, 32, 118, 105, 118, 101, 114, 114, 97, 44, 32, 109, 105, 46, 32, 65, 101, 110, 101, 97, 110, 32, 115, 117, 115, 99,
-105, 112, 105, 116, 32, 110, 105, 115, 108, 32, 110, 111, 110, 32, 110, 117, 110, 99, 46, 32, 80, 114, 111, 105, 110, 32, 113, 117, 105, 115, 32, 108,
-101, 99, 116, 117, 115, 32, 97, 99, 32, 116, 101, 108, 108, 117, 115, 32, 110, 111, 110, 117, 109, 109, 121, 32, 99, 111, 109, 109, 111, 100, 111, 46,
-32, 78, 117, 110, 99, 32, 101, 103, 101, 116, 32, 100, 105, 97, 109, 32, 97, 99, 32, 101, 108, 105, 116, 32, 118, 101, 115, 116, 105, 98, 117, 108,
-117, 109, 32, 97, 117, 99, 116, 111, 114, 46, 32, 69, 116, 105, 97, 109, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 44, 32, 111, 100, 105, 111,
-32, 115, 101, 100, 32, 108, 97, 99, 105, 110, 105, 97, 32, 99, 111, 110, 115, 101, 113, 117, 97, 116, 44, 32, 106, 117, 115, 116, 111, 32, 109, 105,
-32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 112, 117, 114, 117, 115, 44, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 101, 117, 105, 115, 109,
-111, 100, 32, 108, 105, 98, 101, 114, 111, 32, 109, 101, 116, 117, 115, 32, 115, 101, 100, 32, 116, 111, 114, 116, 111, 114, 46, 32, 77, 97, 101, 99,
-101, 110, 97, 115, 32, 97, 99, 32, 101, 108, 105, 116, 32, 115, 101, 100, 32, 108, 111, 114, 101, 109, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101,
-32, 103, 114, 97, 118, 105, 100, 97, 46, 32, 80, 114, 111, 105, 110, 32, 108, 101, 99, 116, 117, 115, 32, 101, 114, 111, 115, 44, 32, 117, 108, 108,
-97, 109, 99, 111, 114, 112, 101, 114, 32, 105, 100, 44, 32, 118, 111, 108, 117, 116, 112, 97, 116, 32, 113, 117, 105, 115, 44, 32, 99, 111, 110, 100,
-105, 109, 101, 110, 116, 117, 109, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 44, 32, 115, 97, 112, 105, 101, 110, 46, 32, 83, 101, 100, 32, 101,
-116, 32, 109, 97, 115, 115, 97, 32, 101, 103, 101, 116, 32, 108, 111, 114, 101, 109, 32, 97, 108, 105, 113, 117, 101, 116, 32, 116, 101, 109, 112, 117,
-115, 46, 32, 68, 117, 105, 115, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 110, 105, 115, 108, 32, 110, 111, 110, 32, 114, 105, 115, 117, 115,
-46, 32, 78, 97, 109, 32, 105, 100, 32, 113, 117, 97, 109, 46, 32, 78, 117, 108, 108, 97, 109, 32, 101, 115, 116, 46, 32, 80, 114, 111, 105, 110,
-32, 111, 114, 99, 105, 32, 100, 105, 97, 109, 44, 32, 112, 111, 115, 117, 101, 114, 101, 32, 101, 116, 44, 32, 112, 104, 97, 114, 101, 116, 114, 97,
-32, 99, 111, 109, 109, 111, 100, 111, 44, 32, 100, 105, 99, 116, 117, 109, 32, 118, 101, 108, 44, 32, 101, 110, 105, 109, 46, 32, 80, 114, 111, 105,
-110, 32, 101, 103, 101, 116, 32, 101, 114, 97, 116, 46, 32, 68, 111, 110, 101, 99, 32, 110, 105, 115, 108, 46, 32, 77, 97, 101, 99, 101, 110, 97,
-115, 32, 97, 117, 99, 116, 111, 114, 32, 118, 101, 108, 105, 116, 32, 117, 116, 32, 112, 101, 100, 101, 46, 32, 78, 117, 110, 99, 32, 118, 105, 116,
-97, 101, 32, 108, 101, 99, 116, 117, 115, 32, 110, 101, 99, 32, 108, 105, 98, 101, 114, 111, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 104,
-101, 110, 100, 114, 101, 114, 105, 116, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 118, 97, 114, 105, 117, 115, 44, 32, 101, 114, 97, 116, 32, 117,
-108, 116, 114, 105, 99, 101, 115, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 101, 117, 105, 115, 109, 111, 100, 44, 32, 112, 117, 114, 117, 115, 32,
-108, 97, 99, 117, 115, 32, 100, 105, 99, 116, 117, 109, 32, 101, 114, 111, 115, 44, 32, 97, 116, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117,
-109, 32, 101, 110, 105, 109, 32, 100, 117, 105, 32, 110, 101, 99, 32, 109, 97, 103, 110, 97, 46, 32, 77, 111, 114, 98, 105, 32, 100, 105, 97, 109,
-46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 115, 101, 100, 32, 101, 115, 116, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 110,
-101, 99, 32, 108, 105, 98, 101, 114, 111, 32, 105, 110, 32, 97, 114, 99, 117, 32, 102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 115, 111, 108, 108,
-105, 99, 105, 116, 117, 100, 105, 110, 46, 32, 73, 110, 32, 114, 117, 116, 114, 117, 109, 32, 110, 105, 115, 108, 32, 97, 116, 32, 97, 114, 99, 117,
-46, 32, 78, 117, 108, 108, 97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 77, 97, 117, 114, 105, 115, 32, 100, 105, 103, 110, 105, 115, 115,
-105, 109, 46, 32, 69, 116, 105, 97, 109, 32, 101, 115, 116, 32, 109, 97, 117, 114, 105, 115, 44, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32, 115,
-101, 100, 44, 32, 118, 105, 118, 101, 114, 114, 97, 32, 101, 116, 44, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 115, 101, 100, 44, 32, 110,
-101, 113, 117, 101, 46, 32, 85, 116, 32, 97, 116, 32, 108, 101, 99, 116, 117, 115, 32, 105, 100, 32, 110, 105, 98, 104, 32, 108, 117, 99, 116, 117,
-115, 32, 111, 114, 110, 97, 114, 101, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 97, 114, 105, 117, 115, 32, 112, 111, 114, 116, 116, 105, 116, 111,
-114, 32, 114, 105, 115, 117, 115, 46, 32, 85, 116, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 97, 108, 105, 113, 117, 101, 116, 32, 114, 105,
-115, 117, 115, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 108, 117, 99, 116, 117, 115, 32, 110, 101, 113, 117, 101, 32, 115, 105, 116,
-32, 97, 109, 101, 116, 32, 110, 117, 110, 99, 46, 32, 68, 117, 105, 115, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 32, 110, 105, 98, 104, 46,
-32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 100, 97, 112, 105, 98, 117, 115, 46, 32, 80, 114, 111, 105, 110, 32, 101, 114, 111,
-115, 32, 108, 105, 98, 101, 114, 111, 44, 32, 97, 108, 105, 113, 117, 97, 109, 32, 110, 111, 110, 44, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116,
-117, 109, 32, 97, 44, 32, 115, 111, 100, 97, 108, 101, 115, 32, 117, 116, 44, 32, 116, 117, 114, 112, 105, 115, 46, 32, 73, 110, 116, 101, 103, 101,
-114, 32, 97, 99, 99, 117, 109, 115, 97, 110, 32, 109, 105, 32, 115, 101, 100, 32, 108, 111, 114, 101, 109, 46, 32, 86, 101, 115, 116, 105, 98, 117,
-108, 117, 109, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 115, 111, 100, 97, 108, 101, 115, 32, 110, 105, 115, 108, 46, 32, 78,
-117, 108, 108, 97, 32, 101, 117, 32, 106, 117, 115, 116, 111, 32, 113, 117, 105, 115, 32, 100, 117, 105, 32, 112, 114, 101, 116, 105, 117, 109, 32, 114,
-104, 111, 110, 99, 117, 115, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 118, 105, 118, 101, 114, 114, 97, 32, 99, 111, 109, 109, 111, 100, 111,
-32, 109, 105, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32, 100, 111, 108, 111, 114, 32, 108, 105, 98, 101, 114, 111, 44, 32, 118, 105, 118, 101,
-114, 114, 97, 32, 97, 44, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 97, 108, 105, 113, 117, 101, 116, 32,
-118, 105, 116, 97, 101, 44, 32, 100, 117, 105, 46, 32, 77, 97, 117, 114, 105, 115, 32, 99, 111, 110, 118, 97, 108, 108, 105, 115, 32, 108, 101, 99,
-116, 117, 115, 32, 101, 116, 32, 109, 105, 46, 32, 77, 97, 117, 114, 105, 115, 32, 115, 97, 103, 105, 116, 116, 105, 115, 46, 32, 83, 101, 100, 32,
-97, 114, 99, 117, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 97, 117, 99, 116, 111, 114, 46, 32, 68, 111, 110, 101, 99,
-32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 112, 117, 114, 117, 115, 32, 110, 111, 110, 32, 116, 101, 108, 108, 117, 115, 46, 32,
-85, 116, 32, 108, 101, 111, 32, 119, 105, 115, 105, 44, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32,
-117, 108, 116, 114, 105, 99, 101, 115, 32, 101, 117, 44, 32, 103, 114, 97, 118, 105, 100, 97, 32, 97, 99, 44, 32, 108, 105, 98, 101, 114, 111, 46,
-32, 77, 97, 117, 114, 105, 115, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 32, 100, 97, 112, 105, 98, 117, 115, 32, 100, 105, 97, 109, 46, 32,
-73, 110, 116, 101, 103, 101, 114, 32, 113, 117, 105, 115, 32, 108, 97, 99, 117, 115, 32, 100, 97, 112, 105, 98, 117, 115, 32, 111, 100, 105, 111, 32,
-112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 118, 97, 114, 105, 117, 115, 46, 32, 70, 117, 115, 99, 101, 32, 112, 101, 100, 101, 32,
-113, 117, 97, 109, 44, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32, 117, 116, 44, 32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 101, 116, 44, 32,
-116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 115, 101, 100, 44, 32, 102, 101, 108, 105, 115, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32,
-101, 114, 111, 115, 32, 101, 110, 105, 109, 44, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 115, 101, 100, 44, 32, 97, 108, 105, 113, 117, 97,
-109, 32, 97, 99, 44, 32, 101, 117, 105, 115, 109, 111, 100, 32, 97, 99, 44, 32, 101, 114, 97, 116, 46, 32, 85, 116, 32, 100, 105, 103, 110, 105,
-115, 115, 105, 109, 44, 32, 108, 97, 99, 117, 115, 32, 97, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 105, 97, 99, 117, 108, 105, 115, 44, 32,
-101, 110, 105, 109, 32, 111, 114, 99, 105, 32, 112, 111, 115, 117, 101, 114, 101, 32, 110, 117, 110, 99, 44, 32, 110, 101, 99, 32, 117, 108, 116, 114,
-105, 99, 105, 101, 115, 32, 108, 101, 99, 116, 117, 115, 32, 114, 105, 115, 117, 115, 32, 105, 110, 32, 111, 100, 105, 111, 46, 32, 69, 116, 105, 97,
-109, 32, 101, 116, 32, 109, 97, 115, 115, 97, 32, 105, 100, 32, 100, 117, 105, 32, 99, 111, 109, 109, 111, 100, 111, 32, 118, 101, 104, 105, 99, 117,
-108, 97, 46, 32, 78, 117, 110, 99, 32, 98, 108, 97, 110, 100, 105, 116, 32, 116, 111, 114, 116, 111, 114, 32, 113, 117, 105, 115, 32, 100, 117, 105,
-46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 110, 105, 115, 108, 46, 32, 83, 101, 100, 32, 118, 101, 110, 101, 110, 97, 116, 105, 115, 32, 98, 108,
-97, 110, 100, 105, 116, 32, 108, 105, 103, 117, 108, 97, 46, 32, 70, 117, 115, 99, 101, 32, 118, 105, 118, 101, 114, 114, 97, 32, 105, 109, 112, 101,
-114, 100, 105, 101, 116, 32, 109, 97, 103, 110, 97, 46, 32, 68, 111, 110, 101, 99, 32, 101, 103, 101, 116, 32, 110, 117, 110, 99, 32, 113, 117, 105,
-115, 32, 101, 115, 116, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32, 108, 111, 98, 111, 114, 116, 105, 115, 46, 32, 86, 101, 115, 116, 105, 98, 117,
-108, 117, 109, 32, 113, 117, 105, 115, 32, 108, 101, 99, 116, 117, 115, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 101, 108, 32, 111, 114, 99, 105,
-32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 110, 117, 110, 99, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 32, 98, 105, 98, 101, 110, 100, 117,
-109, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 101, 103, 101, 116, 32, 108, 101, 111, 46, 32, 77, 111, 114, 98, 105, 32,
-118, 101, 108, 32, 117, 114, 110, 97, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 101, 114, 97, 116, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109,
-32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 46, 32, 83, 101, 100, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 44, 32, 108, 105, 98, 101, 114,
-111, 32, 101, 116, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 99, 111, 110, 103, 117, 101, 44, 32, 119, 105, 115, 105, 32, 108,
-101, 99, 116, 117, 115, 32, 115, 111, 100, 97, 108, 101, 115, 32, 100, 111, 108, 111, 114, 44, 32, 101, 103, 101, 116, 32, 109, 111, 108, 101, 115, 116,
-105, 101, 32, 109, 97, 103, 110, 97, 32, 111, 114, 99, 105, 32, 118, 101, 108, 32, 116, 101, 108, 108, 117, 115, 46, 32, 83, 101, 100, 32, 116, 101,
-109, 112, 111, 114, 32, 97, 110, 116, 101, 32, 101, 116, 32, 101, 110, 105, 109, 46, 32, 77, 97, 117, 114, 105, 115, 32, 101, 108, 105, 116, 46, 32,
-67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32, 109,
-97, 115, 115, 97, 46, 32, 83, 101, 100, 32, 118, 105, 118, 101, 114, 114, 97, 46, 32, 68, 117, 105, 115, 32, 110, 117, 108, 108, 97, 46, 32, 78,
-97, 109, 32, 98, 105, 98, 101, 110, 100, 117, 109, 46, 32, 78, 97, 109, 32, 116, 111, 114, 116, 111, 114, 32, 108, 111, 114, 101, 109, 44, 32, 117,
-108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 118, 105, 116, 97, 101, 44, 32, 100, 105, 99, 116, 117, 109, 32, 115, 101, 100, 44, 32, 112, 111,
-115, 117, 101, 114, 101, 32, 101, 117, 44, 32, 106, 117, 115, 116, 111, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 97, 100, 105, 112, 105, 115, 99,
-105, 110, 103, 32, 97, 114, 99, 117, 32, 118, 105, 116, 97, 101, 32, 116, 117, 114, 112, 105, 115, 46, 32, 68, 111, 110, 101, 99, 32, 109, 97, 108,
-101, 115, 117, 97, 100, 97, 32, 112, 111, 115, 117, 101, 114, 101, 32, 108, 105, 98, 101, 114, 111, 46, 32, 85, 116, 32, 115, 101, 100, 32, 116, 101,
-108, 108, 117, 115, 46, 32, 70, 117, 115, 99, 101, 32, 115, 101, 100, 32, 110, 117, 110, 99, 32, 101, 103, 101, 116, 32, 110, 105, 115, 108, 32, 100,
-97, 112, 105, 98, 117, 115, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 112, 111,
-116, 101, 110, 116, 105, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 108, 105, 98, 101, 114, 111, 32,
-101, 116, 32, 109, 101, 116, 117, 115, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 112, 111, 115, 117, 101, 114, 101, 46, 32, 77, 97, 101, 99, 101,
-110, 97, 115, 32, 110, 111, 110, 32, 115, 101, 109, 32, 110, 111, 110, 32, 113, 117, 97, 109, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 32, 98,
-108, 97, 110, 100, 105, 116, 46, 32, 68, 117, 105, 115, 32, 114, 105, 115, 117, 115, 32, 116, 101, 108, 108, 117, 115, 44, 32, 114, 117, 116, 114, 117,
-109, 32, 118, 105, 116, 97, 101, 44, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 32, 110, 101, 99, 44, 32, 109, 97, 108, 101, 115, 117, 97, 100,
-97, 32, 110, 101, 99, 44, 32, 105, 112, 115, 117, 109, 46, 32, 78, 117, 110, 99, 32, 113, 117, 97, 109, 32, 100, 111, 108, 111, 114, 44, 32, 108,
-117, 99, 116, 117, 115, 32, 101, 103, 101, 116, 44, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 110, 111, 110, 44, 32, 114, 104, 111, 110, 99, 117,
-115, 32, 97, 116, 44, 32, 116, 101, 108, 108, 117, 115, 46, 32, 68, 117, 105, 115, 32, 112, 101, 100, 101, 32, 108, 101, 99, 116, 117, 115, 44, 32,
-109, 97, 116, 116, 105, 115, 32, 97, 100, 105, 112, 105, 115, 99, 105, 110, 103, 44, 32, 116, 101, 109, 112, 111, 114, 32, 117, 116, 44, 32, 112, 111,
-114, 116, 97, 32, 97, 116, 44, 32, 109, 105, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 114, 105, 115, 117, 115, 32, 110,
-117, 108, 108, 97, 44, 32, 115, 111, 100, 97, 108, 101, 115, 32, 115, 101, 100, 44, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 105, 100, 44, 32,
-110, 111, 110, 117, 109, 109, 121, 32, 118, 105, 116, 97, 101, 44, 32, 108, 105, 103, 117, 108, 97, 46, 32, 77, 111, 114, 98, 105, 32, 112, 117, 108,
-118, 105, 110, 97, 114, 32, 112, 101, 100, 101, 32, 117, 116, 32, 109, 97, 115, 115, 97, 46, 32, 78, 117, 110, 99, 32, 114, 105, 115, 117, 115, 32,
-109, 97, 117, 114, 105, 115, 44, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 101, 116, 44, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 101,
-117, 44, 32, 115, 117, 115, 99, 105, 112, 105, 116, 32, 118, 101, 108, 44, 32, 111, 114, 99, 105, 46, 32, 73, 110, 32, 102, 97, 117, 99, 105, 98,
-117, 115, 32, 102, 101, 108, 105, 115, 32, 105, 110, 32, 97, 114, 99, 117, 46, 32, 78, 117, 108, 108, 97, 32, 115, 105, 116, 32, 97, 109, 101, 116,
-32, 101, 108, 105, 116, 46, 32, 78, 117, 108, 108, 97, 32, 101, 114, 97, 116, 32, 115, 97, 112, 105, 101, 110, 44, 32, 115, 97, 103, 105, 116, 116,
-105, 115, 32, 101, 103, 101, 116, 44, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 101, 103, 101, 116, 44, 32, 118, 105, 118, 101, 114, 114, 97,
-32, 101, 117, 44, 32, 102, 101, 108, 105, 115, 46, 32, 78, 97, 109, 32, 97, 99, 32, 105, 112, 115, 117, 109, 46, 32, 83, 117, 115, 112, 101, 110,
-100, 105, 115, 115, 101, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 116, 117, 114, 112, 105, 115, 32, 118, 101, 108, 32, 115, 101, 109, 32, 108,
-97, 99, 105, 110, 105, 97, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 46, 32, 77, 97, 117, 114, 105, 115, 32, 111, 114, 110, 97, 114,
-101, 32, 105, 112, 115, 117, 109, 32, 115, 101, 100, 32, 108, 105, 103, 117, 108, 97, 46, 32, 68, 117, 105, 115, 32, 102, 97, 99, 105, 108, 105, 115,
-105, 115, 32, 110, 101, 113, 117, 101, 32, 113, 117, 105, 115, 32, 111, 114, 99, 105, 46, 32, 78, 117, 108, 108, 97, 109, 32, 101, 116, 32, 101, 114,
-97, 116, 32, 101, 116, 32, 111, 114, 99, 105, 32, 108, 97, 99, 105, 110, 105, 97, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 46,
-32, 68, 111, 110, 101, 99, 32, 97, 99, 32, 105, 112, 115, 117, 109, 46, 32, 68, 117, 105, 115, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32, 105,
-112, 115, 117, 109, 32, 97, 99, 32, 97, 114, 99, 117, 46, 32, 65, 101, 110, 101, 97, 110, 32, 99, 111, 110, 103, 117, 101, 32, 97, 99, 99, 117,
-109, 115, 97, 110, 32, 97, 110, 116, 101, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 98, 105, 98, 101, 110, 100, 117, 109, 44, 32, 108, 101, 111,
-32, 117, 116, 32, 111, 114, 110, 97, 114, 101, 32, 97, 108, 105, 113, 117, 97, 109, 44, 32, 110, 117, 110, 99, 32, 101, 114, 97, 116, 32, 99, 111,
-110, 100, 105, 109, 101, 110, 116, 117, 109, 32, 97, 114, 99, 117, 44, 32, 117, 116, 32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 109, 105, 32, 97,
-117, 103, 117, 101, 32, 101, 116, 32, 110, 117, 108, 108, 97, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 108, 97, 99, 105, 110, 105, 97, 32, 97,
-108, 105, 113, 117, 101, 116, 32, 119, 105, 115, 105, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 110, 101, 99, 32, 100, 117, 105, 46, 32, 69, 116,
-105, 97, 109, 32, 119, 105, 115, 105, 32, 108, 101, 111, 44, 32, 101, 117, 105, 115, 109, 111, 100, 32, 118, 105, 116, 97, 101, 44, 32, 118, 117, 108,
-112, 117, 116, 97, 116, 101, 32, 97, 44, 32, 100, 105, 99, 116, 117, 109, 32, 118, 105, 116, 97, 101, 44, 32, 113, 117, 97, 109, 46, 32, 81, 117,
-105, 115, 113, 117, 101, 32, 113, 117, 105, 115, 32, 116, 111, 114, 116, 111, 114, 46, 32, 69, 116, 105, 97, 109, 32, 105, 110, 116, 101, 114, 100, 117,
-109, 46, 32, 73, 110, 32, 109, 97, 115, 115, 97, 32, 101, 114, 97, 116, 44, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 115, 101, 100, 44,
-32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32, 118, 101, 108, 44, 32, 118, 101, 104, 105, 99, 117, 108, 97, 32, 102, 114, 105, 110, 103, 105, 108,
-108, 97, 44, 32, 97, 117, 103, 117, 101, 46, 32, 78, 117, 108, 108, 97, 32, 118, 101, 108, 32, 117, 114, 110, 97, 46, 32, 73, 110, 32, 108, 105,
-98, 101, 114, 111, 32, 109, 105, 44, 32, 112, 114, 101, 116, 105, 117, 109, 32, 115, 101, 100, 44, 32, 109, 97, 116, 116, 105, 115, 32, 116, 101, 109,
-112, 117, 115, 44, 32, 115, 97, 103, 105, 116, 116, 105, 115, 32, 115, 101, 100, 44, 32, 109, 97, 115, 115, 97, 46, 32, 83, 117, 115, 112, 101, 110,
-100, 105, 115, 115, 101, 32, 113, 117, 97, 109, 32, 119, 105, 115, 105, 44, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109, 32, 113, 117, 105, 115, 44,
-32, 115, 97, 103, 105, 116, 116, 105, 115, 32, 97, 116, 44, 32, 99, 111, 110, 115, 101, 113, 117, 97, 116, 32, 101, 103, 101, 116, 44, 32, 111, 100,
-105, 111, 46, 32, 78, 117, 108, 108, 97, 109, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 44, 32, 112, 117, 114, 117, 115, 32, 113, 117, 105, 115,
-32, 97, 108, 105, 113, 117, 97, 109, 32, 99, 117, 114, 115, 117, 115, 44, 32, 116, 117, 114, 112, 105, 115, 32, 111, 100, 105, 111, 32, 101, 103, 101,
-115, 116, 97, 115, 32, 106, 117, 115, 116, 111, 44, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 103, 114, 97, 118, 105, 100, 97, 32, 116, 117, 114,
-112, 105, 115, 32, 119, 105, 115, 105, 32, 118, 101, 108, 32, 116, 111, 114, 116, 111, 114, 46, 32, 78, 117, 110, 99, 32, 117, 108, 116, 114, 105, 99,
-105, 101, 115, 32, 112, 111, 114, 116, 97, 32, 112, 117, 114, 117, 115, 46, 32, 80, 114, 111, 105, 110, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109,
-32, 101, 114, 97, 116, 32, 97, 99, 32, 111, 114, 99, 105, 46, 32, 85, 116, 32, 118, 101, 108, 32, 109, 97, 103, 110, 97, 32, 110, 101, 99, 32,
-109, 105, 32, 102, 101, 117, 103, 105, 97, 116, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 46, 32, 85, 116, 32, 108, 105, 103, 117, 108, 97, 46,
-32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 97, 110, 116, 101, 32, 105, 112, 115, 117, 109, 32, 112, 114, 105, 109, 105, 115, 32, 105, 110,
-32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 111, 114, 99, 105, 32, 108, 117, 99, 116, 117, 115, 32, 101, 116, 32, 117, 108, 116, 114, 105, 99, 101,
-115, 32, 112, 111, 115, 117, 101, 114, 101, 32, 99, 117, 98, 105, 108, 105, 97, 32, 67, 117, 114, 97, 101, 59, 32, 68, 111, 110, 101, 99, 32, 101,
-116, 32, 109, 97, 103, 110, 97, 32, 105, 110, 32, 100, 105, 97, 109, 32, 112, 111, 114, 116, 97, 32, 110, 111, 110, 117, 109, 109, 121, 46, 32, 77,
-97, 101, 99, 101, 110, 97, 115, 32, 117, 116, 32, 115, 101, 109, 32, 105, 110, 32, 116, 117, 114, 112, 105, 115, 32, 102, 101, 114, 109, 101, 110, 116,
-117, 109, 32, 118, 105, 118, 101, 114, 114, 97, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 97, 116, 32, 111, 114, 99, 105, 46,
-32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 104, 97, 98, 105, 116, 97, 110, 116, 32, 109, 111, 114, 98, 105, 32, 116, 114, 105,
-115, 116, 105, 113, 117, 101, 32, 115, 101, 110, 101, 99, 116, 117, 115, 32, 101, 116, 32, 110, 101, 116, 117, 115, 32, 101, 116, 32, 109, 97, 108, 101,
-115, 117, 97, 100, 97, 32, 102, 97, 109, 101, 115, 32, 97, 99, 32, 116, 117, 114, 112, 105, 115, 32, 101, 103, 101, 115, 116, 97, 115, 46, 32, 86,
-101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 97, 110, 116, 101, 32, 105, 112, 115, 117, 109, 32, 112, 114, 105, 109, 105, 115, 32, 105, 110, 32, 102,
-97, 117, 99, 105, 98, 117, 115, 32, 111, 114, 99, 105, 32, 108, 117, 99, 116, 117, 115, 32, 101, 116, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32,
-112, 111, 115, 117, 101, 114, 101, 32, 99, 117, 98, 105, 108, 105, 97, 32, 67, 117, 114, 97, 101, 59, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115,
-113, 117, 101, 32, 114, 117, 116, 114, 117, 109, 32, 101, 108, 101, 105, 102, 101, 110, 100, 32, 106, 117, 115, 116, 111, 46, 32, 78, 117, 108, 108, 97,
-109, 32, 118, 105, 116, 97, 101, 32, 112, 101, 100, 101, 46, 32, 68, 111, 110, 101, 99, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117, 109, 32,
-110, 105, 98, 104, 32, 101, 116, 32, 111, 100, 105, 111, 46, 32, 83, 101, 100, 32, 101, 116, 32, 109, 101, 116, 117, 115, 46, 32, 67, 108, 97, 115,
-115, 32, 97, 112, 116, 101, 110, 116, 32, 116, 97, 99, 105, 116, 105, 32, 115, 111, 99, 105, 111, 115, 113, 117, 32, 97, 100, 32, 108, 105, 116, 111,
-114, 97, 32, 116, 111, 114, 113, 117, 101, 110, 116, 32, 112, 101, 114, 32, 99, 111, 110, 117, 98, 105, 97, 32, 110, 111, 115, 116, 114, 97, 44, 32,
-112, 101, 114, 32, 105, 110, 99, 101, 112, 116, 111, 115, 32, 104, 121, 109, 101, 110, 97, 101, 111, 115, 46, 32, 78, 97, 109, 32, 116, 101, 109, 112,
-117, 115, 46, 32, 83, 101, 100, 32, 97, 99, 32, 119, 105, 115, 105, 46, 32, 73, 110, 32, 104, 97, 99, 32, 104, 97, 98, 105, 116, 97, 115, 115,
-101, 32, 112, 108, 97, 116, 101, 97, 32, 100, 105, 99, 116, 117, 109, 115, 116, 46, 32, 83, 101, 100, 32, 115, 101, 100, 32, 119, 105, 115, 105, 46,
-32, 85, 116, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 116, 101, 108, 108, 117, 115, 32, 110, 111, 110, 32, 108, 105, 103, 117, 108, 97, 46,
-32, 73, 110, 116, 101, 103, 101, 114, 32, 109, 101, 116, 117, 115, 46, 32, 73, 110, 32, 108, 97, 99, 105, 110, 105, 97, 32, 100, 117, 105, 46, 32,
-67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 111, 114, 110, 97, 114, 101, 46, 32, 77, 97, 117, 114, 105, 115, 32, 118, 101, 108, 32, 117, 114, 110,
-97, 46, 32, 78, 97, 109, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 117, 114,
-110, 97, 46, 32, 78, 117, 110, 99, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 101, 114, 97,
-116, 46, 32, 83, 101, 100, 32, 98, 108, 97, 110, 100, 105, 116, 44, 32, 114, 105, 115, 117, 115, 32, 110, 111, 110, 32, 99, 111, 109, 109, 111, 100,
-111, 32, 110, 111, 110, 117, 109, 109, 121, 44, 32, 108, 105, 103, 117, 108, 97, 32, 101, 114, 97, 116, 32, 102, 101, 114, 109, 101, 110, 116, 117, 109,
-32, 110, 105, 98, 104, 44, 32, 101, 117, 32, 102, 97, 99, 105, 108, 105, 115, 105, 115, 32, 97, 110, 116, 101, 32, 110, 101, 113, 117, 101, 32, 115,
-101, 100, 32, 115, 101, 109, 46, 32, 69, 116, 105, 97, 109, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 32, 106, 117, 115, 116, 111, 32,
-101, 103, 101, 116, 32, 119, 105, 115, 105, 46, 32, 78, 117, 110, 99, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 46, 32, 80, 114, 111, 105, 110,
-32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 113, 117, 97, 109, 32, 110, 111, 110, 32, 108, 101, 99, 116, 117, 115, 46, 32, 80, 114, 111, 105, 110,
-32, 117, 116, 32, 116, 117, 114, 112, 105, 115, 32, 113, 117, 105, 115, 32, 97, 117, 103, 117, 101, 32, 112, 101, 108, 108, 101, 110, 116, 101, 115, 113,
-117, 101, 32, 100, 105, 99, 116, 117, 109, 46, 32, 70, 117, 115, 99, 101, 32, 101, 116, 32, 108, 111, 114, 101, 109, 46, 32, 65, 108, 105, 113, 117,
-97, 109, 32, 117, 114, 110, 97, 32, 108, 97, 99, 117, 115, 44, 32, 98, 108, 97, 110, 100, 105, 116, 32, 115, 101, 100, 44, 32, 118, 101, 115, 116,
-105, 98, 117, 108, 117, 109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 101, 116, 44, 32, 100, 111,
-108, 111, 114, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 97, 117, 99, 116, 111, 114, 32, 101, 114, 97, 116, 32, 110, 101, 99, 32, 108,
-111, 114, 101, 109, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 117, 114, 110, 97, 32, 119, 105, 115, 105, 44, 32, 108, 97, 99, 105, 110,
-105, 97, 32, 117, 116, 44, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 44, 32, 99, 111, 110, 100, 105,
-109, 101, 110, 116, 117, 109, 32, 105, 100, 44, 32, 111, 100, 105, 111, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 99, 111, 110, 118, 97,
-108, 108, 105, 115, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 106, 117, 115, 116, 111, 46, 32, 68, 111, 110, 101, 99, 32, 118, 101,
-115, 116, 105, 98, 117, 108, 117, 109, 32, 101, 115, 116, 32, 97, 99, 32, 113, 117, 97, 109, 46, 32, 78, 117, 108, 108, 97, 109, 32, 118, 105, 116,
-97, 101, 32, 101, 108, 105, 116, 32, 101, 117, 32, 109, 97, 115, 115, 97, 32, 118, 97, 114, 105, 117, 115, 32, 118, 117, 108, 112, 117, 116, 97, 116,
-101, 46, 32, 78, 117, 108, 108, 97, 32, 102, 97, 99, 105, 108, 105, 115, 105, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 112,
-111, 116, 101, 110, 116, 105, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 110, 111, 110, 32, 108, 105, 98, 101, 114, 111, 46, 32, 78, 117, 108,
-108, 97, 109, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 109, 97, 115, 115, 97, 32, 105, 100, 32, 109, 97, 103, 110, 97, 32, 118, 105, 118,
-101, 114, 114, 97, 32, 99, 111, 109, 109, 111, 100, 111, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 108, 105, 98, 101, 114, 111, 32,
-116, 111, 114, 116, 111, 114, 44, 32, 108, 117, 99, 116, 117, 115, 32, 97, 99, 44, 32, 118, 105, 118, 101, 114, 114, 97, 32, 99, 111, 110, 103, 117,
-101, 44, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 32, 118, 101, 108, 44, 32, 108, 105, 98, 101, 114, 111, 46, 32, 65, 101, 110,
-101, 97, 110, 32, 97, 114, 99, 117, 32, 97, 117, 103, 117, 101, 44, 32, 108, 117, 99, 116, 117, 115, 32, 105, 100, 44, 32, 108, 97, 111, 114, 101,
-101, 116, 32, 112, 117, 108, 118, 105, 110, 97, 114, 44, 32, 100, 105, 99, 116, 117, 109, 32, 115, 101, 100, 44, 32, 108, 101, 99, 116, 117, 115, 46,
-32, 68, 111, 110, 101, 99, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 118, 111, 108, 117, 116, 112, 97, 116, 32, 100, 111, 108, 111, 114,
-46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 104, 97, 98, 105, 116, 97, 110, 116, 32, 109, 111, 114, 98, 105, 32, 116, 114,
-105, 115, 116, 105, 113, 117, 101, 32, 115, 101, 110, 101, 99, 116, 117, 115, 32, 101, 116, 32, 110, 101, 116, 117, 115, 32, 101, 116, 32, 109, 97, 108,
-101, 115, 117, 97, 100, 97, 32, 102, 97, 109, 101, 115, 32, 97, 99, 32, 116, 117, 114, 112, 105, 115, 32, 101, 103, 101, 115, 116, 97, 115, 46, 32,
-80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 97, 117, 103, 117, 101, 32, 116, 117, 114, 112, 105, 115, 44, 32, 108, 97, 111, 114, 101,
-101, 116, 32, 110, 101, 99, 44, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 97, 116, 44, 32, 110, 111, 110, 117, 109, 109, 121, 32, 118, 105,
-116, 97, 101, 44, 32, 110, 105, 98, 104, 46, 32, 69, 116, 105, 97, 109, 32, 111, 114, 99, 105, 32, 115, 97, 112, 105, 101, 110, 44, 32, 99, 111,
-110, 103, 117, 101, 32, 105, 110, 44, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 114, 117, 116,
-114, 117, 109, 32, 118, 101, 108, 44, 32, 110, 105, 98, 104, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 101, 117, 32, 108, 111, 114, 101, 109, 46,
-32, 77, 97, 117, 114, 105, 115, 32, 112, 114, 101, 116, 105, 117, 109, 32, 108, 101, 111, 32, 101, 116, 32, 101, 108, 105, 116, 46, 32, 73, 110, 32,
-110, 111, 110, 117, 109, 109, 121, 32, 117, 108, 116, 114, 105, 99, 105, 101, 115, 32, 115, 97, 112, 105, 101, 110, 46, 32, 77, 97, 117, 114, 105, 115,
-32, 118, 97, 114, 105, 117, 115, 46, 32, 77, 97, 117, 114, 105, 115, 32, 115, 101, 100, 32, 108, 105, 98, 101, 114, 111, 46, 32, 67, 117, 114, 97,
-98, 105, 116, 117, 114, 32, 117, 108, 108, 97, 109, 99, 111, 114, 112, 101, 114, 32, 101, 108, 105, 116, 32, 101, 117, 32, 112, 117, 114, 117, 115, 46,
-32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 118, 101, 108, 105, 116, 32, 112, 101, 100, 101, 44, 32, 115, 101, 109, 112, 101, 114, 32, 115,
-105, 116, 32, 97, 109, 101, 116, 44, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 118, 105, 116, 97, 101, 44, 32, 116, 105, 110, 99, 105, 100, 117,
-110, 116, 32, 118, 101, 108, 44, 32, 100, 117, 105, 46, 32, 78, 117, 108, 108, 97, 32, 110, 101, 113, 117, 101, 32, 97, 110, 116, 101, 44, 32, 115,
-97, 103, 105, 116, 116, 105, 115, 32, 101, 117, 44, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 101, 116, 44, 32, 108, 97, 99, 105, 110,
-105, 97, 32, 97, 44, 32, 108, 105, 98, 101, 114, 111, 46, 32, 77, 111, 114, 98, 105, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 119, 105, 115,
-105, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 110, 111, 110, 32, 102, 101, 108, 105, 115, 32, 113, 117, 105, 115, 32, 97,
-114, 99, 117, 32, 98, 105, 98, 101, 110, 100, 117, 109, 32, 111, 114, 110, 97, 114, 101, 46, 32, 65, 101, 110, 101, 97, 110, 32, 101, 110, 105, 109,
-32, 109, 101, 116, 117, 115, 44, 32, 99, 111, 109, 109, 111, 100, 111, 32, 101, 117, 44, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 110, 111,
-110, 117, 109, 109, 121, 44, 32, 101, 117, 105, 115, 109, 111, 100, 32, 117, 116, 44, 32, 113, 117, 97, 109, 46, 32, 78, 117, 108, 108, 97, 32, 101,
-108, 101, 105, 102, 101, 110, 100, 32, 110, 105, 115, 108, 32, 113, 117, 105, 115, 32, 100, 111, 108, 111, 114, 46, 32, 67, 108, 97, 115, 115, 32, 97,
-112, 116, 101, 110, 116, 32, 116, 97, 99, 105, 116, 105, 32, 115, 111, 99, 105, 111, 115, 113, 117, 32, 97, 100, 32, 108, 105, 116, 111, 114, 97, 32,
-116, 111, 114, 113, 117, 101, 110, 116, 32, 112, 101, 114, 32, 99, 111, 110, 117, 98, 105, 97, 32, 110, 111, 115, 116, 114, 97, 44, 32, 112, 101, 114,
-32, 105, 110, 99, 101, 112, 116, 111, 115, 32, 104, 121, 109, 101, 110, 97, 101, 111, 115, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32, 112, 101,
-108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 109, 97, 115, 115, 97, 32, 105, 110, 32, 101, 114, 97, 116, 32, 109, 111, 108, 101, 115, 116, 105,
-101, 32, 109, 111, 108, 101, 115, 116, 105, 101, 46, 32, 77, 97, 117, 114, 105, 115, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 100, 97, 112,
-105, 98, 117, 115, 32, 108, 105, 98, 101, 114, 111, 46, 32, 83, 101, 100, 32, 115, 101, 100, 32, 114, 105, 115, 117, 115, 32, 105, 100, 32, 110, 101,
-113, 117, 101, 32, 100, 105, 99, 116, 117, 109, 32, 111, 114, 110, 97, 114, 101, 46, 32, 83, 101, 100, 32, 101, 117, 32, 108, 105, 103, 117, 108, 97,
-32, 97, 116, 32, 102, 101, 108, 105, 115, 32, 115, 111, 100, 97, 108, 101, 115, 32, 97, 99, 99, 117, 109, 115, 97, 110, 46, 32, 83, 101, 100, 32,
-105, 110, 116, 101, 114, 100, 117, 109, 44, 32, 117, 114, 110, 97, 32, 110, 111, 110, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32, 104, 101, 110, 100,
-114, 101, 114, 105, 116, 44, 32, 113, 117, 97, 109, 32, 109, 105, 32, 111, 114, 110, 97, 114, 101, 32, 108, 105, 98, 101, 114, 111, 44, 32, 105, 100,
-32, 102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 116, 111, 114, 116, 111, 114, 32, 111, 114, 99, 105, 32, 110, 111, 110, 32, 118, 101, 108, 105, 116,
-46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 110, 101, 99, 32, 114, 105, 115, 117, 115, 46, 32, 68, 111, 110, 101, 99, 32, 97, 116, 32, 110, 117,
-110, 99, 32, 118, 105, 116, 97, 101, 32, 116, 101, 108, 108, 117, 115, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32, 118, 101, 115, 116, 105, 98, 117,
-108, 117, 109, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115, 113, 117, 101, 32, 118, 101, 108, 32, 106, 117, 115, 116, 111, 46, 32, 68, 117, 105,
-115, 32, 108, 105, 103, 117, 108, 97, 32, 108, 105, 98, 101, 114, 111, 44, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 113, 117, 105, 115, 44,
-32, 97, 100, 105, 112, 105, 115, 99, 105, 110, 103, 32, 98, 105, 98, 101, 110, 100, 117, 109, 44, 32, 102, 101, 117, 103, 105, 97, 116, 32, 118, 105,
-116, 97, 101, 44, 32, 118, 101, 108, 105, 116, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 101, 116, 32, 97, 114, 99, 117, 46, 32, 70, 117, 115,
-99, 101, 32, 101, 103, 101, 116, 32, 113, 117, 97, 109, 46, 32, 85, 116, 32, 97, 110, 116, 101, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115,
-115, 101, 32, 102, 101, 117, 103, 105, 97, 116, 32, 109, 101, 116, 117, 115, 32, 110, 111, 110, 32, 105, 112, 115, 117, 109, 46, 32, 78, 117, 108, 108,
-97, 32, 116, 101, 109, 112, 117, 115, 32, 108, 101, 111, 32, 117, 116, 32, 109, 105, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 118, 105,
-116, 97, 101, 32, 110, 105, 115, 108, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 46, 32, 69, 116, 105,
-97, 109, 32, 97, 32, 111, 114, 99, 105, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 97, 110, 116, 101, 32, 105, 112, 115, 117, 109,
-32, 112, 114, 105, 109, 105, 115, 32, 105, 110, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 111, 114, 99, 105, 32, 108, 117, 99, 116, 117, 115, 32,
-101, 116, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 112, 111, 115, 117, 101, 114, 101, 32, 99, 117, 98, 105, 108, 105, 97, 32, 67, 117, 114, 97,
-101, 59, 32, 86, 105, 118, 97, 109, 117, 115, 32, 117, 114, 110, 97, 32, 113, 117, 97, 109, 44, 32, 116, 105, 110, 99, 105, 100, 117, 110, 116, 32,
-97, 116, 44, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 118, 101, 108, 44, 32, 102, 101, 117, 103, 105, 97, 116, 32, 101, 103, 101, 116, 44, 32,
-110, 117, 108, 108, 97, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32, 108, 97, 99, 117, 115, 32, 109, 97, 103, 110, 97, 44, 32, 110, 111, 110,
-117, 109, 109, 121, 32, 101, 117, 44, 32, 105, 97, 99, 117, 108, 105, 115, 32, 115, 101, 100, 44, 32, 99, 111, 110, 115, 101, 99, 116, 101, 116, 117,
-101, 114, 32, 113, 117, 105, 115, 44, 32, 101, 110, 105, 109, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 97, 32, 101, 114, 111, 115, 46, 32,
-65, 108, 105, 113, 117, 97, 109, 32, 110, 111, 110, 117, 109, 109, 121, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 110, 101, 113, 117, 101, 46,
-32, 78, 117, 108, 108, 97, 32, 101, 110, 105, 109, 46, 32, 80, 114, 97, 101, 115, 101, 110, 116, 32, 109, 111, 108, 101, 115, 116, 105, 101, 44, 32,
-111, 114, 99, 105, 32, 113, 117, 105, 115, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 32, 118, 111, 108, 117, 116, 112, 97, 116, 44, 32, 108, 97,
-99, 117, 115, 32, 109, 101, 116, 117, 115, 32, 108, 117, 99, 116, 117, 115, 32, 115, 97, 112, 105, 101, 110, 44, 32, 101, 116, 32, 102, 97, 99, 105,
-108, 105, 115, 105, 115, 32, 101, 114, 111, 115, 32, 110, 101, 113, 117, 101, 32, 105, 100, 32, 115, 97, 112, 105, 101, 110, 46, 32, 78, 117, 110, 99,
-32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117, 109, 32, 100, 111, 108, 111, 114, 32, 118, 101, 108, 32, 111, 114, 99, 105, 46, 32, 73, 110, 116,
-101, 103, 101, 114, 32, 119, 105, 115, 105, 32, 100, 105, 97, 109, 44, 32, 112, 111, 114, 116, 116, 105, 116, 111, 114, 32, 115, 105, 116, 32, 97, 109,
-101, 116, 44, 32, 102, 101, 117, 103, 105, 97, 116, 32, 105, 110, 44, 32, 100, 97, 112, 105, 98, 117, 115, 32, 105, 110, 44, 32, 108, 101, 99, 116,
-117, 115, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 101, 114, 97, 116, 32, 118, 111, 108, 117, 116, 112, 97, 116, 46, 32, 81, 117, 105, 115, 113,
-117, 101, 32, 109, 111, 108, 108, 105, 115, 32, 116, 117, 114, 112, 105, 115, 32, 118, 105, 116, 97, 101, 32, 116, 111, 114, 116, 111, 114, 46, 32, 77,
-97, 117, 114, 105, 115, 32, 116, 117, 114, 112, 105, 115, 32, 109, 105, 44, 32, 112, 114, 101, 116, 105, 117, 109, 32, 117, 116, 44, 32, 117, 108, 116,
-114, 105, 99, 101, 115, 32, 115, 101, 100, 44, 32, 112, 111, 114, 116, 97, 32, 105, 110, 44, 32, 106, 117, 115, 116, 111, 46, 32, 83, 117, 115, 112,
-101, 110, 100, 105, 115, 115, 101, 32, 112, 111, 115, 117, 101, 114, 101, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 117, 108, 116, 114, 105, 99, 105,
-101, 115, 32, 108, 97, 99, 117, 115, 32, 118, 105, 116, 97, 101, 32, 101, 110, 105, 109, 46, 32, 68, 111, 110, 101, 99, 32, 108, 97, 99, 117, 115,
-46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32, 112, 111, 116, 101, 110, 116, 105, 46, 32, 68, 111, 110, 101, 99, 32, 109, 111, 108,
-101, 115, 116, 105, 101, 44, 32, 109, 97, 103, 110, 97, 32, 115, 101, 100, 32, 101, 117, 105, 115, 109, 111, 100, 32, 100, 105, 99, 116, 117, 109, 44,
-32, 109, 97, 103, 110, 97, 32, 109, 97, 103, 110, 97, 32, 105, 110, 116, 101, 114, 100, 117, 109, 32, 100, 105, 97, 109, 44, 32, 118, 105, 116, 97,
-101, 32, 115, 97, 103, 105, 116, 116, 105, 115, 32, 108, 101, 111, 32, 108, 111, 114, 101, 109, 32, 97, 99, 32, 110, 101, 113, 117, 101, 46, 32, 67,
-114, 97, 115, 32, 109, 101, 116, 117, 115, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 110, 117, 110, 99, 46, 32, 68, 117, 105, 115, 32, 99, 111,
-110, 115, 101, 99, 116, 101, 116, 117, 101, 114, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 103, 114, 97, 118, 105, 100, 97, 32, 115,
-111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 117, 114, 110, 97, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 118, 111, 108, 117, 116, 112,
-97, 116, 44, 32, 109, 97, 115, 115, 97, 32, 113, 117, 105, 115, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 112, 117, 108, 118, 105, 110, 97, 114,
-44, 32, 101, 114, 111, 115, 32, 112, 117, 114, 117, 115, 32, 100, 105, 103, 110, 105, 115, 115, 105, 109, 32, 110, 117, 110, 99, 44, 32, 101, 103, 101,
-116, 32, 114, 104, 111, 110, 99, 117, 115, 32, 101, 110, 105, 109, 32, 108, 101, 99, 116, 117, 115, 32, 113, 117, 105, 115, 32, 116, 111, 114, 116, 111,
-114, 46, 32, 73, 110, 116, 101, 103, 101, 114, 32, 108, 97, 99, 105, 110, 105, 97, 32, 113, 117, 97, 109, 32, 113, 117, 105, 115, 32, 101, 114, 97,
-116, 32, 99, 111, 110, 118, 97, 108, 108, 105, 115, 32, 109, 97, 116, 116, 105, 115, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101, 32,
-105, 97, 99, 117, 108, 105, 115, 32, 112, 111, 115, 117, 101, 114, 101, 32, 118, 101, 108, 105, 116, 46, 32, 69, 116, 105, 97, 109, 32, 116, 101, 108,
-108, 117, 115, 32, 101, 110, 105, 109, 44, 32, 97, 108, 105, 113, 117, 101, 116, 32, 110, 101, 99, 44, 32, 108, 97, 111, 114, 101, 101, 116, 32, 97,
-44, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32, 110, 111, 110, 44, 32, 118, 101, 108, 105, 116, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 108,
-97, 99, 117, 115, 32, 118, 101, 108, 105, 116, 44, 32, 101, 108, 101, 105, 102, 101, 110, 100, 32, 105, 109, 112, 101, 114, 100, 105, 101, 116, 44, 32,
-102, 114, 105, 110, 103, 105, 108, 108, 97, 32, 105, 100, 44, 32, 100, 97, 112, 105, 98, 117, 115, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117,
-101, 44, 32, 108, 101, 99, 116, 117, 115, 46, 32, 78, 117, 108, 108, 97, 32, 113, 117, 105, 115, 32, 108, 111, 114, 101, 109, 46, 32, 78, 117, 108,
-108, 97, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 110, 101, 113, 117, 101, 32, 101, 116, 32, 100, 117, 105, 46, 32, 80, 104, 97, 115, 101,
-108, 108, 117, 115, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 117, 108, 116, 114, 105, 99, 105, 101, 115, 32, 111, 100, 105, 111, 46, 32, 80,
-104, 97, 115, 101, 108, 108, 117, 115, 32, 118, 105, 116, 97, 101, 32, 108, 105, 103, 117, 108, 97, 46, 32, 80, 101, 108, 108, 101, 110, 116, 101, 115,
-113, 117, 101, 32, 102, 101, 117, 103, 105, 97, 116, 32, 97, 114, 99, 117, 32, 97, 116, 32, 101, 114, 97, 116, 46, 32, 86, 105, 118, 97, 109, 117,
-115, 32, 117, 116, 32, 101, 114, 111, 115, 32, 117, 116, 32, 108, 111, 114, 101, 109, 32, 112, 117, 108, 118, 105, 110, 97, 114, 32, 105, 97, 99, 117,
-108, 105, 115, 46, 32, 80, 114, 111, 105, 110, 32, 108, 111, 98, 111, 114, 116, 105, 115, 32, 105, 112, 115, 117, 109, 32, 105, 100, 32, 110, 117, 110,
-99, 46, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 118, 101, 108, 32, 109, 97, 115, 115, 97, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105,
-115, 115, 101, 32, 110, 117, 108, 108, 97, 32, 105, 112, 115, 117, 109, 44, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 118, 101, 108, 44, 32,
-112, 111, 115, 117, 101, 114, 101, 32, 101, 103, 101, 116, 44, 32, 109, 111, 108, 108, 105, 115, 32, 97, 116, 44, 32, 114, 105, 115, 117, 115, 46, 32,
-86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 115, 101, 100, 32, 100, 105, 97, 109, 32, 105, 100, 32, 101, 115, 116, 32, 100, 97, 112, 105, 98,
-117, 115, 32, 117, 108, 116, 114, 105, 99, 101, 115, 46, 32, 80, 114, 111, 105, 110, 32, 116, 101, 109, 112, 117, 115, 44, 32, 101, 114, 111, 115, 32,
-97, 32, 115, 99, 101, 108, 101, 114, 105, 115, 113, 117, 101, 32, 118, 101, 115, 116, 105, 98, 117, 108, 117, 109, 44, 32, 105, 112, 115, 117, 109, 32,
-97, 114, 99, 117, 32, 97, 108, 105, 113, 117, 97, 109, 32, 109, 105, 44, 32, 117, 116, 32, 102, 101, 117, 103, 105, 97, 116, 32, 108, 105, 98, 101,
-114, 111, 32, 111, 100, 105, 111, 32, 105, 110, 32, 110, 105, 115, 108, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 101, 116, 32, 109, 97, 115, 115,
-97, 32, 97, 32, 109, 97, 117, 114, 105, 115, 32, 108, 117, 99, 116, 117, 115, 32, 99, 111, 110, 103, 117, 101, 46, 32, 85, 116, 32, 105, 100, 32,
-101, 114, 111, 115, 46, 32, 70, 117, 115, 99, 101, 32, 97, 110, 116, 101, 32, 101, 114, 111, 115, 44, 32, 112, 104, 97, 114, 101, 116, 114, 97, 32,
-110, 111, 110, 44, 32, 109, 111, 108, 101, 115, 116, 105, 101, 32, 116, 114, 105, 115, 116, 105, 113, 117, 101, 44, 32, 98, 105, 98, 101, 110, 100, 117,
-109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 119, 105, 115, 105, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 114, 117, 116, 114,
-117, 109, 44, 32, 100, 111, 108, 111, 114, 32, 101, 116, 32, 115, 101, 109, 112, 101, 114, 32, 101, 108, 101, 109, 101, 110, 116, 117, 109, 44, 32, 101,
-114, 111, 115, 32, 97, 110, 116, 101, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 109, 97, 115, 115, 97, 44, 32, 115, 101, 100, 32, 115, 111,
-108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 108, 101, 99, 116, 117, 115, 32, 118, 101, 108, 105, 116, 32, 101, 116, 32, 109, 97, 115, 115, 97,
-46, 32, 73, 110, 32, 97, 117, 99, 116, 111, 114, 46, 32, 65, 108, 105, 113, 117, 97, 109, 32, 101, 114, 97, 116, 32, 118, 111, 108, 117, 116, 112,
-97, 116, 46, 32, 69, 116, 105, 97, 109, 32, 114, 105, 115, 117, 115, 32, 108, 101, 111, 44, 32, 118, 117, 108, 112, 117, 116, 97, 116, 101, 32, 115,
-117, 115, 99, 105, 112, 105, 116, 44, 32, 115, 111, 108, 108, 105, 99, 105, 116, 117, 100, 105, 110, 32, 101, 116, 44, 32, 115, 111, 100, 97, 108, 101,
-115, 32, 101, 103, 101, 116, 44, 32, 110, 105, 115, 108, 46, 32, 86, 101, 115, 116, 105, 98, 117, 108, 117, 109, 32, 97, 110, 116, 101, 32, 105, 112,
-115, 117, 109, 32, 112, 114, 105, 109, 105, 115, 32, 105, 110, 32, 102, 97, 117, 99, 105, 98, 117, 115, 32, 111, 114, 99, 105, 32, 108, 117, 99, 116,
-117, 115, 32, 101, 116, 32, 117, 108, 116, 114, 105, 99, 101, 115, 32, 112, 111, 115, 117, 101, 114, 101, 32, 99, 117, 98, 105, 108, 105, 97, 32, 67,
-117, 114, 97, 101, 59, 32, 67, 117, 114, 97, 98, 105, 116, 117, 114, 32, 108, 111, 98, 111, 114, 116, 105, 115, 44, 32, 108, 105, 98, 101, 114, 111,
-32, 97, 99, 32, 108, 97, 111, 114, 101, 101, 116, 32, 109, 111, 108, 108, 105, 115, 44, 32, 108, 105, 103, 117, 108, 97, 32, 108, 101, 111, 32, 112,
-111, 114, 116, 97, 32, 119, 105, 115, 105, 44, 32, 117, 116, 32, 101, 117, 105, 115, 109, 111, 100, 32, 102, 101, 108, 105, 115, 32, 108, 105, 103, 117,
-108, 97, 32, 105, 100, 32, 101, 108, 105, 116, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 109, 97, 108, 101, 115, 117, 97, 100, 97, 32, 110, 117,
-108, 108, 97, 32, 101, 117, 32, 101, 110, 105, 109, 46, 32, 68, 111, 110, 101, 99, 32, 97, 99, 99, 117, 109, 115, 97, 110, 32, 102, 97, 117, 99,
-105, 98, 117, 115, 32, 111, 114, 99, 105, 46, 32, 78, 117, 108, 108, 97, 32, 108, 97, 99, 105, 110, 105, 97, 32, 97, 110, 116, 101, 46, 32, 80,
-114, 97, 101, 115, 101, 110, 116, 32, 97, 116, 32, 110, 105, 98, 104, 46, 32, 77, 97, 117, 114, 105, 115, 32, 112, 111, 114, 116, 97, 32, 100, 105,
-103, 110, 105, 115, 115, 105, 109, 32, 119, 105, 115, 105, 46, 32, 85, 116, 32, 108, 97, 99, 105, 110, 105, 97, 32, 116, 111, 114, 116, 111, 114, 32,
-110, 101, 99, 32, 110, 117, 110, 99, 46, 32, 80, 104, 97, 115, 101, 108, 108, 117, 115, 32, 101, 116, 32, 97, 117, 103, 117, 101, 46, 32, 73, 110,
-116, 101, 103, 101, 114, 32, 114, 104, 111, 110, 99, 117, 115, 44, 32, 108, 105, 98, 101, 114, 111, 32, 97, 32, 112, 101, 108, 108, 101, 110, 116, 101,
-115, 113, 117, 101, 32, 114, 104, 111, 110, 99, 117, 115, 44, 32, 116, 111, 114, 116, 111, 114, 32, 115, 97, 112, 105, 101, 110, 32, 108, 111, 98, 111,
-114, 116, 105, 115, 32, 112, 101, 100, 101, 44, 32, 101, 103, 101, 116, 32, 99, 111, 110, 100, 105, 109, 101, 110, 116, 117, 109, 32, 115, 97, 112, 105,
-101, 110, 32, 114, 105, 115, 117, 115, 32, 118, 105, 116, 97, 101, 32, 101, 108, 105, 116, 46, 32, 83, 117, 115, 112, 101, 110, 100, 105, 115, 115, 101,
-32, 115, 101, 100, 32, 116, 117, 114, 112, 105, 115, 32, 117, 116, 32, 100, 111, 108, 111, 114, 32, 112, 108, 97, 99, 101, 114, 97, 116, 32, 100, 105,
-103, 110, 105, 115, 115, 105, 109, 46, 32, 81, 117, 105, 115, 113, 117, 101, 32, 113, 117, 105, 115, 32, 108, 101, 111, 46, 32, 67, 114, 97, 115, 32,
-117, 108, 116, 114, 105, 99, 101, 115, 46, 32, 77, 97, 101, 99, 101, 110, 97, 115, 32, 104, 101, 110, 100, 114, 101, 114, 105, 116, 32, 97, 117, 99,
-116, 111, 114, 32, 116, 111, 114, 116, 111, 114, 46, 32, 69, 116, 105, 97, 109, 32, 115, 105, 116, 32, 97, 109, 101, 116, 32, 97, 114, 99, 117, 46,
-0};
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 2a84ca7f297..2ac800ee6e0 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -78,6 +78,13 @@ if(WITH_BLENDER)
data_to_c_simple(../../../../release/datafiles/brushicons/fill.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/flatten.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/grab.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/hairadd.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/haircomb.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/haircut.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/hairlength.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/hairpuff.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/hairsmooth.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/hairweight.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/inflate.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/layer.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/lighten.png SRC)
diff --git a/source/blender/editors/datafiles/SConscript b/source/blender/editors/datafiles/SConscript
index 6bc8f21e384..e16d99ef15a 100644
--- a/source/blender/editors/datafiles/SConscript
+++ b/source/blender/editors/datafiles/SConscript
@@ -62,6 +62,13 @@ sources.extend((
os.path.join(env['DATA_SOURCES'], "fill.png.c"),
os.path.join(env['DATA_SOURCES'], "flatten.png.c"),
os.path.join(env['DATA_SOURCES'], "grab.png.c"),
+ os.path.join(env['DATA_SOURCES'], "hairadd.png.c"),
+ os.path.join(env['DATA_SOURCES'], "haircomb.png.c"),
+ os.path.join(env['DATA_SOURCES'], "haircut.png.c"),
+ os.path.join(env['DATA_SOURCES'], "hairlength.png.c"),
+ os.path.join(env['DATA_SOURCES'], "hairpuff.png.c"),
+ os.path.join(env['DATA_SOURCES'], "hairsmooth.png.c"),
+ os.path.join(env['DATA_SOURCES'], "hairweight.png.c"),
os.path.join(env['DATA_SOURCES'], "inflate.png.c"),
os.path.join(env['DATA_SOURCES'], "layer.png.c"),
os.path.join(env['DATA_SOURCES'], "lighten.png.c"),
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt
index 58192f59219..56b8d284386 100644
--- a/source/blender/editors/gpencil/CMakeLists.txt
+++ b/source/blender/editors/gpencil/CMakeLists.txt
@@ -39,6 +39,8 @@ set(INC_SYS
set(SRC
drawgpencil.c
editaction_gpencil.c
+ gpencil_convert.c
+ gpencil_data.c
gpencil_edit.c
gpencil_ops.c
gpencil_paint.c
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 55224b87c59..ffcd204135f 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -40,6 +40,9 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLF_api.h"
+#include "BLF_translation.h"
+
#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -57,12 +60,12 @@
#include "BIF_glutil.h"
#include "ED_gpencil.h"
+#include "ED_screen.h"
#include "ED_view3d.h"
+#include "UI_interface_icons.h"
#include "UI_resources.h"
-#include "gpencil_intern.h"
-
/* ************************************************** */
/* GREASE PENCIL DRAWING */
@@ -118,7 +121,7 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
/* draw stroke curve */
if (G.debug & G_DEBUG) setlinestyle(2);
- glLineWidth(oldpressure * thickness);
+ glLineWidth(max_ff(oldpressure * thickness, 1.0));
glBegin(GL_LINE_STRIP);
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
@@ -127,7 +130,7 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
*/
if (fabsf(pt->pressure - oldpressure) > 0.2f) {
glEnd();
- glLineWidth(pt->pressure * thickness);
+ glLineWidth(max_ff(pt->pressure * thickness, 1.0f));
glBegin(GL_LINE_STRIP);
/* need to roll-back one point to ensure that there are no gaps in the stroke */
@@ -412,7 +415,7 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
int i;
/* draw stroke curve */
- glLineWidth(curpressure * thickness);
+ glLineWidth(max_ff(curpressure * thickness, 1.0f));
glBegin(GL_LINE_STRIP);
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
/* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
@@ -422,7 +425,7 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
if (fabsf(pt->pressure - curpressure) > 0.2f / (float)thickness) {
glEnd();
curpressure = pt->pressure;
- glLineWidth(curpressure * thickness);
+ glLineWidth(max_ff(curpressure * thickness, 1.0f));
glBegin(GL_LINE_STRIP);
/* need to roll-back one point to ensure that there are no gaps in the stroke */
@@ -440,6 +443,8 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
/* draw debug points of curve on top? */
/* XXX: for now, we represent "selected" strokes in the same way as debug, which isn't used anymore */
if (debug) {
+ glPointSize((float)(thickness + 2));
+
glBegin(GL_POINTS);
for (i = 0, pt = points; i < totpoints && pt; i++, pt++)
glVertex3fv(&pt->x);
@@ -614,6 +619,8 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
bGPDspoint *pt;
int i;
+ glPointSize((float)(thickness_s + 2));
+
glBegin(GL_POINTS);
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
float co[2];
@@ -754,7 +761,7 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
{
bGPDstroke *gps;
- const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY);
+ const bool no_xray = (dflag & GP_DRAWDATA_NO_XRAY) != 0;
int mask_orig = 0;
/* set up depth masks... */
@@ -873,7 +880,7 @@ static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx,
/* draw onion-skinning for a layer */
static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
- int UNUSED(cfra), int dflag, short debug, short lthick)
+ int UNUSED(cfra), int dflag, bool debug, short lthick)
{
const float alpha = gpl->color[3];
float color[4];
@@ -1044,6 +1051,51 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
}
}
+/* draw a short status message in the top-right corner */
+static void gp_draw_status_text(bGPdata *gpd, ARegion *ar)
+{
+ rcti rect;
+
+ /* Cannot draw any status text when drawing OpenGL Renders */
+ if (G.f & G_RENDER_OGL)
+ return;
+
+ /* Get bounds of region - Necessary to avoid problems with region overlap */
+ ED_region_visible_rect(ar, &rect);
+
+ /* for now, this should only be used to indicate when we are in stroke editmode */
+ if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ const char *printable = IFACE_("GPencil Stroke Editing");
+ float printable_size[2];
+ int xco, yco;
+
+ BLF_width_and_height_default(printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
+
+ xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
+ yco = (rect.ymax - U.widget_unit);
+
+ /* text label */
+ UI_ThemeColor(TH_TEXT_HI);
+#ifdef WITH_INTERNATIONAL
+ BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
+#else
+ BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
+#endif
+
+ /* grease pencil icon... */
+ // XXX: is this too intrusive?
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+
+ xco -= U.widget_unit;
+ yco -= (int)printable_size[1] / 2;
+
+ UI_icon_draw(xco, yco, ICON_GREASEPENCIL);
+
+ glDisable(GL_BLEND);
+ }
+}
+
/* draw grease-pencil datablock */
static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
@@ -1195,6 +1247,11 @@ void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d)
/* draw it! */
if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS);
gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype);
+
+ /* draw status text (if in screen/pixel-space) */
+ if (onlyv2d == false) {
+ gp_draw_status_text(gpd, ar);
+ }
}
/* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly
@@ -1229,10 +1286,27 @@ void ED_gpencil_draw_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
winy = ar->winy;
}
- /* draw it! */
- if (only3d) dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
+ /* set flags */
+ if (only3d) {
+ /* 3D strokes/3D space:
+ * - only 3D space points
+ * - don't status text either (as it's the wrong space)
+ */
+ dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
+ }
+
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
+ /* don't draw status text when "only render" flag is set */
+ dflag |= GP_DRAWDATA_NOSTATUS;
+ }
+ /* draw it! */
gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
+
+ /* draw status text (if in screen/pixel-space) */
+ if (only3d == false) {
+ gp_draw_status_text(gpd, ar);
+ }
}
void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
new file mode 100644
index 00000000000..2c8f86423a5
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -0,0 +1,1484 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ * Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operator for converting Grease Pencil data to geometry
+ */
+
+/** \file blender/editors/gpencil/gpencil_convert.c
+ * \ingroup edgpencil
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_rand.h"
+#include "BLI_utildefines.h"
+
+#include "BLF_translation.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_node_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_library.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_tracking.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_view2d.h"
+
+#include "ED_gpencil.h"
+#include "ED_view3d.h"
+#include "ED_clip.h"
+#include "ED_keyframing.h"
+
+#include "gpencil_intern.h"
+
+/* ************************************************ */
+/* Grease Pencil to Data Operator */
+
+/* defines for possible modes */
+enum {
+ GP_STROKECONVERT_PATH = 1,
+ GP_STROKECONVERT_CURVE,
+ GP_STROKECONVERT_POLY,
+};
+
+/* Defines for possible timing modes */
+enum {
+ GP_STROKECONVERT_TIMING_NONE = 1,
+ GP_STROKECONVERT_TIMING_LINEAR = 2,
+ GP_STROKECONVERT_TIMING_FULL = 3,
+ GP_STROKECONVERT_TIMING_CUSTOMGAP = 4,
+};
+
+/* RNA enum define */
+static EnumPropertyItem prop_gpencil_convertmodes[] = {
+ {GP_STROKECONVERT_PATH, "PATH", 0, "Path", ""},
+ {GP_STROKECONVERT_CURVE, "CURVE", 0, "Bezier Curve", ""},
+ {GP_STROKECONVERT_POLY, "POLY", 0, "Polygon Curve", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static EnumPropertyItem prop_gpencil_convert_timingmodes_restricted[] = {
+ {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
+ {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static EnumPropertyItem prop_gpencil_convert_timingmodes[] = {
+ {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
+ {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
+ {GP_STROKECONVERT_TIMING_FULL, "FULL", 0, "Original", "Use the original timing, gaps included"},
+ {GP_STROKECONVERT_TIMING_CUSTOMGAP, "CUSTOMGAP", 0, "Custom Gaps",
+ "Use the original timing, but with custom gap lengths (in frames)"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop),
+ bool *UNUSED(r_free))
+{
+ if (RNA_boolean_get(ptr, "use_timing_data")) {
+ return prop_gpencil_convert_timingmodes;
+ }
+ return prop_gpencil_convert_timingmodes_restricted;
+}
+
+/* --- */
+
+/* convert the coordinates from the given stroke point into 3d-coordinates
+ * - assumes that the active space is the 3D-View
+ */
+static void gp_strokepoint_convertcoords(bContext *C, bGPDstroke *gps, bGPDspoint *pt, float p3d[3], rctf *subrect)
+{
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ /* directly use 3d-coordinates */
+ copy_v3_v3(p3d, &pt->x);
+ }
+ else {
+ const float *fp = ED_view3d_cursor3d_get(scene, v3d);
+ float mvalf[2];
+
+ /* get screen coordinate */
+ if (gps->flag & GP_STROKE_2DSPACE) {
+ View2D *v2d = &ar->v2d;
+ UI_view2d_view_to_region_fl(v2d, pt->x, pt->y, &mvalf[0], &mvalf[1]);
+ }
+ else {
+ if (subrect) {
+ mvalf[0] = (((float)pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
+ mvalf[1] = (((float)pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
+ }
+ else {
+ mvalf[0] = (float)pt->x / 100.0f * ar->winx;
+ mvalf[1] = (float)pt->y / 100.0f * ar->winy;
+ }
+ }
+
+ ED_view3d_win_to_3d(ar, fp, mvalf, p3d);
+ }
+}
+
+/* --- */
+
+/* temp struct for gp_stroke_path_animation() */
+typedef struct tGpTimingData {
+ /* Data set from operator settings */
+ int mode;
+ int frame_range; /* Number of frames evaluated for path animation */
+ int start_frame, end_frame;
+ bool realtime; /* Will overwrite end_frame in case of Original or CustomGap timing... */
+ float gap_duration, gap_randomness; /* To be used with CustomGap mode*/
+ int seed;
+
+ /* Data set from points, used to compute final timing FCurve */
+ int num_points, cur_point;
+
+ /* Distances */
+ float *dists;
+ float tot_dist;
+
+ /* Times */
+ float *times; /* Note: Gap times will be negative! */
+ float tot_time, gap_tot_time;
+ double inittime;
+
+ /* Only used during creation of dists & times lists. */
+ float offset_time;
+} tGpTimingData;
+
+/* Init point buffers for timing data.
+ * Note this assumes we only grow those arrays!
+ */
+static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr)
+{
+ float *tmp;
+
+ BLI_assert(nbr > gtd->num_points);
+
+ /* distances */
+ tmp = gtd->dists;
+ gtd->dists = MEM_callocN(sizeof(float) * nbr, __func__);
+ if (tmp) {
+ memcpy(gtd->dists, tmp, sizeof(float) * gtd->num_points);
+ MEM_freeN(tmp);
+ }
+
+ /* times */
+ tmp = gtd->times;
+ gtd->times = MEM_callocN(sizeof(float) * nbr, __func__);
+ if (tmp) {
+ memcpy(gtd->times, tmp, sizeof(float) * gtd->num_points);
+ MEM_freeN(tmp);
+ }
+
+ gtd->num_points = nbr;
+}
+
+/* add stroke point to timing buffers */
+static void gp_timing_data_add_point(tGpTimingData *gtd, const double stroke_inittime, const float time,
+ const float delta_dist)
+{
+ float delta_time = 0.0f;
+ const int cur_point = gtd->cur_point;
+
+ if (!cur_point) {
+ /* Special case, first point, if time is not 0.0f we have to compensate! */
+ gtd->offset_time = -time;
+ gtd->times[cur_point] = 0.0f;
+ }
+ else if (time < 0.0f) {
+ /* This is a gap, negative value! */
+ gtd->times[cur_point] = -(((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time);
+ delta_time = -gtd->times[cur_point] - gtd->times[cur_point - 1];
+
+ gtd->gap_tot_time += delta_time;
+ }
+ else {
+ gtd->times[cur_point] = (((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time);
+ delta_time = gtd->times[cur_point] - fabsf(gtd->times[cur_point - 1]);
+ }
+
+ gtd->tot_time += delta_time;
+ gtd->tot_dist += delta_dist;
+ gtd->dists[cur_point] = gtd->tot_dist;
+
+ gtd->cur_point++;
+}
+
+/* In frames! Binary search for FCurve keys have a threshold of 0.01, so we can't set
+ * arbitrarily close points - this is esp. important with NoGaps mode!
+ */
+#define MIN_TIME_DELTA 0.02f
+
+/* Loop over next points to find the end of the stroke, and compute */
+static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, RNG *rng, const int idx, const int nbr_gaps,
+ int *nbr_done_gaps, const float tot_gaps_time, const float delta_time,
+ float *next_delta_time)
+{
+ int j;
+
+ for (j = idx + 1; j < gtd->num_points; j++) {
+ if (gtd->times[j] < 0) {
+ gtd->times[j] = -gtd->times[j];
+ if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
+ /* In this mode, gap time between this stroke and the next should be 0 currently...
+ * So we have to compute its final duration!
+ */
+ if (gtd->gap_randomness > 0.0f) {
+ /* We want gaps that are in gtd->gap_duration +/- gtd->gap_randomness range,
+ * and which sum to exactly tot_gaps_time...
+ */
+ int rem_gaps = nbr_gaps - (*nbr_done_gaps);
+ if (rem_gaps < 2) {
+ /* Last gap, just give remaining time! */
+ *next_delta_time = tot_gaps_time;
+ }
+ else {
+ float delta, min, max;
+
+ /* This code ensures that if the first gaps have been shorter than average gap_duration,
+ * next gaps will tend to be longer (i.e. try to recover the lateness), and vice-versa!
+ */
+ delta = delta_time - (gtd->gap_duration * (*nbr_done_gaps));
+
+ /* Clamp min between [-gap_randomness, 0.0], with lower delta giving higher min */
+ min = -gtd->gap_randomness - delta;
+ CLAMP(min, -gtd->gap_randomness, 0.0f);
+
+ /* Clamp max between [0.0, gap_randomness], with lower delta giving higher max */
+ max = gtd->gap_randomness - delta;
+ CLAMP(max, 0.0f, gtd->gap_randomness);
+ *next_delta_time += gtd->gap_duration + (BLI_rng_get_float(rng) * (max - min)) + min;
+ }
+ }
+ else {
+ *next_delta_time += gtd->gap_duration;
+ }
+ }
+ (*nbr_done_gaps)++;
+ break;
+ }
+ }
+
+ return j - 1;
+}
+
+static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, RNG *rng, int *nbr_gaps, float *tot_gaps_time)
+{
+ int i;
+ float delta_time = 0.0f;
+
+ for (i = 0; i < gtd->num_points; i++) {
+ if (gtd->times[i] < 0 && i) {
+ (*nbr_gaps)++;
+ gtd->times[i] = -gtd->times[i] - delta_time;
+ delta_time += gtd->times[i] - gtd->times[i - 1];
+ gtd->times[i] = -gtd->times[i - 1]; /* Temp marker, values *have* to be different! */
+ }
+ else {
+ gtd->times[i] -= delta_time;
+ }
+ }
+ gtd->tot_time -= delta_time;
+
+ *tot_gaps_time = (float)(*nbr_gaps) * gtd->gap_duration;
+ gtd->tot_time += *tot_gaps_time;
+ if (G.debug & G_DEBUG) {
+ printf("%f, %f, %f, %d\n", gtd->tot_time, delta_time, *tot_gaps_time, *nbr_gaps);
+ }
+ if (gtd->gap_randomness > 0.0f) {
+ BLI_rng_srandom(rng, gtd->seed);
+ }
+}
+
+static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu,
+ Curve *cu, tGpTimingData *gtd, RNG *rng, const float time_range,
+ const int nbr_gaps, const float tot_gaps_time)
+{
+ /* Use actual recorded timing! */
+ const float time_start = (float)gtd->start_frame;
+
+ float last_valid_time = 0.0f;
+ int end_stroke_idx = -1, start_stroke_idx = 0;
+ float end_stroke_time = 0.0f;
+
+ /* CustomGaps specific */
+ float delta_time = 0.0f, next_delta_time = 0.0f;
+ int nbr_done_gaps = 0;
+
+ int i;
+ float cfra;
+
+ /* This is a bit tricky, as:
+ * - We can't add arbitrarily close points on FCurve (in time).
+ * - We *must* have all "caps" points of all strokes in FCurve, as much as possible!
+ */
+ for (i = 0; i < gtd->num_points; i++) {
+ /* If new stroke... */
+ if (i > end_stroke_idx) {
+ start_stroke_idx = i;
+ delta_time = next_delta_time;
+ /* find end of that new stroke */
+ end_stroke_idx = gp_find_end_of_stroke_idx(gtd, rng, i, nbr_gaps, &nbr_done_gaps,
+ tot_gaps_time, delta_time, &next_delta_time);
+ /* This one should *never* be negative! */
+ end_stroke_time = time_start + ((gtd->times[end_stroke_idx] + delta_time) / gtd->tot_time * time_range);
+ }
+
+ /* Simple proportional stuff... */
+ cu->ctime = gtd->dists[i] / gtd->tot_dist * cu->pathlen;
+ cfra = time_start + ((gtd->times[i] + delta_time) / gtd->tot_time * time_range);
+
+ /* And now, the checks about timing... */
+ if (i == start_stroke_idx) {
+ /* If first point of a stroke, be sure it's enough ahead of last valid keyframe, and
+ * that the end point of the stroke is far enough!
+ * In case it is not, we keep the end point...
+ * Note that with CustomGaps mode, this is here we set the actual gap timing!
+ */
+ if ((end_stroke_time - last_valid_time) > MIN_TIME_DELTA * 2) {
+ if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
+ cfra = last_valid_time + MIN_TIME_DELTA;
+ }
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ last_valid_time = cfra;
+ }
+ else if (G.debug & G_DEBUG) {
+ printf("\t Skipping start point %d, too close from end point %d\n", i, end_stroke_idx);
+ }
+ }
+ else if (i == end_stroke_idx) {
+ /* Always try to insert end point of a curve (should be safe enough, anyway...) */
+ if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
+ cfra = last_valid_time + MIN_TIME_DELTA;
+ }
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ last_valid_time = cfra;
+ }
+ else {
+ /* Else ("middle" point), we only insert it if it's far enough from last keyframe,
+ * and also far enough from (not yet added!) end_stroke keyframe!
+ */
+ if ((cfra - last_valid_time) > MIN_TIME_DELTA && (end_stroke_time - cfra) > MIN_TIME_DELTA) {
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ last_valid_time = cfra;
+ }
+ else if (G.debug & G_DEBUG) {
+ printf("\t Skipping \"middle\" point %d, too close from last added point or end point %d\n",
+ i, end_stroke_idx);
+ }
+ }
+ }
+}
+
+static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu, tGpTimingData *gtd)
+{
+ Scene *scene = CTX_data_scene(C);
+ bAction *act;
+ FCurve *fcu;
+ PointerRNA ptr;
+ PropertyRNA *prop = NULL;
+ int nbr_gaps = 0, i;
+
+ if (gtd->mode == GP_STROKECONVERT_TIMING_NONE)
+ return;
+
+ /* gap_duration and gap_randomness are in frames, but we need seconds!!! */
+ gtd->gap_duration = FRA2TIME(gtd->gap_duration);
+ gtd->gap_randomness = FRA2TIME(gtd->gap_randomness);
+
+ /* Enable path! */
+ cu->flag |= CU_PATH;
+ cu->pathlen = gtd->frame_range;
+
+ /* Get RNA pointer to read/write path time values */
+ RNA_id_pointer_create((ID *)cu, &ptr);
+ prop = RNA_struct_find_property(&ptr, "eval_time");
+
+ /* Ensure we have an F-Curve to add keyframes to */
+ act = verify_adt_action((ID *)cu, true);
+ fcu = verify_fcurve(act, NULL, &ptr, "eval_time", 0, true);
+
+ if (G.debug & G_DEBUG) {
+ printf("%s: tot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time);
+ for (i = 0; i < gtd->num_points; i++) {
+ printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]);
+ }
+ }
+
+ if (gtd->mode == GP_STROKECONVERT_TIMING_LINEAR) {
+ float cfra;
+
+ /* Linear extrapolation! */
+ fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
+
+ cu->ctime = 0.0f;
+ cfra = (float)gtd->start_frame;
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+
+ cu->ctime = cu->pathlen;
+ if (gtd->realtime) {
+ cfra += (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
+ }
+ else {
+ cfra = (float)gtd->end_frame;
+ }
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ }
+ else {
+ /* Use actual recorded timing! */
+ RNG *rng = BLI_rng_new(0);
+ float time_range;
+
+ /* CustomGaps specific */
+ float tot_gaps_time = 0.0f;
+
+ /* Pre-process gaps, in case we don't want to keep their original timing */
+ if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
+ gp_stroke_path_animation_preprocess_gaps(gtd, rng, &nbr_gaps, &tot_gaps_time);
+ }
+
+ if (gtd->realtime) {
+ time_range = (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
+ }
+ else {
+ time_range = (float)(gtd->end_frame - gtd->start_frame);
+ }
+
+ if (G.debug & G_DEBUG) {
+ printf("GP Stroke Path Conversion: Starting keying!\n");
+ }
+
+ gp_stroke_path_animation_add_keyframes(reports, ptr, prop, fcu, cu, gtd, rng, time_range,
+ nbr_gaps, tot_gaps_time);
+
+ BLI_rng_free(rng);
+ }
+
+ /* As we used INSERTKEY_FAST mode, we need to recompute all curve's handles now */
+ calchandles_fcurve(fcu);
+
+ if (G.debug & G_DEBUG) {
+ printf("%s: \ntot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time);
+ for (i = 0; i < gtd->num_points; i++) {
+ printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]);
+ }
+ printf("\n\n");
+ }
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ /* send updates */
+ DAG_id_tag_update(&cu->id, 0);
+}
+
+#undef MIN_TIME_DELTA
+
+#define GAP_DFAC 0.01f
+#define WIDTH_CORR_FAC 0.1f
+#define BEZT_HANDLE_FAC 0.3f
+
+/* convert stroke to 3d path */
+
+/* helper */
+static void gp_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const float p[3], const float prev_p[3],
+ const bool do_gtd, const double inittime, const float time,
+ const float width, const float rad_fac, float minmax_weights[2])
+{
+ copy_v3_v3(bp->vec, p);
+ bp->vec[3] = 1.0f;
+
+ /* set settings */
+ bp->f1 = SELECT;
+ bp->radius = width * rad_fac;
+ bp->weight = width;
+ CLAMP(bp->weight, 0.0f, 1.0f);
+ if (bp->weight < minmax_weights[0]) {
+ minmax_weights[0] = bp->weight;
+ }
+ else if (bp->weight > minmax_weights[1]) {
+ minmax_weights[1] = bp->weight;
+ }
+
+ /* Update timing data */
+ if (do_gtd) {
+ gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
+ }
+}
+
+static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
+ float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
+ const bool add_end_point, tGpTimingData *gtd)
+{
+ bGPDspoint *pt;
+ Nurb *nu = (curnu) ? *curnu : NULL;
+ BPoint *bp, *prev_bp = NULL;
+ const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
+ const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
+ int i, old_nbp = 0;
+
+ /* create new 'nurb' or extend current one within the curve */
+ if (nu) {
+ old_nbp = nu->pntsu;
+
+ /* If stitch, the first point of this stroke is already present in current nu.
+ * Else, we have to add two additional points to make the zero-radius link between strokes.
+ */
+ BKE_nurb_points_add(nu, gps->totpoints + (stitch ? -1 : 2) + add_start_end_points);
+ }
+ else {
+ nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
+
+ nu->pntsu = gps->totpoints + add_start_end_points;
+ nu->pntsv = 1;
+ nu->orderu = 2; /* point-to-point! */
+ nu->type = CU_NURBS;
+ nu->flagu = CU_NURB_ENDPOINT;
+ nu->resolu = cu->resolu;
+ nu->resolv = cu->resolv;
+ nu->knotsu = NULL;
+
+ nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "bpoints");
+
+ stitch = false; /* Security! */
+ }
+
+ if (do_gtd) {
+ gp_timing_data_set_nbr(gtd, nu->pntsu);
+ }
+
+ /* If needed, make the link between both strokes with two zero-radius additional points */
+ /* About "zero-radius" point interpolations:
+ * - If we have at least two points in current curve (most common case), we linearly extrapolate
+ * the last segment to get the first point (p1) position and timing.
+ * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
+ * with the first point of the current stroke.
+ * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
+ * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
+ */
+ if (curnu && !stitch && old_nbp) {
+ float p1[3], p2[3], p[3], next_p[3];
+ float dt1 = 0.0f, dt2 = 0.0f;
+
+ BLI_assert(gps->prev != NULL);
+
+ prev_bp = NULL;
+ if ((old_nbp > 1) && (gps->prev->totpoints > 1)) {
+ /* Only use last curve segment if previous stroke was not a single-point one! */
+ prev_bp = &nu->bp[old_nbp - 2];
+ }
+ bp = &nu->bp[old_nbp - 1];
+
+ /* First point */
+ gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
+ if (prev_bp) {
+ interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC);
+ if (do_gtd) {
+ const int idx = gps->prev->totpoints - 1;
+ dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
+ }
+ }
+ else {
+ interp_v3_v3v3(p1, bp->vec, p, GAP_DFAC);
+ if (do_gtd) {
+ dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
+ }
+ }
+ bp++;
+ gp_stroke_to_path_add_point(gtd, bp, p1, (bp - 1)->vec, do_gtd, gps->prev->inittime, dt1,
+ 0.0f, rad_fac, minmax_weights);
+
+ /* Second point */
+ /* Note dt2 is always negative, which marks the gap. */
+ if (gps->totpoints > 1) {
+ gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
+ interp_v3_v3v3(p2, p, next_p, -GAP_DFAC);
+ if (do_gtd) {
+ dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+ }
+ }
+ else {
+ interp_v3_v3v3(p2, p, bp->vec, GAP_DFAC);
+ if (do_gtd) {
+ dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
+ }
+ }
+ bp++;
+ gp_stroke_to_path_add_point(gtd, bp, p2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights);
+
+ old_nbp += 2;
+ }
+ else if (add_start_point) {
+ float p[3], next_p[3];
+ float dt = 0.0f;
+
+ gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
+ if (gps->totpoints > 1) {
+ gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
+ interp_v3_v3v3(p, p, next_p, -GAP_DFAC);
+ if (do_gtd) {
+ dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+ }
+ }
+ else {
+ p[0] -= GAP_DFAC; /* Rather arbitrary... */
+ dt = -GAP_DFAC; /* Rather arbitrary too! */
+ }
+ bp = &nu->bp[old_nbp];
+ /* Note we can't give anything else than 0.0 as time here, since a negative one (which would be expected value)
+ * would not work (it would be *before* gtd->inittime, which is not supported currently).
+ */
+ gp_stroke_to_path_add_point(gtd, bp, p, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
+
+ old_nbp++;
+ }
+
+ if (old_nbp) {
+ prev_bp = &nu->bp[old_nbp - 1];
+ }
+
+ /* add points */
+ for (i = (stitch) ? 1 : 0, pt = &gps->points[(stitch) ? 1 : 0], bp = &nu->bp[old_nbp];
+ i < gps->totpoints;
+ i++, pt++, bp++)
+ {
+ float p[3];
+ float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
+
+ /* get coordinates to add at */
+ gp_strokepoint_convertcoords(C, gps, pt, p, subrect);
+
+ gp_stroke_to_path_add_point(gtd, bp, p, (prev_bp) ? prev_bp->vec : p, do_gtd, gps->inittime, pt->time,
+ width, rad_fac, minmax_weights);
+
+ prev_bp = bp;
+ }
+
+ if (add_end_point) {
+ float p[3];
+ float dt = 0.0f;
+
+ if (gps->totpoints > 1) {
+ interp_v3_v3v3(p, prev_bp->vec, (prev_bp - 1)->vec, -GAP_DFAC);
+ if (do_gtd) {
+ const int idx = gps->totpoints - 1;
+ dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
+ }
+ }
+ else {
+ copy_v3_v3(p, prev_bp->vec);
+ p[0] += GAP_DFAC; /* Rather arbitrary... */
+ dt = GAP_DFAC; /* Rather arbitrary too! */
+ }
+ /* Note bp has already been incremented in main loop above, so it points to the right place. */
+ gp_stroke_to_path_add_point(gtd, bp, p, prev_bp->vec, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
+ }
+
+ /* add nurb to curve */
+ if (!curnu || !*curnu) {
+ BLI_addtail(&cu->nurb, nu);
+ }
+ if (curnu) {
+ *curnu = nu;
+ }
+
+ BKE_nurb_knot_calc_u(nu);
+}
+
+/* convert stroke to 3d bezier */
+
+/* helper */
+static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt,
+ const float p[3], const float h1[3], const float h2[3], const float prev_p[3],
+ const bool do_gtd, const double inittime, const float time,
+ const float width, const float rad_fac, float minmax_weights[2])
+{
+ copy_v3_v3(bezt->vec[0], h1);
+ copy_v3_v3(bezt->vec[1], p);
+ copy_v3_v3(bezt->vec[2], h2);
+
+ /* set settings */
+ bezt->h1 = bezt->h2 = HD_FREE;
+ bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
+ bezt->radius = width * rad_fac;
+ bezt->weight = width;
+ CLAMP(bezt->weight, 0.0f, 1.0f);
+ if (bezt->weight < minmax_weights[0]) {
+ minmax_weights[0] = bezt->weight;
+ }
+ else if (bezt->weight > minmax_weights[1]) {
+ minmax_weights[1] = bezt->weight;
+ }
+
+ /* Update timing data */
+ if (do_gtd) {
+ gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
+ }
+}
+
+static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
+ float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
+ const bool add_end_point, tGpTimingData *gtd)
+{
+ bGPDspoint *pt;
+ Nurb *nu = (curnu) ? *curnu : NULL;
+ BezTriple *bezt, *prev_bezt = NULL;
+ int i, tot, old_nbezt = 0;
+ const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
+ float p3d_cur[3], p3d_prev[3], p3d_next[3], h1[3], h2[3];
+ const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
+
+ /* create new 'nurb' or extend current one within the curve */
+ if (nu) {
+ old_nbezt = nu->pntsu;
+ /* If we do stitch, first point of current stroke is assumed the same as last point of previous stroke,
+ * so no need to add it.
+ * If no stitch, we want to add two additional points to make a "zero-radius" link between both strokes.
+ */
+ BKE_nurb_bezierPoints_add(nu, gps->totpoints + ((stitch) ? -1 : 2) + add_start_end_points);
+ }
+ else {
+ nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");
+
+ nu->pntsu = gps->totpoints + add_start_end_points;
+ nu->resolu = 12;
+ nu->resolv = 12;
+ nu->type = CU_BEZIER;
+ nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * nu->pntsu, "bezts");
+
+ stitch = false; /* Security! */
+ }
+
+ if (do_gtd) {
+ gp_timing_data_set_nbr(gtd, nu->pntsu);
+ }
+
+ tot = gps->totpoints;
+
+ /* get initial coordinates */
+ pt = gps->points;
+ if (tot) {
+ gp_strokepoint_convertcoords(C, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
+ if (tot > 1) {
+ gp_strokepoint_convertcoords(C, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
+ }
+ if (stitch && tot > 2) {
+ gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
+ }
+ }
+
+ /* If needed, make the link between both strokes with two zero-radius additional points */
+ if (curnu && old_nbezt) {
+ BLI_assert(gps->prev != NULL);
+
+ /* Update last point's second handle */
+ if (stitch) {
+ bezt = &nu->bezt[old_nbezt - 1];
+ interp_v3_v3v3(h2, bezt->vec[1], p3d_cur, BEZT_HANDLE_FAC);
+ copy_v3_v3(bezt->vec[2], h2);
+ pt++;
+ }
+
+ /* Create "link points" */
+ /* About "zero-radius" point interpolations:
+ * - If we have at least two points in current curve (most common case), we linearly extrapolate
+ * the last segment to get the first point (p1) position and timing.
+ * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
+ * with the first point of the current stroke.
+ * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
+ * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
+ */
+ else {
+ float p1[3], p2[3];
+ float dt1 = 0.0f, dt2 = 0.0f;
+
+ prev_bezt = NULL;
+ if ((old_nbezt > 1) && (gps->prev->totpoints > 1)) {
+ /* Only use last curve segment if previous stroke was not a single-point one! */
+ prev_bezt = &nu->bezt[old_nbezt - 2];
+ }
+ bezt = &nu->bezt[old_nbezt - 1];
+
+ /* First point */
+ if (prev_bezt) {
+ interp_v3_v3v3(p1, prev_bezt->vec[1], bezt->vec[1], 1.0f + GAP_DFAC);
+ if (do_gtd) {
+ const int idx = gps->prev->totpoints - 1;
+ dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
+ }
+ }
+ else {
+ interp_v3_v3v3(p1, bezt->vec[1], p3d_cur, GAP_DFAC);
+ if (do_gtd) {
+ dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
+ }
+ }
+
+ /* Second point */
+ /* Note dt2 is always negative, which marks the gap. */
+ if (tot > 1) {
+ interp_v3_v3v3(p2, p3d_cur, p3d_next, -GAP_DFAC);
+ if (do_gtd) {
+ dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+ }
+ }
+ else {
+ interp_v3_v3v3(p2, p3d_cur, bezt->vec[1], GAP_DFAC);
+ if (do_gtd) {
+ dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
+ }
+ }
+
+ /* Second handle of last point of previous stroke. */
+ interp_v3_v3v3(h2, bezt->vec[1], p1, BEZT_HANDLE_FAC);
+ copy_v3_v3(bezt->vec[2], h2);
+
+ /* First point */
+ interp_v3_v3v3(h1, p1, bezt->vec[1], BEZT_HANDLE_FAC);
+ interp_v3_v3v3(h2, p1, p2, BEZT_HANDLE_FAC);
+ bezt++;
+ gp_stroke_to_bezier_add_point(gtd, bezt, p1, h1, h2, (bezt - 1)->vec[1], do_gtd, gps->prev->inittime, dt1,
+ 0.0f, rad_fac, minmax_weights);
+
+ /* Second point */
+ interp_v3_v3v3(h1, p2, p1, BEZT_HANDLE_FAC);
+ interp_v3_v3v3(h2, p2, p3d_cur, BEZT_HANDLE_FAC);
+ bezt++;
+ gp_stroke_to_bezier_add_point(gtd, bezt, p2, h1, h2, p1, do_gtd, gps->inittime, dt2,
+ 0.0f, rad_fac, minmax_weights);
+
+ old_nbezt += 2;
+ copy_v3_v3(p3d_prev, p2);
+ }
+ }
+ else if (add_start_point) {
+ float p[3];
+ float dt = 0.0f;
+
+ if (gps->totpoints > 1) {
+ interp_v3_v3v3(p, p3d_cur, p3d_next, -GAP_DFAC);
+ if (do_gtd) {
+ dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
+ }
+ }
+ else {
+ copy_v3_v3(p, p3d_cur);
+ p[0] -= GAP_DFAC; /* Rather arbitrary... */
+ dt = -GAP_DFAC; /* Rather arbitrary too! */
+ }
+ interp_v3_v3v3(h1, p, p3d_cur, -BEZT_HANDLE_FAC);
+ interp_v3_v3v3(h2, p, p3d_cur, BEZT_HANDLE_FAC);
+ bezt = &nu->bezt[old_nbezt];
+ gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, p, do_gtd, gps->inittime, dt,
+ 0.0f, rad_fac, minmax_weights);
+
+ old_nbezt++;
+ copy_v3_v3(p3d_prev, p);
+ }
+
+ if (old_nbezt) {
+ prev_bezt = &nu->bezt[old_nbezt - 1];
+ }
+
+ /* add points */
+ for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) {
+ float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
+
+ if (i || old_nbezt) {
+ interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC);
+ }
+ else {
+ interp_v3_v3v3(h1, p3d_cur, p3d_next, -BEZT_HANDLE_FAC);
+ }
+
+ if (i < tot - 1) {
+ interp_v3_v3v3(h2, p3d_cur, p3d_next, BEZT_HANDLE_FAC);
+ }
+ else {
+ interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC);
+ }
+
+ gp_stroke_to_bezier_add_point(gtd, bezt, p3d_cur, h1, h2, prev_bezt ? prev_bezt->vec[1] : p3d_cur,
+ do_gtd, gps->inittime, pt->time, width, rad_fac, minmax_weights);
+
+ /* shift coord vects */
+ copy_v3_v3(p3d_prev, p3d_cur);
+ copy_v3_v3(p3d_cur, p3d_next);
+
+ if (i + 2 < tot) {
+ gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
+ }
+
+ prev_bezt = bezt;
+ }
+
+ if (add_end_point) {
+ float p[3];
+ float dt = 0.0f;
+
+ if (gps->totpoints > 1) {
+ interp_v3_v3v3(p, prev_bezt->vec[1], (prev_bezt - 1)->vec[1], -GAP_DFAC);
+ if (do_gtd) {
+ const int idx = gps->totpoints - 1;
+ dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
+ }
+ }
+ else {
+ copy_v3_v3(p, prev_bezt->vec[1]);
+ p[0] += GAP_DFAC; /* Rather arbitrary... */
+ dt = GAP_DFAC; /* Rather arbitrary too! */
+ }
+
+ /* Second handle of last point of this stroke. */
+ interp_v3_v3v3(h2, prev_bezt->vec[1], p, BEZT_HANDLE_FAC);
+ copy_v3_v3(prev_bezt->vec[2], h2);
+
+ /* The end point */
+ interp_v3_v3v3(h1, p, prev_bezt->vec[1], BEZT_HANDLE_FAC);
+ interp_v3_v3v3(h2, p, prev_bezt->vec[1], -BEZT_HANDLE_FAC);
+ /* Note bezt has already been incremented in main loop above, so it points to the right place. */
+ gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, prev_bezt->vec[1], do_gtd, gps->inittime, dt,
+ 0.0f, rad_fac, minmax_weights);
+ }
+
+ /* must calculate handles or else we crash */
+ BKE_nurb_handles_calc(nu);
+
+ if (!curnu || !*curnu) {
+ BLI_addtail(&cu->nurb, nu);
+ }
+ if (curnu) {
+ *curnu = nu;
+ }
+}
+
+#undef GAP_DFAC
+#undef WIDTH_CORR_FAC
+#undef BEZT_HANDLE_FAC
+
+static void gp_stroke_finalize_curve_endpoints(Curve *cu)
+{
+ /* start */
+ Nurb *nu = cu->nurb.first;
+ int i = 0;
+ if (nu->bezt) {
+ BezTriple *bezt = nu->bezt;
+ if (bezt) {
+ bezt[i].weight = bezt[i].radius = 0.0f;
+ }
+ }
+ else if (nu->bp) {
+ BPoint *bp = nu->bp;
+ if (bp) {
+ bp[i].weight = bp[i].radius = 0.0f;
+ }
+ }
+
+ /* end */
+ nu = cu->nurb.last;
+ i = nu->pntsu - 1;
+ if (nu->bezt) {
+ BezTriple *bezt = nu->bezt;
+ if (bezt) {
+ bezt[i].weight = bezt[i].radius = 0.0f;
+ }
+ }
+ else if (nu->bp) {
+ BPoint *bp = nu->bp;
+ if (bp) {
+ bp[i].weight = bp[i].radius = 0.0f;
+ }
+ }
+}
+
+static void gp_stroke_norm_curve_weights(Curve *cu, const float minmax_weights[2])
+{
+ Nurb *nu;
+ const float delta = minmax_weights[0];
+ float fac;
+ int i;
+
+ /* when delta == minmax_weights[0] == minmax_weights[1], we get div by zero [#35686] */
+ if (IS_EQF(delta, minmax_weights[1]))
+ fac = 1.0f;
+ else
+ fac = 1.0f / (minmax_weights[1] - delta);
+
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->bezt) {
+ BezTriple *bezt = nu->bezt;
+ for (i = 0; i < nu->pntsu; i++, bezt++) {
+ bezt->weight = (bezt->weight - delta) * fac;
+ }
+ }
+ else if (nu->bp) {
+ BPoint *bp = nu->bp;
+ for (i = 0; i < nu->pntsu; i++, bp++) {
+ bp->weight = (bp->weight - delta) * fac;
+ }
+ }
+ }
+}
+
+static int gp_camera_view_subrect(bContext *C, rctf *subrect)
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ if (v3d) {
+ RegionView3D *rv3d = ar->regiondata;
+
+ /* for camera view set the subrect */
+ if (rv3d->persp == RV3D_CAMOB) {
+ Scene *scene = CTX_data_scene(C);
+ ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, subrect, true); /* no shift */
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */
+static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bGPDlayer *gpl, const int mode,
+ const bool norm_weights, const float rad_fac, const bool link_strokes, tGpTimingData *gtd)
+{
+ struct Main *bmain = CTX_data_main(C);
+ View3D *v3d = CTX_wm_view3d(C); /* may be NULL */
+ Scene *scene = CTX_data_scene(C);
+ bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
+ bGPDstroke *gps, *prev_gps = NULL;
+ Object *ob;
+ Curve *cu;
+ Nurb *nu = NULL;
+ Base *base_orig = BASACT, *base_new = NULL;
+ float minmax_weights[2] = {1.0f, 0.0f};
+
+ /* camera framing */
+ rctf subrect, *subrect_ptr = NULL;
+
+ /* error checking */
+ if (ELEM(NULL, gpd, gpl, gpf))
+ return;
+
+ /* only convert if there are any strokes on this layer's frame to convert */
+ if (BLI_listbase_is_empty(&gpf->strokes))
+ return;
+
+ /* initialize camera framing */
+ if (gp_camera_view_subrect(C, &subrect)) {
+ subrect_ptr = &subrect;
+ }
+
+ /* init the curve object (remove rotation and get curve data from it)
+ * - must clear transforms set on object, as those skew our results
+ */
+ ob = BKE_object_add_only_object(bmain, OB_CURVE, gpl->info);
+ cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVE);
+ base_new = BKE_scene_base_add(scene, ob);
+
+ cu->flag |= CU_3D;
+
+ gtd->inittime = ((bGPDstroke *)gpf->strokes.first)->inittime;
+
+ /* add points to curve */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ const bool add_start_point = (link_strokes && !(prev_gps));
+ const bool add_end_point = (link_strokes && !(gps->next));
+
+ /* Detect new strokes created because of GP_STROKE_BUFFER_MAX reached, and stitch them to previous one. */
+ bool stitch = false;
+ if (prev_gps) {
+ bGPDspoint *pt1 = &prev_gps->points[prev_gps->totpoints - 1];
+ bGPDspoint *pt2 = &gps->points[0];
+
+ if ((pt1->x == pt2->x) && (pt1->y == pt2->y)) {
+ stitch = true;
+ }
+ }
+
+ /* Decide whether we connect this stroke to previous one */
+ if (!(stitch || link_strokes)) {
+ nu = NULL;
+ }
+
+ switch (mode) {
+ case GP_STROKECONVERT_PATH:
+ gp_stroke_to_path(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
+ add_start_point, add_end_point, gtd);
+ break;
+ case GP_STROKECONVERT_CURVE:
+ case GP_STROKECONVERT_POLY: /* convert after */
+ gp_stroke_to_bezier(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
+ add_start_point, add_end_point, gtd);
+ break;
+ default:
+ BLI_assert(!"invalid mode");
+ break;
+ }
+ prev_gps = gps;
+ }
+
+ /* If link_strokes, be sure first and last points have a zero weight/size! */
+ if (link_strokes) {
+ gp_stroke_finalize_curve_endpoints(cu);
+ }
+
+ /* Update curve's weights, if needed */
+ if (norm_weights && ((minmax_weights[0] > 0.0f) || (minmax_weights[1] < 1.0f))) {
+ gp_stroke_norm_curve_weights(cu, minmax_weights);
+ }
+
+ /* Create the path animation, if needed */
+ gp_stroke_path_animation(C, reports, cu, gtd);
+
+ if (mode == GP_STROKECONVERT_POLY) {
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ BKE_nurb_type_convert(nu, CU_POLY, false);
+ }
+ }
+
+ /* set the layer and select */
+ base_new->lay = ob->lay = base_orig ? base_orig->lay : BKE_screen_view3d_layer_active(v3d, scene);
+ base_new->flag = ob->flag = base_new->flag | SELECT;
+}
+
+/* --- */
+
+/* Check a GP layer has valid timing data! Else, most timing options are hidden in the operator.
+ * op may be NULL.
+ */
+static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ bGPDframe *gpf = NULL;
+ bGPDstroke *gps = NULL;
+ bGPDspoint *pt;
+ double base_time, cur_time, prev_time = -1.0;
+ int i;
+ bool valid = true;
+
+ if (!gpl || !(gpf = gpencil_layer_getframe(gpl, CFRA, 0)) || !(gps = gpf->strokes.first))
+ return false;
+
+ do {
+ base_time = cur_time = gps->inittime;
+ if (cur_time <= prev_time) {
+ valid = false;
+ break;
+ }
+
+ prev_time = cur_time;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ cur_time = base_time + (double)pt->time;
+ /* First point of a stroke should have the same time as stroke's inittime,
+ * so it's the only case where equality is allowed!
+ */
+ if ((i && cur_time <= prev_time) || (cur_time < prev_time)) {
+ valid = false;
+ break;
+ }
+ prev_time = cur_time;
+ }
+
+ if (!valid) {
+ break;
+ }
+ } while ((gps = gps->next));
+
+ if (op) {
+ RNA_boolean_set(op->ptr, "use_timing_data", valid);
+ }
+ return valid;
+}
+
+/* Check end_frame is always > start frame! */
+static void gp_convert_set_end_frame(struct Main *UNUSED(main), struct Scene *UNUSED(scene), struct PointerRNA *ptr)
+{
+ int start_frame = RNA_int_get(ptr, "start_frame");
+ int end_frame = RNA_int_get(ptr, "end_frame");
+
+ if (end_frame <= start_frame) {
+ RNA_int_set(ptr, "end_frame", start_frame + 1);
+ }
+}
+
+static int gp_convert_poll(bContext *C)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = NULL;
+ bGPDframe *gpf = NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ Scene *scene = CTX_data_scene(C);
+
+ /* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!),
+ * and if we are not in edit mode!
+ */
+ return ((sa && sa->spacetype == SPACE_VIEW3D) &&
+ (gpl = gpencil_layer_getactive(gpd)) &&
+ (gpf = gpencil_layer_getframe(gpl, CFRA, 0)) &&
+ (gpf->strokes.first) &&
+ (scene->obedit == NULL));
+}
+
+static int gp_convert_layer_exec(bContext *C, wmOperator *op)
+{
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_timing_data");
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ Scene *scene = CTX_data_scene(C);
+ const int mode = RNA_enum_get(op->ptr, "type");
+ const bool norm_weights = RNA_boolean_get(op->ptr, "use_normalize_weights");
+ const float rad_fac = RNA_float_get(op->ptr, "radius_multiplier");
+ const bool link_strokes = RNA_boolean_get(op->ptr, "use_link_strokes");
+ bool valid_timing;
+ tGpTimingData gtd;
+
+ /* check if there's data to work with */
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data to work on");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!RNA_property_is_set(op->ptr, prop) && !gp_convert_check_has_valid_timing(C, gpl, op)) {
+ BKE_report(op->reports, RPT_WARNING,
+ "Current Grease Pencil strokes have no valid timing data, most timing options will be hidden!");
+ }
+ valid_timing = RNA_property_boolean_get(op->ptr, prop);
+
+ gtd.mode = RNA_enum_get(op->ptr, "timing_mode");
+ /* Check for illegal timing mode! */
+ if (!valid_timing && !ELEM(gtd.mode, GP_STROKECONVERT_TIMING_NONE, GP_STROKECONVERT_TIMING_LINEAR)) {
+ gtd.mode = GP_STROKECONVERT_TIMING_LINEAR;
+ RNA_enum_set(op->ptr, "timing_mode", gtd.mode);
+ }
+ if (!link_strokes) {
+ gtd.mode = GP_STROKECONVERT_TIMING_NONE;
+ }
+
+ /* grab all relevant settings */
+ gtd.frame_range = RNA_int_get(op->ptr, "frame_range");
+ gtd.start_frame = RNA_int_get(op->ptr, "start_frame");
+ gtd.realtime = valid_timing ? RNA_boolean_get(op->ptr, "use_realtime") : false;
+ gtd.end_frame = RNA_int_get(op->ptr, "end_frame");
+ gtd.gap_duration = RNA_float_get(op->ptr, "gap_duration");
+ gtd.gap_randomness = RNA_float_get(op->ptr, "gap_randomness");
+ gtd.gap_randomness = min_ff(gtd.gap_randomness, gtd.gap_duration);
+ gtd.seed = RNA_int_get(op->ptr, "seed");
+ gtd.num_points = gtd.cur_point = 0;
+ gtd.dists = gtd.times = NULL;
+ gtd.tot_dist = gtd.tot_time = gtd.gap_tot_time = 0.0f;
+ gtd.inittime = 0.0;
+ gtd.offset_time = 0.0f;
+
+ /* perform conversion */
+ gp_layer_to_curve(C, op->reports, gpd, gpl, mode, norm_weights, rad_fac, link_strokes, &gtd);
+
+ /* free temp memory */
+ if (gtd.dists) {
+ MEM_freeN(gtd.dists);
+ gtd.dists = NULL;
+ }
+ if (gtd.times) {
+ MEM_freeN(gtd.times);
+ gtd.times = NULL;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_OBJECT | NA_ADDED, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+
+ /* done */
+ return OPERATOR_FINISHED;
+}
+
+static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+ const bool link_strokes = RNA_boolean_get(ptr, "use_link_strokes");
+ int timing_mode = RNA_enum_get(ptr, "timing_mode");
+ bool realtime = RNA_boolean_get(ptr, "use_realtime");
+ float gap_duration = RNA_float_get(ptr, "gap_duration");
+ float gap_randomness = RNA_float_get(ptr, "gap_randomness");
+ const bool valid_timing = RNA_boolean_get(ptr, "use_timing_data");
+
+ /* Always show those props */
+ if (STREQ(prop_id, "type") ||
+ STREQ(prop_id, "use_normalize_weights") ||
+ STREQ(prop_id, "radius_multiplier") ||
+ STREQ(prop_id, "use_link_strokes"))
+ {
+ return true;
+ }
+
+ /* Never show this prop */
+ if (STREQ(prop_id, "use_timing_data"))
+ return false;
+
+ if (link_strokes) {
+ /* Only show when link_stroke is true */
+ if (STREQ(prop_id, "timing_mode"))
+ return true;
+
+ if (timing_mode != GP_STROKECONVERT_TIMING_NONE) {
+ /* Only show when link_stroke is true and stroke timing is enabled */
+ if (STREQ(prop_id, "frame_range") ||
+ STREQ(prop_id, "start_frame"))
+ {
+ return true;
+ }
+
+ /* Only show if we have valid timing data! */
+ if (valid_timing && STREQ(prop_id, "use_realtime"))
+ return true;
+
+ /* Only show if realtime or valid_timing is false! */
+ if ((!realtime || !valid_timing) && STREQ(prop_id, "end_frame"))
+ return true;
+
+ if (valid_timing && timing_mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
+ /* Only show for custom gaps! */
+ if (STREQ(prop_id, "gap_duration"))
+ return true;
+
+ /* Only show randomness for non-null custom gaps! */
+ if (STREQ(prop_id, "gap_randomness") && (gap_duration > 0.0f))
+ return true;
+
+ /* Only show seed for randomize action! */
+ if (STREQ(prop_id, "seed") && (gap_duration > 0.0f) && (gap_randomness > 0.0f))
+ return true;
+ }
+ }
+ }
+
+ /* Else, hidden! */
+ return false;
+}
+
+static void gp_convert_ui(bContext *C, wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ PointerRNA ptr;
+
+ RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
+
+ /* Main auto-draw call */
+ uiDefAutoButsRNA(layout, &ptr, gp_convert_draw_check_prop, '\0');
+}
+
+void GPENCIL_OT_convert(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Convert Grease Pencil";
+ ot->idname = "GPENCIL_OT_convert";
+ ot->description = "Convert the active Grease Pencil layer to a new Curve Object";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = gp_convert_layer_exec;
+ ot->poll = gp_convert_poll;
+ ot->ui = gp_convert_ui;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_convertmodes, 0, "Type", "Which type of curve to convert to");
+
+ RNA_def_boolean(ot->srna, "use_normalize_weights", true, "Normalize Weight",
+ "Normalize weight (set from stroke width)");
+ RNA_def_float(ot->srna, "radius_multiplier", 1.0f, 0.0f, 1000.0f, "Radius Fac",
+ "Multiplier for the points' radii (set from stroke width)", 0.0f, 10.0f);
+ RNA_def_boolean(ot->srna, "use_link_strokes", true, "Link Strokes",
+ "Whether to link strokes with zero-radius sections of curves");
+
+ prop = RNA_def_enum(ot->srna, "timing_mode", prop_gpencil_convert_timingmodes, GP_STROKECONVERT_TIMING_FULL,
+ "Timing Mode", "How to use timing data stored in strokes");
+ RNA_def_enum_funcs(prop, rna_GPConvert_mode_items);
+
+ RNA_def_int(ot->srna, "frame_range", 100, 1, 10000, "Frame Range",
+ "The duration of evaluation of the path control curve", 1, 1000);
+ RNA_def_int(ot->srna, "start_frame", 1, 1, 100000, "Start Frame",
+ "The start frame of the path control curve", 1, 100000);
+ RNA_def_boolean(ot->srna, "use_realtime", false, "Realtime",
+ "Whether the path control curve reproduces the drawing in realtime, starting from Start Frame");
+ prop = RNA_def_int(ot->srna, "end_frame", 250, 1, 100000, "End Frame",
+ "The end frame of the path control curve (if Realtime is not set)", 1, 100000);
+ RNA_def_property_update_runtime(prop, gp_convert_set_end_frame);
+
+ RNA_def_float(ot->srna, "gap_duration", 0.0f, 0.0f, 10000.0f, "Gap Duration",
+ "Custom Gap mode: (Average) length of gaps, in frames "
+ "(Note: Realtime value, will be scaled if Realtime is not set)", 0.0f, 1000.0f);
+ RNA_def_float(ot->srna, "gap_randomness", 0.0f, 0.0f, 10000.0f, "Gap Randomness",
+ "Custom Gap mode: Number of frames that gap lengths can vary", 0.0f, 1000.0f);
+ RNA_def_int(ot->srna, "seed", 0, 0, 1000, "Random Seed",
+ "Custom Gap mode: Random generator seed", 0, 100);
+
+ /* Note: Internal use, this one will always be hidden by UI code... */
+ prop = RNA_def_boolean(ot->srna, "use_timing_data", false, "Has Valid Timing",
+ "Whether the converted Grease Pencil layer has valid timing data (internal use)");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+/* ************************************************ */
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
new file mode 100644
index 00000000000..fa76029bb2e
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -0,0 +1,447 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008, Blender Foundation, Joshua Leung
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators for dealing with GP datablocks and layers
+ */
+
+/** \file blender/editors/gpencil/gpencil_data.c
+ * \ingroup edgpencil
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "BLF_translation.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_library.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "ED_gpencil.h"
+
+#include "gpencil_intern.h"
+
+
+/* ************************************************ */
+/* Datablock Operators */
+
+/* ******************* Add New Data ************************ */
+
+/* add new datablock - wrapper around API */
+static int gp_data_add_exec(bContext *C, wmOperator *op)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+
+ if (gpd_ptr == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* decrement user count and add new datablock */
+ bGPdata *gpd = (*gpd_ptr);
+
+ id_us_min(&gpd->id);
+ *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_data_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Grease Pencil Add New";
+ ot->idname = "GPENCIL_OT_data_add";
+ ot->description = "Add new Grease Pencil datablock";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_data_add_exec;
+ ot->poll = gp_add_poll;
+}
+
+/* ******************* Unlink Data ************************ */
+
+/* poll callback for adding data/layers - special */
+static int gp_data_unlink_poll(bContext *C)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+
+ /* if we have access to some active data, make sure there's a datablock before enabling this */
+ return (gpd_ptr && *gpd_ptr);
+}
+
+
+/* unlink datablock - wrapper around API */
+static int gp_data_unlink_exec(bContext *C, wmOperator *op)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+
+ if (gpd_ptr == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* just unlink datablock now, decreasing its user count */
+ bGPdata *gpd = (*gpd_ptr);
+
+ id_us_min(&gpd->id);
+ *gpd_ptr = NULL;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_data_unlink(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Grease Pencil Unlink";
+ ot->idname = "GPENCIL_OT_data_unlink";
+ ot->description = "Unlink active Grease Pencil datablock";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_data_unlink_exec;
+ ot->poll = gp_data_unlink_poll;
+}
+
+
+/* ************************************************ */
+/* Layer Operators */
+
+/* ******************* Add New Layer ************************ */
+
+/* add new layer - wrapper around API */
+static int gp_layer_add_exec(bContext *C, wmOperator *op)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+
+ /* if there's no existing Grease-Pencil data there, add some */
+ if (gpd_ptr == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
+ return OPERATOR_CANCELLED;
+ }
+ if (*gpd_ptr == NULL)
+ *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
+
+ /* add new layer now */
+ gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), 1);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add New Layer";
+ ot->idname = "GPENCIL_OT_layer_add";
+ ot->description = "Add new Grease Pencil layer for the active Grease Pencil datablock";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_layer_add_exec;
+ ot->poll = gp_add_poll;
+}
+
+/* ******************* Remove Active Layer ************************* */
+
+static int gp_layer_remove_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl))
+ return OPERATOR_CANCELLED;
+
+ if (gpl->flag & GP_LAYER_LOCKED) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot delete locked layers");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* make the layer before this the new active layer
+ * - use the one after if this is the first
+ * - if this is the only layer, this naturally becomes NULL
+ */
+ if (gpl->prev)
+ gpencil_layer_setactive(gpd, gpl->prev);
+ else
+ gpencil_layer_setactive(gpd, gpl->next);
+
+ /* delete the layer now... */
+ gpencil_layer_delete(gpd, gpl);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Layer";
+ ot->idname = "GPENCIL_OT_layer_remove";
+ ot->description = "Remove active Grease Pencil layer";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_layer_remove_exec;
+ ot->poll = gp_active_layer_poll;
+}
+
+/* ******************* Move Layer Up/Down ************************** */
+
+enum {
+ GP_LAYER_MOVE_UP = -1,
+ GP_LAYER_MOVE_DOWN = 1
+};
+
+static int gp_layer_move_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+
+ int direction = RNA_enum_get(op->ptr, "type");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl))
+ return OPERATOR_CANCELLED;
+
+ /* up or down? */
+ if (direction == GP_LAYER_MOVE_UP) {
+ /* up */
+ BLI_remlink(&gpd->layers, gpl);
+ BLI_insertlinkbefore(&gpd->layers, gpl->prev, gpl);
+ }
+ else {
+ /* down */
+ BLI_remlink(&gpd->layers, gpl);
+ BLI_insertlinkafter(&gpd->layers, gpl->next, gpl);
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem slot_move[] = {
+ {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""},
+ {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Move Grease Pencil Layer";
+ ot->idname = "GPENCIL_OT_layer_move";
+ ot->description = "Move the active Grease Pencil layer up/down in the list";
+
+ /* api callbacks */
+ ot->exec = gp_layer_move_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
+}
+
+/* ********************* Duplicate Layer ************************** */
+
+static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+ bGPDlayer *new_layer;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl))
+ return OPERATOR_CANCELLED;
+
+ /* make copy of layer, and add it immediately after the existing layer */
+ new_layer = gpencil_layer_duplicate(gpl);
+ BLI_insertlinkafter(&gpd->layers, gpl, new_layer);
+
+ /* ensure new layer has a unique name, and is now the active layer */
+ BLI_uniquename(&gpd->layers, new_layer, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(new_layer->info));
+ gpencil_layer_setactive(gpd, new_layer);
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_duplicate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Duplicate Layer";
+ ot->idname = "GPENCIL_OT_layer_duplicate";
+ ot->description = "Make a copy of the active Grease Pencil layer";
+
+ /* callbacks */
+ ot->exec = gp_layer_copy_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* *********************** Hide Layers ******************************** */
+
+static int gp_hide_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *layer = gpencil_layer_getactive(gpd);
+ bool unselected = RNA_boolean_get(op->ptr, "unselected");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, layer))
+ return OPERATOR_CANCELLED;
+
+ if (unselected) {
+ bGPDlayer *gpl;
+
+ /* hide unselected */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl != layer) {
+ gpl->flag |= GP_LAYER_HIDE;
+ }
+ }
+ }
+ else {
+ /* hide selected/active */
+ layer->flag |= GP_LAYER_HIDE;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_hide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Hide Layer(s)";
+ ot->idname = "GPENCIL_OT_hide";
+ ot->description = "Hide selected/unselected Grease Pencil layers";
+
+ /* callbacks */
+ ot->exec = gp_hide_exec;
+ ot->poll = gp_active_layer_poll; /* NOTE: we need an active layer to play with */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected layers");
+}
+
+/* ********************** Show All Layers ***************************** */
+
+/* poll callback for showing layers */
+static int gp_reveal_poll(bContext *C)
+{
+ return ED_gpencil_data_get_active(C) != NULL;
+}
+
+static int gp_reveal_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl;
+
+ /* sanity checks */
+ if (gpd == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* make all layers visible */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->flag &= ~GP_LAYER_HIDE;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_reveal(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Show All Layers";
+ ot->idname = "GPENCIL_OT_reveal";
+ ot->description = "Show all Grease Pencil layers";
+
+ /* callbacks */
+ ot->exec = gp_reveal_exec;
+ ot->poll = gp_reveal_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ************************************************ */
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 212d384e5ca..26237890539 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -21,6 +21,8 @@
* Contributor(s): Joshua Leung
*
* ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators for editing Grease Pencil strokes
*/
/** \file blender/editors/gpencil/gpencil_edit.c
@@ -38,15 +40,10 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
-#include "BLI_rand.h"
#include "BLI_utildefines.h"
#include "BLF_translation.h"
-#include "DNA_anim_types.h"
-#include "DNA_curve_types.h"
-#include "DNA_object_types.h"
-#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -54,17 +51,11 @@
#include "DNA_gpencil_types.h"
#include "BKE_context.h"
-#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
-#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_library.h"
-#include "BKE_object.h"
#include "BKE_report.h"
-#include "BKE_scene.h"
#include "BKE_screen.h"
-#include "BKE_tracking.h"
#include "UI_interface.h"
@@ -78,454 +69,9 @@
#include "ED_gpencil.h"
#include "ED_view3d.h"
-#include "ED_clip.h"
-#include "ED_keyframing.h"
#include "gpencil_intern.h"
-
-/* ************************************************ */
-/* Context Wrangling... */
-
-/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it,
- * when context info is not available.
- */
-bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob, PointerRNA *ptr)
-{
- /* if there's an active area, check if the particular editor may
- * have defined any special Grease Pencil context for editing...
- */
- if (sa) {
- SpaceLink *sl = sa->spacedata.first;
-
- switch (sa->spacetype) {
- case SPACE_VIEW3D: /* 3D-View */
- case SPACE_TIME: /* Timeline - XXX: this is a hack to get it to show GP keyframes for 3D view */
- case SPACE_ACTION: /* DepeSheet - XXX: this is a hack to get the keyframe jump operator to take GP Keyframes into account */
- {
- BLI_assert(scene && ELEM(scene->toolsettings->gpencil_src,
- GP_TOOL_SOURCE_SCENE, GP_TOOL_SOURCE_OBJECT));
-
- if (scene->toolsettings->gpencil_src == GP_TOOL_SOURCE_OBJECT) {
- /* legacy behaviour for usage with old addons requiring object-linked to objects */
-
- /* just in case no active/selected object... */
- if (ob && (ob->flag & SELECT)) {
- /* for now, as long as there's an object, default to using that in 3D-View */
- if (ptr) RNA_id_pointer_create(&ob->id, ptr);
- return &ob->gpd;
- }
- /* else: defaults to scene... */
- }
- else {
- if (ptr) RNA_id_pointer_create(&scene->id, ptr);
- return &scene->gpd;
- }
- break;
- }
- case SPACE_NODE: /* Nodes Editor */
- {
- SpaceNode *snode = (SpaceNode *)sl;
-
- /* return the GP data for the active node block/node */
- if (snode && snode->nodetree) {
- /* for now, as long as there's an active node tree, default to using that in the Nodes Editor */
- if (ptr) RNA_id_pointer_create(&snode->nodetree->id, ptr);
- return &snode->nodetree->gpd;
- }
-
- /* even when there is no node-tree, don't allow this to flow to scene */
- return NULL;
- }
- case SPACE_SEQ: /* Sequencer */
- {
- SpaceSeq *sseq = (SpaceSeq *)sl;
-
- /* for now, Grease Pencil data is associated with the space (actually preview region only) */
- /* XXX our convention for everything else is to link to data though... */
- if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, ptr);
- return &sseq->gpd;
- }
- case SPACE_IMAGE: /* Image/UV Editor */
- {
- SpaceImage *sima = (SpaceImage *)sl;
-
- /* for now, Grease Pencil data is associated with the space... */
- /* XXX our convention for everything else is to link to data though... */
- if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, ptr);
- return &sima->gpd;
- }
- case SPACE_CLIP: /* Nodes Editor */
- {
- SpaceClip *sc = (SpaceClip *)sl;
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- if (clip) {
- if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
- MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
-
- if (!track)
- return NULL;
-
- if (ptr)
- RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, ptr);
-
- return &track->gpd;
- }
- else {
- if (ptr)
- RNA_id_pointer_create(&clip->id, ptr);
-
- return &clip->gpd;
- }
- }
- break;
- }
- default: /* unsupported space */
- return NULL;
- }
- }
-
- /* just fall back on the scene's GP data */
- if (ptr) RNA_id_pointer_create((ID *)scene, ptr);
- return (scene) ? &scene->gpd : NULL;
-}
-
-/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */
-bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
-{
- ID *screen_id = (ID *)CTX_wm_screen(C);
- Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
- Object *ob = CTX_data_active_object(C);
-
- return ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, ptr);
-}
-
-/* -------------------------------------------------------- */
-
-/* Get the active Grease Pencil datablock, when context is not available */
-bGPdata *ED_gpencil_data_get_active_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob)
-{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, NULL);
- return (gpd_ptr) ? *(gpd_ptr) : NULL;
-}
-
-/* Get the active Grease Pencil datablock */
-bGPdata *ED_gpencil_data_get_active(const bContext *C)
-{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
- return (gpd_ptr) ? *(gpd_ptr) : NULL;
-}
-
-/* -------------------------------------------------------- */
-
-// XXX: this should be removed... We really shouldn't duplicate logic like this!
-bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, View3D *v3d)
-{
- Base *base = scene->basact;
- bGPdata *gpd = NULL;
- /* We have to make sure active object is actually visible and selected, else we must use default scene gpd,
- * to be consistent with ED_gpencil_data_get_active's behavior.
- */
-
- if (base && TESTBASE(v3d, base)) {
- gpd = base->object->gpd;
- }
- return gpd ? gpd : scene->gpd;
-}
-
-/* ************************************************ */
-/* Panel Operators */
-
-/* poll callback for adding data/layers - special */
-static int gp_add_poll(bContext *C)
-{
- /* the base line we have is that we have somewhere to add Grease Pencil data */
- return ED_gpencil_data_get_pointers(C, NULL) != NULL;
-}
-
-/* poll callback for checking if there is an active layer */
-static int gp_active_layer_poll(bContext *C)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
-
- return (gpl != NULL);
-}
-
-/* ******************* Add New Data ************************ */
-
-/* add new datablock - wrapper around API */
-static int gp_data_add_exec(bContext *C, wmOperator *op)
-{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
- if (gpd_ptr == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
- return OPERATOR_CANCELLED;
- }
- else {
- /* decrement user count and add new datablock */
- bGPdata *gpd = (*gpd_ptr);
-
- id_us_min(&gpd->id);
- *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
- }
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_data_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Grease Pencil Add New";
- ot->idname = "GPENCIL_OT_data_add";
- ot->description = "Add new Grease Pencil datablock";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* callbacks */
- ot->exec = gp_data_add_exec;
- ot->poll = gp_add_poll;
-}
-
-/* ******************* Unlink Data ************************ */
-
-/* poll callback for adding data/layers - special */
-static int gp_data_unlink_poll(bContext *C)
-{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
- /* if we have access to some active data, make sure there's a datablock before enabling this */
- return (gpd_ptr && *gpd_ptr);
-}
-
-
-/* unlink datablock - wrapper around API */
-static int gp_data_unlink_exec(bContext *C, wmOperator *op)
-{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
- if (gpd_ptr == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
- return OPERATOR_CANCELLED;
- }
- else {
- /* just unlink datablock now, decreasing its user count */
- bGPdata *gpd = (*gpd_ptr);
-
- id_us_min(&gpd->id);
- *gpd_ptr = NULL;
- }
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_data_unlink(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Grease Pencil Unlink";
- ot->idname = "GPENCIL_OT_data_unlink";
- ot->description = "Unlink active Grease Pencil datablock";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* callbacks */
- ot->exec = gp_data_unlink_exec;
- ot->poll = gp_data_unlink_poll;
-}
-
-/* ******************* Add New Layer ************************ */
-
-/* add new layer - wrapper around API */
-static int gp_layer_add_exec(bContext *C, wmOperator *op)
-{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
- /* if there's no existing Grease-Pencil data there, add some */
- if (gpd_ptr == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
- return OPERATOR_CANCELLED;
- }
- if (*gpd_ptr == NULL)
- *gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
-
- /* add new layer now */
- gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), 1);
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_layer_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add New Layer";
- ot->idname = "GPENCIL_OT_layer_add";
- ot->description = "Add new Grease Pencil layer for the active Grease Pencil datablock";
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* callbacks */
- ot->exec = gp_layer_add_exec;
- ot->poll = gp_add_poll;
-}
-
-/* ******************* Remove Active Layer ************************* */
-
-static int gp_layer_remove_exec(bContext *C, wmOperator *op)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
-
- /* sanity checks */
- if (ELEM(NULL, gpd, gpl))
- return OPERATOR_CANCELLED;
-
- if (gpl->flag & GP_LAYER_LOCKED) {
- BKE_report(op->reports, RPT_ERROR, "Cannot delete locked layers");
- return OPERATOR_CANCELLED;
- }
-
- /* make the layer before this the new active layer
- * - use the one after if this is the first
- * - if this is the only layer, this naturally becomes NULL
- */
- if (gpl->prev)
- gpencil_layer_setactive(gpd, gpl->prev);
- else
- gpencil_layer_setactive(gpd, gpl->next);
-
- /* delete the layer now... */
- gpencil_layer_delete(gpd, gpl);
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_layer_remove(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove Layer";
- ot->idname = "GPENCIL_OT_layer_remove";
- ot->description = "Remove active Grease Pencil layer";
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* callbacks */
- ot->exec = gp_layer_remove_exec;
- ot->poll = gp_active_layer_poll;
-}
-
-/* ******************* Move Layer Up/Down ************************** */
-
-enum {
- GP_LAYER_MOVE_UP = -1,
- GP_LAYER_MOVE_DOWN = 1
-};
-
-static int gp_layer_move_exec(bContext *C, wmOperator *op)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
-
- int direction = RNA_enum_get(op->ptr, "type");
-
- /* sanity checks */
- if (ELEM(NULL, gpd, gpl))
- return OPERATOR_CANCELLED;
-
- /* up or down? */
- if (direction == GP_LAYER_MOVE_UP) {
- /* up */
- BLI_remlink(&gpd->layers, gpl);
- BLI_insertlinkbefore(&gpd->layers, gpl->prev, gpl);
- }
- else {
- /* down */
- BLI_remlink(&gpd->layers, gpl);
- BLI_insertlinkafter(&gpd->layers, gpl->next, gpl);
- }
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_layer_move(wmOperatorType *ot)
-{
- static EnumPropertyItem slot_move[] = {
- {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""},
- {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Move Grease Pencil Layer";
- ot->idname = "GPENCIL_OT_layer_move";
- ot->description = "Move the active Grease Pencil layer up/down in the list";
-
- /* api callbacks */
- ot->exec = gp_layer_move_exec;
- ot->poll = gp_active_layer_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
-}
-
-/* ********************* Duplicate Layer ************************** */
-
-static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
- bGPDlayer *new_layer;
-
- /* sanity checks */
- if (ELEM(NULL, gpd, gpl))
- return OPERATOR_CANCELLED;
-
- /* make copy of layer, and add it immediately after the existing layer */
- new_layer = gpencil_layer_duplicate(gpl);
- BLI_insertlinkafter(&gpd->layers, gpl, new_layer);
-
- /* ensure new layer has a unique name, and is now the active layer */
- BLI_uniquename(&gpd->layers, new_layer, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(new_layer->info));
- gpencil_layer_setactive(gpd, new_layer);
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_layer_duplicate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Duplicate Layer";
- ot->idname = "GPENCIL_OT_layer_duplicate";
- ot->description = "Make a copy of the active Grease Pencil layer";
-
- /* callbacks */
- ot->exec = gp_layer_copy_exec;
- ot->poll = gp_active_layer_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/* ************************************************ */
/* Stroke Editing Operators */
@@ -1256,1398 +802,3 @@ void GPENCIL_OT_delete(wmOperatorType *ot)
}
/* ************************************************ */
-/* Grease Pencil to Data Operator */
-
-/* defines for possible modes */
-enum {
- GP_STROKECONVERT_PATH = 1,
- GP_STROKECONVERT_CURVE,
- GP_STROKECONVERT_POLY,
-};
-
-/* Defines for possible timing modes */
-enum {
- GP_STROKECONVERT_TIMING_NONE = 1,
- GP_STROKECONVERT_TIMING_LINEAR = 2,
- GP_STROKECONVERT_TIMING_FULL = 3,
- GP_STROKECONVERT_TIMING_CUSTOMGAP = 4,
-};
-
-/* RNA enum define */
-static EnumPropertyItem prop_gpencil_convertmodes[] = {
- {GP_STROKECONVERT_PATH, "PATH", 0, "Path", ""},
- {GP_STROKECONVERT_CURVE, "CURVE", 0, "Bezier Curve", ""},
- {GP_STROKECONVERT_POLY, "POLY", 0, "Polygon Curve", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-static EnumPropertyItem prop_gpencil_convert_timingmodes_restricted[] = {
- {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
- {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
- {0, NULL, 0, NULL, NULL},
-};
-
-static EnumPropertyItem prop_gpencil_convert_timingmodes[] = {
- {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
- {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
- {GP_STROKECONVERT_TIMING_FULL, "FULL", 0, "Original", "Use the original timing, gaps included"},
- {GP_STROKECONVERT_TIMING_CUSTOMGAP, "CUSTOMGAP", 0, "Custom Gaps",
- "Use the original timing, but with custom gap lengths (in frames)"},
- {0, NULL, 0, NULL, NULL},
-};
-
-static EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop),
- bool *UNUSED(r_free))
-{
- if (RNA_boolean_get(ptr, "use_timing_data")) {
- return prop_gpencil_convert_timingmodes;
- }
- return prop_gpencil_convert_timingmodes_restricted;
-}
-
-/* --- */
-
-/* convert the coordinates from the given stroke point into 3d-coordinates
- * - assumes that the active space is the 3D-View
- */
-static void gp_strokepoint_convertcoords(bContext *C, bGPDstroke *gps, bGPDspoint *pt, float p3d[3], rctf *subrect)
-{
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- ARegion *ar = CTX_wm_region(C);
-
- if (gps->flag & GP_STROKE_3DSPACE) {
- /* directly use 3d-coordinates */
- copy_v3_v3(p3d, &pt->x);
- }
- else {
- const float *fp = ED_view3d_cursor3d_get(scene, v3d);
- float mvalf[2];
-
- /* get screen coordinate */
- if (gps->flag & GP_STROKE_2DSPACE) {
- View2D *v2d = &ar->v2d;
- UI_view2d_view_to_region_fl(v2d, pt->x, pt->y, &mvalf[0], &mvalf[1]);
- }
- else {
- if (subrect) {
- mvalf[0] = (((float)pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
- mvalf[1] = (((float)pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
- }
- else {
- mvalf[0] = (float)pt->x / 100.0f * ar->winx;
- mvalf[1] = (float)pt->y / 100.0f * ar->winy;
- }
- }
-
- ED_view3d_win_to_3d(ar, fp, mvalf, p3d);
- }
-}
-
-/* --- */
-
-/* temp struct for gp_stroke_path_animation() */
-typedef struct tGpTimingData {
- /* Data set from operator settings */
- int mode;
- int frame_range; /* Number of frames evaluated for path animation */
- int start_frame, end_frame;
- bool realtime; /* Will overwrite end_frame in case of Original or CustomGap timing... */
- float gap_duration, gap_randomness; /* To be used with CustomGap mode*/
- int seed;
-
- /* Data set from points, used to compute final timing FCurve */
- int num_points, cur_point;
-
- /* Distances */
- float *dists;
- float tot_dist;
-
- /* Times */
- float *times; /* Note: Gap times will be negative! */
- float tot_time, gap_tot_time;
- double inittime;
-
- /* Only used during creation of dists & times lists. */
- float offset_time;
-} tGpTimingData;
-
-/* Init point buffers for timing data.
- * Note this assumes we only grow those arrays!
- */
-static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr)
-{
- float *tmp;
-
- BLI_assert(nbr > gtd->num_points);
-
- /* distances */
- tmp = gtd->dists;
- gtd->dists = MEM_callocN(sizeof(float) * nbr, __func__);
- if (tmp) {
- memcpy(gtd->dists, tmp, sizeof(float) * gtd->num_points);
- MEM_freeN(tmp);
- }
-
- /* times */
- tmp = gtd->times;
- gtd->times = MEM_callocN(sizeof(float) * nbr, __func__);
- if (tmp) {
- memcpy(gtd->times, tmp, sizeof(float) * gtd->num_points);
- MEM_freeN(tmp);
- }
-
- gtd->num_points = nbr;
-}
-
-/* add stroke point to timing buffers */
-static void gp_timing_data_add_point(tGpTimingData *gtd, const double stroke_inittime, const float time,
- const float delta_dist)
-{
- float delta_time = 0.0f;
- const int cur_point = gtd->cur_point;
-
- if (!cur_point) {
- /* Special case, first point, if time is not 0.0f we have to compensate! */
- gtd->offset_time = -time;
- gtd->times[cur_point] = 0.0f;
- }
- else if (time < 0.0f) {
- /* This is a gap, negative value! */
- gtd->times[cur_point] = -(((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time);
- delta_time = -gtd->times[cur_point] - gtd->times[cur_point - 1];
-
- gtd->gap_tot_time += delta_time;
- }
- else {
- gtd->times[cur_point] = (((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time);
- delta_time = gtd->times[cur_point] - fabsf(gtd->times[cur_point - 1]);
- }
-
- gtd->tot_time += delta_time;
- gtd->tot_dist += delta_dist;
- gtd->dists[cur_point] = gtd->tot_dist;
-
- gtd->cur_point++;
-}
-
-/* In frames! Binary search for FCurve keys have a threshold of 0.01, so we can't set
- * arbitrarily close points - this is esp. important with NoGaps mode!
- */
-#define MIN_TIME_DELTA 0.02f
-
-/* Loop over next points to find the end of the stroke, and compute */
-static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, RNG *rng, const int idx, const int nbr_gaps,
- int *nbr_done_gaps, const float tot_gaps_time, const float delta_time,
- float *next_delta_time)
-{
- int j;
-
- for (j = idx + 1; j < gtd->num_points; j++) {
- if (gtd->times[j] < 0) {
- gtd->times[j] = -gtd->times[j];
- if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
- /* In this mode, gap time between this stroke and the next should be 0 currently...
- * So we have to compute its final duration!
- */
- if (gtd->gap_randomness > 0.0f) {
- /* We want gaps that are in gtd->gap_duration +/- gtd->gap_randomness range,
- * and which sum to exactly tot_gaps_time...
- */
- int rem_gaps = nbr_gaps - (*nbr_done_gaps);
- if (rem_gaps < 2) {
- /* Last gap, just give remaining time! */
- *next_delta_time = tot_gaps_time;
- }
- else {
- float delta, min, max;
-
- /* This code ensures that if the first gaps have been shorter than average gap_duration,
- * next gaps will tend to be longer (i.e. try to recover the lateness), and vice-versa!
- */
- delta = delta_time - (gtd->gap_duration * (*nbr_done_gaps));
-
- /* Clamp min between [-gap_randomness, 0.0], with lower delta giving higher min */
- min = -gtd->gap_randomness - delta;
- CLAMP(min, -gtd->gap_randomness, 0.0f);
-
- /* Clamp max between [0.0, gap_randomness], with lower delta giving higher max */
- max = gtd->gap_randomness - delta;
- CLAMP(max, 0.0f, gtd->gap_randomness);
- *next_delta_time += gtd->gap_duration + (BLI_rng_get_float(rng) * (max - min)) + min;
- }
- }
- else {
- *next_delta_time += gtd->gap_duration;
- }
- }
- (*nbr_done_gaps)++;
- break;
- }
- }
-
- return j - 1;
-}
-
-static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, RNG *rng, int *nbr_gaps, float *tot_gaps_time)
-{
- int i;
- float delta_time = 0.0f;
-
- for (i = 0; i < gtd->num_points; i++) {
- if (gtd->times[i] < 0 && i) {
- (*nbr_gaps)++;
- gtd->times[i] = -gtd->times[i] - delta_time;
- delta_time += gtd->times[i] - gtd->times[i - 1];
- gtd->times[i] = -gtd->times[i - 1]; /* Temp marker, values *have* to be different! */
- }
- else {
- gtd->times[i] -= delta_time;
- }
- }
- gtd->tot_time -= delta_time;
-
- *tot_gaps_time = (float)(*nbr_gaps) * gtd->gap_duration;
- gtd->tot_time += *tot_gaps_time;
- if (G.debug & G_DEBUG) {
- printf("%f, %f, %f, %d\n", gtd->tot_time, delta_time, *tot_gaps_time, *nbr_gaps);
- }
- if (gtd->gap_randomness > 0.0f) {
- BLI_rng_srandom(rng, gtd->seed);
- }
-}
-
-static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu,
- Curve *cu, tGpTimingData *gtd, RNG *rng, const float time_range,
- const int nbr_gaps, const float tot_gaps_time)
-{
- /* Use actual recorded timing! */
- const float time_start = (float)gtd->start_frame;
-
- float last_valid_time = 0.0f;
- int end_stroke_idx = -1, start_stroke_idx = 0;
- float end_stroke_time = 0.0f;
-
- /* CustomGaps specific */
- float delta_time = 0.0f, next_delta_time = 0.0f;
- int nbr_done_gaps = 0;
-
- int i;
- float cfra;
-
- /* This is a bit tricky, as:
- * - We can't add arbitrarily close points on FCurve (in time).
- * - We *must* have all "caps" points of all strokes in FCurve, as much as possible!
- */
- for (i = 0; i < gtd->num_points; i++) {
- /* If new stroke... */
- if (i > end_stroke_idx) {
- start_stroke_idx = i;
- delta_time = next_delta_time;
- /* find end of that new stroke */
- end_stroke_idx = gp_find_end_of_stroke_idx(gtd, rng, i, nbr_gaps, &nbr_done_gaps,
- tot_gaps_time, delta_time, &next_delta_time);
- /* This one should *never* be negative! */
- end_stroke_time = time_start + ((gtd->times[end_stroke_idx] + delta_time) / gtd->tot_time * time_range);
- }
-
- /* Simple proportional stuff... */
- cu->ctime = gtd->dists[i] / gtd->tot_dist * cu->pathlen;
- cfra = time_start + ((gtd->times[i] + delta_time) / gtd->tot_time * time_range);
-
- /* And now, the checks about timing... */
- if (i == start_stroke_idx) {
- /* If first point of a stroke, be sure it's enough ahead of last valid keyframe, and
- * that the end point of the stroke is far enough!
- * In case it is not, we keep the end point...
- * Note that with CustomGaps mode, this is here we set the actual gap timing!
- */
- if ((end_stroke_time - last_valid_time) > MIN_TIME_DELTA * 2) {
- if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
- cfra = last_valid_time + MIN_TIME_DELTA;
- }
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
- last_valid_time = cfra;
- }
- else if (G.debug & G_DEBUG) {
- printf("\t Skipping start point %d, too close from end point %d\n", i, end_stroke_idx);
- }
- }
- else if (i == end_stroke_idx) {
- /* Always try to insert end point of a curve (should be safe enough, anyway...) */
- if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
- cfra = last_valid_time + MIN_TIME_DELTA;
- }
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
- last_valid_time = cfra;
- }
- else {
- /* Else ("middle" point), we only insert it if it's far enough from last keyframe,
- * and also far enough from (not yet added!) end_stroke keyframe!
- */
- if ((cfra - last_valid_time) > MIN_TIME_DELTA && (end_stroke_time - cfra) > MIN_TIME_DELTA) {
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
- last_valid_time = cfra;
- }
- else if (G.debug & G_DEBUG) {
- printf("\t Skipping \"middle\" point %d, too close from last added point or end point %d\n",
- i, end_stroke_idx);
- }
- }
- }
-}
-
-static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu, tGpTimingData *gtd)
-{
- Scene *scene = CTX_data_scene(C);
- bAction *act;
- FCurve *fcu;
- PointerRNA ptr;
- PropertyRNA *prop = NULL;
- int nbr_gaps = 0, i;
-
- if (gtd->mode == GP_STROKECONVERT_TIMING_NONE)
- return;
-
- /* gap_duration and gap_randomness are in frames, but we need seconds!!! */
- gtd->gap_duration = FRA2TIME(gtd->gap_duration);
- gtd->gap_randomness = FRA2TIME(gtd->gap_randomness);
-
- /* Enable path! */
- cu->flag |= CU_PATH;
- cu->pathlen = gtd->frame_range;
-
- /* Get RNA pointer to read/write path time values */
- RNA_id_pointer_create((ID *)cu, &ptr);
- prop = RNA_struct_find_property(&ptr, "eval_time");
-
- /* Ensure we have an F-Curve to add keyframes to */
- act = verify_adt_action((ID *)cu, true);
- fcu = verify_fcurve(act, NULL, &ptr, "eval_time", 0, true);
-
- if (G.debug & G_DEBUG) {
- printf("%s: tot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time);
- for (i = 0; i < gtd->num_points; i++) {
- printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]);
- }
- }
-
- if (gtd->mode == GP_STROKECONVERT_TIMING_LINEAR) {
- float cfra;
-
- /* Linear extrapolation! */
- fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
-
- cu->ctime = 0.0f;
- cfra = (float)gtd->start_frame;
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
-
- cu->ctime = cu->pathlen;
- if (gtd->realtime) {
- cfra += (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
- }
- else {
- cfra = (float)gtd->end_frame;
- }
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
- }
- else {
- /* Use actual recorded timing! */
- RNG *rng = BLI_rng_new(0);
- float time_range;
-
- /* CustomGaps specific */
- float tot_gaps_time = 0.0f;
-
- /* Pre-process gaps, in case we don't want to keep their original timing */
- if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
- gp_stroke_path_animation_preprocess_gaps(gtd, rng, &nbr_gaps, &tot_gaps_time);
- }
-
- if (gtd->realtime) {
- time_range = (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
- }
- else {
- time_range = (float)(gtd->end_frame - gtd->start_frame);
- }
-
- if (G.debug & G_DEBUG) {
- printf("GP Stroke Path Conversion: Starting keying!\n");
- }
-
- gp_stroke_path_animation_add_keyframes(reports, ptr, prop, fcu, cu, gtd, rng, time_range,
- nbr_gaps, tot_gaps_time);
-
- BLI_rng_free(rng);
- }
-
- /* As we used INSERTKEY_FAST mode, we need to recompute all curve's handles now */
- calchandles_fcurve(fcu);
-
- if (G.debug & G_DEBUG) {
- printf("%s: \ntot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time);
- for (i = 0; i < gtd->num_points; i++) {
- printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]);
- }
- printf("\n\n");
- }
-
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
-
- /* send updates */
- DAG_id_tag_update(&cu->id, 0);
-}
-
-#undef MIN_TIME_DELTA
-
-#define GAP_DFAC 0.01f
-#define WIDTH_CORR_FAC 0.1f
-#define BEZT_HANDLE_FAC 0.3f
-
-/* convert stroke to 3d path */
-
-/* helper */
-static void gp_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const float p[3], const float prev_p[3],
- const bool do_gtd, const double inittime, const float time,
- const float width, const float rad_fac, float minmax_weights[2])
-{
- copy_v3_v3(bp->vec, p);
- bp->vec[3] = 1.0f;
-
- /* set settings */
- bp->f1 = SELECT;
- bp->radius = width * rad_fac;
- bp->weight = width;
- CLAMP(bp->weight, 0.0f, 1.0f);
- if (bp->weight < minmax_weights[0]) {
- minmax_weights[0] = bp->weight;
- }
- else if (bp->weight > minmax_weights[1]) {
- minmax_weights[1] = bp->weight;
- }
-
- /* Update timing data */
- if (do_gtd) {
- gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
- }
-}
-
-static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
- float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
- const bool add_end_point, tGpTimingData *gtd)
-{
- bGPDspoint *pt;
- Nurb *nu = (curnu) ? *curnu : NULL;
- BPoint *bp, *prev_bp = NULL;
- const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
- const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
- int i, old_nbp = 0;
-
- /* create new 'nurb' or extend current one within the curve */
- if (nu) {
- old_nbp = nu->pntsu;
-
- /* If stitch, the first point of this stroke is already present in current nu.
- * Else, we have to add two additional points to make the zero-radius link between strokes.
- */
- BKE_nurb_points_add(nu, gps->totpoints + (stitch ? -1 : 2) + add_start_end_points);
- }
- else {
- nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
-
- nu->pntsu = gps->totpoints + add_start_end_points;
- nu->pntsv = 1;
- nu->orderu = 2; /* point-to-point! */
- nu->type = CU_NURBS;
- nu->flagu = CU_NURB_ENDPOINT;
- nu->resolu = cu->resolu;
- nu->resolv = cu->resolv;
- nu->knotsu = NULL;
-
- nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "bpoints");
-
- stitch = false; /* Security! */
- }
-
- if (do_gtd) {
- gp_timing_data_set_nbr(gtd, nu->pntsu);
- }
-
- /* If needed, make the link between both strokes with two zero-radius additional points */
- /* About "zero-radius" point interpolations:
- * - If we have at least two points in current curve (most common case), we linearly extrapolate
- * the last segment to get the first point (p1) position and timing.
- * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
- * with the first point of the current stroke.
- * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
- * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
- */
- if (curnu && !stitch && old_nbp) {
- float p1[3], p2[3], p[3], next_p[3];
- float dt1 = 0.0f, dt2 = 0.0f;
-
- BLI_assert(gps->prev != NULL);
-
- prev_bp = NULL;
- if ((old_nbp > 1) && (gps->prev->totpoints > 1)) {
- /* Only use last curve segment if previous stroke was not a single-point one! */
- prev_bp = &nu->bp[old_nbp - 2];
- }
- bp = &nu->bp[old_nbp - 1];
-
- /* First point */
- gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
- if (prev_bp) {
- interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC);
- if (do_gtd) {
- const int idx = gps->prev->totpoints - 1;
- dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
- }
- }
- else {
- interp_v3_v3v3(p1, bp->vec, p, GAP_DFAC);
- if (do_gtd) {
- dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
- }
- }
- bp++;
- gp_stroke_to_path_add_point(gtd, bp, p1, (bp - 1)->vec, do_gtd, gps->prev->inittime, dt1,
- 0.0f, rad_fac, minmax_weights);
-
- /* Second point */
- /* Note dt2 is always negative, which marks the gap. */
- if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
- interp_v3_v3v3(p2, p, next_p, -GAP_DFAC);
- if (do_gtd) {
- dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
- }
- }
- else {
- interp_v3_v3v3(p2, p, bp->vec, GAP_DFAC);
- if (do_gtd) {
- dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
- }
- }
- bp++;
- gp_stroke_to_path_add_point(gtd, bp, p2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights);
-
- old_nbp += 2;
- }
- else if (add_start_point) {
- float p[3], next_p[3];
- float dt = 0.0f;
-
- gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect);
- if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect);
- interp_v3_v3v3(p, p, next_p, -GAP_DFAC);
- if (do_gtd) {
- dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
- }
- }
- else {
- p[0] -= GAP_DFAC; /* Rather arbitrary... */
- dt = -GAP_DFAC; /* Rather arbitrary too! */
- }
- bp = &nu->bp[old_nbp];
- /* Note we can't give anything else than 0.0 as time here, since a negative one (which would be expected value)
- * would not work (it would be *before* gtd->inittime, which is not supported currently).
- */
- gp_stroke_to_path_add_point(gtd, bp, p, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
-
- old_nbp++;
- }
-
- if (old_nbp) {
- prev_bp = &nu->bp[old_nbp - 1];
- }
-
- /* add points */
- for (i = (stitch) ? 1 : 0, pt = &gps->points[(stitch) ? 1 : 0], bp = &nu->bp[old_nbp];
- i < gps->totpoints;
- i++, pt++, bp++)
- {
- float p[3];
- float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
-
- /* get coordinates to add at */
- gp_strokepoint_convertcoords(C, gps, pt, p, subrect);
-
- gp_stroke_to_path_add_point(gtd, bp, p, (prev_bp) ? prev_bp->vec : p, do_gtd, gps->inittime, pt->time,
- width, rad_fac, minmax_weights);
-
- prev_bp = bp;
- }
-
- if (add_end_point) {
- float p[3];
- float dt = 0.0f;
-
- if (gps->totpoints > 1) {
- interp_v3_v3v3(p, prev_bp->vec, (prev_bp - 1)->vec, -GAP_DFAC);
- if (do_gtd) {
- const int idx = gps->totpoints - 1;
- dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
- }
- }
- else {
- copy_v3_v3(p, prev_bp->vec);
- p[0] += GAP_DFAC; /* Rather arbitrary... */
- dt = GAP_DFAC; /* Rather arbitrary too! */
- }
- /* Note bp has already been incremented in main loop above, so it points to the right place. */
- gp_stroke_to_path_add_point(gtd, bp, p, prev_bp->vec, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
- }
-
- /* add nurb to curve */
- if (!curnu || !*curnu) {
- BLI_addtail(&cu->nurb, nu);
- }
- if (curnu) {
- *curnu = nu;
- }
-
- BKE_nurb_knot_calc_u(nu);
-}
-
-/* convert stroke to 3d bezier */
-
-/* helper */
-static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt,
- const float p[3], const float h1[3], const float h2[3], const float prev_p[3],
- const bool do_gtd, const double inittime, const float time,
- const float width, const float rad_fac, float minmax_weights[2])
-{
- copy_v3_v3(bezt->vec[0], h1);
- copy_v3_v3(bezt->vec[1], p);
- copy_v3_v3(bezt->vec[2], h2);
-
- /* set settings */
- bezt->h1 = bezt->h2 = HD_FREE;
- bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
- bezt->radius = width * rad_fac;
- bezt->weight = width;
- CLAMP(bezt->weight, 0.0f, 1.0f);
- if (bezt->weight < minmax_weights[0]) {
- minmax_weights[0] = bezt->weight;
- }
- else if (bezt->weight > minmax_weights[1]) {
- minmax_weights[1] = bezt->weight;
- }
-
- /* Update timing data */
- if (do_gtd) {
- gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
- }
-}
-
-static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
- float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
- const bool add_end_point, tGpTimingData *gtd)
-{
- bGPDspoint *pt;
- Nurb *nu = (curnu) ? *curnu : NULL;
- BezTriple *bezt, *prev_bezt = NULL;
- int i, tot, old_nbezt = 0;
- const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
- float p3d_cur[3], p3d_prev[3], p3d_next[3], h1[3], h2[3];
- const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
-
- /* create new 'nurb' or extend current one within the curve */
- if (nu) {
- old_nbezt = nu->pntsu;
- /* If we do stitch, first point of current stroke is assumed the same as last point of previous stroke,
- * so no need to add it.
- * If no stitch, we want to add two additional points to make a "zero-radius" link between both strokes.
- */
- BKE_nurb_bezierPoints_add(nu, gps->totpoints + ((stitch) ? -1 : 2) + add_start_end_points);
- }
- else {
- nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");
-
- nu->pntsu = gps->totpoints + add_start_end_points;
- nu->resolu = 12;
- nu->resolv = 12;
- nu->type = CU_BEZIER;
- nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * nu->pntsu, "bezts");
-
- stitch = false; /* Security! */
- }
-
- if (do_gtd) {
- gp_timing_data_set_nbr(gtd, nu->pntsu);
- }
-
- tot = gps->totpoints;
-
- /* get initial coordinates */
- pt = gps->points;
- if (tot) {
- gp_strokepoint_convertcoords(C, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
- if (tot > 1) {
- gp_strokepoint_convertcoords(C, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
- }
- if (stitch && tot > 2) {
- gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
- }
- }
-
- /* If needed, make the link between both strokes with two zero-radius additional points */
- if (curnu && old_nbezt) {
- BLI_assert(gps->prev != NULL);
-
- /* Update last point's second handle */
- if (stitch) {
- bezt = &nu->bezt[old_nbezt - 1];
- interp_v3_v3v3(h2, bezt->vec[1], p3d_cur, BEZT_HANDLE_FAC);
- copy_v3_v3(bezt->vec[2], h2);
- pt++;
- }
-
- /* Create "link points" */
- /* About "zero-radius" point interpolations:
- * - If we have at least two points in current curve (most common case), we linearly extrapolate
- * the last segment to get the first point (p1) position and timing.
- * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
- * with the first point of the current stroke.
- * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated
- * if it exists, else (if the stroke is a single point), linear interpolation with last curve point...
- */
- else {
- float p1[3], p2[3];
- float dt1 = 0.0f, dt2 = 0.0f;
-
- prev_bezt = NULL;
- if ((old_nbezt > 1) && (gps->prev->totpoints > 1)) {
- /* Only use last curve segment if previous stroke was not a single-point one! */
- prev_bezt = &nu->bezt[old_nbezt - 2];
- }
- bezt = &nu->bezt[old_nbezt - 1];
-
- /* First point */
- if (prev_bezt) {
- interp_v3_v3v3(p1, prev_bezt->vec[1], bezt->vec[1], 1.0f + GAP_DFAC);
- if (do_gtd) {
- const int idx = gps->prev->totpoints - 1;
- dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
- }
- }
- else {
- interp_v3_v3v3(p1, bezt->vec[1], p3d_cur, GAP_DFAC);
- if (do_gtd) {
- dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
- }
- }
-
- /* Second point */
- /* Note dt2 is always negative, which marks the gap. */
- if (tot > 1) {
- interp_v3_v3v3(p2, p3d_cur, p3d_next, -GAP_DFAC);
- if (do_gtd) {
- dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
- }
- }
- else {
- interp_v3_v3v3(p2, p3d_cur, bezt->vec[1], GAP_DFAC);
- if (do_gtd) {
- dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
- }
- }
-
- /* Second handle of last point of previous stroke. */
- interp_v3_v3v3(h2, bezt->vec[1], p1, BEZT_HANDLE_FAC);
- copy_v3_v3(bezt->vec[2], h2);
-
- /* First point */
- interp_v3_v3v3(h1, p1, bezt->vec[1], BEZT_HANDLE_FAC);
- interp_v3_v3v3(h2, p1, p2, BEZT_HANDLE_FAC);
- bezt++;
- gp_stroke_to_bezier_add_point(gtd, bezt, p1, h1, h2, (bezt - 1)->vec[1], do_gtd, gps->prev->inittime, dt1,
- 0.0f, rad_fac, minmax_weights);
-
- /* Second point */
- interp_v3_v3v3(h1, p2, p1, BEZT_HANDLE_FAC);
- interp_v3_v3v3(h2, p2, p3d_cur, BEZT_HANDLE_FAC);
- bezt++;
- gp_stroke_to_bezier_add_point(gtd, bezt, p2, h1, h2, p1, do_gtd, gps->inittime, dt2,
- 0.0f, rad_fac, minmax_weights);
-
- old_nbezt += 2;
- copy_v3_v3(p3d_prev, p2);
- }
- }
- else if (add_start_point) {
- float p[3];
- float dt = 0.0f;
-
- if (gps->totpoints > 1) {
- interp_v3_v3v3(p, p3d_cur, p3d_next, -GAP_DFAC);
- if (do_gtd) {
- dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
- }
- }
- else {
- copy_v3_v3(p, p3d_cur);
- p[0] -= GAP_DFAC; /* Rather arbitrary... */
- dt = -GAP_DFAC; /* Rather arbitrary too! */
- }
- interp_v3_v3v3(h1, p, p3d_cur, -BEZT_HANDLE_FAC);
- interp_v3_v3v3(h2, p, p3d_cur, BEZT_HANDLE_FAC);
- bezt = &nu->bezt[old_nbezt];
- gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, p, do_gtd, gps->inittime, dt,
- 0.0f, rad_fac, minmax_weights);
-
- old_nbezt++;
- copy_v3_v3(p3d_prev, p);
- }
-
- if (old_nbezt) {
- prev_bezt = &nu->bezt[old_nbezt - 1];
- }
-
- /* add points */
- for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) {
- float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC;
-
- if (i || old_nbezt) {
- interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC);
- }
- else {
- interp_v3_v3v3(h1, p3d_cur, p3d_next, -BEZT_HANDLE_FAC);
- }
-
- if (i < tot - 1) {
- interp_v3_v3v3(h2, p3d_cur, p3d_next, BEZT_HANDLE_FAC);
- }
- else {
- interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC);
- }
-
- gp_stroke_to_bezier_add_point(gtd, bezt, p3d_cur, h1, h2, prev_bezt ? prev_bezt->vec[1] : p3d_cur,
- do_gtd, gps->inittime, pt->time, width, rad_fac, minmax_weights);
-
- /* shift coord vects */
- copy_v3_v3(p3d_prev, p3d_cur);
- copy_v3_v3(p3d_cur, p3d_next);
-
- if (i + 2 < tot) {
- gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect);
- }
-
- prev_bezt = bezt;
- }
-
- if (add_end_point) {
- float p[3];
- float dt = 0.0f;
-
- if (gps->totpoints > 1) {
- interp_v3_v3v3(p, prev_bezt->vec[1], (prev_bezt - 1)->vec[1], -GAP_DFAC);
- if (do_gtd) {
- const int idx = gps->totpoints - 1;
- dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
- }
- }
- else {
- copy_v3_v3(p, prev_bezt->vec[1]);
- p[0] += GAP_DFAC; /* Rather arbitrary... */
- dt = GAP_DFAC; /* Rather arbitrary too! */
- }
-
- /* Second handle of last point of this stroke. */
- interp_v3_v3v3(h2, prev_bezt->vec[1], p, BEZT_HANDLE_FAC);
- copy_v3_v3(prev_bezt->vec[2], h2);
-
- /* The end point */
- interp_v3_v3v3(h1, p, prev_bezt->vec[1], BEZT_HANDLE_FAC);
- interp_v3_v3v3(h2, p, prev_bezt->vec[1], -BEZT_HANDLE_FAC);
- /* Note bezt has already been incremented in main loop above, so it points to the right place. */
- gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, prev_bezt->vec[1], do_gtd, gps->inittime, dt,
- 0.0f, rad_fac, minmax_weights);
- }
-
- /* must calculate handles or else we crash */
- BKE_nurb_handles_calc(nu);
-
- if (!curnu || !*curnu) {
- BLI_addtail(&cu->nurb, nu);
- }
- if (curnu) {
- *curnu = nu;
- }
-}
-
-#undef GAP_DFAC
-#undef WIDTH_CORR_FAC
-#undef BEZT_HANDLE_FAC
-
-static void gp_stroke_finalize_curve_endpoints(Curve *cu)
-{
- /* start */
- Nurb *nu = cu->nurb.first;
- int i = 0;
- if (nu->bezt) {
- BezTriple *bezt = nu->bezt;
- if (bezt) {
- bezt[i].weight = bezt[i].radius = 0.0f;
- }
- }
- else if (nu->bp) {
- BPoint *bp = nu->bp;
- if (bp) {
- bp[i].weight = bp[i].radius = 0.0f;
- }
- }
-
- /* end */
- nu = cu->nurb.last;
- i = nu->pntsu - 1;
- if (nu->bezt) {
- BezTriple *bezt = nu->bezt;
- if (bezt) {
- bezt[i].weight = bezt[i].radius = 0.0f;
- }
- }
- else if (nu->bp) {
- BPoint *bp = nu->bp;
- if (bp) {
- bp[i].weight = bp[i].radius = 0.0f;
- }
- }
-}
-
-static void gp_stroke_norm_curve_weights(Curve *cu, const float minmax_weights[2])
-{
- Nurb *nu;
- const float delta = minmax_weights[0];
- float fac;
- int i;
-
- /* when delta == minmax_weights[0] == minmax_weights[1], we get div by zero [#35686] */
- if (IS_EQF(delta, minmax_weights[1]))
- fac = 1.0f;
- else
- fac = 1.0f / (minmax_weights[1] - delta);
-
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu->bezt) {
- BezTriple *bezt = nu->bezt;
- for (i = 0; i < nu->pntsu; i++, bezt++) {
- bezt->weight = (bezt->weight - delta) * fac;
- }
- }
- else if (nu->bp) {
- BPoint *bp = nu->bp;
- for (i = 0; i < nu->pntsu; i++, bp++) {
- bp->weight = (bp->weight - delta) * fac;
- }
- }
- }
-}
-
-static int gp_camera_view_subrect(bContext *C, rctf *subrect)
-{
- View3D *v3d = CTX_wm_view3d(C);
- ARegion *ar = CTX_wm_region(C);
-
- if (v3d) {
- RegionView3D *rv3d = ar->regiondata;
-
- /* for camera view set the subrect */
- if (rv3d->persp == RV3D_CAMOB) {
- Scene *scene = CTX_data_scene(C);
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, subrect, true); /* no shift */
- return 1;
- }
- }
-
- return 0;
-}
-
-/* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */
-static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bGPDlayer *gpl, const int mode,
- const bool norm_weights, const float rad_fac, const bool link_strokes, tGpTimingData *gtd)
-{
- struct Main *bmain = CTX_data_main(C);
- View3D *v3d = CTX_wm_view3d(C); /* may be NULL */
- Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
- bGPDstroke *gps, *prev_gps = NULL;
- Object *ob;
- Curve *cu;
- Nurb *nu = NULL;
- Base *base_orig = BASACT, *base_new = NULL;
- float minmax_weights[2] = {1.0f, 0.0f};
-
- /* camera framing */
- rctf subrect, *subrect_ptr = NULL;
-
- /* error checking */
- if (ELEM(NULL, gpd, gpl, gpf))
- return;
-
- /* only convert if there are any strokes on this layer's frame to convert */
- if (BLI_listbase_is_empty(&gpf->strokes))
- return;
-
- /* initialize camera framing */
- if (gp_camera_view_subrect(C, &subrect)) {
- subrect_ptr = &subrect;
- }
-
- /* init the curve object (remove rotation and get curve data from it)
- * - must clear transforms set on object, as those skew our results
- */
- ob = BKE_object_add_only_object(bmain, OB_CURVE, gpl->info);
- cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVE);
- base_new = BKE_scene_base_add(scene, ob);
-
- cu->flag |= CU_3D;
-
- gtd->inittime = ((bGPDstroke *)gpf->strokes.first)->inittime;
-
- /* add points to curve */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- const bool add_start_point = (link_strokes && !(prev_gps));
- const bool add_end_point = (link_strokes && !(gps->next));
-
- /* Detect new strokes created because of GP_STROKE_BUFFER_MAX reached, and stitch them to previous one. */
- bool stitch = false;
- if (prev_gps) {
- bGPDspoint *pt1 = &prev_gps->points[prev_gps->totpoints - 1];
- bGPDspoint *pt2 = &gps->points[0];
-
- if ((pt1->x == pt2->x) && (pt1->y == pt2->y)) {
- stitch = true;
- }
- }
-
- /* Decide whether we connect this stroke to previous one */
- if (!(stitch || link_strokes)) {
- nu = NULL;
- }
-
- switch (mode) {
- case GP_STROKECONVERT_PATH:
- gp_stroke_to_path(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
- add_start_point, add_end_point, gtd);
- break;
- case GP_STROKECONVERT_CURVE:
- case GP_STROKECONVERT_POLY: /* convert after */
- gp_stroke_to_bezier(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
- add_start_point, add_end_point, gtd);
- break;
- default:
- BLI_assert(!"invalid mode");
- break;
- }
- prev_gps = gps;
- }
-
- /* If link_strokes, be sure first and last points have a zero weight/size! */
- if (link_strokes) {
- gp_stroke_finalize_curve_endpoints(cu);
- }
-
- /* Update curve's weights, if needed */
- if (norm_weights && ((minmax_weights[0] > 0.0f) || (minmax_weights[1] < 1.0f))) {
- gp_stroke_norm_curve_weights(cu, minmax_weights);
- }
-
- /* Create the path animation, if needed */
- gp_stroke_path_animation(C, reports, cu, gtd);
-
- if (mode == GP_STROKECONVERT_POLY) {
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- BKE_nurb_type_convert(nu, CU_POLY, false);
- }
- }
-
- /* set the layer and select */
- base_new->lay = ob->lay = base_orig ? base_orig->lay : BKE_screen_view3d_layer_active(v3d, scene);
- base_new->flag = ob->flag = base_new->flag | SELECT;
-}
-
-/* --- */
-
-/* Check a GP layer has valid timing data! Else, most timing options are hidden in the operator.
- * op may be NULL.
- */
-static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = NULL;
- bGPDstroke *gps = NULL;
- bGPDspoint *pt;
- double base_time, cur_time, prev_time = -1.0;
- int i;
- bool valid = true;
-
- if (!gpl || !(gpf = gpencil_layer_getframe(gpl, CFRA, 0)) || !(gps = gpf->strokes.first))
- return false;
-
- do {
- base_time = cur_time = gps->inittime;
- if (cur_time <= prev_time) {
- valid = false;
- break;
- }
-
- prev_time = cur_time;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- cur_time = base_time + (double)pt->time;
- /* First point of a stroke should have the same time as stroke's inittime,
- * so it's the only case where equality is allowed!
- */
- if ((i && cur_time <= prev_time) || (cur_time < prev_time)) {
- valid = false;
- break;
- }
- prev_time = cur_time;
- }
-
- if (!valid) {
- break;
- }
- } while ((gps = gps->next));
-
- if (op) {
- RNA_boolean_set(op->ptr, "use_timing_data", valid);
- }
- return valid;
-}
-
-/* Check end_frame is always > start frame! */
-static void gp_convert_set_end_frame(struct Main *UNUSED(main), struct Scene *UNUSED(scene), struct PointerRNA *ptr)
-{
- int start_frame = RNA_int_get(ptr, "start_frame");
- int end_frame = RNA_int_get(ptr, "end_frame");
-
- if (end_frame <= start_frame) {
- RNA_int_set(ptr, "end_frame", start_frame + 1);
- }
-}
-
-static int gp_convert_poll(bContext *C)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = NULL;
- bGPDframe *gpf = NULL;
- ScrArea *sa = CTX_wm_area(C);
- Scene *scene = CTX_data_scene(C);
-
- /* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!),
- * and if we are not in edit mode!
- */
- return ((sa && sa->spacetype == SPACE_VIEW3D) &&
- (gpl = gpencil_layer_getactive(gpd)) &&
- (gpf = gpencil_layer_getframe(gpl, CFRA, 0)) &&
- (gpf->strokes.first) &&
- (scene->obedit == NULL));
-}
-
-static int gp_convert_layer_exec(bContext *C, wmOperator *op)
-{
- PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_timing_data");
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
- Scene *scene = CTX_data_scene(C);
- const int mode = RNA_enum_get(op->ptr, "type");
- const bool norm_weights = RNA_boolean_get(op->ptr, "use_normalize_weights");
- const float rad_fac = RNA_float_get(op->ptr, "radius_multiplier");
- const bool link_strokes = RNA_boolean_get(op->ptr, "use_link_strokes");
- bool valid_timing;
- tGpTimingData gtd;
-
- /* check if there's data to work with */
- if (gpd == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data to work on");
- return OPERATOR_CANCELLED;
- }
-
- if (!RNA_property_is_set(op->ptr, prop) && !gp_convert_check_has_valid_timing(C, gpl, op)) {
- BKE_report(op->reports, RPT_WARNING,
- "Current Grease Pencil strokes have no valid timing data, most timing options will be hidden!");
- }
- valid_timing = RNA_property_boolean_get(op->ptr, prop);
-
- gtd.mode = RNA_enum_get(op->ptr, "timing_mode");
- /* Check for illegal timing mode! */
- if (!valid_timing && !ELEM(gtd.mode, GP_STROKECONVERT_TIMING_NONE, GP_STROKECONVERT_TIMING_LINEAR)) {
- gtd.mode = GP_STROKECONVERT_TIMING_LINEAR;
- RNA_enum_set(op->ptr, "timing_mode", gtd.mode);
- }
- if (!link_strokes) {
- gtd.mode = GP_STROKECONVERT_TIMING_NONE;
- }
-
- /* grab all relevant settings */
- gtd.frame_range = RNA_int_get(op->ptr, "frame_range");
- gtd.start_frame = RNA_int_get(op->ptr, "start_frame");
- gtd.realtime = valid_timing ? RNA_boolean_get(op->ptr, "use_realtime") : false;
- gtd.end_frame = RNA_int_get(op->ptr, "end_frame");
- gtd.gap_duration = RNA_float_get(op->ptr, "gap_duration");
- gtd.gap_randomness = RNA_float_get(op->ptr, "gap_randomness");
- gtd.gap_randomness = min_ff(gtd.gap_randomness, gtd.gap_duration);
- gtd.seed = RNA_int_get(op->ptr, "seed");
- gtd.num_points = gtd.cur_point = 0;
- gtd.dists = gtd.times = NULL;
- gtd.tot_dist = gtd.tot_time = gtd.gap_tot_time = 0.0f;
- gtd.inittime = 0.0;
- gtd.offset_time = 0.0f;
-
- /* perform conversion */
- gp_layer_to_curve(C, op->reports, gpd, gpl, mode, norm_weights, rad_fac, link_strokes, &gtd);
-
- /* free temp memory */
- if (gtd.dists) {
- MEM_freeN(gtd.dists);
- gtd.dists = NULL;
- }
- if (gtd.times) {
- MEM_freeN(gtd.times);
- gtd.times = NULL;
- }
-
- /* notifiers */
- WM_event_add_notifier(C, NC_OBJECT | NA_ADDED, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
-
- /* done */
- return OPERATOR_FINISHED;
-}
-
-static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
-{
- const char *prop_id = RNA_property_identifier(prop);
- const bool link_strokes = RNA_boolean_get(ptr, "use_link_strokes");
- int timing_mode = RNA_enum_get(ptr, "timing_mode");
- bool realtime = RNA_boolean_get(ptr, "use_realtime");
- float gap_duration = RNA_float_get(ptr, "gap_duration");
- float gap_randomness = RNA_float_get(ptr, "gap_randomness");
- const bool valid_timing = RNA_boolean_get(ptr, "use_timing_data");
-
- /* Always show those props */
- if (STREQ(prop_id, "type") ||
- STREQ(prop_id, "use_normalize_weights") ||
- STREQ(prop_id, "radius_multiplier") ||
- STREQ(prop_id, "use_link_strokes"))
- {
- return true;
- }
-
- /* Never show this prop */
- if (STREQ(prop_id, "use_timing_data"))
- return false;
-
- if (link_strokes) {
- /* Only show when link_stroke is true */
- if (STREQ(prop_id, "timing_mode"))
- return true;
-
- if (timing_mode != GP_STROKECONVERT_TIMING_NONE) {
- /* Only show when link_stroke is true and stroke timing is enabled */
- if (STREQ(prop_id, "frame_range") ||
- STREQ(prop_id, "start_frame"))
- {
- return true;
- }
-
- /* Only show if we have valid timing data! */
- if (valid_timing && STREQ(prop_id, "use_realtime"))
- return true;
-
- /* Only show if realtime or valid_timing is false! */
- if ((!realtime || !valid_timing) && STREQ(prop_id, "end_frame"))
- return true;
-
- if (valid_timing && timing_mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
- /* Only show for custom gaps! */
- if (STREQ(prop_id, "gap_duration"))
- return true;
-
- /* Only show randomness for non-null custom gaps! */
- if (STREQ(prop_id, "gap_randomness") && (gap_duration > 0.0f))
- return true;
-
- /* Only show seed for randomize action! */
- if (STREQ(prop_id, "seed") && (gap_duration > 0.0f) && (gap_randomness > 0.0f))
- return true;
- }
- }
- }
-
- /* Else, hidden! */
- return false;
-}
-
-static void gp_convert_ui(bContext *C, wmOperator *op)
-{
- uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- /* Main auto-draw call */
- uiDefAutoButsRNA(layout, &ptr, gp_convert_draw_check_prop, '\0');
-}
-
-void GPENCIL_OT_convert(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Convert Grease Pencil";
- ot->idname = "GPENCIL_OT_convert";
- ot->description = "Convert the active Grease Pencil layer to a new Curve Object";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = gp_convert_layer_exec;
- ot->poll = gp_convert_poll;
- ot->ui = gp_convert_ui;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_convertmodes, 0, "Type", "Which type of curve to convert to");
-
- RNA_def_boolean(ot->srna, "use_normalize_weights", true, "Normalize Weight",
- "Normalize weight (set from stroke width)");
- RNA_def_float(ot->srna, "radius_multiplier", 1.0f, 0.0f, 1000.0f, "Radius Fac",
- "Multiplier for the points' radii (set from stroke width)", 0.0f, 10.0f);
- RNA_def_boolean(ot->srna, "use_link_strokes", true, "Link Strokes",
- "Whether to link strokes with zero-radius sections of curves");
-
- prop = RNA_def_enum(ot->srna, "timing_mode", prop_gpencil_convert_timingmodes, GP_STROKECONVERT_TIMING_FULL,
- "Timing Mode", "How to use timing data stored in strokes");
- RNA_def_enum_funcs(prop, rna_GPConvert_mode_items);
-
- RNA_def_int(ot->srna, "frame_range", 100, 1, 10000, "Frame Range",
- "The duration of evaluation of the path control curve", 1, 1000);
- RNA_def_int(ot->srna, "start_frame", 1, 1, 100000, "Start Frame",
- "The start frame of the path control curve", 1, 100000);
- RNA_def_boolean(ot->srna, "use_realtime", false, "Realtime",
- "Whether the path control curve reproduces the drawing in realtime, starting from Start Frame");
- prop = RNA_def_int(ot->srna, "end_frame", 250, 1, 100000, "End Frame",
- "The end frame of the path control curve (if Realtime is not set)", 1, 100000);
- RNA_def_property_update_runtime(prop, gp_convert_set_end_frame);
-
- RNA_def_float(ot->srna, "gap_duration", 0.0f, 0.0f, 10000.0f, "Gap Duration",
- "Custom Gap mode: (Average) length of gaps, in frames "
- "(Note: Realtime value, will be scaled if Realtime is not set)", 0.0f, 1000.0f);
- RNA_def_float(ot->srna, "gap_randomness", 0.0f, 0.0f, 10000.0f, "Gap Randomness",
- "Custom Gap mode: Number of frames that gap lengths can vary", 0.0f, 1000.0f);
- RNA_def_int(ot->srna, "seed", 0, 0, 1000, "Random Seed",
- "Custom Gap mode: Random generator seed", 0, 100);
-
- /* Note: Internal use, this one will always be hidden by UI code... */
- prop = RNA_def_boolean(ot->srna, "use_timing_data", false, "Has Valid Timing",
- "Whether the converted Grease Pencil layer has valid timing data (internal use)");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-}
-
-/* ************************************************ */
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 56420434494..72cd9022d69 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -96,6 +96,12 @@ void gp_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc);
void gp_point_to_xy(GP_SpaceConversion *settings, struct bGPDstroke *gps, struct bGPDspoint *pt,
int *r_x, int *r_y);
+/* Poll Callbacks ------------------------------------ */
+/* gpencil_utils.c */
+
+int gp_add_poll(struct bContext *C);
+int gp_active_layer_poll(struct bContext *C);
+
/* ***************************************************** */
/* Operator Defines */
@@ -138,6 +144,9 @@ void GPENCIL_OT_layer_remove(struct wmOperatorType *ot);
void GPENCIL_OT_layer_move(struct wmOperatorType *ot);
void GPENCIL_OT_layer_duplicate(struct wmOperatorType *ot);
+void GPENCIL_OT_hide(struct wmOperatorType *ot);
+void GPENCIL_OT_reveal(struct wmOperatorType *ot);
+
void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
void GPENCIL_OT_convert(struct wmOperatorType *ot);
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 3fae208a2e2..4752f3dbb36 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -34,8 +34,6 @@
#include "BLI_sys_types.h"
-#include "BLI_blenlib.h"
-
#include "BKE_context.h"
#include "DNA_gpencil_types.h"
@@ -183,7 +181,18 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
#ifdef __APPLE__
WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
WM_keymap_add_item(keymap, "GPENCIL_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
-#endif
+#endif
+
+ /* Show/Hide */
+ /* NOTE: These are available only in EditMode now, since they clash with general-purpose hotkeys */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_hide", HKEY, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "unselected", false);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "unselected", true);
+
/* Transform Tools */
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0);
@@ -262,6 +271,9 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_layer_move);
WM_operatortype_append(GPENCIL_OT_layer_duplicate);
+ WM_operatortype_append(GPENCIL_OT_hide);
+ WM_operatortype_append(GPENCIL_OT_reveal);
+
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
WM_operatortype_append(GPENCIL_OT_convert);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 38a7ffaca86..f3eb1612576 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -48,6 +48,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_report.h"
+#include "BKE_screen.h"
#include "BKE_tracking.h"
#include "DNA_object_types.h"
@@ -1030,6 +1031,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
/* set current area
* - must verify that region data is 3D-view (and not something else)
*/
+ /* CAUTION: If this is the "toolbar", then this will change on the first stroke */
p->sa = curarea;
p->ar = ar;
@@ -1252,6 +1254,7 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode)
/* when drawing in the camera view, in 2D space, set the subrect */
+ p->subrect = NULL;
if (!(p->gpd->flag & GP_DATA_VIEWALIGN)) {
if (p->sa->spacetype == SPACE_VIEW3D) {
View3D *v3d = p->sa->spacedata.first;
@@ -1437,12 +1440,14 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
if (p->paintmode == GP_PAINTMODE_ERASER) {
/* turn off radial brush cursor */
gpencil_draw_toggle_eraser_cursor(C, p, false);
-
- /* if successful, store the new eraser size to be used again next time */
- if (p->status == GP_STATUS_DONE)
- U.gp_eraser = p->radius;
}
+ /* always store the new eraser size to be used again next time
+ * NOTE: Do this even when not in eraser mode, as eraser may
+ * have been toggled at some point.
+ */
+ U.gp_eraser = p->radius;
+
/* cleanup */
gp_paint_cleanup(p);
gp_session_cleanup(p);
@@ -1493,6 +1498,15 @@ static int gpencil_draw_init(bContext *C, wmOperator *op)
/* ------------------------------- */
+/* ensure that the correct cursor icon is set */
+static void gpencil_draw_cursor_set(tGPsdata *p)
+{
+ if (p->paintmode == GP_PAINTMODE_ERASER)
+ WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
+ else
+ WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR);
+}
+
/* update UI indicators of status, including cursor and header prints */
static void gpencil_draw_status_indicators(tGPsdata *p)
{
@@ -1608,7 +1622,7 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
/* handle pressure sensitivity (which is supplied by tablets) */
if (event->tablet_data) {
- wmTabletData *wmtab = event->tablet_data;
+ const wmTabletData *wmtab = event->tablet_data;
tablet = (wmtab->Active != EVT_TABLET_NONE);
p->pressure = wmtab->Pressure;
@@ -1733,7 +1747,6 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
tGPsdata *p = NULL;
- wmWindow *win = CTX_wm_window(C);
if (G.debug & G_DEBUG)
printf("GPencil - Starting Drawing\n");
@@ -1759,11 +1772,11 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
gpencil_draw_toggle_eraser_cursor(C, p, true);
}
- /* set cursor */
- if (p->paintmode == GP_PAINTMODE_ERASER)
- WM_cursor_modal_set(win, BC_CROSSCURSOR); /* XXX need a better cursor */
- else
- WM_cursor_modal_set(win, BC_PAINTBRUSHCURSOR);
+ /* set cursor
+ * NOTE: This may change later (i.e. intentionally via brush toggle,
+ * or unintentionally if the user scrolls outside the area)...
+ */
+ gpencil_draw_cursor_set(p);
/* only start drawing immediately if we're allowed to do so... */
if (RNA_boolean_get(op->ptr, "wait_for_input") == false) {
@@ -1777,6 +1790,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
else {
/* toolbar invoked - don't start drawing yet... */
/* printf("\tGP - hotkey invoked... waiting for click-drag\n"); */
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
@@ -1814,8 +1828,10 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
if (gp_session_initdata(C, p))
gp_paint_initstroke(p, p->paintmode);
- if (p->status != GP_STATUS_ERROR)
+ if (p->status != GP_STATUS_ERROR) {
p->status = GP_STATUS_PAINTING;
+ op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
+ }
return op->customdata;
}
@@ -1831,6 +1847,7 @@ static void gpencil_stroke_end(wmOperator *op)
gp_session_cleanup(p);
p->status = GP_STATUS_IDLING;
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
p->gpd = NULL;
p->gpl = NULL;
@@ -1856,6 +1873,11 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* in 3D space.
*/
+ if (p->status == GP_STATUS_IDLING) {
+ ARegion *ar = CTX_wm_region(C);
+ p->ar = ar;
+ }
+
/* we don't pass on key events, GP is used with key-modifiers - prevents Dkey to insert drivers */
if (ISKEYBOARD(event->type)) {
if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY, ZKEY)) {
@@ -1885,8 +1907,9 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only)
* - RIGHTMOUSE = polyline (hotkey) / eraser (all)
* (Disabling RIGHTMOUSE case here results in bugs like [#32647])
+ * also making sure we have a valid event value, to not exit too early
*/
- if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE)) {
+ if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && (event->val != KM_NOTHING)) {
/* if painting, end stroke */
if (p->status == GP_STATUS_PAINTING) {
int sketch = 0;
@@ -1937,32 +1960,88 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else if (event->val == KM_PRESS) {
- /* Switch paintmode (temporarily if need be) based on which button was used
- * NOTE: This is to make it more convenient to erase strokes when using drawing sessions
+ bool in_bounds = false;
+
+ /* Check if we're outside the bounds of the active region
+ * NOTE: An exception here is that if launched from the toolbar,
+ * whatever region we're now in should become the new region
*/
- if (event->type == LEFTMOUSE) {
- /* restore drawmode to default */
- // XXX: no need for this... this should just revert by itself
- if (p->paintmode == GP_PAINTMODE_ERASER)
- gpencil_draw_toggle_eraser_cursor(C, p, false);
+ if ((p->ar) && (p->ar->regiontype == RGN_TYPE_TOOLS)) {
+ /* Change to whatever region is now under the mouse */
+ ARegion *current_region = BKE_area_find_region_xy(p->sa, RGN_TYPE_ANY, event->x, event->y);
+
+ if (G.debug & G_DEBUG) {
+ printf("found alternative region %p (old was %p) - at %d %d (sa: %d %d -> %d %d)\n",
+ current_region, p->ar, event->x, event->y,
+ p->sa->totrct.xmin, p->sa->totrct.ymin, p->sa->totrct.xmax, p->sa->totrct.ymax);
+ }
+
+ if (current_region) {
+ /* Assume that since we found the cursor in here, it is in bounds
+ * and that this should be the region that we begin drawing in
+ */
+ p->ar = current_region;
+ in_bounds = true;
+ }
+ else {
+ /* Out of bounds, or invalid in some other way */
+ p->status = GP_STATUS_ERROR;
+ estate = OPERATOR_CANCELLED;
- p->paintmode = RNA_enum_get(op->ptr, "mode");
+ if (G.debug & G_DEBUG)
+ printf("%s: Region under cursor is out of bounds, so cannot be drawn on\n", __func__);
+ }
+ }
+ else if (p->ar) {
+ rcti region_rect;
+
+ /* Perform bounds check using */
+ ED_region_visible_rect(p->ar, &region_rect);
+ in_bounds = BLI_rcti_isect_pt_v(&region_rect, event->mval);
}
- else if (event->type == RIGHTMOUSE) {
- /* turn on eraser */
- p->paintmode = GP_PAINTMODE_ERASER;
- gpencil_draw_toggle_eraser_cursor(C, p, true);
+ else {
+ /* No region */
+ p->status = GP_STATUS_ERROR;
+ estate = OPERATOR_CANCELLED;
+
+ if (G.debug & G_DEBUG)
+ printf("%s: No active region found in GP Paint session data\n", __func__);
}
- /* not painting, so start stroke (this should be mouse-button down) */
- p = gpencil_stroke_begin(C, op);
-
- if (p->status == GP_STATUS_ERROR) {
- estate = OPERATOR_CANCELLED;
+ if (in_bounds) {
+ /* Switch paintmode (temporarily if need be) based on which button was used
+ * NOTE: This is to make it more convenient to erase strokes when using drawing sessions
+ */
+ if (event->type == LEFTMOUSE) {
+ /* restore drawmode to default */
+ p->paintmode = RNA_enum_get(op->ptr, "mode");
+ }
+ else if (event->type == RIGHTMOUSE) {
+ /* turn on eraser */
+ p->paintmode = GP_PAINTMODE_ERASER;
+ }
+
+ gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER);
+
+ /* not painting, so start stroke (this should be mouse-button down) */
+ p = gpencil_stroke_begin(C, op);
+
+ if (p->status == GP_STATUS_ERROR) {
+ estate = OPERATOR_CANCELLED;
+ }
+ }
+ else if (p->status != GP_STATUS_ERROR) {
+ /* User clicked outside bounds of window while idling, so exit paintmode
+ * NOTE: Don't eter this case if an error occurred while finding the
+ * region (as above)
+ */
+ p->status = GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
}
}
else {
p->status = GP_STATUS_IDLING;
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
}
@@ -2026,9 +2105,11 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
if (0 == gpencil_area_exists(C, p->sa))
estate = OPERATOR_CANCELLED;
- else
+ else {
/* update status indicators - cursor, header, etc. */
gpencil_draw_status_indicators(p);
+ gpencil_draw_cursor_set(p); /* cursor may have changed outside our control - T44084 */
+ }
/* process last operations before exiting */
switch (estate) {
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 9ba77a4244e..1b66f366b70 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -35,28 +35,16 @@
#include "MEM_guardedalloc.h"
-#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_lasso.h"
#include "BLI_utildefines.h"
#include "DNA_gpencil_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
-#include "DNA_view3d_types.h"
#include "BKE_context.h"
-#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
-#include "BKE_global.h"
#include "BKE_gpencil.h"
-#include "BKE_library.h"
-#include "BKE_object.h"
#include "BKE_report.h"
-#include "BKE_scene.h"
-#include "BKE_screen.h"
#include "UI_interface.h"
@@ -69,8 +57,6 @@
#include "UI_view2d.h"
#include "ED_gpencil.h"
-#include "ED_view3d.h"
-#include "ED_keyframing.h"
#include "gpencil_intern.h"
@@ -789,6 +775,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
bGPDstroke *hit_stroke = NULL;
bGPDspoint *hit_point = NULL;
+ int hit_distance = radius_squared;
/* sanity checks */
if (sa == NULL) {
@@ -811,7 +798,6 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
{
bGPDspoint *pt;
int i;
- int hit_index = -1;
/* firstly, check for hit-point */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
@@ -821,18 +807,19 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* do boundbox check first */
if (!ELEM(V2D_IS_CLIPPED, x0, x0)) {
- /* only check if point is inside */
- if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius_squared) {
- hit_stroke = gps;
- hit_point = pt;
- break;
+ const int pt_distance = ((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my));
+
+ /* check if point is inside */
+ if (pt_distance <= radius_squared) {
+ /* only use this point if it is a better match than the current hit - T44685 */
+ if (pt_distance < hit_distance) {
+ hit_stroke = gps;
+ hit_point = pt;
+ hit_distance = pt_distance;
+ }
}
}
}
-
- /* skip to next stroke if nothing found */
- if (hit_index == -1)
- continue;
}
CTX_DATA_END;
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 289cbc568d2..0d7aac7f48f 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -32,8 +32,6 @@
#include <stddef.h>
#include <math.h>
-#include "MEM_guardedalloc.h"
-
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -46,18 +44,10 @@
#include "DNA_view3d_types.h"
#include "BKE_context.h"
-#include "BKE_global.h"
#include "BKE_gpencil.h"
-#include "BKE_library.h"
-#include "BKE_object.h"
-#include "BKE_report.h"
-#include "BKE_scene.h"
-#include "BKE_screen.h"
-
-#include "UI_interface.h"
+#include "BKE_tracking.h"
#include "WM_api.h"
-#include "WM_types.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -65,11 +55,183 @@
#include "UI_view2d.h"
#include "ED_gpencil.h"
+#include "ED_clip.h"
#include "ED_view3d.h"
#include "gpencil_intern.h"
/* ******************************************************** */
+/* Context Wrangling... */
+
+/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it,
+ * when context info is not available.
+ */
+bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob, PointerRNA *ptr)
+{
+ /* if there's an active area, check if the particular editor may
+ * have defined any special Grease Pencil context for editing...
+ */
+ if (sa) {
+ SpaceLink *sl = sa->spacedata.first;
+
+ switch (sa->spacetype) {
+ case SPACE_VIEW3D: /* 3D-View */
+ case SPACE_TIME: /* Timeline - XXX: this is a hack to get it to show GP keyframes for 3D view */
+ case SPACE_ACTION: /* DepeSheet - XXX: this is a hack to get the keyframe jump operator to take GP Keyframes into account */
+ {
+ BLI_assert(scene && ELEM(scene->toolsettings->gpencil_src,
+ GP_TOOL_SOURCE_SCENE, GP_TOOL_SOURCE_OBJECT));
+
+ if (scene->toolsettings->gpencil_src == GP_TOOL_SOURCE_OBJECT) {
+ /* legacy behaviour for usage with old addons requiring object-linked to objects */
+
+ /* just in case no active/selected object... */
+ if (ob && (ob->flag & SELECT)) {
+ /* for now, as long as there's an object, default to using that in 3D-View */
+ if (ptr) RNA_id_pointer_create(&ob->id, ptr);
+ return &ob->gpd;
+ }
+ /* else: defaults to scene... */
+ }
+ else {
+ if (ptr) RNA_id_pointer_create(&scene->id, ptr);
+ return &scene->gpd;
+ }
+ break;
+ }
+ case SPACE_NODE: /* Nodes Editor */
+ {
+ SpaceNode *snode = (SpaceNode *)sl;
+
+ /* return the GP data for the active node block/node */
+ if (snode && snode->nodetree) {
+ /* for now, as long as there's an active node tree, default to using that in the Nodes Editor */
+ if (ptr) RNA_id_pointer_create(&snode->nodetree->id, ptr);
+ return &snode->nodetree->gpd;
+ }
+
+ /* even when there is no node-tree, don't allow this to flow to scene */
+ return NULL;
+ }
+ case SPACE_SEQ: /* Sequencer */
+ {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+
+ /* for now, Grease Pencil data is associated with the space (actually preview region only) */
+ /* XXX our convention for everything else is to link to data though... */
+ if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, ptr);
+ return &sseq->gpd;
+ }
+ case SPACE_IMAGE: /* Image/UV Editor */
+ {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ /* for now, Grease Pencil data is associated with the space... */
+ /* XXX our convention for everything else is to link to data though... */
+ if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, ptr);
+ return &sima->gpd;
+ }
+ case SPACE_CLIP: /* Nodes Editor */
+ {
+ SpaceClip *sc = (SpaceClip *)sl;
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+
+ if (clip) {
+ if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
+ MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
+
+ if (!track)
+ return NULL;
+
+ if (ptr)
+ RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, ptr);
+
+ return &track->gpd;
+ }
+ else {
+ if (ptr)
+ RNA_id_pointer_create(&clip->id, ptr);
+
+ return &clip->gpd;
+ }
+ }
+ break;
+ }
+ default: /* unsupported space */
+ return NULL;
+ }
+ }
+
+ /* just fall back on the scene's GP data */
+ if (ptr) RNA_id_pointer_create((ID *)scene, ptr);
+ return (scene) ? &scene->gpd : NULL;
+}
+
+/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */
+bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
+{
+ ID *screen_id = (ID *)CTX_wm_screen(C);
+ Scene *scene = CTX_data_scene(C);
+ ScrArea *sa = CTX_wm_area(C);
+ Object *ob = CTX_data_active_object(C);
+
+ return ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, ptr);
+}
+
+/* -------------------------------------------------------- */
+
+/* Get the active Grease Pencil datablock, when context is not available */
+bGPdata *ED_gpencil_data_get_active_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, NULL);
+ return (gpd_ptr) ? *(gpd_ptr) : NULL;
+}
+
+/* Get the active Grease Pencil datablock */
+bGPdata *ED_gpencil_data_get_active(const bContext *C)
+{
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+ return (gpd_ptr) ? *(gpd_ptr) : NULL;
+}
+
+/* -------------------------------------------------------- */
+
+// XXX: this should be removed... We really shouldn't duplicate logic like this!
+bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, View3D *v3d)
+{
+ Base *base = scene->basact;
+ bGPdata *gpd = NULL;
+ /* We have to make sure active object is actually visible and selected, else we must use default scene gpd,
+ * to be consistent with ED_gpencil_data_get_active's behavior.
+ */
+
+ if (base && TESTBASE(v3d, base)) {
+ gpd = base->object->gpd;
+ }
+ return gpd ? gpd : scene->gpd;
+}
+
+/* ******************************************************** */
+/* Poll Callbacks */
+
+/* poll callback for adding data/layers - special */
+int gp_add_poll(bContext *C)
+{
+ /* the base line we have is that we have somewhere to add Grease Pencil data */
+ return ED_gpencil_data_get_pointers(C, NULL) != NULL;
+}
+
+/* poll callback for checking if there is an active layer */
+int gp_active_layer_poll(bContext *C)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = gpencil_layer_getactive(gpd);
+
+ return (gpl != NULL);
+}
+
+/* ******************************************************** */
+/* Brush Tool Core */
/* Check if part of stroke occurs within last segment drawn by eraser */
bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]),
@@ -89,6 +251,7 @@ bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]),
}
/* ******************************************************** */
+/* Stroke Validity Testing */
/* Check whether given stroke can be edited given the supplied context */
// XXX: do we need additional flags for screenspace vs dataspace?
@@ -125,6 +288,7 @@ bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
}
/* ******************************************************** */
+/* Space Conversion */
/* Init handling for space-conversion function (from passed-in parameters) */
void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
diff --git a/source/blender/editors/hair/CMakeLists.txt b/source/blender/editors/hair/CMakeLists.txt
new file mode 100644
index 00000000000..2a72ebb9aa4
--- /dev/null
+++ b/source/blender/editors/hair/CMakeLists.txt
@@ -0,0 +1,56 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ ../include
+ ../sculpt_paint
+ ../../blenfont
+ ../../blenkernel
+ ../../blenlib
+ ../../bmesh
+ ../../gpu
+ ../../makesdna
+ ../../makesrna
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
+)
+
+set(INC_SYS
+ ${GLEW_INCLUDE_PATH}
+)
+
+set(SRC
+ hair_cursor.c
+ hair_edit.c
+ hair_mirror.c
+ hair_object_cachelib.c
+ hair_object_particles.c
+ hair_ops.c
+ hair_select.c
+ hair_stroke.c
+ hair_undo.c
+
+ hair_intern.h
+)
+
+add_definitions(${GL_DEFINITIONS})
+
+blender_add_lib(bf_editor_hair "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/hair/SConscript b/source/blender/editors/hair/SConscript
new file mode 100644
index 00000000000..d34bb48218d
--- /dev/null
+++ b/source/blender/editors/hair/SConscript
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+#
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Nathan Letwory.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+Import ('env')
+
+sources = env.Glob('*.c')
+
+incs = [
+ '#/intern/guardedalloc',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
+ '../include',
+ '../sculpt_paint',
+ '../../blenfont',
+ '../../blenkernel',
+ '../../blenlib',
+ '../../bmesh',
+ '../../gpu',
+ '../../makesdna',
+ '../../makesrna',
+ '../../windowmanager',
+ ]
+incs = ' '.join(incs)
+
+defs = ['BF_GL_DEFINITIONS']
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
+ incs += ' ' + env['BF_PTHREADS_INC']
+
+env.BlenderLib ( 'bf_editors_hair', sources, Split(incs), defs, libtype=['core'], priority=[344] )
diff --git a/source/blender/editors/hair/hair_cursor.c b/source/blender/editors/hair/hair_cursor.c
new file mode 100644
index 00000000000..dadd0cf114e
--- /dev/null
+++ b/source/blender/editors/hair/hair_cursor.c
@@ -0,0 +1,109 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/hair/hair_cursor.c
+ * \ingroup edhair
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "ED_view3d.h"
+
+#include "hair_intern.h"
+
+static void hair_draw_cursor(bContext *C, int x, int y, void *UNUSED(customdata))
+{
+ Scene *scene = CTX_data_scene(C);
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+ Brush *brush = settings->brush;
+
+ float final_radius;
+ float translation[2];
+ float outline_alpha, *outline_col;
+
+ if (!brush)
+ return;
+
+ final_radius = BKE_brush_size_get(scene, brush);
+
+ /* set various defaults */
+ translation[0] = x;
+ translation[1] = y;
+ outline_alpha = 0.5;
+ outline_col = brush->add_col;
+
+ /* make lines pretty */
+ glEnable(GL_BLEND);
+ glEnable(GL_LINE_SMOOTH);
+
+ /* set brush color */
+ glColor4f(outline_col[0], outline_col[1], outline_col[2], outline_alpha);
+
+ /* draw brush outline */
+ glTranslatef(translation[0], translation[1], 0);
+
+ /* draw an inner brush */
+ if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
+ /* inner at full alpha */
+ glutil_draw_lined_arc(0.0, M_PI*2.0f, final_radius * ups->size_pressure_value, 40);
+ /* outer at half alpha */
+ glColor4f(outline_col[0], outline_col[1], outline_col[2], outline_alpha * 0.5f);
+ }
+ glutil_draw_lined_arc(0.0, M_PI*2.0f, final_radius, 40);
+ glTranslatef(-translation[0], -translation[1], 0);
+
+ /* restore GL state */
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+}
+
+void hair_edit_cursor_start(bContext *C, int (*poll)(bContext *C))
+{
+ Scene *scene = CTX_data_scene(C);
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+
+ if (!settings->paint_cursor)
+ settings->paint_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), poll, hair_draw_cursor, NULL);
+}
diff --git a/source/blender/editors/hair/hair_edit.c b/source/blender/editors/hair/hair_edit.c
new file mode 100644
index 00000000000..e4aad528f33
--- /dev/null
+++ b/source/blender/editors/hair/hair_edit.c
@@ -0,0 +1,459 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/hair/hair_edit.c
+ * \ingroup edhair
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_editstrands.h"
+#include "BKE_paint.h"
+
+#include "bmesh.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_view3d.h"
+
+#include "hair_intern.h"
+#include "paint_intern.h"
+
+int hair_edit_poll(bContext *C)
+{
+ Object *obact;
+
+ obact = CTX_data_active_object(C);
+ if ((obact && obact->mode & OB_MODE_HAIR_EDIT) && CTX_wm_region_view3d(C)) {
+ return true;
+ }
+
+ return false;
+}
+
+bool hair_use_mirror_x(Object *ob)
+{
+ if (ob->type == OB_MESH)
+ return ((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X;
+ else
+ return false;
+}
+
+bool hair_use_mirror_topology(Object *ob)
+{
+ if (ob->type == OB_MESH)
+ return ((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_TOPO;
+ else
+ return false;
+}
+
+
+/* ==== BMesh utilities ==== */
+
+void hair_bm_min_max(BMEditStrands *edit, float min[3], float max[3])
+{
+ BMVert *v;
+ BMIter iter;
+
+ if (edit->bm->totvert > 0) {
+ INIT_MINMAX(min, max);
+
+ BM_ITER_MESH(v, &iter, edit->bm, BM_VERTS_OF_MESH) {
+ minmax_v3v3_v3(min, max, v->co);
+ }
+ }
+ else {
+ zero_v3(min);
+ zero_v3(max);
+ }
+}
+
+
+/* ==== edit mode toggle ==== */
+
+int hair_edit_toggle_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+
+ if (ob == NULL)
+ return false;
+ if (CTX_data_edit_object(C))
+ return false;
+
+ return (ob->data && !((ID *)ob->data)->lib && ED_hair_object_has_hair_particle_data(ob)) ||
+ ED_hair_object_has_hair_cache_data(ob);
+}
+
+static void toggle_hair_cursor(bContext *C, bool enable)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ Scene *scene = CTX_data_scene(C);
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+
+ if (enable) {
+ hair_edit_cursor_start(C, hair_edit_toggle_poll);
+ }
+ else {
+ if (settings->paint_cursor) {
+ WM_paint_cursor_end(wm, settings->paint_cursor);
+ settings->paint_cursor = NULL;
+ }
+ }
+}
+
+static int hair_edit_toggle_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ const int mode_flag = OB_MODE_HAIR_EDIT;
+ const bool is_mode_set = (ob->mode & mode_flag) != 0;
+
+ if (!is_mode_set) {
+ if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ if (!is_mode_set) {
+ if (ED_hair_object_init_particle_edit(scene, ob)) {
+ /* particle edit */
+ }
+ else if (ED_hair_object_init_cache_edit(ob)) {
+ /* strands cache edit */
+ }
+
+ ob->mode |= mode_flag;
+
+ toggle_hair_cursor(C, true);
+ WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_HAIR, NULL);
+ }
+ else {
+ if (ED_hair_object_apply_particle_edit(ob)) {
+ /* particle edit */
+ }
+ else if (ED_hair_object_apply_cache_edit(ob)) {
+ /* strands cache edit */
+ }
+ ob->mode &= ~mode_flag;
+
+ toggle_hair_cursor(C, false);
+ WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_HAIR, NULL);
+ }
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ return OPERATOR_FINISHED;
+}
+
+void HAIR_OT_hair_edit_toggle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Hair Edit Toggle";
+ ot->idname = "HAIR_OT_hair_edit_toggle";
+ ot->description = "Toggle hair edit mode";
+
+ /* api callbacks */
+ ot->exec = hair_edit_toggle_exec;
+ ot->poll = hair_edit_toggle_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+/* ==== brush stroke ==== */
+
+void hair_init_viewdata(bContext *C, HairViewData *viewdata)
+{
+ View3D *v3d;
+ bool has_zbuf;
+
+ view3d_set_viewcontext(C, &viewdata->vc);
+
+ v3d = viewdata->vc.v3d;
+ has_zbuf = (v3d->drawtype > OB_WIRE) && (v3d->flag & V3D_ZBUF_SELECT);
+
+ view3d_get_transformation(viewdata->vc.ar, viewdata->vc.rv3d, NULL, &viewdata->mats);
+
+ if (has_zbuf) {
+ if (v3d->flag & V3D_INVALID_BACKBUF) {
+ /* needed or else the draw matrix can be incorrect */
+ view3d_operator_needs_opengl(C);
+
+ ED_view3d_backbuf_validate(&viewdata->vc);
+ /* we may need to force an update here by setting the rv3d as dirty
+ * for now it seems ok, but take care!:
+ * rv3d->depths->dirty = 1; */
+ ED_view3d_depth_update(viewdata->vc.ar);
+ }
+ }
+}
+
+typedef struct HairStroke {
+ Scene *scene;
+ Object *ob;
+ BMEditStrands *edit;
+
+ bool first;
+ float lastmouse[2];
+ float zfac;
+
+ float smoothdir[2];
+} HairStroke;
+
+static int hair_stroke_init(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ BMEditStrands *edit = BKE_editstrands_from_object(ob);
+ ARegion *ar = CTX_wm_region(C);
+
+ HairStroke *stroke;
+ float min[3], max[3], center[3];
+
+ /* set the 'distance factor' for grabbing (used in comb etc) */
+ hair_bm_min_max(edit, min, max);
+ mid_v3_v3v3(center, min, max);
+
+ stroke = MEM_callocN(sizeof(HairStroke), "HairStroke");
+ stroke->first = true;
+ op->customdata = stroke;
+
+ stroke->scene = scene;
+ stroke->ob = ob;
+ stroke->edit = edit;
+
+ stroke->zfac = ED_view3d_calc_zfac(ar->regiondata, center, NULL);
+
+ return 1;
+}
+
+static bool hair_stroke_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
+{
+ HairStroke *stroke = op->customdata;
+ Scene *scene = stroke->scene;
+ Object *ob = stroke->ob;
+ BMEditStrands *edit = stroke->edit;
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+ ARegion *ar = CTX_wm_region(C);
+ const float smoothfac = 0.9f; /* XXX should this be configurable? */
+
+ float mouse[2], mdelta[2], zvec[3], delta_max;
+ int totsteps, step;
+ HairToolData tool_data;
+ bool updated = false;
+
+ RNA_float_get_array(itemptr, "mouse", mouse);
+
+ if (stroke->first) {
+ copy_v2_v2(stroke->lastmouse, mouse);
+ zero_v2(stroke->smoothdir);
+ stroke->first = false;
+ }
+
+ if (!settings->brush)
+ return false;
+
+ sub_v2_v2v2(mdelta, mouse, stroke->lastmouse);
+ delta_max = max_ff(fabsf(mdelta[0]), fabsf(mdelta[1]));
+
+ totsteps = delta_max / (0.2f * BKE_brush_size_get(scene, settings->brush)) + 1;
+ mul_v2_fl(mdelta, 1.0f / (float)totsteps);
+
+ /* low-pass filter to smooth out jittery pixel increments in the direction */
+ interp_v2_v2v2(stroke->smoothdir, mdelta, stroke->smoothdir, smoothfac);
+
+ hair_init_viewdata(C, &tool_data.viewdata);
+ tool_data.scene = scene;
+ tool_data.ob = ob;
+ tool_data.edit = edit;
+ tool_data.settings = settings;
+
+ invert_m4_m4(tool_data.imat, ob->obmat);
+ copy_v2_v2(tool_data.mval, mouse);
+ tool_data.mdepth = stroke->zfac;
+
+ zvec[0] = 0.0f; zvec[1] = 0.0f; zvec[2] = stroke->zfac;
+ ED_view3d_win_to_3d(ar, zvec, mouse, tool_data.loc);
+ ED_view3d_win_to_delta(ar, stroke->smoothdir, tool_data.delta, stroke->zfac);
+ /* tools work in object space */
+ mul_m4_v3(tool_data.imat, tool_data.loc);
+ mul_mat3_m4_v3(tool_data.imat, tool_data.delta);
+
+ for (step = 0; step < totsteps; ++step) {
+ bool step_updated = hair_brush_step(&tool_data);
+
+ if (step_updated)
+ BKE_editstrands_solve_constraints(ob, edit, NULL);
+
+ updated |= step_updated;
+ }
+
+ copy_v2_v2(stroke->lastmouse, mouse);
+
+ return updated;
+}
+
+static void hair_stroke_exit(wmOperator *op)
+{
+ HairStroke *stroke = op->customdata;
+ MEM_freeN(stroke);
+}
+
+static int hair_stroke_exec(bContext *C, wmOperator *op)
+{
+ HairStroke *stroke = op->customdata;
+ Object *ob = stroke->ob;
+
+ bool updated = false;
+
+ if (!hair_stroke_init(C, op))
+ return OPERATOR_CANCELLED;
+
+ RNA_BEGIN (op->ptr, itemptr, "stroke")
+ {
+ updated |= hair_stroke_apply(C, op, &itemptr);
+ }
+ RNA_END;
+
+ if (updated) {
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
+ }
+
+ hair_stroke_exit(op);
+
+ return OPERATOR_FINISHED;
+}
+
+static void hair_stroke_apply_event(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ HairStroke *stroke = op->customdata;
+ Object *ob = stroke->ob;
+
+ PointerRNA itemptr;
+ float mouse[2];
+ bool updated = false;
+
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+
+ /* fill in stroke */
+ RNA_collection_add(op->ptr, "stroke", &itemptr);
+
+ RNA_float_set_array(&itemptr, "mouse", mouse);
+
+ /* apply */
+ updated |= hair_stroke_apply(C, op, &itemptr);
+
+ if (updated) {
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
+ }
+ else {
+ /* even if nothing was changed, still trigger redraw
+ * for brush drawing during the modal operator
+ */
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+ }
+}
+
+static int hair_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!hair_stroke_init(C, op))
+ return OPERATOR_CANCELLED;
+
+ hair_stroke_apply_event(C, op, event);
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int hair_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ switch (event->type) {
+ case LEFTMOUSE:
+ case MIDDLEMOUSE:
+ case RIGHTMOUSE: // XXX hardcoded
+ hair_stroke_exit(op);
+ return OPERATOR_FINISHED;
+ case MOUSEMOVE:
+ hair_stroke_apply_event(C, op, event);
+ break;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void hair_stroke_cancel(bContext *UNUSED(C), wmOperator *op)
+{
+ hair_stroke_exit(op);
+}
+
+void HAIR_OT_stroke(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Hair Stroke";
+ ot->idname = "HAIR_OT_stroke";
+ ot->description = "Use a stroke tool on hair strands";
+
+ /* api callbacks */
+ ot->exec = hair_stroke_exec;
+ ot->invoke = hair_stroke_invoke;
+ ot->modal = hair_stroke_modal;
+ ot->cancel = hair_stroke_cancel;
+ ot->poll = hair_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
+
+ /* properties */
+ RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+}
diff --git a/source/blender/editors/hair/hair_intern.h b/source/blender/editors/hair/hair_intern.h
new file mode 100644
index 00000000000..cc805136ace
--- /dev/null
+++ b/source/blender/editors/hair/hair_intern.h
@@ -0,0 +1,124 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/hair/hair_intern.h
+ * \ingroup edhair
+ */
+
+#ifndef __HAIR_INTERN_H__
+#define __HAIR_INTERN_H__
+
+#include "BIF_glutil.h"
+
+#include "ED_view3d.h"
+
+struct ARegion;
+struct bContext;
+struct wmOperatorType;
+struct rcti;
+
+struct Object;
+struct Strands;
+struct DupliObjectData;
+struct StrandsKeyCacheModifier;
+struct DerivedMesh;
+
+/* hair_edit.c */
+bool hair_use_mirror_x(struct Object *ob);
+bool hair_use_mirror_topology(struct Object *ob);
+
+int hair_edit_toggle_poll(struct bContext *C);
+int hair_edit_poll(struct bContext *C);
+
+void HAIR_OT_hair_edit_toggle(struct wmOperatorType *ot);
+
+/* hair_select.c */
+void HAIR_OT_select_all(struct wmOperatorType *ot);
+void HAIR_OT_select_linked(struct wmOperatorType *ot);
+
+/* hair_stroke.c */
+void HAIR_OT_stroke(struct wmOperatorType *ot);
+
+/* hair_object_cachelib.c */
+bool ED_hair_object_has_hair_cache_data(struct Object *ob);
+bool ED_hair_object_init_cache_edit(struct Object *ob);
+bool ED_hair_object_apply_cache_edit(struct Object *ob);
+
+/* hair_object_particles.c */
+bool ED_hair_object_has_hair_particle_data(struct Object *ob);
+bool ED_hair_object_init_particle_edit(struct Scene *scene, struct Object *ob);
+bool ED_hair_object_apply_particle_edit(struct Object *ob);
+
+
+/* ==== Hair Brush ==== */
+
+typedef struct HairViewData {
+ ViewContext vc;
+ bglMats mats;
+} HairViewData;
+
+void hair_init_viewdata(struct bContext *C, struct HairViewData *viewdata);
+
+bool hair_test_depth(struct HairViewData *viewdata, const float co[3], const int screen_co[2]);
+bool hair_test_vertex_inside_circle(struct HairViewData *viewdata, const float mval[2], float radsq,
+ struct BMVert *v, float *r_dist);
+bool hair_test_edge_inside_circle(struct HairViewData *viewdata, const float mval[2], float radsq,
+ struct BMVert *v1, struct BMVert *v2, float *r_dist, float *r_lambda);
+bool hair_test_vertex_inside_rect(struct HairViewData *viewdata, struct rcti *rect, struct BMVert *v);
+bool hair_test_vertex_inside_lasso(struct HairViewData *viewdata, const int mcoords[][2], short moves, struct BMVert *v);
+
+typedef struct HairToolData {
+ /* context */
+ struct Scene *scene;
+ struct Object *ob;
+ struct BMEditStrands *edit;
+ struct HairEditSettings *settings;
+ HairViewData viewdata;
+
+ /* view space */
+ float mval[2]; /* mouse coordinates */
+ float mdepth; /* mouse z depth */
+
+ /* object space */
+ float imat[4][4]; /* obmat inverse */
+ float loc[3]; /* start location */
+ float delta[3]; /* stroke step */
+} HairToolData;
+
+bool hair_brush_step(struct HairToolData *data);
+
+/* ==== Cursor ==== */
+
+void hair_edit_cursor_start(struct bContext *C, int (*poll)(struct bContext *C));
+
+/* ==== BMesh utilities ==== */
+
+struct BMEditStrands;
+
+void hair_bm_min_max(struct BMEditStrands *edit, float min[3], float max[3]);
+
+#endif
diff --git a/source/blender/editors/hair/hair_mirror.c b/source/blender/editors/hair/hair_mirror.c
new file mode 100644
index 00000000000..7f5b14e4b37
--- /dev/null
+++ b/source/blender/editors/hair/hair_mirror.c
@@ -0,0 +1,210 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/hair/hair_mirror.c
+ * \ingroup edhair
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "BKE_editmesh_bvh.h"
+#include "BKE_editstrands.h"
+
+#include "ED_physics.h"
+#include "ED_util.h"
+
+#include "bmesh.h"
+
+#include "hair_intern.h"
+
+/* TODO use_topology is not yet implemented for strands.
+ * Native strand topology is not very useful for this.
+ * Instead, the topology of the scalp mesh should be used for finding mirrored strand roots,
+ * then the arc- or parametric length of a vertex from the root to find mirrored verts.
+ */
+
+#define BM_SEARCH_MAXDIST_MIRR 0.00002f
+#define BM_CD_LAYER_ID "__mirror_index"
+/**
+ * \param edit Edit strands.
+ * \param use_self Allow a vertex to point to its self (middle verts).
+ * \param use_select Restrict to selected verts.
+ * \param use_topology Use topology mirror.
+ * \param maxdist Distance for close point test.
+ * \param r_index Optional array to write into, as an alternative to a customdata layer (length of total verts).
+ */
+void ED_strands_mirror_cache_begin_ex(BMEditStrands *edit, const int axis, const bool use_self, const bool use_select,
+ /* extra args */
+ const bool UNUSED(use_topology), float maxdist, int *r_index)
+{
+ BMesh *bm = edit->bm;
+ BMIter iter;
+ BMVert *v;
+ int cd_vmirr_offset;
+ int i;
+
+ /* one or the other is used depending if topo is enabled */
+ struct BMBVHTree *tree = NULL;
+
+ BM_mesh_elem_table_ensure(bm, BM_VERT);
+
+ if (r_index == NULL) {
+ const char *layer_id = BM_CD_LAYER_ID;
+ edit->mirror_cdlayer = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT, layer_id);
+ if (edit->mirror_cdlayer == -1) {
+ BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_INT, layer_id);
+ edit->mirror_cdlayer = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT, layer_id);
+ }
+
+ cd_vmirr_offset = CustomData_get_n_offset(&bm->vdata, CD_PROP_INT,
+ edit->mirror_cdlayer - CustomData_get_layer_index(&bm->vdata, CD_PROP_INT));
+
+ bm->vdata.layers[edit->mirror_cdlayer].flag |= CD_FLAG_TEMPORARY;
+ }
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ tree = BKE_bmbvh_new(edit->bm, NULL, 0, 0, NULL, false);
+
+#define VERT_INTPTR(_v, _i) r_index ? &r_index[_i] : BM_ELEM_CD_GET_VOID_P(_v, cd_vmirr_offset);
+
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ BLI_assert(BM_elem_index_get(v) == i);
+
+ /* temporary for testing, check for selection */
+ if (use_select && !BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ /* do nothing */
+ }
+ else {
+ BMVert *v_mirr;
+ float co[3];
+ int *idx = VERT_INTPTR(v, i);
+
+ copy_v3_v3(co, v->co);
+ co[axis] *= -1.0f;
+ v_mirr = BKE_bmbvh_find_vert_closest(tree, co, maxdist);
+
+ if (v_mirr && (use_self || (v_mirr != v))) {
+ const int i_mirr = BM_elem_index_get(v_mirr);
+ *idx = i_mirr;
+ idx = VERT_INTPTR(v_mirr, i_mirr);
+ *idx = i;
+ }
+ else {
+ *idx = -1;
+ }
+ }
+
+ }
+
+#undef VERT_INTPTR
+
+ BKE_bmbvh_free(tree);
+}
+
+void ED_strands_mirror_cache_begin(BMEditStrands *edit, const int axis,
+ const bool use_self, const bool use_select,
+ const bool use_topology)
+{
+ ED_strands_mirror_cache_begin_ex(edit, axis,
+ use_self, use_select,
+ /* extra args */
+ use_topology, BM_SEARCH_MAXDIST_MIRR, NULL);
+}
+
+BMVert *ED_strands_mirror_get(BMEditStrands *edit, BMVert *v)
+{
+ const int *mirr = CustomData_bmesh_get_layer_n(&edit->bm->vdata, v->head.data, edit->mirror_cdlayer);
+
+ BLI_assert(edit->mirror_cdlayer != -1); /* invalid use */
+
+ if (mirr && *mirr >= 0 && *mirr < edit->bm->totvert) {
+ if (!edit->bm->vtable) {
+ printf("err: should only be called between "
+ "ED_strands_mirror_cache_begin and ED_strands_mirror_cache_end\n");
+ return NULL;
+ }
+
+ return edit->bm->vtable[*mirr];
+ }
+
+ return NULL;
+}
+
+BMEdge *ED_strands_mirror_get_edge(BMEditStrands *edit, BMEdge *e)
+{
+ BMVert *v1_mirr = ED_strands_mirror_get(edit, e->v1);
+ if (v1_mirr) {
+ BMVert *v2_mirr = ED_strands_mirror_get(edit, e->v2);
+ if (v2_mirr) {
+ return BM_edge_exists(v1_mirr, v2_mirr);
+ }
+ }
+
+ return NULL;
+}
+
+void ED_strands_mirror_cache_clear(BMEditStrands *edit, BMVert *v)
+{
+ int *mirr = CustomData_bmesh_get_layer_n(&edit->bm->vdata, v->head.data, edit->mirror_cdlayer);
+
+ BLI_assert(edit->mirror_cdlayer != -1); /* invalid use */
+
+ if (mirr) {
+ *mirr = -1;
+ }
+}
+
+void ED_strands_mirror_cache_end(BMEditStrands *edit)
+{
+ edit->mirror_cdlayer = -1;
+}
+
+void ED_strands_mirror_apply(BMEditStrands *edit, const int sel_from, const int sel_to)
+{
+ BMIter iter;
+ BMVert *v;
+
+ BLI_assert((edit->bm->vtable != NULL) && ((edit->bm->elem_table_dirty & BM_VERT) == 0));
+
+ BM_ITER_MESH (v, &iter, edit->bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) == sel_from) {
+ BMVert *mirr = ED_strands_mirror_get(edit, v);
+ if (mirr) {
+ if (BM_elem_flag_test(mirr, BM_ELEM_SELECT) == sel_to) {
+ copy_v3_v3(mirr->co, v->co);
+ mirr->co[0] *= -1.0f;
+ }
+ }
+ }
+ }
+}
diff --git a/source/blender/editors/hair/hair_object_cachelib.c b/source/blender/editors/hair/hair_object_cachelib.c
new file mode 100644
index 00000000000..576d8cd2c9d
--- /dev/null
+++ b/source/blender/editors/hair/hair_object_cachelib.c
@@ -0,0 +1,104 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/hair/hair_object_cachelib.c
+ * \ingroup edhair
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "DNA_cache_library_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_strands_types.h"
+
+#include "BKE_anim.h"
+#include "BKE_cache_library.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_editstrands.h"
+#include "BKE_strands.h"
+
+#include "bmesh.h"
+
+#include "hair_intern.h"
+
+bool ED_hair_object_has_hair_cache_data(Object *ob)
+{
+ return BKE_cache_modifier_strands_key_get(ob, NULL, NULL, NULL, NULL, NULL, NULL);
+}
+
+bool ED_hair_object_init_cache_edit(Object *ob)
+{
+ StrandsKeyCacheModifier *skmd;
+ DerivedMesh *dm;
+ Strands *strands;
+ float mat[4][4];
+
+ if (!BKE_cache_modifier_strands_key_get(ob, &skmd, &dm, &strands, NULL, NULL, mat))
+ return false;
+
+ if (!skmd->edit) {
+ BMesh *bm = BKE_cache_strands_to_bmesh(strands, skmd->key, mat, skmd->shapenr, dm);
+
+ skmd->edit = BKE_editstrands_create(bm, dm, mat);
+ }
+
+ return true;
+}
+
+bool ED_hair_object_apply_cache_edit(Object *ob)
+{
+ StrandsKeyCacheModifier *skmd;
+ DerivedMesh *dm;
+ Strands *strands;
+ DupliObjectData *dobdata;
+ const char *name;
+ float mat[4][4];
+
+ if (!BKE_cache_modifier_strands_key_get(ob, &skmd, &dm, &strands, &dobdata, &name, mat))
+ return false;
+
+ if (skmd->edit) {
+ Strands *nstrands;
+
+ nstrands = BKE_cache_strands_from_bmesh(skmd->edit, skmd->key, mat, dm);
+
+ BKE_dupli_object_data_add_strands(dobdata, name, nstrands);
+
+ BKE_editstrands_free(skmd->edit);
+ MEM_freeN(skmd->edit);
+ skmd->edit = NULL;
+ }
+
+ return true;
+}
diff --git a/source/blender/editors/hair/hair_object_particles.c b/source/blender/editors/hair/hair_object_particles.c
new file mode 100644
index 00000000000..a6d05327482
--- /dev/null
+++ b/source/blender/editors/hair/hair_object_particles.c
@@ -0,0 +1,101 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/hair/hair_object_particles.c
+ * \ingroup edhair
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_editstrands.h"
+#include "BKE_particle.h"
+
+#include "bmesh.h"
+
+#include "hair_intern.h"
+
+bool ED_hair_object_has_hair_particle_data(Object *ob)
+{
+ ParticleSystem *psys = psys_get_current(ob);
+ if (psys && psys->part->type == PART_HAIR)
+ return true;
+
+ return false;
+}
+
+bool ED_hair_object_init_particle_edit(Scene *scene, Object *ob)
+{
+ ParticleSystem *psys = psys_get_current(ob);
+ BMesh *bm;
+ DerivedMesh *dm;
+
+ if (psys && psys->part->type == PART_HAIR) {
+ if (!psys->hairedit) {
+ bm = BKE_particles_to_bmesh(ob, psys);
+
+ if (ob->type == OB_MESH || ob->derivedFinal)
+ dm = ob->derivedFinal ? ob->derivedFinal : mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+ else
+ dm = NULL;
+
+ psys->hairedit = BKE_editstrands_create(bm, dm, NULL);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool ED_hair_object_apply_particle_edit(Object *ob)
+{
+ ParticleSystem *psys = psys_get_current(ob);
+ if (psys && psys->part->type == PART_HAIR) {
+ if (psys->hairedit) {
+ BKE_particles_from_bmesh(ob, psys);
+ psys->flag |= PSYS_EDITED;
+
+ BKE_editstrands_free(psys->hairedit);
+ MEM_freeN(psys->hairedit);
+ psys->hairedit = NULL;
+ }
+
+ return true;
+ }
+
+ return false;
+}
diff --git a/source/blender/editors/hair/hair_ops.c b/source/blender/editors/hair/hair_ops.c
new file mode 100644
index 00000000000..bb3b027cf20
--- /dev/null
+++ b/source/blender/editors/hair/hair_ops.c
@@ -0,0 +1,143 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/hair/hair_ops.c
+ * \ingroup edhair
+ */
+
+#include "BLI_utildefines.h"
+
+#include "DNA_object_types.h"
+
+#include "BKE_context.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_physics.h"
+
+#include "hair_intern.h"
+#include "paint_intern.h"
+
+void ED_operatortypes_hair(void)
+{
+ WM_operatortype_append(HAIR_OT_hair_edit_toggle);
+
+ WM_operatortype_append(HAIR_OT_select_all);
+ WM_operatortype_append(HAIR_OT_select_linked);
+
+ WM_operatortype_append(HAIR_OT_stroke);
+}
+
+static int hair_poll(bContext *C)
+{
+ if (hair_edit_toggle_poll(C))
+ if (CTX_data_active_object(C)->mode & OB_MODE_HAIR_EDIT)
+ return true;
+
+ return false;
+}
+
+static void ed_keymap_hair_brush_switch(wmKeyMap *keymap, const char *mode)
+{
+ wmKeyMapItem *kmi;
+ int i;
+ /* index 0-9 (zero key is tenth), shift key for index 10-19 */
+ for (i = 0; i < 20; i++) {
+ kmi = WM_keymap_add_item(keymap, "BRUSH_OT_active_index_set",
+ ZEROKEY + ((i + 1) % 10), KM_PRESS, i < 10 ? 0 : KM_SHIFT, 0);
+ RNA_string_set(kmi->ptr, "mode", mode);
+ RNA_int_set(kmi->ptr, "index", i);
+ }
+}
+
+static void ed_keymap_hair_brush_size(wmKeyMap *keymap, const char *UNUSED(path))
+{
+ wmKeyMapItem *kmi;
+
+ kmi = WM_keymap_add_item(keymap, "BRUSH_OT_scale_size", LEFTBRACKETKEY, KM_PRESS, 0, 0);
+ RNA_float_set(kmi->ptr, "scalar", 0.9);
+
+ kmi = WM_keymap_add_item(keymap, "BRUSH_OT_scale_size", RIGHTBRACKETKEY, KM_PRESS, 0, 0);
+ RNA_float_set(kmi->ptr, "scalar", 10.0 / 9.0); // 1.1111....
+}
+
+static void ed_keymap_hair_brush_radial_control(wmKeyMap *keymap, const char *settings, RCFlags flags)
+{
+ wmKeyMapItem *kmi;
+ /* only size needs to follow zoom, strength shows fixed size circle */
+ int flags_nozoom = flags & (~RC_ZOOM);
+ int flags_noradial_secondary = flags & (~(RC_SECONDARY_ROTATION | RC_ZOOM));
+
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0);
+ set_brush_rc_props(kmi->ptr, settings, "size", "use_unified_size", flags);
+
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0);
+ set_brush_rc_props(kmi->ptr, settings, "strength", "use_unified_strength", flags_nozoom);
+
+ if (flags & RC_WEIGHT) {
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", WKEY, KM_PRESS, 0, 0);
+ set_brush_rc_props(kmi->ptr, settings, "weight", "use_unified_weight", flags_nozoom);
+ }
+
+ if (flags & RC_ROTATION) {
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0);
+ set_brush_rc_props(kmi->ptr, settings, "texture_slot.angle", NULL, flags_noradial_secondary);
+ }
+
+ if (flags & RC_SECONDARY_ROTATION) {
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
+ set_brush_rc_props(kmi->ptr, settings, "mask_texture_slot.angle", NULL, flags_nozoom);
+ }
+}
+
+void ED_keymap_hair(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap;
+ wmKeyMapItem *kmi;
+
+ keymap = WM_keymap_find(keyconf, "Hair", 0, 0);
+ keymap->poll = hair_poll;
+
+ kmi = WM_keymap_add_item(keymap, "HAIR_OT_select_all", AKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
+ kmi = WM_keymap_add_item(keymap, "HAIR_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
+
+ kmi = WM_keymap_add_item(keymap, "HAIR_OT_select_linked", LKEY, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", false);
+ kmi = WM_keymap_add_item(keymap, "HAIR_OT_select_linked", LKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "deselect", true);
+
+ kmi = WM_keymap_add_item(keymap, "HAIR_OT_stroke", LEFTMOUSE, KM_PRESS, 0, 0);
+
+ ed_keymap_hair_brush_switch(keymap, "hair_edit");
+ ed_keymap_hair_brush_size(keymap, "tool_settings.hair_edit.brush.size");
+ ed_keymap_hair_brush_radial_control(keymap, "hair_edit", 0);
+}
diff --git a/source/blender/editors/hair/hair_select.c b/source/blender/editors/hair/hair_select.c
new file mode 100644
index 00000000000..986e669f3a7
--- /dev/null
+++ b/source/blender/editors/hair/hair_select.c
@@ -0,0 +1,502 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/hair/hair_select.c
+ * \ingroup edhair
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_editstrands.h"
+
+#include "bmesh.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_physics.h"
+#include "ED_view3d.h"
+
+#include "hair_intern.h"
+
+BLI_INLINE bool apply_select_action_flag(BMVert *v, int action)
+{
+ bool cursel = BM_elem_flag_test_bool(v, BM_ELEM_SELECT);
+ bool newsel;
+
+ switch (action) {
+ case SEL_SELECT:
+ newsel = true;
+ break;
+ case SEL_DESELECT:
+ newsel = false;
+ break;
+ case SEL_INVERT:
+ newsel = !cursel;
+ break;
+ case SEL_TOGGLE:
+ /* toggle case should be converted to SELECT or DESELECT based on global state */
+ BLI_assert(false);
+ break;
+ }
+
+ if (newsel != cursel) {
+ BM_elem_flag_set(v, BM_ELEM_SELECT, newsel);
+ return true;
+ }
+ else
+ return false;
+}
+
+/* poll function */
+typedef bool (*PollVertexCb)(void *userdata, struct BMVert *v);
+/* distance metric function */
+typedef bool (*DistanceVertexCb)(void *userdata, struct BMVert *v, float *dist);
+typedef void (*ActionVertexCb)(void *userdata, struct BMVert *v, int action);
+
+static int hair_select_verts_filter(BMEditStrands *edit, HairEditSelectMode select_mode, int action, PollVertexCb cb, void *userdata)
+{
+ BMesh *bm = edit->bm;
+
+ BMVert *v;
+ BMIter iter;
+ int tot = 0;
+
+ bm->selectmode = BM_VERT;
+
+ switch (select_mode) {
+ case HAIR_SELECT_STRAND:
+ break;
+ case HAIR_SELECT_VERTEX:
+ BM_ITER_MESH(v, &iter, edit->bm, BM_VERTS_OF_MESH) {
+ if (!cb(userdata, v))
+ continue;
+
+ if (apply_select_action_flag(v, action))
+ ++tot;
+ }
+ break;
+ case HAIR_SELECT_TIP:
+ BM_ITER_MESH(v, &iter, edit->bm, BM_VERTS_OF_MESH) {
+ if (!BM_strands_vert_is_tip(v))
+ continue;
+ if (!cb(userdata, v))
+ continue;
+
+ if (apply_select_action_flag(v, action))
+ ++tot;
+ }
+ break;
+ }
+
+ BM_mesh_select_mode_flush(bm);
+
+ return tot;
+}
+
+static bool hair_select_verts_closest(BMEditStrands *edit, HairEditSelectMode select_mode, int action, DistanceVertexCb cb, ActionVertexCb action_cb, void *userdata)
+{
+ BMesh *bm = edit->bm;
+
+ BMVert *v;
+ BMIter iter;
+
+ float dist;
+ BMVert *closest_v = NULL;
+ float closest_dist = FLT_MAX;
+
+ bm->selectmode = BM_VERT;
+
+ switch (select_mode) {
+ case HAIR_SELECT_STRAND:
+ break;
+ case HAIR_SELECT_VERTEX:
+ BM_ITER_MESH(v, &iter, edit->bm, BM_VERTS_OF_MESH) {
+ if (!cb(userdata, v, &dist))
+ continue;
+
+ if (dist < closest_dist) {
+ closest_v = v;
+ closest_dist = dist;
+ }
+ }
+ break;
+ case HAIR_SELECT_TIP:
+ BM_ITER_MESH(v, &iter, edit->bm, BM_VERTS_OF_MESH) {
+ if (!BM_strands_vert_is_tip(v))
+ continue;
+ if (!cb(userdata, v, &dist))
+ continue;
+
+ if (dist < closest_dist) {
+ closest_v = v;
+ closest_dist = dist;
+ }
+ }
+ break;
+ }
+
+ if (closest_v) {
+ action_cb(userdata, closest_v, action);
+
+ BM_mesh_select_mode_flush(bm);
+ return true;
+ }
+ else
+ return false;
+}
+
+static void hair_deselect_all(BMEditStrands *edit)
+{
+ BMVert *v;
+ BMIter iter;
+
+ BM_ITER_MESH(v, &iter, edit->bm, BM_VERTS_OF_MESH) {
+ BM_elem_flag_set(v, BM_ELEM_SELECT, false);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+/************************ select/deselect all operator ************************/
+
+static bool poll_vertex_all(void *UNUSED(userdata), struct BMVert *UNUSED(v))
+{
+ return true;
+}
+
+static int select_all_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ BMEditStrands *edit = BKE_editstrands_from_object(ob);
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+ int action = RNA_enum_get(op->ptr, "action");
+
+ if (!edit)
+ return 0;
+
+ /* toggle action depends on current global selection state */
+ if (action == SEL_TOGGLE) {
+ if (edit->bm->totvertsel == 0)
+ action = SEL_SELECT;
+ else
+ action = SEL_DESELECT;
+ }
+
+ hair_select_verts_filter(edit, settings->select_mode, action, poll_vertex_all, NULL);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | NA_SELECTED, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void HAIR_OT_select_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select/Deselect All";
+ ot->idname = "HAIR_OT_select_all";
+ ot->description = "Select/Deselect all hair vertices";
+
+ /* api callbacks */
+ ot->exec = select_all_exec;
+ ot->poll = hair_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ WM_operator_properties_select_all(ot);
+}
+
+/************************ mouse select operator ************************/
+
+typedef struct DistanceVertexCirleData {
+ HairViewData viewdata;
+ float mval[2];
+ float radsq;
+} DistanceVertexCirleData;
+
+static bool distance_vertex_circle(void *userdata, struct BMVert *v, float *dist)
+{
+ DistanceVertexCirleData *data = userdata;
+
+ return hair_test_vertex_inside_circle(&data->viewdata, data->mval, data->radsq, v, dist);
+}
+
+static void closest_vertex_select(void *UNUSED(userdata), struct BMVert *v, int action)
+{
+ apply_select_action_flag(v, action);
+}
+
+int ED_hair_mouse_select(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ BMEditStrands *edit = BKE_editstrands_from_object(ob);
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+ float select_radius = ED_view3d_select_dist_px();
+
+ DistanceVertexCirleData data;
+ int action;
+
+ if (!extend && !deselect && !toggle) {
+ hair_deselect_all(edit);
+ }
+
+ hair_init_viewdata(C, &data.viewdata);
+ data.mval[0] = mval[0];
+ data.mval[1] = mval[1];
+ data.radsq = select_radius * select_radius;
+
+ if (extend)
+ action = SEL_SELECT;
+ else if (deselect)
+ action = SEL_DESELECT;
+ else
+ action = SEL_INVERT;
+
+ hair_select_verts_closest(edit, settings->select_mode, action, distance_vertex_circle, closest_vertex_select, &data);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | NA_SELECTED, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+/************************ select linked operator ************************/
+
+static void linked_vertices_select(void *UNUSED(userdata), struct BMVert *v, int action)
+{
+ BMVert *lv;
+
+ apply_select_action_flag(v, action);
+
+ for (lv = BM_strands_vert_prev(v); lv; lv = BM_strands_vert_prev(lv))
+ apply_select_action_flag(lv, action);
+ for (lv = BM_strands_vert_next(v); lv; lv = BM_strands_vert_next(lv))
+ apply_select_action_flag(lv, action);
+}
+
+static int select_linked_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ BMEditStrands *edit = BKE_editstrands_from_object(ob);
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+ float select_radius = ED_view3d_select_dist_px();
+
+ DistanceVertexCirleData data;
+ int location[2];
+ int action;
+
+ RNA_int_get_array(op->ptr, "location", location);
+
+ hair_init_viewdata(C, &data.viewdata);
+ data.mval[0] = location[0];
+ data.mval[1] = location[1];
+ data.radsq = select_radius * select_radius;
+
+ action = RNA_boolean_get(op->ptr, "deselect") ? SEL_DESELECT : SEL_SELECT;
+
+ hair_select_verts_closest(edit, settings->select_mode, action, distance_vertex_circle, linked_vertices_select, &data);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | NA_SELECTED, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ RNA_int_set_array(op->ptr, "location", event->mval);
+ return select_linked_exec(C, op);
+}
+
+void HAIR_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Linked";
+ ot->idname = "HAIR_OT_select_linked";
+ ot->description = "Select connected vertices";
+
+ /* api callbacks */
+ ot->exec = select_linked_exec;
+ ot->invoke = select_linked_invoke;
+ ot->poll = hair_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked keys rather than selecting them");
+ RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
+}
+
+/************************ border select operator ************************/
+
+typedef struct PollVertexRectData {
+ HairViewData viewdata;
+ rcti rect;
+} PollVertexRectData;
+
+static bool poll_vertex_inside_rect(void *userdata, struct BMVert *v)
+{
+ PollVertexRectData *data = userdata;
+
+ return hair_test_vertex_inside_rect(&data->viewdata, &data->rect, v);
+}
+
+int ED_hair_border_select(bContext *C, rcti *rect, bool select, bool extend)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ BMEditStrands *edit = BKE_editstrands_from_object(ob);
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+
+ PollVertexRectData data;
+ int action;
+
+ if (!extend && select)
+ hair_deselect_all(edit);
+
+ hair_init_viewdata(C, &data.viewdata);
+ data.rect = *rect;
+
+ if (extend)
+ action = SEL_SELECT;
+ else if (select)
+ action = SEL_INVERT;
+ else
+ action = SEL_DESELECT;
+
+ hair_select_verts_filter(edit, settings->select_mode, action, poll_vertex_inside_rect, &data);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | NA_SELECTED, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+/************************ circle select operator ************************/
+
+typedef struct PollVertexCirleData {
+ HairViewData viewdata;
+ float mval[2];
+ float radsq;
+} PollVertexCirleData;
+
+static bool poll_vertex_inside_circle(void *userdata, struct BMVert *v)
+{
+ PollVertexCirleData *data = userdata;
+ float dist;
+
+ return hair_test_vertex_inside_circle(&data->viewdata, data->mval, data->radsq, v, &dist);
+}
+
+int ED_hair_circle_select(bContext *C, bool select, const int mval[2], float radius)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ BMEditStrands *edit = BKE_editstrands_from_object(ob);
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+ int action = select ? SEL_SELECT : SEL_DESELECT;
+
+ PollVertexCirleData data;
+ int tot;
+
+ if (!edit)
+ return 0;
+
+ hair_init_viewdata(C, &data.viewdata);
+ data.mval[0] = mval[0];
+ data.mval[1] = mval[1];
+ data.radsq = radius * radius;
+
+ tot = hair_select_verts_filter(edit, settings->select_mode, action, poll_vertex_inside_circle, &data);
+
+ return tot;
+}
+
+/************************ lasso select operator ************************/
+
+typedef struct PollVertexLassoData {
+ HairViewData viewdata;
+ const int (*mcoords)[2];
+ short moves;
+} PollVertexLassoData;
+
+static bool poll_vertex_inside_lasso(void *userdata, struct BMVert *v)
+{
+ PollVertexLassoData *data = userdata;
+
+ return hair_test_vertex_inside_lasso(&data->viewdata, data->mcoords, data->moves, v);
+}
+
+int ED_hair_lasso_select(bContext *C, const int mcoords[][2], const short moves, bool extend, bool select)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ BMEditStrands *edit = BKE_editstrands_from_object(ob);
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+
+ PollVertexLassoData data;
+ int action;
+
+ if (!extend && select)
+ hair_deselect_all(edit);
+
+ hair_init_viewdata(C, &data.viewdata);
+ data.mcoords = mcoords;
+ data.moves = moves;
+
+ if (extend)
+ action = SEL_SELECT;
+ else if (select)
+ action = SEL_INVERT;
+ else
+ action = SEL_DESELECT;
+
+ hair_select_verts_filter(edit, settings->select_mode, action, poll_vertex_inside_lasso, &data);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | NA_SELECTED, ob);
+
+ return OPERATOR_FINISHED;
+}
diff --git a/source/blender/editors/hair/hair_stroke.c b/source/blender/editors/hair/hair_stroke.c
new file mode 100644
index 00000000000..aeb460990db
--- /dev/null
+++ b/source/blender/editors/hair/hair_stroke.c
@@ -0,0 +1,498 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/hair/hair_edit.c
+ * \ingroup edhair
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_lasso.h"
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_editstrands.h"
+#include "BKE_effect.h"
+#include "BKE_mesh_sample.h"
+
+#include "bmesh.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "ED_physics.h"
+#include "ED_view3d.h"
+
+#include "hair_intern.h"
+
+bool hair_test_depth(HairViewData *viewdata, const float co[3], const int screen_co[2])
+{
+ View3D *v3d = viewdata->vc.v3d;
+ ViewDepths *vd = viewdata->vc.rv3d->depths;
+ const bool has_zbuf = (v3d->drawtype > OB_WIRE) && (v3d->flag & V3D_ZBUF_SELECT);
+
+ double ux, uy, uz;
+ float depth;
+
+ /* nothing to do */
+ if (!has_zbuf)
+ return true;
+
+ gluProject(co[0], co[1], co[2],
+ viewdata->mats.modelview, viewdata->mats.projection, viewdata->mats.viewport,
+ &ux, &uy, &uz);
+
+ /* check if screen_co is within bounds because brush_cut uses out of screen coords */
+ if (screen_co[0] >= 0 && screen_co[0] < vd->w && screen_co[1] >= 0 && screen_co[1] < vd->h) {
+ BLI_assert(vd && vd->depths);
+ /* we know its not clipped */
+ depth = vd->depths[screen_co[1] * vd->w + screen_co[0]];
+
+ return ((float)uz - 0.00001f <= depth);
+ }
+
+ return false;
+}
+
+bool hair_test_vertex_inside_circle(HairViewData *viewdata, const float mval[2], float radsq, BMVert *v, float *r_dist)
+{
+ float (*obmat)[4] = viewdata->vc.obact->obmat;
+ float co_world[3];
+ float dx, dy, distsq;
+ int screen_co[2];
+
+ mul_v3_m4v3(co_world, obmat, v->co);
+
+ /* TODO, should this check V3D_PROJ_TEST_CLIP_BB too? */
+ if (ED_view3d_project_int_global(viewdata->vc.ar, co_world, screen_co, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK)
+ return false;
+
+ dx = mval[0] - (float)screen_co[0];
+ dy = mval[1] - (float)screen_co[1];
+ distsq = dx * dx + dy * dy;
+
+ if (distsq > radsq)
+ return false;
+
+ if (hair_test_depth(viewdata, v->co, screen_co)) {
+ *r_dist = sqrtf(distsq);
+ return true;
+ }
+ else
+ return false;
+}
+
+bool hair_test_edge_inside_circle(HairViewData *viewdata, const float mval[2], float radsq, BMVert *v1, BMVert *v2, float *r_dist, float *r_lambda)
+{
+ float (*obmat)[4] = viewdata->vc.obact->obmat;
+ float world_co1[3], world_co2[3];
+ float dx, dy, distsq;
+ int screen_co1[2], screen_co2[2], screen_cp[2];
+ float lambda, world_cp[3], screen_cpf[2], screen_co1f[2], screen_co2f[2];
+
+ mul_v3_m4v3(world_co1, obmat, v1->co);
+ mul_v3_m4v3(world_co2, obmat, v2->co);
+
+ /* TODO, should this check V3D_PROJ_TEST_CLIP_BB too? */
+ if (ED_view3d_project_int_global(viewdata->vc.ar, world_co1, screen_co1, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK)
+ return false;
+ if (ED_view3d_project_int_global(viewdata->vc.ar, world_co2, screen_co2, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK)
+ return false;
+
+ screen_co1f[0] = screen_co1[0];
+ screen_co1f[1] = screen_co1[1];
+ screen_co2f[0] = screen_co2[0];
+ screen_co2f[1] = screen_co2[1];
+ lambda = closest_to_line_v2(screen_cpf, mval, screen_co1f, screen_co2f);
+ if (lambda < 0.0f || lambda > 1.0f) {
+ CLAMP(lambda, 0.0f, 1.0f);
+ interp_v2_v2v2(screen_cpf, screen_co1f, screen_co2f, lambda);
+ }
+
+ dx = mval[0] - screen_cpf[0];
+ dy = mval[1] - screen_cpf[1];
+ distsq = dx * dx + dy * dy;
+
+ if (distsq > radsq)
+ return false;
+
+ interp_v3_v3v3(world_cp, world_co1, world_co2, lambda);
+
+ screen_cp[0] = screen_cpf[0];
+ screen_cp[1] = screen_cpf[1];
+ if (hair_test_depth(viewdata, world_cp, screen_cp)) {
+ *r_dist = sqrtf(distsq);
+ *r_lambda = lambda;
+ return true;
+ }
+ else
+ return false;
+}
+
+bool hair_test_vertex_inside_rect(HairViewData *viewdata, rcti *rect, BMVert *v)
+{
+ float (*obmat)[4] = viewdata->vc.obact->obmat;
+ float co_world[3];
+ int screen_co[2];
+
+ mul_v3_m4v3(co_world, obmat, v->co);
+
+ /* TODO, should this check V3D_PROJ_TEST_CLIP_BB too? */
+ if (ED_view3d_project_int_global(viewdata->vc.ar, co_world, screen_co, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK)
+ return false;
+
+ if (!BLI_rcti_isect_pt_v(rect, screen_co))
+ return false;
+
+ if (hair_test_depth(viewdata, v->co, screen_co))
+ return true;
+ else
+ return false;
+}
+
+bool hair_test_vertex_inside_lasso(HairViewData *viewdata, const int mcoords[][2], short moves, BMVert *v)
+{
+ float (*obmat)[4] = viewdata->vc.obact->obmat;
+ float co_world[3];
+ int screen_co[2];
+
+ mul_v3_m4v3(co_world, obmat, v->co);
+
+ /* TODO, should this check V3D_PROJ_TEST_CLIP_BB too? */
+ if (ED_view3d_project_int_global(viewdata->vc.ar, co_world, screen_co, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK)
+ return false;
+
+ if (!BLI_lasso_is_point_inside(mcoords, moves, screen_co[0], screen_co[1], IS_CLIPPED))
+ return false;
+
+ if (hair_test_depth(viewdata, v->co, screen_co))
+ return true;
+ else
+ return false;
+}
+
+/* ------------------------------------------------------------------------- */
+
+typedef void (*VertexToolCb)(HairToolData *data, void *userdata, BMVert *v, float factor);
+
+/* apply tool directly to each vertex inside the filter area */
+static int UNUSED_FUNCTION(hair_tool_apply_vertex)(HairToolData *data, VertexToolCb cb, void *userdata)
+{
+ Scene *scene = data->scene;
+ Brush *brush = data->settings->brush;
+ const float rad = BKE_brush_size_get(scene, brush);
+ const float radsq = rad*rad;
+ const float threshold = 0.0f; /* XXX could be useful, is it needed? */
+ const bool use_mirror = hair_use_mirror_x(data->ob);
+
+ BMVert *v, *v_mirr;
+ BMIter iter;
+ int tot = 0;
+ float dist, factor;
+
+ if (use_mirror)
+ ED_strands_mirror_cache_begin(data->edit, 0, false, false, hair_use_mirror_topology(data->ob));
+
+ BM_ITER_MESH(v, &iter, data->edit->bm, BM_VERTS_OF_MESH) {
+ if (!hair_test_vertex_inside_circle(&data->viewdata, data->mval, radsq, v, &dist))
+ continue;
+
+ factor = 1.0f - dist / rad;
+ if (factor > threshold) {
+ cb(data, userdata, v, factor);
+ ++tot;
+
+ if (use_mirror) {
+ v_mirr = ED_strands_mirror_get(data->edit, v);
+ if (v_mirr)
+ cb(data, userdata, v_mirr, factor);
+ }
+ }
+ }
+
+ /* apply mirror */
+ if (use_mirror)
+ ED_strands_mirror_cache_end(data->edit);
+
+ return tot;
+}
+
+/* ------------------------------------------------------------------------- */
+
+typedef void (*EdgeToolCb)(HairToolData *data, void *userdata, BMVert *v1, BMVert *v2, float factor, float edge_param);
+
+static int hair_tool_apply_strand_edges(HairToolData *data, EdgeToolCb cb, void *userdata, BMVert *root)
+{
+ Scene *scene = data->scene;
+ Brush *brush = data->settings->brush;
+ const float rad = BKE_brush_size_get(scene, brush);
+ const float radsq = rad*rad;
+ const float threshold = 0.0f; /* XXX could be useful, is it needed? */
+ const bool use_mirror = hair_use_mirror_x(data->ob);
+
+ BMVert *v, *vprev, *v_mirr, *vprev_mirr;
+ BMIter iter;
+ int k;
+ int tot = 0;
+
+ BM_ITER_STRANDS_ELEM_INDEX(v, &iter, root, BM_VERTS_OF_STRAND, k) {
+ if (k > 0) {
+ float dist, lambda;
+
+ if (hair_test_edge_inside_circle(&data->viewdata, data->mval, radsq, vprev, v, &dist, &lambda)) {
+ float factor = 1.0f - dist / rad;
+ if (factor > threshold) {
+ cb(data, userdata, vprev, v, factor, lambda);
+ ++tot;
+
+ if (use_mirror) {
+ v_mirr = ED_strands_mirror_get(data->edit, v);
+ if (vprev_mirr && v_mirr)
+ cb(data, userdata, vprev_mirr, v_mirr, factor, lambda);
+ }
+ }
+ }
+ }
+
+ vprev = v;
+ vprev_mirr = v_mirr;
+ }
+
+ return tot;
+}
+
+/* apply tool to vertices of edges inside the filter area,
+ * using the closest edge point for weighting
+ */
+static int hair_tool_apply_edge(HairToolData *data, EdgeToolCb cb, void *userdata)
+{
+ BMVert *root;
+ BMIter iter;
+ int tot = 0;
+
+ if (hair_use_mirror_x(data->ob))
+ ED_strands_mirror_cache_begin(data->edit, 0, false, false, hair_use_mirror_topology(data->ob));
+
+ BM_ITER_STRANDS(root, &iter, data->edit->bm, BM_STRANDS_OF_MESH) {
+ tot += hair_tool_apply_strand_edges(data, cb, userdata, root);
+ }
+
+ /* apply mirror */
+ if (hair_use_mirror_x(data->ob))
+ ED_strands_mirror_cache_end(data->edit);
+
+ return tot;
+}
+
+/* ------------------------------------------------------------------------- */
+
+typedef struct CombData {
+ float power;
+} CombData;
+
+static void UNUSED_FUNCTION(hair_vertex_comb)(HairToolData *data, void *userdata, BMVert *v, float factor)
+{
+ CombData *combdata = userdata;
+
+ float combfactor = powf(factor, combdata->power);
+
+ madd_v3_v3fl(v->co, data->delta, combfactor);
+}
+
+/* Edge-based combing tool:
+ * Unlike the vertex tool (which simply displaces vertices), the edge tool
+ * adjusts edge orientations to follow the stroke direction.
+ */
+static void hair_edge_comb(HairToolData *data, void *userdata, BMVert *v1, BMVert *v2, float factor, float UNUSED(edge_param))
+{
+ CombData *combdata = userdata;
+ float strokedir[3], edge[3], edgedir[3], strokelen, edgelen;
+ float edge_proj[3];
+
+ float combfactor = powf(factor, combdata->power);
+ float effect;
+
+ strokelen = normalize_v3_v3(strokedir, data->delta);
+
+ sub_v3_v3v3(edge, v2->co, v1->co);
+ edgelen = normalize_v3_v3(edgedir, edge);
+ if (edgelen == 0.0f)
+ return;
+
+ /* This factor prevents sudden changes in direction with small stroke lengths.
+ * The arctan maps the 0..inf range of the length ratio to 0..1 smoothly.
+ */
+ effect = atan(strokelen / edgelen * 4.0f / (0.5f*M_PI));
+
+ mul_v3_v3fl(edge_proj, strokedir, edgelen);
+
+ interp_v3_v3v3(edge, edge, edge_proj, combfactor * effect);
+
+ add_v3_v3v3(v2->co, v1->co, edge);
+}
+
+
+BLI_INLINE void construct_m4_loc_nor_tan(float mat[4][4], const float loc[3], const float nor[3], const float tang[3])
+{
+ float cotang[3];
+
+ cross_v3_v3v3(cotang, nor, tang);
+
+ copy_v3_v3(mat[0], tang);
+ copy_v3_v3(mat[1], cotang);
+ copy_v3_v3(mat[2], nor);
+ copy_v3_v3(mat[3], loc);
+ mat[0][3] = 0.0f;
+ mat[1][3] = 0.0f;
+ mat[2][3] = 0.0f;
+ mat[3][3] = 1.0f;
+}
+
+static void grow_hair(BMEditStrands *edit, MSurfaceSample *sample)
+{
+ DerivedMesh *dm = edit->root_dm;
+ const float len = 1.5f;
+
+ float root_mat[4][4];
+ BMVert *root, *v;
+ BMIter iter;
+ int i;
+
+ {
+ float co[3], nor[3], tang[3];
+ BKE_mesh_sample_eval(dm, sample, co, nor, tang);
+ construct_m4_loc_nor_tan(root_mat, co, nor, tang);
+ }
+
+ root = BM_strands_create(edit->bm, 5, true);
+
+ BM_elem_meshsample_data_named_set(&edit->bm->vdata, root, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION, sample);
+
+ BM_ITER_STRANDS_ELEM_INDEX(v, &iter, root, BM_VERTS_OF_STRAND, i) {
+ float co[3];
+
+ co[0] = co[1] = 0.0f;
+ co[2] = len * (float)i / (float)(len - 1);
+
+ mul_m4_v3(root_mat, co);
+
+ copy_v3_v3(v->co, co);
+ }
+
+ BM_mesh_elem_index_ensure(edit->bm, BM_ALL);
+}
+
+static bool hair_add_ray_cb(void *vdata, float ray_start[3], float ray_end[3])
+{
+ HairToolData *data = vdata;
+ ViewContext *vc = &data->viewdata.vc;
+
+ ED_view3d_win_to_segment(vc->ar, vc->v3d, data->mval, ray_start, ray_end, true);
+
+ mul_m4_v3(data->imat, ray_start);
+ mul_m4_v3(data->imat, ray_end);
+
+ return true;
+}
+
+static bool hair_get_surface_sample(HairToolData *data, MSurfaceSample *sample)
+{
+ DerivedMesh *dm = data->edit->root_dm;
+
+ MSurfaceSampleStorage dst;
+ int tot;
+
+ BKE_mesh_sample_storage_single(&dst, sample);
+ tot = BKE_mesh_sample_generate_raycast(&dst, dm, hair_add_ray_cb, data, 1);
+ BKE_mesh_sample_storage_release(&dst);
+
+ return tot > 0;
+}
+
+static bool hair_add(HairToolData *data)
+{
+ MSurfaceSample sample;
+
+ if (!hair_get_surface_sample(data, &sample))
+ return false;
+
+ grow_hair(data->edit, &sample);
+
+ return true;
+}
+
+
+bool hair_brush_step(HairToolData *data)
+{
+ Brush *brush = data->settings->brush;
+ BrushHairTool hair_tool = brush->hair_tool;
+ BMEditStrands *edit = data->edit;
+ int tot = 0;
+
+ switch (hair_tool) {
+ case HAIR_TOOL_COMB: {
+ CombData combdata;
+ combdata.power = (brush->alpha - 0.5f) * 2.0f;
+ if (combdata.power < 0.0f)
+ combdata.power = 1.0f - 9.0f * combdata.power;
+ else
+ combdata.power = 1.0f - combdata.power;
+
+ /*tot = hair_tool_apply_vertex(data, hair_vertex_comb, &combdata);*/ /* UNUSED */
+ tot = hair_tool_apply_edge(data, hair_edge_comb, &combdata);
+ break;
+ }
+ case HAIR_TOOL_CUT:
+ break;
+ case HAIR_TOOL_LENGTH:
+ break;
+ case HAIR_TOOL_PUFF:
+ break;
+ case HAIR_TOOL_ADD:
+ if (hair_add(data))
+ edit->flag |= BM_STRANDS_DIRTY_SEGLEN;
+ break;
+ case HAIR_TOOL_SMOOTH:
+ break;
+ case HAIR_TOOL_WEIGHT:
+ break;
+ }
+
+ return tot > 0;
+}
diff --git a/source/blender/editors/hair/hair_undo.c b/source/blender/editors/hair/hair_undo.c
new file mode 100644
index 00000000000..a58b9c042f8
--- /dev/null
+++ b/source/blender/editors/hair/hair_undo.c
@@ -0,0 +1,190 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/hair/hair_undo.c
+ * \ingroup edhair
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_context.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_editstrands.h"
+#include "BKE_key.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_sample.h"
+
+#include "ED_physics.h"
+#include "ED_util.h"
+
+#include "bmesh.h"
+
+#include "hair_intern.h"
+
+static void *strands_get_edit(bContext *C)
+{
+ Object *obact = CTX_data_active_object(C);
+ const int mode_flag = OB_MODE_HAIR_EDIT;
+ const bool is_mode_set = ((obact->mode & mode_flag) != 0);
+
+ if (obact && is_mode_set) {
+ BMEditStrands *edit = BKE_editstrands_from_object(obact);
+ return edit;
+ }
+ return NULL;
+}
+
+typedef struct UndoStrands {
+ Mesh me; /* Mesh supports all the customdata we need, easiest way to implement undo storage */
+ int selectmode;
+
+ /** \note
+ * this isn't a prefect solution, if you edit keys and change shapes this works well (fixing [#32442]),
+ * but editing shape keys, going into object mode, removing or changing their order,
+ * then go back into editmode and undo will give issues - where the old index will be out of sync
+ * with the new object index.
+ *
+ * There are a few ways this could be made to work but for now its a known limitation with mixing
+ * object and editmode operations - Campbell */
+ int shapenr;
+} UndoStrands;
+
+/* undo simply makes copies of a bmesh */
+static void *strands_edit_to_undo(void *editv, void *UNUSED(obdata))
+{
+ BMEditStrands *edit = editv;
+// Mesh *obme = obdata;
+
+ UndoStrands *undo = MEM_callocN(sizeof(UndoStrands), "undo Strands");
+
+ /* make sure shape keys work */
+// um->me.key = obme->key ? BKE_key_copy_nolib(obme->key) : NULL;
+
+ /* BM_mesh_validate(em->bm); */ /* for troubleshooting */
+
+ BM_mesh_bm_to_me_ex(edit->bm, &undo->me, CD_MASK_STRANDS, false);
+
+ undo->selectmode = edit->bm->selectmode;
+ undo->shapenr = edit->bm->shapenr;
+
+ return undo;
+}
+
+static void strands_undo_to_edit(void *undov, void *editv, void *UNUSED(obdata))
+{
+ UndoStrands *undo = undov;
+ BMEditStrands *edit = editv, *edit_tmp;
+ Object *ob = edit->ob;
+ DerivedMesh *dm = edit->root_dm;
+ BMesh *bm;
+// Key *key = ((Mesh *) obdata)->key;
+
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&undo->me);
+
+ edit->bm->shapenr = undo->shapenr;
+
+ bm = BM_mesh_create(&allocsize);
+ BM_mesh_bm_from_me_ex(bm, &undo->me, CD_MASK_STRANDS_BMESH, false, false, undo->shapenr);
+
+ /* note: have to create the new edit before freeing the old one,
+ * because it owns the root_dm and we have to copy it before
+ * it gets released when freeing the old edit.
+ */
+ edit_tmp = BKE_editstrands_create(bm, dm, NULL);
+ BKE_editstrands_free(edit);
+ *edit = *edit_tmp;
+
+ bm->selectmode = undo->selectmode;
+ edit->ob = ob;
+
+#if 0
+ /* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens
+ * if the active is a basis for any other. */
+ if (key && (key->type == KEY_RELATIVE)) {
+ /* Since we can't add, remove or reorder keyblocks in editmode, it's safe to assume
+ * shapenr from restored bmesh and keyblock indices are in sync. */
+ const int kb_act_idx = ob->shapenr - 1;
+
+ /* If it is, let's patch the current mesh key block to its restored value.
+ * Else, the offsets won't be computed and it won't matter. */
+ if (BKE_keyblock_is_basis(key, kb_act_idx)) {
+ KeyBlock *kb_act = BLI_findlink(&key->block, kb_act_idx);
+
+ if (kb_act->totelem != undo->me.totvert) {
+ /* The current mesh has some extra/missing verts compared to the undo, adjust. */
+ MEM_SAFE_FREE(kb_act->data);
+ kb_act->data = MEM_mallocN((size_t)(key->elemsize * bm->totvert), __func__);
+ kb_act->totelem = undo->me.totvert;
+ }
+
+ BKE_keyblock_update_from_mesh(&undo->me, kb_act);
+ }
+ }
+#endif
+
+ ob->shapenr = undo->shapenr;
+
+ MEM_freeN(edit_tmp);
+}
+
+static void strands_free_undo(void *undov)
+{
+ UndoStrands *undo = undov;
+
+ if (undo->me.key) {
+ BKE_key_free(undo->me.key);
+ MEM_freeN(undo->me.key);
+ }
+
+ BKE_mesh_free(&undo->me, false);
+ MEM_freeN(undo);
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_strands(bContext *C, const char *name)
+{
+ /* edit->ob gets out of date and crashes on mesh undo,
+ * this is an easy way to ensure its OK
+ * though we could investigate the matter further. */
+ Object *obact = CTX_data_active_object(C);
+ BMEditStrands *edit = BKE_editstrands_from_object(obact);
+ if (edit) {
+ edit->ob = obact;
+
+ undo_editmode_push(C, name, CTX_data_active_object, strands_get_edit, strands_free_undo, strands_undo_to_edit, strands_edit_to_undo, NULL);
+ }
+}
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index 4dc39681ed2..7292e8b171f 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -89,6 +89,9 @@ void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments
*/
void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments);
+
+void glutil_draw_filled_arc_part(float start, float angle, float radius, float radius_inn, int nsegments);
+
/**
* Returns an integer value as obtained by glGetIntegerv.
* The param must cause only one value to be gotten from GL.
@@ -155,7 +158,8 @@ void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int ty
* only RGBA
* needs glaDefine2DArea to be set.
*/
-void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect);
+void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format,
+ int type, int zoomfilter, float alpha, void *rect);
void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY);
@@ -181,8 +185,8 @@ typedef struct gla2DDrawInfo gla2DDrawInfo;
#if 0
gla2DDrawInfo *glaBegin2DDraw(struct rcti *screen_rect, struct rctf *world_rect);
-void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *sc_x_r, int *sc_y_r);
-void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int screen_r[2]);
+void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *r_sc_x, int *r_sc_y);
+void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int r_screen[2]);
void glaEnd2DDraw(gla2DDrawInfo *di);
@@ -217,12 +221,12 @@ void bgl_get_mats(bglMats *mats);
/* **** Color management helper functions for GLSL display/transform ***** */
/* Draw imbuf on a screen, preferably using GLSL display transform */
-void glaDrawImBuf_glsl(struct ImBuf *ibuf, float x, float y, int zoomfilter,
+void glaDrawImBuf_glsl(struct ImBuf *ibuf, float x, float y, int zoomfilter, float alpha,
struct ColorManagedViewSettings *view_settings,
struct ColorManagedDisplaySettings *display_settings);
/* Draw imbuf on a screen, preferably using GLSL display transform */
-void glaDrawImBuf_glsl_ctx(const struct bContext *C, struct ImBuf *ibuf, float x, float y, int zoomfilter);
+void glaDrawImBuf_glsl_ctx(const struct bContext *C, struct ImBuf *ibuf, float x, float y, int zoomfilter, float alpha);
void glaDrawBorderCorners(const struct rcti *border, float zoomx, float zoomy);
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 50581429700..dfa667d095a 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -49,7 +49,6 @@ struct Object;
struct bDopeSheet;
struct bAction;
-struct bActionGroup;
struct FCurve;
struct FModifier;
@@ -115,13 +114,17 @@ typedef struct bAnimListElem {
int flag; /* copy of elem's flags for quick access */
int index; /* for un-named data, the index of the data in its collection */
- short update; /* (eAnim_Update_Flags) tag the element for updating */
+ char update; /* (eAnim_Update_Flags) tag the element for updating */
+ char tag; /* tag the included data. Temporary always */
+
short datatype; /* (eAnim_KeyType) type of motion data to expect */
void *key_data; /* motion data - mostly F-Curves, but can be other types too */
struct ID *id; /* ID block that channel is attached to */
struct AnimData *adt; /* source of the animation data attached to ID block (for convenience) */
+
+ void *owner; /* for per-element F-Curves (e.g. NLA Control Curves), the element that this represents (e.g. NlaStrip) */
} bAnimListElem;
@@ -141,6 +144,9 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_GROUP,
ANIMTYPE_FCURVE,
+ ANIMTYPE_NLACONTROLS,
+ ANIMTYPE_NLACURVE,
+
ANIMTYPE_FILLACTD,
ANIMTYPE_FILLDRIVERS,
@@ -406,7 +412,8 @@ typedef enum eAnimChannel_Settings {
ACHANNEL_SETTING_EXPAND = 3,
ACHANNEL_SETTING_VISIBLE = 4, /* only for Graph Editor */
ACHANNEL_SETTING_SOLO = 5, /* only for NLA Tracks */
- ACHANNEL_SETTING_PINNED = 6 /* only for NLA Actions */
+ ACHANNEL_SETTING_PINNED = 6, /* only for NLA Actions */
+ ACHANNEL_SETTING_MOD_OFF = 7
} eAnimChannel_Settings;
@@ -450,13 +457,13 @@ typedef struct bAnimChannelType {
/* ------------------------ Drawing API -------------------------- */
/* Get typeinfo for the given channel */
-bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale);
+const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale);
/* Print debugging info about a given channel */
void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level);
/* Draw the given channel */
-void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc);
+void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc, size_t channel_index);
/* Draw the widgets for the given channel */
void ANIM_channel_draw_widgets(const struct bContext *C, bAnimContext *ac, bAnimListElem *ale, struct uiBlock *block, float yminc, float ymaxc, size_t channel_index);
@@ -611,7 +618,7 @@ typedef enum eAnimUnitConv_Flags {
short ANIM_get_normalization_flags(bAnimContext *ac);
/* Get unit conversion factor for given ID + F-Curve */
-float ANIM_unit_mapping_get_factor(struct Scene *scene, struct ID *id, struct FCurve *fcu, short flag);
+float ANIM_unit_mapping_get_factor(struct Scene *scene, struct ID *id, struct FCurve *fcu, short flag, float *r_offset);
/* ------------- Utility macros ----------------------- */
@@ -653,6 +660,7 @@ void ANIM_list_elem_update(struct Scene *scene, bAnimListElem *ale);
/* data -> channels syncing */
void ANIM_sync_animchannels_to_data(const struct bContext *C);
+void ANIM_center_frame(struct bContext *C, int smooth_viewtx);
/* ************************************************* */
/* OPERATORS */
@@ -670,6 +678,14 @@ void ED_operatormacros_graph(void);
void ED_operatormacros_action(void);
/* ************************************************ */
+/* Animation Editor Exports */
+/* XXX: Should we be doing these here, or at all? */
+
+/* Action Editor - Action Management */
+struct AnimData *ED_actedit_animdata_from_context(struct bContext *C);
+void ED_animedit_unlink_action(struct bContext *C, struct ID *id, struct AnimData *adt, struct bAction *act, struct ReportList *reports);
+
+/* ************************************************ */
#endif /* __ED_ANIM_API_H__ */
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index b08cc12dc3e..35bb12ddaad 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -39,16 +39,12 @@ struct Base;
struct bContext;
struct Bone;
struct bPoseChannel;
-struct DerivedMesh;
struct IDProperty;
struct ListBase;
struct MeshDeformModifierData;
struct Object;
-struct RegionView3D;
struct ReportList;
struct Scene;
-struct SK_Sketch;
-struct View3D;
struct ViewContext;
struct wmKeyConfig;
struct wmOperator;
@@ -59,8 +55,6 @@ typedef struct EditBone {
struct EditBone *parent; /* Editbones have a one-way link (i.e. children refer
* to parents. This is converted to a two-way link for
* normal bones when leaving editmode. */
- void *temp; /* Used to store temporary data */
-
char name[64]; /* MAXBONENAME */
float roll; /* Roll along axis. We'll ultimately use the axis/angle method
* for determining the transformation matrix of the bone. The axis
@@ -83,6 +77,14 @@ typedef struct EditBone {
float oldlength; /* for envelope scaling */
short segments;
+
+ /* Used to store temporary data */
+ union {
+ struct EditBone *ebone;
+ struct Bone *bone;
+ void *p;
+ int i;
+ } temp;
} EditBone;
#define BONESEL_ROOT (1 << 28)
@@ -119,10 +121,12 @@ void ED_keymap_armature(struct wmKeyConfig *keyconf);
void ED_armature_from_edit(struct bArmature *arm);
void ED_armature_to_edit(struct bArmature *arm);
void ED_armature_edit_free(struct bArmature *arm);
-void ED_armature_deselect_all(struct Object *obedit, int toggle);
+void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb);
+
+void ED_armature_deselect_all(struct Object *obedit);
void ED_armature_deselect_all_visible(struct Object *obedit);
-int ED_do_pose_selectbuffer(struct Scene *scene, struct Base *base, unsigned int *buffer,
+int ED_do_pose_selectbuffer(struct Scene *scene, struct Base *base, unsigned int *buffer,
short hits, bool extend, bool deselect, bool toggle, bool do_nearest);
bool mouse_armature(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
int join_armature_exec(struct bContext *C, struct wmOperator *op);
diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h
index 64c16605dec..9a987d7618c 100644
--- a/source/blender/editors/include/ED_buttons.h
+++ b/source/blender/editors/include/ED_buttons.h
@@ -37,4 +37,6 @@ bool ED_texture_context_check_particles(const struct bContext *C);
bool ED_texture_context_check_linestyle(const struct bContext *C);
bool ED_texture_context_check_others(const struct bContext *C);
+void ED_buttons_id_unref(struct SpaceButs *sbuts, const struct ID *id);
+
#endif /* __ED_BUTTONS_H__ */
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 27e9cad4fd5..fee3d44b8eb 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -31,13 +31,10 @@
#ifndef __ED_CURVE_H__
#define __ED_CURVE_H__
-struct Base;
struct bContext;
struct Nurb;
struct Object;
-struct Scene;
struct Text;
-struct View3D;
struct wmOperator;
struct wmKeyConfig;
struct Curve;
@@ -79,7 +76,7 @@ void free_editText(struct Object *obedit);
void ED_text_to_object(struct bContext *C, struct Text *text, const bool split_lines);
-bool ED_curve_select_nth(struct Curve *cu, int nth);
+bool ED_curve_select_nth(struct Curve *cu, int nth, int skip, int offset);
void ED_curve_beztcpy(struct EditNurb *editnurb, struct BezTriple *dst, struct BezTriple *src, int count);
void ED_curve_bpcpy(struct EditNurb *editnurb, struct BPoint *dst, struct BPoint *src, int count);
diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h
index 661ab58b98c..5e2c6bb8c44 100644
--- a/source/blender/editors/include/ED_datafiles.h
+++ b/source/blender/editors/include/ED_datafiles.h
@@ -165,6 +165,27 @@ extern char datatoc_twist_png[];
extern int datatoc_vertexdraw_png_size;
extern char datatoc_vertexdraw_png[];
+extern int datatoc_haircomb_png_size;
+extern char datatoc_haircomb_png[];
+
+extern int datatoc_haircut_png_size;
+extern char datatoc_haircut_png[];
+
+extern int datatoc_hairlength_png_size;
+extern char datatoc_hairlength_png[];
+
+extern int datatoc_hairpuff_png_size;
+extern char datatoc_hairpuff_png[];
+
+extern int datatoc_hairadd_png_size;
+extern char datatoc_hairadd_png[];
+
+extern int datatoc_hairsmooth_png_size;
+extern char datatoc_hairsmooth_png[];
+
+extern int datatoc_hairweight_png_size;
+extern char datatoc_hairweight_png[];
+
/* Matcap files */
extern int datatoc_mc01_jpg_size;
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index c4f08ca4775..448f2c83aad 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -33,19 +33,15 @@
struct ID;
struct ListBase;
struct bContext;
-struct bScreen;
struct ScrArea;
struct ARegion;
struct View3D;
-struct SpaceNode;
-struct SpaceSeq;
struct Object;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
struct PointerRNA;
-struct ImBuf;
struct wmKeyConfig;
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 704876e1261..f49d4b508c6 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -31,13 +31,11 @@
#define __ED_IMAGE_H__
struct SpaceImage;
-struct Main;
struct bContext;
struct Image;
struct ImageUser;
struct ImBuf;
struct ToolSettings;
-struct uiBlock;
struct wmWindowManager;
struct ARegion;
struct Scene;
@@ -49,7 +47,7 @@ struct Mask *ED_space_image_get_mask(struct SpaceImage *sima);
void ED_space_image_set_mask(struct bContext *C, struct SpaceImage *sima, struct Mask *mask);
bool ED_space_image_color_sample(struct Scene *scene, struct SpaceImage *sima, struct ARegion *ar, int mval[2], float r_col[3]);
-struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **lock_r);
+struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock);
void ED_space_image_release_buffer(struct SpaceImage *sima, struct ImBuf *ibuf, void *lock);
bool ED_space_image_has_buffer(struct SpaceImage *sima);
diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h
index 0359153317b..7d163da0db0 100644
--- a/source/blender/editors/include/ED_keyframes_draw.h
+++ b/source/blender/editors/include/ED_keyframes_draw.h
@@ -34,7 +34,6 @@
struct bAnimContext;
struct AnimData;
-struct BezTriple;
struct FCurve;
struct bDopeSheet;
struct bAction;
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index adf82acb399..92375cbbbcf 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -261,7 +261,7 @@ bool delete_fcurve_keys(struct FCurve *fcu);
void clear_fcurve_keys(struct FCurve *fcu);
void duplicate_fcurve_keys(struct FCurve *fcu);
-void clean_fcurve(struct FCurve *fcu, float thresh);
+void clean_fcurve(struct bAnimContext *ac, struct bAnimListElem *ale, float thresh, bool cleardefault);
void smooth_fcurve(struct FCurve *fcu);
void sample_fcurve(struct FCurve *fcu);
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index e5b5e79875d..5d76c9e0f6f 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -46,10 +46,8 @@ struct FCurve;
struct BezTriple;
struct bPoseChannel;
-struct bConstraint;
struct bContext;
-struct wmOperatorType;
struct ReportList;
struct PointerRNA;
diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h
index 6636319dc9b..6fe1524cb6d 100644
--- a/source/blender/editors/include/ED_lattice.h
+++ b/source/blender/editors/include/ED_lattice.h
@@ -32,7 +32,6 @@
#define __ED_LATTICE_H__
struct Object;
-struct Lattice;
void free_editLatt(struct Object *ob);
void make_editLatt(struct Object *obedit);
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index 97fd553ea19..1611276ca70 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -34,7 +34,6 @@
struct wmKeyConfig;
struct MaskLayer;
struct MaskLayerShape;
-struct wmEvent;
/* mask_edit.c */
void ED_mask_get_size(struct ScrArea *sa, int *width, int *height);
diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h
index 5e774c63841..05a4ccabd1b 100644
--- a/source/blender/editors/include/ED_mball.h
+++ b/source/blender/editors/include/ED_mball.h
@@ -32,7 +32,6 @@
#define __ED_MBALL_H__
struct bContext;
-struct MetaBall;
struct Object;
struct wmKeyConfig;
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index b144fd27902..7b66bf5cbb0 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -41,39 +41,27 @@ struct ARegion;
struct bContext;
struct bFaceMap;
struct wmOperator;
-struct wmWindowManager;
struct wmKeyConfig;
struct ReportList;
-struct EditSelection;
struct ViewContext;
struct bDeformGroup;
-struct MDeformWeight;
struct MDeformVert;
struct Scene;
struct Mesh;
-struct MFace;
-struct MEdge;
-struct MVert;
-struct MCol;
struct UvVertMap;
struct UvMapVert;
-struct CustomData;
struct BMEditMesh;
-struct BMEditSelection;
struct BMesh;
struct BMVert;
struct BMLoop;
struct BMBVHTree;
-struct MLoopCol;
struct BMEdge;
struct BMFace;
struct UvVertMap;
struct UvMapVert;
struct ToolSettings;
-struct Material;
struct Object;
struct rcti;
-struct MeshStatVis;
/* editmesh_utils.c */
void EDBM_verts_mirror_cache_begin_ex(struct BMEditMesh *em, const int axis,
@@ -129,7 +117,9 @@ struct MTexPoly *EDBM_mtexpoly_active_get(struct BMEditMesh *em, struct BMFace *
void BM_uv_vert_map_free(struct UvVertMap *vmap);
struct UvMapVert *BM_uv_vert_map_at_index(struct UvVertMap *vmap, unsigned int v);
-struct UvVertMap *BM_uv_vert_map_create(struct BMesh *bm, bool use_select, const float limit[2]);
+struct UvVertMap *BM_uv_vert_map_create(
+ struct BMesh *bm,
+ const float limit[2], const bool use_select, const bool use_winding);
void EDBM_flag_enable_all(struct BMEditMesh *em, const char hflag);
void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag);
@@ -150,9 +140,27 @@ bool EDBM_backbuf_border_mask_init(struct ViewContext *vc, const int mcords[][2]
short xmin, short ymin, short xmax, short ymax);
bool EDBM_backbuf_circle_init(struct ViewContext *vc, short xs, short ys, short rads);
-struct BMVert *EDBM_vert_find_nearest(struct ViewContext *vc, float *r_dist, const bool sel, const bool strict);
-struct BMEdge *EDBM_edge_find_nearest(struct ViewContext *vc, float *r_dist);
-struct BMFace *EDBM_face_find_nearest(struct ViewContext *vc, float *r_dist);
+struct BMVert *EDBM_vert_find_nearest_ex(
+ struct ViewContext *vc, float *r_dist,
+ const bool use_select_bias, bool use_cycle);
+struct BMVert *EDBM_vert_find_nearest(
+ struct ViewContext *vc, float *r_dist);
+
+struct BMEdge *EDBM_edge_find_nearest_ex(
+ struct ViewContext *vc, float *r_dist,
+ float *r_dist_center,
+ const bool use_select_bias, const bool use_cycle,
+ struct BMEdge **r_eed_zbuf);
+struct BMEdge *EDBM_edge_find_nearest(
+ struct ViewContext *vc, float *r_dist);
+
+struct BMFace *EDBM_face_find_nearest_ex(
+ struct ViewContext *vc, float *r_dist,
+ float *r_dist_center,
+ const bool use_select_bias, const bool use_cycle,
+ struct BMFace **r_efa_zbuf);
+struct BMFace *EDBM_face_find_nearest(
+ struct ViewContext *vc, float *r_dist);
bool EDBM_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 824c82a0069..1445308c485 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -33,7 +33,6 @@
struct ID;
struct Main;
-struct Material;
struct Scene;
struct Tex;
struct bContext;
@@ -104,6 +103,8 @@ void ED_node_set_active(struct Main *bmain, struct bNodeTree *ntree, struct bNod
void ED_node_composite_job(const struct bContext *C, struct bNodeTree *nodetree, struct Scene *scene_owner);
+void ED_node_id_unref(struct SpaceNode *snode, const ID *id);
+
/* node_ops.c */
void ED_operatormacros_node(void);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 295bb752a08..c52174c8f2d 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -35,33 +35,17 @@
extern "C" {
#endif
-struct BMEdge;
-struct BMFace;
-struct BMVert;
-struct BPoint;
struct Base;
-struct BezTriple;
-struct Curve;
-struct EditBone;
struct EnumPropertyItem;
struct ID;
-struct KeyBlock;
-struct Lattice;
struct Main;
-struct Mesh;
-struct MetaElem;
struct ModifierData;
-struct HookModifierData;
-struct Nurb;
struct Object;
struct ReportList;
struct Scene;
-struct View3D;
-struct ViewContext;
struct bConstraint;
struct bContext;
struct bPoseChannel;
-struct wmEvent;
struct wmKeyConfig;
struct wmKeyMap;
struct wmOperator;
@@ -154,8 +138,10 @@ bool ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op, c
bool *enter_editmode, unsigned int *layer, bool *is_view_aligned);
struct Object *ED_object_add_type(
- struct bContext *C, int type, const float loc[3], const float rot[3],
- bool enter_editmode, unsigned int layer) ATTR_RETURNS_NONNULL;
+ struct bContext *C,
+ int type, const char *name, const float loc[3], const float rot[3],
+ bool enter_editmode, unsigned int layer)
+ ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
void ED_object_single_users(struct Main *bmain, struct Scene *scene, const bool full, const bool copy_groups);
void ED_object_single_user(struct Main *bmain, struct Scene *scene, struct Object *ob);
@@ -175,6 +161,9 @@ void ED_object_constraint_set_active(struct Object *ob, struct bConstraint *con)
void ED_object_constraint_update(struct Object *ob);
void ED_object_constraint_dependency_update(struct Main *bmain, struct Object *ob);
+void ED_object_constraint_tag_update(struct Object *ob, struct bConstraint *con);
+void ED_object_constraint_dependency_tag_update(struct Main *bmain, struct Object *ob, struct bConstraint *con);
+
/* object_lattice.c */
bool mouse_lattice(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
void undo_push_lattice(struct bContext *C, const char *name);
diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h
new file mode 100644
index 00000000000..af4af8e2f5d
--- /dev/null
+++ b/source/blender/editors/include/ED_outliner.h
@@ -0,0 +1,36 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ED_outliner.h
+ * \ingroup editors
+ */
+
+#ifndef __ED_OUTLINER_H__
+#define __ED_OUTLINER_H__
+
+struct ID;
+struct SpaceOops;
+
+/* Used to check whether a given texture context is valid in current context. */
+void ED_outliner_id_unref(struct SpaceOops *so, const struct ID *id);
+
+#endif /* __ED_OUTLINER_H__ */
diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h
index decd79fcc7b..e46f4b966c0 100644
--- a/source/blender/editors/include/ED_paint.h
+++ b/source/blender/editors/include/ED_paint.h
@@ -26,7 +26,6 @@
#define __ED_PAINT_H__
struct bContext;
-struct RegionView3D;
struct wmKeyConfig;
struct wmOperator;
@@ -47,9 +46,9 @@ typedef bool (*UndoCleanupCb)(struct bContext *C, struct ListBase *lb);
int ED_undo_paint_step(struct bContext *C, int type, int step, const char *name);
void ED_undo_paint_step_num(struct bContext *C, int type, int num);
-const char *ED_undo_paint_get_name(struct bContext *C, int type, int nr, int *active);
+const char *ED_undo_paint_get_name(struct bContext *C, int type, int nr, bool *r_active);
void ED_undo_paint_free(void);
-int ED_undo_paint_valid(int type, const char *name);
+bool ED_undo_paint_is_valid(int type, const char *name);
bool ED_undo_paint_empty(int type);
void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup);
void ED_undo_paint_push_end(int type);
@@ -59,7 +58,7 @@ void ED_undo_paint_push_end(int type);
void ED_image_undo_restore(struct bContext *C, struct ListBase *lb);
void ED_image_undo_free(struct ListBase *lb);
void ED_imapaint_clear_partial_redraw(void);
-void ED_imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h);
+void ED_imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h, bool find_old);
void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op);
#endif /* __ED_PAINT_H__ */
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index 7c8a2b7b143..26a8563bf52 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -35,10 +35,7 @@
struct bContext;
struct Object;
struct ParticleEditSettings;
-struct ParticleSystem;
-struct RadialControl;
struct rcti;
-struct wmKeyConfig;
struct PTCacheEdit;
struct Scene;
@@ -71,9 +68,9 @@ void PE_undo_push(struct Scene *scene, const char *str);
void PE_undo_step(struct Scene *scene, int step);
void PE_undo(struct Scene *scene);
void PE_redo(struct Scene *scene);
-int PE_undo_valid(struct Scene *scene);
+bool PE_undo_is_valid(struct Scene *scene);
void PE_undo_number(struct Scene *scene, int nr);
-const char *PE_undo_get_name(struct Scene *scene, int nr, int *active);
+const char *PE_undo_get_name(struct Scene *scene, int nr, bool *r_active);
#endif /* __ED_PARTICLE_H__ */
diff --git a/source/blender/editors/include/ED_physics.h b/source/blender/editors/include/ED_physics.h
index 584e9a92bb6..efa852797e1 100644
--- a/source/blender/editors/include/ED_physics.h
+++ b/source/blender/editors/include/ED_physics.h
@@ -35,9 +35,12 @@
struct bContext;
struct ReportList;
struct wmKeyConfig;
+struct ViewContext;
+struct rcti;
struct Scene;
struct Object;
+struct BMEditStrands;
/* particle_edit.c */
int PE_poll(struct bContext *C);
@@ -56,5 +59,28 @@ void ED_rigidbody_constraint_remove(struct Scene *scene, struct Object *ob);
void ED_operatortypes_physics(void);
void ED_keymap_physics(struct wmKeyConfig *keyconf);
+/* hair edit */
+void undo_push_strands(struct bContext *C, const char *name);
+
+void ED_strands_mirror_cache_begin_ex(struct BMEditStrands *edit, const int axis,
+ const bool use_self, const bool use_select,
+ const bool use_topology, float maxdist, int *r_index);
+void ED_strands_mirror_cache_begin(struct BMEditStrands *edit, const int axis,
+ const bool use_self, const bool use_select,
+ const bool use_topology);
+void ED_strands_mirror_apply(struct BMEditStrands *edit, const int sel_from, const int sel_to);
+struct BMVert *ED_strands_mirror_get(struct BMEditStrands *edit, struct BMVert *v);
+struct BMEdge *ED_strands_mirror_get_edge(struct BMEditStrands *edit, struct BMEdge *e);
+void ED_strands_mirror_cache_clear(struct BMEditStrands *edit, struct BMVert *v);
+void ED_strands_mirror_cache_end(struct BMEditStrands *edit);
+
+int ED_hair_mouse_select(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+int ED_hair_border_select(struct bContext *C, struct rcti *rect, bool select, bool extend);
+int ED_hair_circle_select(struct bContext *C, bool select, const int mval[2], float radius);
+int ED_hair_lasso_select(struct bContext *C, const int mcoords[][2], short moves, bool extend, bool select);
+
+void ED_operatortypes_hair(void);
+void ED_keymap_hair(struct wmKeyConfig *keyconf);
+
#endif /* __ED_PHYSICS_H__ */
diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h
index de3843c91eb..ba58ae60b15 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -37,9 +37,6 @@ struct MTex;
struct Render;
struct Scene;
struct ScrArea;
-struct RegionView3D;
-struct RenderEngine;
-struct View3D;
struct wmWindowManager;
/* render_ops.c */
@@ -50,11 +47,12 @@ void ED_operatortypes_render(void);
void ED_render_id_flush_update(struct Main *bmain, struct ID *id);
void ED_render_engine_changed(struct Main *bmain);
-void ED_render_engine_area_exit(struct ScrArea *sa);
+void ED_render_engine_area_exit(struct Main *bmain, struct ScrArea *sa);
void ED_render_scene_update(struct Main *bmain, struct Scene *scene, int updated);
void ED_viewport_render_kill_jobs(struct wmWindowManager *wm, struct Main *bmain, bool free_database);
struct Scene *ED_render_job_get_scene(const struct bContext *C);
+struct Scene *ED_render_job_get_current_scene(const struct bContext *C);
/* Render the preview
*
@@ -62,17 +60,21 @@ struct Scene *ED_render_job_get_scene(const struct bContext *C);
* - PR_BUTS_RENDER: preview is rendered for buttons window
* - PR_ICON_RENDER: preview is rendered for icons. hopefully fast enough for at least 32x32
* - PR_NODE_RENDER: preview is rendered for node editor
+ * - PR_ICON_DEFERRED: No render, we just ensure deferred icon data gets generated.
*/
-#define PR_BUTS_RENDER 0
-#define PR_ICON_RENDER 1
-#define PR_NODE_RENDER 2
+enum {
+ PR_BUTS_RENDER = 0,
+ PR_ICON_RENDER = 1,
+ PR_NODE_RENDER = 2,
+ PR_ICON_DEFERRED = 3,
+};
void ED_preview_init_dbase(void);
void ED_preview_free_dbase(void);
void ED_preview_shader_job(const struct bContext *C, void *owner, struct ID *id, struct ID *parent, struct MTex *slot, int sizex, int sizey, int method);
-void ED_preview_icon_render(struct Scene *scene, struct ID *id, unsigned int *rect, int sizex, int sizey);
+void ED_preview_icon_render(struct Main *bmain, struct Scene *scene, struct ID *id, unsigned int *rect, int sizex, int sizey);
void ED_preview_icon_job(const struct bContext *C, void *owner, struct ID *id, unsigned int *rect, int sizex, int sizey);
void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain);
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 8c33395cc49..aa8e211af38 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -42,7 +42,6 @@ struct wmNotifier;
struct wmEvent;
struct wmKeyConfig;
struct bContext;
-struct SpaceType;
struct Scene;
struct bScreen;
struct ARegion;
@@ -67,16 +66,22 @@ void ED_region_header_init(struct ARegion *ar);
void ED_region_header(const struct bContext *C, struct ARegion *ar);
void ED_region_toggle_hidden(struct bContext *C, struct ARegion *ar);
void ED_region_info_draw(struct ARegion *ar, const char *text, int block, float fill_color[4]);
+void ED_region_image_metadata_draw(int x, int y, struct ImBuf *ibuf, rctf frame, float zoomx, float zoomy);
void ED_region_grid_draw(struct ARegion *ar, float zoomx, float zoomy);
+void ED_region_draw_backdrop_view3d(const struct bContext *C, struct Object *camera, const float alpha,
+ const float width, const float height, const float x, const float y,
+ const float zoomx, const float zoomy, const bool draw_background);
float ED_region_blend_factor(struct ARegion *ar);
void ED_region_visible_rect(struct ARegion *ar, struct rcti *rect);
+int ED_match_area_with_refresh(int spacetype, int refresh);
+int ED_match_region_with_redraws(int spacetype, int regiontype, int redraws);
+
/* spaces */
void ED_spacetypes_keymap(struct wmKeyConfig *keyconf);
int ED_area_header_switchbutton(const struct bContext *C, struct uiBlock *block, int yco);
-
/* areas */
void ED_area_initialize(struct wmWindowManager *wm, struct wmWindow *win, struct ScrArea *sa);
void ED_area_exit(struct bContext *C, struct ScrArea *sa);
@@ -86,6 +91,7 @@ void ED_area_tag_redraw(ScrArea *sa);
void ED_area_tag_redraw_regiontype(ScrArea *sa, int type);
void ED_area_tag_refresh(ScrArea *sa);
void ED_area_do_refresh(struct bContext *C, ScrArea *sa);
+void ED_area_azones_update(ScrArea *sa, const int mouse_xy[]);
void ED_area_headerprint(ScrArea *sa, const char *str);
void ED_area_newspace(struct bContext *C, ScrArea *sa, int type);
void ED_area_prevspace(struct bContext *C, ScrArea *sa);
@@ -113,6 +119,7 @@ void ED_screen_full_prevspace(struct bContext *C, ScrArea *sa);
void ED_screen_full_restore(struct bContext *C, ScrArea *sa);
struct ScrArea *ED_screen_state_toggle(struct bContext *C, struct wmWindow *win, struct ScrArea *sa, const short state);
void ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
+bool ED_screen_stereo3d_required(struct bScreen *screen);
/* anim */
void ED_update_for_newframe(struct Main *bmain, struct Scene *scene, int mute);
@@ -120,6 +127,7 @@ void ED_update_for_newframe(struct Main *bmain, struct Scene *scene, int mute
void ED_refresh_viewport_fps(struct bContext *C);
int ED_screen_animation_play(struct bContext *C, int sync, int mode);
bScreen *ED_screen_animation_playing(const struct wmWindowManager *wm);
+bScreen *ED_screen_animation_no_scrub(const struct wmWindowManager *wm);
/* screen keymaps */
void ED_operatortypes_screen(void);
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index d3b1a824104..6daaac5bb42 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -34,7 +34,6 @@ struct ARegion;
struct bContext;
struct Object;
struct RegionView3D;
-struct Scene;
struct ViewContext;
struct rcti;
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index e26e03473e0..c46780a975a 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -31,15 +31,11 @@
#ifndef __ED_UTIL_H__
#define __ED_UTIL_H__
-struct Scene;
-struct Object;
struct bContext;
-struct ARegion;
-struct uiBlock;
+struct PackedFile;
+struct SpaceLink;
struct wmOperator;
struct wmOperatorType;
-struct BMEditMesh;
-struct Mesh;
/* ed_util.c */
@@ -48,6 +44,8 @@ void ED_editors_exit(struct bContext *C);
bool ED_editors_flush_edits(const struct bContext *C, bool for_render);
+void ED_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id);
+
/* ************** Undo ************************ */
/* undo.c */
@@ -66,10 +64,11 @@ int ED_undo_operator_repeat(struct bContext *C, struct wmOperator *op);
void ED_undo_operator_repeat_cb(struct bContext *C, void *arg_op, void *arg_unused);
void ED_undo_operator_repeat_cb_evt(struct bContext *C, void *arg_op, int arg_unused);
-int ED_undo_valid(const struct bContext *C, const char *undoname);
+bool ED_undo_is_valid(const struct bContext *C, const char *undoname);
/* undo_editmode.c */
void undo_editmode_push(struct bContext *C, const char *name,
+ struct Object *(*get_object)(const struct bContext * C),
void * (*getdata)(struct bContext *C),
void (*freedata)(void *),
void (*to_editmode)(void *, void *, void *),
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 3e8f234e979..535683823bf 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -37,13 +37,11 @@ struct BMFace;
struct BMLoop;
struct Image;
struct ImageUser;
-struct MTFace;
struct MTexPoly;
struct Main;
struct Object;
struct Scene;
struct SpaceImage;
-struct bContext;
struct bNode;
struct wmKeyConfig;
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index ba93e2face1..b84d4099d46 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -62,6 +62,7 @@ struct rcti;
struct wmOperator;
struct wmOperatorType;
struct wmWindow;
+struct wmWindowManager;
struct wmWidget;
struct wmWidgetGroup;
struct wmWidgetGroupType;
@@ -107,7 +108,7 @@ void ED_view3d_lastview_store(struct RegionView3D *rv3d);
/* Depth buffer */
void ED_view3d_depth_update(struct ARegion *ar);
-float ED_view3d_depth_read_cached(struct ViewContext *vc, int x, int y);
+float ED_view3d_depth_read_cached(const struct ViewContext *vc, int x, int y);
void ED_view3d_depth_tag_update(struct RegionView3D *rv3d);
/* Projection */
@@ -222,50 +223,62 @@ void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], floa
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);
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]);
+void ED_view3d_ob_project_mat_get_from_obmat(const struct RegionView3D *rv3d, float obmat[4][4], float pmat[4][4]);
void ED_view3d_unproject(struct bglMats *mats, float out[3], const float x, const float y, const float z);
/* end */
-void ED_view3d_dist_range_get(struct View3D *v3d,
- float r_dist_range[2]);
-bool ED_view3d_clip_range_get(struct View3D *v3d, struct RegionView3D *rv3d,
- float *r_clipsta, float *r_clipend, const bool use_ortho_factor);
-bool ED_view3d_viewplane_get(struct View3D *v3d, struct RegionView3D *rv3d, int winxi, int winyi,
- struct rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize);
+void ED_view3d_dist_range_get(
+ const struct View3D *v3d,
+ float r_dist_range[2]);
+bool ED_view3d_clip_range_get(
+ const struct View3D *v3d, const struct RegionView3D *rv3d,
+ float *r_clipsta, float *r_clipend, const bool use_ortho_factor);
+bool ED_view3d_viewplane_get(
+ const struct View3D *v3d, const struct RegionView3D *rv3d, int winxi, int winyi,
+ struct rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize);
void ED_view3d_polygon_offset(const struct RegionView3D *rv3d, const float dist);
-void ED_view3d_calc_camera_border(struct Scene *scene, struct ARegion *ar,
- struct View3D *v3d, struct RegionView3D *rv3d,
- struct rctf *r_viewborder, const bool no_shift);
-void ED_view3d_calc_camera_border_size(struct Scene *scene, struct ARegion *ar,
- struct View3D *v3d, struct RegionView3D *rv3d,
- float r_size[2]);
+void ED_view3d_calc_camera_border(
+ const struct Scene *scene, const struct ARegion *ar,
+ const struct View3D *v3d, const struct RegionView3D *rv3d,
+ struct rctf *r_viewborder, const bool no_shift);
+void ED_view3d_calc_camera_border_size(
+ const struct Scene *scene, const struct ARegion *ar,
+ const struct View3D *v3d, const struct RegionView3D *rv3d,
+ float r_size[2]);
bool ED_view3d_calc_render_border(struct Scene *scene, struct View3D *v3d,
struct ARegion *ar, struct rcti *rect);
+void ED_view3d_clipping_calc_from_boundbox(float clip[6][4], const struct BoundBox *clipbb, const bool is_flip);
void ED_view3d_clipping_calc(struct BoundBox *bb, float planes[4][4], struct bglMats *mats, const struct rcti *rect);
void ED_view3d_clipping_local(struct RegionView3D *rv3d, float mat[4][4]);
-bool ED_view3d_clipping_test(struct RegionView3D *rv3d, const float co[3], const bool is_local);
+bool ED_view3d_clipping_test(const struct RegionView3D *rv3d, const float co[3], const bool is_local);
void ED_view3d_clipping_set(struct RegionView3D *rv3d);
void ED_view3d_clipping_enable(void);
void ED_view3d_clipping_disable(void);
-float ED_view3d_pixel_size(struct RegionView3D *rv3d, const float co[3]);
+float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]);
-float ED_view3d_radius_to_persp_dist(const float angle, const float radius);
-float ED_view3d_radius_to_ortho_dist(const float lens, const float radius);
+float ED_view3d_radius_to_dist_persp(const float angle, const float radius);
+float ED_view3d_radius_to_dist_ortho(const float lens, const float radius);
+float ED_view3d_radius_to_dist(
+ const struct View3D *v3d, const struct ARegion *ar,
+ const char persp, const bool use_aspect,
+ const float radius);
void drawcircball(int mode, const float cent[3], float rad, float tmat[4][4]);
/* backbuffer select and draw support */
-void view3d_validate_backbuf(struct ViewContext *vc);
-struct ImBuf *view3d_read_backbuf(struct ViewContext *vc, short xmin, short ymin, short xmax, short ymax);
-unsigned int view3d_sample_backbuf_rect(struct ViewContext *vc, const int mval[2], int size,
- unsigned int min, unsigned int max, float *dist, short strict,
- void *handle, bool (*indextest)(void *handle, unsigned int index));
-unsigned int view3d_sample_backbuf(struct ViewContext *vc, int x, int y);
+void ED_view3d_backbuf_validate(struct ViewContext *vc);
+struct ImBuf *ED_view3d_backbuf_read(struct ViewContext *vc, short xmin, short ymin, short xmax, short ymax);
+unsigned int ED_view3d_backbuf_sample_rect(
+ struct ViewContext *vc, const int mval[2], int size,
+ unsigned int min, unsigned int max, float *r_dist);
+int ED_view3d_backbuf_sample_size_clamp(struct ARegion *ar, const float dist);
+unsigned int ED_view3d_backbuf_sample(struct ViewContext *vc, int x, int y);
/* draws and does a 4x4 sample */
bool ED_view3d_autodist(struct Scene *scene, struct ARegion *ar, struct View3D *v3d,
@@ -318,12 +331,13 @@ void ED_view3d_draw_offscreen(
struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int winx, int winy, float viewmat[4][4],
float winmat[4][4], bool do_bgpic, bool do_sky, bool is_persp,
struct GPUOffScreen *ofs,
- struct GPUFX *fx, struct GPUFXSettings *fx_settings);
+ struct GPUFX *fx, struct GPUFXSettings *fx_settings,
+ const char *viewname);
struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey, unsigned int flag,
- bool draw_background, int alpha_mode, char err_out[256]);
+ bool draw_background, int alpha_mode, const char *viewname, char err_out[256]);
struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Scene *scene, struct Object *camera, int width, int height, unsigned int flag, int drawtype,
- bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode, char err_out[256]);
+ bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode, const char *viewname, char err_out[256]);
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, bool do_clip);
@@ -331,17 +345,16 @@ void ED_view3d_update_viewmat(struct Scene *scene, struct View3D *v3d, struct AR
bool ED_view3d_quat_from_axis_view(const char view, float quat[4]);
char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon);
char ED_view3d_lock_view_from_index(int index);
+char ED_view3d_axis_view_opposite(char view);
bool ED_view3d_lock(struct RegionView3D *rv3d);
-uint64_t ED_view3d_datamask(struct Scene *scene, struct View3D *v3d);
-uint64_t ED_view3d_screen_datamask(struct bScreen *screen);
+uint64_t ED_view3d_datamask(const struct Scene *scene, const struct View3D *v3d);
+uint64_t ED_view3d_screen_datamask(const struct bScreen *screen);
-bool ED_view3d_view_lock_check(struct View3D *v3d, struct RegionView3D *rv3d);
-
-bool ED_view3d_offset_lock_check(struct View3D *v3d, struct RegionView3D *rv3d);
+bool ED_view3d_offset_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
/* camera lock functions */
-bool ED_view3d_camera_lock_check(struct View3D *v3d, struct RegionView3D *rv3d);
+bool ED_view3d_camera_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
/* copy the camera to the view before starting a view transformation */
void ED_view3d_camera_lock_init_ex(struct View3D *v3d, struct RegionView3D *rv3d, const bool calc_dist);
void ED_view3d_camera_lock_init(struct View3D *v3d, struct RegionView3D *rv3d);
@@ -384,6 +397,10 @@ int WIDGETGROUP_lamp_poll(const struct bContext *C, struct wmWidgetGroupType *wg
void WIDGETGROUP_lamp_draw(const struct bContext *C, struct wmWidgetGroup *wgroup);
/* render */
+void ED_view3d_stop_render_preview(struct wmWindowManager *wm, struct ARegion *ar);
void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct ScrArea *sa);
+#define V3D_IS_ZBUF(v3d) \
+ (((v3d)->flag & V3D_ZBUF_SELECT) && ((v3d)->drawtype > OB_WIRE))
+
#endif /* __ED_VIEW3D_H__ */
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index bfb7a3420c9..35d5f264ae7 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -979,6 +979,13 @@ DEF_ICON(BRUSH_TEXMASK)
DEF_ICON(BRUSH_THUMB)
DEF_ICON(BRUSH_ROTATE)
DEF_ICON(BRUSH_VERTEXDRAW)
+DEF_ICON(BRUSH_HAIR_COMB)
+DEF_ICON(BRUSH_HAIR_CUT)
+DEF_ICON(BRUSH_HAIR_LENGTH)
+DEF_ICON(BRUSH_HAIR_PUFF)
+DEF_ICON(BRUSH_HAIR_ADD)
+DEF_ICON(BRUSH_HAIR_SMOOTH)
+DEF_ICON(BRUSH_HAIR_WEIGHT)
/* Matcaps */
DEF_ICON(MATCAP_01)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 3716fe74c3f..79a7fc05dc3 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -40,14 +40,11 @@
/* Struct Declarations */
struct ID;
-struct Main;
struct ListBase;
struct ARegion;
-struct ARegionType;
struct ScrArea;
struct wmEvent;
struct wmWindow;
-struct wmWindowManager;
struct wmOperator;
struct AutoComplete;
struct bContext;
@@ -58,23 +55,20 @@ struct PointerRNA;
struct PropertyRNA;
struct ReportList;
struct rcti;
-struct rctf;
struct uiList;
struct uiStyle;
struct uiFontStyle;
struct uiWidgetColors;
-struct ColorBand;
-struct CurveMapping;
struct Image;
struct ImageUser;
struct wmOperatorType;
struct uiWidgetColors;
-struct Tex;
struct MTex;
struct ImBuf;
struct bNodeTree;
struct bNode;
struct bNodeSocket;
+struct CacheLibrary;
struct wmDropBox;
struct wmDrag;
struct wmEvent;
@@ -144,7 +138,6 @@ enum {
#define UI_BLOCK_LIST_ITEM (1 << 19)
#define UI_BLOCK_RADIAL (1 << 20)
-#define UI_BLOCK_DRAGGABLE (1 << 21)
/* uiPopupBlockHandle->menuretval */
#define UI_RETURN_CANCEL (1 << 0) /* cancel all menus cascading */
@@ -184,10 +177,12 @@ enum {
UI_BUT_COLOR_CUBIC = (1 << 23), /* cubic saturation for the color wheel */
UI_BUT_LIST_ITEM = (1 << 24), /* This but is "inside" a list item (currently used to change theme colors). */
UI_BUT_DRAG_MULTI = (1 << 25), /* edit this button as well as the active button (not just dragging) */
- UI_BUT_SCA_LINK_GREY = (1 << 26), /* used to flag if sca links shoud be grey out */
+ UI_BUT_SCA_LINK_GREY = (1 << 26), /* used to flag if sca links shoud be gray out */
UI_BUT_HAS_SEP_CHAR = (1 << 27), /* but->str contains UI_SEP_CHAR, used for key shortcuts */
UI_BUT_TIP_FORCE = (1 << 28), /* force show tooltips when holding option/alt if U's USER_TOOLTIPS is off */
UI_BUT_TEXTEDIT_UPDATE = (1 << 29), /* when widget is in textedit mode, update value on each char stroke */
+ UI_BUT_SEARCH_UNLINK = (1 << 30), /* show unlink for search button */
+ UI_BUT_MENU_ROOT = (1 << 31), /* but is root of a menu */
};
#define UI_PANEL_WIDTH 340
@@ -282,7 +277,6 @@ typedef enum {
UI_BTYPE_WAVEFORM = (49 << 9),
UI_BTYPE_VECTORSCOPE = (50 << 9),
UI_BTYPE_PROGRESS_BAR = (51 << 9),
- UI_BTYPE_SEARCH_MENU_UNLINK = (52 << 9),
UI_BTYPE_NODE_SOCKET = (53 << 9),
UI_BTYPE_SEPR = (54 << 9),
UI_BTYPE_SEPR_LINE = (55 << 9),
@@ -329,6 +323,11 @@ void UI_draw_safe_areas(
#define UI_SCROLL_NO_OUTLINE (1 << 2)
void UI_draw_widget_scroll(struct uiWidgetColors *wcol, const struct rcti *rect, const struct rcti *slider, int state);
+/* Shortening string helper. */
+float UI_text_clip_middle_ex(
+ struct uiFontStyle *fstyle, char *str, float okwidth, const float minwidth,
+ const size_t max_len, const char rpart_sep);
+
/* Callbacks
*
* UI_block_func_handle_set/ButmFunc are for handling events through a callback.
@@ -406,7 +405,7 @@ void UI_popup_block_invoke_ex(struct bContext *C, uiBlockCreateFunc func, void *
void UI_popup_block_ex(struct bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg);
/* void uiPupBlockOperator(struct bContext *C, uiBlockCreateFunc func, struct wmOperator *op, int opcontext); */ /* UNUSED */
-void UI_popup_block_close(struct bContext *C, uiBlock *block);
+void UI_popup_block_close(struct bContext *C, struct wmWindow *win, uiBlock *block);
/* Blocks
*
@@ -493,6 +492,14 @@ bool UI_but_active_only(const struct bContext *C, struct ARegion *ar, uiBlock
void UI_but_execute(const struct bContext *C, uiBut *but);
+bool UI_but_online_manual_id(
+ const uiBut *but,
+ char *r_str, size_t maxlength)
+ ATTR_WARN_UNUSED_RESULT;
+bool UI_but_online_manual_id_from_active(
+ const struct bContext *C,
+ char *r_str, size_t maxlength)
+ ATTR_WARN_UNUSED_RESULT;
/* Buttons
*
@@ -685,6 +692,7 @@ void UI_but_func_drawextra_set(
void *arg1, void *arg2);
void UI_but_func_tooltip_set(uiBut *but, uiButToolTipFunc func, void *argN);
+void UI_but_tooltip_timer_remove(struct bContext *C, uiBut *but);
bool UI_textbutton_activate_rna(const struct bContext *C, struct ARegion *ar,
const void *rna_poin_data, const char *rna_prop_id);
@@ -742,7 +750,7 @@ void UI_panel_category_draw_all(struct ARegion *ar, const
* as screen/ if ED_KEYMAP_UI is set, or internally in popup functions. */
void UI_region_handlers_add(struct ListBase *handlers);
-void UI_popup_handlers_add(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *popup, const bool accept_dbl_click);
+void UI_popup_handlers_add(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *popup, const char flag);
void UI_popup_handlers_remove(struct ListBase *handlers, uiPopupBlockHandle *popup);
void UI_popup_handlers_remove_all(struct bContext *C, struct ListBase *handlers);
@@ -824,8 +832,6 @@ enum {
uiLayout *UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, struct uiStyle *style);
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout);
void UI_block_layout_resolve(uiBlock *block, int *x, int *y);
-void uiLayoutSubblockBegin(uiLayout *layout, const char *identifier);
-void uiLayoutSubblockEnd(uiLayout *layout);
uiBlock *uiLayoutGetBlock(uiLayout *layout);
@@ -887,7 +893,7 @@ uiLayout *uiTemplateConstraint(uiLayout *layout, struct PointerRNA *ptr);
void uiTemplatePreview(uiLayout *layout, struct bContext *C, struct ID *id, int show_buttons, struct ID *parent,
struct MTex *slot, const char *preview_id);
void uiTemplateColorRamp(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int expand);
-void uiTemplateIconView(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
+void uiTemplateIconView(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int show_labels);
void uiTemplateHistogram(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
void uiTemplateWaveform(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
void uiTemplateVectorscope(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
@@ -901,6 +907,9 @@ void uiTemplateGameStates(uiLayout *layout, struct PointerRNA *ptr, const char *
PointerRNA *used_ptr, const char *used_propname, int active_state);
void uiTemplateImage(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr, int compact);
void uiTemplateImageSettings(uiLayout *layout, struct PointerRNA *imfptr, int color_management);
+void uiTemplateImageStereo3d(uiLayout *layout, struct PointerRNA *stereo3d_format_ptr);
+void uiTemplateImageViews(uiLayout *layout, struct PointerRNA *imaptr);
+void uiTemplateImageFormatViews(uiLayout *layout, PointerRNA *imfptr, PointerRNA *ptr);
void uiTemplateImageLayers(uiLayout *layout, struct bContext *C, struct Image *ima, struct ImageUser *iuser);
void uiTemplateImageInfo(uiLayout *layout, struct bContext *C, Image *ima, ImageUser *iuser);
void uiTemplateRunningJobs(uiLayout *layout, struct bContext *C);
@@ -912,6 +921,8 @@ void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr);
void uiTemplateComponentMenu(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name);
void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float *color);
+uiLayout *uiTemplateCacheLibraryItem(uiLayout *layout, struct bContext *C, struct CacheLibrary *cachelib,
+ struct Object *ob, int type, int index, int enabled);
/* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */
#define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list"
@@ -976,6 +987,10 @@ void ED_button_operatortypes(void);
void UI_drop_color_copy(struct wmDrag *drag, struct wmDropBox *drop);
int UI_drop_color_poll(struct bContext *C, struct wmDrag *drag, const struct wmEvent *event);
+bool UI_context_copy_to_selected_list(
+ struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop,
+ struct ListBase *r_lb, bool *r_use_path_from_id, char **r_path);
+
/* Helpers for Operators */
uiBut *UI_context_active_but_get(const struct bContext *C);
void UI_context_active_but_prop_get(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index);
@@ -1026,9 +1041,6 @@ void UI_butstore_register(uiButStore *bs_handle, uiBut **but_p);
bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src);
void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p);
-/* UI_subblock_ helplers */
-bool UI_subblock_is_dragging(uiBlock *block);
-
/* Float precision helpers */
#define UI_PRECISION_FLOAT_MAX 7
diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h
index 74927428363..634dd3d5bbc 100644
--- a/source/blender/editors/include/UI_interface_icons.h
+++ b/source/blender/editors/include/UI_interface_icons.h
@@ -34,12 +34,6 @@
struct bContext;
struct ID;
-struct Image;
-struct ImBuf;
-struct World;
-struct Tex;
-struct Lamp;
-struct Material;
struct PreviewImage;
struct PointerRNA;
@@ -55,7 +49,7 @@ typedef struct IconFile {
#define ICON_DEFAULT_HEIGHT_SCALE ((int)(UI_UNIT_Y * 0.8f))
#define ICON_DEFAULT_WIDTH_SCALE ((int)(UI_UNIT_X * 0.8f))
-#define PREVIEW_DEFAULT_HEIGHT 96
+#define PREVIEW_DEFAULT_HEIGHT 128
/*
* Resizable Icons for Blender
@@ -70,7 +64,7 @@ void UI_id_icon_render(
void UI_icon_draw(float x, float y, int icon_id);
void UI_icon_draw_preview(float x, float y, int icon_id);
void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect);
-void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, int size);
+void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, float alpha, int size);
void UI_icon_draw_aspect(float x, float y, int icon_id, float aspect, float alpha);
void UI_icon_draw_aspect_color(float x, float y, int icon_id, float aspect, const float rgb[3]);
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 4a6d9911d3b..2b19b6180e5 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -294,14 +294,16 @@ enum {
TH_INFO_DEBUG_TEXT,
TH_VIEW_OVERLAY,
- TH_V3D_CLIPPING_BORDER
+ TH_V3D_CLIPPING_BORDER,
+
+ TH_METADATA_BG,
+ TH_METADATA_TEXT
};
/* XXX WARNING: previous is saved in file, so do not change order! */
/* specific defines per space should have higher define values */
struct bTheme;
-struct PointerRNA;
struct bThemeState {
struct bTheme *theme;
@@ -361,6 +363,9 @@ void UI_GetColorPtrBlendShade3ubv(const unsigned char cp1[3], const unsigned
// clear the openGL ClearColor using the input colorid
void UI_ThemeClearColor(int colorid);
+// clear the openGL ClearColor using the input colorid using optional transparency
+void UI_ThemeClearColorAlpha(int colorid, float alpha);
+
// internal (blender) usage only, for init and set active
void UI_SetTheme(int spacetype, int regionid);
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index 4d7446a7a81..2c8f5f6590a 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -233,7 +233,6 @@ void ED_keymap_view2d(struct wmKeyConfig *keyconf);
void UI_view2d_smooth_view(struct bContext *C, struct ARegion *ar,
const struct rctf *cur, const int smooth_viewtx);
-
#define UI_MARKER_MARGIN_Y (42 * UI_DPI_FAC)
#endif /* __UI_VIEW2D_H__ */
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 2056269144e..e045db8fdd2 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -37,6 +37,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
@@ -82,11 +83,11 @@
#define B_NOP -1
-/*
- * a full doc with API notes can be found in bf-blender/trunk/blender/doc/guides/interface_API.txt
+/**
+ * a full doc with API notes can be found in 'blender/doc/guides/interface_API.txt'
*
- * uiBlahBlah() external function
- * ui_blah_blah() internal function
+ * `uiBlahBlah()` external function.
+ * `ui_blah_blah()` internal function.
*/
static void ui_but_free(const bContext *C, uiBut *but);
@@ -513,7 +514,7 @@ static void ui_draw_links(uiBlock *block)
uiBut *but;
uiLinkLine *line;
- /* Draw the grey out lines. Do this first so they appear at the
+ /* Draw the gray out lines. Do this first so they appear at the
* bottom of inactive or active lines.
* As we go, remember if we see any active or selected lines. */
bool found_selectline = false;
@@ -548,7 +549,7 @@ static void ui_draw_links(uiBlock *block)
}
/* Draw any active lines (lines with either button being hovered over).
- * Do this last so they appear on top of inactive and grey out lines. */
+ * Do this last so they appear on top of inactive and gray out lines. */
if (found_activeline) {
for (but = block->buttons.first; but; but = but->next) {
if (but->type == UI_BTYPE_LINK && but->link) {
@@ -1099,13 +1100,16 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but,
return found;
}
-/* this goes in a seemingly weird pattern:
+/**
+ * This goes in a seemingly weird pattern:
*
+ * <pre>
* 4
* 5 6
* 1 2
* 7 8
* 3
+ * </pre>
*
* but it's actually quite logical. It's designed to be 'upwards compatible'
* for muscle memory so that the menu item locations are fixed and don't move
@@ -1188,16 +1192,6 @@ void UI_block_update_from_old(const bContext *C, uiBlock *block)
block->auto_open_last = block->oldblock->auto_open_last;
block->tooltipdisabled = block->oldblock->tooltipdisabled;
BLI_movelisttolist(&block->color_pickers.list, &block->oldblock->color_pickers.list);
- /* sub-block drag & drop data */
- if (UI_subblock_is_dragging(block->oldblock)) {
- block->subblock.drag_state = block->oldblock->subblock.drag_state;
- block->subblock.rect = block->oldblock->subblock.rect;
- block->subblock.rect_above = block->oldblock->subblock.rect_above;
- block->subblock.rect_below = block->oldblock->subblock.rect_below;
- copy_v2_v2_int(block->subblock.click_xy, block->oldblock->subblock.click_xy);
- copy_v2_v2_int(block->subblock.drag_xy_prev, block->oldblock->subblock.drag_xy_prev);
- BLI_strncpy(block->subblock.dragged_subblock, block->oldblock->subblock.dragged_subblock, MAX_NAME);
- }
block->oldblock = NULL;
}
@@ -1329,25 +1323,10 @@ static void ui_but_to_pixelrect(rcti *rect, const ARegion *ar, uiBlock *block, u
rect->ymax = floorf(rectf.ymax);
}
-static void ui_but_draw(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rcti *rect)
-{
- /* XXX: figure out why invalid coordinates happen when closing render window */
- /* and material preview is redrawn in main window (temp fix for bug #23848) */
- if (rect->xmin < rect->xmax && rect->ymin < rect->ymax)
- ui_draw_but(C, ar, style, but, rect);
-}
-
-static bool ui_subblock_is_but_dragged(uiBlock *block, uiBut *but)
-{
- return (but->subblock_id[0] && STREQ(but->subblock_id, block->subblock.dragged_subblock));
-}
-
-#include "BIF_glutil.h"
/* uses local copy of style, to scale things down, and allow widgets to change stuff */
void UI_block_draw(const bContext *C, uiBlock *block)
{
uiStyle style = *UI_style_get_dpi(); /* XXX pass on as arg */
- wmWindow *win = CTX_wm_window(C);
ARegion *ar;
uiBut *but;
rcti rect;
@@ -1395,59 +1374,17 @@ void UI_block_draw(const bContext *C, uiBlock *block)
else if (block->panel)
ui_draw_aligned_panel(&style, block, &rect, UI_panel_category_is_visible(ar));
- /********** widgets **********/
-
- /* first pass: draw not-dragged widgets */
+ /* widgets */
for (but = block->buttons.first; but; but = but->next) {
if (!(but->flag & (UI_HIDDEN | UI_SCROLLED))) {
ui_but_to_pixelrect(&rect, ar, block, but);
-
- if (UI_subblock_is_dragging(block)) {
- if (ui_subblock_is_but_dragged(block, but)) {
- continue;
- }
- }
-
- ui_but_draw(C, ar, &style, but, &rect);
- }
- }
-
- /* second pass: draw dragged widgets above others */
- if (UI_subblock_is_dragging(block)) {
- int mx = win->eventstate->x, my = win->eventstate->y;
- int drag_ofs_y = my - block->subblock.drag_xy_prev[1];
- int ofs = 0;
-
- ui_window_to_block(ar, block, &mx, &my);
- ofs = block->subblock.click_xy[1] - (my - (block->subblock.rect.ymin + drag_ofs_y));
-
- for (but = block->buttons.first; but; but = but->next) {
- if (ui_subblock_is_but_dragged(block, but) &&
- !(but->flag & (UI_HIDDEN | UI_SCROLLED)))
- {
- ui_but_to_pixelrect(&rect, ar, block, but);
- BLI_rcti_translate(&rect, 0, drag_ofs_y - ofs);
-
- ui_but_draw(C, ar, &style, but, &rect);
- }
- }
- BLI_rctf_translate(&block->subblock.rect, 0, drag_ofs_y - ofs);
- }
-
-#if 0 /* debugging - draw border around sub-blocks */
- if (UI_subblock_is_dragging(block)) {
- rctf rectf = block->subblock.rect;
-
- ui_block_to_window_rctf(ar, block, &rectf, &block->subblock.rect);
- rectf.xmin -= ar->winrct.xmin;
- rectf.ymin -= ar->winrct.ymin;
- rectf.xmax -= ar->winrct.xmin;
- rectf.ymax -= ar->winrct.ymin;
-
- fdrawbox(rectf.xmin, rectf.ymin, rectf.xmax, rectf.ymax);
+ /* XXX: figure out why invalid coordinates happen when closing render window */
+ /* and material preview is redrawn in main window (temp fix for bug #23848) */
+ if (rect.xmin < rect.xmax && rect.ymin < rect.ymax)
+ ui_draw_but(C, ar, &style, but, &rect);
+ }
}
-#endif
/* restore matrix */
glMatrixMode(GL_PROJECTION);
@@ -1997,7 +1934,7 @@ void ui_but_value_set(uiBut *but, double value)
int ui_but_string_get_max_length(uiBut *but)
{
- if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK))
+ if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU))
return but->hardmax;
else
return UI_MAX_DRAW_STR;
@@ -2018,6 +1955,56 @@ uiBut *ui_but_drag_multi_edit_get(uiBut *but)
return but_iter;
}
+/** \name Check to show extra icons
+ *
+ * Extra icons are shown on the right hand side of buttons.
+ * \{ */
+
+static bool ui_but_icon_extra_is_visible_search_unlink(const uiBut *but)
+{
+ BLI_assert(but->type == UI_BTYPE_SEARCH_MENU);
+ return ((but->editstr == NULL) &&
+ (but->drawstr[0] != '\0') &&
+ (but->flag & UI_BUT_SEARCH_UNLINK));
+}
+
+static bool ui_but_icon_extra_is_visible_eyedropper(uiBut *but)
+{
+ StructRNA *type;
+ short idcode;
+
+ BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_SEARCH_UNLINK));
+
+ if (but->rnaprop == NULL) {
+ return false;
+ }
+
+ type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
+ idcode = RNA_type_to_ID_code(type);
+
+
+ return ((but->editstr == NULL) &&
+ (idcode == ID_OB || OB_DATA_SUPPORT_ID(idcode)));
+}
+
+uiButExtraIconType ui_but_icon_extra_get(uiBut *but)
+{
+ if ((but->flag & UI_BUT_SEARCH_UNLINK) == 0) {
+ /* pass */
+ }
+ else if (ui_but_icon_extra_is_visible_search_unlink(but)) {
+ return UI_BUT_ICONEXTRA_UNLINK;
+ }
+ else if (ui_but_icon_extra_is_visible_eyedropper(but)) {
+ return UI_BUT_ICONEXTRA_EYEDROPPER;
+ }
+
+ return UI_BUT_ICONEXTRA_NONE;
+}
+
+/** \} */
+
+
static double ui_get_but_scale_unit(uiBut *but, double value)
{
UnitSettings *unit = but->block->unit;
@@ -2098,7 +2085,7 @@ static float ui_get_but_step_unit(uiBut *but, float step_default)
*/
void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision)
{
- if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
PropertyType type;
const char *buf = NULL;
int buf_len;
@@ -2140,7 +2127,7 @@ void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int
BLI_strncpy(str, but->poin, maxlen);
return;
}
- else if (ELEM(but->type, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ else if (but->type == UI_BTYPE_SEARCH_MENU) {
/* string */
BLI_strncpy(str, but->poin, maxlen);
return;
@@ -2261,7 +2248,7 @@ static void ui_but_string_free_internal(uiBut *but)
bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
{
- if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
if (RNA_property_editable(&but->rnapoin, but->rnaprop)) {
PropertyType type;
@@ -2313,7 +2300,7 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
return true;
}
- else if (ELEM(but->type, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ else if (but->type == UI_BTYPE_SEARCH_MENU) {
/* string */
BLI_strncpy(but->poin, str, but->hardmax);
return true;
@@ -2331,6 +2318,7 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
double value;
if (ui_but_string_set_eval_num(C, but, str, &value) == false) {
+ WM_report_banner_show(C);
return false;
}
@@ -2608,10 +2596,6 @@ void UI_block_region_set(uiBlock *block, ARegion *region)
oldblock->active = 0;
oldblock->panel = NULL;
oldblock->handle = NULL;
-
- if (UI_subblock_is_dragging(oldblock)) {
- block->rect = oldblock->rect;
- }
}
/* at the beginning of the list! for dynamical menus/blocks */
@@ -2785,11 +2769,11 @@ void ui_but_update(uiBut *but)
}
else {
const int prec = ui_but_calc_float_precision(but, value);
- slen += BLI_snprintf(but->drawstr + slen, sizeof(but->drawstr) - slen, "%.*f", prec, value);
+ slen += BLI_snprintf_rlen(but->drawstr + slen, sizeof(but->drawstr) - slen, "%.*f", prec, value);
}
}
else {
- slen += BLI_snprintf(but->drawstr + slen, sizeof(but->drawstr) - slen, "%d", (int)value);
+ slen += BLI_snprintf_rlen(but->drawstr + slen, sizeof(but->drawstr) - slen, "%d", (int)value);
}
if (but->rnaprop) {
@@ -2825,7 +2809,6 @@ void ui_but_update(uiBut *but)
case UI_BTYPE_TEXT:
case UI_BTYPE_SEARCH_MENU:
- case UI_BTYPE_SEARCH_MENU_UNLINK:
if (!but->editstr) {
char str[UI_MAX_DRAW_STR];
@@ -3118,17 +3101,18 @@ void ui_block_cm_to_scene_linear_v3(uiBlock *block, float pixel[3])
/**
* \brief ui_def_but is the function that draws many button types
*
- * \param x,y The lower left hand corner of the button (X axis)
- * \param width,height The size of the button.
+ * \param x, y: The lower left hand corner of the button (X axis)
+ * \param width, height: The size of the button.
*
* for float buttons:
- * - \a a1 Click Step (how much to change the value each click)
- * - \a a2 Number of decimal point values to display. 0 defaults to 3 (0.000)
- * 1,2,3, and a maximum of 4, all greater values will be clamped to 4.
+ * \param a1: Click Step (how much to change the value each click)
+ * \param a2: Number of decimal point values to display. 0 defaults to 3 (0.000)
+ * 1,2,3, and a maximum of 4, all greater values will be clamped to 4.
*/
-static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
- int x, int y, short width, short height,
- void *poin, float min, float max, float a1, float a2, const char *tip)
+static uiBut *ui_def_but(
+ uiBlock *block, int type, int retval, const char *str,
+ int x, int y, short width, short height,
+ void *poin, float min, float max, float a1, float a2, const char *tip)
{
uiBut *but;
int slen;
@@ -3193,10 +3177,6 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
but->pos = -1; /* cursor invisible */
- if (block->subblock.is_subblock_building) {
- BLI_strncpy(but->subblock_id, block->subblock.subblock_id[block->subblock.tot_subblocks], MAX_NAME);
- }
-
if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) { /* add a space to name */
/* slen remains unchanged from previous assignment, ensure this stays true */
if (slen > 0 && slen < UI_MAX_NAME_STR - 2) {
@@ -3214,7 +3194,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
ELEM(but->type,
UI_BTYPE_MENU, UI_BTYPE_TEXT, UI_BTYPE_LABEL,
UI_BTYPE_BLOCK, UI_BTYPE_BUT_MENU, UI_BTYPE_SEARCH_MENU,
- UI_BTYPE_PROGRESS_BAR, UI_BTYPE_SEARCH_MENU_UNLINK))
+ UI_BTYPE_PROGRESS_BAR))
{
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
}
@@ -3261,6 +3241,19 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
return but;
}
+void ui_def_but_icon(uiBut *but, const int icon, const int flag)
+{
+ if (icon) {
+ ui_icon_ensure_deferred(but->block->evil_C, icon, (flag & UI_BUT_ICON_PREVIEW) != 0);
+ }
+ but->icon = (BIFIconID)icon;
+ but->flag |= flag;
+
+ if (but->str && but->str[0]) {
+ but->drawflag |= UI_BUT_ICON_LEFT;
+ }
+}
+
static void ui_def_but_rna__disable(uiBut *but)
{
but->flag |= UI_BUT_DISABLED;
@@ -3400,10 +3393,11 @@ static void ui_def_but_rna__menu(bContext *UNUSED(C), uiLayout *layout, void *bu
* When this kind of change won't disrupt branches, best look into making more
* of our UI functions take prop rather then propname.
*/
-static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *str,
- int x, int y, short width, short height,
- PointerRNA *ptr, PropertyRNA *prop, int index,
- float min, float max, float a1, float a2, const char *tip)
+static uiBut *ui_def_but_rna(
+ uiBlock *block, int type, int retval, const char *str,
+ int x, int y, short width, short height,
+ PointerRNA *ptr, PropertyRNA *prop, int index,
+ float min, float max, float a1, float a2, const char *tip)
{
const PropertyType proptype = RNA_property_type(prop);
uiBut *but;
@@ -3523,11 +3517,7 @@ static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *s
but->rnaindex = 0;
if (icon) {
- but->icon = (BIFIconID)icon;
- but->flag |= UI_HAS_ICON;
- if (str[0]) {
- but->drawflag |= UI_BUT_ICON_LEFT;
- }
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
}
if ((type == UI_BTYPE_MENU) && (but->dt == UI_EMBOSS_PULLDOWN)) {
@@ -3714,8 +3704,7 @@ int UI_autocomplete_end(AutoComplete *autocpl, char *autoname)
static void ui_but_update_and_icon_set(uiBut *but, int icon)
{
if (icon) {
- but->icon = (BIFIconID) icon;
- but->flag |= UI_HAS_ICON;
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
}
ui_but_update(but);
@@ -4089,7 +4078,7 @@ void UI_but_drag_set_value(uiBut *but)
void UI_but_drag_set_image(uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale)
{
but->dragtype = WM_DRAG_PATH;
- but->icon = icon; /* no flag UI_HAS_ICON, so icon doesnt draw in button */
+ ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesnt draw in button */
but->dragpoin = (void *)path;
but->imb = imb;
but->imb_scale = scale;
@@ -4243,8 +4232,7 @@ uiBut *uiDefIconTextMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, in
{
uiBut *but = ui_def_but(block, UI_BTYPE_PULLDOWN, 0, str, x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
- but->icon = (BIFIconID) icon;
- but->flag |= UI_HAS_ICON;
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
but->drawflag |= UI_BUT_ICON_LEFT;
but->flag |= UI_BUT_ICON_SUBMENU;
@@ -4259,8 +4247,7 @@ uiBut *uiDefIconMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int ic
{
uiBut *but = ui_def_but(block, UI_BTYPE_PULLDOWN, 0, "", x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
- but->icon = (BIFIconID) icon;
- but->flag |= UI_HAS_ICON;
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
but->drawflag &= ~UI_BUT_ICON_LEFT;
but->menu_create_func = func;
@@ -4276,7 +4263,7 @@ uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg,
/* XXX temp, old menu calls pass on icon arrow, which is now UI_BUT_ICON_SUBMENU flag */
if (icon != ICON_RIGHTARROW_THIN) {
- but->icon = (BIFIconID) icon;
+ ui_def_but_icon(but, icon, 0);
but->drawflag |= UI_BUT_ICON_LEFT;
}
but->flag |= UI_HAS_ICON;
@@ -4293,9 +4280,8 @@ uiBut *uiDefIconBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, int
{
uiBut *but = ui_def_but(block, UI_BTYPE_BLOCK, retval, "", x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip);
- but->icon = (BIFIconID) icon;
- but->flag |= UI_HAS_ICON;
-
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
+
but->drawflag |= UI_BUT_ICON_LEFT;
but->block_create_func = func;
@@ -4328,9 +4314,8 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle
{
uiBut *but = ui_def_but(block, UI_BTYPE_SEARCH_MENU, retval, "", x, y, width, height, arg, 0.0, maxlen, a1, a2, tip);
- but->icon = (BIFIconID) icon;
- but->flag |= UI_HAS_ICON;
-
+ ui_def_but_icon(but, icon, UI_HAS_ICON);
+
but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT;
ui_but_update(but);
@@ -4339,8 +4324,11 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle
}
-/* arg is user value, searchfunc and handlefunc both get it as arg */
-/* if active set, button opens with this item visible and selected */
+/**
+ * \param sfunc, bfunc: both get it as \a arg.
+ * \param arg: user value,
+ * \param active: when set, button opens with this item visible and selected.
+ */
void UI_but_func_search_set(uiBut *but, uiButSearchFunc sfunc, void *arg, uiButHandleFunc bfunc, void *active)
{
but->search_func = sfunc;
@@ -4409,11 +4397,14 @@ static void operator_enum_call_cb(struct bContext *UNUSED(C), void *but, void *a
}
}
-/* Same parameters as for uiDefSearchBut, with additional operator type and properties, used by callback
- * to call again the right op with the right options (properties values). */
-uiBut *uiDefSearchButO_ptr(uiBlock *block, wmOperatorType *ot, IDProperty *properties,
- void *arg, int retval, int icon, int maxlen, int x, int y,
- short width, short height, float a1, float a2, const char *tip)
+/**
+ * Same parameters as for uiDefSearchBut, with additional operator type and properties, used by callback
+ * to call again the right op with the right options (properties values).
+ */
+uiBut *uiDefSearchButO_ptr(
+ uiBlock *block, wmOperatorType *ot, IDProperty *properties,
+ void *arg, int retval, int icon, int maxlen, int x, int y,
+ short width, short height, float a1, float a2, const char *tip)
{
uiBut *but;
@@ -4432,7 +4423,8 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block, wmOperatorType *ot, IDProperty *prope
return but;
}
-/* push a new event onto event queue to activate the given button
+/**
+ * push a new event onto event queue to activate the given button
* (usually a text-field) upon entering a popup
*/
void UI_but_focus_on_enter_event(wmWindow *win, uiBut *but)
@@ -4465,7 +4457,19 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
if (type == BUT_GET_LABEL) {
if (but->str) {
- tmp = BLI_strdup(but->str);
+ const char *str_sep;
+ size_t str_len;
+
+ if ((but->flag & UI_BUT_HAS_SEP_CHAR) &&
+ (str_sep = strrchr(but->str, UI_SEP_CHAR)))
+ {
+ str_len = (str_sep - but->str);
+ }
+ else {
+ str_len = strlen(but->str);
+ }
+
+ tmp = BLI_strdupn(but->str, str_len);
}
else {
type = BUT_GET_RNA_LABEL; /* Fail-safe solution... */
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 24a30ebe3d8..f6757b35462 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -54,13 +54,13 @@
#include "interface_intern.h"
-static FCurve *ui_but_get_fcurve(uiBut *but, AnimData **adt, bAction **action, bool *r_driven)
+static FCurve *ui_but_get_fcurve(uiBut *but, AnimData **adt, bAction **action, bool *r_driven, bool *r_special)
{
/* for entire array buttons we check the first component, it's not perfect
* but works well enough in typical cases */
int rnaindex = (but->rnaindex == -1) ? 0 : but->rnaindex;
- return rna_get_fcurve_context_ui(but->block->evil_C, &but->rnapoin, but->rnaprop, rnaindex, adt, action, r_driven);
+ return rna_get_fcurve_context_ui(but->block->evil_C, &but->rnapoin, but->rnaprop, rnaindex, adt, action, r_driven, r_special);
}
void ui_but_anim_flag(uiBut *but, float cfra)
@@ -69,11 +69,16 @@ void ui_but_anim_flag(uiBut *but, float cfra)
bAction *act;
FCurve *fcu;
bool driven;
-
+ bool special;
+
but->flag &= ~(UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN);
-
- fcu = ui_but_get_fcurve(but, &adt, &act, &driven);
-
+
+ /* NOTE: "special" is reserved for special F-Curves stored on the animation data
+ * itself (which are used to animate properties of the animation data).
+ * We count those as "animated" too for now
+ */
+ fcu = ui_but_get_fcurve(but, &adt, &act, &driven, &special);
+
if (fcu) {
if (!driven) {
but->flag |= UI_BUT_ANIMATED;
@@ -98,10 +103,10 @@ bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen)
{
FCurve *fcu;
ChannelDriver *driver;
- bool driven;
-
- fcu = ui_but_get_fcurve(but, NULL, NULL, &driven);
-
+ bool driven, special;
+
+ fcu = ui_but_get_fcurve(but, NULL, NULL, &driven, &special);
+
if (fcu && driven) {
driver = fcu->driver;
@@ -118,9 +123,9 @@ bool ui_but_anim_expression_set(uiBut *but, const char *str)
{
FCurve *fcu;
ChannelDriver *driver;
- bool driven;
+ bool driven, special;
- fcu = ui_but_get_fcurve(but, NULL, NULL, &driven);
+ fcu = ui_but_get_fcurve(but, NULL, NULL, &driven, &special);
if (fcu && driven) {
driver = fcu->driver;
@@ -215,8 +220,9 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
bAction *action;
FCurve *fcu;
bool driven;
+ bool special;
- fcu = ui_but_get_fcurve(but, NULL, &action, &driven);
+ fcu = ui_but_get_fcurve(but, NULL, &action, &driven, &special);
if (fcu && !driven) {
id = but->rnapoin.id.data;
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 07d580b9138..3f0154f8cc3 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -436,7 +436,7 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(w
float facy = (float)h / (float)ibuf->y;
glPixelZoom(facx, facy);
}
- glaDrawPixelsAuto((float)rect->xmin, (float)rect->ymin, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, ibuf->rect);
+ glaDrawPixelsAuto((float)rect->xmin, (float)rect->ymin, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, 1.0f, ibuf->rect);
glPixelZoom(1.0f, 1.0f);
@@ -508,8 +508,9 @@ static void draw_scope_end(const rctf *rect, GLint *scissor)
UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rect->xmin - 1, rect->ymin, rect->xmax + 1, rect->ymax + 1, 3.0f);
}
-static void histogram_draw_one(float r, float g, float b, float alpha,
- float x, float y, float w, float h, const float *data, int res, const bool is_line)
+static void histogram_draw_one(
+ float r, float g, float b, float alpha,
+ float x, float y, float w, float h, const float *data, int res, const bool is_line)
{
int i;
@@ -1453,7 +1454,7 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
glEnd();
}
else if (cumap->cur == 3) {
- float lum = rgb_to_bw(cumap->sample);
+ float lum = IMB_colormanagement_get_luminance(cumap->sample);
glColor3ub(240, 240, 240);
glBegin(GL_LINES);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index aabb8e29fa9..4f77185fb8f 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -176,8 +176,8 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int
if (sa) {
if (sa->spacetype == SPACE_IMAGE) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
SpaceImage *sima = sa->spacedata.first;
int mval[2] = {mx - ar->winrct.xmin,
my - ar->winrct.ymin};
@@ -188,8 +188,8 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int
}
}
else if (sa->spacetype == SPACE_NODE) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
SpaceNode *snode = sa->spacedata.first;
int mval[2] = {mx - ar->winrct.xmin,
my - ar->winrct.ymin};
@@ -200,8 +200,8 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int
}
}
else if (sa->spacetype == SPACE_CLIP) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
SpaceClip *sc = sa->spacedata.first;
int mval[2] = {mx - ar->winrct.xmin,
my - ar->winrct.ymin};
@@ -379,12 +379,11 @@ void UI_OT_eyedropper_color(wmOperatorType *ot)
/* -------------------------------------------------------------------- */
-/* Data Dropper
- *
- * note: datadropper is only internal name to avoid confusion in this file
- */
+/* Data Dropper */
/** \name Eyedropper (ID data-blocks)
+ *
+ * \note: datadropper is only internal name to avoid confusion in this file.
* \{ */
typedef struct DataDropper {
@@ -456,6 +455,8 @@ static void datadropper_exit(bContext *C, wmOperator *op)
op->customdata = NULL;
}
+
+ WM_event_add_mousemove(C);
}
static void datadropper_cancel(bContext *C, wmOperator *op)
@@ -482,8 +483,8 @@ static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int
if (sa) {
if (sa->spacetype == SPACE_VIEW3D) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
const int mval[2] = {
mx - ar->winrct.xmin,
my - ar->winrct.ymin};
@@ -632,7 +633,7 @@ void UI_OT_eyedropper_id(wmOperatorType *ot)
/* identifiers */
ot->name = "Eyedropper Datablock";
ot->idname = "UI_OT_eyedropper_id";
- ot->description = "Sample a color from the Blender Window to store in a property";
+ ot->description = "Sample a datablock from the Blender Window to store in a property";
/* api callbacks */
ot->invoke = datadropper_invoke;
@@ -651,12 +652,11 @@ void UI_OT_eyedropper_id(wmOperatorType *ot)
/* -------------------------------------------------------------------- */
-/* Depth Dropper
- *
- * note: depthdropper is only internal name to avoid confusion in this file
- */
+/* Depth Dropper */
/** \name Eyedropper (Depth)
+ *
+ * \note: depthdropper is only internal name to avoid confusion in this file.
* \{ */
typedef struct DepthDropper {
@@ -765,8 +765,8 @@ static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx,
if (sa) {
if (sa->spacetype == SPACE_VIEW3D) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
View3D *v3d = sa->spacedata.first;
RegionView3D *rv3d = ar->regiondata;
/* weak, we could pass in some reference point */
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 15c504dc9d7..01296385cd3 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -52,9 +52,9 @@
#include "BLI_linklist.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
+#include "BLI_string_cursor_utf8.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
-#include "BLI_string_cursor_utf8.h"
#include "BLF_translation.h"
@@ -99,6 +99,9 @@
/* support dragging multiple number buttons at once */
#define USE_DRAG_MULTINUM
+/* allow dragging/editing all other selected items at once */
+#define USE_ALLSELECT
+
/* so we can avoid very small mouse-moves from jumping away from keyboard navigation [#34936] */
#define USE_KEYNAV_LIMIT
@@ -110,9 +113,6 @@
/* This hack is needed because we don't have a good way to re-reference keymap items once added: T42944 */
#define USE_KEYMAP_ADD_HACK
-static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(userdata));
-static void ui_region_handler_remove(bContext *C, void *UNUSED(userdata));
-
/* proto */
static void ui_but_smart_controller_add(bContext *C, uiBut *from, uiBut *to);
static void ui_but_link_add(bContext *C, uiBut *from, uiBut *to);
@@ -161,17 +161,63 @@ typedef enum uiHandleButtonState {
} uiHandleButtonState;
+#ifdef USE_ALLSELECT
+
+/* Unfortunately theres no good way handle more generally:
+ * (propagate single clicks on layer buttons to other objects) */
+#define USE_ALLSELECT_LAYER_HACK
+
+typedef struct uiSelectContextElem {
+ PointerRNA ptr;
+ union {
+ bool val_b;
+ int val_i;
+ float val_f;
+ };
+} uiSelectContextElem;
+
+typedef struct uiSelectContextStore {
+ uiSelectContextElem *elems;
+ int elems_len;
+ bool do_free;
+ bool is_enabled;
+ /* When set, simply copy values (don't apply difference).
+ * Rules are:
+ * - dragging numbers uses delta.
+ * - typing in values will assign to all. */
+ bool is_copy;
+} uiSelectContextStore;
+
+static bool ui_selectcontext_begin(
+ bContext *C, uiBut *but, struct uiSelectContextStore *selctx_data);
+static void ui_selectcontext_end(
+ uiBut *but, uiSelectContextStore *selctx_data);
+static void ui_selectcontext_apply(
+ bContext *C, uiBut *but, struct uiSelectContextStore *selctx_data,
+ const double value, const double value_orig);
+
+#define IS_ALLSELECT_EVENT(event) ((event)->alt != 0)
+
+/** just show a tinted color so users know its activated */
+#define UI_BUT_IS_SELECT_CONTEXT UI_BUT_NODE_ACTIVE
+
+#endif /* USE_ALLSELECT */
+
+
#ifdef USE_DRAG_MULTINUM
-/* how far to drag before we check for gesture direction (in pixels),
+/**
+ * how far to drag before we check for gesture direction (in pixels),
* note: half the height of a button is about right... */
#define DRAG_MULTINUM_THRESHOLD_DRAG_X (UI_UNIT_Y / 4)
-/* how far to drag horizontally before we stop checking which buttons the gesture spans (in pixels),
+/**
+ * how far to drag horizontally before we stop checking which buttons the gesture spans (in pixels),
* locking down the buttons so we can drag freely without worrying about vertical movement. */
#define DRAG_MULTINUM_THRESHOLD_DRAG_Y (UI_UNIT_Y / 4)
-/* how strict to be when detecting a vertical gesture, [0.5 == sloppy], [0.9 == strict], (unsigned dot-product)
+/**
+ * how strict to be when detecting a vertical gesture, [0.5 == sloppy], [0.9 == strict], (unsigned dot-product)
* note: we should be quite strict here, since doing a vertical gesture by accident should be avoided,
* however with some care a user should be able to do a vertical movement without *missing*. */
#define DRAG_MULTINUM_THRESHOLD_VERTICAL (0.75f)
@@ -181,6 +227,10 @@ typedef enum uiHandleButtonState {
typedef struct uiButMultiState {
double origvalue;
uiBut *but;
+
+#ifdef USE_ALLSELECT
+ uiSelectContextStore select_others;
+#endif
} uiButMultiState;
typedef struct uiHandleButtonMulti {
@@ -213,8 +263,6 @@ typedef struct uiHandleButtonMulti {
#endif /* USE_DRAG_MULTINUM */
-
-
typedef struct uiHandleButtonData {
wmWindowManager *wm;
wmWindow *window;
@@ -283,6 +331,10 @@ typedef struct uiHandleButtonData {
uiHandleButtonMulti multi_data;
#endif
+#ifdef USE_ALLSELECT
+ uiSelectContextStore select_others;
+#endif
+
/* post activate */
uiButtonActivateType posttype;
uiBut *postbut;
@@ -331,14 +383,14 @@ static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, c
static uiBut *ui_but_find_mouse_over(ARegion *ar, const wmEvent *event);
static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonActivateType type);
static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState state);
-static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *data,
- const bool mousemove, const bool onfree);
+static void button_activate_exit(
+ bContext *C, uiBut *but, uiHandleButtonData *data,
+ const bool mousemove, const bool onfree);
static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *userdata);
static void ui_handle_button_activate(bContext *C, ARegion *ar, uiBut *but, uiButtonActivateType type);
-static void button_timers_tooltip_remove(bContext *C, uiBut *but);
#ifdef USE_DRAG_MULTINUM
-static void ui_multibut_restore(uiHandleButtonData *data, uiBlock *block);
+static void ui_multibut_restore(bContext *C, uiHandleButtonData *data, uiBlock *block);
static uiButMultiState *ui_multibut_lookup(uiHandleButtonData *data, const uiBut *but);
#endif
@@ -369,7 +421,7 @@ static void ui_color_snap_hue(const enum eSnapType snap, float *r_hue)
{
const float snap_increment = (snap == SNAP_ON_SMALL) ? 24 : 12;
BLI_assert(snap != SNAP_OFF);
- *r_hue = floorf(0.5f + ((*r_hue) * snap_increment)) / snap_increment;
+ *r_hue = roundf((*r_hue) * snap_increment) / snap_increment;
}
/* assumes event type is MOUSEPAN */
@@ -416,7 +468,7 @@ bool ui_but_is_editable_as_text(const uiBut *but)
{
return ELEM(but->type,
UI_BTYPE_TEXT, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER,
- UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK);
+ UI_BTYPE_SEARCH_MENU);
}
@@ -481,10 +533,9 @@ static float ui_mouse_scale_warp_factor(const bool shift)
return shift ? 0.05f : 1.0f;
}
-static void ui_mouse_scale_warp(uiHandleButtonData *data,
- const float mx, const float my,
- float *r_mx, float *r_my,
- const bool shift)
+static void ui_mouse_scale_warp(
+ uiHandleButtonData *data, const float mx, const float my,
+ float *r_mx, float *r_my, const bool shift)
{
const float fac = ui_mouse_scale_warp_factor(shift);
@@ -897,7 +948,7 @@ static uiButMultiState *ui_multibut_lookup(uiHandleButtonData *data, const uiBut
return NULL;
}
-static void ui_multibut_restore(uiHandleButtonData *data, uiBlock *block)
+static void ui_multibut_restore(bContext *C, uiHandleButtonData *data, uiBlock *block)
{
uiBut *but;
@@ -906,6 +957,16 @@ static void ui_multibut_restore(uiHandleButtonData *data, uiBlock *block)
uiButMultiState *mbut_state = ui_multibut_lookup(data, but);
if (mbut_state) {
ui_but_value_set(but, mbut_state->origvalue);
+
+#ifdef USE_ALLSELECT
+ if (mbut_state->select_others.elems_len > 0) {
+ ui_selectcontext_apply(
+ C, but, &mbut_state->select_others,
+ mbut_state->origvalue, mbut_state->origvalue);
+ }
+#else
+ UNUSED_VARS(C);
+#endif
}
}
}
@@ -913,7 +974,26 @@ static void ui_multibut_restore(uiHandleButtonData *data, uiBlock *block)
static void ui_multibut_free(uiHandleButtonData *data, uiBlock *block)
{
+#ifdef USE_ALLSELECT
+ if (data->multi_data.mbuts) {
+ LinkNode *list = data->multi_data.mbuts;
+ while (list) {
+ LinkNode *next = list->next;
+ uiButMultiState *mbut_state = list->link;
+
+ if (mbut_state->select_others.elems) {
+ MEM_freeN(mbut_state->select_others.elems);
+ }
+
+ MEM_freeN(list->link);
+ MEM_freeN(list);
+ list = next;
+ }
+ }
+#else
BLI_linklist_freeN(data->multi_data.mbuts);
+#endif
+
data->multi_data.mbuts = NULL;
if (data->multi_data.bs_mbuts) {
@@ -1019,6 +1099,24 @@ static void ui_multibut_states_apply(bContext *C, uiHandleButtonData *data, uiBl
void *active_back;
ui_but_execute_begin(C, ar, but, &active_back);
+
+#ifdef USE_ALLSELECT
+ if (data->select_others.is_enabled) {
+ /* init once! */
+ if (mbut_state->select_others.elems_len == 0) {
+ ui_selectcontext_begin(C, but, &mbut_state->select_others);
+ }
+ if (mbut_state->select_others.elems_len == 0) {
+ mbut_state->select_others.elems_len = -1;
+ }
+ }
+
+ /* needed so we apply the right deltas */
+ but->active->origvalue = mbut_state->origvalue;
+ but->active->select_others = mbut_state->select_others;
+ but->active->select_others.do_free = false;
+#endif
+
BLI_assert(active_back == NULL);
/* no need to check 'data->state' here */
if (data->str) {
@@ -1067,8 +1165,9 @@ typedef struct uiDragToggleHandle {
int xy_last[2];
} uiDragToggleHandle;
-static bool ui_drag_toggle_set_xy_xy(bContext *C, ARegion *ar, const bool is_set, const eButType but_type_start,
- const int xy_src[2], const int xy_dst[2])
+static bool ui_drag_toggle_set_xy_xy(
+ bContext *C, ARegion *ar, const bool is_set, const eButType but_type_start,
+ const int xy_src[2], const int xy_dst[2])
{
/* popups such as layers won't re-evaluate on redraw */
const bool do_check = (ar->regiontype == RGN_TYPE_TEMPORARY);
@@ -1228,6 +1327,255 @@ static bool ui_but_is_drag_toggle(const uiBut *but)
#endif /* USE_DRAG_TOGGLE */
+#ifdef USE_ALLSELECT
+
+static bool ui_selectcontext_begin(
+ bContext *C, uiBut *but, uiSelectContextStore *selctx_data)
+{
+ PointerRNA ptr, lptr, idptr;
+ PropertyRNA *prop, *lprop;
+ bool success = false;
+ int index;
+
+ char *path = NULL;
+ ListBase lb = {NULL};
+
+ ptr = but->rnapoin;
+ prop = but->rnaprop;
+ index = but->rnaindex;
+
+ /* for now don't support whole colors */
+ if (index == -1)
+ return false;
+
+ /* if there is a valid property that is editable... */
+ if (ptr.data && prop) {
+ CollectionPointerLink *link;
+ bool use_path_from_id;
+ int i;
+
+ /* some facts we want to know */
+ const bool is_array = RNA_property_array_check(prop);
+ const int rna_type = RNA_property_type(prop);
+
+ if (!UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path)) {
+ goto finally;
+ }
+
+ selctx_data->elems_len = BLI_listbase_count(&lb);
+ if (selctx_data->elems_len == 0) {
+ goto finally;
+ }
+
+ selctx_data->elems = MEM_mallocN(sizeof(uiSelectContextElem) * selctx_data->elems_len, __func__);
+
+ for (i = 0, link = lb.first; i < selctx_data->elems_len; i++, link = link->next) {
+ uiSelectContextElem *other = &selctx_data->elems[i];
+ /* TODO,. de-duplicate copy_to_selected_button */
+ if (link->ptr.data != ptr.data) {
+ if (use_path_from_id) {
+ /* Path relative to ID. */
+ lprop = NULL;
+ RNA_id_pointer_create(link->ptr.id.data, &idptr);
+ RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
+ }
+ else if (path) {
+ /* Path relative to elements from list. */
+ lprop = NULL;
+ RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
+ }
+ else {
+ lptr = link->ptr;
+ lprop = prop;
+ }
+
+ /* lptr might not be the same as link->ptr! */
+ if ((lptr.data != ptr.data) &&
+ (lprop == prop) &&
+ RNA_property_editable(&lptr, lprop))
+ {
+ other->ptr = lptr;
+ if (is_array) {
+ if (rna_type == PROP_FLOAT) {
+ other->val_f = RNA_property_float_get_index(&lptr, lprop, index);
+ }
+ else if (rna_type == PROP_INT) {
+ other->val_i = RNA_property_int_get_index(&lptr, lprop, index);
+ }
+ /* ignored for now */
+#if 0
+ else if (rna_type == PROP_BOOLEAN) {
+ other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index);
+ }
+#endif
+ }
+ else {
+ if (rna_type == PROP_FLOAT) {
+ other->val_f = RNA_property_float_get(&lptr, lprop);
+ }
+ else if (rna_type == PROP_INT) {
+ other->val_i = RNA_property_int_get(&lptr, lprop);
+ }
+ /* ignored for now */
+#if 0
+ else if (rna_type == PROP_BOOLEAN) {
+ other->val_b = RNA_property_boolean_get(&lptr, lprop);
+ }
+ else if (rna_type == PROP_ENUM) {
+ other->val_i = RNA_property_enum_get(&lptr, lprop);
+ }
+#endif
+ }
+
+ continue;
+ }
+ }
+
+ selctx_data->elems_len -= 1;
+ i -= 1;
+ }
+ }
+
+ success = (selctx_data->elems_len != 0);
+
+finally:
+ if (selctx_data->elems_len == 0) {
+ MEM_SAFE_FREE(selctx_data->elems);
+ }
+
+ MEM_SAFE_FREE(path);
+ BLI_freelistN(&lb);
+
+ /* caller can clear */
+ selctx_data->do_free = true;
+
+ if (success) {
+ but->flag |= UI_BUT_IS_SELECT_CONTEXT;
+ }
+
+ return success;
+}
+
+static void ui_selectcontext_end(
+ uiBut *but, uiSelectContextStore *selctx_data)
+{
+ if (selctx_data->do_free) {
+ if (selctx_data->elems) {
+ MEM_freeN(selctx_data->elems);
+ }
+ }
+
+ but->flag &= ~UI_BUT_IS_SELECT_CONTEXT;
+}
+
+static void ui_selectcontext_apply(
+ bContext *C, uiBut *but, uiSelectContextStore *selctx_data,
+ const double value, const double value_orig)
+{
+ if (selctx_data->elems) {
+ PropertyRNA *prop = but->rnaprop;
+ PropertyRNA *lprop = but->rnaprop;
+ int index = but->rnaindex;
+ int i;
+ const bool use_delta = (selctx_data->is_copy == false);
+
+ union {
+ bool b;
+ int i;
+ float f;
+ } delta;
+
+ const bool is_array = RNA_property_array_check(prop);
+ const int rna_type = RNA_property_type(prop);
+
+ if (rna_type == PROP_FLOAT) {
+ delta.f = use_delta ? (value - value_orig) : value;
+ }
+ else if (rna_type == PROP_INT) {
+ delta.i = use_delta ? ((int)value - (int)value_orig) : (int)value;
+ }
+ else if (rna_type == PROP_ENUM) {
+ delta.i = RNA_property_enum_get(&but->rnapoin, prop); /* not a delta infact */
+ }
+ else if (rna_type == PROP_BOOLEAN) {
+ if (is_array) {
+ delta.b = RNA_property_boolean_get_index(&but->rnapoin, prop, index); /* not a delta infact */
+ }
+ else {
+ delta.b = RNA_property_boolean_get(&but->rnapoin, prop); /* not a delta infact */
+ }
+ }
+
+#ifdef USE_ALLSELECT_LAYER_HACK
+ /* make up for not having 'handle_layer_buttons' */
+ {
+ PropertySubType subtype = RNA_property_subtype(prop);
+
+ if ((rna_type == PROP_BOOLEAN) &&
+ ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER) &&
+ is_array &&
+ /* could check for 'handle_layer_buttons' */
+ but->func)
+ {
+ wmWindow *win = CTX_wm_window(C);
+ if (!win->eventstate->shift) {
+ const int len = RNA_property_array_length(&but->rnapoin, prop);
+ int *tmparray = MEM_callocN(sizeof(int) * len, __func__);
+
+ tmparray[index] = true;
+
+ for (i = 0; i < selctx_data->elems_len; i++) {
+ uiSelectContextElem *other = &selctx_data->elems[i];
+ PointerRNA lptr = other->ptr;
+ RNA_property_boolean_set_array(&lptr, lprop, tmparray);
+ RNA_property_update(C, &lptr, lprop);
+ }
+
+ MEM_freeN(tmparray);
+
+ return;
+ }
+ }
+ }
+#endif
+
+ for (i = 0; i < selctx_data->elems_len; i++) {
+ uiSelectContextElem *other = &selctx_data->elems[i];
+ PointerRNA lptr = other->ptr;
+ if (is_array) {
+ if (rna_type == PROP_FLOAT) {
+ RNA_property_float_set_index(&lptr, lprop, index, use_delta ? (other->val_f + delta.f) : delta.f);
+ }
+ else if (rna_type == PROP_INT) {
+ RNA_property_int_set_index(&lptr, lprop, index, use_delta ? (other->val_i + delta.i) : delta.i);
+ }
+ else if (rna_type == PROP_BOOLEAN) {
+ RNA_property_boolean_set_index(&lptr, lprop, index, delta.b);
+ }
+ }
+ else {
+ if (rna_type == PROP_FLOAT) {
+ RNA_property_float_set(&lptr, lprop, use_delta ? (other->val_f + delta.f) : delta.f);
+ }
+ else if (rna_type == PROP_INT) {
+ RNA_property_int_set(&lptr, lprop, use_delta ? (other->val_i + delta.i) : delta.i);
+ }
+ else if (rna_type == PROP_BOOLEAN) {
+ RNA_property_boolean_set(&lptr, lprop, delta.b);
+ }
+ else if (rna_type == PROP_ENUM) {
+ RNA_property_enum_set(&lptr, lprop, delta.i);
+ }
+ }
+
+ RNA_property_update(C, &lptr, prop);
+ }
+ }
+}
+
+#endif /* USE_ALLSELECT */
+
+
static bool ui_but_contains_point_px_icon(uiBut *but, ARegion *ar, const wmEvent *event)
{
rcti rect;
@@ -1281,10 +1629,11 @@ static bool ui_but_drag_init(bContext *C, uiBut *but, uiHandleButtonData *data,
ar_prev = CTX_wm_region(C);
CTX_wm_region_set(C, data->region);
- WM_event_add_ui_handler(C, &data->window->modalhandlers,
- ui_handler_region_drag_toggle,
- ui_handler_region_drag_toggle_remove,
- drag_info, false);
+ WM_event_add_ui_handler(
+ C, &data->window->modalhandlers,
+ ui_handler_region_drag_toggle,
+ ui_handler_region_drag_toggle_remove,
+ drag_info, WM_HANDLER_BLOCKING);
CTX_wm_region_set(C, ar_prev);
}
@@ -1599,9 +1948,8 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
data->str = data->origstr;
data->origstr = NULL;
data->value = data->origvalue;
- data->origvalue = 0.0;
copy_v3_v3(data->vec, data->origvec);
- data->origvec[0] = data->origvec[1] = data->origvec[2] = 0.0f;
+ /* postpone clearing origdata */
}
else {
/* we avoid applying interactive edits a second time
@@ -1612,6 +1960,27 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
else if (data->applied_interactive) {
return;
}
+
+#ifdef USE_ALLSELECT
+# ifdef USE_DRAG_MULTINUM
+ if (but->flag & UI_BUT_DRAG_MULTI) {
+ /* pass */
+ }
+ else
+# endif
+ if (data->select_others.elems_len == 0) {
+ wmWindow *win = CTX_wm_window(C);
+ /* may have been enabled before activating */
+ if (data->select_others.is_enabled || IS_ALLSELECT_EVENT(win->eventstate)) {
+ ui_selectcontext_begin(C, but, &data->select_others);
+ data->select_others.is_enabled = true;
+ }
+ }
+ if (data->select_others.elems_len == 0) {
+ /* dont check again */
+ data->select_others.elems_len = -1;
+ }
+#endif
}
/* ensures we are writing actual values */
@@ -1632,7 +2001,6 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
ui_apply_but_BUT(C, but, data);
break;
case UI_BTYPE_TEXT:
- case UI_BTYPE_SEARCH_MENU_UNLINK:
case UI_BTYPE_SEARCH_MENU:
ui_apply_but_TEX(C, but, data);
break;
@@ -1708,7 +2076,7 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
if (data->multi_data.has_mbuts) {
if (data->multi_data.init == BUTTON_MULTI_INIT_ENABLE) {
if (data->cancel) {
- ui_multibut_restore(data, block);
+ ui_multibut_restore(C, data, block);
}
else {
ui_multibut_states_apply(C, data, block);
@@ -1717,6 +2085,15 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
}
#endif
+#ifdef USE_ALLSELECT
+ ui_selectcontext_apply(C, but, &data->select_others, data->value, data->origvalue);
+#endif
+
+ if (data->cancel) {
+ data->origvalue = 0.0;
+ zero_v3(data->origvec);
+ }
+
but->editstr = editstr;
but->editval = editval;
but->editvec = editvec;
@@ -1735,13 +2112,13 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB
for (wmd = drags->first; wmd; wmd = wmd->next) {
if (wmd->type == WM_DRAG_ID) {
/* align these types with UI_but_active_drop_name */
- if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
ID *id = (ID *)wmd->poin;
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
BLI_strncpy(data->str, id->name + 2, data->maxlen);
- if (ELEM(but->type, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, UI_BTYPE_SEARCH_MENU)) {
but->changed = true;
ui_searchbox_update(C, data->searchbox, but, true);
}
@@ -1882,7 +2259,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
}
/* text/string and ID data */
- else if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ else if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
uiHandleButtonData *active_data = but->active;
if (but->poin == NULL && but->rnapoin.data == NULL) {
@@ -1902,7 +2279,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
else
BLI_strncpy(active_data->str, buf_paste, active_data->maxlen);
- if (ELEM(but->type, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (but->type == UI_BTYPE_SEARCH_MENU) {
/* else uiSearchboxData.active member is not updated [#26856] */
but->changed = true;
ui_searchbox_update(C, data->searchbox, but, true);
@@ -1977,15 +2354,17 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
}
}
-/* ************************ password text ******************************
+/**
+ * Password Text
+ * =============
*
* Functions to convert password strings that should not be displayed
- * to asterisk representation (e.g. mysecretpasswd -> *************)
+ * to asterisk representation (e.g. 'mysecretpasswd' -> '*************')
*
* It converts every UTF-8 character to an asterisk, and also remaps
* the cursor position and selection start/end.
*
- * Note: remaping is used, because password could contain UTF-8 characters.
+ * \note: remaping is used, because password could contain UTF-8 characters.
*
*/
@@ -2095,7 +2474,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
BLI_strncpy(origstr, but->editstr, data->maxlen);
- if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
if (but->flag & UI_HAS_ICON) {
startx += UI_DPI_ICON_SIZE / aspect;
}
@@ -2185,11 +2564,13 @@ static void ui_textedit_set_cursor_select(uiBut *but, uiHandleButtonData *data,
ui_but_update(but);
}
-/* this is used for both utf8 and ascii, its meant to be used for single keys,
+/**
+ * This is used for both utf8 and ascii, its meant to be used for single keys,
* notice the buffer is either copied or not, so its not suitable for pasting in
* - campbell */
-static bool ui_textedit_type_buf(uiBut *but, uiHandleButtonData *data,
- const char *utf8_buf, int utf8_buf_len)
+static bool ui_textedit_type_buf(
+ uiBut *but, uiHandleButtonData *data,
+ const char *utf8_buf, int utf8_buf_len)
{
char *str;
int len;
@@ -2233,8 +2614,9 @@ static bool ui_textedit_type_ascii(uiBut *but, uiHandleButtonData *data, char as
return ui_textedit_type_buf(but, data, buf, 1);
}
-static void ui_textedit_move(uiBut *but, uiHandleButtonData *data, strCursorJumpDirection direction,
- const bool select, strCursorJumpType jump)
+static void ui_textedit_move(
+ uiBut *but, uiHandleButtonData *data, strCursorJumpDirection direction,
+ const bool select, strCursorJumpType jump)
{
const char *str = data->str;
const int len = strlen(str);
@@ -2450,6 +2832,18 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in
}
#ifdef WITH_INPUT_IME
+/* test if the translation context allows IME input - used to
+ * avoid weird character drawing if IME inputs non-ascii chars */
+static bool ui_ime_is_lang_supported(void)
+{
+ const char *uilng = BLF_lang_get();
+ const bool is_lang_supported = STREQ(uilng, "zh_CN") ||
+ STREQ(uilng, "zh_TW") ||
+ STREQ(uilng, "ja_JP");
+
+ return ((U.transopts & USER_DOTRANSLATE) && is_lang_supported);
+}
+
/* enable ime, and set up uibut ime data */
static void ui_textedit_ime_begin(wmWindow *win, uiBut *UNUSED(but))
{
@@ -2480,8 +2874,7 @@ void ui_but_ime_reposition(uiBut *but, int x, int y, bool complete)
wm_window_IME_begin(but->active->window, x, y - 4, 0, 0, complete);
}
-/* should be ui_but_ime_data_get */
-wmIMEData *ui_but_get_ime_data(uiBut *but)
+wmIMEData *ui_but_ime_data_get(uiBut *but)
{
if (but->active && but->active->window) {
return but->active->window->ime_data;
@@ -2515,6 +2908,16 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
}
#endif
+#ifdef USE_ALLSELECT
+ if (is_num_but) {
+ if (IS_ALLSELECT_EVENT(win->eventstate)) {
+ data->select_others.is_enabled = true;
+ data->select_others.is_copy = true;
+
+ }
+ }
+#endif
+
/* retrieve string */
data->maxlen = ui_but_string_get_max_length(but);
data->str = MEM_callocN(sizeof(char) * data->maxlen + 1, "textedit str");
@@ -2542,7 +2945,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
but->selend = len;
/* optional searchbox */
- if (ELEM(but->type, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (but->type == UI_BTYPE_SEARCH_MENU) {
data->searchbox = ui_searchbox_create(C, data->region, but);
ui_searchbox_update(C, data->searchbox, but, true); /* true = reset */
}
@@ -2555,7 +2958,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
WM_cursor_modal_set(win, BC_TEXTEDITCURSOR);
#ifdef WITH_INPUT_IME
- if (is_num_but == false) {
+ if (is_num_but == false && ui_ime_is_lang_supported()) {
ui_textedit_ime_begin(win, but);
}
#endif
@@ -2792,6 +3195,9 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
ui_searchbox_event(C, data->searchbox, but, event);
break;
}
+ if (event->type == WHEELDOWNMOUSE) {
+ break;
+ }
/* fall-through */
case ENDKEY:
ui_textedit_move(but, data, STRCUR_DIR_NEXT,
@@ -2807,6 +3213,9 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
ui_searchbox_event(C, data->searchbox, but, event);
break;
}
+ if (event->type == WHEELUPMOUSE) {
+ break;
+ }
/* fall-through */
case HOMEKEY:
ui_textedit_move(but, data, STRCUR_DIR_PREV,
@@ -2857,8 +3266,6 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
if (autocomplete == AUTOCOMPLETE_FULL_MATCH)
button_activate_state(C, but, BUTTON_STATE_EXIT);
-
- update = true; /* do live update for tab key */
}
/* the hotkey here is not well defined, was G.qual so we check all */
else if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) {
@@ -2937,7 +3344,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
#endif
if (changed) {
- /* only update when typing for TAB key */
+ /* only do live update when but flag request it (UI_BUT_TEXTEDIT_UPDATE). */
if (update && data->interactive) {
ui_apply_but(C, block, but, data, true);
}
@@ -3095,6 +3502,17 @@ static void ui_block_open_begin(bContext *C, uiBut *but, uiHandleButtonData *dat
data->menu->popup = but->block->handle->popup;
}
+ but->flag |= UI_BUT_MENU_ROOT;
+
+#ifdef USE_ALLSELECT
+ {
+ wmWindow *win = CTX_wm_window(C);
+ if (IS_ALLSELECT_EVENT(win->eventstate)) {
+ data->select_others.is_enabled = true;
+ }
+ }
+#endif
+
/* this makes adjacent blocks auto open from now on */
//if (but->block->auto_open == 0) but->block->auto_open = 1;
}
@@ -3124,9 +3542,13 @@ int ui_but_menu_direction(uiBut *but)
return 0;
}
-/* Hack for uiList UI_BTYPE_LISTROW buttons to "give" events to overlaying UI_BTYPE_TEXT buttons (cltr-clic rename feature & co). */
-static uiBut *ui_but_list_row_text_activate(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event,
- uiButtonActivateType activate_type)
+/**
+ * Hack for #uiList #UI_BTYPE_LISTROW buttons to "give" events to overlaying #UI_BTYPE_TEXT buttons
+ * (Ctrl-Click rename feature & co).
+ */
+static uiBut *ui_but_list_row_text_activate(
+ bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event,
+ uiButtonActivateType activate_type)
{
ARegion *ar = CTX_wm_region(C);
uiBut *labelbut = ui_but_find_mouse_over_ex(ar, event->x, event->y, true);
@@ -3296,9 +3718,11 @@ static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
+ uiButExtraIconType extra_icon_type;
+
/* unlink icon is on right */
- if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS &&
- ui_but_is_search_unlink_visible(but))
+ if ((ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY)) &&
+ ((extra_icon_type = ui_but_icon_extra_get(but)) != UI_BUT_ICONEXTRA_NONE))
{
ARegion *ar = data->region;
rcti rect;
@@ -3309,14 +3733,29 @@ static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHa
BLI_rcti_rctf_copy(&rect, &but->rect);
rect.xmin = rect.xmax - (BLI_rcti_size_y(&rect));
+ /* handle click on unlink/eyedropper icon */
if (BLI_rcti_isect_pt(&rect, x, y)) {
- /* most likely NULL, but let's check, and give it temp zero string */
- if (data->str == NULL)
- data->str = MEM_callocN(1, "temp str");
- data->str[0] = 0;
+ /* doing this on KM_PRESS calls eyedropper after clicking unlink icon */
+ if (event->val == KM_RELEASE) {
+ /* unlink */
+ if (extra_icon_type == UI_BUT_ICONEXTRA_UNLINK) {
+ /* most likely NULL, but let's check, and give it temp zero string */
+ if (data->str == NULL) {
+ data->str = MEM_callocN(1, "temp str");
+ }
+ data->str[0] = 0;
- ui_apply_but_TEX(C, but, data);
- button_activate_state(C, but, BUTTON_STATE_EXIT);
+ ui_apply_but_TEX(C, but, data);
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ }
+ /* eyedropper */
+ else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
+ WM_operator_name_call(C, "UI_OT_eyedropper_id", WM_OP_INVOKE_DEFAULT, NULL);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
return WM_UI_HANDLER_BREAK;
}
@@ -3355,7 +3794,7 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
button_activate_state(C, but, BUTTON_STATE_EXIT);
return WM_UI_HANDLER_BREAK;
}
- else if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
+ else if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->ctrl) {
/* Support alt+wheel on expanded enum rows */
if (but->type == UI_BTYPE_ROW) {
const int direction = (event->type == WHEELDOWNMOUSE) ? -1 : 1;
@@ -3451,8 +3890,9 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
}
/* var names match ui_numedit_but_NUM */
-static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, float softmax, float softrange,
- const enum eSnapType snap)
+static float ui_numedit_apply_snapf(
+ uiBut *but, float tempf, float softmin, float softmax, float softrange,
+ const enum eSnapType snap)
{
if (tempf == softmin || tempf == softmax || snap == SNAP_OFF) {
/* pass */
@@ -3480,15 +3920,25 @@ static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, floa
softrange /= fac;
}
+ /* workaround, too high snapping values */
+ /* snapping by 10's for float buttons is quite annoying (location, scale...),
+ * but allow for rotations */
+ if ((softrange > 2100.0f)) {
+ int unit_type = UI_but_unit_type_get(but);
+ if (!ELEM(unit_type, PROP_UNIT_ROTATION)) {
+ softrange = 20.0f;
+ }
+ }
+
if (snap == SNAP_ON) {
- if (softrange < 2.10f) tempf = 0.1f * floorf(10.0f * tempf);
- else if (softrange < 21.0f) tempf = floorf(tempf);
- else tempf = 10.0f * floorf(tempf / 10.0f);
+ if (softrange < 2.10f) tempf = roundf(tempf * 10.0f) * 0.1f;
+ else if (softrange < 21.0f) tempf = roundf(tempf);
+ else tempf = roundf(tempf * 0.1f) * 10.0f;
}
else if (snap == SNAP_ON_SMALL) {
- if (softrange < 2.10f) tempf = 0.01f * floorf(100.0f * tempf);
- else if (softrange < 21.0f) tempf = 0.1f * floorf(10.0f * tempf);
- else tempf = floor(tempf);
+ if (softrange < 2.10f) tempf = roundf(tempf * 100.0f) * 0.01f;
+ else if (softrange < 21.0f) tempf = roundf(tempf * 10.0f) * 0.1f;
+ else tempf = roundf(tempf);
}
else {
BLI_assert(0);
@@ -3501,8 +3951,9 @@ static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, floa
return tempf;
}
-static float ui_numedit_apply_snap(int temp, float softmin, float softmax,
- const enum eSnapType snap)
+static float ui_numedit_apply_snap(
+ int temp, float softmin, float softmax,
+ const enum eSnapType snap)
{
if (temp == softmin || temp == softmax)
return temp;
@@ -3521,9 +3972,10 @@ static float ui_numedit_apply_snap(int temp, float softmin, float softmax,
return temp;
}
-static bool ui_numedit_but_NUM(uiBut *but, uiHandleButtonData *data,
- int mx,
- const enum eSnapType snap, float fac)
+static bool ui_numedit_but_NUM(
+ uiBut *but, uiHandleButtonData *data,
+ int mx,
+ const enum eSnapType snap, float fac)
{
float deler, tempf, softmin, softmax, softrange;
int lvalue, temp;
@@ -3639,7 +4091,7 @@ static bool ui_numedit_but_NUM(uiBut *but, uiHandleButtonData *data,
if (!is_float) {
- temp = floorf(tempf + 0.5f);
+ temp = iroundf(tempf);
temp = ui_numedit_apply_snap(temp, softmin, softmax, snap);
@@ -3692,11 +4144,11 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
/* XXX hardcoded keymap check.... */
if (type == MOUSEPAN && event->alt)
retval = WM_UI_HANDLER_BREAK; /* allow accumulating values, otherwise scrolling gets preference */
- else if (type == WHEELDOWNMOUSE && event->alt) {
+ else if (type == WHEELDOWNMOUSE && event->ctrl) {
mx = but->rect.xmin;
click = 1;
}
- else if (type == WHEELUPMOUSE && event->alt) {
+ else if (type == WHEELUPMOUSE && event->ctrl) {
mx = but->rect.xmax;
click = 1;
}
@@ -3762,7 +4214,6 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
fac = 1.0f;
if (event->shift) fac /= 10.0f;
- if (event->alt) fac /= 20.0f;
if (ui_numedit_but_NUM(but, data, (ui_but_is_cursor_warp(but) ? screen_mx : mx), snap, fac))
ui_numedit_apply(C, block, but, data);
@@ -3857,9 +4308,10 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
return retval;
}
-static bool ui_numedit_but_SLI(uiBut *but, uiHandleButtonData *data,
- int mx, const bool is_horizontal,
- const bool snap, const bool shift)
+static bool ui_numedit_but_SLI(
+ uiBut *but, uiHandleButtonData *data,
+ int mx, const bool is_horizontal,
+ const bool snap, const bool shift)
{
float deler, f, tempf, softmin, softmax, softrange;
int temp, lvalue;
@@ -3912,7 +4364,7 @@ static bool ui_numedit_but_SLI(uiBut *but, uiHandleButtonData *data,
tempf = softmin + f * softrange;
- temp = floorf(tempf + 0.5f);
+ temp = iroundf(tempf);
if (snap) {
if (tempf == softmin || tempf == softmax) {
@@ -3922,14 +4374,14 @@ static bool ui_numedit_but_SLI(uiBut *but, uiHandleButtonData *data,
if (shift) {
if (tempf == softmin || tempf == softmax) {}
- else if (softmax - softmin < 2.10f) tempf = 0.01f * floorf(100.0f * tempf);
- else if (softmax - softmin < 21.0f) tempf = 0.1f * floorf(10.0f * tempf);
- else tempf = floorf(tempf);
+ else if (softrange < 2.10f) tempf = roundf(tempf * 100.0f) * 0.01f;
+ else if (softrange < 21.0f) tempf = roundf(tempf * 10.0f) * 0.1f;
+ else tempf = roundf(tempf);
}
else {
- if (softmax - softmin < 2.10f) tempf = 0.1f * floorf(10.0f * tempf);
- else if (softmax - softmin < 21.0f) tempf = floorf(tempf);
- else tempf = 10.0f * floorf(tempf / 10.0f);
+ if (softrange < 2.10f) tempf = roundf(tempf * 10.0f) * 0.1f;
+ else if (softrange < 21.0f) tempf = roundf(tempf);
+ else tempf = roundf(tempf * 0.1f) * 10.0f;
}
}
else {
@@ -3939,7 +4391,7 @@ static bool ui_numedit_but_SLI(uiBut *but, uiHandleButtonData *data,
}
if (!ui_but_is_float(but)) {
- lvalue = floor(data->value + 0.5);
+ lvalue = round(data->value);
CLAMP(temp, softmin, softmax);
@@ -3981,11 +4433,11 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
/* XXX hardcoded keymap check.... */
if (type == MOUSEPAN && event->alt)
retval = WM_UI_HANDLER_BREAK; /* allow accumulating values, otherwise scrolling gets preference */
- else if (type == WHEELDOWNMOUSE && event->alt) {
+ else if (type == WHEELDOWNMOUSE && event->ctrl) {
mx = but->rect.xmin;
click = 2;
}
- else if (type == WHEELUPMOUSE && event->alt) {
+ else if (type == WHEELUPMOUSE && event->ctrl) {
mx = but->rect.xmax;
click = 2;
}
@@ -3994,6 +4446,7 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
retval = WM_UI_HANDLER_BREAK;
}
+#ifndef USE_ALLSELECT
/* alt-click on sides to get "arrows" like in UI_BTYPE_NUM buttons, and match wheel usage above */
else if (event->type == LEFTMOUSE && event->alt) {
int halfpos = BLI_rctf_cent_x(&but->rect);
@@ -4003,6 +4456,7 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
else
mx = but->rect.xmax;
}
+#endif
else if (event->type == LEFTMOUSE) {
data->dragstartx = mx;
data->draglastx = mx;
@@ -4289,7 +4743,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
return WM_UI_HANDLER_BREAK;
}
else if (but->type == UI_BTYPE_MENU) {
- if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
+ if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->ctrl) {
const int direction = (event->type == WHEELDOWNMOUSE) ? -1 : 1;
data->value = ui_but_menu_step(but, direction);
@@ -4345,9 +4799,10 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
return WM_UI_HANDLER_CONTINUE;
}
-static bool ui_numedit_but_UNITVEC(uiBut *but, uiHandleButtonData *data,
- int mx, int my,
- const enum eSnapType snap)
+static bool ui_numedit_but_UNITVEC(
+ uiBut *but, uiHandleButtonData *data,
+ int mx, int my,
+ const enum eSnapType snap)
{
float dx, dy, rad, radsq, mrad, *fp;
int mdx, mdy;
@@ -4413,7 +4868,7 @@ static bool ui_numedit_but_UNITVEC(uiBut *but, uiHandleButtonData *data,
* do this in "angle" space - this gives increments of same size */
for (i = 0; i < 3; i++) {
angle = asinf(fp[i]);
- angle_snap = floorf(0.5f + (angle / snap_steps_angle)) * snap_steps_angle;
+ angle_snap = roundf((angle / snap_steps_angle)) * snap_steps_angle;
fp[i] = sinf(angle_snap);
}
normalize_v3(fp);
@@ -4463,7 +4918,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
return WM_UI_HANDLER_BREAK;
}
- else if (ELEM(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
+ else if (ELEM(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->ctrl) {
ColorPicker *cpicker = but->custom_data;
float hsv_static[3] = {0.0f};
float *hsv = cpicker ? cpicker->color_data : hsv_static;
@@ -4497,6 +4952,12 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
BKE_palette_color_remove(palette, color);
button_activate_state(C, but, BUTTON_STATE_EXIT);
+
+ /* this is risky. it works OK for now,
+ * but if it gives trouble we should delay execution */
+ but->rnapoin = PointerRNA_NULL;
+ but->rnaprop = NULL;
+
return WM_UI_HANDLER_BREAK;
}
}
@@ -4641,9 +5102,10 @@ static void ui_color_picker_to_rgb_HSVCUBE_v(uiBut *but, const float hsv[3], flo
hsv_to_rgb_v(hsv, rgb);
}
-static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
- int mx, int my,
- const enum eSnapType snap, const bool shift)
+static bool ui_numedit_but_HSVCUBE(
+ uiBut *but, uiHandleButtonData *data,
+ int mx, int my,
+ const enum eSnapType snap, const bool shift)
{
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
@@ -4702,8 +5164,8 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
switch ((int)but->a1) {
case UI_GRAD_SV:
- hsv[2] = x;
- hsv[1] = y;
+ hsv[1] = x;
+ hsv[2] = y;
break;
case UI_GRAD_HV:
hsv[0] = x;
@@ -4760,9 +5222,10 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
return changed;
}
-static void ui_ndofedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
- const wmNDOFMotionData *ndof,
- const enum eSnapType snap, const bool shift)
+static void ui_ndofedit_but_HSVCUBE(
+ uiBut *but, uiHandleButtonData *data,
+ const wmNDOFMotionData *ndof,
+ const enum eSnapType snap, const bool shift)
{
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
@@ -4780,8 +5243,8 @@ static void ui_ndofedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
switch ((int)but->a1) {
case UI_GRAD_SV:
- hsv[2] += ndof->rvec[2] * sensitivity;
- hsv[1] += ndof->rvec[0] * sensitivity;
+ hsv[1] += ndof->rvec[2] * sensitivity;
+ hsv[2] += ndof->rvec[0] * sensitivity;
break;
case UI_GRAD_HV:
hsv[0] += ndof->rvec[2] * sensitivity;
@@ -4925,9 +5388,10 @@ static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
return WM_UI_HANDLER_CONTINUE;
}
-static bool ui_numedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data,
- float mx, float my,
- const enum eSnapType snap, const bool shift)
+static bool ui_numedit_but_HSVCIRCLE(
+ uiBut *but, uiHandleButtonData *data,
+ float mx, float my,
+ const enum eSnapType snap, const bool shift)
{
rcti rect;
bool changed = true;
@@ -5022,9 +5486,10 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data,
return changed;
}
-static void ui_ndofedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data,
- const wmNDOFMotionData *ndof,
- const enum eSnapType snap, const bool shift)
+static void ui_ndofedit_but_HSVCIRCLE(
+ uiBut *but, uiHandleButtonData *data,
+ const wmNDOFMotionData *ndof,
+ const enum eSnapType snap, const bool shift)
{
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
@@ -5283,7 +5748,8 @@ static int ui_do_but_COLORBAND(bContext *C, uiBlock *block, uiBut *but, uiHandle
return WM_UI_HANDLER_CONTINUE;
}
-static bool ui_numedit_but_CURVE(uiBlock *block, uiBut *but, uiHandleButtonData *data,
+static bool ui_numedit_but_CURVE(
+ uiBlock *block, uiBut *but, uiHandleButtonData *data,
int evtx, int evty,
bool snap, const bool shift)
{
@@ -5333,8 +5799,8 @@ static bool ui_numedit_but_CURVE(uiBlock *block, uiBut *but, uiHandleButtonData
cmp[a].x += fx;
cmp[a].y += fy;
if (snap) {
- cmp[a].x = 0.125f * floorf(0.5f + 8.0f * cmp[a].x);
- cmp[a].y = 0.125f * floorf(0.5f + 8.0f * cmp[a].y);
+ cmp[a].x = 0.125f * roundf(8.0f * cmp[a].x);
+ cmp[a].y = 0.125f * roundf(8.0f * cmp[a].y);
}
if (cmp[a].x != origx || cmp[a].y != origy)
moved_point = true;
@@ -5717,9 +6183,10 @@ static int ui_do_but_LINK(bContext *C, uiBut *but, uiHandleButtonData *data, con
return WM_UI_HANDLER_CONTINUE;
}
-static bool ui_numedit_but_TRACKPREVIEW(bContext *C, uiBut *but, uiHandleButtonData *data,
- int mx, int my,
- const bool shift)
+static bool ui_numedit_but_TRACKPREVIEW(
+ bContext *C, uiBut *but, uiHandleButtonData *data,
+ int mx, int my,
+ const bool shift)
{
MovieClipScopes *scopes = (MovieClipScopes *)but->poin;
bool changed = true;
@@ -5928,7 +6395,7 @@ static void menu_add_shortcut_cancel(struct bContext *C, void *arg1)
static void popup_change_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiBut *but = (uiBut *)arg1;
- button_timers_tooltip_remove(C, but);
+ UI_but_tooltip_timer_remove(C, but);
UI_popup_block_invoke(C, menu_change_shortcut, but);
}
@@ -5949,7 +6416,7 @@ static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiBut *but = (uiBut *)arg1;
- button_timers_tooltip_remove(C, but);
+ UI_but_tooltip_timer_remove(C, but);
UI_popup_block_ex(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but);
}
@@ -5983,6 +6450,33 @@ void ui_panel_menu(bContext *C, ARegion *ar, Panel *pa)
UI_popup_menu_end(C, pup);
}
+static void ui_menu_scripting(bContext *UNUSED(C), uiLayout *layout, void *arg)
+{
+ uiBut *but = arg;
+
+ if (!ui_block_is_menu(but->block)) {
+ uiItemFullO(layout, "UI_OT_editsource", NULL, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, 0);
+ }
+
+ uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Data Path"),
+ ICON_NONE, "UI_OT_copy_data_path_button", "full", 0);
+ uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Full Data Path"),
+ ICON_NONE, "UI_OT_copy_data_path_button", "full", 1);
+
+ if (but->rnapoin.data && but->rnaprop) {
+ PointerRNA ptr_props;
+ char buf[512];
+
+ BLI_snprintf(buf, sizeof(buf), "%s.%s",
+ RNA_struct_identifier(but->rnapoin.type), RNA_property_identifier(but->rnaprop));
+
+ 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_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
+ ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
+ }
+}
+
static bool ui_but_menu(bContext *C, uiBut *but)
{
uiPopupMenu *pup;
@@ -5997,8 +6491,10 @@ static bool ui_but_menu(bContext *C, uiBut *but)
if (but->type == UI_BTYPE_IMAGE) {
return false;
}
-
- button_timers_tooltip_remove(C, but);
+
+ but->flag |= UI_BUT_MENU_ROOT;
+
+ UI_but_tooltip_timer_remove(C, but);
/* highly unlikely getting the label ever fails */
UI_but_string_info_get(C, but, &label, NULL);
@@ -6167,15 +6663,16 @@ static bool ui_but_menu(bContext *C, uiBut *but)
uiItemO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Unset"),
ICON_NONE, "UI_OT_unset_property_button");
}
-
- uiItemO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Data Path"),
- ICON_NONE, "UI_OT_copy_data_path_button");
uiItemO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Copy To Selected"),
ICON_NONE, "UI_OT_copy_to_selected_button");
uiItemS(layout);
}
+ /* Scripting submenu */
+ uiItemMenuF(layout, IFACE_("Scripting"), ICON_NONE, ui_menu_scripting, but);
+ uiItemS(layout);
+
/* Operator buttons */
if (but->optype) {
uiBlock *block = uiLayoutGetBlock(layout);
@@ -6214,7 +6711,7 @@ static bool ui_but_menu(bContext *C, uiBut *but)
}
/* Show header tools for header buttons. */
- {
+ if (ui_block_is_menu(but->block) == false) {
ARegion *ar = CTX_wm_region(C);
if (ar && (ar->regiontype == RGN_TYPE_HEADER)) {
uiItemMenuF(layout, IFACE_("Header"), ICON_NONE, ED_screens_header_tools_menu_create, NULL);
@@ -6224,21 +6721,11 @@ static bool ui_but_menu(bContext *C, uiBut *but)
{ /* Docs */
char buf[512];
- PointerRNA ptr_props;
-
- if (but->rnapoin.data && but->rnaprop) {
- BLI_snprintf(buf, sizeof(buf), "%s.%s",
- RNA_struct_identifier(but->rnapoin.type), RNA_property_identifier(but->rnaprop));
-
- WM_operator_properties_create(&ptr_props, "WM_OT_doc_view_manual");
- RNA_string_set(&ptr_props, "doc_id", buf);
- uiItemFullO(layout, "WM_OT_doc_view_manual", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Online Manual"),
- ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
+ // PointerRNA ptr_props;
- 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_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
- ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
+ if (UI_but_online_manual_id(but, buf, sizeof(buf))) {
+ uiItemO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Online Manual"),
+ ICON_NONE, "WM_OT_doc_view_manual_ui_context");
/* XXX inactive option, not for public! */
#if 0
@@ -6249,30 +6736,6 @@ static bool ui_but_menu(bContext *C, uiBut *but)
uiItemFullO(layout, "WM_OT_doc_edit", "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0);
#endif
}
- else if (but->optype) {
- WM_operator_py_idname(buf, but->optype->idname);
-
-
- WM_operator_properties_create(&ptr_props, "WM_OT_doc_view_manual");
- RNA_string_set(&ptr_props, "doc_id", buf);
- uiItemFullO(layout, "WM_OT_doc_view_manual", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Online Manual"),
- ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
-
- 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_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
- ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
-
- /* XXX inactive option, not for public! */
-#if 0
- WM_operator_properties_create(&ptr_props, "WM_OT_doc_edit");
- RNA_string_set(&ptr_props, "doc_id", buf);
- RNA_string_set(&ptr_props, "doc_new", but->optype->description);
-
- uiItemFullO(layout, "WM_OT_doc_edit", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Submit Description"),
- ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0);
-#endif
- }
}
/* perhaps we should move this into (G.debug & G_DEBUG) - campbell */
@@ -6328,7 +6791,9 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
WM_operator_name_call(C, "UI_OT_eyedropper_color", WM_OP_INVOKE_DEFAULT, NULL);
return WM_UI_HANDLER_BREAK;
}
- else if (but->type == UI_BTYPE_SEARCH_MENU_UNLINK) {
+ else if ((but->type == UI_BTYPE_SEARCH_MENU) &&
+ (but->flag & UI_BUT_SEARCH_UNLINK))
+ {
if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_POINTER) {
StructRNA *type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
const short idcode = RNA_type_to_ID_code(type);
@@ -6485,11 +6950,16 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
break;
case UI_BTYPE_TEXT:
case UI_BTYPE_SEARCH_MENU:
+ if ((but->type == UI_BTYPE_SEARCH_MENU) &&
+ (but->flag & UI_BUT_SEARCH_UNLINK))
+ {
+ retval = ui_do_but_SEARCH_UNLINK(C, block, but, data, event);
+ if (retval & WM_UI_HANDLER_BREAK) {
+ break;
+ }
+ }
retval = ui_do_but_TEX(C, block, but, data, event);
break;
- case UI_BTYPE_SEARCH_MENU_UNLINK:
- retval = ui_do_but_SEARCH_UNLINK(C, block, but, data, event);
- break;
case UI_BTYPE_MENU:
case UI_BTYPE_BLOCK:
case UI_BTYPE_PULLDOWN:
@@ -6728,7 +7198,7 @@ bool UI_but_active_drop_name(bContext *C)
uiBut *but = ui_but_find_active_in_region(ar);
if (but) {
- if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK))
+ if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU))
return 1;
}
@@ -6843,13 +7313,6 @@ static bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
return true;
}
-bool ui_but_is_search_unlink_visible(const uiBut *but)
-{
- BLI_assert(but->type == UI_BTYPE_SEARCH_MENU_UNLINK);
- return ((but->editstr == NULL) &&
- (but->drawstr[0] != '\0'));
-}
-
/* x and y are only used in case event is NULL... */
static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, const bool labeledit)
{
@@ -6937,7 +7400,8 @@ static bool button_modal_state(uiHandleButtonState state)
BUTTON_STATE_MENU_OPEN);
}
-static void button_timers_tooltip_remove(bContext *C, uiBut *but)
+/* removes tooltip timer from active but (meaning tooltip is disabled until it's reenabled again) */
+void UI_but_tooltip_timer_remove(bContext *C, uiBut *but)
{
uiHandleButtonData *data;
@@ -7021,7 +7485,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
}
else {
but->flag |= UI_SELECT;
- button_timers_tooltip_remove(C, but);
+ UI_but_tooltip_timer_remove(C, but);
}
/* text editing */
@@ -7083,7 +7547,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
if (!(but->block->handle && but->block->handle->popup)) {
if (button_modal_state(state)) {
if (!button_modal_state(data->state))
- WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_menu, NULL, data, false);
+ WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_menu, NULL, data, 0);
}
else {
if (button_modal_state(data->state)) {
@@ -7128,7 +7592,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
copy_v2_fl(data->ungrab_mval, FLT_MAX);
#endif
- if (ELEM(but->type, UI_BTYPE_CURVE, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, UI_BTYPE_CURVE, UI_BTYPE_SEARCH_MENU)) {
/* XXX curve is temp */
}
else {
@@ -7188,8 +7652,9 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
}
}
-static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *data,
- const bool mousemove, const bool onfree)
+static void button_activate_exit(
+ bContext *C, uiBut *but, uiHandleButtonData *data,
+ const bool mousemove, const bool onfree)
{
uiBlock *block = but->block;
uiBut *bt;
@@ -7261,6 +7726,10 @@ static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *da
if (data->origstr)
MEM_freeN(data->origstr);
+#ifdef USE_ALLSELECT
+ ui_selectcontext_end(but, &data->select_others);
+#endif
+
/* redraw (data is but->active!) */
ED_region_tag_redraw(data->region);
@@ -7467,7 +7936,7 @@ void UI_context_update_anim_flag(const bContext *C)
/************** handle activating a button *************/
-static uiBut *uit_but_find_open_event(ARegion *ar, const wmEvent *event)
+static uiBut *ui_but_find_open_event(ARegion *ar, const wmEvent *event)
{
uiBlock *block;
uiBut *but;
@@ -7498,7 +7967,7 @@ static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *ar)
}
}
else if (event->type == EVT_BUT_OPEN) {
- but = uit_but_find_open_event(ar, event);
+ but = ui_but_find_open_event(ar, event);
if (but) {
button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER);
ui_do_button(C, but->block, but, event);
@@ -7602,7 +8071,8 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
uiBut *but_other = ui_but_find_mouse_over(ar, event);
bool exit = false;
- if ((!ui_block_is_menu(block) || ui_block_is_pie_menu(but->block)) &&
+ /* always deactivate button for pie menus, else moving to blank space will leave activated */
+ if ((!ui_block_is_menu(block) || ui_block_is_pie_menu(block)) &&
!ui_but_contains_point_px(ar, but, event->x, event->y))
{
exit = true;
@@ -7650,7 +8120,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
case WHEELDOWNMOUSE:
case MIDDLEMOUSE:
case MOUSEPAN:
- button_timers_tooltip_remove(C, but);
+ UI_but_tooltip_timer_remove(C, but);
/* fall-through */
default:
/* handle button type specific events */
@@ -7811,7 +8281,7 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar)
if (val == KM_PRESS) {
if (ELEM(type, UPARROWKEY, DOWNARROWKEY) ||
- ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt)))
+ ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->ctrl)))
{
const int value_orig = RNA_property_int_get(&but->rnapoin, but->rnaprop);
int value, min, max, inc;
@@ -7907,160 +8377,6 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar)
return retval;
}
-static rctf UI_subblock_boundbox_set(uiBlock *block, const char *subblock_id)
-{
- uiBut *but;
- rctf rect;
-
- if (subblock_id && subblock_id[0]) {
- for (but = block->buttons.first; but; but = but->next) {
- if (but->subblock_id[0] && STREQ(but->subblock_id, subblock_id)) {
- if (BLI_rctf_is_empty(&rect)) {
- rect = but->rect;
- }
- BLI_rctf_union(&rect, &but->rect);
- }
- }
- }
- else {
- /* return empty rect */
- rect.xmin = rect.xmax = rect.ymin = rect.ymax = 0;
- }
- return rect;
-}
-
-static char *UI_subblock_get_prev_id(uiBlock *block, const char *subblock_id)
-{
- int i;
-
- for (i = 1; i < block->subblock.tot_subblocks; i++) {
- if (STREQ(block->subblock.subblock_id[i], subblock_id)) {
- if (block->subblock.subblock_id[i - 1] && block->subblock.subblock_id[i - 1][0]) {
- return block->subblock.subblock_id[i - 1];
- }
- }
- }
- return NULL;
-}
-
-static char *UI_subblock_get_next_id(uiBlock *block, const char *subblock_id)
-{
- int i;
-
- for (i = 0; i < block->subblock.tot_subblocks; i++) {
- if (STREQ(block->subblock.subblock_id[i], subblock_id)) {
- if (block->subblock.subblock_id[i + 1] && block->subblock.subblock_id[i + 1][0]) {
- return block->subblock.subblock_id[i + 1];
- }
- }
- }
- return NULL;
-}
-
-static void UI_subblock_neighbours_rects_set(uiBlock *block, const char *subblock_id)
-{
- block->subblock.rect_above = UI_subblock_boundbox_set(block, UI_subblock_get_prev_id(block, subblock_id));
- block->subblock.rect_below = UI_subblock_boundbox_set(block, UI_subblock_get_next_id(block, subblock_id));
-}
-
-static int ui_subblock_handler(bContext *C, const wmEvent *event, void *userdata)
-{
- uiBut *but = (uiBut *)userdata;
- uiBlock *block = but->block;
-
- if (UI_subblock_is_dragging(block) == false)
- return WM_UI_HANDLER_CONTINUE;
-
- if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
- wmWindow *win = CTX_wm_window(C);
- ARegion *ar = CTX_wm_region(C);
-
- block->subblock.drag_state = 0;
- block->subblock.dragged_subblock[0] = '\0';
-
- /* remove sub-block dragging handler, bring back region handler */
- WM_event_remove_ui_handler(&win->modalhandlers, ui_subblock_handler, NULL, but, false);
- WM_event_add_ui_handler(NULL, &ar->handlers, ui_region_handler, ui_region_handler_remove, NULL, false);
-
- WM_event_add_mousemove(C);
- }
- else if (event->type == MOUSEMOVE) {
- PointerRNA ptr_props;
- /* XXX - ugly hardcoded operator calls, grrrr... */
- /* up */
- if ((BLI_rctf_is_empty(&block->subblock.rect_above) == false) &&
- (block->subblock.rect.ymax > block->subblock.rect_above.ymax))
- {
- WM_operator_properties_create(&ptr_props, "OBJECT_OT_modifier_move_up");
- RNA_string_set(&ptr_props, "modifier", block->subblock.dragged_subblock);
- WM_operator_name_call(C, "OBJECT_OT_modifier_move_up", WM_OP_INVOKE_DEFAULT, &ptr_props);
-
- WM_operator_properties_free(&ptr_props);
-
- copy_v2_v2_int(block->subblock.drag_xy_prev, &event->x);
- UI_subblock_neighbours_rects_set(block, UI_subblock_get_prev_id(block, but->subblock_id));
- }
- /* down */
- else if ((BLI_rctf_is_empty(&block->subblock.rect_below) == false) &&
- (block->subblock.rect.ymax < block->subblock.rect_below.ymax))
- {
- WM_operator_properties_create(&ptr_props, "OBJECT_OT_modifier_move_down");
- RNA_string_set(&ptr_props, "modifier", block->subblock.dragged_subblock);
- WM_operator_name_call(C, "OBJECT_OT_modifier_move_down", WM_OP_INVOKE_DEFAULT, &ptr_props);
-
- WM_operator_properties_free(&ptr_props);
-
- copy_v2_v2_int(block->subblock.drag_xy_prev, &event->x);
- UI_subblock_neighbours_rects_set(block, UI_subblock_get_next_id(block, but->subblock_id));
- }
- else {
- block->subblock.rect = UI_subblock_boundbox_set(block, but->subblock_id);
- }
- ED_region_tag_redraw(CTX_wm_region(C));
- }
-
- return WM_UI_HANDLER_BREAK;
-}
-
-static int ui_handle_block_region(bContext *C, const wmEvent *event, uiBut *but)
-{
- uiBlock *block;
-
- if (!but)
- return WM_UI_HANDLER_CONTINUE;
-
- block = but->block;
-
- if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
- BLI_assert(block->subblock.drag_state == UI_BLOCK_DRAGSTATE_NONE);
- if (block->flag & UI_BLOCK_DRAGGABLE && but->icon == ICON_GRIP) { /* XXX better check - but->flag? */
- if (but->subblock_id[0]) {
- wmWindow *win = CTX_wm_window(C);
- ARegion *ar = CTX_wm_region(C);
- int mx, my = event->y;
-
- /* initialize drag data */
- block->subblock.drag_state = UI_BLOCK_DRAGSTATE_DRAGGING;
- block->subblock.rect = UI_subblock_boundbox_set(block, but->subblock_id);
- copy_v2_v2_int(block->subblock.drag_xy_prev, &event->x);
- UI_subblock_neighbours_rects_set(block, but->subblock_id);
- BLI_strncpy(block->subblock.dragged_subblock, but->subblock_id, MAX_NAME);
-
- ui_window_to_block(ar, block, &mx, &my);
- block->subblock.click_xy[1] = my - (int)block->subblock.rect.ymin;
-
- /* add modal handler for dragging, remove ui handler to avoid conflicts */
- WM_event_add_ui_handler(C, &win->modalhandlers, ui_subblock_handler, NULL, but, false);
- WM_event_remove_ui_handler(&ar->handlers, ui_region_handler, ui_region_handler_remove, NULL, false);
-
- return WM_UI_HANDLER_BREAK;
- }
- }
- }
-
- return WM_UI_HANDLER_CONTINUE;
-}
-
static void ui_handle_button_return_submenu(bContext *C, const wmEvent *event, uiBut *but)
{
uiHandleButtonData *data;
@@ -8115,13 +8431,14 @@ static void ui_handle_button_return_submenu(bContext *C, const wmEvent *event, u
/* ************************* menu handling *******************************/
-/* function used to prevent loosing the open menu when using nested pulldowns,
+/**
+ * Function used to prevent loosing the open menu when using nested pulldowns,
* when moving mouse towards the pulldown menu over other buttons that could
* steal the highlight from the current button, only checks:
*
* - while mouse moves in triangular area defined old mouse position and
- * left/right side of new menu
- * - only for 1 second
+ * left/right side of new menu.
+ * - only for 1 second.
*/
static void ui_mouse_motion_towards_init_ex(uiPopupBlockHandle *menu, const int xy[2], const bool force)
@@ -8150,8 +8467,9 @@ static void ui_mouse_motion_towards_reinit(uiPopupBlockHandle *menu, const int x
ui_mouse_motion_towards_init_ex(menu, xy, true);
}
-static bool ui_mouse_motion_towards_check(uiBlock *block, uiPopupBlockHandle *menu, const int xy[2],
- const bool use_wiggle_room)
+static bool ui_mouse_motion_towards_check(
+ uiBlock *block, uiPopupBlockHandle *menu, const int xy[2],
+ const bool use_wiggle_room)
{
float p1[2], p2[2], p3[2], p4[2];
float oldp[2] = {menu->towards_xy[0], menu->towards_xy[1]};
@@ -8339,8 +8657,9 @@ static int ui_menu_scroll(ARegion *ar, uiBlock *block, int my, uiBut *to_bt)
*
* Without this keyboard navigation from menu's wont work.
*/
-static bool ui_menu_pass_event_to_parent_if_nonactive(uiPopupBlockHandle *menu, const uiBut *but,
- const int level, const int retval)
+static bool ui_menu_pass_event_to_parent_if_nonactive(
+ uiPopupBlockHandle *menu, const uiBut *but,
+ const int level, const int retval)
{
if ((level != 0) && (but == NULL)) {
menu->menuretval = UI_RETURN_OUT | UI_RETURN_OUT_PARENT;
@@ -8779,7 +9098,7 @@ static int ui_handle_menu_event(
{
if (!but || !ui_but_contains_point_px(ar, but, event->x, event->y)) {
if (but) {
- button_timers_tooltip_remove(C, but);
+ UI_but_tooltip_timer_remove(C, but);
}
menu->is_grab = true;
@@ -8858,6 +9177,9 @@ static int ui_handle_menu_return_submenu(bContext *C, const wmEvent *event, uiPo
block = ar->uiblocks.first;
but = ui_but_find_active_in_region(ar);
+
+ BLI_assert(but);
+
data = but->active;
submenu = data->menu;
@@ -9257,7 +9579,7 @@ static int ui_handle_menus_recursive(
/* now handle events for our own menu */
if (retval == WM_UI_HANDLER_CONTINUE || event->type == TIMER) {
- const bool do_but_search = (but && ELEM(but->type, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK));
+ const bool do_but_search = (but && (but->type == UI_BTYPE_SEARCH_MENU));
if (submenu && submenu->menuretval) {
const bool do_ret_out_parent = (submenu->menuretval & UI_RETURN_OUT_PARENT) != 0;
retval = ui_handle_menu_return_submenu(C, event, menu);
@@ -9323,9 +9645,6 @@ static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(use
retval = ui_handler_panel_region(C, event, ar);
if (retval == WM_UI_HANDLER_CONTINUE)
- retval = ui_handle_block_region(C, event, but);
-
- if (retval == WM_UI_HANDLER_CONTINUE)
retval = ui_handle_list_event(C, event, ar);
if (retval == WM_UI_HANDLER_CONTINUE) {
@@ -9544,12 +9863,12 @@ static void ui_popup_handler_remove(bContext *C, void *userdata)
void UI_region_handlers_add(ListBase *handlers)
{
WM_event_remove_ui_handler(handlers, ui_region_handler, ui_region_handler_remove, NULL, false);
- WM_event_add_ui_handler(NULL, handlers, ui_region_handler, ui_region_handler_remove, NULL, false);
+ WM_event_add_ui_handler(NULL, handlers, ui_region_handler, ui_region_handler_remove, NULL, 0);
}
-void UI_popup_handlers_add(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup, const bool accept_dbl_click)
+void UI_popup_handlers_add(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup, const char flag)
{
- WM_event_add_ui_handler(C, handlers, ui_popup_handler, ui_popup_handler_remove, popup, accept_dbl_click);
+ WM_event_add_ui_handler(C, handlers, ui_popup_handler, ui_popup_handler_remove, popup, flag);
}
void UI_popup_handlers_remove(ListBase *handlers, uiPopupBlockHandle *popup)
@@ -9562,8 +9881,9 @@ void UI_popup_handlers_remove_all(bContext *C, ListBase *handlers)
WM_event_free_ui_handler_all(C, handlers, ui_popup_handler, ui_popup_handler_remove);
}
-bool UI_textbutton_activate_rna(const bContext *C, ARegion *ar,
- const void *rna_poin_data, const char *rna_prop_id)
+bool UI_textbutton_activate_rna(
+ const bContext *C, ARegion *ar,
+ const void *rna_poin_data, const char *rna_prop_id)
{
uiBlock *block;
uiBut *but = NULL;
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 679681cb372..626dbbb6f08 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -55,6 +55,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "IMB_thumbs.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -514,6 +515,13 @@ static void init_brush_icons(void)
INIT_BRUSH_ICON(ICON_BRUSH_THUMB, thumb);
INIT_BRUSH_ICON(ICON_BRUSH_ROTATE, twist);
INIT_BRUSH_ICON(ICON_BRUSH_VERTEXDRAW, vertexdraw);
+ INIT_BRUSH_ICON(ICON_BRUSH_HAIR_COMB, haircomb);
+ INIT_BRUSH_ICON(ICON_BRUSH_HAIR_CUT, haircut);
+ INIT_BRUSH_ICON(ICON_BRUSH_HAIR_LENGTH, hairlength);
+ INIT_BRUSH_ICON(ICON_BRUSH_HAIR_PUFF, hairpuff);
+ INIT_BRUSH_ICON(ICON_BRUSH_HAIR_ADD, hairadd);
+ INIT_BRUSH_ICON(ICON_BRUSH_HAIR_SMOOTH, hairsmooth);
+ INIT_BRUSH_ICON(ICON_BRUSH_HAIR_WEIGHT, hairweight);
#undef INIT_BRUSH_ICON
}
@@ -888,11 +896,9 @@ int UI_icon_get_height(int icon_id)
void UI_icons_init(int first_dyn_id)
{
-#ifdef WITH_HEADLESS
- (void)first_dyn_id;
-#else
- init_iconfile_list(&iconfilelist);
BKE_icons_init(first_dyn_id);
+#ifndef WITH_HEADLESS
+ init_iconfile_list(&iconfilelist);
init_internal_icons();
init_brush_icons();
init_matcap_icons();
@@ -904,10 +910,13 @@ void UI_icons_init(int first_dyn_id)
static int preview_render_size(enum eIconSizes size)
{
switch (size) {
- case ICON_SIZE_ICON: return 32;
- case ICON_SIZE_PREVIEW: return PREVIEW_DEFAULT_HEIGHT;
+ case ICON_SIZE_ICON:
+ return ICON_RENDER_DEFAULT_HEIGHT;
+ case ICON_SIZE_PREVIEW:
+ return PREVIEW_RENDER_DEFAULT_HEIGHT;
+ default:
+ return 0;
}
- return 0;
}
/* Create rect for the icon
@@ -923,12 +932,49 @@ static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size)
else if (!prv_img->rect[size]) {
prv_img->w[size] = render_size;
prv_img->h[size] = render_size;
- prv_img->changed[size] = 1;
+ prv_img->flag[size] |= PRV_CHANGED;
prv_img->changed_timestamp[size] = 0;
prv_img->rect[size] = MEM_callocN(render_size * render_size * sizeof(unsigned int), "prv_rect");
}
}
+void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool big)
+{
+ Icon *icon = BKE_icon_get(icon_id);
+
+ if (icon) {
+ DrawInfo *di = (DrawInfo *)icon->drawinfo;
+
+ if (!di) {
+ di = icon_create_drawinfo();
+
+ icon->drawinfo = di;
+ icon->drawinfo_free = UI_icons_free_drawinfo;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+ }
+ }
+ }
+}
+
/* only called when icon has changed */
/* only call with valid pointer from UI_icon_draw */
static void icon_set_image(
@@ -940,6 +986,11 @@ static void icon_set_image(
return;
}
+ if (prv_img->flag[size] & PRV_USER_EDITED) {
+ /* user-edited preview, do not auto-update! */
+ return;
+ }
+
icon_create_rect(prv_img, size);
if (use_job) {
@@ -951,7 +1002,7 @@ static void icon_set_image(
scene = CTX_data_scene(C);
}
/* Immediate version */
- ED_preview_icon_render(scene, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]);
+ ED_preview_icon_render(CTX_data_main(C), scene, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]);
}
}
@@ -961,22 +1012,32 @@ PreviewImage *UI_icon_to_preview(int icon_id)
if (icon) {
DrawInfo *di = (DrawInfo *)icon->drawinfo;
- if (di && di->data.buffer.image) {
- ImBuf *bbuf;
-
- bbuf = IMB_ibImageFromMemory(di->data.buffer.image->datatoc_rect, di->data.buffer.image->datatoc_size, IB_rect, NULL, "<matcap buffer>");
- if (bbuf) {
- PreviewImage *prv = BKE_previewimg_create();
-
- prv->rect[0] = bbuf->rect;
+ if (di) {
+ if (di->type == ICON_TYPE_PREVIEW) {
+ PreviewImage *prv = (icon->type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : icon->obj;
- prv->w[0] = bbuf->x;
- prv->h[0] = bbuf->y;
-
- bbuf->rect = NULL;
- IMB_freeImBuf(bbuf);
-
- return prv;
+ if (prv) {
+ return BKE_previewimg_copy(prv);
+ }
+ }
+ else if (di->data.buffer.image) {
+ ImBuf *bbuf;
+
+ bbuf = IMB_ibImageFromMemory(di->data.buffer.image->datatoc_rect, di->data.buffer.image->datatoc_size,
+ IB_rect, NULL, __func__);
+ if (bbuf) {
+ PreviewImage *prv = BKE_previewimg_create();
+
+ prv->rect[0] = bbuf->rect;
+
+ prv->w[0] = bbuf->x;
+ prv->h[0] = bbuf->y;
+
+ bbuf->rect = NULL;
+ IMB_freeImBuf(bbuf);
+
+ return prv;
+ }
}
}
}
@@ -987,6 +1048,10 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect),
unsigned int *rect, float alpha, const float rgb[3], const bool is_preview)
{
ImBuf *ima = NULL;
+ int draw_w = w;
+ int draw_h = h;
+ int draw_x = x;
+ int draw_y = y;
/* sanity check */
if (w <= 0 || h <= 0 || w > 2000 || h > 2000) {
@@ -1006,21 +1071,34 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect),
}
/* rect contains image in 'rendersize', we only scale if needed */
- if (rw != w && rh != h) {
+ if (rw != w || rh != h) {
+ /* preserve aspect ratio and center */
+ if (rw > rh) {
+ draw_w = w;
+ draw_h = (int)(((float)rh / (float)rw) * (float)w);
+ draw_y += (h - draw_h) / 2;
+ }
+ else if (rw < rh) {
+ draw_w = (int)(((float)rw / (float)rh) * (float)h);
+ draw_h = h;
+ draw_x += (w - draw_w) / 2;
+ }
+ /* if the image is squared, the draw_ initialization values are good */
+
/* first allocate imbuf for scaling and copy preview into it */
ima = IMB_allocImBuf(rw, rh, 32, IB_rect);
memcpy(ima->rect, rect, rw * rh * sizeof(unsigned int));
- IMB_scaleImBuf(ima, w, h); /* scale it */
+ IMB_scaleImBuf(ima, draw_w, draw_h); /* scale it */
rect = ima->rect;
}
/* draw */
if (is_preview) {
- glaDrawPixelsSafe(x, y, w, h, w, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ glaDrawPixelsSafe(draw_x, draw_y, draw_w, draw_h, draw_w, GL_RGBA, GL_UNSIGNED_BYTE, rect);
}
else {
- glRasterPos2f(x, y);
- glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ glRasterPos2f(draw_x, draw_y);
+ glDrawPixels(draw_w, draw_h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
}
if (ima)
@@ -1037,8 +1115,9 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect),
}
}
-static void icon_draw_texture(float x, float y, float w, float h, int ix, int iy,
- int UNUSED(iw), int ih, float alpha, const float rgb[3])
+static void icon_draw_texture(
+ float x, float y, float w, float h, int ix, int iy,
+ int UNUSED(iw), int ih, float alpha, const float rgb[3])
{
float x1, x2, y1, y2;
@@ -1080,16 +1159,20 @@ static void icon_draw_texture(float x, float y, float w, float h, int ix, int iy
static int get_draw_size(enum eIconSizes size)
{
switch (size) {
- case ICON_SIZE_ICON: return ICON_DEFAULT_HEIGHT;
- case ICON_SIZE_PREVIEW: return PREVIEW_DEFAULT_HEIGHT;
+ case ICON_SIZE_ICON:
+ return ICON_DEFAULT_HEIGHT;
+ case ICON_SIZE_PREVIEW:
+ return PREVIEW_DEFAULT_HEIGHT;
+ default:
+ return 0;
}
- return 0;
}
-static void icon_draw_size(float x, float y, int icon_id, float aspect, float alpha, const float rgb[3],
- enum eIconSizes size, int draw_size, const bool UNUSED(nocreate), const bool is_preview)
+static void icon_draw_size(
+ float x, float y, int icon_id, float aspect, float alpha, const float rgb[3],
+ enum eIconSizes size, int draw_size, const bool UNUSED(nocreate), const bool is_preview)
{
bTheme *btheme = UI_GetTheme();
Icon *icon = NULL;
@@ -1145,15 +1228,15 @@ static void icon_draw_size(float x, float y, int icon_id, float aspect, float al
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
else if (di->type == ICON_TYPE_PREVIEW) {
- PreviewImage *pi = BKE_previewimg_get((ID *)icon->obj);
+ PreviewImage *pi = (icon->type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : icon->obj;
if (pi) {
/* no create icon on this level in code */
if (!pi->rect[size]) return; /* something has gone wrong! */
/* preview images use premul alpha ... */
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- icon_draw_rect(x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], 1.0f, NULL, is_preview);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ icon_draw_rect(x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], alpha, rgb, is_preview);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
}
@@ -1162,17 +1245,17 @@ static void icon_draw_size(float x, float y, int icon_id, float aspect, float al
static void ui_id_preview_image_render_size(
const bContext *C, Scene *scene, ID *id, PreviewImage *pi, int size, const bool use_job)
{
- if ((pi->changed[size] || !pi->rect[size])) { /* changed only ever set by dynamic icons */
+ if (((pi->flag[size] & PRV_CHANGED) || !pi->rect[size])) { /* changed only ever set by dynamic icons */
/* create the rect if necessary */
icon_set_image(C, scene, id, pi, size, use_job);
- pi->changed[size] = 0;
+ pi->flag[size] &= ~PRV_CHANGED;
}
}
void UI_id_icon_render(const bContext *C, Scene *scene, ID *id, const bool big, const bool use_job)
{
- PreviewImage *pi = BKE_previewimg_get(id);
+ PreviewImage *pi = BKE_previewimg_id_ensure(id);
if (pi) {
if (big)
@@ -1184,7 +1267,7 @@ void UI_id_icon_render(const bContext *C, Scene *scene, ID *id, const bool big,
static void ui_id_brush_render(const bContext *C, ID *id)
{
- PreviewImage *pi = BKE_previewimg_get(id);
+ PreviewImage *pi = BKE_previewimg_id_ensure(id);
enum eIconSizes i;
if (!pi)
@@ -1193,9 +1276,9 @@ static void ui_id_brush_render(const bContext *C, ID *id)
for (i = 0; i < NUM_ICON_SIZES; i++) {
/* check if rect needs to be created; changed
* only set by dynamic icons */
- if ((pi->changed[i] || !pi->rect[i])) {
+ if (((pi->flag[i] & PRV_CHANGED) || !pi->rect[i])) {
icon_set_image(C, NULL, id, pi, i, true);
- pi->changed[i] = 0;
+ pi->flag[i] &= ~PRV_CHANGED;
}
}
}
@@ -1206,7 +1289,7 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
Brush *br = (Brush *)id;
if (br->flag & BRUSH_CUSTOM_ICON) {
- BKE_icon_getid(id);
+ BKE_icon_id_ensure(id);
ui_id_brush_render(C, id);
}
else {
@@ -1226,6 +1309,8 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
mode = OB_MODE_VERTEX_PAINT;
else if (ob->mode & OB_MODE_TEXTURE_PAINT)
mode = OB_MODE_TEXTURE_PAINT;
+ else if (ob->mode & OB_MODE_HAIR_EDIT)
+ mode = OB_MODE_HAIR_EDIT;
}
else if ((sima = CTX_wm_space_image(C)) &&
(sima->mode == SI_MODE_PAINT))
@@ -1246,6 +1331,10 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
items = brush_image_tool_items;
tool = br->imagepaint_tool;
}
+ else if (mode == OB_MODE_HAIR_EDIT) {
+ items = brush_hair_tool_items;
+ tool = br->hair_tool;
+ }
if (!items || !RNA_enum_icon_from_value(items, tool, &id->icon_id))
id->icon_id = 0;
@@ -1268,7 +1357,7 @@ int ui_id_icon_get(const bContext *C, ID *id, const bool big)
case ID_IM: /* fall through */
case ID_WO: /* fall through */
case ID_LA: /* fall through */
- iconid = BKE_icon_getid(id);
+ iconid = BKE_icon_id_ensure(id);
/* checks if not exists, or changed */
UI_id_icon_render(C, NULL, id, big, true);
break;
@@ -1317,8 +1406,9 @@ int UI_rnaptr_icon_get(bContext *C, PointerRNA *ptr, int rnaicon, const bool big
return rnaicon;
}
-static void icon_draw_at_size(float x, float y, int icon_id, float aspect, float alpha,
- enum eIconSizes size, const bool nocreate)
+static void icon_draw_at_size(
+ float x, float y, int icon_id, float aspect, float alpha,
+ enum eIconSizes size, const bool nocreate)
{
int draw_size = get_draw_size(size);
icon_draw_size(x, y, icon_id, aspect, alpha, NULL, size, draw_size, nocreate, false);
@@ -1356,8 +1446,8 @@ void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect)
icon_draw_at_size(x, y, icon_id, aspect, 1.0f, ICON_SIZE_PREVIEW, 0);
}
-void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, int size)
+void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, float alpha, int size)
{
- icon_draw_size(x, y, icon_id, aspect, 1.0f, NULL, ICON_SIZE_PREVIEW, size, false, true);
+ icon_draw_size(x, y, icon_id, aspect, alpha, NULL, ICON_SIZE_PREVIEW, size, false, true);
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index ab62691e9d1..dd1937500ec 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -40,11 +40,9 @@
struct ARegion;
struct bContext;
-struct IDProperty;
struct uiHandleButtonData;
struct wmEvent;
struct wmOperatorType;
-struct wmWindow;
struct wmTimer;
struct uiStyle;
struct uiWidgetColors;
@@ -123,6 +121,14 @@ enum {
/* warn: rest of uiBut->flag in UI_interface.h */
};
+/* some buttons display icons only under special conditions
+ * (e.g. 'x' icon in search menu) - used with ui_but_icon_extra_get */
+typedef enum uiButExtraIconType {
+ UI_BUT_ICONEXTRA_NONE = 1,
+ UI_BUT_ICONEXTRA_UNLINK,
+ UI_BUT_ICONEXTRA_EYEDROPPER,
+} uiButExtraIconType;
+
/* but->pie_dir */
typedef enum RadialDirection {
UI_RADIAL_NONE = -1,
@@ -294,9 +300,6 @@ struct uiBut {
void *dragpoin;
struct ImBuf *imb;
float imb_scale;
-
- /* block drag and drop */
- char subblock_id[64]; /* NAME_MAX */
/* active button data */
struct uiHandleButtonData *active;
@@ -335,27 +338,6 @@ struct PieMenuData {
float alphafac;
};
-/* SubBlockData->drag_state */
-enum {
- UI_BLOCK_DRAGSTATE_NONE = 0,
- UI_BLOCK_DRAGSTATE_DRAGGING = 1, /* block is being dragged */
- UI_BLOCK_DRAGSTATE_ANIMATING = 2, /* key was released -> animation is running */
-};
-
-typedef struct SubBlockData {
- char subblock_id[64][MAX_NAME]; /* buttons that have the same but->subblock_id build a sub-block */
- int tot_subblocks; /* total amount of built sub-blocks */
- rctf rect; /* bounds of the sub-block */
- bool is_subblock_building; /* set while buttons are collected to build the sub-block */
-
- /* sub-but drag data */
- short drag_state; /* current state for sub-block drag and drop */
- char dragged_subblock[MAX_NAME]; /* name of the currently dragged sub-block */
- int drag_xy_prev[2]; /* coordinates used to calc block position while dragging */
- int click_xy[2]; /* coordinates on mouse click relative to sub-block */
- rctf rect_above, rect_below; /* rectangles of the sub-blocks above and below the dragged one */
-} SubBlockData;
-
struct uiBlock {
uiBlock *next, *prev;
@@ -368,8 +350,6 @@ struct uiBlock {
ListBase layouts;
struct uiLayout *curlayout;
- SubBlockData subblock;
-
ListBase contexts;
char name[UI_MAX_NAME_STR];
@@ -471,8 +451,9 @@ extern void ui_but_hsv_set(uiBut *but);
extern void ui_but_v3_get(uiBut *but, float vec[3]);
extern void ui_but_v3_set(uiBut *but, const float vec[3]);
-extern void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rect,
- const float mx, const float my);
+extern void ui_hsvcircle_vals_from_pos(
+ float *val_rad, float *val_dist, const rcti *rect,
+ const float mx, const float my);
extern void ui_hsvcircle_pos_from_vals(struct uiBut *but, const rcti *rect, float *hsv, float *xpos, float *ypos);
extern void ui_hsvcube_pos_from_vals(struct uiBut *but, const rcti *rect, float *hsv, float *xp, float *yp);
bool ui_but_is_colorpicker_display_space(struct uiBut *but);
@@ -485,6 +466,9 @@ extern bool ui_but_string_set_eval_num(struct bContext *C, uiBut *but, const cha
extern int ui_but_string_get_max_length(uiBut *but);
extern uiBut *ui_but_drag_multi_edit_get(uiBut *but);
+void ui_def_but_icon(uiBut *but, const int icon, const int flag);
+extern uiButExtraIconType ui_but_icon_extra_get(uiBut *but);
+
extern void ui_but_default_set(struct bContext *C, const bool all, const bool use_afterfunc);
extern void ui_but_update(uiBut *but);
@@ -494,7 +478,6 @@ extern bool ui_but_is_unit(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
extern bool ui_but_is_compatible(const uiBut *but_a, const uiBut *but_b) ATTR_WARN_UNUSED_RESULT;
extern bool ui_but_is_rna_valid(uiBut *but) ATTR_WARN_UNUSED_RESULT;
extern bool ui_but_is_utf8(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
-extern bool ui_but_is_search_unlink_visible(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
extern int ui_but_is_pushed_ex(uiBut *but, double *value) ATTR_WARN_UNUSED_RESULT;
extern int ui_but_is_pushed(uiBut *but) ATTR_WARN_UNUSED_RESULT;
@@ -601,20 +584,22 @@ bool ui_searchbox_apply(uiBut *but, struct ARegion *ar);
void ui_searchbox_free(struct bContext *C, struct ARegion *ar);
void ui_but_search_refresh(uiBut *but);
-uiBlock *ui_popup_block_refresh(struct bContext *C, uiPopupBlockHandle *handle,
- ARegion *butregion, uiBut *but);
+uiBlock *ui_popup_block_refresh(
+ struct bContext *C, uiPopupBlockHandle *handle,
+ ARegion *butregion, uiBut *but);
-uiPopupBlockHandle *ui_popup_block_create(struct bContext *C, struct ARegion *butregion, uiBut *but,
- uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func,
- void *arg);
-uiPopupBlockHandle *ui_popup_menu_create(struct bContext *C, struct ARegion *butregion, uiBut *but,
- uiMenuCreateFunc create_func, void *arg);
+uiPopupBlockHandle *ui_popup_block_create(
+ struct bContext *C, struct ARegion *butregion, uiBut *but,
+ uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func,
+ void *arg);
+uiPopupBlockHandle *ui_popup_menu_create(
+ struct bContext *C, struct ARegion *butregion, uiBut *but,
+ uiMenuCreateFunc create_func, void *arg);
void ui_popup_block_free(struct bContext *C, uiPopupBlockHandle *handle);
int ui_but_menu_step(uiBut *but, int step);
-struct AutoComplete;
/* interface_panel.c */
extern int ui_handler_panel_region(struct bContext *C, const struct wmEvent *event, struct ARegion *ar);
@@ -648,6 +633,7 @@ extern int ui_but_menu_direction(uiBut *but);
extern void ui_but_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore);
extern uiBut *ui_but_find_select_in_enum(uiBut *but, int direction);
extern uiBut *ui_but_find_active_in_region(struct ARegion *ar);
+extern uiBut *ui_but_find_menu_root(struct bContext *C);
bool ui_but_is_editable(const uiBut *but);
bool ui_but_is_editable_as_text(const uiBut *but);
void ui_but_pie_dir_visual(RadialDirection dir, float vec[2]);
@@ -661,7 +647,7 @@ uiBut *ui_but_find_new(uiBlock *block_old, const uiBut *but_new);
#ifdef WITH_INPUT_IME
void ui_but_ime_reposition(uiBut *but, int x, int y, bool complete);
-struct wmIMEData *ui_but_get_ime_data(uiBut *but);
+struct wmIMEData *ui_but_ime_data_get(uiBut *but);
#endif
/* interface_widgets.c */
@@ -690,6 +676,7 @@ void ui_draw_preview_item(struct uiFontStyle *fstyle, rcti *rect, const char *na
void uiStyleInit(void);
/* interface_icons.c */
+void ui_icon_ensure_deferred(const struct bContext *C, const int icon_id, const bool big);
int ui_id_icon_get(const struct bContext *C, struct ID *id, const bool big);
/* resources.c */
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 450bda0c2bd..279d72819be 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -356,9 +356,10 @@ static void ui_layer_but_cb(bContext *C, void *arg_but, void *arg_index)
}
/* create buttons for an item with an RNA array */
-static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, int icon,
- PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int UNUSED(h),
- bool expand, bool slider, bool toggle, bool icon_only)
+static void ui_item_array(
+ uiLayout *layout, uiBlock *block, const char *name, int icon,
+ PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int UNUSED(h),
+ bool expand, bool slider, bool toggle, bool icon_only)
{
uiStyle *style = layout->root->style;
uiBut *but;
@@ -545,8 +546,9 @@ static void ui_item_enum_expand_handle(bContext *C, void *arg1, void *arg2)
RNA_property_enum_set(&but->rnapoin, but->rnaprop, current_value);
}
}
-static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop,
- const char *uiname, int h, bool icon_only)
+static void ui_item_enum_expand(
+ uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop,
+ const char *uiname, int h, bool icon_only)
{
/* XXX The way this function currently handles uiname parameter is insane and inconsistent with general UI API:
* * uiname is the *enum property* label.
@@ -877,8 +879,9 @@ void uiItemEnumO(uiLayout *layout, const char *opname, const char *name, int ico
}
-void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname, IDProperty *properties,
- int context, int flag)
+void uiItemsFullEnumO(
+ uiLayout *layout, const char *opname, const char *propname, IDProperty *properties,
+ int context, int flag)
{
wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
@@ -1129,8 +1132,9 @@ void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
/* RNA property items */
-static void ui_item_rna_size(uiLayout *layout, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop,
- int index, bool icon_only, int *r_w, int *r_h)
+static void ui_item_rna_size(
+ uiLayout *layout, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop,
+ int index, bool icon_only, int *r_w, int *r_h)
{
PropertyType type;
PropertySubType subtype;
@@ -1573,11 +1577,14 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN
/* turn button into search button */
if (searchprop) {
- but->type = RNA_property_is_unlink(prop) ? UI_BTYPE_SEARCH_MENU_UNLINK : UI_BTYPE_SEARCH_MENU;
+ but->type = UI_BTYPE_SEARCH_MENU;
but->hardmax = MAX2(but->hardmax, 256.0f);
but->rnasearchpoin = *searchptr;
but->rnasearchprop = searchprop;
but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT;
+ if (RNA_property_is_unlink(prop)) {
+ but->flag |= UI_BUT_SEARCH_UNLINK;
+ }
if (RNA_property_type(prop) == PROP_ENUM) {
/* XXX, this will have a menu string,
@@ -1677,8 +1684,9 @@ static void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
layout->root->block->flag ^= UI_BLOCK_IS_FLIP;
}
-static uiBut *ui_item_menu(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg, void *argN,
- const char *tip, bool force_menu)
+static uiBut *ui_item_menu(
+ uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg, void *argN,
+ const char *tip, bool force_menu)
{
uiBlock *block = layout->root->block;
uiBut *but;
@@ -2139,7 +2147,11 @@ static void ui_litem_layout_column(uiLayout *litem)
static RadialDirection ui_get_radialbut_vec(float vec[2], short itemnum)
{
RadialDirection dir;
- BLI_assert(itemnum < 8);
+
+ if (itemnum >= 8) {
+ itemnum %= 8;
+ printf("Warning: Pie menus with more than 8 items are currently unsupported\n");
+ }
dir = ui_radial_dir_order[itemnum];
ui_but_pie_dir(dir, vec);
@@ -2717,7 +2729,8 @@ uiLayout *uiLayoutBox(uiLayout *layout)
return (uiLayout *)ui_layout_box(layout, UI_BTYPE_ROUNDBOX);
}
-/* Check all buttons defined in this layout, and set any button flagged as UI_BUT_LIST_ITEM as active/selected.
+/**
+ * Check all buttons defined in this layout, and set any button flagged as UI_BUT_LIST_ITEM as active/selected.
* Needed to handle correctly text colors of active (selected) list item.
*/
void ui_layout_list_set_labels_active(uiLayout *layout)
@@ -2733,8 +2746,9 @@ void ui_layout_list_set_labels_active(uiLayout *layout)
}
}
-uiLayout *uiLayoutListBox(uiLayout *layout, uiList *ui_list, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr,
- PropertyRNA *actprop)
+uiLayout *uiLayoutListBox(
+ uiLayout *layout, uiList *ui_list, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr,
+ PropertyRNA *actprop)
{
uiLayoutItemBx *box = ui_layout_box(layout, UI_BTYPE_LISTBOX);
uiBut *but = box->roundbox;
@@ -3225,22 +3239,6 @@ void UI_block_layout_resolve(uiBlock *block, int *x, int *y)
}
}
-void uiLayoutSubblockBegin(uiLayout *layout, const char *identifier)
-{
- uiBlock *block = layout->root->block;
-
- block->subblock.is_subblock_building = true;
- BLI_strncpy(block->subblock.subblock_id[block->subblock.tot_subblocks], identifier, MAX_NAME);
-}
-
-void uiLayoutSubblockEnd(uiLayout *layout)
-{
- uiBlock *block = layout->root->block;
-
- block->subblock.is_subblock_building = false;
- block->subblock.tot_subblocks++;
-}
-
void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr)
{
uiBlock *block = layout->root->block;
@@ -3349,9 +3347,10 @@ static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C), void *op_pt,
#endif
/* this function does not initialize the layout, functions can be called on the layout before and after */
-void uiLayoutOperatorButs(const bContext *C, uiLayout *layout, wmOperator *op,
- bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *),
- const char label_align, const short flag)
+void uiLayoutOperatorButs(
+ const bContext *C, uiLayout *layout, wmOperator *op,
+ bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *),
+ const char label_align, const short flag)
{
if (!op->properties) {
IDPropertyTemplate val = {0};
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 41d2a90e548..88da91acc36 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -33,6 +33,7 @@
#include "DNA_screen_types.h"
#include "DNA_text_types.h" /* for UI_OT_reports_to_text */
+#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */
#include "BLI_blenlib.h"
#include "BLI_math_color.h"
@@ -43,6 +44,7 @@
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_global.h"
+#include "BKE_node.h"
#include "BKE_text.h" /* for UI_OT_reports_to_text */
#include "BKE_report.h"
@@ -92,15 +94,15 @@ static void UI_OT_reset_default_theme(wmOperatorType *ot)
static int copy_data_path_button_poll(bContext *C)
{
- PointerRNA ptr;
- PropertyRNA *prop;
- char *path;
- int index;
+ uiBut *but = ui_but_find_menu_root(C);
- UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+ /* fallback to find but->active */
+ if (but == NULL) {
+ but = UI_context_active_but_get(C);
+ }
- if (ptr.id.data && ptr.data && prop) {
- path = RNA_path_from_ID_to_property(&ptr, prop);
+ if (but && but->rnapoin.data) {
+ char *path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
if (path) {
MEM_freeN(path);
@@ -111,19 +113,20 @@ static int copy_data_path_button_poll(bContext *C)
return 0;
}
-static int copy_data_path_button_exec(bContext *C, wmOperator *UNUSED(op))
+static int copy_data_path_button_exec(bContext *C, wmOperator *op)
{
- PointerRNA ptr;
- PropertyRNA *prop;
- char *path;
- int index;
+ uiBut *but = ui_but_find_menu_root(C);
- /* try to create driver using property retrieved from UI */
- UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+ /* fallback to find but->active */
+ if (but == NULL) {
+ but = UI_context_active_but_get(C);
+ }
+
+ if (but && but->rnapoin.data) {
+ const bool full = RNA_boolean_get(op->ptr, "full");
+ char *path = full ? RNA_path_full_property_py(&but->rnapoin, but->rnaprop, -1) :
+ RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
- if (ptr.id.data && ptr.data && prop) {
- path = RNA_path_from_ID_to_property(&ptr, prop);
-
if (path) {
WM_clipboard_text_set(path, false);
MEM_freeN(path);
@@ -147,6 +150,9 @@ static void UI_OT_copy_data_path_button(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "full", 0, "Full", "Copy the full RNA data path for this property to the clipboard");
}
/* Reset to Default Values Button Operator ------------------------ */
@@ -261,7 +267,7 @@ static void UI_OT_unset_property_button(wmOperatorType *ot)
/* Copy To Selected Operator ------------------------ */
-static bool copy_to_selected_list(
+bool UI_context_copy_to_selected_list(
bContext *C, PointerRNA *ptr, PropertyRNA *prop,
ListBase *r_lb, bool *r_use_path_from_id, char **r_path)
{
@@ -277,6 +283,49 @@ static bool copy_to_selected_list(
else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
*r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
}
+ else if (RNA_struct_is_a(ptr->type, &RNA_Node) ||
+ RNA_struct_is_a(ptr->type, &RNA_NodeSocket))
+ {
+ ListBase lb = {NULL, NULL};
+ char *path = NULL;
+ bNode *node = NULL;
+
+ /* Get the node we're editing */
+ if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
+ bNodeTree *ntree = ptr->id.data;
+ bNodeSocket *sock = ptr->data;
+ if (nodeFindNode(ntree, sock, &node, NULL)) {
+ if ((path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Node)) != NULL) {
+ /* we're good! */
+ }
+ else {
+ node = NULL;
+ }
+ }
+ }
+ else {
+ node = ptr->data;
+ }
+
+ /* Now filter by type */
+ if (node) {
+ CollectionPointerLink *link, *link_next;
+ lb = CTX_data_collection_get(C, "selected_nodes");
+
+ for (link = lb.first; link; link = link_next) {
+ bNode *node_data = link->ptr.data;
+ link_next = link->next;
+
+ if (node_data->type != node->type) {
+ BLI_remlink(&lb, link);
+ MEM_freeN(link);
+ }
+ }
+ }
+
+ *r_lb = lb;
+ *r_path = path;
+ }
else if (ptr->id.data) {
ID *id = ptr->id.data;
@@ -285,6 +334,51 @@ static bool copy_to_selected_list(
*r_use_path_from_id = true;
*r_path = RNA_path_from_ID_to_property(ptr, prop);
}
+ else if (OB_DATA_SUPPORT_ID(GS(id->name))) {
+ /* check we're using the active object */
+ const short id_code = GS(id->name);
+ ListBase lb = CTX_data_collection_get(C, "selected_editable_objects");
+ char *path = RNA_path_from_ID_to_property(ptr, prop);
+
+ /* de-duplicate obdata */
+ if (!BLI_listbase_is_empty(&lb)) {
+ CollectionPointerLink *link, *link_next;
+
+ for (link = lb.first; link; link = link->next) {
+ Object *ob = link->ptr.id.data;
+ if (ob->data) {
+ ID *id_data = ob->data;
+ id_data->flag |= LIB_DOIT;
+ }
+ }
+
+ for (link = lb.first; link; link = link_next) {
+ Object *ob = link->ptr.id.data;
+ ID *id_data = ob->data;
+ link_next = link->next;
+
+ if ((id_data == NULL) ||
+ (id_data->flag & LIB_DOIT) == 0 ||
+ (id_data->lib) ||
+ (GS(id_data->name) != id_code))
+ {
+ BLI_remlink(&lb, link);
+ MEM_freeN(link);
+ }
+ else {
+ /* avoid prepending 'data' to the path */
+ RNA_id_pointer_create(id_data, &link->ptr);
+ }
+
+ if (id_data) {
+ id_data->flag &= ~LIB_DOIT;
+ }
+ }
+ }
+
+ *r_lb = lb;
+ *r_path = path;
+ }
else if (GS(id->name) == ID_SCE) {
/* Sequencer's ID is scene :/ */
/* Try to recursively find an RNA_Sequence ancestor, to handle situations like T41062... */
@@ -325,7 +419,7 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll)
CollectionPointerLink *link;
ListBase lb;
- if (!copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path))
+ if (!UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path))
return success;
for (link = lb.first; link; link = link->next) {
@@ -553,8 +647,9 @@ void UI_editsource_active_but_test(uiBut *but)
BLI_ghash_insert(ui_editsource_info->hash, but, but_store);
}
-static int editsource_text_edit(bContext *C, wmOperator *op,
- char filepath[FILE_MAX], int line)
+static int editsource_text_edit(
+ bContext *C, wmOperator *op,
+ char filepath[FILE_MAX], int line)
{
struct Main *bmain = CTX_data_main(C);
Text *text;
@@ -613,6 +708,7 @@ static int editsource_exec(bContext *C, wmOperator *op)
/* redraw and get active button python info */
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
for (BLI_ghashIterator_init(&ghi, ui_editsource_info->hash);
BLI_ghashIterator_done(&ghi) == false;
@@ -667,10 +763,12 @@ static void UI_OT_editsource(wmOperatorType *ot)
}
/* ------------------------------------------------------------------------- */
-/* EditTranslation utility funcs and operator,
- * Note: this includes utility functions and button matching checks.
- * this only works in conjunction with a py operator! */
+/**
+ * EditTranslation utility funcs and operator,
+ * \note: this includes utility functions and button matching checks.
+ * this only works in conjunction with a py operator!
+ */
static void edittranslation_find_po_file(const char *root, const char *uilng, char *path, const size_t maxlen)
{
char tstr[32]; /* Should be more than enough! */
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 3c78b6fce8a..665266edb9f 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -82,6 +82,14 @@
/* only show pin header button for pinned panels */
#define USE_PIN_HIDDEN
+/* the state of the mouse position relative to the panel */
+typedef enum uiPanelMouseState {
+ PANEL_MOUSE_OUTSIDE, /* mouse is not in the panel */
+ PANEL_MOUSE_INSIDE_CONTENT, /* mouse is in the actual panel content */
+ PANEL_MOUSE_INSIDE_HEADER, /* mouse is in the panel header */
+ PANEL_MOUSE_INSIDE_SCALE, /* mouse is inside panel scale widget */
+} uiPanelMouseState;
+
typedef enum uiHandlePanelState {
PANEL_STATE_DRAG,
PANEL_STATE_DRAG_SCALE,
@@ -202,8 +210,9 @@ static void ui_panel_copy_offset(Panel *pa, Panel *papar)
}
-/* XXX Disabled paneltab handling for now. Old 2.4x feature, *DO NOT* confuse it with new tool tabs in 2.70. ;)
- * See also T41704.
+/**
+ * XXX Disabled paneltab handling for now. Old 2.4x feature, *DO NOT* confuse it with new tool tabs in 2.70. ;)
+ * See also T41704.
*/
/* #define UI_USE_PANELTAB */
@@ -560,6 +569,8 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
rcti headrect;
rctf itemrect;
int ofsx;
+ const bool is_closed_x = (panel->flag & PNL_CLOSEDX) ? true : false;
+ const bool is_closed_y = (panel->flag & PNL_CLOSEDY) ? true : false;
if (panel->paneltab) return;
if (panel->type && (panel->type->flag & PNL_NO_HEADER)) return;
@@ -572,7 +583,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
{
float minx = rect->xmin;
- float maxx = rect->xmax;
+ float maxx = is_closed_x ? (minx + PNL_HEADER / block->aspect) : rect->xmax;
float y = headrect.ymax;
glEnable(GL_BLEND);
@@ -587,8 +598,11 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
}
else if (!(panel->runtime_flag & PNL_FIRST)) {
/* draw embossed separator */
- minx += 5.0f / block->aspect;
- maxx -= 5.0f / block->aspect;
+
+ if (is_closed_x == false) {
+ minx += 5.0f / block->aspect;
+ maxx -= 5.0f / block->aspect;
+ }
glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
fdrawline(minx, y, maxx, y);
@@ -615,7 +629,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
}
/* horizontal title */
- if (!(panel->flag & PNL_CLOSEDX)) {
+ if (is_closed_x == false) {
ui_draw_aligned_panel_header(style, block, &headrect, 'h');
/* itemrect smaller */
@@ -624,16 +638,17 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
itemrect.ymin = headrect.ymin;
itemrect.ymax = headrect.ymax;
- BLI_rctf_scale(&itemrect, 0.7f); /* XXX hardcoded size */
+ BLI_rctf_scale(&itemrect, 0.7f);
ui_draw_panel_dragwidget(&itemrect);
}
/* if the panel is minimized vertically:
* (------)
*/
- if (panel->flag & PNL_CLOSEDY) {
+ if (is_closed_y) {
+ /* skip */
}
- else if (panel->flag & PNL_CLOSEDX) {
+ else if (is_closed_x) {
/* draw vertical title */
ui_draw_aligned_panel_header(style, block, &headrect, 'v');
}
@@ -680,9 +695,9 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
BLI_rctf_scale(&itemrect, 0.35f);
- if (panel->flag & PNL_CLOSEDY)
+ if (is_closed_y)
ui_draw_tria_rect(&itemrect, 'h');
- else if (panel->flag & PNL_CLOSEDX)
+ else if (is_closed_x)
ui_draw_tria_rect(&itemrect, 'h');
else
ui_draw_tria_rect(&itemrect, 'v');
@@ -729,11 +744,13 @@ typedef struct PanelSort {
Panel *pa, *orig;
} PanelSort;
-/* note about sorting;
+/**
+ * \note about sorting;
* the sortorder has a lower value for new panels being added.
* however, that only works to insert a single panel, when more new panels get
* added the coordinates of existing panels and the previously stored to-be-inserted
- * panels do not match for sorting */
+ * panels do not match for sorting
+ */
static int find_leftmost_panel(const void *a1, const void *a2)
{
@@ -1128,6 +1145,157 @@ static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel)
/******************* region level panel interaction *****************/
+static uiPanelMouseState ui_panel_mouse_state_get(const uiBlock *block, const Panel *pa, const int mx, const int my)
+{
+ /* open panel */
+ if (pa->flag & PNL_CLOSEDX) {
+ if ((block->rect.xmin <= mx) && (block->rect.xmin + PNL_HEADER >= mx)) {
+ return PANEL_MOUSE_INSIDE_HEADER;
+ }
+ }
+ /* outside left/right side */
+ else if ((block->rect.xmin > mx) || (block->rect.xmax < mx)) {
+ /* pass */
+ }
+ else if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) {
+ return PANEL_MOUSE_INSIDE_HEADER;
+ }
+ /* open panel */
+ else if (!(pa->flag & PNL_CLOSEDY)) {
+ if (pa->control & UI_PNL_SCALE) {
+ if (block->rect.xmax - PNL_HEADER <= mx) {
+ if (block->rect.ymin + PNL_HEADER >= my) {
+ return PANEL_MOUSE_INSIDE_SCALE;
+ }
+ }
+ }
+ if ((block->rect.xmin <= mx) && (block->rect.xmax >= mx)) {
+ if ((block->rect.ymin <= my) && (block->rect.ymax + PNL_HEADER >= my)) {
+ return PANEL_MOUSE_INSIDE_CONTENT;
+ }
+ }
+ }
+ return PANEL_MOUSE_OUTSIDE;
+}
+
+typedef struct uiPanelDragCollapseHandle {
+ bool was_first_open;
+ int xy_init[2];
+} uiPanelDragCollapseHandle;
+
+static void ui_panel_drag_collapse_handler_remove(bContext *UNUSED(C), void *userdata)
+{
+ uiPanelDragCollapseHandle *dragcol_data = userdata;
+ MEM_freeN(dragcol_data);
+}
+
+static void ui_panel_drag_collapse(bContext *C, uiPanelDragCollapseHandle *dragcol_data, const int xy_dst[2])
+{
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ uiBlock *block;
+ Panel *pa;
+
+ for (block = ar->uiblocks.first; block; block = block->next) {
+ float xy_a_block[2] = {UNPACK2(dragcol_data->xy_init)};
+ float xy_b_block[2] = {UNPACK2(xy_dst)};
+ rctf rect = block->rect;
+ int oldflag;
+ const bool is_horizontal = (panel_aligned(sa, ar) == BUT_HORIZONTAL);
+
+ if ((pa = block->panel) == 0 || (pa->type && (pa->type->flag & PNL_NO_HEADER))) {
+ continue;
+ }
+ oldflag = pa->flag;
+
+ /* lock one axis */
+ if (is_horizontal) {
+ xy_b_block[1] = dragcol_data->xy_init[1];
+ }
+ else {
+ xy_b_block[0] = dragcol_data->xy_init[0];
+ }
+
+ /* use cursor coords in block space */
+ ui_window_to_block_fl(ar, block, &xy_a_block[0], &xy_a_block[1]);
+ ui_window_to_block_fl(ar, block, &xy_b_block[0], &xy_b_block[1]);
+
+ /* set up rect to match header size */
+ rect.ymin = rect.ymax;
+ rect.ymax = rect.ymin + PNL_HEADER;
+ if (pa->flag & PNL_CLOSEDX) {
+ rect.xmax = rect.xmin + PNL_HEADER;
+ }
+
+ /* touch all panels between last mouse coord and the current one */
+ if (BLI_rctf_isect_segment(&rect, xy_a_block, xy_b_block)) {
+ /* force panel to close */
+ if (dragcol_data->was_first_open == true) {
+ pa->flag |= (is_horizontal ? PNL_CLOSEDX : PNL_CLOSEDY);
+ }
+ /* force panel to open */
+ else {
+ pa->flag &= ~PNL_CLOSED;
+ }
+
+ /* if pa->flag has changed this means a panel was opened/closed here */
+ if (pa->flag != oldflag) {
+ panel_activate_state(C, pa, PANEL_STATE_ANIMATION);
+ }
+ }
+ }
+}
+
+/**
+ * Panel drag-collapse (modal handler)
+ * Clicking and dragging over panels toggles their collapse state based on the panel that was first
+ * dragged over. If it was open all affected panels incl the initial one are closed and vise versa.
+ */
+static int ui_panel_drag_collapse_handler(bContext *C, const wmEvent *event, void *userdata)
+{
+ wmWindow *win = CTX_wm_window(C);
+ uiPanelDragCollapseHandle *dragcol_data = userdata;
+ short retval = WM_UI_HANDLER_CONTINUE;
+
+ switch (event->type) {
+ case MOUSEMOVE:
+ ui_panel_drag_collapse(C, dragcol_data, &event->x);
+
+ retval = WM_UI_HANDLER_BREAK;
+ break;
+ case LEFTMOUSE:
+ if (event->val == KM_RELEASE) {
+ /* done! */
+ WM_event_remove_ui_handler(
+ &win->modalhandlers,
+ ui_panel_drag_collapse_handler,
+ ui_panel_drag_collapse_handler_remove,
+ dragcol_data, true);
+ ui_panel_drag_collapse_handler_remove(C, dragcol_data);
+ }
+ /* don't let any left-mouse event fall through! */
+ retval = WM_UI_HANDLER_BREAK;
+ break;
+ }
+
+ return retval;
+}
+
+static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was_open)
+{
+ wmWindow *win = CTX_wm_window(C);
+ wmEvent *event = win->eventstate;
+ uiPanelDragCollapseHandle *dragcol_data = MEM_mallocN(sizeof(*dragcol_data), __func__);
+
+ dragcol_data->was_first_open = was_open;
+ copy_v2_v2_int(dragcol_data->xy_init, &event->x);
+
+ WM_event_add_ui_handler(
+ C, &win->modalhandlers,
+ ui_panel_drag_collapse_handler,
+ ui_panel_drag_collapse_handler_remove,
+ dragcol_data, 0);
+}
/* this function is supposed to call general window drawing too */
/* also it supposes a block has panel, and isn't a menu */
@@ -1187,23 +1355,39 @@ static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, in
ED_region_tag_redraw(ar);
}
else { /* collapse */
- if (ctrl)
+ if (ctrl) {
panels_collapse_all(sa, ar, block->panel);
+ /* reset the view - we don't want to display a view without content */
+ UI_view2d_offset(&ar->v2d, 0.0f, 1.0f);
+ }
+
if (block->panel->flag & PNL_CLOSED) {
block->panel->flag &= ~PNL_CLOSED;
/* snap back up so full panel aligns with screen edge */
if (block->panel->snap & PNL_SNAP_BOTTOM)
block->panel->ofsy = 0;
+
+ if (event == LEFTMOUSE) {
+ ui_panel_drag_collapse_handler_add(C, false);
+ }
}
else if (align == BUT_HORIZONTAL) {
block->panel->flag |= PNL_CLOSEDX;
+
+ if (event == LEFTMOUSE) {
+ ui_panel_drag_collapse_handler_add(C, true);
+ }
}
else {
- /* snap down to bottom screen edge*/
+ /* snap down to bottom screen edge */
block->panel->flag |= PNL_CLOSEDY;
if (block->panel->snap & PNL_SNAP_BOTTOM)
block->panel->ofsy = -block->panel->sizey;
+
+ if (event == LEFTMOUSE) {
+ ui_panel_drag_collapse_handler_add(C, true);
+ }
}
for (pa = ar->panels.first; pa; pa = pa->next) {
@@ -1332,10 +1516,11 @@ void UI_panel_category_clear_all(ARegion *ar)
}
/* based on UI_draw_roundbox_gl_mode, check on making a version which allows us to skip some sides */
-static void ui_panel_category_draw_tab(int mode, float minx, float miny, float maxx, float maxy, float rad,
- int roundboxtype,
- const bool use_highlight, const bool use_shadow,
- const unsigned char highlight_fade[3])
+static void ui_panel_category_draw_tab(
+ int mode, float minx, float miny, float maxx, float maxy, float rad,
+ int roundboxtype,
+ const bool use_highlight, const bool use_shadow,
+ const unsigned char highlight_fade[3])
{
float vec[4][2] = {
{0.195, 0.02},
@@ -1718,8 +1903,8 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
}
for (block = ar->uiblocks.last; block; block = block->prev) {
- bool inside = false, inside_header = false, inside_scale = false;
-
+ uiPanelMouseState mouse_state;
+
mx = event->x;
my = event->y;
ui_window_to_block(ar, block, &mx, &my);
@@ -1731,32 +1916,11 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
continue;
if (pa->type && pa->type->flag & PNL_NO_HEADER) /* XXX - accessed freed panels when scripts reload, need to fix. */
continue;
-
- /* clicked at panel header? */
- if (pa->flag & PNL_CLOSEDX) {
- if (block->rect.xmin <= mx && block->rect.xmin + PNL_HEADER >= mx)
- inside_header = true;
- }
- else if (block->rect.xmin > mx || block->rect.xmax < mx) {
- /* outside left/right side */
- }
- else if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) {
- inside_header = true;
- }
- else if (!(pa->flag & PNL_CLOSEDY)) {
- /* open panel */
- if (pa->control & UI_PNL_SCALE) {
- if (block->rect.xmax - PNL_HEADER <= mx)
- if (block->rect.ymin + PNL_HEADER >= my)
- inside_scale = true;
- }
- if (block->rect.xmin <= mx && block->rect.xmax >= mx)
- if (block->rect.ymin <= my && block->rect.ymax + PNL_HEADER >= my)
- inside = true;
- }
-
+
+ mouse_state = ui_panel_mouse_state_get(block, pa, mx, my);
+
/* XXX hardcoded key warning */
- if ((inside || inside_header) && event->val == KM_PRESS) {
+ if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER) && event->val == KM_PRESS) {
if (event->type == AKEY && ((event->ctrl + event->oskey + event->shift + event->alt) == 0)) {
if (pa->flag & PNL_CLOSEDY) {
@@ -1775,13 +1939,13 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
if (ui_but_is_active(ar))
continue;
- if (inside || inside_header) {
+ if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) {
if (event->val == KM_PRESS) {
/* open close on header */
if (ELEM(event->type, RETKEY, PADENTER)) {
- if (inside_header) {
+ if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) {
ui_handle_panel_header(C, block, mx, my, RETKEY, event->ctrl, event->shift);
retval = WM_UI_HANDLER_BREAK;
break;
@@ -1791,12 +1955,12 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
/* all inside clicks should return in break - overlapping/float panels */
retval = WM_UI_HANDLER_BREAK;
- if (inside_header) {
- ui_handle_panel_header(C, block, mx, my, 0, event->ctrl, event->shift);
+ if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) {
+ ui_handle_panel_header(C, block, mx, my, event->type, event->ctrl, event->shift);
retval = WM_UI_HANDLER_BREAK;
break;
}
- else if (inside_scale && !(pa->flag & PNL_CLOSED)) {
+ else if ((mouse_state == PANEL_MOUSE_INSIDE_SCALE) && !(pa->flag & PNL_CLOSED)) {
panel_activate_state(C, pa, PANEL_STATE_DRAG_SCALE);
retval = WM_UI_HANDLER_BREAK;
break;
@@ -1804,7 +1968,7 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
}
else if (event->type == RIGHTMOUSE) {
- if (inside_header) {
+ if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) {
ui_panel_menu(C, ar, block->panel);
retval = WM_UI_HANDLER_BREAK;
break;
@@ -1943,7 +2107,7 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat
data = MEM_callocN(sizeof(uiHandlePanelData), "uiHandlePanelData");
pa->activedata = data;
- WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, false);
+ WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, 0);
}
if (ELEM(state, PANEL_STATE_ANIMATION, PANEL_STATE_DRAG))
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 6e5f6af3c5f..da2852c71d1 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -70,8 +70,9 @@
#include "interface_intern.h"
-#define MENU_TOP 8
+#define MENU_TOP (int)(8 * UI_DPI_FAC)
#define MENU_PADDING (int)(0.2f * UI_UNIT_Y)
+#define MENU_BORDER (int)(0.3f * U.widget_unit)
static int rna_property_enum_step(const bContext *C, PointerRNA *ptr, PropertyRNA *prop, int direction)
{
@@ -179,9 +180,10 @@ typedef struct uiTooltipData {
BLI_STATIC_ASSERT(UI_TIP_LC_MAX == UI_TIP_LC_ALERT + 1, "invalid lc-max");
BLI_STATIC_ASSERT(sizeof(((uiTooltipData *)NULL)->format[0]) <= sizeof(int), "oversize");
-static void rgb_tint(float col[3],
- float h, float h_strength,
- float v, float v_strength)
+static void rgb_tint(
+ float col[3],
+ float h, float h_strength,
+ float v, float v_strength)
{
float col_hsv_from[3];
float col_hsv_to[3];
@@ -241,10 +243,10 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
/* tone_fg = rgb_to_grayscale(main_color); */
/* mix the colors */
- rgb_tint(value_color, 0.0f, 0.0f, tone_bg, 0.2f); /* light grey */
+ rgb_tint(value_color, 0.0f, 0.0f, tone_bg, 0.2f); /* light gray */
rgb_tint(active_color, 0.6f, 0.2f, tone_bg, 0.2f); /* light blue */
- rgb_tint(normal_color, 0.0f, 0.0f, tone_bg, 0.4f); /* grey */
- rgb_tint(python_color, 0.0f, 0.0f, tone_bg, 0.5f); /* dark grey */
+ rgb_tint(normal_color, 0.0f, 0.0f, tone_bg, 0.4f); /* gray */
+ rgb_tint(python_color, 0.0f, 0.0f, tone_bg, 0.5f); /* dark gray */
rgb_tint(alert_color, 0.0f, 0.8f, tone_bg, 0.1f); /* red */
/* draw text */
@@ -261,7 +263,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
/* override text-style */
fstyle_header.shadow = 1;
- fstyle_header.shadowcolor = rgb_to_luma(tip_colors[UI_TIP_LC_MAIN]);
+ fstyle_header.shadowcolor = rgb_to_grayscale(tip_colors[UI_TIP_LC_MAIN]);
fstyle_header.shadx = fstyle_header.shady = 0;
fstyle_header.shadowalpha = 1.0f;
@@ -394,7 +396,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
data->totline++;
}
- if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
/* better not show the value of a password */
if ((but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD)) == 0) {
/* full string */
@@ -815,7 +817,7 @@ static void ui_searchbox_select(bContext *C, ARegion *ar, uiBut *but, int step)
}
else {
/* only let users step into an 'unset' state for unlink buttons */
- data->active = (but->type == UI_BTYPE_SEARCH_MENU_UNLINK) ? -1 : 0;
+ data->active = (but->flag & UI_BUT_SEARCH_UNLINK) ? -1 : 0;
}
}
@@ -826,8 +828,8 @@ static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr
{
/* thumbnail preview */
if (data->preview) {
- int butw = BLI_rcti_size_x(&data->bbox) / data->prv_cols;
- int buth = (BLI_rcti_size_y(&data->bbox) - 2 * MENU_TOP) / data->prv_rows;
+ int butw = (BLI_rcti_size_x(&data->bbox) - 2 * MENU_BORDER) / data->prv_cols;
+ int buth = (BLI_rcti_size_y(&data->bbox) - 2 * MENU_BORDER) / data->prv_rows;
int row, col;
*r_rect = data->bbox;
@@ -835,10 +837,10 @@ static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr
col = itemnr % data->prv_cols;
row = itemnr / data->prv_cols;
- r_rect->xmin += col * butw;
+ r_rect->xmin += MENU_BORDER + (col * butw);
r_rect->xmax = r_rect->xmin + butw;
- r_rect->ymax = data->bbox.ymax - MENU_TOP - (row * buth);
+ r_rect->ymax -= MENU_BORDER + (row * buth);
r_rect->ymin = r_rect->ymax - buth;
}
/* list view */
@@ -886,7 +888,7 @@ bool ui_searchbox_apply(uiBut *but, ARegion *ar)
return true;
}
- else if (but->type == UI_BTYPE_SEARCH_MENU_UNLINK) {
+ else if (but->flag & UI_BUT_SEARCH_UNLINK) {
/* It is valid for _UNLINK flavor to have no active element (it's a valid way to unlink). */
but->editstr[0] = '\0';
@@ -1044,14 +1046,8 @@ static void ui_searchbox_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
ui_searchbox_butrect(&rect, data, a);
/* widget itself */
- if (data->preview) {
- ui_draw_preview_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a],
- (a == data->active) ? UI_ACTIVE : 0);
- }
- else {
- ui_draw_menu_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a],
- (a == data->active) ? UI_ACTIVE : 0, data->use_sep);
- }
+ ui_draw_preview_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a],
+ (a == data->active) ? UI_ACTIVE : 0);
}
/* indicate more */
@@ -1164,25 +1160,27 @@ ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but)
/* compute position */
if (but->block->flag & UI_BLOCK_SEARCH_MENU) {
- const int margin = UI_POPUP_MARGIN;
+ const int margin_x = UI_POPUP_MARGIN;
+ const int margin_y = MENU_TOP;
+ const int search_but_h = BLI_rctf_size_y(&but->rect) + 10;
/* this case is search menu inside other menu */
/* we copy region size */
ar->winrct = butregion->winrct;
/* widget rect, in region coords */
- data->bbox.xmin = margin;
- data->bbox.xmax = BLI_rcti_size_x(&ar->winrct) - margin;
+ data->bbox.xmin = margin_x;
+ data->bbox.xmax = BLI_rcti_size_x(&ar->winrct) - margin_x;
/* Do not use shadow width for height, gives insane margin with big shadows, and issue T41548 with small ones */
- data->bbox.ymin = 8 * UI_DPI_FAC;
- data->bbox.ymax = BLI_rcti_size_y(&ar->winrct) - 8 * UI_DPI_FAC;
+ data->bbox.ymin = margin_y;
+ data->bbox.ymax = BLI_rcti_size_y(&ar->winrct) - margin_y;
/* check if button is lower half */
if (but->rect.ymax < BLI_rctf_cent_y(&but->block->rect)) {
- data->bbox.ymin += BLI_rctf_size_y(&but->rect);
+ data->bbox.ymin += search_but_h;
}
else {
- data->bbox.ymax -= BLI_rctf_size_y(&but->rect);
+ data->bbox.ymax -= search_but_h;
}
}
else {
@@ -1426,7 +1424,8 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
if (down || top) {
if (dir1 == UI_DIR_UP && top == 0) dir1 = UI_DIR_DOWN;
if (dir1 == UI_DIR_DOWN && down == 0) dir1 = UI_DIR_UP;
- if (dir2 == UI_DIR_UP && top == 0) dir2 = UI_DIR_DOWN;
+ BLI_assert(dir2 != UI_DIR_UP);
+// if (dir2 == UI_DIR_UP && top == 0) dir2 = UI_DIR_DOWN;
if (dir2 == UI_DIR_DOWN && down == 0) dir2 = UI_DIR_UP;
}
@@ -1808,9 +1807,10 @@ uiBlock *ui_popup_block_refresh(
return block;
}
-uiPopupBlockHandle *ui_popup_block_create(bContext *C, ARegion *butregion, uiBut *but,
- uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func,
- void *arg)
+uiPopupBlockHandle *ui_popup_block_create(
+ bContext *C, ARegion *butregion, uiBut *but,
+ uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func,
+ void *arg)
{
wmWindow *window = CTX_wm_window(C);
static ARegionType type;
@@ -2571,8 +2571,9 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
return pup->block;
}
-uiPopupBlockHandle *ui_popup_menu_create(bContext *C, ARegion *butregion, uiBut *but,
- uiMenuCreateFunc menu_func, void *arg)
+uiPopupBlockHandle *ui_popup_menu_create(
+ bContext *C, ARegion *butregion, uiBut *but,
+ uiMenuCreateFunc menu_func, void *arg)
{
wmWindow *window = CTX_wm_window(C);
uiStyle *style = UI_style_get_dpi();
@@ -2619,7 +2620,7 @@ uiPopupBlockHandle *ui_popup_menu_create(bContext *C, ARegion *butregion, uiBut
if (!but) {
handle->popup = true;
- UI_popup_handlers_add(C, &window->modalhandlers, handle, false);
+ UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
WM_event_add_mousemove(C);
}
@@ -2681,7 +2682,7 @@ void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
menu = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_POPUP, pup);
menu->popup = true;
- UI_popup_handlers_add(C, &window->modalhandlers, menu, false);
+ UI_popup_handlers_add(C, &window->modalhandlers, menu, 0);
WM_event_add_mousemove(C);
MEM_freeN(pup);
@@ -2807,7 +2808,9 @@ void UI_pie_menu_end(bContext *C, uiPieMenu *pie)
menu->popup = true;
menu->towardstime = PIL_check_seconds_timer();
- UI_popup_handlers_add(C, &window->modalhandlers, menu, true);
+ UI_popup_handlers_add(
+ C, &window->modalhandlers,
+ menu, WM_HANDLER_ACCEPT_DBL_CLICK);
WM_event_add_mousemove(C);
MEM_freeN(pie);
@@ -2850,8 +2853,9 @@ int UI_pie_menu_invoke(struct bContext *C, const char *idname, const wmEvent *ev
return OPERATOR_INTERFACE;
}
-int UI_pie_menu_invoke_from_operator_enum(struct bContext *C, const char *title, const char *opname,
- const char *propname, const wmEvent *event)
+int UI_pie_menu_invoke_from_operator_enum(
+ struct bContext *C, const char *title, const char *opname,
+ const char *propname, const wmEvent *event)
{
uiPieMenu *pie;
uiLayout *layout;
@@ -2867,8 +2871,9 @@ int UI_pie_menu_invoke_from_operator_enum(struct bContext *C, const char *title,
return OPERATOR_INTERFACE;
}
-int UI_pie_menu_invoke_from_rna_enum(struct bContext *C, const char *title, const char *path,
- const wmEvent *event)
+int UI_pie_menu_invoke_from_rna_enum(
+ struct bContext *C, const char *title, const char *path,
+ const wmEvent *event)
{
PointerRNA ctx_ptr;
PointerRNA r_ptr;
@@ -2997,7 +3002,7 @@ void UI_popup_block_invoke_ex(bContext *C, uiBlockCreateFunc func, void *arg, co
handle->optype = (opname) ? WM_operatortype_find(opname, 0) : NULL;
handle->opcontext = opcontext;
- UI_popup_handlers_add(C, &window->modalhandlers, handle, false);
+ UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
WM_event_add_mousemove(C);
}
@@ -3020,7 +3025,7 @@ void UI_popup_block_ex(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc po
handle->cancel_func = cancel_func;
// handle->opcontext = opcontext;
- UI_popup_handlers_add(C, &window->modalhandlers, handle, false);
+ UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
WM_event_add_mousemove(C);
}
@@ -3039,17 +3044,15 @@ void uiPupBlockOperator(bContext *C, uiBlockCreateFunc func, wmOperator *op, int
handle->cancel_func = confirm_cancel_operator;
handle->opcontext = opcontext;
- UI_popup_handlers_add(C, &window->modalhandlers, handle);
+ UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
WM_event_add_mousemove(C);
}
#endif
-void UI_popup_block_close(bContext *C, uiBlock *block)
+void UI_popup_block_close(bContext *C, wmWindow *win, uiBlock *block)
{
+ /* if loading new .blend while popup is open, window will be NULL */
if (block->handle) {
- wmWindow *win = CTX_wm_window(C);
-
- /* if loading new .blend while popup is open, window will be NULL */
if (win) {
UI_popup_handlers_remove(&win->modalhandlers, block->handle);
ui_popup_block_free(C, block->handle);
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index 2f46c0906ae..10575fcbc54 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -64,7 +64,7 @@
/* style + theme + layout-engine = UI */
-/*
+/**
* This is a complete set of layout rules, the 'state' of the Layout
* Engine. Multiple styles are possible, defined via C or Python. Styles
* get a name, and will typically get activated per region type, like
@@ -323,10 +323,14 @@ void UI_fontstyle_draw_simple_backdrop(
/* XXX: read a style configure */
uiStyle *UI_style_get(void)
{
+#if 0
uiStyle *style = NULL;
/* offset is two struct uiStyle pointers */
- /* style = BLI_findstring(&U.uistyles, "Unifont Style", sizeof(style) * 2) */;
+ style = BLI_findstring(&U.uistyles, "Unifont Style", sizeof(style) * 2);
return (style != NULL) ? style : U.uistyles.first;
+#else
+ return U.uistyles.first;
+#endif
}
/* for drawing, scaled with DPI setting */
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index abf4fb76ac5..e6e8a96dd8d 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -31,6 +31,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_cache_library_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -49,6 +50,7 @@
#include "BLF_api.h"
#include "BLF_translation.h"
+#include "BKE_cache_library.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
@@ -73,6 +75,7 @@
#include "ED_util.h"
#include "RNA_access.h"
+#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -187,10 +190,10 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
/* preview thumbnails */
if (template.prv_rows > 0 && template.prv_cols > 0) {
int w = 4 * U.widget_unit * template.prv_cols;
- int h = 4 * U.widget_unit * template.prv_rows + U.widget_unit;
+ int h = 5 * U.widget_unit * template.prv_rows;
/* fake button, it holds space for search items */
- uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 15, w, h, NULL, 0, 0, 0, 0, NULL);
+ uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 26, w, h, NULL, 0, 0, 0, 0, NULL);
but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, w, UI_UNIT_Y,
template.prv_rows, template.prv_cols, "");
@@ -273,8 +276,11 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
RNA_property_pointer_set(&template->ptr, template->prop, idptr);
RNA_property_update(C, &template->ptr, template->prop);
- if (id && CTX_wm_window(C)->eventstate->shift) /* useful hidden functionality, */
+ if (id && CTX_wm_window(C)->eventstate->shift) {
+ /* only way to force-remove data (on save) */
+ id->flag &= ~LIB_FAKEUSER;
id->us = 0;
+ }
break;
case UI_ID_FAKE_USER:
@@ -354,12 +360,14 @@ static const char *template_id_browse_tip(StructRNA *type)
case ID_MSK: return N_("Browse Mask to be linked");
case ID_PAL: return N_("Browse Palette Data to be linked");
case ID_PC: return N_("Browse Paint Curve Data to be linked");
+ case ID_CL: return N_("Browse Cache Library Data to be linked");
}
}
return N_("Browse ID data to be linked");
}
-/* Return a type-based i18n context, needed e.g. by "New" button.
+/**
+ * \return a type-based i18n context, needed e.g. by "New" button.
* In most languages, this adjective takes different form based on gender of type name...
*/
#ifdef WITH_INTERNATIONAL
@@ -394,14 +402,16 @@ static const char *template_id_context(StructRNA *type)
case ID_MSK: return BLF_I18NCONTEXT_ID_MASK;
case ID_PAL: return BLF_I18NCONTEXT_ID_PALETTE;
case ID_PC: return BLF_I18NCONTEXT_ID_PAINTCURVE;
+ case ID_CL: return BLF_I18NCONTEXT_ID_CACHELIBRARY;
}
}
return BLF_I18NCONTEXT_DEFAULT;
}
#endif
-static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, short idcode, int flag,
- const char *newop, const char *openop, const char *unlinkop)
+static void template_ID(
+ bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, short idcode, int flag,
+ const char *newop, const char *openop, const char *unlinkop)
{
uiBut *but;
uiBlock *block;
@@ -426,8 +436,8 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6,
TIP_(template_id_browse_tip(type)));
- but->icon = id ? ui_id_icon_get(C, id, true) : RNA_struct_ui_icon(type);
- UI_but_flag_enable(but, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+ ui_def_but_icon(but, id ? ui_id_icon_get(C, id, true) : RNA_struct_ui_icon(type),
+ UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
if ((idfrom && idfrom->lib) || !editable)
UI_but_flag_enable(but, UI_BUT_DISABLED);
@@ -437,10 +447,9 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
else if (flag & UI_ID_BROWSE) {
but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X * 1.6, UI_UNIT_Y,
TIP_(template_id_browse_tip(type)));
- but->icon = RNA_struct_ui_icon(type);
+ ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON);
/* default dragging of icon for id browse buttons */
UI_but_drag_set_id(but, id);
- UI_but_flag_enable(but, UI_HAS_ICON);
UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
if ((idfrom && idfrom->lib) || !editable)
@@ -617,8 +626,9 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
UI_block_align_end(block);
}
-static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop, int flag, int prv_rows, int prv_cols)
+static void ui_template_id(
+ uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
+ const char *openop, const char *unlinkop, int flag, int prv_rows, int prv_cols)
{
TemplateID *template;
PropertyRNA *prop;
@@ -658,21 +668,24 @@ static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, const
MEM_freeN(template);
}
-void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop)
+void uiTemplateID(
+ uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
+ const char *openop, const char *unlinkop)
{
ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE, 0, 0);
}
-void uiTemplateIDBrowse(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop)
+void uiTemplateIDBrowse(
+ uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
+ const char *openop, const char *unlinkop)
{
ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME, 0, 0);
}
-void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop, int rows, int cols)
+void uiTemplateIDPreview(
+ uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
+ const char *openop, const char *unlinkop, int rows, int cols)
{
ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE | UI_ID_PREVIEWS, rows, cols);
@@ -680,13 +693,15 @@ void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
/************************ ID Chooser Template ***************************/
-/* This is for selecting the type of ID-block to use, and then from the relevant type choosing the block to use
+/**
+ * This is for selecting the type of ID-block to use, and then from the relevant type choosing the block to use
*
* - propname: property identifier for property that ID-pointer gets stored to
* - proptypename: property identifier for property used to determine the type of ID-pointer that can be used
*/
-void uiTemplateAnyID(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *proptypename,
- const char *text)
+void uiTemplateAnyID(
+ uiLayout *layout, PointerRNA *ptr, const char *propname, const char *proptypename,
+ const char *text)
{
PropertyRNA *propID, *propType;
uiLayout *split, *row, *sub;
@@ -739,7 +754,8 @@ void uiTemplateAnyID(uiLayout *layout, PointerRNA *ptr, const char *propname, co
/* ---------- */
-/* This is creating/editing RNA-Paths
+/**
+ * This is creating/editing RNA-Paths
*
* - ptr: struct which holds the path property
* - propname: property identifier for property that path gets stored to
@@ -820,10 +836,11 @@ static int modifier_is_simulation(ModifierData *md)
}
}
-static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
- ModifierData *md, int index, int cageIndex, int lastCageIndex)
+static uiLayout *draw_modifier(
+ uiLayout *layout, Scene *scene, Object *ob,
+ ModifierData *md, int index, int cageIndex, int lastCageIndex)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
PointerRNA ptr;
uiBut *but;
uiBlock *block;
@@ -845,9 +862,6 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
row = uiLayoutRow(box, false);
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_EXPAND);
block = uiLayoutGetBlock(row);
-
- UI_block_flag_enable(block, UI_BLOCK_DRAGGABLE);
-
/* VIRTUAL MODIFIER */
/* XXX this is not used now, since these cannot be accessed via RNA */
BLI_snprintf(str, sizeof(str), IFACE_("%s parent deform"), md->name);
@@ -861,9 +875,7 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
/* REAL MODIFIER */
row = uiLayoutRow(box, false);
block = uiLayoutGetBlock(row);
-
- UI_block_flag_enable(block, UI_BLOCK_DRAGGABLE);
-
+
UI_block_emboss_set(block, UI_EMBOSS_NONE);
/* Open/Close ................................. */
uiItemR(row, &ptr, "show_expanded", 0, "", ICON_NONE);
@@ -925,7 +937,12 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
UI_block_align_end(block);
- /* Delete */
+ /* Up/Down + Delete ........................... */
+ UI_block_align_begin(block);
+ uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_modifier_move_up");
+ uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_modifier_move_down");
+ UI_block_align_end(block);
+
UI_block_emboss_set(block, UI_EMBOSS_NONE);
/* When Modifier is a simulation, show button to switch to context rather than the delete button. */
if (modifier_can_delete(md) &&
@@ -940,11 +957,6 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
else if (modifier_is_simulation(md) == 2) {
uiItemStringO(row, "", ICON_BUTS, "WM_OT_properties_context_change", "context", "PARTICLES");
}
-
- /* Drag Widget */
- but = uiDefIconBut(block, UI_BTYPE_GRIP, 0, ICON_GRIP, 0, 0, UI_UNIT_X, UI_UNIT_Y * 0.8f, NULL,
- 0, 0, 0, 0, "");
-
UI_block_emboss_set(block, UI_EMBOSS);
}
@@ -1070,7 +1082,8 @@ static void do_constraint_panels(bContext *C, void *ob_pt, int event)
case B_CONSTRAINT_CHANGETARGET:
{
Main *bmain = CTX_data_main(C);
- if (ob->pose) ob->pose->flag |= POSE_RECALC; /* checks & sorts pose channels */
+ if (ob->pose)
+ BKE_pose_tag_recalc(bmain, ob->pose); /* checks & sorts pose channels */
DAG_relations_tag_update(bmain);
break;
}
@@ -1100,7 +1113,7 @@ static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v)
static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
{
bPoseChannel *pchan = BKE_pose_channel_active(ob);
- bConstraintTypeInfo *cti;
+ const bConstraintTypeInfo *cti;
uiBlock *block;
uiLayout *result = NULL, *col, *box, *row;
PointerRNA ptr;
@@ -1288,8 +1301,9 @@ static void do_preview_buttons(bContext *C, void *arg, int event)
}
}
-void uiTemplatePreview(uiLayout *layout, bContext *C, ID *id, int show_buttons, ID *parent, MTex *slot,
- const char *preview_id)
+void uiTemplatePreview(
+ uiLayout *layout, bContext *C, ID *id, int show_buttons, ID *parent, MTex *slot,
+ const char *preview_id)
{
uiLayout *row, *col;
uiBlock *block;
@@ -1497,8 +1511,9 @@ static void colorband_update_cb(bContext *UNUSED(C), void *bt_v, void *coba_v)
bt->rnapoin.data = coba->data + coba->cur;
}
-static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand *coba, const rctf *butr,
- RNAUpdateCb *cb, int expand)
+static void colorband_buttons_layout(
+ uiLayout *layout, uiBlock *block, ColorBand *coba, const rctf *butr,
+ RNAUpdateCb *cb, int expand)
{
uiLayout *row, *split, *subsplit;
uiBut *bt;
@@ -1563,6 +1578,7 @@ static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand
row = uiLayoutRow(split, false);
uiItemR(row, &ptr, "position", 0, IFACE_("Pos"), ICON_NONE);
bt = block->buttons.last;
+ bt->a1 = 1.0f; /* gives a bit more precision for modifying position */
UI_but_func_set(bt, colorband_update_cb, bt, coba);
row = uiLayoutRow(layout, false);
@@ -1580,6 +1596,7 @@ static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand
row = uiLayoutRow(subsplit, false);
uiItemR(row, &ptr, "position", UI_ITEM_R_SLIDER, IFACE_("Pos"), ICON_NONE);
bt = block->buttons.last;
+ bt->a1 = 1.0f; /* gives a bit more precision for modifying position */
UI_but_func_set(bt, colorband_update_cb, bt, coba);
row = uiLayoutRow(split, false);
@@ -1627,44 +1644,57 @@ void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname
/********************* Icon viewer Template ************************/
+typedef struct IconViewMenuArgs {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int show_labels;
+} IconViewMenuArgs;
/* ID Search browse menu, open */
static uiBlock *ui_icon_view_menu_cb(bContext *C, ARegion *ar, void *arg_litem)
{
- static RNAUpdateCb cb;
+ static IconViewMenuArgs args;
uiBlock *block;
uiBut *but;
- int icon;
+ int icon, value;
EnumPropertyItem *item;
int a;
bool free;
/* arg_litem is malloced, can be freed by parent button */
- cb = *((RNAUpdateCb *)arg_litem);
-
- /* unused */
- // icon = RNA_property_enum_get(&cb.ptr, cb.prop);
-
- block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
+ args = *((IconViewMenuArgs *) arg_litem);
+
+ block = UI_block_begin(C, ar, "_popup", UI_EMBOSS_PULLDOWN);
UI_block_flag_enable(block, UI_BLOCK_LOOP);
-
-
- RNA_property_enum_items(C, &cb.ptr, cb.prop, &item, NULL, &free);
-
+
+ RNA_property_enum_items(C, &args.ptr, args.prop, &item, NULL, &free);
+
for (a = 0; item[a].identifier; a++) {
int x, y;
-
- /* XXX hardcoded size to 5 x unit */
- x = (a % 8) * UI_UNIT_X * 5;
- y = (a / 8) * UI_UNIT_X * 5;
-
+ /* XXX hardcoded size to 5 units */
+ const int w = UI_UNIT_X * 5;
+ const int h = args.show_labels ? 6 * UI_UNIT_Y : UI_UNIT_Y * 5;
+
+ x = (a % 8) * w;
+ y = (a / 8) * h;
+
icon = item[a].icon;
- but = uiDefIconButR_prop(block, UI_BTYPE_ROW, 0, icon, x, y, UI_UNIT_X * 5, UI_UNIT_Y * 5, &cb.ptr, cb.prop, -1, 0, icon, -1, -1, NULL);
- UI_but_flag_enable(but, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+ value = item[a].value;
+ if (args.show_labels) {
+ but = uiDefIconTextButR_prop(
+ block, UI_BTYPE_ROW, 0, icon, item[a].name, x, y, w, h,
+ &args.ptr, args.prop, -1, 0, value, -1, -1, NULL);
+ }
+ else {
+ but = uiDefIconButR_prop(
+ block, UI_BTYPE_ROW, 0, icon, x, y, w, h,
+ &args.ptr, args.prop, -1, 0, value, -1, -1, NULL);
+ }
+ ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
}
UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
- UI_block_direction_set(block, UI_DIR_UP);
+ UI_block_direction_set(block, UI_DIR_DOWN);
if (free) {
MEM_freeN(item);
@@ -1673,40 +1703,39 @@ static uiBlock *ui_icon_view_menu_cb(bContext *C, ARegion *ar, void *arg_litem)
return block;
}
-void uiTemplateIconView(uiLayout *layout, PointerRNA *ptr, const char *propname)
+void uiTemplateIconView(uiLayout *layout, PointerRNA *ptr, const char *propname, int show_labels)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
- RNAUpdateCb *cb;
+ IconViewMenuArgs *cb_args;
+ EnumPropertyItem *items;
uiBlock *block;
uiBut *but;
-// rctf rect; /* UNUSED */
- int icon;
-
- if (!prop || RNA_property_type(prop) != PROP_ENUM)
+ int value, icon = ICON_NONE, tot_items;
+ bool free_items;
+
+ if (!prop || RNA_property_type(prop) != PROP_ENUM) {
+ RNA_warning("property of type Enum not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
return;
-
- icon = RNA_property_enum_get(ptr, prop);
-
- cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
- cb->ptr = *ptr;
- cb->prop = prop;
-
-// rect.xmin = 0; rect.xmax = 10.0f * UI_UNIT_X;
-// rect.ymin = 0; rect.ymax = 10.0f * UI_UNIT_X;
-
+ }
+
block = uiLayoutAbsoluteBlock(layout);
- but = uiDefBlockButN(block, ui_icon_view_menu_cb, MEM_dupallocN(cb), "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6, "");
+ RNA_property_enum_items(block->evil_C, ptr, prop, &items, &tot_items, &free_items);
+ value = RNA_property_enum_get(ptr, prop);
+ RNA_enum_icon_from_value(items, value, &icon);
-
-// but = uiDefIconButR_prop(block, UI_BTYPE_ROW, 0, icon, 0, 0, BLI_rctf_size_x(&rect), BLI_rctf_size_y(&rect), ptr, prop, -1, 0, icon, -1, -1, NULL);
-
- but->icon = icon;
- UI_but_flag_enable(but, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
-
- UI_but_funcN_set(but, rna_update_cb, MEM_dupallocN(cb), NULL);
-
- MEM_freeN(cb);
+ cb_args = MEM_callocN(sizeof(IconViewMenuArgs), __func__);
+ cb_args->ptr = *ptr;
+ cb_args->prop = prop;
+ cb_args->show_labels = show_labels;
+
+ but = uiDefBlockButN(block, ui_icon_view_menu_cb, cb_args, "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6, "");
+
+ ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+
+ if (free_items) {
+ MEM_freeN(items);
+ }
}
/********************* Histogram Template ************************/
@@ -2076,8 +2105,9 @@ static void curvemap_buttons_reset(bContext *C, void *cb_v, void *cumap_v)
}
/* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
-static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labeltype, int levels,
- int brush, int neg_slope, RNAUpdateCb *cb)
+static void curvemap_buttons_layout(
+ uiLayout *layout, PointerRNA *ptr, char labeltype, int levels,
+ int brush, int neg_slope, RNAUpdateCb *cb)
{
CurveMapping *cumap = ptr->data;
CurveMap *cm = &cumap->cm[cumap->cur];
@@ -2238,8 +2268,9 @@ static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labe
UI_block_funcN_set(block, NULL, NULL, NULL);
}
-void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propname, int type,
- int levels, int brush, int neg_slope)
+void uiTemplateCurveMapping(
+ uiLayout *layout, PointerRNA *ptr, const char *propname, int type,
+ int levels, int brush, int neg_slope)
{
RNAUpdateCb *cb;
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
@@ -2282,8 +2313,9 @@ void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propn
#define WHEEL_SIZE (5 * U.widget_unit)
/* This template now follows User Preference for type - name is not correct anymore... */
-void uiTemplateColorPicker(uiLayout *layout, PointerRNA *ptr, const char *propname, int value_slider,
- int lock, int lock_luminosity, int cubic)
+void uiTemplateColorPicker(
+ uiLayout *layout, PointerRNA *ptr, const char *propname, int value_slider,
+ int lock, int lock_luminosity, int cubic)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
uiBlock *block = uiLayoutGetBlock(layout);
@@ -2403,9 +2435,6 @@ void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname,
palette = cptr.data;
- /* first delete any pending colors */
- BKE_palette_cleanup(palette);
-
color = palette->colors.first;
col = uiLayoutColumn(layout, true);
@@ -2457,12 +2486,13 @@ static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
/* see view3d_header.c */
}
-/* TODO:
- * - for now, grouping of layers is determined by dividing up the length of
- * the array of layer bitflags */
-
-void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, const char *propname,
- PointerRNA *used_ptr, const char *used_propname, int active_layer)
+/**
+ * \todo for now, grouping of layers is determined by dividing up the length of
+ * the array of layer bitflags
+ */
+void uiTemplateLayers(
+ uiLayout *layout, PointerRNA *ptr, const char *propname,
+ PointerRNA *used_ptr, const char *used_propname, int active_layer)
{
uiLayout *uRow, *uCol;
PropertyRNA *prop, *used_prop = NULL;
@@ -2528,8 +2558,9 @@ void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, const char *propname,
}
}
-void uiTemplateGameStates(uiLayout *layout, PointerRNA *ptr, const char *propname,
- PointerRNA *used_ptr, const char *used_propname, int active_state)
+void uiTemplateGameStates(
+ uiLayout *layout, PointerRNA *ptr, const char *propname,
+ PointerRNA *used_ptr, const char *used_propname, int active_state)
{
uiLayout *uRow, *uCol;
PropertyRNA *prop, *used_prop = NULL;
@@ -2599,10 +2630,11 @@ void uiTemplateGameStates(uiLayout *layout, PointerRNA *ptr, const char *propnam
/************************* List Template **************************/
-static void uilist_draw_item_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout,
- struct PointerRNA *UNUSED(dataptr), struct PointerRNA *itemptr, int icon,
- struct PointerRNA *UNUSED(active_dataptr), const char *UNUSED(active_propname),
- int UNUSED(index), int UNUSED(flt_flag))
+static void uilist_draw_item_default(
+ struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout,
+ struct PointerRNA *UNUSED(dataptr), struct PointerRNA *itemptr, int icon,
+ struct PointerRNA *UNUSED(active_dataptr), const char *UNUSED(active_propname),
+ int UNUSED(index), int UNUSED(flt_flag))
{
PropertyRNA *nameprop = RNA_struct_name_property(itemptr->type);
@@ -2769,8 +2801,9 @@ typedef struct {
int end_idx; /* Index of last item to display + 1. */
} uiListLayoutdata;
-static void uilist_prepare(uiList *ui_list, int len, int activei, int rows, int maxrows, int columns,
- uiListLayoutdata *layoutdata)
+static void uilist_prepare(
+ uiList *ui_list, int len, int activei, int rows, int maxrows, int columns,
+ uiListLayoutdata *layoutdata)
{
uiListDyn *dyn_data = ui_list->dyn_data;
int activei_row, max_scroll;
@@ -2856,9 +2889,10 @@ static char *uilist_item_tooltip_func(bContext *UNUSED(C), void *argN, const cha
return BLI_sprintfN("%s - %s", tip, dyn_tooltip);
}
-void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, const char *list_id,
- PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, const char *active_propname,
- const char *item_dyntip_propname, int rows, int maxrows, int layout_type, int columns)
+void uiTemplateList(
+ uiLayout *layout, bContext *C, const char *listtype_name, const char *list_id,
+ PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, const char *active_propname,
+ const char *item_dyntip_propname, int rows, int maxrows, int layout_type, int columns)
{
uiListType *ui_list_type;
uiList *ui_list = NULL;
@@ -3204,7 +3238,7 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
/* add scrollbar */
if (len > layoutdata.visual_items) {
- col = uiLayoutColumn(row, false);
+ /* col = */ uiLayoutColumn(row, false);
uiDefButI(block, UI_BTYPE_SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * dyn_data->visual_height,
&ui_list->list_scroll, 0, dyn_data->height - dyn_data->visual_height,
dyn_data->visual_height, 0, "");
@@ -3282,17 +3316,18 @@ static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char
for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
+ const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name);
if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0)
continue;
- if (BLI_strcasestr(ot->name, str)) {
+ if (BLI_strcasestr(ot_ui_name, str)) {
if (WM_operator_poll((bContext *)C, ot)) {
char name[256];
- int len = strlen(ot->name);
+ int len = strlen(ot_ui_name);
/* display name for menu, can hold hotkey */
- BLI_strncpy(name, ot->name, sizeof(name));
+ BLI_strncpy(name, ot_ui_name, sizeof(name));
/* check for hotkey */
if (len < sizeof(name) - 6) {
@@ -3701,3 +3736,51 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float *color)
UI_block_align_end(block);
}
+
+/************************* Cache Library Item **************************/
+
+static int cache_item_indent(int type)
+{
+ switch (type) {
+ case CACHE_TYPE_OBJECT:
+ return 0;
+
+ default:
+ return 1;
+ }
+}
+
+uiLayout *uiTemplateCacheLibraryItem(uiLayout *layout, bContext *UNUSED(C), CacheLibrary *UNUSED(cachelib),
+ Object *ob, int datatype, int index, int enabled)
+{
+ uiLayout *split, *row, *col;
+ int i;
+ char name[2*MAX_NAME];
+ int icon = ICON_NONE;
+
+ row = uiLayoutRow(layout, false);
+ uiLayoutSetEnabled(row, enabled);
+ uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
+
+ split = uiLayoutSplit(row, 0.0f, false);
+
+ for (i = 0; i < cache_item_indent(datatype); ++i)
+ uiItemL(split, "", ICON_NONE);
+
+ col = uiLayoutColumn(split, false);
+
+ BKE_cache_item_name(ob, datatype, index, name);
+ RNA_enum_icon_from_value(cache_library_data_type_items, datatype, &icon);
+ uiItemL(split, name, icon);
+
+ /* display read result */
+ split = uiLayoutSplit(row, 0.9f, false);
+ // XXX TODO store cache read results in a hash table and display them here
+// if (item && (item->flag & CACHE_ITEM_ENABLED))
+// RNA_enum_icon_from_value(cache_library_read_result_items, item->read_result, &icon);
+// else
+// icon = ICON_NONE;
+// uiItemL(split, NULL, icon);
+
+ return col;
+}
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index e0ce200869a..576e17727dd 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -43,6 +43,7 @@
#include "BLF_translation.h"
+#include "BKE_context.h"
#include "BKE_report.h"
#include "MEM_guardedalloc.h"
@@ -52,6 +53,9 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "WM_api.h"
+#include "WM_types.h"
+
#include "interface_intern.h"
@@ -154,9 +158,10 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind
* \a check_prop callback filters functions to avoid drawing certain properties,
* in cases where PROP_HIDDEN flag can't be used for a property.
*/
-int uiDefAutoButsRNA(uiLayout *layout, PointerRNA *ptr,
- bool (*check_prop)(PointerRNA *, PropertyRNA *),
- const char label_align)
+int uiDefAutoButsRNA(
+ uiLayout *layout, PointerRNA *ptr,
+ bool (*check_prop)(PointerRNA *, PropertyRNA *),
+ const char label_align)
{
uiLayout *split, *col;
int flag;
@@ -309,6 +314,53 @@ int UI_calc_float_precision(int prec, double value)
return prec;
}
+uiBut *ui_but_find_menu_root(struct bContext *C) {
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar;
+ uiBlock *block;
+ uiBut *but;
+
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ for (block = ar->uiblocks.first; block; block = block->next) {
+ for (but = block->buttons.first; but; but = but->next) {
+ if (but->flag & UI_BUT_MENU_ROOT) {
+ return but;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+bool UI_but_online_manual_id(const uiBut *but, char *r_str, size_t maxlength)
+{
+ if (but->rnapoin.id.data && but->rnapoin.data && but->rnaprop) {
+ BLI_snprintf(r_str, maxlength, "%s.%s", RNA_struct_identifier(but->rnapoin.type),
+ RNA_property_identifier(but->rnaprop));
+ return true;
+ }
+ else if (but->optype) {
+ WM_operator_py_idname(r_str, but->optype->idname);
+ return true;
+ }
+
+ *r_str = '\0';
+ return false;
+}
+
+bool UI_but_online_manual_id_from_active(const struct bContext *C, char *r_str, size_t maxlength)
+{
+ uiBut *but = UI_context_active_but_get(C);
+
+ if (but) {
+ return UI_but_online_manual_id(but, r_str, maxlength);
+ }
+
+ *r_str = '\0';
+ return false;
+}
+
/* -------------------------------------------------------------------- */
/* Modal Button Store API */
@@ -485,14 +537,4 @@ void UI_butstore_update(uiBlock *block)
}
}
-
-/* -------------------------------------------------------------------- */
-/* Sub-Block API */
-
-bool UI_subblock_is_dragging(uiBlock *block)
-{
- return ((block->flag & UI_BLOCK_DRAGGABLE) &&
- (block->subblock.drag_state == UI_BLOCK_DRAGSTATE_DRAGGING));
-}
-
/** \} */
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 805cca7db24..253f4616843 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -27,7 +27,6 @@
* \ingroup edinterface
*/
-
#include <limits.h>
#include <stdlib.h>
#include <string.h>
@@ -56,7 +55,6 @@
#include "UI_interface.h"
#include "UI_interface_icons.h"
-
#include "interface_intern.h"
#ifdef WITH_INPUT_IME
@@ -67,12 +65,12 @@
#define ICON_SIZE_FROM_BUTRECT(rect) (0.8f * BLI_rcti_size_y(rect))
/* ************** widget base functions ************** */
-/*
+/**
* - in: roundbox codes for corner types and radius
- * - return: array of [size][2][x,y] points, the edges of the roundbox, + UV coords
+ * - return: array of `[size][2][x, y]` points, the edges of the roundbox, + UV coords
*
* - draw black box with alpha 0 on exact button boundbox
- * - for ever AA step:
+ * - for every AA step:
* - draw the inner part for a round filled box, with color blend codes or texture coords
* - draw outline in outline color
* - draw outer part, bottom half, extruded 1 pixel to bottom, for emboss shadow
@@ -102,14 +100,14 @@ typedef struct uiWidgetBase {
float inner_v[WIDGET_SIZE_MAX][2];
float inner_uv[WIDGET_SIZE_MAX][2];
- bool inner, outline, emboss, shadedir;
+ bool draw_inner, draw_outline, draw_emboss, draw_shadedir;
uiWidgetTrias tria1;
uiWidgetTrias tria2;
} uiWidgetBase;
-/* uiWidgetType: for time being only for visual appearance,
+/** uiWidgetType: for time being only for visual appearance,
* later, a handling callback can be added too
*/
typedef struct uiWidgetType {
@@ -239,10 +237,10 @@ static void widget_init(uiWidgetBase *wtb)
wtb->tria1.tot = 0;
wtb->tria2.tot = 0;
- wtb->inner = 1;
- wtb->outline = 1;
- wtb->emboss = 1;
- wtb->shadedir = 1;
+ wtb->draw_inner = true;
+ wtb->draw_outline = true;
+ wtb->draw_emboss = true;
+ wtb->draw_shadedir = true;
}
/* helper call, makes shadow rect, with 'sun' above menu, so only shadow to left/right/bottom */
@@ -549,12 +547,12 @@ static void widget_menu_trias(uiWidgetTrias *tria, const rcti *rect)
{
float centx, centy, size;
int a;
-
+
/* center position and size */
centx = rect->xmax - 0.32f * BLI_rcti_size_y(rect);
centy = rect->ymin + 0.50f * BLI_rcti_size_y(rect);
- size = 0.4f * (float)BLI_rcti_size_y(rect);
-
+ size = 0.4f * BLI_rcti_size_y(rect);
+
for (a = 0; a < 6; a++) {
tria->vec[a][0] = size * menu_tria_vert[a][0] + centx;
tria->vec[a][1] = size * menu_tria_vert[a][1] + centy;
@@ -587,7 +585,6 @@ static void widget_check_trias(uiWidgetTrias *tria, const rcti *rect)
/* prepares shade colors */
static void shadecolors4(char coltop[4], char coldown[4], const char *color, short shadetop, short shadedown)
{
-
coltop[0] = CLAMPIS(color[0] + shadetop, 0, 255);
coltop[1] = CLAMPIS(color[1] + shadetop, 0, 255);
coltop[2] = CLAMPIS(color[2] + shadetop, 0, 255);
@@ -604,10 +601,10 @@ static void round_box_shade_col4_r(unsigned char r_col[4], const char col1[4], c
const int faci = FTOCHAR(fac);
const int facm = 255 - faci;
- r_col[0] = (faci * col1[0] + facm * col2[0]) >> 8;
- r_col[1] = (faci * col1[1] + facm * col2[1]) >> 8;
- r_col[2] = (faci * col1[2] + facm * col2[2]) >> 8;
- r_col[3] = (faci * col1[3] + facm * col2[3]) >> 8;
+ r_col[0] = (faci * col1[0] + facm * col2[0]) / 256;
+ r_col[1] = (faci * col1[1] + facm * col2[1]) / 256;
+ r_col[2] = (faci * col1[2] + facm * col2[2]) / 256;
+ r_col[3] = (faci * col1[3] + facm * col2[3]) / 256;
}
static void widget_verts_to_triangle_strip(uiWidgetBase *wtb, const int totvert, float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2])
@@ -650,7 +647,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
glEnable(GL_BLEND);
/* backdrop non AA */
- if (wtb->inner) {
+ if (wtb->draw_inner) {
if (wcol->shaded == 0) {
if (wcol->alpha_check) {
float inner_v_half[WIDGET_SIZE_MAX][2];
@@ -716,7 +713,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
glShadeModel(GL_SMOOTH);
for (a = 0; a < wtb->totvert; a++, col_pt += 4) {
- round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->shadedir]);
+ round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->draw_shadedir ? 1 : 0]);
}
glEnableClientState(GL_VERTEX_ARRAY);
@@ -732,7 +729,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
}
/* for each AA step */
- if (wtb->outline) {
+ if (wtb->draw_outline) {
float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
float triangle_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */
@@ -743,7 +740,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip);
- if (wtb->emboss) {
+ if (wtb->draw_emboss) {
widget_verts_to_triangle_strip_open(wtb, wtb->halfwayvert, triangle_strip_emboss);
}
@@ -761,7 +758,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->totvert * 2 + 2);
/* emboss bottom shadow */
- if (wtb->emboss) {
+ if (wtb->draw_emboss) {
UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss);
if (emboss[3]) {
@@ -783,6 +780,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
wcol->item[1],
wcol->item[2],
(unsigned char)((float)wcol->item[3] / WIDGET_AA_JITTER)};
+
/* for each AA step */
for (j = 0; j < WIDGET_AA_JITTER; j++) {
glTranslatef(jit[j][0], jit[j][1], 0.0f);
@@ -801,7 +799,6 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
}
glDisable(GL_BLEND);
-
}
/* *********************** text/icon ************************************** */
@@ -810,7 +807,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
#define PREVIEW_PAD 4
-static void widget_draw_preview(BIFIconID icon, float UNUSED(alpha), const rcti *rect)
+static void widget_draw_preview(BIFIconID icon, float alpha, const rcti *rect)
{
int w, h, size;
@@ -826,44 +823,7 @@ static void widget_draw_preview(BIFIconID icon, float UNUSED(alpha), const rcti
int x = rect->xmin + w / 2 - size / 2;
int y = rect->ymin + h / 2 - size / 2;
- UI_icon_draw_preview_aspect_size(x, y, icon, 1.0f, size);
- }
-}
-
-static void ui_draw_dragwidget(const rctf *rect)
-{
- unsigned char col_back[3], col_high[3], col_dark[3];
- const int col_tint = 84;
-
- const int px = (int)U.pixelsize;
- const int px_zoom = max_ii(iroundf(BLI_rctf_size_y(rect) / 22.0f), 1);
-
- const int box_margin = max_ii(iroundf((float)(px_zoom * 2.0f)), px);
- const int box_size = max_ii(iroundf((BLI_rctf_size_y(rect) / 8.0f) - px), px);
-
- const int x_min = rect->xmin;
- const int y_min = rect->ymin;
- const int y_ofs = max_ii(iroundf(BLI_rctf_size_y(rect) / 3.0f), px);
- const int x_ofs = y_ofs;
- int i_x, i_y;
-
-
- UI_GetThemeColor3ubv(UI_GetThemeValue(TH_PANEL_SHOW_HEADER) ? TH_PANEL_HEADER : TH_PANEL_BACK, col_back);
- UI_GetColorPtrShade3ubv(col_back, col_high, col_tint);
- UI_GetColorPtrShade3ubv(col_back, col_dark, -col_tint);
-
-
- /* draw multiple boxes */
- for (i_x = 0; i_x < 4; i_x++) {
- for (i_y = 0; i_y < 2; i_y++) {
- const int x_co = (x_min + x_ofs) + (i_x * (box_size + box_margin));
- const int y_co = (y_min + y_ofs) + (i_y * (box_size + box_margin));
-
- glColor3ubv(col_dark);
- glRectf(x_co - box_size, y_co - px_zoom, x_co, (y_co + box_size) - px_zoom);
- glColor3ubv(col_high);
- glRectf(x_co - box_size, y_co, x_co, y_co + box_size);
- }
+ UI_icon_draw_preview_aspect_size(x, y, icon, 1.0f, alpha, size);
}
}
@@ -875,8 +835,9 @@ static int ui_but_draw_menu_icon(const uiBut *but)
/* icons have been standardized... and this call draws in untransformed coordinates */
-static void widget_draw_icon(const uiBut *but, BIFIconID icon, float alpha, const rcti *rect,
- const bool show_menu_icon)
+static void widget_draw_icon(
+ const uiBut *but, BIFIconID icon, float alpha, const rcti *rect,
+ const bool show_menu_icon)
{
float xs = 0.0f, ys = 0.0f;
float aspect, height;
@@ -907,49 +868,39 @@ static void widget_draw_icon(const uiBut *but, BIFIconID icon, float alpha, cons
glEnable(GL_BLEND);
- if (icon) {
- if (icon == ICON_BLANK1) {
- /* skip */
- }
- else if (icon == ICON_GRIP && (but->block->flag & UI_BLOCK_DRAGGABLE)) {
- rctf drag_rect;
-
- BLI_rctf_rcti_copy(&drag_rect, rect);
- ui_draw_dragwidget(&drag_rect);
- }
- else {
- float ofs = 1.0f / aspect;
- if (but->drawflag & UI_BUT_ICON_LEFT) {
- if (but->block->flag & UI_BLOCK_LOOP) {
- if (ELEM(but->type, UI_BTYPE_SEARCH_MENU, UI_BTYPE_SEARCH_MENU_UNLINK))
- xs = rect->xmin + 4.0f * ofs;
- else
- xs = rect->xmin + ofs;
- }
- else {
+ if (icon && icon != ICON_BLANK1) {
+ float ofs = 1.0f / aspect;
+
+ if (but->drawflag & UI_BUT_ICON_LEFT) {
+ if (but->block->flag & UI_BLOCK_LOOP) {
+ if (but->type == UI_BTYPE_SEARCH_MENU)
xs = rect->xmin + 4.0f * ofs;
- }
- ys = (rect->ymin + rect->ymax - height) / 2.0f;
+ else
+ xs = rect->xmin + ofs;
}
else {
- xs = (rect->xmin + rect->xmax - height) / 2.0f;
- ys = (rect->ymin + rect->ymax - height) / 2.0f;
- }
-
- /* force positions to integers, for zoom levels near 1. draws icons crisp. */
- if (aspect > 0.95f && aspect < 1.05f) {
- xs = (int)(xs + 0.1f);
- ys = (int)(ys + 0.1f);
+ xs = rect->xmin + 4.0f * ofs;
}
+ ys = (rect->ymin + rect->ymax - height) / 2.0f;
+ }
+ else {
+ xs = (rect->xmin + rect->xmax - height) / 2.0f;
+ ys = (rect->ymin + rect->ymax - height) / 2.0f;
+ }
- /* to indicate draggable */
- if (but->dragpoin && (but->flag & UI_ACTIVE)) {
- float rgb[3] = {1.25f, 1.25f, 1.25f};
- UI_icon_draw_aspect_color(xs, ys, icon, aspect, rgb);
- }
- else
- UI_icon_draw_aspect(xs, ys, icon, aspect, alpha);
+ /* force positions to integers, for zoom levels near 1. draws icons crisp. */
+ if (aspect > 0.95f && aspect < 1.05f) {
+ xs = (int)(xs + 0.1f);
+ ys = (int)(ys + 0.1f);
+ }
+
+ /* to indicate draggable */
+ if (but->dragpoin && (but->flag & UI_ACTIVE)) {
+ float rgb[3] = {1.25f, 1.25f, 1.25f};
+ UI_icon_draw_aspect_color(xs, ys, icon, aspect, rgb);
}
+ else
+ UI_icon_draw_aspect(xs, ys, icon, aspect, alpha);
}
if (show_menu_icon) {
@@ -978,12 +929,14 @@ static void ui_text_clip_give_next_off(uiBut *but, const char *str)
but->ofs += bytes;
}
-/* Helper.
+/**
+ * Helper.
* This func assumes things like kerning handling have already been handled!
* Return the length of modified (right-clipped + ellipsis) string.
*/
-static void ui_text_clip_right_ex(uiFontStyle *fstyle, char *str, const size_t max_len, const float okwidth,
- const char *sep, const int sep_len, const float sep_strwidth, size_t *r_final_len)
+static void ui_text_clip_right_ex(
+ uiFontStyle *fstyle, char *str, const size_t max_len, const float okwidth,
+ const char *sep, const int sep_len, const float sep_strwidth, size_t *r_final_len)
{
float tmp;
int l_end;
@@ -1015,11 +968,16 @@ static void ui_text_clip_right_ex(uiFontStyle *fstyle, char *str, const size_t m
* If rpart_sep is not Null, the part of str starting to first occurrence of rpart_sep is preserved at all cost (useful
* for strings with shortcuts, like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O').
*/
-static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, float okwidth, const float minwidth,
- const size_t max_len, const char *rpart_sep)
+float UI_text_clip_middle_ex(
+ uiFontStyle *fstyle, char *str, float okwidth, const float minwidth,
+ const size_t max_len, const char rpart_sep)
{
float strwidth;
+ /* Add some epsilon to OK width, avoids 'ellipsing' text that nearly fits!
+ * Better to have a small piece of the last char cut out, than two remaining chars replaced by an allipsis... */
+ okwidth += 1.0f + UI_DPI_FAC;
+
BLI_assert(str[0]);
/* need to set this first */
@@ -1045,7 +1003,7 @@ static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, float okwidt
size_t final_lpart_len;
if (rpart_sep) {
- rpart = strstr(str, rpart_sep);
+ rpart = strrchr(str, rpart_sep);
if (rpart) {
rpart_len = strlen(rpart);
@@ -1116,7 +1074,7 @@ static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, float okwidt
}
/**
- * Wrapper around ui_text_clip_middle_ex.
+ * Wrapper around UI_text_clip_middle_ex.
*/
static void ui_text_clip_middle(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
{
@@ -1127,14 +1085,14 @@ static void ui_text_clip_middle(uiFontStyle *fstyle, uiBut *but, const rcti *rec
const float minwidth = (float)(UI_DPI_ICON_SIZE) / but->block->aspect * 2.0f;
but->ofs = 0;
- but->strwidth = ui_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, NULL);
+ but->strwidth = UI_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, '\0');
}
/**
* Like ui_text_clip_middle(), but protect/preserve at all cost the right part of the string after sep.
* Useful for strings with shortcuts (like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O').
*/
-static void ui_text_clip_middle_protect_right(uiFontStyle *fstyle, uiBut *but, const rcti *rect, const char *rsep)
+static void ui_text_clip_middle_protect_right(uiFontStyle *fstyle, uiBut *but, const rcti *rect, const char rsep)
{
/* No margin for labels! */
const int border = ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_MENU) ? 0 : (int)(UI_TEXT_CLIP_MARGIN + 0.5f);
@@ -1143,7 +1101,7 @@ static void ui_text_clip_middle_protect_right(uiFontStyle *fstyle, uiBut *but, c
const float minwidth = (float)(UI_DPI_ICON_SIZE) / but->block->aspect * 2.0f;
but->ofs = 0;
- but->strwidth = ui_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, rsep);
+ but->strwidth = UI_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, rsep);
}
/**
@@ -1264,7 +1222,6 @@ static void ui_text_clip_right_label(uiFontStyle *fstyle, uiBut *but, const rcti
but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs, sizeof(but->drawstr) - but->ofs);
if (but->strwidth < 10) break;
}
-
}
@@ -1367,7 +1324,7 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
#ifdef WITH_INPUT_IME
/* FIXME, IME is modifying 'const char *drawstr! */
- ime_data = ui_but_get_ime_data(but);
+ ime_data = ui_but_ime_data_get(but);
if (ime_data && ime_data->composite_len) {
/* insert composite string into cursor pos */
@@ -1431,7 +1388,7 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
t = 0;
}
- glColor3f(0.20, 0.6, 0.9);
+ glColor3f(0.2, 0.6, 0.9);
tx = rect->xmin + t + 2;
ty = rect->ymin + 2;
@@ -1552,6 +1509,7 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
const bool show_menu_icon = ui_but_draw_menu_icon(but);
float alpha = (float)wcol->text[3] / 255.0f;
char password_str[UI_MAX_DRAW_STR];
+ uiButExtraIconType extra_icon_type;
ui_but_text_password_hide(password_str, but, false);
@@ -1565,7 +1523,34 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
/* If there's an icon too (made with uiDefIconTextBut) then draw the icon
* and offset the text label to accommodate it */
- if (but->flag & UI_HAS_ICON || show_menu_icon) {
+ /* Big previews with optional text label below */
+ if (but->flag & UI_BUT_ICON_PREVIEW && ui_block_is_menu(but->block)) {
+ const BIFIconID icon = (but->flag & UI_HAS_ICON) ? but->icon + but->iconadd : ICON_NONE;
+ int icon_size = BLI_rcti_size_y(rect);
+ int text_size = 0;
+
+ /* This is a bit britle, but avoids adding an 'UI_BUT_HAS_LABEL' flag to but... */
+ if (icon_size > BLI_rcti_size_x(rect)) {
+ /* button is not square, it has extra height for label */
+ text_size = UI_UNIT_Y;
+ icon_size -= text_size;
+ }
+
+ /* draw icon in rect above the space reserved for the label */
+ rect->ymin += text_size;
+ glEnable(GL_BLEND);
+ widget_draw_preview(icon, alpha, rect);
+ glDisable(GL_BLEND);
+
+ /* offset rect to draw label in */
+ rect->ymin -= text_size;
+ rect->ymax -= icon_size;
+
+ /* vertically centering text */
+ rect->ymin += UI_UNIT_Y / 2;
+ }
+ /* Icons on the left with optional text label on the right */
+ else if (but->flag & UI_HAS_ICON || show_menu_icon) {
const BIFIconID icon = (but->flag & UI_HAS_ICON) ? but->icon + but->iconadd : ICON_NONE;
const float icon_size = ICON_SIZE_FROM_BUTRECT(rect);
@@ -1591,11 +1576,23 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
}
/* unlink icon for this button type */
- if ((but->type == UI_BTYPE_SEARCH_MENU_UNLINK) && ui_but_is_search_unlink_visible(but)) {
+ if ((but->type == UI_BTYPE_SEARCH_MENU) &&
+ ((extra_icon_type = ui_but_icon_extra_get(but)) != UI_BUT_ICONEXTRA_NONE))
+ {
rcti temp = *rect;
temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f);
- widget_draw_icon(but, ICON_X, alpha, &temp, false);
+
+ if (extra_icon_type == UI_BUT_ICONEXTRA_UNLINK) {
+ widget_draw_icon(but, ICON_X, alpha, &temp, false);
+ }
+ else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
+ widget_draw_icon(but, ICON_EYEDROPPER, alpha, &temp, false);
+ }
+ else {
+ BLI_assert(0);
+ }
+
rect->xmax -= ICON_SIZE_FROM_BUTRECT(rect);
}
@@ -1611,9 +1608,9 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
else if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) {
ui_text_clip_right_label(fstyle, but, rect);
}
- else if ((but->block->flag & UI_BLOCK_LOOP) && (but->type == UI_BTYPE_BUT)) {
+ else if (but->flag & UI_BUT_HAS_SEP_CHAR) {
/* Clip middle, but protect in all case right part containing the shortcut, if any. */
- ui_text_clip_middle_protect_right(fstyle, but, rect, "|");
+ ui_text_clip_middle_protect_right(fstyle, but, rect, UI_SEP_CHAR);
}
else {
ui_text_clip_middle(fstyle, but, rect);
@@ -1630,17 +1627,6 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
/* *********************** widget types ************************************* */
-
-/* uiWidgetStateColors
- * char inner_anim[4];
- * char inner_anim_sel[4];
- * char inner_key[4];
- * char inner_key_sel[4];
- * char inner_driven[4];
- * char inner_driven_sel[4];
- * float blend;
- */
-
static struct uiWidgetStateColors wcol_state_colors = {
{115, 190, 76, 255},
{90, 166, 51, 255},
@@ -1651,18 +1637,6 @@ static struct uiWidgetStateColors wcol_state_colors = {
0.5f, 0.0f
};
-/* uiWidgetColors
- * char outline[3];
- * char inner[4];
- * char inner_sel[4];
- * char item[3];
- * char text[3];
- * char text_sel[3];
- *
- * short shaded;
- * float shadetop, shadedown;
- */
-
static struct uiWidgetColors wcol_num = {
{25, 25, 25, 255},
{180, 180, 180, 255},
@@ -1793,7 +1767,7 @@ static struct uiWidgetColors wcol_tooltip = {
{45, 45, 45, 230},
{100, 100, 100, 255},
- {160, 160, 160, 255},
+ {255, 255, 255, 255},
{255, 255, 255, 255},
0,
@@ -2228,7 +2202,7 @@ static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int dir
widget_softshadow(rect, roundboxalign, 0.25f * U.widget_unit);
round_box_edges(&wtb, roundboxalign, rect, 0.25f * U.widget_unit);
- wtb.emboss = 0;
+ wtb.draw_emboss = false;
widgetbase_draw(&wtb, wcol);
glDisable(GL_BLEND);
@@ -2237,7 +2211,6 @@ static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int dir
static void ui_hsv_cursor(float x, float y)
{
-
glPushMatrix();
glTranslatef(x, y, 0.0f);
@@ -2252,7 +2225,6 @@ static void ui_hsv_cursor(float x, float y)
glDisable(GL_LINE_SMOOTH);
glPopMatrix();
-
}
void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rect,
@@ -2327,12 +2299,12 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
* Useful for color correction tools where you're only interested in hue. */
if (but->flag & UI_BUT_COLOR_LOCK) {
if (U.color_picker_type == USER_CP_CIRCLE_HSV)
- hsv[2] = 1.f;
+ hsv[2] = 1.0f;
else
hsv[2] = 0.5f;
}
- ui_color_picker_to_rgb(0.f, 0.f, hsv[2], colcent, colcent + 1, colcent + 2);
+ ui_color_picker_to_rgb(0.0f, 0.0f, hsv[2], colcent, colcent + 1, colcent + 2);
glShadeModel(GL_SMOOTH);
@@ -2378,7 +2350,7 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, const float alpha)
{
/* allows for 4 steps (red->yellow) */
- const float color_step = (1.0 / 48.0);
+ const float color_step = 1.0f / 48.0f;
int a;
float h = hsv[0], s = hsv[1], v = hsv[2];
float dx, dy, sx1, sx2, sy;
@@ -2391,9 +2363,9 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
switch (type) {
case UI_GRAD_SV:
hsv_to_rgb(h, 0.0, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
- hsv_to_rgb(h, 0.333, 0.0, &col1[1][0], &col1[1][1], &col1[1][2]);
- hsv_to_rgb(h, 0.666, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
- hsv_to_rgb(h, 1.0, 0.0, &col1[3][0], &col1[3][1], &col1[3][2]);
+ hsv_to_rgb(h, 0.0, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(h, 0.0, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(h, 0.0, 1.0, &col1[3][0], &col1[3][1], &col1[3][2]);
break;
case UI_GRAD_HV:
hsv_to_rgb(0.0, s, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
@@ -2408,26 +2380,26 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
hsv_to_rgb(0.0, 1.0, v, &col1[3][0], &col1[3][1], &col1[3][2]);
break;
case UI_GRAD_H:
- hsv_to_rgb(0.0, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
+ hsv_to_rgb(0.0, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
copy_v3_v3(col1[1], col1[0]);
copy_v3_v3(col1[2], col1[0]);
copy_v3_v3(col1[3], col1[0]);
break;
case UI_GRAD_S:
- hsv_to_rgb(1.0, 0.0, 1.0, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(1.0, 0.0, 1.0, &col1[1][0], &col1[1][1], &col1[1][2]);
copy_v3_v3(col1[0], col1[1]);
copy_v3_v3(col1[2], col1[1]);
copy_v3_v3(col1[3], col1[1]);
break;
case UI_GRAD_V:
- hsv_to_rgb(1.0, 1.0, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(1.0, 1.0, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
copy_v3_v3(col1[0], col1[2]);
copy_v3_v3(col1[1], col1[2]);
copy_v3_v3(col1[3], col1[2]);
break;
default:
assert(!"invalid 'type' argument");
- hsv_to_rgb(1.0, 1.0, 1.0, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(1.0, 1.0, 1.0, &col1[2][0], &col1[2][1], &col1[2][2]);
copy_v3_v3(col1[0], col1[2]);
copy_v3_v3(col1[1], col1[2]);
copy_v3_v3(col1[3], col1[2]);
@@ -2448,10 +2420,10 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
/* new color */
switch (type) {
case UI_GRAD_SV:
- hsv_to_rgb(h, 0.0, dx, &col1[0][0], &col1[0][1], &col1[0][2]);
- hsv_to_rgb(h, 0.333, dx, &col1[1][0], &col1[1][1], &col1[1][2]);
- hsv_to_rgb(h, 0.666, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
- hsv_to_rgb(h, 1.0, dx, &col1[3][0], &col1[3][1], &col1[3][2]);
+ hsv_to_rgb(h, dx, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
+ hsv_to_rgb(h, dx, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(h, dx, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(h, dx, 1.0, &col1[3][0], &col1[3][1], &col1[3][2]);
break;
case UI_GRAD_HV:
hsv_to_rgb(dx_next, s, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
@@ -2466,23 +2438,21 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
hsv_to_rgb(dx_next, 1.0, v, &col1[3][0], &col1[3][1], &col1[3][2]);
break;
case UI_GRAD_H:
- {
/* annoying but without this the color shifts - could be solved some other way
* - campbell */
- hsv_to_rgb(dx_next, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
+ hsv_to_rgb(dx_next, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
copy_v3_v3(col1[1], col1[0]);
copy_v3_v3(col1[2], col1[0]);
copy_v3_v3(col1[3], col1[0]);
break;
- }
case UI_GRAD_S:
- hsv_to_rgb(h, dx, 1.0, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(h, dx, 1.0, &col1[1][0], &col1[1][1], &col1[1][2]);
copy_v3_v3(col1[0], col1[1]);
copy_v3_v3(col1[2], col1[1]);
copy_v3_v3(col1[3], col1[1]);
break;
case UI_GRAD_V:
- hsv_to_rgb(h, 1.0, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(h, 1.0, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
copy_v3_v3(col1[0], col1[2]);
copy_v3_v3(col1[1], col1[2]);
copy_v3_v3(col1[3], col1[2]);
@@ -2511,9 +2481,8 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
}
glEnd();
}
-
+
glShadeModel(GL_FLAT);
-
}
bool ui_but_is_colorpicker_display_space(uiBut *but)
@@ -2534,7 +2503,7 @@ void ui_hsvcube_pos_from_vals(uiBut *but, const rcti *rect, float *hsv, float *x
switch ((int)but->a1) {
case UI_GRAD_SV:
- x = hsv[2]; y = hsv[1]; break;
+ x = hsv[1]; y = hsv[2]; break;
case UI_GRAD_HV:
x = hsv[0]; y = hsv[2]; break;
case UI_GRAD_HS:
@@ -2556,11 +2525,10 @@ void ui_hsvcube_pos_from_vals(uiBut *but, const rcti *rect, float *hsv, float *x
y = (hsv[2] - but->softmin) / (but->softmax - but->softmin);
break;
}
-
+
/* cursor */
*xp = rect->xmin + x * BLI_rcti_size_x(rect);
*yp = rect->ymin + y * BLI_rcti_size_y(rect);
-
}
static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
@@ -2641,9 +2609,8 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
x = rect->xmin + 0.5f * BLI_rcti_size_x(rect);
y = rect->ymin + v * BLI_rcti_size_y(rect);
CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
-
+
ui_hsv_cursor(x, y);
-
}
@@ -2728,7 +2695,8 @@ bool ui_link_bezier_points(const rcti *rect, float coord_array[][2], int resol)
BKE_curve_forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0], &coord_array[0][0], resol, sizeof(float[2]));
BKE_curve_forward_diff_bezier(vec[0][1], vec[1][1], vec[2][1], vec[3][1], &coord_array[0][1], resol, sizeof(float[2]));
- return 1;
+ /* TODO: why return anything if always true? */
+ return true;
}
#define LINK_RESOL 24
@@ -2737,9 +2705,10 @@ void ui_draw_link_bezier(const rcti *rect)
float coord_array[LINK_RESOL + 1][2];
if (ui_link_bezier_points(rect, coord_array, LINK_RESOL)) {
+#if 0 /* unused */
/* we can reuse the dist variable here to increment the GL curve eval amount*/
- // const float dist = 1.0f / (float)LINK_RESOL; // UNUSED
-
+ const float dist = 1.0f / (float)LINK_RESOL;
+#endif
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
@@ -2750,7 +2719,6 @@ void ui_draw_link_bezier(const rcti *rect)
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
-
}
}
@@ -2772,7 +2740,7 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s
else
rad = 0.5f * BLI_rcti_size_x(rect);
- wtb.shadedir = (horizontal) ? 1 : 0;
+ wtb.draw_shadedir = (horizontal) ? true : false;
/* draw back part, colors swapped and shading inverted */
if (horizontal)
@@ -2801,11 +2769,11 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s
}
/* draw */
- wtb.emboss = 0; /* only emboss once */
+ wtb.draw_emboss = false; /* only emboss once */
/* exception for progress bar */
if (state & UI_SCROLL_NO_OUTLINE) {
- SWAP(bool, outline, wtb.outline);
+ SWAP(bool, outline, wtb.draw_outline);
}
round_box_edges(&wtb, UI_CNR_ALL, slider, rad);
@@ -2828,7 +2796,7 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s
widgetbase_draw(&wtb, wcol);
if (state & UI_SCROLL_NO_OUTLINE) {
- SWAP(bool, outline, wtb.outline);
+ SWAP(bool, outline, wtb.draw_outline);
}
}
}
@@ -2955,7 +2923,7 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s
toffs = offs * 0.75f;
round_box_edges(&wtb, roundboxalign, rect, offs);
- wtb.outline = 0;
+ wtb.draw_outline = false;
widgetbase_draw(&wtb, wcol);
/* draw left/right parts only when not in text editing */
@@ -2980,7 +2948,7 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s
/* left part of slider, always rounded */
rect1.xmax = rect1.xmin + ceil(offs + U.pixelsize);
round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT), &rect1, offs);
- wtb1.outline = 0;
+ wtb1.draw_outline = false;
widgetbase_draw(&wtb1, wcol);
/* right part of slider, interpolate roundness */
@@ -3005,8 +2973,8 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s
}
/* outline */
- wtb.outline = 1;
- wtb.inner = 0;
+ wtb.draw_outline = true;
+ wtb.draw_inner = false;
widgetbase_draw(&wtb, wcol);
/* add space at either side of the button so text aligns with numbuttons (which have arrow icons) */
@@ -3014,7 +2982,6 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s
rect->xmax -= toffs;
rect->xmin += toffs;
}
-
}
/* I think 3 is sufficient border to indicate keyed status */
@@ -3074,7 +3041,7 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
float width = rect->xmax - rect->xmin;
float height = rect->ymax - rect->ymin;
/* find color luminance and change it slightly */
- float bw = rgb_to_bw(col);
+ float bw = rgb_to_grayscale(col);
bw += (bw < 0.5f) ? 0.5f : -0.5f;
@@ -3099,7 +3066,7 @@ static void widget_icon_has_anim(uiBut *but, uiWidgetColors *wcol, rcti *rect, i
float rad;
widget_init(&wtb);
- wtb.outline = 0;
+ wtb.draw_outline = false;
/* rounded */
rad = 0.5f * BLI_rcti_size_y(rect);
@@ -3129,7 +3096,6 @@ static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roun
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
-
}
@@ -3215,7 +3181,7 @@ static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(sta
widget_init(&wtb);
/* not rounded, no outline */
- wtb.outline = 0;
+ wtb.draw_outline = false;
round_box_edges(&wtb, 0, rect, 0.0f);
widgetbase_draw(&wtb, wcol);
@@ -3229,7 +3195,7 @@ static void widget_menu_radial_itembut(uiBut *but, uiWidgetColors *wcol, rcti *r
widget_init(&wtb);
- wtb.emboss = 0;
+ wtb.draw_emboss = false;
rad = 0.5f * BLI_rcti_size_y(rect);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
@@ -3252,7 +3218,7 @@ static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(sta
widget_init(&wtb);
/* rounded, but no outline */
- wtb.outline = 0;
+ wtb.draw_outline = false;
rad = 0.2f * U.widget_unit;
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
@@ -3325,7 +3291,6 @@ static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state),
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
-
}
static void widget_box(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
@@ -3366,7 +3331,6 @@ static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
-
}
static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
@@ -3407,10 +3371,9 @@ static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *
/* outline */
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
- wtb.outline = 1;
- wtb.inner = 0;
+ wtb.draw_outline = true;
+ wtb.draw_inner = false;
widgetbase_draw(&wtb, &wt->wcol);
-
}
static uiWidgetType *widget_type(uiWidgetTypeEnum type)
@@ -3700,8 +3663,7 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
case UI_BTYPE_TEXT:
wt = widget_type(UI_WTYPE_NAME);
break;
-
- case UI_BTYPE_SEARCH_MENU_UNLINK:
+
case UI_BTYPE_SEARCH_MENU:
wt = widget_type(UI_WTYPE_NAME);
if (but->block->flag & UI_BLOCK_LOOP)
@@ -3978,7 +3940,6 @@ static void draw_disk_shaded(
glVertex2f(c * radius_ext, s * radius_ext);
}
glEnd();
-
}
void ui_draw_pie_center(uiBlock *block)
@@ -4067,7 +4028,6 @@ void ui_draw_search_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
wt->draw(&wt->wcol, rect, block->flag, UI_CNR_ALL);
else
wt->draw(&wt->wcol, rect, 0, UI_CNR_ALL);
-
}
@@ -4117,7 +4077,7 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic
const float minwidth = (float)(UI_DPI_ICON_SIZE);
BLI_strncpy(drawstr, name, sizeof(drawstr));
- ui_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, NULL);
+ UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
glColor4ubv((unsigned char *)wt->wcol.text);
UI_fontstyle_draw(fstyle, rect, drawstr);
@@ -4152,39 +4112,31 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic
void ui_draw_preview_item(uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state)
{
- rcti trect = *rect, bg_rect;
+ rcti trect = *rect;
+ const float text_size = UI_UNIT_Y;
float font_dims[2] = {0.0f, 0.0f};
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM);
+ /* drawing button background */
wt->state(wt, state);
wt->draw(&wt->wcol, rect, 0, 0);
+ /* draw icon in rect above the space reserved for the label */
+ rect->ymin += text_size;
glEnable(GL_BLEND);
widget_draw_preview(iconid, 1.0f, rect);
+ glDisable(GL_BLEND);
BLF_width_and_height(fstyle->uifont_id, name, BLF_DRAW_STR_DUMMY_MAX, &font_dims[0], &font_dims[1]);
/* text rect */
trect.xmin += 0;
- trect.xmax = trect.xmin + font_dims[0] + 10;
- trect.ymin += 10;
+ trect.xmax = trect.xmin + font_dims[0] + U.widget_unit / 2;
+ trect.ymin += U.widget_unit / 2;
trect.ymax = trect.ymin + font_dims[1];
if (trect.xmax > rect->xmax - PREVIEW_PAD)
trect.xmax = rect->xmax - PREVIEW_PAD;
- bg_rect = trect;
- bg_rect.xmin = rect->xmin + PREVIEW_PAD;
- bg_rect.ymin = rect->ymin + PREVIEW_PAD;
- bg_rect.xmax = rect->xmax - PREVIEW_PAD;
- bg_rect.ymax += PREVIEW_PAD / 2;
-
- if (bg_rect.xmax > rect->xmax - PREVIEW_PAD)
- bg_rect.xmax = rect->xmax - PREVIEW_PAD;
-
- glColor4ubv((unsigned char *)wt->wcol_theme->inner_sel);
- glRecti(bg_rect.xmin, bg_rect.ymin, bg_rect.xmax, bg_rect.ymax);
- glDisable(GL_BLEND);
-
{
char drawstr[UI_MAX_DRAW_STR];
const float okwidth = (float)BLI_rcti_size_x(&trect);
@@ -4192,7 +4144,7 @@ void ui_draw_preview_item(uiFontStyle *fstyle, rcti *rect, const char *name, int
const float minwidth = (float)(UI_DPI_ICON_SIZE);
BLI_strncpy(drawstr, name, sizeof(drawstr));
- ui_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, NULL);
+ UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
glColor4ubv((unsigned char *)wt->wcol.text);
UI_fontstyle_draw(fstyle, &trect, drawstr);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index ab237e78c26..617a3e1bdc6 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -569,6 +569,13 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->paint_curve_pivot;
break;
+ case TH_METADATA_BG:
+ cp = ts->metadatabg;
+ break;
+ case TH_METADATA_TEXT:
+ cp = ts->metadatatext;
+ break;
+
case TH_UV_OTHERS:
cp = ts->uv_others;
break;
@@ -817,8 +824,9 @@ static void ui_theme_space_init_handles_color(ThemeSpace *theme_space)
rgba_char_args_set(theme_space->act_spline, 0xdb, 0x25, 0x12, 255);
}
-/* initialize default theme
- * Note: when you add new colors, created & saved themes need initialized
+/**
+ * initialize default theme
+ * \note: when you add new colors, created & saved themes need initialized
* use function below, init_userdef_do_versions()
*/
void ui_theme_init_default(void)
@@ -1098,7 +1106,7 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->text.syntaxd, 50, 0, 140, 255); /* Decorator/Preprocessor Dir. Blue-purple */
rgba_char_args_set(btheme->text.syntaxr, 140, 60, 0, 255); /* Reserved Orange*/
rgba_char_args_set(btheme->text.syntaxb, 128, 0, 80, 255); /* Builtin Red-purple */
- rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Grey (mix between fg/bg) */
+ rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Gray (mix between fg/bg) */
/* space oops */
btheme->toops = btheme->tv3d;
@@ -1504,8 +1512,9 @@ void UI_GetColorPtrShade3ubv(const unsigned char cp[3], unsigned char col[3], in
}
/* get a 3 byte color, blended and shaded between two other char color pointers */
-void UI_GetColorPtrBlendShade3ubv(const unsigned char cp1[3], const unsigned char cp2[3], unsigned char col[3],
- float fac, int offset)
+void UI_GetColorPtrBlendShade3ubv(
+ const unsigned char cp1[3], const unsigned char cp2[3], unsigned char col[3],
+ float fac, int offset)
{
int r, g, b;
@@ -1531,6 +1540,14 @@ void UI_ThemeClearColor(int colorid)
glClearColor(col[0], col[1], col[2], 0.0f);
}
+void UI_ThemeClearColorAlpha(int colorid, float alpha)
+{
+ float col[3];
+ UI_GetThemeColor3fv(colorid, col);
+ glClearColor(col[0], col[1], col[2], alpha);
+}
+
+
int UI_ThemeMenuShadowWidth(void)
{
bTheme *btheme = UI_GetTheme();
@@ -2343,7 +2360,7 @@ void init_userdef_do_versions(void)
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
rgba_char_args_set(btheme->text.syntaxd, 50, 0, 140, 255); /* Decorator/Preprocessor Dir. Blue-purple */
rgba_char_args_set(btheme->text.syntaxr, 140, 60, 0, 255); /* Reserved Orange */
- rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Grey (mix between fg/bg) */
+ rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Gray (mix between fg/bg) */
}
}
@@ -2594,6 +2611,15 @@ void init_userdef_do_versions(void)
cp[3] = 255;
}
}
+
+ if (U.versionfile < 274 || (U.versionfile == 274 && U.subversionfile < 5)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ copy_v4_v4_char(btheme->tima.metadatatext, btheme->tima.text_hi);
+ copy_v4_v4_char(btheme->tseq.metadatatext, btheme->tseq.text_hi);
+ }
+ }
+
if (U.pixelsize == 0.0f)
U.pixelsize = 1.0f;
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index fff60a00739..37b14318c16 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -99,11 +99,12 @@ BLI_INLINE void clamp_rctf_to_rcti(rcti *dst, const rctf *src)
/* XXX still unresolved: scrolls hide/unhide vs region mask handling */
/* XXX there's V2D_SCROLL_HORIZONTAL_HIDE and V2D_SCROLL_HORIZONTAL_FULLR ... */
-/* helper to allow scrollbars to dynamically hide
- * - returns a copy of the scrollbar settings with the flags to display
- * horizontal/vertical scrollbars removed
- * - input scroll value is the v2d->scroll var
- * - hide flags are set per region at drawtime
+/**
+ * helper to allow scrollbars to dynamically hide
+ * - returns a copy of the scrollbar settings with the flags to display
+ * horizontal/vertical scrollbars removed
+ * - input scroll value is the v2d->scroll var
+ * - hide flags are set per region at drawtime
*/
static int view2d_scroll_mapped(int scroll)
{
@@ -197,11 +198,12 @@ static void view2d_masks(View2D *v2d, int check_scrollers)
/* Refresh and Validation */
-/* Initialize all relevant View2D data (including view rects if first time) and/or refresh mask sizes after view resize
- * - for some of these presets, it is expected that the region will have defined some
- * additional settings necessary for the customization of the 2D viewport to its requirements
- * - this function should only be called from region init() callbacks, where it is expected that
- * this is called before UI_view2d_size_update(), as this one checks that the rects are properly initialized.
+/**
+ * Initialize all relevant View2D data (including view rects if first time) and/or refresh mask sizes after view resize
+ * - for some of these presets, it is expected that the region will have defined some
+ * additional settings necessary for the customization of the 2D viewport to its requirements
+ * - this function should only be called from region init() callbacks, where it is expected that
+ * this is called before UI_view2d_size_update(), as this one checks that the rects are properly initialized.
*/
void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
{
@@ -320,7 +322,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
if (do_init) {
float panelzoom = (style) ? style->panelzoom : 1.0f;
- float scrolw = v2d->scroll & V2D_SCROLL_RIGHT ? V2D_SCROLL_WIDTH : 0.0f;
+ float scrolw = (v2d->scroll & V2D_SCROLL_RIGHT) ? V2D_SCROLL_WIDTH : 0.0f;
v2d->tot.xmin = 0.0f;
v2d->tot.xmax = winx - scrolw;
@@ -361,8 +363,9 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
}
-/* Ensure View2D rects remain in a viable configuration
- * - cur is not allowed to be: larger than max, smaller than min, or outside of tot
+/**
+ * Ensure View2D rects remain in a viable configuration
+ * 'cur' is not allowed to be: larger than max, smaller than min, or outside of 'tot'
*/
// XXX pre2.5 -> this used to be called test_view2d()
static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_scrollers)
@@ -842,7 +845,8 @@ void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
}
-/* Restore 'cur' rect to standard orientation (i.e. optimal maximum view of tot)
+/**
+ * Restore 'cur' rect to standard orientation (i.e. optimal maximum view of tot)
* This does not take into account if zooming the view on an axis will improve the view (if allowed)
*/
void UI_view2d_curRect_reset(View2D *v2d)
@@ -1098,8 +1102,10 @@ void UI_view2d_view_ortho(View2D *v2d)
glLoadIdentity();
}
-/* Set view matrices to only use one axis of 'cur' only
- * - xaxis = if non-zero, only use cur x-axis, otherwise use cur-yaxis (mostly this will be used for x)
+/**
+ * Set view matrices to only use one axis of 'cur' only
+ *
+ * \param xaxis: if non-zero, only use cur x-axis, otherwise use cur-yaxis (mostly this will be used for x)
*/
void UI_view2d_view_orthoSpecial(ARegion *ar, View2D *v2d, const bool xaxis)
{
@@ -1192,20 +1198,23 @@ static void step_to_grid(float *step, int *power, int unit)
}
}
-/* Initialize settings necessary for drawing gridlines in a 2d-view
- * - Currently, will return pointer to View2DGrid struct that needs to
- * be freed with UI_view2d_grid_free()
- * - Is used for scrollbar drawing too (for units drawing)
- * - Units + clamping args will be checked, to make sure they are valid values that can be used
- * so it is very possible that we won't return grid at all!
- *
- * - xunits,yunits = V2D_UNIT_* grid steps in seconds or frames
- * - xclamp,yclamp = V2D_CLAMP_* only show whole-number intervals
- * - winx = width of region we're drawing to, note: not used but keeping for completeness.
- * - winy = height of region we're drawing into
+/**
+ * Initialize settings necessary for drawing gridlines in a 2d-view
+ *
+ * - Currently, will return pointer to View2DGrid struct that needs to
+ * be freed with UI_view2d_grid_free()
+ * - Is used for scrollbar drawing too (for units drawing)
+ * - Units + clamping args will be checked, to make sure they are valid values that can be used
+ * so it is very possible that we won't return grid at all!
+ *
+ * - xunits,yunits = V2D_UNIT_* grid steps in seconds or frames
+ * - xclamp,yclamp = V2D_CLAMP_* only show whole-number intervals
+ * - winx = width of region we're drawing to, note: not used but keeping for completeness.
+ * - winy = height of region we're drawing into
*/
-View2DGrid *UI_view2d_grid_calc(Scene *scene, View2D *v2d,
- short xunits, short xclamp, short yunits, short yclamp, int UNUSED(winx), int winy)
+View2DGrid *UI_view2d_grid_calc(
+ Scene *scene, View2D *v2d,
+ short xunits, short xclamp, short yunits, short yclamp, int UNUSED(winx), int winy)
{
View2DGrid *grid;
@@ -1483,9 +1492,11 @@ void UI_view2d_grid_free(View2DGrid *grid)
/* *********************************************************************** */
/* Scrollers */
-/* View2DScrollers is typedef'd in UI_view2d.h
- * WARNING: the start of this struct must not change, as view2d_ops.c uses this too.
- * For now, we don't need to have a separate (internal) header for structs like this...
+/**
+ * View2DScrollers is typedef'd in UI_view2d.h
+ *
+ * \warning The start of this struct must not change, as view2d_ops.c uses this too.
+ * For now, we don't need to have a separate (internal) header for structs like this...
*/
struct View2DScrollers {
/* focus bubbles */
@@ -1502,8 +1513,9 @@ struct View2DScrollers {
};
/* Calculate relevant scroller properties */
-View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d,
- short xunits, short xclamp, short yunits, short yclamp)
+View2DScrollers *UI_view2d_scrollers_calc(
+ const bContext *C, View2D *v2d,
+ short xunits, short xclamp, short yunits, short yclamp)
{
View2DScrollers *scrollers;
rcti vert, hor;
@@ -1885,18 +1897,22 @@ void UI_view2d_scrollers_free(View2DScrollers *scrollers)
/* *********************************************************************** */
/* List View Utilities */
-/* Get the view-coordinates of the nominated cell
- * - columnwidth, rowheight = size of each 'cell'
- * - startx, starty = coordinates (in 'tot' rect space) that the list starts from
- * This should be (0,0) for most views. However, for those where the starting row was offsetted
- * (like for Animation Editor channel lists, to make the first entry more visible), these will be
- * the min-coordinates of the first item.
- * - column, row = the 2d-coordinates (in 2D-view / 'tot' rect space) the cell exists at
- * - rect = coordinates of the cell (passed as single var instead of 4 separate, as it's more useful this way)
+/** Get the view-coordinates of the nominated cell
+ *
+ * \param columnwidth, rowheight: size of each 'cell'
+ * \param startx, starty: coordinates (in 'tot' rect space) that the list starts from.
+ * This should be (0,0) for most views. However, for those where the starting row was offsetted
+ * (like for Animation Editor channel lists, to make the first entry more visible), these will be
+ * the min-coordinates of the first item.
+ * \param column, row: The 2d-coordinates
+ * (in 2D-view / 'tot' rect space) the cell exists at
+ * \param rect: coordinates of the cell
+ * (passed as single var instead of 4 separate, as it's more useful this way)
*/
-void UI_view2d_listview_cell_to_view(View2D *v2d, float columnwidth, float rowheight,
- float startx, float starty,
- int column, int row, rctf *rect)
+void UI_view2d_listview_cell_to_view(
+ View2D *v2d, float columnwidth, float rowheight,
+ float startx, float starty,
+ int column, int row, rctf *rect)
{
/* sanity checks */
if (ELEM(NULL, v2d, rect)) {
@@ -1930,17 +1946,20 @@ void UI_view2d_listview_cell_to_view(View2D *v2d, float columnwidth, float rowhe
}
}
-/* Get the 'cell' (row, column) that the given 2D-view coordinates (i.e. in 'tot' rect space) lie in.
- * - columnwidth, rowheight = size of each 'cell'
- * - startx, starty = coordinates (in 'tot' rect space) that the list starts from
- * This should be (0,0) for most views. However, for those where the starting row was offsetted
- * (like for Animation Editor channel lists, to make the first entry more visible), these will be
- * the min-coordinates of the first item.
- * - viewx, viewy = 2D-coordinates (in 2D-view / 'tot' rect space) to get the cell for
- * - column, row = the 'coordinates' of the relevant 'cell'
+/**
+ * Get the 'cell' (row, column) that the given 2D-view coordinates (i.e. in 'tot' rect space) lie in.
+ *
+ * \param columnwidth, rowheight: size of each 'cell'
+ * \param startx, starty: coordinates (in 'tot' rect space) that the list starts from.
+ * This should be (0,0) for most views. However, for those where the starting row was offsetted
+ * (like for Animation Editor channel lists, to make the first entry more visible), these will be
+ * the min-coordinates of the first item.
+ * \param viewx, viewy: 2D-coordinates (in 2D-view / 'tot' rect space) to get the cell for
+ * \param column, row: the 'coordinates' of the relevant 'cell'
*/
-void UI_view2d_listview_view_to_cell(View2D *v2d, float columnwidth, float rowheight, float startx, float starty,
- float viewx, float viewy, int *column, int *row)
+void UI_view2d_listview_view_to_cell(
+ View2D *v2d, float columnwidth, float rowheight, float startx, float starty,
+ float viewx, float viewy, int *column, int *row)
{
/* adjust view coordinates to be all positive ints, corrected for the start offset */
const int x = (int)(floorf(fabsf(viewx) + 0.5f) - startx);
@@ -1967,13 +1986,16 @@ void UI_view2d_listview_view_to_cell(View2D *v2d, float columnwidth, float rowhe
*row = 0;
}
-/* Get the 'extreme' (min/max) column and row indices which are visible within the 'cur' rect
- * - columnwidth, rowheight = size of each 'cell'
- * - startx, starty = coordinates that the list starts from, which should be (0,0) for most views
- * - column/row_min/max = the starting and ending column/row indices
+/**
+ * Get the 'extreme' (min/max) column and row indices which are visible within the 'cur' rect
+ *
+ * \param columnwidth, rowheight: Size of each 'cell'
+ * \param startx, starty: Coordinates that the list starts from, which should be (0,0) for most views
+ * \param column_min, column_max, row_min, row_max: The starting and ending column/row indices
*/
-void UI_view2d_listview_visible_cells(View2D *v2d, float columnwidth, float rowheight, float startx, float starty,
- int *column_min, int *column_max, int *row_min, int *row_max)
+void UI_view2d_listview_visible_cells(
+ View2D *v2d, float columnwidth, float rowheight, float startx, float starty,
+ int *column_min, int *column_max, int *row_min, int *row_max)
{
/* using 'cur' rect coordinates, call the cell-getting function to get the cells for this */
if (v2d) {
@@ -1999,10 +2021,11 @@ float UI_view2d_region_to_view_y(struct View2D *v2d, float y)
return (v2d->cur.ymin + (BLI_rctf_size_y(&v2d->cur) * (y - v2d->mask.ymin) / BLI_rcti_size_y(&v2d->mask)));
}
-/* Convert from screen/region space to 2d-View space
- *
- * - x,y = coordinates to convert
- * - viewx,viewy = resultant coordinates
+/**
+ * Convert from screen/region space to 2d-View space
+ *
+ * \param x, y: coordinates to convert
+ * \param r_view_x, r_view_y: resultant coordinates
*/
void UI_view2d_region_to_view(View2D *v2d, float x, float y, float *r_view_x, float *r_view_y)
{
@@ -2030,11 +2053,12 @@ float UI_view2d_view_to_region_y(View2D *v2d, float y)
return (v2d->mask.ymin + (((y - v2d->cur.ymin) / BLI_rctf_size_y(&v2d->cur)) * BLI_rcti_size_y(&v2d->mask)));
}
-/* Convert from 2d-View space to screen/region space
- * - Coordinates are clamped to lie within bounds of region
+/**
+ * Convert from 2d-View space to screen/region space
+ * \note Coordinates are clamped to lie within bounds of region
*
- * - x,y = coordinates to convert
- * - regionx,regiony = resultant coordinates
+ * \param x, y: Coordinates to convert.
+ * \param r_region_x, r_region_y: Resultant coordinates.
*/
bool UI_view2d_view_to_region_clip(View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
{
@@ -2057,11 +2081,13 @@ bool UI_view2d_view_to_region_clip(View2D *v2d, float x, float y, int *r_region_
}
}
-/* Convert from 2d-view space to screen/region space
- * - Coordinates are NOT clamped to lie within bounds of region
+/**
+ * Convert from 2d-view space to screen/region space
+ *
+ * \note Coordinates are NOT clamped to lie within bounds of region.
*
- * - x,y = coordinates to convert
- * - regionx,regiony = resultant coordinates
+ * \param x, y: Coordinates to convert.
+ * \param r_region_x, r_region_y: Resultant coordinates.
*/
void UI_view2d_view_to_region(View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
{
@@ -2175,25 +2201,30 @@ View2D *UI_view2d_fromcontext_rwin(const bContext *C)
}
-/* Calculate the scale per-axis of the drawing-area
- * - Is used to inverse correct drawing of icons, etc. that need to follow view
- * but not be affected by scale
+/**
+ * Calculate the scale per-axis of the drawing-area
*
- * - x,y = scale on each axis
+ * Is used to inverse correct drawing of icons, etc. that need to follow view
+ * but not be affected by scale
+ *
+ * \param x, y: scale on each axis
*/
void UI_view2d_scale_get(View2D *v2d, float *x, float *y)
{
if (x) *x = BLI_rcti_size_x(&v2d->mask) / BLI_rctf_size_x(&v2d->cur);
if (y) *y = BLI_rcti_size_y(&v2d->mask) / BLI_rctf_size_y(&v2d->cur);
}
-/* Same as UI_view2d_scale_get() - 1.0f / x, y */
+/**
+ * Same as ``UI_view2d_scale_get() - 1.0f / x, y``
+ */
void UI_view2d_scale_get_inverse(View2D *v2d, float *x, float *y)
{
if (x) *x = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
if (y) *y = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask);
}
-/* Simple functions for consistent center offset access.
+/**
+ * Simple functions for consistent center offset access.
* Used by node editor to shift view center for each individual node tree.
*/
void UI_view2d_center_get(struct View2D *v2d, float *x, float *y)
@@ -2239,13 +2270,15 @@ void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac)
UI_view2d_curRect_validate(v2d);
}
-/* Check if mouse is within scrollers
- * - Returns appropriate code for match
- * 'h' = in horizontal scroller
- * 'v' = in vertical scroller
- * 0 = not in scroller
- *
- * - x,y = mouse coordinates in screen (not region) space
+/**
+ * Check if mouse is within scrollers
+ *
+ * \param x, y: Mouse coordinates in screen (not region) space.
+ *
+ * \return appropriate code for match.
+ * - 'h' = in horizontal scroller.
+ * - 'v' = in vertical scroller.
+ * - 0 = not in scroller.
*/
short UI_view2d_mouse_in_scrollers(const bContext *C, View2D *v2d, int x, int y)
{
@@ -2288,8 +2321,9 @@ typedef struct View2DString {
static MemArena *g_v2d_strings_arena = NULL;
static View2DString *g_v2d_strings = NULL;
-void UI_view2d_text_cache_add(View2D *v2d, float x, float y,
- const char *str, size_t str_len, const char col[4])
+void UI_view2d_text_cache_add(
+ View2D *v2d, float x, float y,
+ const char *str, size_t str_len, const char col[4])
{
int mval[2];
@@ -2319,8 +2353,9 @@ void UI_view2d_text_cache_add(View2D *v2d, float x, float y,
}
/* no clip (yet) */
-void UI_view2d_text_cache_add_rectf(View2D *v2d, const rctf *rect_view,
- const char *str, size_t str_len, const char col[4])
+void UI_view2d_text_cache_add_rectf(
+ View2D *v2d, const rctf *rect_view,
+ const char *str, size_t str_len, const char col[4])
{
rcti rect;
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 88140d897ae..6fbe8509188 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -63,12 +63,13 @@ static int view2d_poll(bContext *C)
/* ********************************************************* */
/* VIEW PANNING OPERATOR */
-/* This group of operators come in several forms:
- * 1) Modal 'dragging' with MMB - where movement of mouse dictates amount to pan view by
- * 2) Scrollwheel 'steps' - rolling mousewheel by one step moves view by predefined amount
+/**
+ * This group of operators come in several forms:
+ * -# Modal 'dragging' with MMB - where movement of mouse dictates amount to pan view by
+ * -# Scrollwheel 'steps' - rolling mousewheel by one step moves view by predefined amount
*
- * In order to make sure this works, each operator must define the following RNA-Operator Props:
- * deltax, deltay - define how much to move view by (relative to zoom-correction factor)
+ * In order to make sure this works, each operator must define the following RNA-Operator Props:
+ * - `deltax, deltay` - define how much to move view by (relative to zoom-correction factor)
*/
/* ------------------ Shared 'core' stuff ---------------------- */
@@ -328,7 +329,7 @@ static void VIEW2D_OT_pan(wmOperatorType *ot)
ot->cancel = view_pan_cancel;
/* operator is modal */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
/* rna - must keep these in sync with the other operators */
RNA_def_int(ot->srna, "deltax", 0, INT_MIN, INT_MAX, "Delta X", "", INT_MIN, INT_MAX);
@@ -525,15 +526,18 @@ static void VIEW2D_OT_scroll_up(wmOperatorType *ot)
/* ********************************************************* */
/* SINGLE-STEP VIEW ZOOMING OPERATOR */
-/* This group of operators come in several forms:
- * 1) Scrollwheel 'steps' - rolling mousewheel by one step zooms view by predefined amount
- * 2) Scrollwheel 'steps' + alt + ctrl/shift - zooms view on one axis only (ctrl=x, shift=y) // XXX this could be implemented...
- * 3) Pad +/- Keys - pressing each key moves the zooms the view by a predefined amount
+/**
+ * This group of operators come in several forms:
+ * -# Scrollwheel 'steps' - rolling mousewheel by one step zooms view by predefined amount.
+ * -# Scrollwheel 'steps' + alt + ctrl/shift - zooms view on one axis only (ctrl=x, shift=y).
+ * XXX this could be implemented...
+ * -# Pad +/- Keys - pressing each key moves the zooms the view by a predefined amount.
*
* In order to make sure this works, each operator must define the following RNA-Operator Props:
- * zoomfacx, zoomfacy - These two zoom factors allow for non-uniform scaling.
- * It is safe to scale by 0, as these factors are used to determine
- * amount to enlarge 'cur' by
+ *
+ * - zoomfacx, zoomfacy - These two zoom factors allow for non-uniform scaling.
+ * It is safe to scale by 0, as these factors are used to determine.
+ * amount to enlarge 'cur' by.
*/
/* ------------------ 'Shared' stuff ------------------------ */
@@ -620,8 +624,9 @@ static int view_zoom_poll(bContext *C)
}
/* apply transform to view (i.e. adjust 'cur' rect) */
-static void view_zoomstep_apply_ex(bContext *C, v2dViewZoomData *vzd, const bool use_mousepos,
- const float facx, const float facy)
+static void view_zoomstep_apply_ex(
+ bContext *C, v2dViewZoomData *vzd, const bool use_mousepos,
+ const float facx, const float facy)
{
ARegion *ar = CTX_wm_region(C);
View2D *v2d = &ar->v2d;
@@ -661,7 +666,9 @@ static void view_zoomstep_apply_ex(bContext *C, v2dViewZoomData *vzd, const bool
const float zoomx = (float)(BLI_rcti_size_x(&v2d->mask) + 1) / BLI_rctf_size_x(&v2d->cur);
/* only move view to mouse if zoom fac is inside minzoom/maxzoom */
- if (IN_RANGE_INCL(zoomx, v2d->minzoom, v2d->maxzoom)) {
+ if (((v2d->keepzoom & V2D_LIMITZOOM) == 0) ||
+ IN_RANGE_INCL(zoomx, v2d->minzoom, v2d->maxzoom))
+ {
float mval_fac = (vzd->mx_2d - cur_old.xmin) / BLI_rctf_size_x(&cur_old);
float mval_faci = 1.0f - mval_fac;
float ofs = (mval_fac * dx) - (mval_faci * dx);
@@ -692,7 +699,9 @@ static void view_zoomstep_apply_ex(bContext *C, v2dViewZoomData *vzd, const bool
const float zoomy = (float)(BLI_rcti_size_y(&v2d->mask) + 1) / BLI_rctf_size_y(&v2d->cur);
/* only move view to mouse if zoom fac is inside minzoom/maxzoom */
- if (IN_RANGE_INCL(zoomy, v2d->minzoom, v2d->maxzoom)) {
+ if (((v2d->keepzoom & V2D_LIMITZOOM) == 0) ||
+ IN_RANGE_INCL(zoomy, v2d->minzoom, v2d->maxzoom))
+ {
float mval_fac = (vzd->my_2d - cur_old.ymin) / BLI_rctf_size_y(&cur_old);
float mval_faci = 1.0f - mval_fac;
float ofs = (mval_fac * dy) - (mval_faci * dy);
@@ -867,10 +876,11 @@ static void VIEW2D_OT_zoom_out(wmOperatorType *ot)
/* ********************************************************* */
/* DRAG-ZOOM OPERATOR */
-/* MMB Drag - allows non-uniform scaling by dragging mouse
+/**
+ * MMB Drag - allows non-uniform scaling by dragging mouse
*
- * In order to make sure this works, each operator must define the following RNA-Operator Props:
- * deltax, deltay - amounts to add to each side of the 'cur' rect
+ * In order to make sure this works, each operator must define the following RNA-Operator Props:
+ * - `deltax, deltay` - amounts to add to each side of the 'cur' rect
*/
/* apply transform to view (i.e. adjust 'cur' rect) */
@@ -1175,7 +1185,7 @@ static void VIEW2D_OT_zoom(wmOperatorType *ot)
ot->poll = view_zoom_poll;
/* operator is repeatable */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
/* rna - must keep these in sync with the other operators */
prop = RNA_def_float(ot->srna, "deltax", 0, -FLT_MAX, FLT_MAX, "Delta X", "", -FLT_MAX, FLT_MAX);
@@ -1187,10 +1197,12 @@ static void VIEW2D_OT_zoom(wmOperatorType *ot)
/* ********************************************************* */
/* BORDER-ZOOM */
-/* The user defines a rect using standard borderselect tools, and we use this rect to
+/**
+ * The user defines a rect using standard borderselect tools, and we use this rect to
* define the new zoom-level of the view in the following ways:
- * 1) LEFTMOUSE - zoom in to view
- * 2) RIGHTMOUSE - zoom out of view
+ *
+ * -# LEFTMOUSE - zoom in to view
+ * -# RIGHTMOUSE - zoom out of view
*
* Currently, these key mappings are hardcoded, but it shouldn't be too important to
* have custom keymappings for this...
@@ -1402,8 +1414,9 @@ static float smooth_view_rect_to_fac(const rctf *rect_a, const rctf *rect_b)
/* will start timer if appropriate */
/* the arguments are the desired situation */
-void UI_view2d_smooth_view(bContext *C, ARegion *ar,
- const rctf *cur, const int smooth_viewtx)
+void UI_view2d_smooth_view(
+ bContext *C, ARegion *ar,
+ const rctf *cur, const int smooth_viewtx)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
@@ -1528,13 +1541,14 @@ static void VIEW2D_OT_smoothview(wmOperatorType *ot)
/* ********************************************************* */
/* SCROLLERS */
-/* Scrollers should behave in the following ways, when clicked on with LMB (and dragged):
- * 1) 'Handles' on end of 'bubble' - when the axis that the scroller represents is zoomable,
- * enlarge 'cur' rect on the relevant side
- * 2) 'Bubble'/'bar' - just drag, and bar should move with mouse (view pans opposite)
+/**
+ * Scrollers should behave in the following ways, when clicked on with LMB (and dragged):
+ * -# 'Handles' on end of 'bubble' - when the axis that the scroller represents is zoomable,
+ * enlarge 'cur' rect on the relevant side.
+ * -# 'Bubble'/'bar' - just drag, and bar should move with mouse (view pans opposite).
*
- * In order to make sure this works, each operator must define the following RNA-Operator Props:
- * deltax, deltay - define how much to move view by (relative to zoom-correction factor)
+ * In order to make sure this works, each operator must define the following RNA-Operator Props:
+ * - `deltax, deltay` - define how much to move view by (relative to zoom-correction factor)
*/
/* customdata for scroller-invoke data */
@@ -1556,10 +1570,12 @@ typedef struct v2dScrollerMove {
} v2dScrollerMove;
-/* View2DScrollers is typedef'd in UI_view2d.h
+/**
+ * #View2DScrollers is typedef'd in UI_view2d.h
* This is a CUT DOWN VERSION of the 'real' version, which is defined in view2d.c, as we only need focus bubble info
- * WARNING: the start of this struct must not change, so that it stays in sync with the 'real' version
- * For now, we don't need to have a separate (internal) header for structs like this...
+ *
+ * \warning: The start of this struct must not change, so that it stays in sync with the 'real' version
+ * For now, we don't need to have a separate (internal) header for structs like this...
*/
struct View2DScrollers {
/* focus bubbles */
@@ -1578,10 +1594,12 @@ enum {
/* ------------------------ */
-/* check if mouse is within scroller handle
- * - mouse = relevant mouse coordinate in region space
- * - sc_min, sc_max = extents of scroller 'groove' (potential available space for scroller)
- * - sh_min, sh_max = positions of scrollbar handles
+/**
+ * Check if mouse is within scroller handle.
+ *
+ * \param mouse: relevant mouse coordinate in region space.
+ * \param sc_min, sc_max: extents of scroller 'groove' (potential available space for scroller).
+ * \param sh_min, sh_max: positions of scrollbar handles.
*/
static short mouse_in_scroller_handle(int mouse, int sc_min, int sc_max, int sh_min, int sh_max)
{
@@ -1785,7 +1803,10 @@ static void scroller_activate_apply(bContext *C, wmOperator *op)
UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
}
-/* handle user input for scrollers - calculations of mouse-movement need to be done here, not in the apply callback! */
+/**
+ * Handle user input for scrollers - calculations of mouse-movement need to be done here,
+ * not in the apply callback!
+ */
static int scroller_activate_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
v2dScrollerMove *vsm = op->customdata;
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index f331dea5c5c..f8e4738ab38 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -26,8 +26,10 @@ set(INC
../../bmesh
../../makesdna
../../makesrna
+ ../../pointcache
../../windowmanager
../../collada
+ ../../../../intern/guardedalloc
)
set(INC_SYS
@@ -35,9 +37,12 @@ set(INC_SYS
)
set(SRC
+ io_cache_library.c
+ io_cache_shapekey.c
io_collada.c
io_ops.c
+ io_cache_library.h
io_collada.h
io_ops.h
)
diff --git a/source/blender/editors/io/SConscript b/source/blender/editors/io/SConscript
index 0facb24e2c3..d1826784547 100644
--- a/source/blender/editors/io/SConscript
+++ b/source/blender/editors/io/SConscript
@@ -36,10 +36,13 @@ incs = [
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../bmesh',
'../../collada',
+ '../../makesdna',
'../../makesrna',
+ '../../pointcache',
'../../windowmanager',
- '../../bmesh../../makesdna',
+ '../../../../intern/guardedalloc',
]
if env['WITH_BF_COLLADA']:
diff --git a/source/blender/editors/io/io_cache_library.c b/source/blender/editors/io/io_cache_library.c
new file mode 100644
index 00000000000..f7076ae0cae
--- /dev/null
+++ b/source/blender/editors/io/io_cache_library.c
@@ -0,0 +1,961 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/io/io_cache_library.c
+ * \ingroup editor/io
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLF_translation.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_fileops.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_path_util.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_cache_library_types.h"
+#include "DNA_group_types.h"
+#include "DNA_listBase.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_force.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+
+#include "BKE_anim.h"
+#include "BKE_blender.h"
+#include "BKE_depsgraph.h"
+#include "BKE_cache_library.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+
+#include "ED_screen.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "io_cache_library.h"
+
+#include "PTC_api.h"
+
+static int ED_cache_library_active_object_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ if (!(ob && (ob->transflag & OB_DUPLIGROUP) && ob->dup_group && ob->cache_library))
+ return false;
+
+ return true;
+}
+
+static int ED_cache_modifier_poll(bContext *C)
+{
+ if (!ED_cache_library_active_object_poll(C))
+ return false;
+ if (!CTX_data_pointer_get_type(C, "cache_modifier", &RNA_CacheLibraryModifier).data)
+ return false;
+
+ return true;
+}
+
+/********************** new cache library operator *********************/
+
+static int new_cachelib_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+ CacheLibrary *cachelib = ob->cache_library;
+ Main *bmain = CTX_data_main(C);
+ PointerRNA ptr, idptr;
+ PropertyRNA *prop;
+
+ /* add or copy material */
+ if (cachelib) {
+ cachelib = BKE_cache_library_copy(cachelib);
+ }
+ else {
+ cachelib = BKE_cache_library_add(bmain, DATA_("CacheLibrary"));
+ }
+
+ /* enable fake user by default */
+ cachelib->id.flag |= LIB_FAKEUSER;
+
+ /* hook into UI */
+ UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
+
+ if (prop) {
+ /* when creating new ID blocks, use is already 1, but RNA
+ * pointer se also increases user, so this compensates it */
+ cachelib->id.us--;
+
+ RNA_id_pointer_create(&cachelib->id, &idptr);
+ RNA_property_pointer_set(&ptr, prop, idptr);
+ RNA_property_update(C, &ptr, prop);
+ }
+
+ WM_event_add_notifier(C, NC_SCENE, cachelib);
+
+ return OPERATOR_FINISHED;
+}
+
+void CACHELIBRARY_OT_new(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "New Cache Library";
+ ot->idname = "CACHELIBRARY_OT_new";
+ ot->description = "Add a new cache library";
+
+ /* api callbacks */
+ ot->poll = ED_operator_object_active;
+ ot->exec = new_cachelib_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+}
+
+/********************** delete cache library operator *********************/
+
+static int cache_library_delete_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ CacheLibrary *cachelib = ob->cache_library;
+
+ BKE_cache_library_unlink(cachelib);
+ BKE_libblock_free(bmain, cachelib);
+
+ WM_event_add_notifier(C, NC_SCENE, cachelib);
+
+ return OPERATOR_FINISHED;
+}
+
+void CACHELIBRARY_OT_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete Cache Library";
+ ot->idname = "CACHELIBRARY_OT_delete";
+ ot->description = "Delete a cache library data block";
+
+ /* api callbacks */
+ ot->exec = cache_library_delete_exec;
+ ot->invoke = WM_operator_confirm;
+ ot->poll = ED_cache_library_active_object_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+}
+
+/********************** bake cache operator *********************/
+
+typedef enum eCacheLibraryBake_EvalMode {
+ CACHELIBRARY_BAKE_PREVIEW = (1 << 0), /* evaluate data with preview settings */
+ CACHELIBRARY_BAKE_RENDER = (1 << 1), /* evaluate data with render settings */
+} eCacheLibraryBake_EvalMode;
+
+static int cache_library_bake_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+
+ if (!ob || !(ob->transflag & OB_DUPLIGROUP) || !ob->dup_group || !ob->cache_library)
+ return false;
+ /* disable when the result is not displayed, just to avoid confusing situations */
+ if (ob->cache_library->display_mode != CACHE_LIBRARY_DISPLAY_RESULT)
+ return false;
+
+ return true;
+}
+
+typedef struct CacheLibraryBakeJob {
+ short *stop, *do_update;
+ float *progress;
+
+ struct Main *bmain;
+ struct Scene *scene;
+ struct CacheLibrary *cachelib;
+ int lay;
+ float mat[4][4];
+ struct Group *group;
+
+ eCacheLibraryBake_EvalMode eval_mode;
+ EvaluationContext eval_ctx;
+
+ struct PTCWriterArchive *archive;
+ struct PTCWriter *writer;
+
+ int start_frame, end_frame;
+ int origfra; /* original frame to reset scene after export */
+ float origframelen; /* original frame length to reset scene after export */
+} CacheLibraryBakeJob;
+
+static bool cache_library_bake_stop(CacheLibraryBakeJob *data)
+{
+ return (*data->stop) || G.is_break;
+}
+
+static void cache_library_bake_set_progress(CacheLibraryBakeJob *data, float progress)
+{
+ *data->do_update = 1;
+ *data->progress = progress;
+}
+
+static void cache_library_bake_set_particle_baking(Main *bmain, bool baking)
+{
+ /* XXX would be nicer to just loop over scene->base here,
+ * but this does not catch all objects included in dupli groups ...
+ */
+ Object *ob;
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
+ ParticleSystem *psys;
+
+ for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ if (baking)
+ psys->pointcache->flag |= PTCACHE_BAKING;
+ else
+ psys->pointcache->flag &= ~PTCACHE_BAKING;
+ }
+ }
+}
+
+static void cache_library_bake_do(CacheLibraryBakeJob *data, bool use_render)
+{
+ Scene *scene = data->scene;
+ int frame, frame_prev, start_frame, end_frame;
+ CacheProcessData process_data;
+
+ if (cache_library_bake_stop(data))
+ return;
+
+ /* === prepare === */
+
+ process_data.lay = data->lay;
+ copy_m4_m4(process_data.mat, data->mat);
+ process_data.dupcache = BKE_dupli_cache_new();
+
+ switch (data->cachelib->source_mode) {
+ case CACHE_LIBRARY_SOURCE_SCENE:
+ data->writer = PTC_writer_dupligroup(data->group->id.name, &data->eval_ctx, scene, data->group, data->cachelib);
+ break;
+ case CACHE_LIBRARY_SOURCE_CACHE:
+ data->writer = PTC_writer_duplicache(data->group->id.name, data->group, process_data.dupcache, data->cachelib->data_types, G.debug & G_DEBUG_SIMDATA);
+ break;
+ }
+ if (!data->writer) {
+ BKE_dupli_cache_free(process_data.dupcache);
+ return;
+ }
+
+ data->cachelib->flag |= CACHE_LIBRARY_BAKING;
+
+ PTC_writer_init(data->writer, data->archive);
+
+ start_frame = data->start_frame;
+ end_frame = data->end_frame;
+
+ /* === frame loop === */
+
+ cache_library_bake_set_progress(data, 0.0f);
+ for (frame = frame_prev = start_frame; frame <= end_frame; frame_prev = frame++) {
+
+ const bool init_strands = (frame == start_frame);
+
+ printf("Bake Cache '%s' | Frame %d\n", data->group->id.name+2, frame);
+
+ /* XXX Ugly, but necessary to avoid particle caching of paths when not needed.
+ * This takes a lot of time, but is only needed in the first frame.
+ */
+ cache_library_bake_set_particle_baking(data->bmain, !init_strands);
+
+ scene->r.cfra = frame;
+ BKE_scene_update_group_for_newframe(&data->eval_ctx, data->bmain, scene, data->group, scene->lay);
+
+ switch (data->cachelib->source_mode) {
+ case CACHE_LIBRARY_SOURCE_SCENE:
+ BKE_dupli_cache_from_group(scene, data->group, data->cachelib, process_data.dupcache, &data->eval_ctx, init_strands);
+ break;
+ case CACHE_LIBRARY_SOURCE_CACHE:
+ BKE_cache_read_dupli_cache(data->cachelib, process_data.dupcache, scene, data->group, frame, use_render, false);
+ break;
+ }
+
+ BKE_cache_process_dupli_cache(data->cachelib, &process_data, scene, data->group, frame_prev, frame, true, false, true);
+
+ PTC_write_sample(data->writer);
+
+ cache_library_bake_set_progress(data, (float)(frame - start_frame + 1) / (float)(end_frame - start_frame + 1));
+ if (cache_library_bake_stop(data))
+ break;
+ }
+
+ /* === cleanup === */
+
+ if (data->writer) {
+ PTC_writer_free(data->writer);
+ data->writer = NULL;
+ }
+
+ data->cachelib->flag &= ~CACHE_LIBRARY_BAKING;
+ cache_library_bake_set_particle_baking(data->bmain, false);
+
+ BKE_dupli_cache_free(process_data.dupcache);
+}
+
+/* Warning! Deletes existing files if possible, operator should show confirm dialog! */
+static bool cache_library_bake_ensure_file_target(const char *filename)
+{
+ if (BLI_exists(filename)) {
+ if (BLI_is_dir(filename)) {
+ return false;
+ }
+ else if (BLI_is_file(filename)) {
+ if (BLI_file_is_writable(filename)) {
+ /* returns 0 on success */
+ return (BLI_delete(filename, false, false) == 0);
+ }
+ else {
+ return false;
+ }
+ }
+ else {
+ return false;
+ }
+ }
+ return true;
+}
+
+static void cache_library_bake_start(void *customdata, short *stop, short *do_update, float *progress)
+{
+ CacheLibraryBakeJob *data = (CacheLibraryBakeJob *)customdata;
+ const bool do_preview = data->eval_mode & CACHELIBRARY_BAKE_PREVIEW;
+ const bool do_render = data->eval_mode & CACHELIBRARY_BAKE_RENDER;
+ const PTCArchiveResolution archive_res = (do_preview ? PTC_RESOLUTION_PREVIEW : 0) | (do_render ? PTC_RESOLUTION_RENDER : 0);
+ Scene *scene = data->scene;
+ char filename[FILE_MAX];
+ char app_name[MAX_NAME];
+ IDProperty *metadata;
+
+ data->stop = stop;
+ data->do_update = do_update;
+ data->progress = progress;
+
+ data->origfra = scene->r.cfra;
+ data->origframelen = scene->r.framelen;
+ scene->r.framelen = 1.0f;
+
+ BKE_cache_archive_output_path(data->cachelib, filename, sizeof(filename));
+ BLI_snprintf(app_name, sizeof(app_name), "Blender %s", versionstr);
+
+ metadata = BKE_cache_library_get_output_metadata(data->cachelib, false);
+
+ data->archive = PTC_open_writer_archive(FPS, data->start_frame, filename, archive_res, app_name, data->cachelib->description, NULL, metadata);
+
+ if (data->archive) {
+
+ G.is_break = false;
+
+ if (do_preview) {
+ data->eval_ctx.mode = DAG_EVAL_VIEWPORT;
+ PTC_writer_archive_use_render(data->archive, false);
+ cache_library_bake_do(data, false);
+ }
+
+ if (do_render) {
+ data->eval_ctx.mode = DAG_EVAL_RENDER;
+ PTC_writer_archive_use_render(data->archive, true);
+ cache_library_bake_do(data, true);
+ }
+
+ }
+
+ *do_update = true;
+ *stop = 0;
+}
+
+static void cache_library_bake_end(void *customdata)
+{
+ CacheLibraryBakeJob *data = (CacheLibraryBakeJob *)customdata;
+ Scene *scene = data->scene;
+
+ G.is_rendering = false;
+ BKE_spacedata_draw_locks(false);
+
+ if (data->writer)
+ PTC_writer_free(data->writer);
+ if (data->archive)
+ PTC_close_writer_archive(data->archive);
+
+ /* reset scene frame */
+ scene->r.cfra = data->origfra;
+ scene->r.framelen = data->origframelen;
+ BKE_scene_update_for_newframe(&data->eval_ctx, data->bmain, scene, scene->lay);
+}
+
+static void cache_library_bake_init(CacheLibraryBakeJob *data, bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ CacheLibrary *cachelib = ob->cache_library;
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+
+ /* make sure we can write */
+ char filename[FILE_MAX];
+ BKE_cache_archive_output_path(cachelib, filename, sizeof(filename));
+ cache_library_bake_ensure_file_target(filename);
+
+ /* XXX annoying hack: needed to prevent data corruption when changing
+ * scene frame in separate threads
+ */
+ G.is_rendering = true;
+
+ BKE_spacedata_draw_locks(true);
+
+ /* setup data */
+ data->bmain = bmain;
+ data->scene = scene;
+ data->cachelib = cachelib;
+ data->lay = ob->lay;
+ copy_m4_m4(data->mat, ob->obmat);
+ data->group = ob->dup_group;
+
+ data->eval_mode = RNA_enum_get(op->ptr, "eval_mode");
+
+ if (RNA_struct_property_is_set(op->ptr, "start_frame"))
+ data->start_frame = RNA_int_get(op->ptr, "start_frame");
+ else
+ data->start_frame = scene->r.sfra;
+ if (RNA_struct_property_is_set(op->ptr, "end_frame"))
+ data->end_frame = RNA_int_get(op->ptr, "end_frame");
+ else
+ data->end_frame = scene->r.efra;
+}
+
+static void cache_library_bake_freejob(void *customdata)
+{
+ CacheLibraryBakeJob *data= (CacheLibraryBakeJob *)customdata;
+ MEM_freeN(data);
+}
+
+static int cache_library_bake_exec(bContext *C, wmOperator *op)
+{
+ const bool use_job = RNA_boolean_get(op->ptr, "use_job");
+
+ if (use_job) {
+ /* when running through invoke, run as a job */
+ CacheLibraryBakeJob *data;
+ wmJob *wm_job;
+
+ /* XXX set WM_JOB_EXCL_RENDER to prevent conflicts with render jobs,
+ * since we need to set G.is_rendering
+ */
+ wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_data_scene(C), "Cache Library Bake",
+ WM_JOB_PROGRESS | WM_JOB_EXCL_RENDER, WM_JOB_TYPE_CACHELIBRARY_BAKE);
+
+ /* setup data */
+ data = MEM_callocN(sizeof(CacheLibraryBakeJob), "Cache Library Bake Job");
+ cache_library_bake_init(data, C, op);
+
+ WM_jobs_customdata_set(wm_job, data, cache_library_bake_freejob);
+ WM_jobs_timer(wm_job, 0.1, NC_SCENE|ND_FRAME, NC_SCENE|ND_FRAME);
+ WM_jobs_callbacks(wm_job, cache_library_bake_start, NULL, NULL, cache_library_bake_end);
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ WM_cursor_wait(0);
+
+ /* add modal handler for ESC */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ /* in direct execution mode we run this operator blocking instead of using a job */
+ CacheLibraryBakeJob data;
+ short stop = false, do_update = false;
+ float progress = 0.0f;
+
+ cache_library_bake_init(&data, C, op);
+
+ cache_library_bake_start(&data, &stop, &do_update, &progress);
+ cache_library_bake_end(&data);
+
+ return OPERATOR_FINISHED;
+ }
+}
+
+static int cache_library_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Object *ob = CTX_data_active_object(C);
+ CacheLibrary *cachelib = ob->cache_library;
+
+ char filename[FILE_MAX];
+
+ if (!cachelib)
+ return OPERATOR_CANCELLED;
+
+ /* make sure we run a job when exec is called after confirm popup */
+ RNA_boolean_set(op->ptr, "use_job", true);
+
+ BKE_cache_archive_output_path(cachelib, filename, sizeof(filename));
+
+ if (!BKE_cache_archive_path_test(cachelib, cachelib->output_filepath)) {
+ BKE_reportf(op->reports, RPT_ERROR, "Cannot create file path for cache library %200s", cachelib->id.name+2);
+ return OPERATOR_CANCELLED;
+ }
+
+ if (BLI_exists(filename)) {
+ if (BLI_is_dir(filename)) {
+ BKE_reportf(op->reports, RPT_ERROR, "Cache Library target is a directory: %200s", filename);
+ return OPERATOR_CANCELLED;
+ }
+ else if (BLI_is_file(filename)) {
+ if (BLI_file_is_writable(filename)) {
+ return WM_operator_confirm_message(C, op, "Overwrite?");
+ }
+ else {
+ BKE_reportf(op->reports, RPT_ERROR, "Cannot overwrite Cache Library target: %200s", filename);
+ return OPERATOR_CANCELLED;
+ }
+
+ }
+ else {
+ BKE_reportf(op->reports, RPT_ERROR, "Invalid Cache Library target: %200s", filename);
+ return OPERATOR_CANCELLED;
+ }
+ }
+ else {
+ return cache_library_bake_exec(C, op);
+ }
+}
+
+/* catch esc */
+static int cache_library_bake_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ /* no running job, remove handler and pass through */
+ if (!WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_CACHELIBRARY_BAKE))
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+
+ /* running bake */
+ switch (event->type) {
+ case ESCKEY:
+ return OPERATOR_RUNNING_MODAL;
+ }
+ return OPERATOR_PASS_THROUGH;
+}
+
+void CACHELIBRARY_OT_bake(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ static EnumPropertyItem eval_mode_items[] = {
+ {CACHELIBRARY_BAKE_PREVIEW, "PREVIEW", ICON_RESTRICT_VIEW_OFF, "Preview", "Evaluate data with preview settings"},
+ {CACHELIBRARY_BAKE_RENDER, "RENDER", ICON_RESTRICT_RENDER_OFF, "Render", "Evaluate data with render settings"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Bake";
+ ot->description = "Bake cache library";
+ ot->idname = "CACHELIBRARY_OT_bake";
+
+ /* api callbacks */
+ ot->invoke = cache_library_bake_invoke;
+ ot->exec = cache_library_bake_exec;
+ ot->modal = cache_library_bake_modal;
+ ot->poll = cache_library_bake_poll;
+
+ /* flags */
+ /* no undo for this operator, cannot restore old cache files anyway */
+ ot->flag = OPTYPE_REGISTER;
+
+ prop = RNA_def_boolean(ot->srna, "use_job", false, "Use Job", "Run operator as a job");
+ /* This is in internal property set by the invoke function.
+ * It allows the exec function to be called from both the confirm popup
+ * as well as a direct exec call for running a blocking operator in background mode.
+ */
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ prop = RNA_def_enum(ot->srna, "eval_mode", eval_mode_items, CACHELIBRARY_BAKE_RENDER, "Evaluation Mode", "Mode to use when evaluating data");
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+
+ RNA_def_int(ot->srna, "start_frame", 0, INT_MIN, INT_MAX, "Start Frame", "First frame to be cached", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "end_frame", 0, INT_MIN, INT_MAX, "End Frame", "Last frame to be cached", INT_MIN, INT_MAX);
+}
+
+/* ========================================================================= */
+
+static int cache_library_archive_slice_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ CacheLibrary *cachelib = ob->cache_library;
+ Scene *scene = CTX_data_scene(C);
+
+ const int start_frame = RNA_int_get(op->ptr, "start_frame");
+ const int end_frame = RNA_int_get(op->ptr, "end_frame");
+
+ char input_filepath[FILE_MAX], input_filename[FILE_MAX];
+ char output_filepath[FILE_MAX], output_filename[FILE_MAX];
+ struct PTCReaderArchive *input_archive;
+ struct PTCWriterArchive *output_archive;
+ PTCArchiveResolution archive_res;
+ CacheArchiveInfo info;
+ IDProperty *metadata;
+
+ RNA_string_get(op->ptr, "input_filepath", input_filepath);
+ if (input_filepath[0] == '\0')
+ return OPERATOR_CANCELLED;
+ RNA_string_get(op->ptr, "output_filepath", output_filepath);
+ if (output_filepath[0] == '\0')
+ return OPERATOR_CANCELLED;
+
+ BKE_cache_archive_path_ex(input_filepath, cachelib->id.lib, NULL, input_filename, sizeof(input_filename));
+ BKE_cache_archive_path_ex(output_filepath, cachelib->id.lib, NULL, output_filename, sizeof(output_filename));
+
+ /* make sure we can write */
+ cache_library_bake_ensure_file_target(output_filename);
+
+ input_archive = PTC_open_reader_archive(scene, input_filename);
+ if (!input_archive) {
+ BKE_reportf(op->reports, RPT_ERROR, "Cannot open cache file at '%s'", input_filepath);
+ return OPERATOR_CANCELLED;
+ }
+
+ archive_res = PTC_reader_archive_get_resolutions(input_archive);
+ {
+ IDPropertyTemplate val;
+ val.i = 0;
+ metadata = IDP_New(IDP_GROUP, &val, "cache input metadata");
+ }
+ PTC_get_archive_info(input_archive, &info, metadata);
+
+ output_archive = PTC_open_writer_archive(FPS, start_frame, output_filename, archive_res, info.app_name, info.description, NULL, metadata);
+
+ IDP_FreeProperty(metadata);
+ MEM_freeN(metadata);
+
+ if (!output_archive) {
+ BKE_reportf(op->reports, RPT_ERROR, "Cannot write to cache file at '%s'", output_filepath);
+ return OPERATOR_CANCELLED;
+ }
+
+ PTC_archive_slice(input_archive, output_archive, start_frame, end_frame);
+
+ PTC_close_reader_archive(input_archive);
+ PTC_close_writer_archive(output_archive);
+
+ return OPERATOR_FINISHED;
+}
+
+static int cache_library_archive_slice_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ return WM_operator_props_popup_confirm(C, op, event);
+
+#if 0
+ Object *ob = CTX_data_active_object(C);
+ CacheLibrary *cachelib = ob->cache_library;
+
+ char output_filename[FILE_MAX];
+
+ if (!cachelib)
+ return OPERATOR_CANCELLED;
+
+ /* make sure we run a job when exec is called after confirm popup */
+ RNA_boolean_set(op->ptr, "use_job", true);
+
+ RNA_string_get(op->ptr, "output_filepath", output_filepath);
+ if (output_filepath[0] == '\0')
+ return OPERATOR_CANCELLED;
+ BKE_cache_archive_output_path(cachelib, output_filename, sizeof(output_filename));
+
+ if (!BKE_cache_archive_path_test(cachelib, output_filepath)) {
+ BKE_reportf(op->reports, RPT_ERROR, "Cannot create file path for cache library %200s", cachelib->id.name+2);
+ return OPERATOR_CANCELLED;
+ }
+
+ if (BLI_exists(output_filename)) {
+ if (BLI_is_dir(output_filename)) {
+ BKE_reportf(op->reports, RPT_ERROR, "Cache Library target is a directory: %200s", output_filename);
+ return OPERATOR_CANCELLED;
+ }
+ else if (BLI_is_file(output_filename)) {
+ if (BLI_file_is_writable(output_filename)) {
+ return WM_operator_confirm_message(C, op, "Overwrite?");
+ }
+ else {
+ BKE_reportf(op->reports, RPT_ERROR, "Cannot overwrite Cache Library target: %200s", output_filename);
+ return OPERATOR_CANCELLED;
+ }
+
+ }
+ else {
+ BKE_reportf(op->reports, RPT_ERROR, "Invalid Cache Library target: %200s", output_filename);
+ return OPERATOR_CANCELLED;
+ }
+ }
+ else {
+ return cache_library_bake_exec(C, op);
+ }
+#endif
+}
+
+void CACHELIBRARY_OT_archive_slice(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Archive Slice";
+ ot->description = "Copy a range of frames to a new cache archive";
+ ot->idname = "CACHELIBRARY_OT_archive_slice";
+
+ /* api callbacks */
+ ot->exec = cache_library_archive_slice_exec;
+ ot->invoke = cache_library_archive_slice_invoke;
+ ot->poll = ED_cache_library_active_object_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ prop = RNA_def_boolean(ot->srna, "use_job", false, "Use Job", "Run operator as a job");
+ /* This is in internal property set by the invoke function.
+ * It allows the exec function to be called from both the confirm popup
+ * as well as a direct exec call for running a blocking operator in background mode.
+ */
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ prop = RNA_def_string(ot->srna, "input_filepath", NULL, FILE_MAX, "Input File Path", "Path to the source cache archive");
+ RNA_def_property_subtype(prop, PROP_FILEPATH);
+ prop = RNA_def_string(ot->srna, "output_filepath", NULL, FILE_MAX, "Output File Path", "Path to the target cache archive");
+ RNA_def_property_subtype(prop, PROP_FILEPATH);
+ RNA_def_int(ot->srna, "start_frame", 1, INT_MIN, INT_MAX, "Start Frame", "First frame to copy", 1, 10000);
+ RNA_def_int(ot->srna, "end_frame", 250, INT_MIN, INT_MAX, "End Frame", "Last frame to copy", 1, 10000);
+}
+
+/* ========================================================================= */
+
+#if 0
+static void ui_item_nlabel(uiLayout *layout, const char *s, size_t len)
+{
+ char buf[256];
+
+ BLI_strncpy(buf, s, sizeof(buf)-1);
+ buf[min_ii(len, sizeof(buf)-1)] = '\0';
+
+ uiItemL(layout, buf, ICON_NONE);
+}
+
+static void archive_info_labels(uiLayout *layout, const char *info)
+{
+ const char delim[] = {'\n', '\0'};
+ const char *cur = info;
+ size_t linelen;
+ char *sep, *suf;
+
+ linelen = BLI_str_partition(cur, delim, &sep, &suf);
+ while (sep) {
+ ui_item_nlabel(layout, cur, linelen);
+ cur = suf;
+
+ linelen = BLI_str_partition(cur, delim, &sep, &suf);
+ }
+ ui_item_nlabel(layout, cur, linelen);
+}
+
+static uiBlock *archive_info_popup_create(bContext *C, ARegion *ar, void *arg)
+{
+ const char *info = arg;
+ uiBlock *block;
+ uiLayout *layout;
+
+ block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
+ UI_block_flag_disable(block, UI_BLOCK_LOOP);
+ UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_MOVEMOUSE_QUIT);
+
+ layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, UI_UNIT_X * 20, UI_UNIT_Y, 0, UI_style_get());
+
+ archive_info_labels(layout, info);
+
+ UI_block_bounds_set_centered(block, 0);
+ UI_block_direction_set(block, UI_DIR_DOWN);
+
+ return block;
+}
+#endif
+
+static void print_stream(void *UNUSED(userdata), const char *s)
+{
+ printf("%s", s);
+}
+
+static int cache_library_archive_info_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ CacheLibrary *cachelib = ob->cache_library;
+ Scene *scene = CTX_data_scene(C);
+
+ const bool use_cache_info = RNA_boolean_get(op->ptr, "use_cache_info");
+ const bool calc_bytes_size = RNA_boolean_get(op->ptr, "calc_bytes_size");
+ const bool use_stdout = RNA_boolean_get(op->ptr, "use_stdout");
+ const bool use_popup = RNA_boolean_get(op->ptr, "use_popup");
+ const bool use_clipboard = RNA_boolean_get(op->ptr, "use_clipboard");
+
+ char filepath[FILE_MAX], filename[FILE_MAX];
+ struct PTCReaderArchive *archive;
+
+ RNA_string_get(op->ptr, "filepath", filepath);
+ if (filepath[0] == '\0')
+ return OPERATOR_CANCELLED;
+
+ BKE_cache_archive_path_ex(filepath, cachelib->id.lib, NULL, filename, sizeof(filename));
+ archive = PTC_open_reader_archive(scene, filename);
+ if (!archive) {
+ BKE_reportf(op->reports, RPT_ERROR, "Cannot open cache file at '%s'", filepath);
+ return OPERATOR_CANCELLED;
+ }
+
+ if (use_cache_info) {
+ if (cachelib->archive_info)
+ BKE_cache_archive_info_clear(cachelib->archive_info);
+ else
+ cachelib->archive_info = BKE_cache_archive_info_new();
+
+ BLI_strncpy(cachelib->archive_info->filepath, filename, sizeof(cachelib->archive_info->filepath));
+
+ PTC_get_archive_info_nodes(archive, cachelib->archive_info, calc_bytes_size);
+ }
+
+ if (use_stdout) {
+ PTC_get_archive_info_stream(archive, print_stream, NULL);
+ }
+
+ if (use_popup) {
+// UI_popup_block_invoke(C, archive_info_popup_create, info);
+ }
+
+ if (use_clipboard) {
+// WM_clipboard_text_set(info, false);
+ }
+
+ PTC_close_reader_archive(archive);
+
+ return OPERATOR_FINISHED;
+}
+
+void CACHELIBRARY_OT_archive_info(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Archive Info";
+ ot->description = "Get archive details from a cache library archive";
+ ot->idname = "CACHELIBRARY_OT_archive_info";
+
+ /* api callbacks */
+ ot->exec = cache_library_archive_info_exec;
+ ot->poll = ED_cache_library_active_object_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_string(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Path to the cache archive");
+ RNA_def_boolean(ot->srna, "use_cache_info", false, "Use Cache Library Info", "Store info in the cache library");
+ RNA_def_boolean(ot->srna, "calc_bytes_size", false, "Calculate Size", "Calculate overall size of nodes in bytes (can take a while)");
+ RNA_def_boolean(ot->srna, "use_stdout", false, "Use stdout", "Print info in standard output");
+ RNA_def_boolean(ot->srna, "use_popup", false, "Show Popup", "Display archive info in a popup");
+ RNA_def_boolean(ot->srna, "use_clipboard", false, "Copy to Clipboard", "Copy archive info to the clipboard");
+}
+
+/* ------------------------------------------------------------------------- */
+/* Cache Modifiers */
+
+static int cache_library_add_modifier_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ CacheLibrary *cachelib = ob->cache_library;
+
+ eCacheModifier_Type type = RNA_enum_get(op->ptr, "type");
+ if (type == eCacheModifierType_None) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_cache_modifier_add(cachelib, NULL, type);
+
+ return OPERATOR_FINISHED;
+}
+
+void CACHELIBRARY_OT_add_modifier(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Cache Modifier";
+ ot->description = "Add a cache modifier";
+ ot->idname = "CACHELIBRARY_OT_add_modifier";
+
+ /* api callbacks */
+ ot->exec = cache_library_add_modifier_exec;
+ ot->poll = ED_cache_library_active_object_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "type", cache_modifier_type_items, eCacheModifierType_None, "Type", "Type of modifier to add");
+}
+
+static int cache_library_remove_modifier_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ PointerRNA md_ptr = CTX_data_pointer_get_type(C, "cache_modifier", &RNA_CacheLibraryModifier);
+ CacheModifier *md = md_ptr.data;
+ CacheLibrary *cachelib = md_ptr.id.data;
+
+ if (!md)
+ return OPERATOR_CANCELLED;
+
+ BKE_cache_modifier_remove(cachelib, md);
+
+ return OPERATOR_FINISHED;
+}
+
+void CACHELIBRARY_OT_remove_modifier(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Cache Modifier";
+ ot->description = "Remove a cache modifier";
+ ot->idname = "CACHELIBRARY_OT_remove_modifier";
+
+ /* api callbacks */
+ ot->exec = cache_library_remove_modifier_exec;
+ ot->poll = ED_cache_modifier_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/io/io_cache_library.h b/source/blender/editors/io/io_cache_library.h
new file mode 100644
index 00000000000..78959e6900c
--- /dev/null
+++ b/source/blender/editors/io/io_cache_library.h
@@ -0,0 +1,56 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/io/io_cache_library.h
+ * \ingroup editor/io
+ */
+
+#ifndef __IO_CACHE_LIBRARY_H__
+#define __IO_CACHE_LIBRARY_H__
+
+struct wmOperatorType;
+
+void CACHELIBRARY_OT_new(struct wmOperatorType *ot);
+void CACHELIBRARY_OT_delete(struct wmOperatorType *ot);
+
+void CACHELIBRARY_OT_bake(struct wmOperatorType *ot);
+
+void CACHELIBRARY_OT_archive_info(struct wmOperatorType *ot);
+void CACHELIBRARY_OT_archive_slice(struct wmOperatorType *ot);
+
+/* ------------------------------------------------------------------------- */
+/* Cache Modifiers */
+
+void CACHELIBRARY_OT_add_modifier(struct wmOperatorType *ot);
+void CACHELIBRARY_OT_remove_modifier(struct wmOperatorType *ot);
+
+/* cache_shapekey.c */
+void CACHELIBRARY_OT_shape_key_add(struct wmOperatorType *ot);
+void CACHELIBRARY_OT_shape_key_remove(struct wmOperatorType *ot);
+void CACHELIBRARY_OT_shape_key_clear(struct wmOperatorType *ot);
+void CACHELIBRARY_OT_shape_key_retime(struct wmOperatorType *ot);
+void CACHELIBRARY_OT_shape_key_move(struct wmOperatorType *ot);
+
+#endif
diff --git a/source/blender/editors/io/io_cache_shapekey.c b/source/blender/editors/io/io_cache_shapekey.c
new file mode 100644
index 00000000000..e28a16b8e55
--- /dev/null
+++ b/source/blender/editors/io/io_cache_shapekey.c
@@ -0,0 +1,417 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/io/io_cache_shapekey.c
+ * \ingroup editor/io
+ */
+
+
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_cache_library_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_strands_types.h"
+
+#include "BKE_cache_library.h"
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "io_cache_library.h"
+
+/*********************** add shape key ***********************/
+
+static void ED_cache_shape_key_add(bContext *C, StrandsKeyCacheModifier *skmd, Strands *strands, const bool from_mix)
+{
+ KeyBlock *kb;
+ if ((kb = BKE_cache_modifier_strands_key_insert_key(skmd, strands, NULL, from_mix))) {
+ Key *key = skmd->key;
+ /* for absolute shape keys, new keys may not be added last */
+ skmd->shapenr = BLI_findindex(&key->block, kb) + 1;
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ }
+}
+
+/*********************** remove shape key ***********************/
+
+static void keyblock_free(StrandsKeyCacheModifier *skmd, KeyBlock *kb)
+{
+ Key *key = skmd->key;
+
+ BLI_remlink(&key->block, kb);
+ key->totkey--;
+
+ if (kb->data) MEM_freeN(kb->data);
+ MEM_freeN(kb);
+}
+
+static bool ED_cache_shape_key_remove_all(StrandsKeyCacheModifier *skmd, Strands *UNUSED(strands))
+{
+ Key *key = skmd->key;
+ KeyBlock *kb, *kb_next;
+
+ if (key == NULL)
+ return false;
+
+ for (kb = key->block.first; kb; kb = kb_next) {
+ kb_next = kb->next;
+
+ keyblock_free(skmd, kb);
+ }
+
+ key->refkey = NULL;
+ skmd->shapenr = 0;
+
+ return true;
+}
+
+static bool ED_cache_shape_key_remove(StrandsKeyCacheModifier *skmd, Strands *strands)
+{
+ Key *key = skmd->key;
+ KeyBlock *kb, *rkb;
+
+ if (key == NULL)
+ return false;
+
+ kb = BLI_findlink(&key->block, skmd->shapenr - 1);
+ if (kb) {
+ for (rkb = key->block.first; rkb; rkb = rkb->next) {
+ if (rkb->relative == skmd->shapenr - 1) {
+ /* remap to the 'Basis' */
+ rkb->relative = 0;
+ }
+ else if (rkb->relative >= skmd->shapenr) {
+ /* Fix positional shift of the keys when kb is deleted from the list */
+ rkb->relative -= 1;
+ }
+ }
+
+ keyblock_free(skmd, kb);
+
+ if (key->refkey == kb) {
+ key->refkey = key->block.first;
+
+ if (key->refkey) {
+ /* apply new basis key on original data */
+ BKE_keyblock_convert_to_strands(key->refkey, strands, skmd->flag & eStrandsKeyCacheModifier_Flag_UseMotionState);
+ }
+ }
+
+ if (skmd->shapenr > 1) {
+ skmd->shapenr--;
+ }
+ }
+
+ return true;
+}
+
+/********************** shape key operators *********************/
+
+static bool shape_key_get_context(bContext *C, CacheLibrary **r_cachelib, StrandsKeyCacheModifier **r_skmd, Strands **r_strands)
+{
+ CacheLibrary *cachelib = CTX_data_pointer_get_type(C, "cache_library", &RNA_CacheLibrary).data;
+ CacheModifier *md = CTX_data_pointer_get_type(C, "cache_modifier", &RNA_CacheLibraryModifier).data;
+ StrandsKeyCacheModifier *skmd;
+ Object *ob = CTX_data_active_object(C);
+ Strands *strands;
+
+ if (!(cachelib && !cachelib->id.lib && md && md->type == eCacheModifierType_StrandsKey))
+ return false;
+ skmd = (StrandsKeyCacheModifier *)md;
+
+ if (!(ob && ob->dup_cache && (ob->transflag & OB_DUPLIGROUP) && ob->dup_group))
+ return false;
+ if (!BKE_cache_modifier_find_strands(ob->dup_cache, skmd->object, skmd->hair_system, NULL, &strands, NULL, NULL))
+ return false;
+
+ if (r_cachelib) *r_cachelib = cachelib;
+ if (r_skmd) *r_skmd = skmd;
+ if (r_strands) *r_strands = strands;
+ return true;
+}
+
+static int shape_key_poll(bContext *C)
+{
+ return shape_key_get_context(C, NULL, NULL, NULL);
+}
+
+static int shape_key_exists_poll(bContext *C)
+{
+ StrandsKeyCacheModifier *skmd;
+
+ if (!shape_key_get_context(C, NULL, &skmd, NULL))
+ return false;
+
+ return (skmd->key && skmd->shapenr >= 0 && skmd->shapenr < skmd->key->totkey);
+}
+
+static int shape_key_move_poll(bContext *C)
+{
+ StrandsKeyCacheModifier *skmd;
+
+ if (!shape_key_get_context(C, NULL, &skmd, NULL))
+ return false;
+
+ return (skmd->key != NULL && skmd->key->totkey > 1);
+}
+
+static int shape_key_add_exec(bContext *C, wmOperator *op)
+{
+ const bool from_mix = RNA_boolean_get(op->ptr, "from_mix");
+ CacheLibrary *cachelib;
+ StrandsKeyCacheModifier *skmd;
+ Strands *strands;
+
+ shape_key_get_context(C, &cachelib, &skmd, &strands);
+
+ ED_cache_shape_key_add(C, skmd, strands, from_mix);
+
+ DAG_id_tag_update(&cachelib->id, OB_RECALC_DATA);
+
+ return OPERATOR_FINISHED;
+}
+
+void CACHELIBRARY_OT_shape_key_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Shape Key";
+ ot->idname = "CACHELIBRARY_OT_shape_key_add";
+ ot->description = "Add shape key to the object";
+
+ /* api callbacks */
+ ot->poll = shape_key_poll;
+ ot->exec = shape_key_add_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "from_mix", true, "From Mix", "Create the new shape key from the existing mix of keys");
+}
+
+static int shape_key_remove_exec(bContext *C, wmOperator *op)
+{
+ CacheLibrary *cachelib;
+ StrandsKeyCacheModifier *skmd;
+ Strands *strands;
+ bool changed = false;
+
+ shape_key_get_context(C, &cachelib, &skmd, &strands);
+
+ if (RNA_boolean_get(op->ptr, "all")) {
+ changed = ED_cache_shape_key_remove_all(skmd, strands);
+ }
+ else {
+ changed = ED_cache_shape_key_remove(skmd, strands);
+ }
+
+ if (changed) {
+ DAG_id_tag_update(&cachelib->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void CACHELIBRARY_OT_shape_key_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Shape Key";
+ ot->idname = "CACHELIBRARY_OT_shape_key_remove";
+ ot->description = "Remove shape key from the object";
+
+ /* api callbacks */
+ ot->poll = shape_key_exists_poll;
+ ot->exec = shape_key_remove_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "all", 0, "All", "Remove all shape keys");
+}
+
+static int shape_key_clear_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ CacheLibrary *cachelib;
+ StrandsKeyCacheModifier *skmd;
+ Strands *strands;
+ KeyBlock *kb;
+
+ shape_key_get_context(C, &cachelib, &skmd, &strands);
+
+ for (kb = skmd->key->block.first; kb; kb = kb->next)
+ kb->curval = 0.0f;
+
+ DAG_id_tag_update(&cachelib->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void CACHELIBRARY_OT_shape_key_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Shape Keys";
+ ot->description = "Clear weights for all shape keys";
+ ot->idname = "CACHELIBRARY_OT_shape_key_clear";
+
+ /* api callbacks */
+ ot->poll = shape_key_poll;
+ ot->exec = shape_key_clear_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* starting point and step size could be optional */
+static int shape_key_retime_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ CacheLibrary *cachelib;
+ StrandsKeyCacheModifier *skmd;
+ Strands *strands;
+ KeyBlock *kb;
+ float cfra = 0.0f;
+
+ shape_key_get_context(C, &cachelib, &skmd, &strands);
+
+ for (kb = skmd->key->block.first; kb; kb = kb->next)
+ kb->pos = (cfra += 0.1f);
+
+ DAG_id_tag_update(&cachelib->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void CACHELIBRARY_OT_shape_key_retime(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Re-Time Shape Keys";
+ ot->description = "Resets the timing for absolute shape keys";
+ ot->idname = "CACHELIBRARY_OT_shape_key_retime";
+
+ /* api callbacks */
+ ot->poll = shape_key_poll;
+ ot->exec = shape_key_retime_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+enum {
+ KB_MOVE_TOP = -2,
+ KB_MOVE_UP = -1,
+ KB_MOVE_DOWN = 1,
+ KB_MOVE_BOTTOM = 2,
+};
+
+static int shape_key_move_exec(bContext *C, wmOperator *op)
+{
+ const int type = RNA_enum_get(op->ptr, "type");
+ CacheLibrary *cachelib;
+ StrandsKeyCacheModifier *skmd;
+ Strands *strands;
+ Key *key;
+ int totkey, act_index, new_index;
+
+ shape_key_get_context(C, &cachelib, &skmd, &strands);
+ key = skmd->key;
+ totkey = key->totkey;
+ act_index = skmd->shapenr - 1;
+
+ switch (type) {
+ case KB_MOVE_TOP:
+ /* Replace the ref key only if we're at the top already (only for relative keys) */
+ new_index = (ELEM(act_index, 0, 1) || key->type == KEY_NORMAL) ? 0 : 1;
+ break;
+ case KB_MOVE_BOTTOM:
+ new_index = totkey - 1;
+ break;
+ case KB_MOVE_UP:
+ case KB_MOVE_DOWN:
+ default:
+ new_index = (totkey + act_index + type) % totkey;
+ break;
+ }
+
+ if (!BKE_keyblock_move_ex(key, &skmd->shapenr, act_index, new_index)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ DAG_id_tag_update(&cachelib->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void CACHELIBRARY_OT_shape_key_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem slot_move[] = {
+ {KB_MOVE_TOP, "TOP", 0, "Top", "Top of the list"},
+ {KB_MOVE_UP, "UP", 0, "Up", ""},
+ {KB_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {KB_MOVE_BOTTOM, "BOTTOM", 0, "Bottom", "Bottom of the list"},
+ { 0, NULL, 0, NULL, NULL }
+ };
+
+ /* identifiers */
+ ot->name = "Move Shape Key";
+ ot->idname = "CACHELIBRARY_OT_shape_key_move";
+ ot->description = "Move the active shape key up/down in the list";
+
+ /* api callbacks */
+ ot->poll = shape_key_move_poll;
+ ot->exec = shape_key_move_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
+}
+
diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c
index a70a51a60be..49b1553ee78 100644
--- a/source/blender/editors/io/io_ops.c
+++ b/source/blender/editors/io/io_ops.c
@@ -30,13 +30,30 @@
#include "io_ops.h" /* own include */
+#include "io_cache_library.h"
#ifdef WITH_COLLADA
# include "io_collada.h"
-# include "WM_api.h"
#endif
+#include "WM_api.h"
+
void ED_operatortypes_io(void)
{
+ WM_operatortype_append(CACHELIBRARY_OT_new);
+ WM_operatortype_append(CACHELIBRARY_OT_delete);
+ WM_operatortype_append(CACHELIBRARY_OT_bake);
+ WM_operatortype_append(CACHELIBRARY_OT_archive_info);
+ WM_operatortype_append(CACHELIBRARY_OT_archive_slice);
+
+ WM_operatortype_append(CACHELIBRARY_OT_add_modifier);
+ WM_operatortype_append(CACHELIBRARY_OT_remove_modifier);
+
+ WM_operatortype_append(CACHELIBRARY_OT_shape_key_add);
+ WM_operatortype_append(CACHELIBRARY_OT_shape_key_remove);
+ WM_operatortype_append(CACHELIBRARY_OT_shape_key_clear);
+ WM_operatortype_append(CACHELIBRARY_OT_shape_key_retime);
+ WM_operatortype_append(CACHELIBRARY_OT_shape_key_move);
+
#ifdef WITH_COLLADA
/* Collada operators: */
WM_operatortype_append(WM_OT_collada_export);
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index cb47adbe73e..2dae9561d4e 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -72,7 +72,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
MaskLayer *masklay, *point_masklay;
MaskSpline *point_spline;
MaskSplinePoint *point = NULL;
- float dist = FLT_MAX, co[2];
+ float dist_best_sq = FLT_MAX, co[2];
int width, height;
float u;
float scalex, scaley;
@@ -123,7 +123,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
}
for (j = 0; j < tot_point - 1; j++) {
- float cur_dist, a[2], b[2];
+ float dist_sq, a[2], b[2];
a[0] = points[2 * j] * scalex;
a[1] = points[2 * j + 1] * scaley;
@@ -131,16 +131,16 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
b[0] = points[2 * j + 2] * scalex;
b[1] = points[2 * j + 3] * scaley;
- cur_dist = dist_to_line_segment_v2(co, a, b);
+ dist_sq = dist_squared_to_line_segment_v2(co, a, b);
- if (cur_dist < dist) {
+ if (dist_sq < dist_best_sq) {
if (tangent)
sub_v2_v2v2(tangent, &diff_points[2 * j + 2], &diff_points[2 * j]);
point_masklay = masklay;
point_spline = spline;
point = use_deform ? &spline->points[(cur_point - spline->points_deform)] : cur_point;
- dist = cur_dist;
+ dist_best_sq = dist_sq;
u = (float)j / tot_point;
}
}
@@ -154,7 +154,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
}
}
- if (point && dist < threshold) {
+ if (point && dist_best_sq < threshold) {
if (masklay_r)
*masklay_r = point_masklay;
@@ -174,7 +174,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
}
if (score_r) {
- *score_r = dist;
+ *score_r = dist_best_sq;
}
return true;
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 7e767d8f6c8..2efa9e211c9 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -253,7 +253,7 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
return;
if (sc)
- undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0;
+ undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT);
/* TODO, add this to sequence editor */
handle_size = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize;
@@ -422,7 +422,7 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*
float (*points)[2] = orig_points;
if (sc) {
- int undistort = sc->clip && sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
+ const bool undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT);
if (undistort) {
int i;
diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h
index 5cdb224ce21..66a6c75272e 100644
--- a/source/blender/editors/mask/mask_intern.h
+++ b/source/blender/editors/mask/mask_intern.h
@@ -34,7 +34,6 @@
struct bContext;
struct Mask;
-struct wmEvent;
struct wmOperatorType;
/* internal exports only */
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 113f0f71b53..35fc4483702 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -446,7 +446,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten
}
}
- view3d_validate_backbuf(vc);
+ ED_view3d_backbuf_validate(vc);
ibuf = IMB_allocImBuf(sx, sy, 32, IB_rect);
rt = ibuf->rect;
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index 6ce5e8a304b..c67ee41703a 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -62,10 +62,7 @@ static Object *make_prim_init(bContext *C, const char *idname,
*was_editmode = false;
if (obedit == NULL || obedit->type != OB_MESH) {
- obedit = ED_object_add_type(C, OB_MESH, loc, rot, false, layer);
-
- rename_id((ID *)obedit, idname);
- rename_id((ID *)obedit->data, idname);
+ obedit = ED_object_add_type(C, OB_MESH, idname, loc, rot, false, layer);
/* create editmode */
ED_object_editmode_enter(C, EM_DO_UNDO | EM_IGNORE_LAYER); /* rare cases the active layer is messed up */
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 0e48cbcd589..1e44d7e654d 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -477,7 +477,7 @@ void MESH_OT_bevel(wmOperatorType *ot)
ot->poll = ED_operator_editmesh;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
RNA_def_enum(ot->srna, "offset_type", offset_type_items, 0, "Amount Type", "What distance Amount measures");
prop = RNA_def_float(ot->srna, "offset", 0.0f, -FLT_MAX, FLT_MAX, "Amount", "", 0.0f, 1.0f);
diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c
index 6a54f1979cf..b9cbc8043ae 100644
--- a/source/blender/editors/mesh/editmesh_bisect.c
+++ b/source/blender/editors/mesh/editmesh_bisect.c
@@ -264,7 +264,7 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op)
invert_m4_m4(imat, obedit->obmat);
mul_m4_v3(imat, plane_co);
- mul_mat3_m4_v3(imat, plane_no);
+ mul_transposed_mat3_m4_v3(obedit->obmat, plane_no);
EDBM_op_init(em, &bmop, op,
"bisect_plane geom=%hvef plane_co=%v plane_no=%v dist=%f clear_inner=%b clear_outer=%b",
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 9b1b0b915c1..e8f9a76a873 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -510,7 +510,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
float min[3], max[3];
bool done = false;
bool use_proj;
-
+
em_setup_viewcontext(C, &vc);
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
@@ -574,8 +574,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */
/* correct the normal to be aligned on the view plane */
- copy_v3_v3(view_vec, vc.rv3d->viewinv[2]);
- mul_mat3_m4_v3(vc.obedit->imat, view_vec);
+ mul_v3_mat3_m4v3(view_vec, vc.obedit->imat, vc.rv3d->viewinv[2]);
cross_v3_v3v3(cross, nor, view_vec);
cross_v3_v3v3(nor, view_vec, cross);
normalize_v3(nor);
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index f1c3ca30610..80d3777d057 100644
--- a/source/blender/editors/mesh/editmesh_inset.c
+++ b/source/blender/editors/mesh/editmesh_inset.c
@@ -499,7 +499,7 @@ void MESH_OT_inset(wmOperatorType *ot)
ot->poll = ED_operator_editmesh;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
/* properties */
RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries");
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index f3745ed72fb..cfd0d3fdcf5 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -1319,18 +1319,63 @@ static BMElem *bm_elem_from_knife_edge(KnifeEdge *kfe)
return ele_test;
}
+/* Do edges e1 and e2 go between exactly the same coordinates? */
+static bool coinciding_edges(BMEdge *e1, BMEdge *e2)
+{
+ const float *co11, *co12, *co21, *co22;
+
+ co11 = e1->v1->co;
+ co12 = e1->v2->co;
+ co21 = e2->v1->co;
+ co22 = e2->v2->co;
+ if ((equals_v3v3(co11, co21) && equals_v3v3(co12, co22)) ||
+ (equals_v3v3(co11, co22) && equals_v3v3(co12, co21)))
+ {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/* Callback used in point_is_visible to exclude hits on the faces that are the same
+ * as or contain the hitting element (which is in user_data).
+ * Also (see T44492) want to exclude hits on faces that butt up to the hitting element
+ * (e.g., when you double an edge by an edge split).
+ */
static bool bm_ray_cast_cb_elem_not_in_face_check(BMFace *f, void *user_data)
{
+ bool ans;
+ BMEdge *e, *e2;
+ BMIter iter;
+
switch (((BMElem *)user_data)->head.htype) {
case BM_FACE:
- return (BMFace *)user_data != f;
+ ans = (BMFace *)user_data != f;
+ break;
case BM_EDGE:
- return !BM_edge_in_face((BMEdge *)user_data, f);
+ e = (BMEdge *)user_data;
+ ans = !BM_edge_in_face(e, f);
+ if (ans) {
+ /* Is it a boundary edge, coincident with a split edge? */
+ if (BM_edge_is_boundary(e)) {
+ BM_ITER_ELEM(e2, &iter, f, BM_EDGES_OF_FACE) {
+ if (coinciding_edges(e, e2)) {
+ ans = false;
+ break;
+ }
+ }
+ }
+ }
+ break;
case BM_VERT:
- return !BM_vert_in_face((BMVert *)user_data, f);
+ ans = !BM_vert_in_face((BMVert *)user_data, f);
+ break;
default:
- return true;
+ ans = true;
+ break;
}
+ return ans;
}
@@ -2831,8 +2876,7 @@ static void knife_recalc_projmat(KnifeTool_OpData *kcd)
ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, kcd->projmat);
invert_m4_m4(kcd->projmat_inv, kcd->projmat);
- copy_v3_v3(kcd->proj_zaxis, kcd->vc.rv3d->viewinv[2]);
- mul_mat3_m4_v3(kcd->ob->imat, kcd->proj_zaxis);
+ mul_v3_mat3_m4v3(kcd->proj_zaxis, kcd->ob->imat, kcd->vc.rv3d->viewinv[2]);
normalize_v3(kcd->proj_zaxis);
kcd->is_ortho = ED_view3d_clip_range_get(kcd->vc.v3d, kcd->vc.rv3d,
@@ -3006,6 +3050,8 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
knifetool_init(C, kcd, only_select, cut_through, true);
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+
/* add a modal handler for this operator - handles loop selection */
WM_cursor_modal_set(CTX_wm_window(C), BC_KNIFECURSOR);
WM_event_add_modal_handler(C, op);
@@ -3098,6 +3144,9 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_FINISHED;
}
+ em_setup_viewcontext(C, &kcd->vc);
+ kcd->ar = kcd->vc.ar;
+
view3d_operator_needs_opengl(C);
ED_view3d_init_mats_rv3d(obedit, kcd->vc.rv3d); /* needed to initialize clipping */
@@ -3257,6 +3306,13 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
+ if (kcd->mode == MODE_DRAGGING) {
+ op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
+ }
+ else {
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ }
+
if (do_refresh) {
/* we don't really need to update mval,
* but this happens to be the best way to refresh at the moment */
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index 553c1faa36a..0d3cc07589b 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -166,7 +166,7 @@ void MESH_OT_knife_project(wmOperatorType *ot)
/* callbacks */
ot->exec = knifeproject_exec;
- ot->poll = ED_operator_editmesh_view3d;
+ ot->poll = ED_operator_editmesh_region_view3d;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 3d93210382c..c7f9522ab3f 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -553,6 +553,7 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event)
/* add a modal handler for this operator - handles loop selection */
if (is_interactive) {
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
WM_event_add_modal_handler(C, op);
}
@@ -639,6 +640,9 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool show_cuts = false;
const bool has_numinput = hasNumInput(&lcd->num);
+ em_setup_viewcontext(C, &lcd->vc);
+ lcd->ar = lcd->vc.ar;
+
view3d_operator_needs_opengl(C);
/* using the keyboard to input the number of cuts */
@@ -835,7 +839,7 @@ void MESH_OT_loopcut(wmOperatorType *ot)
prop = RNA_def_property(ot->srna, "falloff", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, proportional_falloff_curve_only_items);
- RNA_def_property_enum_default(prop, PROP_ROOT);
+ RNA_def_property_enum_default(prop, PROP_INVSQUARE);
RNA_def_property_ui_text(prop, "Falloff", "Falloff type the feather");
RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 4eaac6cc1d3..72dfb89e5f3 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -94,7 +94,7 @@ static bool mouse_mesh_shortest_path_vert(ViewContext *vc)
float dist = ED_view3d_select_dist_px();
const bool use_length = true;
- v_dst = EDBM_vert_find_nearest(vc, &dist, false, false);
+ v_dst = EDBM_vert_find_nearest(vc, &dist);
if (v_dst) {
struct UserData user_data = {bm, vc->obedit->data, vc->scene};
LinkNode *path = NULL;
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index ead243d6de8..c7a7828f3b2 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -63,9 +63,10 @@
* point and would result in the same distance.
*/
#define INSET_DEFAULT 0.00001f
-static float edbm_rip_edgedist_squared(ARegion *ar, float mat[4][4],
- const float co1[3], const float co2[3], const float mvalf[2],
- const float inset)
+static float edbm_rip_edgedist_squared(
+ ARegion *ar, float mat[4][4],
+ const float co1[3], const float co2[3], const float mvalf[2],
+ const float inset)
{
float vec1[2], vec2[2], dist_sq;
@@ -89,8 +90,9 @@ static float edbm_rip_edgedist_squared(ARegion *ar, float mat[4][4],
}
#if 0
-static float edbm_rip_linedist(ARegion *ar, float mat[4][4],
- const float co1[3], const float co2[3], const float mvalf[2])
+static float edbm_rip_linedist(
+ ARegion *ar, float mat[4][4],
+ const float co1[3], const float co2[3], const float mvalf[2])
{
float vec1[2], vec2[2];
@@ -114,9 +116,10 @@ static void edbm_calc_loop_co(BMLoop *l, float l_mid_co[3])
}
-static float edbm_rip_edge_side_measure(BMEdge *e, BMLoop *e_l,
- ARegion *ar,
- float projectMat[4][4], const float fmval[2])
+static float edbm_rip_edge_side_measure(
+ BMEdge *e, BMLoop *e_l,
+ ARegion *ar,
+ float projectMat[4][4], const float fmval[2])
{
float cent[3] = {0, 0, 0}, mid[3];
@@ -532,14 +535,14 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
BMesh *bm = em->bm;
BMIter iter, liter;
BMLoop *l;
- BMEdge *e, *e2;
+ BMEdge *e_best;
BMVert *v;
const int totvert_orig = bm->totvert;
int i;
float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
float dist_sq = FLT_MAX;
float d;
- bool is_wire;
+ bool is_wire, is_manifold_region;
BMEditSelection ese;
int totboundary_edge = 0;
@@ -559,65 +562,91 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
}
}
- /* this should be impossible, but sanity checks are a good thing */
- if (!v)
+ /* (v == NULL) should be impossible */
+ if ((v == NULL) || (v->e == NULL)) {
return OPERATOR_CANCELLED;
+ }
is_wire = BM_vert_is_wire(v);
+ is_manifold_region = BM_vert_is_manifold_region(v);
- e2 = NULL;
+ e_best = NULL;
- if (v->e) {
+ {
+ BMEdge *e;
/* find closest edge to mouse cursor */
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- const bool is_boundary = BM_edge_is_boundary(e);
/* consider wire as boundary for this purpose,
* otherwise we can't a face away from a wire edge */
- totboundary_edge += (is_boundary != 0 || BM_edge_is_wire(e));
+ totboundary_edge += (BM_edge_is_boundary(e) || BM_edge_is_wire(e));
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- if (is_boundary == false && BM_edge_is_manifold(e)) {
+ if ((is_manifold_region == false) || BM_edge_is_manifold(e)) {
d = edbm_rip_edgedist_squared(ar, projectMat, e->v1->co, e->v2->co, fmval, INSET_DEFAULT);
- if ((e2 == NULL) || (d < dist_sq)) {
+ if ((e_best == NULL) || (d < dist_sq)) {
dist_sq = d;
- e2 = e;
+ e_best = e;
}
}
}
}
+ }
- /* if we are ripping a single vertex from 3 faces,
- * then measure the distance to the face corner as well as the edge */
- if (BM_vert_face_count(v) == 3 &&
- BM_vert_edge_count(v) == 3)
- {
- BMEdge *e_all[3];
- BMLoop *l_all[3];
- int i1, i2;
-
- BM_iter_as_array(bm, BM_EDGES_OF_VERT, v, (void **)e_all, 3);
- BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)l_all, 3);
-
- /* not do a loop similar to the one above, but test against loops */
- for (i1 = 0; i1 < 3; i1++) {
- /* consider wire as boundary for this purpose,
- * otherwise we can't a face away from a wire edge */
- float l_mid_co[3];
- l = l_all[i1];
- edbm_calc_loop_co(l, l_mid_co);
- d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT);
- if ((e2 == NULL) || (d < dist_sq)) {
- dist_sq = d;
-
- /* find the edge that is not in this loop */
- e2 = NULL;
- for (i2 = 0; i2 < 3; i2++) {
- if (!BM_edge_in_loop(e_all[i2], l)) {
- e2 = e_all[i2];
- break;
- }
+ if (e_best && (is_manifold_region == false)) {
+ /* Try to split off a non-manifold fan (when we have multiple disconnected fans) */
+ BMLoop *l_sep = e_best->l->v == v ? e_best->l : e_best->l->next;
+ BMVert *v_new;
+
+ BLI_assert(l_sep->v == v);
+ v_new = bmesh_urmv_loop_region(bm, l_sep);
+ BLI_assert(BM_vert_find_first_loop(v));
+
+ BM_vert_select_set(bm, v, false);
+ BM_select_history_remove(bm, v);
+
+ BM_vert_select_set(bm, v_new, true);
+ if (ese.ele) {
+ BM_select_history_store(bm, v_new);
+ }
+
+ if (do_fill) {
+ BM_edge_create(bm, v, v_new, NULL, BM_CREATE_NOP);
+ }
+
+ return OPERATOR_FINISHED;
+ }
+
+ /* if we are ripping a single vertex from 3 faces,
+ * then measure the distance to the face corner as well as the edge */
+ if (BM_vert_face_count_is_equal(v, 3) &&
+ BM_vert_edge_count_is_equal(v, 3))
+ {
+ BMEdge *e_all[3];
+ BMLoop *l_all[3];
+ int i1, i2;
+
+ BM_iter_as_array(bm, BM_EDGES_OF_VERT, v, (void **)e_all, 3);
+ BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)l_all, 3);
+
+ /* not do a loop similar to the one above, but test against loops */
+ for (i1 = 0; i1 < 3; i1++) {
+ /* consider wire as boundary for this purpose,
+ * otherwise we can't a face away from a wire edge */
+ float l_mid_co[3];
+ l = l_all[i1];
+ edbm_calc_loop_co(l, l_mid_co);
+ d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT);
+ if ((e_best == NULL) || (d < dist_sq)) {
+ dist_sq = d;
+
+ /* find the edge that is not in this loop */
+ e_best = NULL;
+ for (i2 = 0; i2 < 3; i2++) {
+ if (!BM_edge_in_loop(e_all[i2], l)) {
+ e_best = e_all[i2];
+ break;
}
- BLI_assert(e2 != NULL);
}
+ BLI_assert(e_best != NULL);
}
}
}
@@ -677,6 +706,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
}
}
else {
+ BMEdge *e;
/* a wire vert, find the best edge */
BM_ITER_ELEM (e, &iter, vout[i], BM_EDGES_OF_VERT) {
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
@@ -694,6 +724,15 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
}
}
+ /* vout[0] == best
+ * vout[1] == glue
+ * vout[2+] == splice with glue (when vout_len > 2)
+ */
+ if (vi_best != 0) {
+ SWAP(BMVert *, vout[0], vout[vi_best]);
+ vi_best = 0;
+ }
+
/* select the vert from the best region */
v = vout[vi_best];
BM_vert_select_set(bm, v, true);
@@ -704,18 +743,15 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
/* splice all others back together */
if (vout_len > 2) {
-
- /* vout[0] == best
- * vout[1] == glue
- * vout[2+] == splice with glue
- */
- if (vi_best != 0) {
- SWAP(BMVert *, vout[0], vout[vi_best]);
- vi_best = 0;
+ for (i = 2; i < vout_len; i++) {
+ BM_vert_splice(bm, vout[1], vout[i]);
}
+ }
- for (i = 2; i < vout_len; i++) {
- BM_vert_splice(bm, vout[i], vout[1]);
+ if (do_fill) {
+ if (do_fill) {
+ /* match extrude vert-order */
+ BM_edge_create(bm, vout[1], vout[0], NULL, BM_CREATE_NOP);
}
}
@@ -725,7 +761,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
}
}
- if (!e2) {
+ if (!e_best) {
BKE_report(op->reports, RPT_ERROR, "Selected vertex has no edge/face pairs attached");
return OPERATOR_CANCELLED;
}
@@ -734,20 +770,51 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
/* unlike edge split, for single vertex split we only use the operator in one of the cases
* but both allocate fill */
- /* rip two adjacent edges */
- if (BM_edge_is_boundary(e2) || BM_vert_face_count(v) == 2) {
- /* Don't run the edge split operator in this case */
+ {
BMVert *v_rip;
+ BMLoop *larr[2];
+ int larr_len = 0;
- l = BM_edge_vert_share_loop(e2->l, v);
+ /* rip two adjacent edges */
+ if (BM_edge_is_boundary(e_best) || BM_vert_face_count_is_equal(v, 2)) {
+ /* Don't run the edge split operator in this case */
- /* only tag for face-fill (we don't call the operator) */
- if (BM_edge_is_boundary(e2)) {
- BM_elem_flag_enable(e2, BM_ELEM_TAG);
+ l = BM_edge_vert_share_loop(e_best->l, v);
+ larr[larr_len] = l;
+ larr_len++;
+
+ /* only tag for face-fill (we don't call the operator) */
+ if (BM_edge_is_boundary(e_best)) {
+ BM_elem_flag_enable(e_best, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_enable(l->e, BM_ELEM_TAG);
+ BM_elem_flag_enable(l->prev->e, BM_ELEM_TAG);
+ }
}
else {
- BM_elem_flag_enable(l->e, BM_ELEM_TAG);
- BM_elem_flag_enable(l->prev->e, BM_ELEM_TAG);
+ if (BM_edge_is_manifold(e_best)) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = e_best->l;
+ do {
+ larr[larr_len] = BM_edge_vert_share_loop(l_iter, v);
+
+ if (do_fill) {
+ /* Only needed when filling...
+ * Also, we never want to tag best edge, that one won't change during split. See T44618. */
+ if (larr[larr_len]->e == e_best) {
+ BM_elem_flag_enable(larr[larr_len]->prev->e, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_enable(larr[larr_len]->e, BM_ELEM_TAG);
+ }
+ }
+ larr_len++;
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+ else {
+ /* looks like there are no split edges, we could just return/report-error? - Campbell */
+ }
}
/* keep directly before edgesplit */
@@ -755,13 +822,12 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm);
}
-#if 0
- v_rip = BM_face_vert_separate(bm, l->f, v);
-#else
- v_rip = BM_face_loop_separate(bm, l);
-#endif
-
- BLI_assert(v_rip);
+ if (larr_len) {
+ v_rip = BM_face_loop_separate_multi(bm, larr, larr_len);
+ }
+ else {
+ v_rip = NULL;
+ }
if (v_rip) {
BM_vert_select_set(bm, v_rip, true);
@@ -771,27 +837,6 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
return OPERATOR_CANCELLED;
}
}
- else {
- if (BM_edge_is_manifold(e2)) {
- l = e2->l;
- e = BM_loop_other_edge_loop(l, v)->e;
- BM_elem_flag_enable(e, BM_ELEM_TAG);
-
- l = e2->l->radial_next;
- e = BM_loop_other_edge_loop(l, v)->e;
- BM_elem_flag_enable(e, BM_ELEM_TAG);
- }
- else {
- /* looks like there are no split edges, we could just return/report-error? - Campbell */
- }
-
- /* keep directly before edgesplit */
- if (do_fill) {
- fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm);
- }
-
- BM_mesh_edgesplit(em->bm, true, true, true);
- }
{
/* --- select which vert --- */
@@ -854,7 +899,7 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve
BMesh *bm = em->bm;
BMIter iter, eiter;
BMLoop *l;
- BMEdge *e, *e2;
+ BMEdge *e_best;
BMVert *v;
const int totedge_orig = bm->totedge;
float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
@@ -868,11 +913,12 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve
/* expand edge selection */
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ BMEdge *e;
bool all_manifold;
int totedge_manifold; /* manifold, visible edges */
int i;
- e2 = NULL;
+ e_best = NULL;
i = 0;
totedge_manifold = 0;
all_manifold = true;
@@ -884,7 +930,7 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve
/* important to check selection rather then tag here
* else we get feedback loop */
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- e2 = e;
+ e_best = e;
i++;
}
totedge_manifold++;
@@ -897,18 +943,18 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve
}
/* single edge, extend */
- if (i == 1 && e2->l) {
+ if (i == 1 && e_best->l) {
/* note: if the case of 3 edges has one change in loop stepping,
* if this becomes more involved we may be better off splitting
* the 3 edge case into its own else-if branch */
if ((totedge_manifold == 4 || totedge_manifold == 3) || (all_manifold == false)) {
- BMLoop *l_a = e2->l;
+ BMLoop *l_a = e_best->l;
BMLoop *l_b = l_a->radial_next;
/* find the best face to follow, this way the edge won't point away from
* the mouse when there are more than 4 (takes the shortest face fan around) */
- l = (edbm_rip_edge_side_measure(e2, l_a, ar, projectMat, fmval) <
- edbm_rip_edge_side_measure(e2, l_b, ar, projectMat, fmval)) ? l_a : l_b;
+ l = (edbm_rip_edge_side_measure(e_best, l_a, ar, projectMat, fmval) <
+ edbm_rip_edge_side_measure(e_best, l_b, ar, projectMat, fmval)) ? l_a : l_b;
l = BM_loop_other_edge_loop(l, v);
/* important edge is manifold else we can be attempting to split off a fan that don't budge,
@@ -926,7 +972,7 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve
}
}
else {
- e = BM_vert_other_disk_edge(v, e2);
+ e = BM_vert_other_disk_edge(v, e_best);
if (e) {
BLI_assert(!BM_elem_flag_test(e, BM_ELEM_TAG));
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index a0c4122af3a..4920a5af41b 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -36,6 +36,7 @@
#include "BLI_linklist.h"
#include "BLI_linklist_stack.h"
#include "BLI_math.h"
+#include "BLI_math_bits.h"
#include "BLI_rand.h"
#include "BLI_array.h"
@@ -52,6 +53,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "ED_mesh.h"
#include "ED_screen.h"
@@ -196,11 +198,11 @@ bool EDBM_backbuf_border_init(ViewContext *vc, short xmin, short ymin, short xma
unsigned int *dr;
int a;
- if (vc->obedit == NULL || vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) {
+ if (vc->obedit == NULL || !V3D_IS_ZBUF(vc->v3d)) {
return false;
}
- buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+ buf = ED_view3d_backbuf_read(vc, xmin, ymin, xmax, ymax);
if (buf == NULL) return false;
if (bm_vertoffs == 0) return false;
@@ -271,11 +273,11 @@ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short
return false;
}
}
- else if (vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) {
+ else if (!V3D_IS_ZBUF(vc->v3d)) {
return false;
}
- buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+ buf = ED_view3d_backbuf_read(vc, xmin, ymin, xmax, ymax);
if (buf == NULL) return false;
if (bm_vertoffs == 0) return false;
@@ -320,13 +322,13 @@ bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads)
return false;
}
}
- else if (vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) {
+ else if (!V3D_IS_ZBUF(vc->v3d)) {
return false;
}
xmin = xs - rads; xmax = xs + rads;
ymin = ys - rads; ymax = ys + rads;
- buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+ buf = ED_view3d_backbuf_read(vc, xmin, ymin, xmax, ymax);
if (bm_vertoffs == 0) return false;
if (buf == NULL) return false;
@@ -350,194 +352,369 @@ bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads)
}
+
+/* -------------------------------------------------------------------- */
+
+/** \name Find Nearest Vert/Edge/Face
+ *
+ * \note Screen-space manhatten distances are used here,
+ * since its faster and good enough for the purpose of selection.
+ *
+ * \note \a dist_bias is used so we can bias against selected items.
+ * when choosing between elements of a single type, but return the real distance
+ * to avoid the bias interfering with distance comparisons when mixing types.
+ * \{ */
+
+#define FIND_NEAR_SELECT_BIAS 5
+#define FIND_NEAR_CYCLE_THRESHOLD_MIN 3
+
+struct NearestVertUserData_Hit {
+ float dist;
+ float dist_bias;
+ int index;
+ BMVert *vert;
+};
+
+struct NearestVertUserData {
+ float mval_fl[2];
+ bool use_select_bias;
+ bool use_cycle;
+ int cycle_index_prev;
+
+ struct NearestVertUserData_Hit hit;
+ struct NearestVertUserData_Hit hit_cycle;
+};
+
static void findnearestvert__doClosest(void *userData, BMVert *eve, const float screen_co[2], int index)
{
- struct { float mval_fl[2], pass, select, strict; float dist, lastIndex, closestIndex; BMVert *closest; } *data = userData;
+ struct NearestVertUserData *data = userData;
+ float dist_test, dist_test_bias;
- if (data->pass == 0) {
- if (index <= data->lastIndex)
- return;
- }
- else {
- if (index > data->lastIndex)
- return;
+ dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
+
+ if (data->use_select_bias && BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ dist_test_bias += FIND_NEAR_SELECT_BIAS;
}
- if (data->dist > 3) {
- float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->select) {
- if (data->strict == 1) {
- return;
- }
- else {
- dist_test += 5;
- }
- }
+ if (dist_test_bias < data->hit.dist_bias) {
+ data->hit.dist_bias = dist_test_bias;
+ data->hit.dist = dist_test;
+ data->hit.index = index;
+ data->hit.vert = eve;
+ }
- if (dist_test < data->dist) {
- data->dist = dist_test;
- data->closest = eve;
- data->closestIndex = index;
+ if (data->use_cycle) {
+ if ((data->hit_cycle.vert == NULL) &&
+ (index > data->cycle_index_prev) &&
+ (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN))
+ {
+ data->hit_cycle.dist_bias = dist_test_bias;
+ data->hit_cycle.dist = dist_test;
+ data->hit_cycle.index = index;
+ data->hit_cycle.vert = eve;
}
}
}
-
-static bool findnearestvert__backbufIndextest(void *handle, unsigned int index)
-{
- BMEditMesh *em = (BMEditMesh *)handle;
- BMVert *eve = BM_vert_at_index_find(em->bm, index - 1);
- return !(eve && BM_elem_flag_test(eve, BM_ELEM_SELECT));
-}
/**
- * findnearestvert
- *
- * dist (in/out): minimal distance to the nearest and at the end, actual distance
- * sel: selection bias
- * if SELECT, selected vertice are given a 5 pixel bias to make them further than unselect verts
- * if 0, unselected vertice are given the bias
- * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
+ * Nearest vertex under the cursor.
+ *
+ * \param r_dist (in/out), minimal distance to the nearest and at the end, actual distance
+ * \param use_select_bias
+ * - When true, selected vertice are given a 5 pixel bias to make them further than unselect verts.
+ * - When false, unselected vertice are given the bias.
+ * \param use_cycle Cycle over elements within #FIND_NEAR_CYCLE_THRESHOLD_MIN in order of index.
*/
-BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *r_dist, const bool sel, const bool strict)
+BMVert *EDBM_vert_find_nearest_ex(
+ ViewContext *vc, float *r_dist,
+ const bool use_select_bias, bool use_cycle)
{
- if (vc->v3d->drawtype > OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
- float distance;
+ BMesh *bm = vc->em->bm;
+
+ if (V3D_IS_ZBUF(vc->v3d)) {
+ const int dist_px = ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist);
+ float dist_test;
unsigned int index;
BMVert *eve;
- if (strict) {
- index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance,
- strict, vc->em, findnearestvert__backbufIndextest);
- }
- else {
- index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance,
- 0, NULL, NULL);
- }
-
- eve = index ? BM_vert_at_index_find(vc->em->bm, index - 1) : NULL;
+ index = ED_view3d_backbuf_sample_rect(
+ vc, vc->mval, dist_px, bm_wireoffs, 0xFFFFFF, &dist_test);
+ eve = index ? BM_vert_at_index_find_or_table(bm, index - 1) : NULL;
- if (eve && distance < *r_dist) {
- *r_dist = distance;
- return eve;
- }
- else {
- return NULL;
+ if (eve) {
+ if (dist_test < *r_dist) {
+ *r_dist = dist_test;
+ return eve;
+ }
}
-
+ return NULL;
}
else {
- struct { float mval_fl[2], pass, select, strict; float dist, lastIndex, closestIndex; BMVert *closest; } data;
- static int lastSelectedIndex = 0;
- static BMVert *lastSelected = NULL;
-
- if (lastSelected && BM_vert_at_index_find(vc->em->bm, lastSelectedIndex) != lastSelected) {
- lastSelectedIndex = 0;
- lastSelected = NULL;
+ struct NearestVertUserData data = {{0}};
+ const struct NearestVertUserData_Hit *hit;
+ const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT;
+
+ static int prev_select_index = 0;
+ static const BMVert *prev_select_elem = NULL;
+
+ if ((use_cycle == false) ||
+ (prev_select_elem && (prev_select_elem != BM_vert_at_index_find_or_table(bm, prev_select_index))))
+ {
+ prev_select_index = 0;
+ prev_select_elem = NULL;
}
- data.lastIndex = lastSelectedIndex;
data.mval_fl[0] = vc->mval[0];
data.mval_fl[1] = vc->mval[1];
- data.select = sel ? BM_ELEM_SELECT : 0;
- data.dist = *r_dist;
- data.strict = strict;
- data.closest = NULL;
- data.closestIndex = 0;
-
- data.pass = 0;
+ data.use_select_bias = use_select_bias;
+ data.use_cycle = use_cycle;
+ data.hit.dist = data.hit_cycle.dist = \
+ data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist;
+ data.cycle_index_prev = prev_select_index;
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+ mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, clip_flag);
- mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ hit = (data.use_cycle && data.hit_cycle.vert) ? &data.hit_cycle : &data.hit;
+ *r_dist = hit->dist;
- if (data.dist > 3) {
- data.pass = 1;
- mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
- }
+ prev_select_elem = hit->vert;
+ prev_select_index = hit->index;
- *r_dist = data.dist;
- lastSelected = data.closest;
- lastSelectedIndex = data.closestIndex;
+ return hit->vert;
+ }
+}
- return data.closest;
+BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *r_dist)
+{
+ return EDBM_vert_find_nearest_ex(vc, r_dist, false, false);
+}
+
+/* find the distance to the edge we already have */
+struct NearestEdgeUserData_ZBuf {
+ float mval_fl[2];
+ float dist;
+ const BMEdge *edge_test;
+};
+
+static void find_nearest_edge_center__doZBuf(
+ void *userData, BMEdge *eed,
+ const float screen_co_a[2], const float screen_co_b[2],
+ int UNUSED(index))
+{
+ struct NearestEdgeUserData_ZBuf *data = userData;
+
+ if (eed == data->edge_test) {
+ float dist_test;
+ float screen_co_mid[2];
+
+ mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
+ dist_test = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
+
+ if (dist_test < data->dist) {
+ data->dist = dist_test;
+ }
}
}
+struct NearestEdgeUserData_Hit {
+ float dist;
+ float dist_bias;
+ int index;
+ BMEdge *edge;
+
+ /* edges only, un-biased manhatten distance to which ever edge we pick
+ * (not used for choosing) */
+ float dist_center;
+};
+
+struct NearestEdgeUserData {
+ ViewContext vc;
+ float mval_fl[2];
+ bool use_select_bias;
+ bool use_cycle;
+ int cycle_index_prev;
+
+ struct NearestEdgeUserData_Hit hit;
+ struct NearestEdgeUserData_Hit hit_cycle;
+};
+
/* note; uses v3d, so needs active 3d window */
-static void findnearestedge__doClosest(void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int UNUSED(index))
+static void find_nearest_edge__doClosest(
+ void *userData, BMEdge *eed,
+ const float screen_co_a[2], const float screen_co_b[2],
+ int index)
{
- struct { ViewContext vc; float mval_fl[2]; float dist; BMEdge *closest; } *data = userData;
- int distance;
+ struct NearestEdgeUserData *data = userData;
+ float dist_test, dist_test_bias;
- distance = dist_to_line_segment_v2(data->mval_fl, screen_co_a, screen_co_b);
-
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- distance += 5;
+ float fac = line_point_factor_v2(data->mval_fl, screen_co_a, screen_co_b);
+ float screen_co[2];
+
+ if (fac <= 0.0f) {
+ fac = 0.0f;
+ copy_v2_v2(screen_co, screen_co_a);
+ }
+ else if (fac >= 1.0f) {
+ fac = 1.0f;
+ copy_v2_v2(screen_co, screen_co_b);
+ }
+ else {
+ interp_v2_v2v2(screen_co, screen_co_a, screen_co_b, fac);
}
- if (distance < data->dist) {
- if (data->vc.rv3d->rflag & RV3D_CLIPPING) {
- float lambda = line_point_factor_v2(data->mval_fl, screen_co_a, screen_co_b);
- float vec[3];
+ dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
- vec[0] = eed->v1->co[0] + lambda * (eed->v2->co[0] - eed->v1->co[0]);
- vec[1] = eed->v1->co[1] + lambda * (eed->v2->co[1] - eed->v1->co[1]);
- vec[2] = eed->v1->co[2] + lambda * (eed->v2->co[2] - eed->v1->co[2]);
+ if (data->use_select_bias && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ dist_test += FIND_NEAR_SELECT_BIAS;
+ }
- if (ED_view3d_clipping_test(data->vc.rv3d, vec, true) == 0) {
- data->dist = distance;
- data->closest = eed;
- }
+ if (data->vc.rv3d->rflag & RV3D_CLIPPING) {
+ float vec[3];
+
+ interp_v3_v3v3(vec, eed->v1->co, eed->v2->co, fac);
+ if (ED_view3d_clipping_test(data->vc.rv3d, vec, true)) {
+ return;
}
- else {
- data->dist = distance;
- data->closest = eed;
+ }
+
+ if (dist_test_bias < data->hit.dist_bias) {
+ float screen_co_mid[2];
+
+ data->hit.dist_bias = dist_test_bias;
+ data->hit.dist = dist_test;
+ data->hit.index = index;
+ data->hit.edge = eed;
+
+ mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
+ data->hit.dist_center = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
+ }
+
+ if (data->use_cycle) {
+ if ((data->hit_cycle.edge == NULL) &&
+ (index > data->cycle_index_prev) &&
+ (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN))
+ {
+ float screen_co_mid[2];
+
+ data->hit_cycle.dist_bias = dist_test_bias;
+ data->hit_cycle.dist = dist_test;
+ data->hit_cycle.index = index;
+ data->hit_cycle.edge = eed;
+
+ mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b);
+ data->hit_cycle.dist_center = len_manhattan_v2v2(data->mval_fl, screen_co_mid);
}
}
}
-BMEdge *EDBM_edge_find_nearest(ViewContext *vc, float *r_dist)
+
+BMEdge *EDBM_edge_find_nearest_ex(
+ ViewContext *vc, float *r_dist,
+ float *r_dist_center,
+ const bool use_select_bias, const bool use_cycle,
+ BMEdge **r_eed_zbuf)
{
+ BMesh *bm = vc->em->bm;
- if (vc->v3d->drawtype > OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
- float distance;
+ if (V3D_IS_ZBUF(vc->v3d)) {
+ const int dist_px = ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist);
+ float dist_test = 0.0f;
unsigned int index;
BMEdge *eed;
- view3d_validate_backbuf(vc);
-
- index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_solidoffs, bm_wireoffs, &distance, 0, NULL, NULL);
- eed = index ? BM_edge_at_index_find(vc->em->bm, index - 1) : NULL;
-
- if (eed && distance < *r_dist) {
- *r_dist = distance;
- return eed;
+ ED_view3d_backbuf_validate(vc);
+
+ index = ED_view3d_backbuf_sample_rect(vc, vc->mval, dist_px, bm_solidoffs, bm_wireoffs, &dist_test);
+ eed = index ? BM_edge_at_index_find_or_table(bm, index - 1) : NULL;
+
+ if (r_eed_zbuf) {
+ *r_eed_zbuf = eed;
}
- else {
- return NULL;
+
+ /* exception for faces (verts don't need this) */
+ if (r_dist_center && eed) {
+ struct NearestEdgeUserData_ZBuf data;
+
+ data.mval_fl[0] = vc->mval[0];
+ data.mval_fl[1] = vc->mval[1];
+ data.dist = FLT_MAX;
+ data.edge_test = eed;
+
+ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+
+ mesh_foreachScreenEdge(vc, find_nearest_edge_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ *r_dist_center = data.dist;
+ }
+ /* end exception */
+
+ if (eed) {
+ if (dist_test < *r_dist) {
+ *r_dist = dist_test;
+ return eed;
+ }
}
+ return NULL;
}
else {
- struct { ViewContext vc; float mval_fl[2]; float dist; BMEdge *closest; } data;
+ struct NearestEdgeUserData data = {{0}};
+ const struct NearestEdgeUserData_Hit *hit;
+ /* interpolate along the edge before doing a clipping plane test */
+ const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT & ~V3D_PROJ_TEST_CLIP_BB;
+
+ static int prev_select_index = 0;
+ static const BMEdge *prev_select_elem = NULL;
+
+ if ((use_cycle == false) ||
+ (prev_select_elem && (prev_select_elem != BM_edge_at_index_find_or_table(bm, prev_select_index))))
+ {
+ prev_select_index = 0;
+ prev_select_elem = NULL;
+ }
data.vc = *vc;
data.mval_fl[0] = vc->mval[0];
data.mval_fl[1] = vc->mval[1];
- data.dist = *r_dist;
- data.closest = NULL;
+ data.use_select_bias = use_select_bias;
+ data.use_cycle = use_cycle;
+ data.hit.dist = data.hit_cycle.dist = \
+ data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist;
+ data.cycle_index_prev = prev_select_index;
+
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+ mesh_foreachScreenEdge(vc, find_nearest_edge__doClosest, &data, clip_flag);
+
+ hit = (data.use_cycle && data.hit_cycle.edge) ? &data.hit_cycle : &data.hit;
+ *r_dist = hit->dist;
+ if (r_dist_center) {
+ *r_dist_center = hit->dist_center;
+ }
- mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, V3D_PROJ_TEST_CLIP_WIN);
+ prev_select_elem = hit->edge;
+ prev_select_index = hit->index;
- *r_dist = data.dist;
- return data.closest;
+ return hit->edge;
}
}
-static void findnearestface__getDistance(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
+BMEdge *EDBM_edge_find_nearest(
+ ViewContext *vc, float *r_dist)
{
- struct { float mval_fl[2]; float dist; BMFace *toFace; } *data = userData;
+ return EDBM_edge_find_nearest_ex(vc, r_dist, false, false, false, NULL);
+}
+
+/* find the distance to the face we already have */
+struct NearestFaceUserData_ZBuf {
+ float mval_fl[2];
+ float dist;
+ const BMFace *face_test;
+};
- if (efa == data->toFace) {
+static void find_nearest_face_center__doZBuf(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
+{
+ struct NearestFaceUserData_ZBuf *data = userData;
+
+ if (efa == data->face_test) {
const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
if (dist_test < data->dist) {
@@ -545,96 +722,152 @@ static void findnearestface__getDistance(void *userData, BMFace *efa, const floa
}
}
}
+
+
+struct NearestFaceUserData_Hit {
+ float dist;
+ float dist_bias;
+ int index;
+ BMFace *face;
+};
+
+struct NearestFaceUserData {
+ float mval_fl[2];
+ bool use_select_bias;
+ bool use_cycle;
+ int cycle_index_prev;
+
+ struct NearestFaceUserData_Hit hit;
+ struct NearestFaceUserData_Hit hit_cycle;
+};
+
static void findnearestface__doClosest(void *userData, BMFace *efa, const float screen_co[2], int index)
{
- struct { float mval_fl[2], pass; float dist, lastIndex, closestIndex; BMFace *closest; } *data = userData;
+ struct NearestFaceUserData *data = userData;
+ float dist_test, dist_test_bias;
- if (data->pass == 0) {
- if (index <= data->lastIndex)
- return;
- }
- else {
- if (index > data->lastIndex)
- return;
+ dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co);
+
+ if (data->use_select_bias && BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ dist_test_bias += FIND_NEAR_SELECT_BIAS;
}
- if (data->dist > 3) {
- const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
+ if (dist_test_bias < data->hit.dist_bias) {
+ data->hit.dist_bias = dist_test_bias;
+ data->hit.dist = dist_test;
+ data->hit.index = index;
+ data->hit.face = efa;
+ }
- if (dist_test < data->dist) {
- data->dist = dist_test;
- data->closest = efa;
- data->closestIndex = index;
+ if (data->use_cycle) {
+ if ((data->hit_cycle.face == NULL) &&
+ (index > data->cycle_index_prev) &&
+ (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN))
+ {
+ data->hit_cycle.dist_bias = dist_test_bias;
+ data->hit_cycle.dist = dist_test;
+ data->hit_cycle.index = index;
+ data->hit_cycle.face = efa;
}
}
}
-BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist)
+
+BMFace *EDBM_face_find_nearest_ex(
+ ViewContext *vc, float *r_dist,
+ float *r_dist_center,
+ const bool use_select_bias, const bool use_cycle,
+ BMFace **r_efa_zbuf)
{
+ BMesh *bm = vc->em->bm;
- if (vc->v3d->drawtype > OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
+ if (V3D_IS_ZBUF(vc->v3d)) {
+ float dist_test = 0.0f;
unsigned int index;
BMFace *efa;
- view3d_validate_backbuf(vc);
+ ED_view3d_backbuf_validate(vc);
- index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]);
- efa = index ? BM_face_at_index_find(vc->em->bm, index - 1) : NULL;
+ index = ED_view3d_backbuf_sample(vc, vc->mval[0], vc->mval[1]);
+ efa = index ? BM_face_at_index_find_or_table(bm, index - 1) : NULL;
- if (efa) {
- struct { float mval_fl[2]; float dist; BMFace *toFace; } data;
+ if (r_efa_zbuf) {
+ *r_efa_zbuf = efa;
+ }
+
+ /* exception for faces (verts don't need this) */
+ if (r_dist_center && efa) {
+ struct NearestFaceUserData_ZBuf data;
data.mval_fl[0] = vc->mval[0];
data.mval_fl[1] = vc->mval[1];
data.dist = FLT_MAX;
- data.toFace = efa;
+ data.face_test = efa;
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- mesh_foreachScreenFace(vc, findnearestface__getDistance, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ mesh_foreachScreenFace(vc, find_nearest_face_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ *r_dist_center = data.dist;
+ }
+ /* end exception */
- if ((vc->em->selectmode == SCE_SELECT_FACE) || (data.dist < *r_dist)) { /* only faces, no dist check */
- *r_dist = data.dist;
+ if (efa) {
+ if (dist_test < *r_dist) {
+ *r_dist = dist_test;
return efa;
}
}
-
return NULL;
}
else {
- struct { float mval_fl[2], pass; float dist, lastIndex, closestIndex; BMFace *closest; } data;
- static int lastSelectedIndex = 0;
- static BMFace *lastSelected = NULL;
+ struct NearestFaceUserData data = {{0}};
+ const struct NearestFaceUserData_Hit *hit;
+ const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT;
+
+ static int prev_select_index = 0;
+ static const BMFace *prev_select_elem = NULL;
- if (lastSelected && BM_face_at_index_find(vc->em->bm, lastSelectedIndex) != lastSelected) {
- lastSelectedIndex = 0;
- lastSelected = NULL;
+ if ((use_cycle == false) ||
+ (prev_select_elem && (prev_select_elem != BM_face_at_index_find_or_table(bm, prev_select_index))))
+ {
+ prev_select_index = 0;
+ prev_select_elem = NULL;
}
- data.lastIndex = lastSelectedIndex;
data.mval_fl[0] = vc->mval[0];
data.mval_fl[1] = vc->mval[1];
- data.dist = *r_dist;
- data.closest = NULL;
- data.closestIndex = 0;
+ data.use_select_bias = use_select_bias;
+ data.use_cycle = use_cycle;
+ data.hit.dist = data.hit_cycle.dist = \
+ data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist;
+ data.cycle_index_prev = prev_select_index;
- data.pass = 0;
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, clip_flag);
- if (data.dist > 3.0f) {
- data.pass = 1;
- mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ hit = (data.use_cycle && data.hit_cycle.face) ? &data.hit_cycle : &data.hit;
+ *r_dist = hit->dist;
+ if (r_dist_center) {
+ *r_dist_center = hit->dist;
}
- *r_dist = data.dist;
- lastSelected = data.closest;
- lastSelectedIndex = data.closestIndex;
+ prev_select_elem = hit->face;
+ prev_select_index = hit->index;
- return data.closest;
+ return hit->face;
}
}
+BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist)
+{
+ return EDBM_face_find_nearest_ex(vc, r_dist, NULL, false, false, NULL);
+}
+
+#undef FIND_NEAR_SELECT_BIAS
+#undef FIND_NEAR_CYCLE_THRESHOLD_MIN
+
+
/* best distance based on screen coords.
* use em->selectmode to define how to use
* selected vertices and edges get disadvantage
@@ -643,35 +876,78 @@ BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist)
static int unified_findnearest(ViewContext *vc, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
{
BMEditMesh *em = vc->em;
- float dist = ED_view3d_select_dist_px();
-
- *r_eve = NULL;
- *r_eed = NULL;
- *r_efa = NULL;
+ static short mval_prev[2] = {-1, -1};
+ /* only cycle while the mouse remains still */
+ const bool use_cycle = ((mval_prev[0] == vc->mval[0]) && (mval_prev[1] == vc->mval[1]));
+ const float dist_init = ED_view3d_select_dist_px();
+ /* since edges select lines, we give dots advantage of ~20 pix */
+ const float dist_margin = (dist_init / 2);
+ float dist = dist_init;
+ BMFace *efa_zbuf = NULL;
+ BMEdge *eed_zbuf = NULL;
+ BMVert *eve = NULL;
+ BMEdge *eed = NULL;
+ BMFace *efa = NULL;
+
+
/* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
- view3d_validate_backbuf(vc);
-
- if (em->selectmode & SCE_SELECT_VERTEX)
- *r_eve = EDBM_vert_find_nearest(vc, &dist, BM_ELEM_SELECT, 0);
- if (em->selectmode & SCE_SELECT_FACE)
- *r_efa = EDBM_face_find_nearest(vc, &dist);
+ ED_view3d_backbuf_validate(vc);
- dist -= 20; /* since edges select lines, we give dots advantage of 20 pix */
- if (em->selectmode & SCE_SELECT_EDGE)
- *r_eed = EDBM_edge_find_nearest(vc, &dist);
+ if ((dist > 0.0f) && em->selectmode & SCE_SELECT_FACE) {
+ float dist_center = 0.0f;
+ float *dist_center_p = (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_VERTEX)) ? &dist_center : NULL;
+ efa = EDBM_face_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf);
+ if (efa && dist_center_p) {
+ dist = min_ff(dist_margin, dist_center);
+ }
+ }
+
+ if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_EDGE)) {
+ float dist_center = 0.0f;
+ float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : NULL;
+ eed = EDBM_edge_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf);
+ if (eed && dist_center_p) {
+ dist = min_ff(dist_margin, dist_center);
+ }
+ }
+
+ if ((dist > 0.0f) && em->selectmode & SCE_SELECT_VERTEX) {
+ eve = EDBM_vert_find_nearest_ex(vc, &dist, true, use_cycle);
+ }
/* return only one of 3 pointers, for frontbuffer redraws */
- if (*r_eed) {
- *r_efa = NULL; *r_eve = NULL;
+ if (eve) {
+ efa = NULL; eed = NULL;
}
- else if (*r_efa) {
- *r_eve = NULL;
+ else if (eed) {
+ efa = NULL;
}
-
- return (*r_eve || *r_eed || *r_efa);
+
+ /* there may be a face under the cursor, who's center if too far away
+ * use this if all else fails, it makes sense to select this */
+ if ((eve || eed || efa) == 0) {
+ if (eed_zbuf) {
+ eed = eed_zbuf;
+ }
+ else if (efa_zbuf) {
+ efa = efa_zbuf;
+ }
+ }
+
+ mval_prev[0] = vc->mval[0];
+ mval_prev[1] = vc->mval[1];
+
+ *r_eve = eve;
+ *r_eed = eed;
+ *r_efa = efa;
+
+ return (eve || eed || efa);
}
+/** \} */
+
+
/* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
static EnumPropertyItem prop_similar_compare_types[] = {
{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
@@ -1179,7 +1455,7 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op)
else {
for (edindex = 0; edindex < totedgesel; edindex += 1) {
eed = edarray[edindex];
- walker_select(em, BMW_LOOP, eed, true);
+ walker_select(em, BMW_EDGELOOP, eed, true);
}
EDBM_selectmode_flush(em);
}
@@ -1237,12 +1513,12 @@ static void mouse_mesh_loop_edge(BMEditMesh *em, BMEdge *eed, bool select, bool
{
bool edge_boundary = false;
- /* cycle between BMW_LOOP / BMW_EDGEBOUNDARY */
+ /* cycle between BMW_EDGELOOP / BMW_EDGEBOUNDARY */
if (select_cycle && BM_edge_is_boundary(eed)) {
int tot[2];
/* if the loops selected toggle the boundaries */
- walker_select_count(em, BMW_LOOP, eed, select, false,
+ walker_select_count(em, BMW_EDGELOOP, eed, select, false,
&tot[0], &tot[1]);
if (tot[select] == 0) {
edge_boundary = true;
@@ -1264,7 +1540,7 @@ static void mouse_mesh_loop_edge(BMEditMesh *em, BMEdge *eed, bool select, bool
walker_select(em, BMW_EDGEBOUNDARY, eed, select);
}
else {
- walker_select(em, BMW_LOOP, eed, select);
+ walker_select(em, BMW_EDGELOOP, eed, select);
}
}
@@ -1286,7 +1562,7 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de
em = vc.em;
/* no afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad */
- view3d_validate_backbuf(&vc);
+ ED_view3d_backbuf_validate(&vc);
eed = EDBM_edge_find_nearest(&vc, &dist);
if (eed == NULL) {
@@ -1307,16 +1583,8 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de
select = true;
}
else if (toggle) {
- int tot[2];
- /* Shift-clicking to toggle selection and shift-clicking an already selected edge
- * loop to do boundary selection conflicts here (see T43871), so we only toggle/deselect
- * if the entire boundary is selected. This gives the following behaviour for shift
- * clicking an edge loop: select edge loop, select edge boundary, toggle edge loop */
- walker_select_count(em, BMW_EDGEBOUNDARY, eed, select, false, &tot[0], &tot[1]);
- if (tot[select] == 0) {
- select = false;
- select_cycle = false;
- }
+ select = false;
+ select_cycle = false;
}
if (em->selectmode & SCE_SELECT_FACE) {
@@ -2050,7 +2318,7 @@ bool EDBM_select_interior_faces(BMEditMesh *em)
ok = true;
BM_ITER_ELEM (eed, &eiter, efa, BM_EDGES_OF_FACE) {
- if (BM_edge_face_count(eed) < 3) {
+ if (!BM_edge_face_count_is_over(eed, 2)) {
ok = false;
break;
}
@@ -2068,16 +2336,98 @@ bool EDBM_select_interior_faces(BMEditMesh *em)
/************************ Select Linked Operator *************************/
-static void linked_limit_default(bContext *C, wmOperator *op)
+struct DelimitData {
+ int cd_loop_type;
+ int cd_loop_offset;
+};
+
+static bool select_linked_delimit_test(
+ BMEdge *e, int delimit,
+ const struct DelimitData *delimit_data)
{
- if (!RNA_struct_property_is_set(op->ptr, "limit")) {
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (em->selectmode == SCE_SELECT_FACE)
- RNA_boolean_set(op->ptr, "limit", true);
- else
- RNA_boolean_set(op->ptr, "limit", false);
+ BLI_assert(delimit);
+
+ if (delimit & BMO_DELIM_SEAM) {
+ if (BM_elem_flag_test(e, BM_ELEM_SEAM)) {
+ return true;
+ }
}
+
+ if (delimit & BMO_DELIM_SHARP) {
+ if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0) {
+ return true;
+ }
+ }
+
+ if (delimit & BMO_DELIM_NORMAL) {
+ if (!BM_edge_is_contiguous(e)) {
+ return true;
+ }
+ }
+
+ if (delimit & BMO_DELIM_MATERIAL) {
+ if (e->l && e->l->radial_next != e->l) {
+ const short mat_nr = e->l->f->mat_nr;
+ BMLoop *l_iter = e->l->radial_next;
+ do {
+ if (l_iter->f->mat_nr != mat_nr) {
+ return true;
+ }
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ }
+ }
+
+ if (delimit & BMO_DELIM_UV) {
+ if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_loop_type, delimit_data->cd_loop_offset) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void select_linked_delimit_begin(BMesh *bm, short selectmode, int delimit)
+{
+ struct DelimitData delimit_data = {0};
+
+ BMIter iter;
+ BMEdge *e;
+
+ if (delimit & BMO_DELIM_UV) {
+ delimit_data.cd_loop_type = CD_MLOOPUV;
+ delimit_data.cd_loop_offset = CustomData_get_offset(&bm->ldata, delimit_data.cd_loop_type);
+ if (delimit_data.cd_loop_offset == -1) {
+ delimit &= ~BMO_DELIM_UV;
+ }
+ }
+
+ /* grr, shouldn't need to alloc BMO flags here */
+ BM_mesh_elem_toolflags_ensure(bm);
+ if (selectmode == SCE_SELECT_FACE) {
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ const bool is_walk_ok = (
+ (select_linked_delimit_test(e, delimit, &delimit_data) == false));
+
+ BMO_elem_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
+ }
+ }
+ else {
+ /* don't delimit selected edges in vert/edge mode */
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ const bool is_walk_ok = (
+ BM_elem_flag_test(e, BM_ELEM_SELECT) ||
+ (select_linked_delimit_test(e, delimit, &delimit_data) == false));
+
+ BMO_elem_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok);
+ }
+ }
+}
+
+static void select_linked_delimit_end(BMEditMesh *em)
+{
+ BMesh *bm = em->bm;
+
+ BM_mesh_elem_toolflags_clear(bm);
}
static int edbm_select_linked_exec(bContext *C, wmOperator *op)
@@ -2086,72 +2436,139 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
BMIter iter;
- BMEdge *e;
BMWalker walker;
- int limit;
-
- linked_limit_default(C, op);
+ const int delimit = RNA_enum_get(op->ptr, "delimit");
- limit = RNA_boolean_get(op->ptr, "limit");
+ if (delimit) {
+ select_linked_delimit_begin(em->bm, em->selectmode, delimit);
+ }
- if (em->selectmode == SCE_SELECT_FACE) {
- BMFace *efa;
+ if (em->selectmode & SCE_SELECT_VERTEX) {
+ BMVert *v;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_set(efa, BM_ELEM_TAG, BM_elem_flag_test(efa, BM_ELEM_SELECT));
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT));
}
- if (limit) {
- /* grr, shouldn't need to alloc BMO flags here */
- BM_mesh_elem_toolflags_ensure(bm);
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- BMO_elem_flag_set(bm, e, BMO_ELE_TAG, !BM_elem_flag_test(e, BM_ELEM_SEAM));
+ BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
+
+ if (delimit) {
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ BMElem *ele_walk;
+ BMW_ITER (ele_walk, &walker, v) {
+ if (ele_walk->head.htype == BM_LOOP) {
+ BMVert *v_step = ((BMLoop *)ele_walk)->v;
+ BM_vert_select_set(em->bm, v_step, true);
+ BM_elem_flag_disable(v_step, BM_ELEM_TAG);
+ }
+ else {
+ BMEdge *e_step = (BMEdge *)ele_walk;
+ BLI_assert(ele_walk->head.htype == BM_EDGE);
+ BM_edge_select_set(em->bm, e_step, true);
+ BM_elem_flag_disable(e_step->v1, BM_ELEM_TAG);
+ BM_elem_flag_disable(e_step->v2, BM_ELEM_TAG);
+ }
+ }
+ }
+ }
+ }
+ else {
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ BMEdge *e_walk;
+ BMW_ITER (e_walk, &walker, v) {
+ BM_edge_select_set(em->bm, e_walk, true);
+ BM_elem_flag_disable(e_walk, BM_ELEM_TAG);
+ }
+ }
}
}
- BMW_init(&walker, bm, BMW_ISLAND,
- BMW_MASK_NOP, limit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_end(&walker);
+
+ EDBM_selectmode_flush(em);
+ }
+ else if (em->selectmode & SCE_SELECT_EDGE) {
+ BMEdge *e;
+
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
+ }
+
+ BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
BMW_FLAG_TEST_HIDDEN,
BMW_NIL_LAY);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- for (efa = BMW_begin(&walker, efa); efa; efa = BMW_step(&walker)) {
- BM_face_select_set(bm, efa, true);
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ if (delimit) {
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BMElem *ele_walk;
+ BMW_ITER (ele_walk, &walker, e) {
+ if (ele_walk->head.htype == BM_LOOP) {
+ BMLoop *l_step = (BMLoop *)ele_walk;
+ BM_edge_select_set(em->bm, l_step->e, true);
+ BM_edge_select_set(em->bm, l_step->prev->e, true);
+ BM_elem_flag_disable(l_step->e, BM_ELEM_TAG);
+ }
+ else {
+ BMEdge *e_step = (BMEdge *)ele_walk;
+ BLI_assert(ele_walk->head.htype == BM_EDGE);
+ BM_edge_select_set(em->bm, e_step, true);
+ BM_elem_flag_disable(e_step, BM_ELEM_TAG);
+ }
+ }
}
}
}
+ else {
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BMEdge *e_walk;
+ BMW_ITER (e_walk, &walker, e) {
+ BM_edge_select_set(em->bm, e_walk, true);
+ BM_elem_flag_disable(e_walk, BM_ELEM_TAG);
+ }
+ }
+ }
+ }
+
BMW_end(&walker);
- if (limit) {
- BM_mesh_elem_toolflags_clear(bm);
- }
+ EDBM_selectmode_flush(em);
}
else {
- BMVert *v;
+ BMFace *f;
- BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT));
+ BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_set(f, BM_ELEM_TAG, BM_elem_flag_test(f, BM_ELEM_SELECT));
}
- BMW_init(&walker, em->bm, BMW_VERT_SHELL,
- BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_init(&walker, bm, BMW_ISLAND,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
BMW_FLAG_TEST_HIDDEN,
BMW_NIL_LAY);
- BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- for (e = BMW_begin(&walker, v); e; e = BMW_step(&walker)) {
- BM_edge_select_set(em->bm, e, true);
- BM_elem_flag_disable(e, BM_ELEM_TAG);
+ BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
+ BMFace *f_walk;
+ BMW_ITER (f_walk, &walker, f) {
+ BM_face_select_set(bm, f_walk, true);
+ BM_elem_flag_disable(f_walk, BM_ELEM_TAG);
}
}
}
+
BMW_end(&walker);
+ }
- EDBM_selectmode_flush(em);
+ if (delimit) {
+ select_linked_delimit_end(em);
}
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
@@ -2173,99 +2590,209 @@ void MESH_OT_select_linked(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
+ RNA_def_enum_flag(ot->srna, "delimit", mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit",
+ "Delimit selected region");
+}
+
+static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op);
+
+static void edbm_select_linked_pick_ex(
+ BMEditMesh *em,
+ BMVert *eve, BMEdge *eed, BMFace *efa,
+ bool sel, int delimit)
+{
+ BMesh *bm = em->bm;
+ BMWalker walker;
+
+ if (delimit) {
+ select_linked_delimit_begin(bm, em->selectmode, delimit);
+ }
+
+ /* Note: logic closely matches 'edbm_select_linked_exec', keep in sync */
+
+ if ((em->selectmode & SCE_SELECT_VERTEX) && eve) {
+
+ BMW_init(&walker, bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
+
+ if (delimit) {
+ BMElem *ele_walk;
+ BMW_ITER (ele_walk, &walker, eve) {
+ if (ele_walk->head.htype == BM_LOOP) {
+ BMVert *v_step = ((BMLoop *)ele_walk)->v;
+ BM_vert_select_set(bm, v_step, sel);
+ }
+ else {
+ BMEdge *e_step = (BMEdge *)ele_walk;
+ BLI_assert(ele_walk->head.htype == BM_EDGE);
+ BM_edge_select_set(bm, e_step, sel);
+ }
+ }
+ }
+ else {
+ BMEdge *e_walk;
+ BMW_ITER (e_walk, &walker, eve) {
+ BM_edge_select_set(bm, e_walk, sel);
+ }
+ }
+
+ BMW_end(&walker);
+
+ EDBM_selectmode_flush(em);
+ }
+ else if ((em->selectmode & SCE_SELECT_EDGE) && eed) {
+
+ BMW_init(&walker, bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
+
+ if (delimit) {
+ BMElem *ele_walk;
+ BMW_ITER (ele_walk, &walker, eed) {
+ if (ele_walk->head.htype == BM_LOOP) {
+ BMEdge *e_step = ((BMLoop *)ele_walk)->e;
+ BM_edge_select_set(bm, e_step, sel);
+ }
+ else {
+ BMEdge *e_step = (BMEdge *)ele_walk;
+ BLI_assert(ele_walk->head.htype == BM_EDGE);
+ BM_edge_select_set(bm, e_step, sel);
+ }
+ }
+ }
+ else {
+ BMEdge *e_walk;
+ BMW_ITER (e_walk, &walker, eed) {
+ BM_edge_select_set(bm, e_walk, sel);
+ }
+ }
+
+ BMW_end(&walker);
+
+ EDBM_selectmode_flush(em);
+ }
+ else if ((em->selectmode & SCE_SELECT_FACE) && efa) {
+
+ BMW_init(&walker, bm, BMW_ISLAND,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
+
+ {
+ BMFace *f_walk;
+ BMW_ITER (f_walk, &walker, efa) {
+ BM_face_select_set(bm, f_walk, sel);
+ BM_elem_flag_disable(f_walk, BM_ELEM_TAG);
+ }
+ }
+
+ BMW_end(&walker);
+ }
+
+ if (delimit) {
+ select_linked_delimit_end(em);
+ }
}
static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *obedit = CTX_data_edit_object(C);
ViewContext vc;
- BMesh *bm;
- BMWalker walker;
BMEditMesh *em;
+ BMesh *bm;
BMVert *eve;
- BMEdge *e, *eed;
+ BMEdge *eed;
BMFace *efa;
const bool sel = !RNA_boolean_get(op->ptr, "deselect");
+ const int delimit = RNA_enum_get(op->ptr, "delimit");
+ int index;
- int limit;
-
- linked_limit_default(C, op);
-
- limit = RNA_boolean_get(op->ptr, "limit");
+ if (RNA_struct_property_is_set(op->ptr, "index")) {
+ return edbm_select_linked_pick_exec(C, op);
+ }
/* unified_finednearest needs ogl */
view3d_operator_needs_opengl(C);
-
+
/* setup view context for argument to callbacks */
em_setup_viewcontext(C, &vc);
em = vc.em;
+ bm = em->bm;
- if (em->bm->totedge == 0)
+ if (bm->totedge == 0) {
return OPERATOR_CANCELLED;
-
- bm = em->bm;
+ }
vc.mval[0] = event->mval[0];
vc.mval[1] = event->mval[1];
-
+
/* return warning! */
-
if (unified_findnearest(&vc, &eve, &eed, &efa) == 0) {
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
-
+
return OPERATOR_CANCELLED;
}
-
- if (em->selectmode == SCE_SELECT_FACE) {
- BMIter iter;
-
- if (efa == NULL)
- return OPERATOR_CANCELLED;
-
- if (limit) {
- /* grr, shouldn't need to alloc BMO flags here */
- BM_mesh_elem_toolflags_ensure(bm);
- /* hflag no-seam --> bmo-tag */
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- BMO_elem_flag_set(bm, e, BMO_ELE_TAG, !BM_elem_flag_test(e, BM_ELEM_SEAM));
- }
- }
- /* walk */
- BMW_init(&walker, bm, BMW_ISLAND,
- BMW_MASK_NOP, limit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
- BMW_FLAG_TEST_HIDDEN,
- BMW_NIL_LAY);
+ edbm_select_linked_pick_ex(em, eve, eed, efa, sel, delimit);
- for (efa = BMW_begin(&walker, efa); efa; efa = BMW_step(&walker)) {
- BM_face_select_set(bm, efa, sel);
- }
- BMW_end(&walker);
+ /* to support redo */
+ if ((em->selectmode & SCE_SELECT_VERTEX) && eve) {
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+ index = BM_elem_index_get(eve);
+ }
+ else if ((em->selectmode & SCE_SELECT_EDGE) && eed) {
+ BM_mesh_elem_index_ensure(bm, BM_EDGE);
+ index = BM_elem_index_get(eed) + bm->totvert;
+ }
+ else if ((em->selectmode & SCE_SELECT_FACE) && efa) {
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+ index = BM_elem_index_get(efa) + bm->totvert + bm->totedge;
}
else {
- if (efa) {
- eed = BM_FACE_FIRST_LOOP(efa)->e;
- }
- else if (!eed) {
- if (!eve || !eve->e)
- return OPERATOR_CANCELLED;
+ index = -1;
+ }
- eed = eve->e;
- }
+ RNA_int_set(op->ptr, "index", index);
- BMW_init(&walker, bm, BMW_VERT_SHELL,
- BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
- BMW_FLAG_TEST_HIDDEN,
- BMW_NIL_LAY);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
- for (e = BMW_begin(&walker, eed->v1); e; e = BMW_step(&walker)) {
- BM_edge_select_set(bm, e, sel);
- }
- BMW_end(&walker);
+ return OPERATOR_FINISHED;
+}
- EDBM_selectmode_flush(em);
+
+static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ int index;
+ BMVert *eve = NULL;
+ BMEdge *eed = NULL;
+ BMFace *efa = NULL;
+ const bool sel = !RNA_boolean_get(op->ptr, "deselect");
+ const int delimit = RNA_enum_get(op->ptr, "delimit");
+
+ index = RNA_int_get(op->ptr, "index");
+ if (index < 0 || index >= (bm->totvert + bm->totedge + bm->totface)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (index < bm->totvert) {
+ eve = BM_vert_at_index_find_or_table(bm, index);
}
+ else if (index < (bm->totvert + bm->totedge)) {
+ index -= bm->totvert;
+ eed = BM_edge_at_index_find_or_table(bm, index);
+ }
+ else if (index < (bm->totvert + bm->totedge + bm->totface)) {
+ index -= (bm->totvert + bm->totedge);
+ efa = BM_face_at_index_find_or_table(bm, index);
+ }
+
+ edbm_select_linked_pick_ex(em, eve, eed, efa, sel, delimit);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
@@ -2274,6 +2801,8 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
void MESH_OT_select_linked_pick(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Select Linked";
ot->idname = "MESH_OT_select_linked_pick";
@@ -2281,13 +2810,19 @@ void MESH_OT_select_linked_pick(wmOperatorType *ot)
/* api callbacks */
ot->invoke = edbm_select_linked_pick_invoke;
+ ot->exec = edbm_select_linked_pick_exec;
ot->poll = ED_operator_editmesh;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
- RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
+ RNA_def_enum_flag(ot->srna, "delimit", mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit",
+ "Delimit selected region");
+
+ /* use for redo */
+ prop = RNA_def_int(ot->srna, "index", -1, 0, INT_MAX, "", "", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
@@ -2560,7 +3095,7 @@ static bool bm_edge_is_select_isolated(BMEdge *e)
/* Walk all reachable elements of the same type as h_act in breadth-first
* order, starting from h_act. Deselects elements if the depth when they
* are reached is not a multiple of "nth". */
-static void walker_deselect_nth(BMEditMesh *em, int nth, int offset, BMHeader *h_act)
+static void walker_deselect_nth(BMEditMesh *em, int nth, int skip, int offset, BMHeader *h_act)
{
BMElem *ele;
BMesh *bm = em->bm;
@@ -2626,7 +3161,8 @@ static void walker_deselect_nth(BMEditMesh *em, int nth, int offset, BMHeader *h
for (ele = BMW_begin(&walker, h_act); ele != NULL; ele = BMW_step(&walker)) {
if (!BM_elem_flag_test(ele, BM_ELEM_TAG)) {
/* Deselect elements that aren't at "nth" depth from active */
- if ((offset + BMW_current_depth(&walker)) % nth) {
+ const int depth = BMW_current_depth(&walker) - 1;
+ if ((offset + depth) % (skip + nth) >= skip) {
BM_elem_select_set(bm, ele, false);
}
BM_elem_flag_enable(ele, BM_ELEM_TAG);
@@ -2693,7 +3229,7 @@ static void deselect_nth_active(BMEditMesh *em, BMVert **r_eve, BMEdge **r_eed,
}
}
-static bool edbm_deselect_nth(BMEditMesh *em, int nth, int offset)
+static bool edbm_deselect_nth(BMEditMesh *em, int nth, int skip, int offset)
{
BMVert *v;
BMEdge *e;
@@ -2702,15 +3238,15 @@ static bool edbm_deselect_nth(BMEditMesh *em, int nth, int offset)
deselect_nth_active(em, &v, &e, &f);
if (v) {
- walker_deselect_nth(em, nth, offset, &v->head);
+ walker_deselect_nth(em, nth, skip, offset, &v->head);
return true;
}
else if (e) {
- walker_deselect_nth(em, nth, offset, &e->head);
+ walker_deselect_nth(em, nth, skip, offset, &e->head);
return true;
}
else if (f) {
- walker_deselect_nth(em, nth, offset, &f->head);
+ walker_deselect_nth(em, nth, skip, offset, &f->head);
return true;
}
@@ -2721,15 +3257,14 @@ static int edbm_select_nth_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int nth = RNA_int_get(op->ptr, "nth");
+ const int nth = RNA_int_get(op->ptr, "nth") - 1;
+ const int skip = RNA_int_get(op->ptr, "skip");
int offset = RNA_int_get(op->ptr, "offset");
/* so input of offset zero ends up being (nth - 1) */
- offset = mod_i(offset, nth);
- /* depth starts at 1, this keeps active item selected */
- offset -= 1;
+ offset = mod_i(offset, nth + skip);
- if (edbm_deselect_nth(em, nth, offset) == false) {
+ if (edbm_deselect_nth(em, nth, skip, offset) == false) {
BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face");
return OPERATOR_CANCELLED;
}
@@ -2755,6 +3290,7 @@ void MESH_OT_select_nth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_int(ot->srna, "nth", 2, 2, INT_MAX, "Nth Selection", "", 2, 100);
+ RNA_def_int(ot->srna, "skip", 1, 1, INT_MAX, "Skip", "", 1, 100);
RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "", -100, 100);
}
@@ -2945,7 +3481,7 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
if ((use_wire && BM_edge_is_wire(e)) ||
(use_boundary && BM_edge_is_boundary(e)) ||
(use_non_contiguous && (BM_edge_is_manifold(e) && !BM_edge_is_contiguous(e))) ||
- (use_multi_face && (BM_edge_face_count(e) > 2)))
+ (use_multi_face && (BM_edge_face_count_is_over(e, 2))))
{
/* check we never select perfect edge (in test above) */
BLI_assert(!(BM_edge_is_manifold(e) && BM_edge_is_contiguous(e)));
@@ -3144,7 +3680,7 @@ static int edbm_select_axis_exec(bContext *C, wmOperator *op)
else {
BMVert *v;
BMIter iter;
- const float limit = CTX_data_tool_settings(C)->doublimit; // XXX
+ const float limit = RNA_float_get(op->ptr, "threshold");
float value = v_act->co[axis];
if (mode == 0)
@@ -3209,6 +3745,7 @@ void MESH_OT_select_axis(wmOperatorType *ot)
/* properties */
RNA_def_enum(ot->srna, "mode", axis_mode_items, 0, "Axis Mode", "Axis side to use when selecting");
RNA_def_enum(ot->srna, "axis", axis_items_xyz, 0, "Axis", "Select the axis to compare each vertex on");
+ RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Threshold", "", 0.00001, 10.0);
}
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 93ebbbcf620..50419cb7347 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -96,7 +96,7 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
}
BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT,
- smooth, SUBD_FALLOFF_ROOT, false,
+ smooth, SUBD_FALLOFF_INVSQUARE, false,
fractal, along_normal,
cuts,
SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"),
@@ -492,7 +492,7 @@ static int edbm_collapse_edge_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (!EDBM_op_callf(em, op, "collapse edges=%he", BM_ELEM_SELECT))
+ if (!EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, true))
return OPERATOR_CANCELLED;
EDBM_update_generic(em, true, true);
@@ -1109,28 +1109,111 @@ static bool bm_vert_connect_select_history(BMesh *bm)
return false;
}
+/**
+ * Convert an edge selection to a temp vertex selection
+ * (which must be cleared after use as a path to connect).
+ */
+static bool bm_vert_connect_select_history_edge_to_vert_path(BMesh *bm, ListBase *r_selected)
+{
+ ListBase selected_orig = {NULL, NULL};
+ BMEditSelection *ese;
+ int edges_len = 0;
+ bool side = false;
+
+ /* first check all edges are OK */
+ for (ese = bm->selected.first; ese; ese = ese->next) {
+ if (ese->htype == BM_EDGE) {
+ edges_len += 1;
+ }
+ else {
+ return false;
+ }
+ }
+ /* if this is a mixed selection, bail out! */
+ if (bm->totedgesel != edges_len) {
+ return false;
+ }
+
+ SWAP(ListBase, bm->selected, selected_orig);
+
+ /* convert edge selection into 2 ordered loops (where the first edge ends up in the middle) */
+ for (ese = selected_orig.first; ese; ese = ese->next) {
+ BMEdge *e_curr = (BMEdge *)ese->ele;
+ BMEdge *e_prev = ese->prev ? (BMEdge *)ese->prev->ele : NULL;
+ BMLoop *l_curr;
+ BMLoop *l_prev;
+ BMVert *v;
+
+ if (e_prev) {
+ BMFace *f = BM_edge_pair_share_face_by_len(e_curr, e_prev, &l_curr, &l_prev, true);
+ if (f) {
+ if ((e_curr->v1 != l_curr->v) == (e_prev->v1 != l_prev->v)) {
+ side = !side;
+ }
+ }
+ else if (is_quad_flip_v3(e_curr->v1->co, e_curr->v2->co, e_prev->v2->co, e_prev->v1->co)) {
+ side = !side;
+ }
+ }
+
+ v = (&e_curr->v1)[side];
+ if (!bm->selected.last || (BMVert *)((BMEditSelection *)bm->selected.last)->ele != v) {
+ BM_select_history_store_notest(bm, v);
+ }
+
+ v = (&e_curr->v1)[!side];
+ if (!bm->selected.first || (BMVert *)((BMEditSelection *)bm->selected.first)->ele != v) {
+ BM_select_history_store_head_notest(bm, v);
+ }
+
+ e_prev = e_curr;
+ }
+
+ *r_selected = bm->selected;
+ bm->selected = selected_orig;
+
+ return true;
+}
static int edbm_vert_connect_path_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
bool is_pair = (em->bm->totvertsel == 2);
+ ListBase selected_orig = {NULL, NULL};
+ int retval;
/* when there is only 2 vertices, we can ignore selection order */
if (is_pair) {
return edbm_vert_connect_exec(C, op);
}
- if (bm_vert_connect_select_history(em->bm)) {
+ if (bm->selected.first) {
+ BMEditSelection *ese = bm->selected.first;
+ if (ese->htype == BM_EDGE) {
+ if (bm_vert_connect_select_history_edge_to_vert_path(bm, &selected_orig)) {
+ SWAP(ListBase, bm->selected, selected_orig);
+ }
+ }
+ }
+
+ if (bm_vert_connect_select_history(bm)) {
EDBM_selectmode_flush(em);
EDBM_update_generic(em, true, true);
-
- return OPERATOR_FINISHED;
+ retval = OPERATOR_FINISHED;
}
else {
BKE_report(op->reports, RPT_ERROR, "Invalid selection order");
- return OPERATOR_CANCELLED;
+ retval = OPERATOR_CANCELLED;
}
+
+ if (!BLI_listbase_is_empty(&selected_orig)) {
+ BM_select_history_clear(bm);
+ bm->selected = selected_orig;
+ }
+
+ return retval;
}
void MESH_OT_vert_connect_path(wmOperatorType *ot)
@@ -2049,9 +2132,7 @@ static int edbm_merge_exec(bContext *C, wmOperator *op)
ok = merge_firstlast(em, true, uvs, op);
break;
case 5:
- ok = true;
- if (!EDBM_op_callf(em, op, "collapse edges=%he", BM_ELEM_SELECT))
- ok = false;
+ ok = EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, uvs);
break;
default:
BLI_assert(0);
@@ -2408,7 +2489,7 @@ void MESH_OT_blend_from_shape(wmOperatorType *ot)
/* properties */
prop = RNA_def_enum(ot->srna, "shape", DummyRNA_NULL_items, 0, "Shape", "Shape key to use for blending");
RNA_def_enum_funcs(prop, shape_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_NEVER_UNLINK);
RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor", -2.0f, 2.0f);
RNA_def_boolean(ot->srna, "add", 1, "Add", "Add rather than blend between shapes");
}
@@ -3678,19 +3759,45 @@ static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- int dosharp, douvs, dovcols, domaterials;
- const float limit = RNA_float_get(op->ptr, "limit");
+ bool do_seam, do_sharp, do_uvs, do_vcols, do_materials;
+ float angle_face_threshold, angle_shape_threshold;
+ PropertyRNA *prop;
- dosharp = RNA_boolean_get(op->ptr, "sharp");
- douvs = RNA_boolean_get(op->ptr, "uvs");
- dovcols = RNA_boolean_get(op->ptr, "vcols");
- domaterials = RNA_boolean_get(op->ptr, "materials");
+ /* When joining exactly 2 faces, no limit.
+ * this is useful for one off joins while editing. */
+ prop = RNA_struct_find_property(op->ptr, "face_threshold");
+ if ((em->bm->totfacesel == 2) &&
+ (RNA_property_is_set(op->ptr, prop) == false))
+ {
+ angle_face_threshold = DEG2RADF(180.0f);
+ }
+ else {
+ angle_face_threshold = RNA_property_float_get(op->ptr, prop);
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "shape_threshold");
+ if ((em->bm->totfacesel == 2) &&
+ (RNA_property_is_set(op->ptr, prop) == false))
+ {
+ angle_shape_threshold = DEG2RADF(180.0f);
+ }
+ else {
+ angle_shape_threshold = RNA_property_float_get(op->ptr, prop);
+ }
+
+ do_seam = RNA_boolean_get(op->ptr, "seam");
+ do_sharp = RNA_boolean_get(op->ptr, "sharp");
+ do_uvs = RNA_boolean_get(op->ptr, "uvs");
+ do_vcols = RNA_boolean_get(op->ptr, "vcols");
+ do_materials = RNA_boolean_get(op->ptr, "materials");
if (!EDBM_op_call_and_selectf(
em, op,
"faces.out", true,
- "join_triangles faces=%hf limit=%f cmp_sharp=%b cmp_uvs=%b cmp_vcols=%b cmp_materials=%b",
- BM_ELEM_SELECT, limit, dosharp, douvs, dovcols, domaterials))
+ "join_triangles faces=%hf angle_face_threshold=%f angle_shape_threshold=%f "
+ "cmp_seam=%b cmp_sharp=%b cmp_uvs=%b cmp_vcols=%b cmp_materials=%b",
+ BM_ELEM_SELECT, angle_face_threshold, angle_shape_threshold,
+ do_seam, do_sharp, do_uvs, do_vcols, do_materials))
{
return OPERATOR_CANCELLED;
}
@@ -3704,12 +3811,19 @@ static void join_triangle_props(wmOperatorType *ot)
{
PropertyRNA *prop;
- prop = RNA_def_float_rotation(ot->srna, "limit", 0, NULL, 0.0f, DEG2RADF(180.0f),
- "Max Angle", "Angle Limit", 0.0f, DEG2RADF(180.0f));
+ prop = RNA_def_float_rotation(
+ ot->srna, "face_threshold", 0, NULL, 0.0f, DEG2RADF(180.0f),
+ "Max Face Angle", "Face angle limit", 0.0f, DEG2RADF(180.0f));
+ RNA_def_property_float_default(prop, DEG2RADF(40.0f));
+
+ prop = RNA_def_float_rotation(
+ ot->srna, "shape_threshold", 0, NULL, 0.0f, DEG2RADF(180.0f),
+ "Max Shape Angle", "Shape angle limit", 0.0f, DEG2RADF(180.0f));
RNA_def_property_float_default(prop, DEG2RADF(40.0f));
RNA_def_boolean(ot->srna, "uvs", 0, "Compare UVs", "");
RNA_def_boolean(ot->srna, "vcols", 0, "Compare VCols", "");
+ RNA_def_boolean(ot->srna, "seam", 0, "Compare Seam", "");
RNA_def_boolean(ot->srna, "sharp", 0, "Compare Sharp", "");
RNA_def_boolean(ot->srna, "materials", 0, "Compare Materials", "");
}
@@ -5072,11 +5186,16 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
/* Merge adjacent triangles */
if (RNA_boolean_get(op->ptr, "join_triangles")) {
- if (!EDBM_op_call_and_selectf(em, op,
- "faces.out", true,
- "join_triangles faces=%S limit=%f",
- &bmop, "geom.out",
- RNA_float_get(op->ptr, "limit")))
+ float angle_face_threshold = RNA_float_get(op->ptr, "face_threshold");
+ float angle_shape_threshold = RNA_float_get(op->ptr, "shape_threshold");
+
+ if (!EDBM_op_call_and_selectf(
+ em, op,
+ "faces.out", true,
+ "join_triangles faces=%S "
+ "angle_face_threshold=%f angle_shape_threshold=%f",
+ &bmop, "geom.out",
+ angle_face_threshold, angle_shape_threshold))
{
EDBM_op_finish(em, &bmop, op, true);
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 86cd75eed7a..517710405a0 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -37,6 +37,8 @@
#include "BLI_math.h"
#include "BLI_alloca.h"
+#include "BLI_buffer.h"
+#include "BLI_kdtree.h"
#include "BLI_listbase.h"
#include "BKE_DerivedMesh.h"
@@ -607,13 +609,15 @@ void undo_push_mesh(bContext *C, const char *name)
BMEditMesh *em = BKE_editmesh_from_object(obedit);
em->ob = obedit;
- undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL);
+ undo_editmode_push(C, name, CTX_data_edit_object, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL);
}
/**
* Return a new UVVertMap from the editmesh
*/
-UvVertMap *BM_uv_vert_map_create(BMesh *bm, bool use_select, const float limit[2])
+UvVertMap *BM_uv_vert_map_create(
+ BMesh *bm,
+ const float limit[2], const bool use_select, const bool use_winding)
{
BMVert *ev;
BMFace *efa;
@@ -625,11 +629,14 @@ UvVertMap *BM_uv_vert_map_create(BMesh *bm, bool use_select, const float limit[2
/* MTexPoly *tf; */ /* UNUSED */
MLoopUV *luv;
unsigned int a;
- int totverts, i, totuv;
+ int totverts, i, totuv, totfaces;
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ bool *winding = NULL;
+ BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
+ totfaces = bm->totface;
totverts = bm->totvert;
totuv = 0;
@@ -650,35 +657,46 @@ UvVertMap *BM_uv_vert_map_create(BMesh *bm, bool use_select, const float limit[2
vmap->vert = (UvMapVert **)MEM_callocN(sizeof(*vmap->vert) * totverts, "UvMapVert_pt");
buf = vmap->buf = (UvMapVert *)MEM_callocN(sizeof(*vmap->buf) * totuv, "UvMapVert");
+ if (use_winding) {
+ winding = MEM_callocN(sizeof(*winding) * totfaces, "winding");
+ }
if (!vmap->vert || !vmap->buf) {
BKE_mesh_uv_vert_map_free(vmap);
return NULL;
}
- a = 0;
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, a) {
if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- i = 0;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ float (*tf_uv)[2];
+
+ if (use_winding) {
+ tf_uv = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa->len);
+ }
+
+ BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) {
buf->tfindex = i;
buf->f = a;
buf->separate = 0;
buf->next = vmap->vert[BM_elem_index_get(l->v)];
vmap->vert[BM_elem_index_get(l->v)] = buf;
-
buf++;
- i++;
+
+ if (use_winding) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ copy_v2_v2(tf_uv[i], luv->uv);
+ }
}
- }
- a++;
+ if (use_winding) {
+ winding[a] = cross_poly_v2((const float (*)[2])tf_uv, efa->len) > 0;
+ }
+ }
}
/* sort individual uvs for each vert */
- a = 0;
- BM_ITER_MESH (ev, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, a) {
UvMapVert *newvlist = NULL, *vlist = vmap->vert[a];
UvMapVert *iterv, *v, *lastv, *next;
float *uv, *uv2, uvdiff[2];
@@ -710,7 +728,9 @@ UvVertMap *BM_uv_vert_map_create(BMesh *bm, bool use_select, const float limit[2
sub_v2_v2v2(uvdiff, uv2, uv);
- if (fabsf(uvdiff[0]) < limit[0] && fabsf(uvdiff[1]) < limit[1]) {
+ if (fabsf(uvdiff[0]) < limit[0] && fabsf(uvdiff[1]) < limit[1] &&
+ (!use_winding || winding[iterv->f] == winding[v->f]))
+ {
if (lastv) lastv->next = next;
else vlist = next;
iterv->next = newvlist;
@@ -727,9 +747,14 @@ UvVertMap *BM_uv_vert_map_create(BMesh *bm, bool use_select, const float limit[2
}
vmap->vert[a] = newvlist;
- a++;
}
+ if (use_winding) {
+ MEM_freeN(winding);
+ }
+
+ BLI_buffer_free(&tf_uv_buf);
+
return vmap;
}
@@ -752,29 +777,20 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
/* vars from original func */
UvElementMap *element_map;
UvElement *buf;
- UvElement *islandbuf;
- /* island number for faces */
- int *island_number;
+ bool *winding;
+ BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
MLoopUV *luv;
- int totverts, i, totuv, j, nislands = 0, islandbufsize = 0;
-
- unsigned int *map;
- BMFace **stack;
- int stacksize = 0;
+ int totverts, totfaces, i, totuv, j;
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
+ totfaces = bm->totface;
totverts = bm->totvert;
totuv = 0;
- island_number = MEM_mallocN(sizeof(*stack) * bm->totface, "uv_island_number_face");
- if (!island_number) {
- return NULL;
- }
-
/* generate UvElement array */
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
@@ -783,28 +799,23 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
}
if (totuv == 0) {
- MEM_freeN(island_number);
return NULL;
}
+
element_map = (UvElementMap *)MEM_callocN(sizeof(*element_map), "UvElementMap");
- if (!element_map) {
- MEM_freeN(island_number);
- return NULL;
- }
element_map->totalUVs = totuv;
element_map->vert = (UvElement **)MEM_callocN(sizeof(*element_map->vert) * totverts, "UvElementVerts");
buf = element_map->buf = (UvElement *)MEM_callocN(sizeof(*element_map->buf) * totuv, "UvElement");
- if (!element_map->vert || !element_map->buf) {
- BM_uv_element_map_free(element_map);
- MEM_freeN(island_number);
- return NULL;
- }
+ winding = MEM_mallocN(sizeof(*winding) * totfaces, "winding");
+
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, j) {
+
+ winding[j] = false;
- j = 0;
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- island_number[j++] = INVALID_ISLAND;
if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ float (*tf_uv)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa->len);
+
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
buf->l = l;
buf->separate = 0;
@@ -814,14 +825,18 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
buf->next = element_map->vert[BM_elem_index_get(l->v)];
element_map->vert[BM_elem_index_get(l->v)] = buf;
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ copy_v2_v2(tf_uv[i], luv->uv);
+
buf++;
}
+
+ winding[j] = cross_poly_v2((const float (*)[2])tf_uv, efa->len) > 0;
}
}
/* sort individual uvs for each vert */
- i = 0;
- BM_ITER_MESH (ev, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, i) {
UvElement *newvlist = NULL, *vlist = element_map->vert[i];
UvElement *iterv, *v, *lastv, *next;
float *uv, *uv2, uvdiff[2];
@@ -848,7 +863,9 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
sub_v2_v2v2(uvdiff, uv2, uv);
- if (fabsf(uvdiff[0]) < STD_UV_CONNECT_LIMIT && fabsf(uvdiff[1]) < STD_UV_CONNECT_LIMIT) {
+ if (fabsf(uvdiff[0]) < STD_UV_CONNECT_LIMIT && fabsf(uvdiff[1]) < STD_UV_CONNECT_LIMIT &&
+ winding[BM_elem_index_get(iterv->l->f)] == winding[BM_elem_index_get(v->l->f)])
+ {
if (lastv) lastv->next = next;
else vlist = next;
iterv->next = newvlist;
@@ -865,14 +882,26 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
}
element_map->vert[i] = newvlist;
- i++;
}
+ MEM_freeN(winding);
+
if (do_islands) {
+ unsigned int *map;
+ BMFace **stack;
+ int stacksize = 0;
+ UvElement *islandbuf;
+ /* island number for faces */
+ int *island_number = NULL;
+
+ int nislands = 0, islandbufsize = 0;
+
/* map holds the map from current vmap->buf to the new, sorted map */
map = MEM_mallocN(sizeof(*map) * totuv, "uvelement_remap");
stack = MEM_mallocN(sizeof(*stack) * bm->totface, "uv_island_face_stack");
islandbuf = MEM_callocN(sizeof(*islandbuf) * totuv, "uvelement_island_buffer");
+ island_number = MEM_mallocN(sizeof(*island_number) * totfaces, "uv_island_number_face");
+ copy_vn_i(island_number, totfaces, INVALID_ISLAND);
/* at this point, every UvElement in vert points to a UvElement sharing the same vertex. Now we should sort uv's in islands. */
for (i = 0; i < totuv; i++) {
@@ -921,6 +950,8 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
}
}
+ MEM_freeN(island_number);
+
/* remap */
for (i = 0; i < bm->totvert; i++) {
/* important since we may do selection only. Some of these may be NULL */
@@ -929,14 +960,6 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
}
element_map->islandIndices = MEM_callocN(sizeof(*element_map->islandIndices) * nislands, "UvElementMap_island_indices");
- if (!element_map->islandIndices) {
- MEM_freeN(islandbuf);
- MEM_freeN(stack);
- MEM_freeN(map);
- BM_uv_element_map_free(element_map);
- MEM_freeN(island_number);
- }
-
j = 0;
for (i = 0; i < totuv; i++) {
UvElement *element = element_map->buf[i].next;
@@ -958,7 +981,8 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, const bool selected, const boo
MEM_freeN(stack);
MEM_freeN(map);
}
- MEM_freeN(island_number);
+
+ BLI_buffer_free(&tf_uv_buf);
return element_map;
}
@@ -1036,26 +1060,19 @@ static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index)
}
/**
- * [note: I've decided to use ideasman's code for non-editmode stuff, but since
- * it has a big "not for editmode!" disclaimer, I'm going to keep what I have here
- * - joeedh]
+ * Mirror editing API, usage:
*
- * x-mirror editing api. usage:
+ * \code{.c}
+ * EDBM_verts_mirror_cache_begin(em, ...);
*
- * EDBM_verts_mirror_cache_begin(em);
- * ...
- * ...
- * BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- * mirrorv = EDBM_verts_mirror_get(em, v);
- * }
- * ...
- * ...
- * EDBM_verts_mirror_cache_end(em);
+ * BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ * v_mirror = EDBM_verts_mirror_get(em, v);
+ * e_mirror = EDBM_verts_mirror_get_edge(em, e);
+ * f_mirror = EDBM_verts_mirror_get_face(em, f);
+ * }
*
- * \param use_self Allow a vertex to reference its self.
- * \param use_select Only cache selected verts.
- *
- * \note why do we only allow x axis mirror editing?
+ * EDBM_verts_mirror_cache_end(em);
+ * \endcode
*/
/* BM_SEARCH_MAXDIST is too big, copied from 2.6x MOC_THRESH, should become a
@@ -1080,9 +1097,10 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
BMVert *v;
int cd_vmirr_offset;
int i;
+ const float maxdist_sq = SQUARE(maxdist);
/* one or the other is used depending if topo is enabled */
- struct BMBVHTree *tree = NULL;
+ KDTree *tree = NULL;
MirrTopoStore_t mesh_topo_store = {NULL, -1, -1, -1};
BM_mesh_elem_table_ensure(bm, BM_VERT);
@@ -1107,7 +1125,11 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
ED_mesh_mirrtopo_init(me, -1, &mesh_topo_store, true);
}
else {
- tree = BKE_bmbvh_new_from_editmesh(em, 0, NULL, false);
+ tree = BLI_kdtree_new(bm->totvert);
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ BLI_kdtree_insert(tree, i, v->co);
+ }
+ BLI_kdtree_balance(tree);
}
#define VERT_INTPTR(_v, _i) r_index ? &r_index[_i] : BM_ELEM_CD_GET_VOID_P(_v, cd_vmirr_offset);
@@ -1127,10 +1149,19 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
v_mirr = cache_mirr_intptr_as_bmvert(mesh_topo_store.index_lookup, i);
}
else {
+ int i_mirr;
float co[3];
copy_v3_v3(co, v->co);
co[axis] *= -1.0f;
- v_mirr = BKE_bmbvh_find_vert_closest(tree, co, maxdist);
+
+ v_mirr = NULL;
+ i_mirr = BLI_kdtree_find_nearest(tree, co, NULL);
+ if (i_mirr != -1) {
+ BMVert *v_test = BM_vert_at_index(bm, i_mirr);
+ if (len_squared_v3v3(co, v_test->co) < maxdist_sq) {
+ v_mirr = v_test;
+ }
+ }
}
if (v_mirr && (use_self || (v_mirr != v))) {
@@ -1152,7 +1183,7 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
ED_mesh_mirrtopo_free(&mesh_topo_store);
}
else {
- BKE_bmbvh_free(tree);
+ BLI_kdtree_free(tree);
}
}
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 86991d7dfeb..a2054a5f43c 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -429,7 +429,7 @@ int ED_mesh_color_add(Mesh *me, const char *name, const bool active_set)
/* copy data from active vertex color layer */
if (layernum) {
const int layernum_dst = CustomData_get_active_layer(&em->bm->ldata, CD_MLOOPCOL);
- BM_data_layer_copy(em->bm, &em->bm->ldata, CD_MLOOPCOL, layernum, layernum_dst);
+ BM_data_layer_copy(em->bm, &em->bm->ldata, CD_MLOOPCOL, layernum_dst, layernum);
}
if (active_set || layernum == 0) {
CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum);
@@ -748,7 +748,7 @@ static int mesh_customdata_clear_exec__internal(bContext *C,
}
/* Clear Mask */
-static int mesh_customdata_clear_mask_poll(bContext *C)
+static int mesh_customdata_mask_clear_poll(bContext *C)
{
Object *ob = ED_object_context(C);
if (ob && ob->type == OB_MESH) {
@@ -772,7 +772,7 @@ static int mesh_customdata_clear_mask_poll(bContext *C)
}
return false;
}
-static int mesh_customdata_clear_mask_exec(bContext *C, wmOperator *UNUSED(op))
+static int mesh_customdata_mask_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
int ret_a = mesh_customdata_clear_exec__internal(C, BM_VERT, CD_PAINT_MASK);
int ret_b = mesh_customdata_clear_exec__internal(C, BM_LOOP, CD_GRID_PAINT_MASK);
@@ -787,24 +787,27 @@ static int mesh_customdata_clear_mask_exec(bContext *C, wmOperator *UNUSED(op))
}
}
-void MESH_OT_customdata_clear_mask(wmOperatorType *ot)
+void MESH_OT_customdata_mask_clear(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Clear Sculpt-Mask Data";
- ot->idname = "MESH_OT_customdata_clear_mask";
+ ot->idname = "MESH_OT_customdata_mask_clear";
ot->description = "Clear vertex sculpt masking data from the mesh";
/* api callbacks */
- ot->exec = mesh_customdata_clear_mask_exec;
- ot->poll = mesh_customdata_clear_mask_poll;
+ ot->exec = mesh_customdata_mask_clear_exec;
+ ot->poll = mesh_customdata_mask_clear_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* Clear Skin */
-static int mesh_customdata_clear_skin_poll(bContext *C)
+/**
+ * Clear Skin
+ * \return -1 invalid state, 0 no skin, 1 has skin.
+ */
+static int mesh_customdata_skin_state(bContext *C)
{
Object *ob = ED_object_context(C);
@@ -812,28 +815,65 @@ static int mesh_customdata_clear_skin_poll(bContext *C)
Mesh *me = ob->data;
if (me->id.lib == NULL) {
CustomData *data = GET_CD_DATA(me, vdata);
- if (CustomData_has_layer(data, CD_MVERT_SKIN)) {
- return true;
- }
+ return CustomData_has_layer(data, CD_MVERT_SKIN);
}
}
- return false;
+ return -1;
}
-static int mesh_customdata_clear_skin_exec(bContext *C, wmOperator *UNUSED(op))
+
+static int mesh_customdata_skin_add_poll(bContext *C)
+{
+ return (mesh_customdata_skin_state(C) == 0);
+}
+
+static int mesh_customdata_skin_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_object_context(C);
+ Mesh *me = ob->data;
+
+ BKE_mesh_ensure_skin_customdata(me);
+
+ DAG_id_tag_update(&me->id, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_customdata_skin_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Skin Data";
+ ot->idname = "MESH_OT_customdata_skin_add";
+ ot->description = "Add a vertex skin layer";
+
+ /* api callbacks */
+ ot->exec = mesh_customdata_skin_add_exec;
+ ot->poll = mesh_customdata_skin_add_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int mesh_customdata_skin_clear_poll(bContext *C)
+{
+ return (mesh_customdata_skin_state(C) == 1);
+}
+
+static int mesh_customdata_skin_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
return mesh_customdata_clear_exec__internal(C, BM_VERT, CD_MVERT_SKIN);
}
-void MESH_OT_customdata_clear_skin(wmOperatorType *ot)
+void MESH_OT_customdata_skin_clear(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Clear Skin Data";
- ot->idname = "MESH_OT_customdata_clear_skin";
+ ot->idname = "MESH_OT_customdata_skin_clear";
ot->description = "Clear vertex skin layer";
/* api callbacks */
- ot->exec = mesh_customdata_clear_skin_exec;
- ot->poll = mesh_customdata_clear_skin_poll;
+ ot->exec = mesh_customdata_skin_clear_exec;
+ ot->poll = mesh_customdata_skin_clear_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 8611872a1a0..9226146bc51 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -34,14 +34,9 @@
#ifndef __MESH_INTERN_H__
#define __MESH_INTERN_H__
-struct BMEdge;
struct BMEditMesh;
-struct BMFace;
-struct BMHeader;
struct BMOperator;
-struct BMesh;
struct EnumPropertyItem;
-struct ViewContext;
struct bContext;
struct wmKeyConfig;
struct wmKeyMap;
@@ -237,8 +232,9 @@ void MESH_OT_uv_texture_remove(struct wmOperatorType *ot);
void MESH_OT_vertex_color_add(struct wmOperatorType *ot);
void MESH_OT_vertex_color_remove(struct wmOperatorType *ot);
/* no create_mask yet */
-void MESH_OT_customdata_clear_mask(struct wmOperatorType *ot);
-void MESH_OT_customdata_clear_skin(struct wmOperatorType *ot);
+void MESH_OT_customdata_mask_clear(struct wmOperatorType *ot);
+void MESH_OT_customdata_skin_add(struct wmOperatorType *ot);
+void MESH_OT_customdata_skin_clear(struct wmOperatorType *ot);
void MESH_OT_customdata_custom_splitnormals_add(struct wmOperatorType *ot);
void MESH_OT_customdata_custom_splitnormals_clear(struct wmOperatorType *ot);
void MESH_OT_drop_named_image(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c
index 440ab14dacd..0d9f6f2a0be 100644
--- a/source/blender/editors/mesh/mesh_navmesh.c
+++ b/source/blender/editors/mesh/mesh_navmesh.c
@@ -325,7 +325,7 @@ static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh,
if (createob) {
/* create new object */
- obedit = ED_object_add_type(C, OB_MESH, co, rot, false, lay);
+ obedit = ED_object_add_type(C, OB_MESH, "Navmesh", co, rot, false, lay);
}
else {
obedit = base->object;
@@ -429,7 +429,6 @@ static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh,
obedit->gameflag &= ~OB_COLLISION;
obedit->gameflag |= OB_NAVMESH;
obedit->body_type = OB_BODY_TYPE_NAVMESH;
- rename_id((ID *)obedit, "Navmesh");
}
BKE_mesh_ensure_navmesh(obedit->data);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 2855af063c0..197df48d688 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -151,8 +151,9 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_uv_texture_remove);
WM_operatortype_append(MESH_OT_vertex_color_add);
WM_operatortype_append(MESH_OT_vertex_color_remove);
- WM_operatortype_append(MESH_OT_customdata_clear_mask);
- WM_operatortype_append(MESH_OT_customdata_clear_skin);
+ WM_operatortype_append(MESH_OT_customdata_mask_clear);
+ WM_operatortype_append(MESH_OT_customdata_skin_add);
+ WM_operatortype_append(MESH_OT_customdata_skin_clear);
WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_add);
WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_clear);
WM_operatortype_append(MESH_OT_drop_named_image);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 00d79b22e99..2491685161c 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -1082,11 +1082,11 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], unsigned int
* on an edge in the backbuf, we can still select a face */
float dummy_dist;
- *index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totpoly + 1, &dummy_dist, 0, NULL, NULL);
+ *index = ED_view3d_backbuf_sample_rect(&vc, mval, size, 1, me->totpoly + 1, &dummy_dist);
}
else {
/* sample only on the exact position */
- *index = view3d_sample_backbuf(&vc, mval[0], mval[1]);
+ *index = ED_view3d_backbuf_sample(&vc, mval[0], mval[1]);
}
if ((*index) == 0 || (*index) > (unsigned int)me->totpoly)
@@ -1248,11 +1248,11 @@ bool ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], unsigned int
* on an face in the backbuf, we can still select a vert */
float dummy_dist;
- *index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totvert + 1, &dummy_dist, 0, NULL, NULL);
+ *index = ED_view3d_backbuf_sample_rect(&vc, mval, size, 1, me->totvert + 1, &dummy_dist);
}
else {
/* sample only on the exact position */
- *index = view3d_sample_backbuf(&vc, mval[0], mval[1]);
+ *index = ED_view3d_backbuf_sample(&vc, mval[0], mval[1]);
}
if ((*index) == 0 || (*index) > (unsigned int)me->totvert)
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 24cac5b9b70..4e4e3214798 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -740,5 +740,5 @@ static void *get_data(bContext *C)
/* this is undo system for MetaBalls */
void undo_push_mball(bContext *C, const char *name)
{
- undo_editmode_push(C, name, get_data, free_undoMball, undoMball_to_editMball, editMball_to_undoMball, NULL);
+ undo_editmode_push(C, name, CTX_data_edit_object, get_data, free_undoMball, undoMball_to_editMball, editMball_to_undoMball, NULL);
}
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 99b351561c7..b8c66fdd109 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -57,6 +57,7 @@
#include "BLF_translation.h"
+#include "BKE_action.h"
#include "BKE_anim.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
@@ -394,8 +395,11 @@ bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, const char view
/* For object add primitive operators.
* Do not call undo push in this function (users of this function have to). */
-Object *ED_object_add_type(bContext *C, int type, const float loc[3], const float rot[3],
- bool enter_editmode, unsigned int layer)
+Object *ED_object_add_type(
+ bContext *C,
+ int type, const char *name,
+ const float loc[3], const float rot[3],
+ bool enter_editmode, unsigned int layer)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -406,7 +410,7 @@ Object *ED_object_add_type(bContext *C, int type, const float loc[3], const floa
ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); /* freedata, and undo */
/* deselects all, sets scene->basact */
- ob = BKE_object_add(bmain, scene, type);
+ ob = BKE_object_add(bmain, scene, type, name);
BASACT->lay = ob->lay = layer;
/* editor level activate, notifiers */
ED_base_object_activate(C, BASACT);
@@ -447,7 +451,7 @@ static int object_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
radius = RNA_float_get(op->ptr, "radius");
- ob = ED_object_add_type(C, RNA_enum_get(op->ptr, "type"), loc, rot, enter_editmode, layer);
+ ob = ED_object_add_type(C, RNA_enum_get(op->ptr, "type"), NULL, loc, rot, enter_editmode, layer);
if (ob->type == OB_LATTICE) {
/* lattice is a special case!
@@ -504,9 +508,9 @@ static int effector_add_exec(bContext *C, wmOperator *op)
if (type == PFIELD_GUIDE) {
Curve *cu;
- ob = ED_object_add_type(C, OB_CURVE, loc, rot, false, layer);
+ const char *name = CTX_DATA_(BLF_I18NCONTEXT_ID_OBJECT, "CurveGuide");
+ ob = ED_object_add_type(C, OB_CURVE, name, loc, rot, false, layer);
- rename_id(&ob->id, CTX_DATA_(BLF_I18NCONTEXT_ID_OBJECT, "CurveGuide"));
cu = ob->data;
cu->flag |= CU_PATH | CU_3D;
ED_object_editmode_enter(C, 0);
@@ -516,9 +520,9 @@ static int effector_add_exec(bContext *C, wmOperator *op)
ED_object_editmode_exit(C, EM_FREEDATA);
}
else {
- ob = ED_object_add_type(C, OB_EMPTY, loc, rot, false, layer);
+ const char *name = CTX_DATA_(BLF_I18NCONTEXT_ID_OBJECT, "Field");
+ ob = ED_object_add_type(C, OB_EMPTY, name, loc, rot, false, layer);
BKE_object_obdata_size_init(ob, dia);
- rename_id(&ob->id, CTX_DATA_(BLF_I18NCONTEXT_ID_OBJECT, "Field"));
if (ELEM(type, PFIELD_WIND, PFIELD_VORTEX))
ob->empty_drawtype = OB_SINGLE_ARROW;
}
@@ -569,7 +573,7 @@ static int object_camera_add_exec(bContext *C, wmOperator *op)
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_CAMERA, loc, rot, false, layer);
+ ob = ED_object_add_type(C, OB_CAMERA, NULL, loc, rot, false, layer);
if (v3d) {
if (v3d->camera == NULL)
@@ -626,7 +630,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
if (obedit == NULL || obedit->type != OB_MBALL) {
- obedit = ED_object_add_type(C, OB_MBALL, loc, rot, true, layer);
+ obedit = ED_object_add_type(C, OB_MBALL, NULL, loc, rot, true, layer);
newob = true;
}
else {
@@ -685,7 +689,7 @@ static int object_add_text_exec(bContext *C, wmOperator *op)
if (obedit && obedit->type == OB_FONT)
return OPERATOR_CANCELLED;
- obedit = ED_object_add_type(C, OB_FONT, loc, rot, enter_editmode, layer);
+ obedit = ED_object_add_type(C, OB_FONT, NULL, loc, rot, enter_editmode, layer);
BKE_object_obdata_size_init(obedit, RNA_float_get(op->ptr, "radius"));
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit);
@@ -729,7 +733,7 @@ static int object_armature_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
if ((obedit == NULL) || (obedit->type != OB_ARMATURE)) {
- obedit = ED_object_add_type(C, OB_ARMATURE, loc, rot, true, layer);
+ obedit = ED_object_add_type(C, OB_ARMATURE, NULL, loc, rot, true, layer);
ED_object_editmode_enter(C, 0);
newob = true;
}
@@ -786,7 +790,7 @@ static int object_empty_add_exec(bContext *C, wmOperator *op)
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_EMPTY, loc, rot, false, layer);
+ ob = ED_object_add_type(C, OB_EMPTY, NULL, loc, rot, false, layer);
BKE_object_empty_draw_type_set(ob, type);
BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius"));
@@ -846,7 +850,7 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv
if (!ED_object_add_generic_get_opts(C, op, 'Z', NULL, rot, NULL, &layer, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_EMPTY, NULL, rot, false, layer);
+ ob = ED_object_add_type(C, OB_EMPTY, NULL, NULL, rot, false, layer);
/* add under the mouse */
ED_object_location_from_view(C, ob->loc);
@@ -916,13 +920,11 @@ static int object_lamp_add_exec(bContext *C, wmOperator *op)
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_LAMP, loc, rot, false, layer);
+ ob = ED_object_add_type(C, OB_LAMP, get_lamp_defname(type), loc, rot, false, layer);
BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius"));
la = (Lamp *)ob->data;
la->type = type;
- rename_id(&ob->id, get_lamp_defname(type));
- rename_id(&la->id, get_lamp_defname(type));
if (BKE_scene_use_new_shading_nodes(scene)) {
ED_node_shader_default(C, &la->id);
@@ -988,8 +990,7 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
if (group) {
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Object *ob = ED_object_add_type(C, OB_EMPTY, loc, rot, false, layer);
- rename_id(&ob->id, group->id.name + 2);
+ Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, loc, rot, false, layer);
ob->dup_group = group;
ob->transflag |= OB_DUPLIGROUP;
id_lib_extern(&group->id);
@@ -1044,14 +1045,14 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op)
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_SPEAKER, loc, rot, false, layer);
+ ob = ED_object_add_type(C, OB_SPEAKER, NULL, loc, rot, false, layer);
/* to make it easier to start using this immediately in NLA, a default sound clip is created
* ready to be moved around to retime the sound and/or make new sound clips
*/
{
/* create new data for NLA hierarchy */
- AnimData *adt = BKE_id_add_animdata(&ob->id);
+ AnimData *adt = BKE_animdata_add_id(&ob->id);
NlaTrack *nlt = add_nlatrack(adt, NULL);
NlaStrip *strip = add_nla_soundstrip(scene, ob->data);
strip->start = CFRA;
@@ -1358,7 +1359,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
basen->object = ob;
/* make sure apply works */
- BKE_free_animdata(&ob->id);
+ BKE_animdata_free(&ob->id);
ob->adt = NULL;
/* Proxies are not to be copied. */
@@ -1976,7 +1977,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
/* duplicates using userflags */
if (dupflag & USER_DUP_ACT) {
- BKE_copy_animdata_id_action(&obn->id);
+ BKE_animdata_copy_id_action(&obn->id);
}
if (dupflag & USER_DUP_MAT) {
@@ -1989,7 +1990,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
id->us--;
if (dupflag & USER_DUP_ACT) {
- BKE_copy_animdata_id_action(&obn->mat[a]->id);
+ BKE_animdata_copy_id_action(&obn->mat[a]->id);
}
}
}
@@ -2004,7 +2005,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
psys->part = BKE_particlesettings_copy(psys->part);
if (dupflag & USER_DUP_ACT) {
- BKE_copy_animdata_id_action(&psys->part->id);
+ BKE_animdata_copy_id_action(&psys->part->id);
}
id->us--;
@@ -2082,7 +2083,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
case OB_ARMATURE:
DAG_id_tag_update(&obn->id, OB_RECALC_DATA);
if (obn->pose)
- obn->pose->flag |= POSE_RECALC;
+ BKE_pose_tag_recalc(bmain, obn->pose);
if (dupflag & USER_DUP_ARM) {
ID_NEW_US2(obn->data)
else {
@@ -2132,9 +2133,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
if (dupflag & USER_DUP_ACT) {
bActuator *act;
- BKE_copy_animdata_id_action((ID *)obn->data);
+ BKE_animdata_copy_id_action((ID *)obn->data);
if (key) {
- BKE_copy_animdata_id_action((ID *)key);
+ BKE_animdata_copy_id_action((ID *)key);
}
/* Update the duplicated action in the action actuators */
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 97cb45daae3..b382fbafcfd 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -574,6 +574,7 @@ static int bake(
float *result = NULL;
BakePixel *pixel_array_low = NULL;
+ BakePixel *pixel_array_high = NULL;
const bool is_save_internal = (save_mode == R_BAKE_SAVE_INTERNAL);
const bool is_noncolor = is_noncolor_pass(pass_type);
@@ -682,10 +683,13 @@ static int bake(
}
pixel_array_low = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly");
+ pixel_array_high = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly");
result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels");
/* get the mesh as it arrives in the renderer */
- me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
+ me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
+ BKE_mesh_split_faces(me_low);
+ BKE_mesh_tessface_ensure(me_low);
/* populate the pixel array with the face data */
if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false)
@@ -700,7 +704,9 @@ static int bake(
/* prepare cage mesh */
if (ob_cage) {
- me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 1, 0);
+ me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 0, 0);
+ BKE_mesh_split_faces(me_cage);
+ BKE_mesh_tessface_ensure(me_cage);
if (me_low->totface != me_cage->totface) {
BKE_report(reports, RPT_ERROR,
"Invalid cage object, the cage mesh must have the same number "
@@ -732,7 +738,9 @@ static int bake(
ob_low->modifiers = modifiers_tmp;
/* get the cage mesh as it arrives in the renderer */
- me_cage = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
+ me_cage = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
+ BKE_mesh_split_faces(me_cage);
+ BKE_mesh_tessface_ensure(me_cage);
RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer);
}
@@ -749,8 +757,6 @@ static int bake(
/* initialize highpoly_data */
highpoly[i].ob = ob_iter;
highpoly[i].restrict_flag = ob_iter->restrictflag;
- highpoly[i].pixel_array = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly");
-
/* triangulating so BVH returns the primitive_id that will be used for rendering */
highpoly[i].tri_mod = ED_object_modifier_add(
@@ -760,18 +766,16 @@ static int bake(
tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED;
tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP;
- highpoly[i].me = BKE_mesh_new_from_object(bmain, scene, highpoly[i].ob, 1, 2, 1, 0);
+ highpoly[i].me = BKE_mesh_new_from_object(bmain, scene, highpoly[i].ob, 1, 2, 0, 0);
highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER;
+ BKE_mesh_split_faces(highpoly[i].me);
+ BKE_mesh_tessface_ensure(highpoly[i].me);
/* lowpoly to highpoly transformation matrix */
copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat);
invert_m4_m4(highpoly[i].imat, highpoly[i].obmat);
- /* rotation */
- normalize_m4_m4(highpoly[i].rotmat, highpoly[i].imat);
- zero_v3(highpoly[i].rotmat[3]);
- if (is_negative_m4(highpoly[i].rotmat))
- negate_mat3_m4(highpoly[i].rotmat);
+ highpoly[i].is_flip_object = is_negative_m4(highpoly[i].ob->obmat);
i++;
}
@@ -782,7 +786,7 @@ static int bake(
/* populate the pixel arrays with the corresponding face data for each high poly object */
if (!RE_bake_pixels_populate_from_objects(
- me_low, pixel_array_low, highpoly, tot_highpoly, num_pixels, ob_cage != NULL,
+ me_low, pixel_array_low, pixel_array_high, highpoly, tot_highpoly, num_pixels, ob_cage != NULL,
cage_extrusion, ob_low->obmat, (ob_cage ? ob_cage->obmat : ob_low->obmat), me_cage))
{
BKE_report(reports, RPT_ERROR, "Error handling selected objects");
@@ -791,8 +795,8 @@ static int bake(
/* the baking itself */
for (i = 0; i < tot_highpoly; i++) {
- ok = RE_bake_engine(re, highpoly[i].ob, highpoly[i].pixel_array, num_pixels,
- depth, pass_type, result);
+ ok = RE_bake_engine(re, highpoly[i].ob, i, pixel_array_high,
+ num_pixels, depth, pass_type, result);
if (!ok) {
BKE_reportf(reports, RPT_ERROR, "Error baking from object \"%s\"", highpoly[i].ob->id.name + 2);
goto cage_cleanup;
@@ -818,7 +822,7 @@ cage_cleanup:
ob_low->restrictflag &= ~OB_RESTRICT_RENDER;
if (RE_bake_has_engine(re)) {
- ok = RE_bake_engine(re, ob_low, pixel_array_low, num_pixels, depth, pass_type, result);
+ ok = RE_bake_engine(re, ob_low, 0, pixel_array_low, num_pixels, depth, pass_type, result);
}
else {
BKE_report(reports, RPT_ERROR, "Current render engine does not support baking");
@@ -867,7 +871,9 @@ cage_cleanup:
md->mode &= ~eModifierMode_Render;
}
- me_nores = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
+ me_nores = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
+ BKE_mesh_split_faces(me_nores);
+ BKE_mesh_tessface_ensure(me_nores);
RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer);
RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle, ob_low->obmat);
@@ -919,7 +925,7 @@ cage_cleanup:
BakeData *bake = &scene->r.bake;
char name[FILE_MAX];
- BKE_image_path_from_imtype(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false);
+ BKE_image_path_from_imtype(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false, NULL);
if (is_automatic_name) {
BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_");
@@ -980,9 +986,6 @@ cleanup:
for (i = 0; i < tot_highpoly; i++) {
highpoly[i].ob->restrictflag = highpoly[i].restrict_flag;
- if (highpoly[i].pixel_array)
- MEM_freeN(highpoly[i].pixel_array);
-
if (highpoly[i].tri_mod)
ED_object_modifier_remove(reports, bmain, highpoly[i].ob, highpoly[i].tri_mod);
@@ -1000,6 +1003,9 @@ cleanup:
if (pixel_array_low)
MEM_freeN(pixel_array_low);
+ if (pixel_array_high)
+ MEM_freeN(pixel_array_high);
+
if (bake_images.data)
MEM_freeN(bake_images.data);
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 97d926761b5..e14674ef517 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -226,7 +226,7 @@ static void update_pyconstraint_cb(void *arg1, void *arg2)
/* helper function for add_constriant - sets the last target for the active constraint */
static void set_constraint_nth_target(bConstraint *con, Object *target, const char subtarget[], int index)
{
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
int num_targets, i;
@@ -260,17 +260,221 @@ static void set_constraint_nth_target(bConstraint *con, Object *target, const ch
/* ------------- Constraint Sanity Testing ------------------- */
-/* checks validity of object pointers, and NULLs,
- * if Bone doesnt exist it sets the CONSTRAINT_DISABLE flag.
- */
-static void test_constraints(Object *owner, bPoseChannel *pchan)
+static void test_constraint(Object *owner, bPoseChannel *pchan, bConstraint *con, int type)
+{
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+ bool check_targets = true;
+
+ /* clear disabled-flag first */
+ con->flag &= ~CONSTRAINT_DISABLE;
+
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ bKinematicConstraint *data = con->data;
+
+ /* bad: we need a separate set of checks here as poletarget is
+ * optional... otherwise poletarget must exist too or else
+ * the constraint is deemed invalid
+ */
+ /* default IK check ... */
+ if (BKE_object_exists_check(data->tar) == 0) {
+ data->tar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (data->tar == owner) {
+ if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->subtarget)) {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+
+ if (data->poletar) {
+ if (BKE_object_exists_check(data->poletar) == 0) {
+ data->poletar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (data->poletar == owner) {
+ if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->polesubtarget)) {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+ }
+ /* ... can be overwritten here */
+ BIK_test_constraint(owner, con);
+ /* targets have already been checked for this */
+ check_targets = false;
+ }
+ else if (con->type == CONSTRAINT_TYPE_PIVOT) {
+ bPivotConstraint *data = con->data;
+
+ /* target doesn't have to exist, but if it is non-null, it must exist! */
+ if (data->tar && BKE_object_exists_check(data->tar) == 0) {
+ data->tar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (data->tar == owner) {
+ if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->subtarget)) {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+
+ /* targets have already been checked for this */
+ check_targets = false;
+ }
+ else if (con->type == CONSTRAINT_TYPE_ACTION) {
+ bActionConstraint *data = con->data;
+
+ /* validate action */
+ if (data->act == NULL) {
+ /* must have action */
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (data->act->idroot != ID_OB) {
+ /* only object-rooted actions can be used */
+ data->act = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_FOLLOWPATH) {
+ bFollowPathConstraint *data = con->data;
+
+ /* don't allow track/up axes to be the same */
+ if (data->upflag == data->trackflag)
+ con->flag |= CONSTRAINT_DISABLE;
+ if (data->upflag + 3 == data->trackflag)
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (con->type == CONSTRAINT_TYPE_TRACKTO) {
+ bTrackToConstraint *data = con->data;
+
+ /* don't allow track/up axes to be the same */
+ if (data->reserved2 == data->reserved1)
+ con->flag |= CONSTRAINT_DISABLE;
+ if (data->reserved2 + 3 == data->reserved1)
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (con->type == CONSTRAINT_TYPE_LOCKTRACK) {
+ bLockTrackConstraint *data = con->data;
+
+ if (data->lockflag == data->trackflag)
+ con->flag |= CONSTRAINT_DISABLE;
+ if (data->lockflag + 3 == data->trackflag)
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (con->type == CONSTRAINT_TYPE_SPLINEIK) {
+ bSplineIKConstraint *data = con->data;
+
+ /* if the number of points does not match the amount required by the chain length,
+ * free the points array and request a rebind...
+ */
+ if ((data->points == NULL) || (data->numpoints != data->chainlen + 1)) {
+ /* free the points array */
+ if (data->points) {
+ MEM_freeN(data->points);
+ data->points = NULL;
+ }
+
+ /* clear the bound flag, forcing a rebind next time this is evaluated */
+ data->flag &= ~CONSTRAINT_SPLINEIK_BOUND;
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
+ bFollowTrackConstraint *data = con->data;
+
+ if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0) {
+ if (data->clip != NULL && data->track[0]) {
+ MovieTracking *tracking = &data->clip->tracking;
+ MovieTrackingObject *tracking_object;
+
+ if (data->object[0])
+ tracking_object = BKE_tracking_object_get_named(tracking, data->object);
+ else
+ tracking_object = BKE_tracking_object_get_camera(tracking);
+
+ if (!tracking_object) {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else {
+ if (!BKE_tracking_track_get_named(tracking, tracking_object, data->track))
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+ else {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_CAMERASOLVER) {
+ bCameraSolverConstraint *data = con->data;
+
+ if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL))
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
+ bObjectSolverConstraint *data = con->data;
+
+ if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL))
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+
+ /* Check targets for constraints */
+ if (check_targets && cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ /* disable and clear constraints targets that are incorrect */
+ for (ct = targets.first; ct; ct = ct->next) {
+ /* general validity checks (for those constraints that need this) */
+ if (BKE_object_exists_check(ct->tar) == 0) {
+ /* object doesn't exist, but constraint requires target */
+ ct->tar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (ct->tar == owner) {
+ if (type == CONSTRAINT_OBTYPE_BONE) {
+ if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), ct->subtarget)) {
+ /* bone must exist in armature... */
+ /* TODO: clear subtarget? */
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (STREQ(pchan->name, ct->subtarget)) {
+ /* cannot target self */
+ ct->subtarget[0] = '\0';
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+ else {
+ /* cannot use self as target */
+ ct->tar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+
+ /* target checks for specific constraints */
+ if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) {
+ if (ct->tar) {
+ if (ct->tar->type != OB_CURVE) {
+ ct->tar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else {
+ Curve *cu = ct->tar->data;
+
+ /* auto-set 'Path' setting on curve so this works */
+ cu->flag |= CU_PATH;
+ }
+ }
+ }
+ }
+
+ /* free any temporary targets */
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+}
+
+static int constraint_type_get(Object *owner, bPoseChannel *pchan)
{
- bConstraint *curcon;
- ListBase *conlist = NULL;
int type;
-
- if (owner == NULL) return;
-
/* Check parents */
if (pchan) {
switch (owner->type) {
@@ -284,7 +488,22 @@ static void test_constraints(Object *owner, bPoseChannel *pchan)
}
else
type = CONSTRAINT_OBTYPE_OBJECT;
+ return type;
+}
+
+/* checks validity of object pointers, and NULLs,
+ * if Bone doesnt exist it sets the CONSTRAINT_DISABLE flag.
+ */
+static void test_constraints(Object *owner, bPoseChannel *pchan)
+{
+ bConstraint *curcon;
+ ListBase *conlist = NULL;
+ int type;
+ if (owner == NULL) return;
+
+ type = constraint_type_get(owner, pchan);
+
/* Get the constraint list for this object */
switch (type) {
case CONSTRAINT_OBTYPE_OBJECT:
@@ -298,213 +517,7 @@ static void test_constraints(Object *owner, bPoseChannel *pchan)
/* Check all constraints - is constraint valid? */
if (conlist) {
for (curcon = conlist->first; curcon; curcon = curcon->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* clear disabled-flag first */
- curcon->flag &= ~CONSTRAINT_DISABLE;
-
- if (curcon->type == CONSTRAINT_TYPE_KINEMATIC) {
- bKinematicConstraint *data = curcon->data;
-
- /* bad: we need a separate set of checks here as poletarget is
- * optional... otherwise poletarget must exist too or else
- * the constraint is deemed invalid
- */
- /* default IK check ... */
- if (BKE_object_exists_check(data->tar) == 0) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (data->tar == owner) {
- if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->subtarget)) {
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
-
- if (data->poletar) {
- if (BKE_object_exists_check(data->poletar) == 0) {
- data->poletar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (data->poletar == owner) {
- if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->polesubtarget)) {
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
- }
- /* ... can be overwritten here */
- BIK_test_constraint(owner, curcon);
- /* targets have already been checked for this */
- continue;
- }
- else if (curcon->type == CONSTRAINT_TYPE_PIVOT) {
- bPivotConstraint *data = curcon->data;
-
- /* target doesn't have to exist, but if it is non-null, it must exist! */
- if (data->tar && BKE_object_exists_check(data->tar) == 0) {
- data->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (data->tar == owner) {
- if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), data->subtarget)) {
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
-
- /* targets have already been checked for this */
- continue;
- }
- else if (curcon->type == CONSTRAINT_TYPE_ACTION) {
- bActionConstraint *data = curcon->data;
-
- /* validate action */
- if (data->act == NULL) {
- /* must have action */
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (data->act->idroot != ID_OB) {
- /* only object-rooted actions can be used */
- data->act = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
- else if (curcon->type == CONSTRAINT_TYPE_FOLLOWPATH) {
- bFollowPathConstraint *data = curcon->data;
-
- /* don't allow track/up axes to be the same */
- if (data->upflag == data->trackflag)
- curcon->flag |= CONSTRAINT_DISABLE;
- if (data->upflag + 3 == data->trackflag)
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (curcon->type == CONSTRAINT_TYPE_TRACKTO) {
- bTrackToConstraint *data = curcon->data;
-
- /* don't allow track/up axes to be the same */
- if (data->reserved2 == data->reserved1)
- curcon->flag |= CONSTRAINT_DISABLE;
- if (data->reserved2 + 3 == data->reserved1)
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (curcon->type == CONSTRAINT_TYPE_LOCKTRACK) {
- bLockTrackConstraint *data = curcon->data;
-
- if (data->lockflag == data->trackflag)
- curcon->flag |= CONSTRAINT_DISABLE;
- if (data->lockflag + 3 == data->trackflag)
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (curcon->type == CONSTRAINT_TYPE_SPLINEIK) {
- bSplineIKConstraint *data = curcon->data;
-
- /* if the number of points does not match the amount required by the chain length,
- * free the points array and request a rebind...
- */
- if ((data->points == NULL) || (data->numpoints != data->chainlen + 1)) {
- /* free the points array */
- if (data->points) {
- MEM_freeN(data->points);
- data->points = NULL;
- }
-
- /* clear the bound flag, forcing a rebind next time this is evaluated */
- data->flag &= ~CONSTRAINT_SPLINEIK_BOUND;
- }
- }
- else if (curcon->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
- bFollowTrackConstraint *data = curcon->data;
-
- if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0) {
- if (data->clip != NULL && data->track[0]) {
- MovieTracking *tracking = &data->clip->tracking;
- MovieTrackingObject *tracking_object;
-
- if (data->object[0])
- tracking_object = BKE_tracking_object_get_named(tracking, data->object);
- else
- tracking_object = BKE_tracking_object_get_camera(tracking);
-
- if (!tracking_object) {
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else {
- if (!BKE_tracking_track_get_named(tracking, tracking_object, data->track))
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
- else {
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
- }
- else if (curcon->type == CONSTRAINT_TYPE_CAMERASOLVER) {
- bCameraSolverConstraint *data = curcon->data;
-
- if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL))
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (curcon->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
- bObjectSolverConstraint *data = curcon->data;
-
- if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL))
- curcon->flag |= CONSTRAINT_DISABLE;
- }
-
- /* Check targets for constraints */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(curcon, &targets);
-
- /* disable and clear constraints targets that are incorrect */
- for (ct = targets.first; ct; ct = ct->next) {
- /* general validity checks (for those constraints that need this) */
- if (BKE_object_exists_check(ct->tar) == 0) {
- /* object doesn't exist, but constraint requires target */
- ct->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (ct->tar == owner) {
- if (type == CONSTRAINT_OBTYPE_BONE) {
- if (!BKE_armature_find_bone_name(BKE_armature_from_object(owner), ct->subtarget)) {
- /* bone must exist in armature... */
- /* TODO: clear subtarget? */
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else if (STREQ(pchan->name, ct->subtarget)) {
- /* cannot target self */
- ct->subtarget[0] = '\0';
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
- else {
- /* cannot use self as target */
- ct->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- }
-
- /* target checks for specific constraints */
- if (ELEM(curcon->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) {
- if (ct->tar) {
- if (ct->tar->type != OB_CURVE) {
- ct->tar = NULL;
- curcon->flag |= CONSTRAINT_DISABLE;
- }
- else {
- Curve *cu = ct->tar->data;
-
- /* auto-set 'Path' setting on curve so this works */
- cu->flag |= CU_PATH;
- }
- }
- }
- }
-
- /* free any temporary targets */
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(curcon, &targets, 0);
- }
+ test_constraint(owner, pchan, curcon, type);
}
}
}
@@ -524,6 +537,26 @@ void object_test_constraints(Object *owner)
}
}
+static void object_test_constraint(Object *owner, bConstraint *con)
+{
+ if (owner->type == OB_ARMATURE && owner->pose) {
+ if (BLI_findindex(&owner->constraints, con) != -1) {
+ test_constraint(owner, NULL, con, CONSTRAINT_OBTYPE_OBJECT);
+ }
+ else {
+ bPoseChannel *pchan;
+ for (pchan = owner->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (BLI_findindex(&pchan->constraints, con) != -1) {
+ test_constraint(owner, pchan, con, CONSTRAINT_OBTYPE_BONE);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ test_constraint(owner, NULL, con, CONSTRAINT_OBTYPE_OBJECT);
+ }
+}
/************************ generic functions for operators using constraint names and data context *********************/
@@ -1161,11 +1194,50 @@ void ED_object_constraint_update(Object *ob)
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
+static void object_pose_tag_update(Main *bmain, Object *ob)
+{
+ BKE_pose_tag_recalc(bmain, ob->pose); /* Checks & sort pose channels. */
+ if (ob->proxy && ob->adt) {
+ /* We need to make use of ugly POSE_ANIMATION_WORKAROUND here too, else anim data are not reloaded
+ * after calling `BKE_pose_rebuild()`, which causes T43872.
+ * Note that this is a bit wide here, since we cannot be sure whether there are some locked proxy bones
+ * or not...
+ * XXX Temp hack until new depsgraph hopefully solves this. */
+ ob->adt->recalc |= ADT_RECALC_ANIM;
+ }
+}
+
void ED_object_constraint_dependency_update(Main *bmain, Object *ob)
{
ED_object_constraint_update(ob);
- if (ob->pose) ob->pose->flag |= POSE_RECALC; // checks & sorts pose channels
+ if (ob->pose) {
+ object_pose_tag_update(bmain, ob);
+ }
+ DAG_relations_tag_update(bmain);
+}
+
+void ED_object_constraint_tag_update(Object *ob, bConstraint *con)
+{
+ if (ob->pose) {
+ BKE_pose_tag_update_constraint_flags(ob->pose);
+ }
+
+ object_test_constraint(ob, con);
+
+ if (ob->type == OB_ARMATURE)
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB);
+ else
+ DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+}
+
+void ED_object_constraint_dependency_tag_update(Main *bmain, Object *ob, bConstraint *con)
+{
+ ED_object_constraint_tag_update(ob, con);
+
+ if (ob->pose) {
+ object_pose_tag_update(bmain, ob);
+ }
DAG_relations_tag_update(bmain);
}
@@ -1188,7 +1260,10 @@ static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op))
/* there's no active constraint now, so make sure this is the case */
BKE_constraints_active_set(&ob->constraints, NULL);
ED_object_constraint_update(ob); /* needed to set the flags on posebones correctly */
-
+
+ /* relatiols */
+ DAG_relations_tag_update(CTX_data_main(C));
+
/* notifiers */
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob);
@@ -1412,8 +1487,8 @@ static int pose_constraint_copy_exec(bContext *C, wmOperator *op)
BKE_constraints_copy(&chan->constraints, &pchan->constraints, true);
/* update flags (need to add here, not just copy) */
chan->constflag |= pchan->constflag;
-
- ob->pose->flag |= POSE_RECALC;
+
+ BKE_pose_tag_recalc(bmain, ob->pose);
DAG_id_tag_update((ID *)ob, OB_RECALC_DATA);
}
}
@@ -1590,7 +1665,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o
Object *obt;
/* add new target object */
- obt = BKE_object_add(bmain, scene, OB_EMPTY);
+ obt = BKE_object_add(bmain, scene, OB_EMPTY, NULL);
/* set layers OK */
newbase = BASACT;
@@ -1724,7 +1799,13 @@ static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase
DAG_relations_tag_update(bmain);
if ((ob->type == OB_ARMATURE) && (pchan)) {
- ob->pose->flag |= POSE_RECALC; /* sort pose channels */
+ BKE_pose_tag_recalc(bmain, ob->pose); /* sort pose channels */
+ if (BKE_constraints_proxylocked_owner(ob, pchan) && ob->adt) {
+ /* We need to make use of ugly POSE_ANIMATION_WORKAROUND here too, else anim data are not reloaded
+ * after calling `BKE_pose_rebuild()`, which causes T43872.
+ * XXX Temp hack until new depsgraph hopefully solves this. */
+ ob->adt->recalc |= ADT_RECALC_ANIM;
+ }
DAG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB);
}
else
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index c57cae41bf4..b3b2299f77f 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -29,8 +29,6 @@
* \ingroup edobj
*/
-#include "MEM_guardedalloc.h"
-
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
@@ -59,7 +57,6 @@
#include "ED_object.h"
#include "UI_interface.h"
-#include "UI_resources.h"
#include "object_intern.h"
@@ -299,7 +296,7 @@ static bool data_transfer_exec_is_object_valid(
wmOperator *op, Object *ob_src, Object *ob_dst, const bool reverse_transfer)
{
Mesh *me;
- if ((ob_dst == ob_src) || !ELEM(OB_MESH, ob_src->type, ob_dst->type)) {
+ if ((ob_dst == ob_src) || (ob_src->type != OB_MESH) || (ob_dst->type != OB_MESH)) {
return false;
}
@@ -325,7 +322,7 @@ static bool data_transfer_exec_is_object_valid(
static int data_transfer_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Object *ob_src = CTX_data_active_object(C);
+ Object *ob_src = ED_object_active_context(C);
ListBase ctx_objects;
CollectionPointerLink *ctx_ob_dst;
@@ -419,7 +416,7 @@ static int data_transfer_exec(bContext *C, wmOperator *op)
/* Note this context poll is only really partial, it cannot check for all possible invalid cases. */
static int data_transfer_poll(bContext *C)
{
- Object *ob = ED_object_context(C);
+ Object *ob = ED_object_active_context(C);
ID *data = (ob) ? ob->data : NULL;
return (ob && ob->type == OB_MESH && data);
}
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 458feebaec7..5f358ebde20 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -65,6 +65,7 @@
#include "BKE_curve.h"
#include "BKE_effect.h"
#include "BKE_depsgraph.h"
+#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
@@ -318,7 +319,7 @@ void OBJECT_OT_hide_render_set(wmOperatorType *ot)
* Load EditMode data back into the object,
* optionally freeing the editmode data.
*/
-static bool ED_object_editmode_load_ex(Object *obedit, const bool freedata)
+static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool freedata)
{
if (obedit == NULL) {
return false;
@@ -348,6 +349,11 @@ static bool ED_object_editmode_load_ex(Object *obedit, const bool freedata)
ED_armature_from_edit(obedit->data);
if (freedata)
ED_armature_edit_free(obedit->data);
+ /* TODO(sergey): Pose channels might have been changed, so need
+ * to inform dependency graph about this. But is it really the
+ * best place to do this?
+ */
+ DAG_relations_tag_update(bmain);
}
else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
load_editNurb(obedit);
@@ -376,7 +382,8 @@ static bool ED_object_editmode_load_ex(Object *obedit, const bool freedata)
bool ED_object_editmode_load(Object *obedit)
{
- return ED_object_editmode_load_ex(obedit, false);
+ /* TODO(sergey): use proper main here? */
+ return ED_object_editmode_load_ex(G.main, obedit, false);
}
void ED_object_editmode_exit(bContext *C, int flag)
@@ -389,7 +396,7 @@ void ED_object_editmode_exit(bContext *C, int flag)
if (flag & EM_WAITCURSOR) waitcursor(1);
- if (ED_object_editmode_load_ex(obedit, freedata) == false) {
+ if (ED_object_editmode_load_ex(CTX_data_main(C), obedit, freedata) == false) {
/* in rare cases (background mode) its possible active object
* is flagged for editmode, without 'obedit' being set [#35489] */
if (UNLIKELY(scene->basact && (scene->basact->object->mode & OB_MODE_EDIT))) {
@@ -571,8 +578,8 @@ static int editmode_toggle_exec(bContext *C, wmOperator *op)
ToolSettings *toolsettings = CTX_data_tool_settings(C);
if (!is_mode_set) {
- Scene *scene = CTX_data_scene(C);
- if (!ED_object_mode_compat_set(C, scene->basact->object, mode_flag, op->reports)) {
+ Object *ob = CTX_data_active_object(C);
+ if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
return OPERATOR_CANCELLED;
}
}
@@ -1512,6 +1519,7 @@ static EnumPropertyItem *object_mode_set_itemsf(bContext *C, PointerRNA *UNUSED(
(input->value == OB_MODE_PARTICLE_EDIT && use_mode_particle_edit) ||
(ELEM(input->value, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT,
OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT) && (ob->type == OB_MESH)) ||
+ (input->value == OB_MODE_HAIR_EDIT) || /* XXX always on, testing for strand data is a bit involved */
(input->value == OB_MODE_OBJECT))
{
RNA_enum_item_add(&item, &totitem, input);
@@ -1545,6 +1553,8 @@ static const char *object_mode_op_string(int mode)
return "PAINT_OT_texture_paint_toggle";
if (mode == OB_MODE_PARTICLE_EDIT)
return "PARTICLE_OT_particle_edit_toggle";
+ if (mode == OB_MODE_HAIR_EDIT)
+ return "HAIR_OT_hair_edit_toggle";
if (mode == OB_MODE_POSE)
return "OBJECT_OT_posemode_toggle";
return NULL;
@@ -1558,6 +1568,9 @@ static bool object_mode_compat_test(Object *ob, ObjectMode mode)
if (ob) {
if (mode == OB_MODE_OBJECT)
return true;
+ /* XXX this is not nice, but testing for cached strands data + shape keys is a bit complicated */
+ if (mode == OB_MODE_HAIR_EDIT)
+ return true;
switch (ob->type) {
case OB_MESH:
@@ -1769,6 +1782,77 @@ void OBJECT_OT_game_property_remove(wmOperatorType *ot)
RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Property index to remove ", 0, INT_MAX);
}
+#define GAME_PROPERTY_MOVE_UP 1
+#define GAME_PROPERTY_MOVE_DOWN -1
+
+static int game_property_move(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ bProperty *prop;
+ bProperty *otherprop = NULL;
+ const int index = RNA_int_get(op->ptr, "index");
+ const int dir = RNA_enum_get(op->ptr, "direction");
+
+ if (ob == NULL)
+ return OPERATOR_CANCELLED;
+
+ prop = BLI_findlink(&ob->prop, index);
+ /* invalid index */
+ if (prop == NULL)
+ return OPERATOR_CANCELLED;
+
+ if (dir == GAME_PROPERTY_MOVE_UP) {
+ otherprop = prop->prev;
+ }
+ else if (dir == GAME_PROPERTY_MOVE_DOWN) {
+ otherprop = prop->next;
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ if (prop && otherprop) {
+ BLI_listbase_swaplinks(&ob->prop, prop, otherprop);
+
+ WM_event_add_notifier(C, NC_LOGIC, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void OBJECT_OT_game_property_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem direction_property_move[] = {
+ {GAME_PROPERTY_MOVE_UP, "UP", 0, "Up", ""},
+ {GAME_PROPERTY_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Move Game Property";
+ ot->description = "Move game property";
+ ot->idname = "OBJECT_OT_game_property_move";
+
+ /* api callbacks */
+ ot->exec = game_property_move;
+ ot->poll = ED_operator_object_active_editable;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Property index to move", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_enum(ot->srna, "direction", direction_property_move, 0, "Direction",
+ "Direction for moving the property");
+}
+
+#undef GAME_PROPERTY_MOVE_UP
+#undef GAME_PROPERTY_MOVE_DOWN
+
#define COPY_PROPERTIES_REPLACE 1
#define COPY_PROPERTIES_MERGE 2
#define COPY_PROPERTIES_COPY 3
@@ -2063,4 +2147,4 @@ bool ED_object_editmode_calc_active_center(Object *obedit, const bool select_onl
}
return false;
-} \ No newline at end of file
+}
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index 1d764ced524..8797b75a801 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -448,11 +448,12 @@ static Object *add_hook_object_new(Main *bmain, Scene *scene, Object *obedit)
Base *base, *basedit;
Object *ob;
- ob = BKE_object_add(bmain, scene, OB_EMPTY);
+ ob = BKE_object_add(bmain, scene, OB_EMPTY, NULL);
basedit = BKE_scene_base_find(scene, obedit);
- base = BKE_scene_base_find(scene, ob);
+ base = scene->basact;
base->lay = ob->lay = obedit->lay;
+ BLI_assert(scene->basact->object == ob);
/* icky, BKE_object_add sets new base as active.
* so set it back to the original edit object */
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 634b0298d88..2049f03326d 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -32,17 +32,12 @@
#define __OBJECT_INTERN_H__
struct wmOperatorType;
-struct KeyBlock;
-struct Lattice;
-struct Curve;
struct Object;
-struct Mesh;
struct bContext;
struct StructRNA;
struct wmOperator;
struct ModifierData;
-struct HookModifierData;
/* add hook menu */
enum eObject_Hook_Add_Mode {
@@ -99,6 +94,7 @@ void OBJECT_OT_game_property_new(struct wmOperatorType *ot);
void OBJECT_OT_game_property_remove(struct wmOperatorType *ot);
void OBJECT_OT_game_property_copy(struct wmOperatorType *ot);
void OBJECT_OT_game_property_clear(struct wmOperatorType *ot);
+void OBJECT_OT_game_property_move(struct wmOperatorType *ot);
void OBJECT_OT_logic_bricks_copy(struct wmOperatorType *ot);
void OBJECT_OT_game_physics_copy(struct wmOperatorType *ot);
@@ -179,6 +175,7 @@ void OBJECT_OT_multires_higher_levels_delete(struct wmOperatorType *ot);
void OBJECT_OT_multires_base_apply(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_save(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_pack(struct wmOperatorType *ot);
+void OBJECT_OT_correctivesmooth_bind(struct wmOperatorType *ot);
void OBJECT_OT_meshdeform_bind(struct wmOperatorType *ot);
void OBJECT_OT_explode_refresh(struct wmOperatorType *ot);
void OBJECT_OT_ocean_bake(struct wmOperatorType *ot);
@@ -257,7 +254,7 @@ void OBJECT_OT_face_map_deselect(struct wmOperatorType *ot);
void OBJECT_OT_face_map_move(struct wmOperatorType *ot);
/* object_warp.c */
-void OBJECT_OT_vertex_warp(struct wmOperatorType *ot);
+void TRANSFORM_OT_vertex_warp(struct wmOperatorType *ot);
/* object_shapekey.c */
void OBJECT_OT_shape_key_add(struct wmOperatorType *ot);
@@ -283,7 +280,7 @@ void OBJECT_OT_lod_add(struct wmOperatorType *ot);
void OBJECT_OT_lod_remove(struct wmOperatorType *ot);
/* object_random.c */
-void OBJECT_OT_vertex_random(struct wmOperatorType *ot);
+void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot);
/* object_transfer_data.c */
void OBJECT_OT_data_transfer(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/object/object_lattice.c
index b577dab8a77..f269a7a5360 100644
--- a/source/blender/editors/object/object_lattice.c
+++ b/source/blender/editors/object/object_lattice.c
@@ -967,6 +967,6 @@ static void *get_editlatt(bContext *C)
/* and this is all the undo system needs to know */
void undo_push_lattice(bContext *C, const char *name)
{
- undo_editmode_push(C, name, get_editlatt, free_undoLatt, undoLatt_to_editLatt, editLatt_to_undoLatt, validate_undoLatt);
+ undo_editmode_push(C, name, CTX_data_edit_object, get_editlatt, free_undoLatt, undoLatt_to_editLatt, editLatt_to_undoLatt, validate_undoLatt);
}
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 710cf2dbdd2..ce9693793a4 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -96,7 +96,7 @@ static void modifier_skin_customdata_delete(struct Object *ob);
ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type)
{
ModifierData *md = NULL, *new_md = NULL;
- ModifierTypeInfo *mti = modifierType_getInfo(type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(type);
/* only geometry objects should be able to get modifiers [#25291] */
if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
@@ -152,10 +152,10 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc
ob->pd = object_add_collision_fields(0);
ob->pd->deflect = 1;
- DAG_relations_tag_update(bmain);
}
- else if (type == eModifierType_Surface)
- DAG_relations_tag_update(bmain);
+ else if (type == eModifierType_Surface) {
+ /* pass */
+ }
else if (type == eModifierType_Multires) {
/* set totlvl from existing MDISPS layer if object already had it */
multiresModifier_set_levels_from_disps((MultiresModifierData *)new_md, ob);
@@ -172,6 +172,7 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc
}
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DAG_relations_tag_update(bmain);
return new_md;
}
@@ -247,7 +248,7 @@ static bool object_has_modifier_cb(Object *ob, void *data)
bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v)
{
ModifierData *md;
- int totlevel = *((int *)totlevel_v);
+ int totlevel = *((char *)totlevel_v);
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Multires) {
@@ -319,6 +320,8 @@ static bool object_modifier_remove(Main *bmain, Object *ob, ModifierData *md,
ob->mode &= ~OB_MODE_PARTICLE_EDIT;
}
+ DAG_relations_tag_update(bmain);
+
BLI_remlink(&ob->modifiers, md);
modifier_free(md);
@@ -368,10 +371,10 @@ void ED_object_modifier_clear(Main *bmain, Object *ob)
int ED_object_modifier_move_up(ReportList *reports, Object *ob, ModifierData *md)
{
if (md->prev) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti->type != eModifierTypeType_OnlyDeform) {
- ModifierTypeInfo *nmti = modifierType_getInfo(md->prev->type);
+ const ModifierTypeInfo *nmti = modifierType_getInfo(md->prev->type);
if (nmti->flags & eModifierTypeFlag_RequiresOriginalData) {
BKE_report(reports, RPT_WARNING, "Cannot move above a modifier requiring original data");
@@ -389,10 +392,10 @@ int ED_object_modifier_move_up(ReportList *reports, Object *ob, ModifierData *md
int ED_object_modifier_move_down(ReportList *reports, Object *ob, ModifierData *md)
{
if (md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (mti->flags & eModifierTypeFlag_RequiresOriginalData) {
- ModifierTypeInfo *nmti = modifierType_getInfo(md->next->type);
+ const ModifierTypeInfo *nmti = modifierType_getInfo(md->next->type);
if (nmti->type != eModifierTypeType_OnlyDeform) {
BKE_report(reports, RPT_WARNING, "Cannot move beyond a non-deforming modifier");
@@ -459,7 +462,7 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
if (totvert == 0) return 0;
/* add new mesh */
- obn = BKE_object_add(bmain, scene, OB_MESH);
+ obn = BKE_object_add(bmain, scene, OB_MESH, NULL);
me = obn->data;
me->totvert = totvert;
@@ -518,7 +521,7 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
static int modifier_apply_shape(ReportList *reports, Scene *scene, Object *ob, ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -578,7 +581,7 @@ static int modifier_apply_shape(ReportList *reports, Scene *scene, Object *ob, M
static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob, ModifierData *md)
{
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene = scene;
@@ -742,7 +745,7 @@ static EnumPropertyItem *modifier_add_itemf(bContext *C, PointerRNA *UNUSED(ptr)
{
Object *ob = ED_object_active_context(C);
EnumPropertyItem *item = NULL, *md_item, *group_item = NULL;
- ModifierTypeInfo *mti;
+ const ModifierTypeInfo *mti;
int totitem = 0, a;
if (!ob)
@@ -1704,7 +1707,7 @@ static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, Object *
NULL,
me->totvert);
- arm_ob = BKE_object_add(bmain, scene, OB_ARMATURE);
+ arm_ob = BKE_object_add(bmain, scene, OB_ARMATURE, NULL);
BKE_object_transform_copy(arm_ob, skin_ob);
arm = arm_ob->data;
arm->layer = 1;
@@ -1815,6 +1818,73 @@ void OBJECT_OT_skin_armature_create(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_modifier_properties(ot);
}
+/************************ delta mush bind operator *********************/
+
+static int correctivesmooth_poll(bContext *C)
+{
+ return edit_modifier_poll_generic(C, &RNA_CorrectiveSmoothModifier, 0);
+}
+
+static int correctivesmooth_bind_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = ED_object_active_context(C);
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)edit_modifier_property_get(op, ob, eModifierType_CorrectiveSmooth);
+ bool is_bind;
+
+ if (!csmd) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!modifier_isEnabled(scene, &csmd->modifier, eModifierMode_Realtime)) {
+ BKE_report(op->reports, RPT_ERROR, "Modifier is disabled");
+ return OPERATOR_CANCELLED;
+ }
+
+ is_bind = (csmd->bind_coords != NULL);
+
+ MEM_SAFE_FREE(csmd->bind_coords);
+ MEM_SAFE_FREE(csmd->delta_cache);
+
+ if (is_bind) {
+ /* toggle off */
+ csmd->bind_coords_num = 0;
+ }
+ else {
+ /* signal to modifier to recalculate */
+ csmd->bind_coords_num = (unsigned int)-1;
+ }
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int correctivesmooth_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (edit_modifier_invoke_properties(C, op))
+ return correctivesmooth_bind_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_correctivesmooth_bind(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Corrective Smooth Bind";
+ ot->description = "Bind base pose in Corrective Smooth modifier";
+ ot->idname = "OBJECT_OT_correctivesmooth_bind";
+
+ /* api callbacks */
+ ot->poll = correctivesmooth_poll;
+ ot->invoke = correctivesmooth_bind_invoke;
+ ot->exec = correctivesmooth_bind_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+}
/************************ mdef bind operator *********************/
@@ -1978,7 +2048,7 @@ static void init_ocean_modifier_bake(struct Ocean *oc, struct OceanModifierData
do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS);
do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM);
- BKE_init_ocean(oc, omd->resolution * omd->resolution, omd->resolution * omd->resolution, omd->spatial_size, omd->spatial_size,
+ BKE_ocean_init(oc, omd->resolution * omd->resolution, omd->resolution * omd->resolution, omd->spatial_size, omd->spatial_size,
omd->wind_velocity, omd->smallest_wave, 1.0, omd->wave_direction, omd->damp, omd->wave_alignment,
omd->depth, omd->time,
do_heightfield, do_chop, do_normals, do_jacobian,
@@ -2036,7 +2106,7 @@ static void oceanbake_startjob(void *customdata, short *stop, short *do_update,
G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */
- BKE_bake_ocean(oj->ocean, oj->och, oceanbake_update, (void *)oj);
+ BKE_ocean_bake(oj->ocean, oj->och, oceanbake_update, (void *)oj);
*do_update = true;
*stop = 0;
@@ -2047,7 +2117,7 @@ static void oceanbake_endjob(void *customdata)
OceanBakeJob *oj = customdata;
if (oj->ocean) {
- BKE_free_ocean(oj->ocean);
+ BKE_ocean_free(oj->ocean);
oj->ocean = NULL;
}
@@ -2078,7 +2148,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
- och = BKE_init_ocean_cache(omd->cachepath, modifier_path_relbase(ob),
+ och = BKE_ocean_init_cache(omd->cachepath, modifier_path_relbase(ob),
omd->bakestart, omd->bakeend, omd->wave_scale,
omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution);
@@ -2112,11 +2182,11 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
}
/* make a copy of ocean to use for baking - threadsafety */
- ocean = BKE_add_ocean();
+ ocean = BKE_ocean_add();
init_ocean_modifier_bake(ocean, omd);
#if 0
- BKE_bake_ocean(ocean, och);
+ BKE_ocean_bake(ocean, och);
omd->oceancache = och;
omd->cached = true;
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 8c3c92110ea..c0eefd6c873 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -144,6 +144,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_skin_radii_equalize);
WM_operatortype_append(OBJECT_OT_skin_armature_create);
+ WM_operatortype_append(OBJECT_OT_correctivesmooth_bind);
WM_operatortype_append(OBJECT_OT_meshdeform_bind);
WM_operatortype_append(OBJECT_OT_explode_refresh);
WM_operatortype_append(OBJECT_OT_ocean_bake);
@@ -207,12 +208,13 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_face_map_deselect);
WM_operatortype_append(OBJECT_OT_face_map_move);
- WM_operatortype_append(OBJECT_OT_vertex_warp);
+ WM_operatortype_append(TRANSFORM_OT_vertex_warp);
WM_operatortype_append(OBJECT_OT_game_property_new);
WM_operatortype_append(OBJECT_OT_game_property_remove);
WM_operatortype_append(OBJECT_OT_game_property_copy);
WM_operatortype_append(OBJECT_OT_game_property_clear);
+ WM_operatortype_append(OBJECT_OT_game_property_move);
WM_operatortype_append(OBJECT_OT_logic_bricks_copy);
WM_operatortype_append(OBJECT_OT_game_physics_copy);
@@ -255,7 +257,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_lod_add);
WM_operatortype_append(OBJECT_OT_lod_remove);
- WM_operatortype_append(OBJECT_OT_vertex_random);
+ WM_operatortype_append(TRANSFORM_OT_vertex_random);
WM_operatortype_append(OBJECT_OT_data_transfer);
WM_operatortype_append(OBJECT_OT_datalayout_transfer);
diff --git a/source/blender/editors/object/object_random.c b/source/blender/editors/object/object_random.c
index 41b26b98047..a293f7a950e 100644
--- a/source/blender/editors/object/object_random.c
+++ b/source/blender/editors/object/object_random.c
@@ -124,12 +124,12 @@ static int object_rand_verts_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void OBJECT_OT_vertex_random(struct wmOperatorType *ot)
+void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Randomize";
ot->description = "Randomize vertices";
- ot->idname = "OBJECT_OT_vertex_random";
+ ot->idname = "TRANSFORM_OT_vertex_random";
/* api callbacks */
ot->exec = object_rand_verts_exec;
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index bfa501c3732..19648c291f7 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -342,12 +342,10 @@ static int make_proxy_exec(bContext *C, wmOperator *op)
Base *newbase, *oldbase = BASACT;
char name[MAX_ID_NAME + 4];
- /* Add new object for the proxy */
- newob = BKE_object_add(bmain, scene, OB_EMPTY);
-
BLI_snprintf(name, sizeof(name), "%s_proxy", ((ID *)(gob ? gob : ob))->name + 2);
- rename_id(&newob->id, name);
+ /* Add new object for the proxy */
+ newob = BKE_object_add(bmain, scene, OB_EMPTY, name);
/* set layers OK */
newbase = BASACT; /* BKE_object_add sets active... */
@@ -1574,13 +1572,13 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
DAG_id_tag_update(&ob_dst->id, 0);
break;
case MAKE_LINKS_ANIMDATA:
- BKE_copy_animdata_id((ID *)ob_dst, (ID *)ob_src, false);
+ BKE_animdata_copy_id((ID *)ob_dst, (ID *)ob_src, false);
if (ob_dst->data && ob_src->data) {
if (obdata_id->lib) {
is_lib = true;
break;
}
- BKE_copy_animdata_id((ID *)ob_dst->data, (ID *)ob_src->data, false);
+ BKE_animdata_copy_id((ID *)ob_dst->data, (ID *)ob_src->data, false);
}
DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
break;
@@ -1871,7 +1869,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
case OB_MESH:
ob->data = me = BKE_mesh_copy(ob->data);
if (me->key)
- BKE_copy_animdata_id_action((ID *)me->key);
+ BKE_animdata_copy_id_action((ID *)me->key);
break;
case OB_MBALL:
ob->data = BKE_mball_copy(ob->data);
@@ -1883,12 +1881,12 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
ID_NEW(cu->bevobj);
ID_NEW(cu->taperobj);
if (cu->key)
- BKE_copy_animdata_id_action((ID *)cu->key);
+ BKE_animdata_copy_id_action((ID *)cu->key);
break;
case OB_LATTICE:
ob->data = lat = BKE_lattice_copy(ob->data);
if (lat->key)
- BKE_copy_animdata_id_action((ID *)lat->key);
+ BKE_animdata_copy_id_action((ID *)lat->key);
break;
case OB_ARMATURE:
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -1909,7 +1907,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
* AnimData structure, which is not what we want.
* (sergey)
*/
- BKE_copy_animdata_id_action((ID *)ob->data);
+ BKE_animdata_copy_id_action((ID *)ob->data);
id->us--;
id->newid = ob->data;
@@ -1933,7 +1931,7 @@ static void single_object_action_users(Scene *scene, const int flag)
ob = base->object;
if (ob->id.lib == NULL && (flag == 0 || (base->flag & SELECT)) ) {
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- BKE_copy_animdata_id_action(&ob->id);
+ BKE_animdata_copy_id_action(&ob->id);
}
}
}
@@ -1956,7 +1954,7 @@ static void single_mat_users(Scene *scene, const int flag, const bool do_texture
if (ma->id.us > 1) {
man = BKE_material_copy(ma);
- BKE_copy_animdata_id_action(&man->id);
+ BKE_animdata_copy_id_action(&man->id);
man->id.us = 0;
assign_material(ob, man, a, BKE_MAT_ASSIGN_USERPREF);
@@ -1967,7 +1965,7 @@ static void single_mat_users(Scene *scene, const int flag, const bool do_texture
if (tex->id.us > 1) {
tex->id.us--;
tex = BKE_texture_copy(tex);
- BKE_copy_animdata_id_action(&tex->id);
+ BKE_animdata_copy_id_action(&tex->id);
man->mtex[b]->tex = tex;
}
}
@@ -1994,7 +1992,7 @@ static void do_single_tex_user(Tex **from)
}
else if (tex->id.us > 1) {
texn = BKE_texture_copy(tex);
- BKE_copy_animdata_id_action(&texn->id);
+ BKE_animdata_copy_id_action(&texn->id);
tex->id.newid = (ID *)texn;
tex->id.us--;
*from = texn;
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index f43789a0428..168891f6459 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -80,7 +80,7 @@
static void ED_object_shape_key_add(bContext *C, Object *ob, const bool from_mix)
{
KeyBlock *kb;
- if ((kb = BKE_object_insert_shape_key(ob, NULL, from_mix))) {
+ if ((kb = BKE_object_shapekey_insert(ob, NULL, from_mix))) {
Key *key = BKE_key_from_object(ob);
/* for absolute shape keys, new keys may not be added last */
ob->shapenr = BLI_findindex(&key->block, kb) + 1;
@@ -91,82 +91,21 @@ static void ED_object_shape_key_add(bContext *C, Object *ob, const bool from_mix
/*********************** remove shape key ***********************/
-static bool ED_object_shape_key_remove_all(Main *bmain, Object *ob)
+static bool object_shapekey_remove(Main *bmain, Object *ob)
{
- Key *key;
-
- key = BKE_key_from_object(ob);
- if (key == NULL)
- return false;
-
- switch (key->from_extra.type) {
- case KEY_OWNER_MESH: ((Mesh *)key->from)->key = NULL; break;
- case KEY_OWNER_CURVE: ((Curve *)key->from)->key = NULL; break;
- case KEY_OWNER_LATTICE: ((Lattice *)key->from)->key = NULL; break;
- }
-
- BKE_libblock_free_us(bmain, key);
-
- return true;
-}
-
-static bool ED_object_shape_key_remove(Main *bmain, Object *ob)
-{
- KeyBlock *kb, *rkb;
- Key *key;
+ KeyBlock *kb;
+ Key *key = BKE_key_from_object(ob);
- key = BKE_key_from_object(ob);
- if (key == NULL)
+ if (key == NULL) {
return false;
+ }
kb = BLI_findlink(&key->block, ob->shapenr - 1);
-
if (kb) {
- for (rkb = key->block.first; rkb; rkb = rkb->next)
- if (rkb->relative == ob->shapenr - 1)
- rkb->relative = 0;
-
- BLI_remlink(&key->block, kb);
- key->totkey--;
- if (key->refkey == kb) {
- key->refkey = key->block.first;
-
- if (key->refkey) {
- /* apply new basis key on original data */
- switch (ob->type) {
- case OB_MESH:
- BKE_keyblock_convert_to_mesh(key->refkey, ob->data);
- break;
- case OB_CURVE:
- case OB_SURF:
- BKE_keyblock_convert_to_curve(key->refkey, ob->data, BKE_curve_nurbs_get(ob->data));
- break;
- case OB_LATTICE:
- BKE_keyblock_convert_to_lattice(key->refkey, ob->data);
- break;
- }
- }
- }
-
- if (kb->data) MEM_freeN(kb->data);
- MEM_freeN(kb);
-
- if (ob->shapenr > 1) {
- ob->shapenr--;
- }
+ return BKE_object_shapekey_remove(bmain, ob, kb);
}
-
- if (key->totkey == 0) {
- switch (key->from_extra.type) {
- case KEY_OWNER_MESH: ((Mesh *)key->from)->key = NULL; break;
- case KEY_OWNER_CURVE: ((Curve *)key->from)->key = NULL; break;
- case KEY_OWNER_LATTICE: ((Lattice *)key->from)->key = NULL; break;
- }
- BKE_libblock_free_us(bmain, key);
- }
-
- return true;
+ return false;
}
static bool object_shape_key_mirror(bContext *C, Object *ob,
@@ -327,6 +266,8 @@ static int shape_key_add_exec(bContext *C, wmOperator *op)
ED_object_shape_key_add(C, ob, from_mix);
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
return OPERATOR_FINISHED;
}
@@ -355,10 +296,10 @@ static int shape_key_remove_exec(bContext *C, wmOperator *op)
bool changed = false;
if (RNA_boolean_get(op->ptr, "all")) {
- changed = ED_object_shape_key_remove_all(bmain, ob);
+ changed = BKE_object_shapekey_free(bmain, ob);
}
else {
- changed = ED_object_shape_key_remove(bmain, ob);
+ changed = object_shapekey_remove(bmain, ob);
}
if (changed) {
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 92fe5ded4dd..340b662c0ef 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -939,8 +939,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
/* convert the offset to parent space */
BKE_object_to_mat4(ob, obmat);
- copy_v3_v3(centn, cent);
- mul_mat3_m4_v3(obmat, centn); /* omit translation part */
+ mul_v3_mat3_m4v3(centn, obmat, cent); /* omit translation part */
add_v3_v3(ob->loc, centn);
@@ -970,8 +969,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
ob_other->flag |= OB_DONE;
DAG_id_tag_update(&ob_other->id, OB_RECALC_OB | OB_RECALC_DATA);
- copy_v3_v3(centn, cent);
- mul_mat3_m4_v3(ob_other->obmat, centn); /* omit translation part */
+ mul_v3_mat3_m4v3(centn, ob_other->obmat, cent); /* omit translation part */
add_v3_v3(ob_other->loc, centn);
BKE_object_where_is_calc(scene, ob_other);
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index f885cbbb24f..960b29ae38e 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -2062,7 +2062,7 @@ void ED_vgroup_mirror(Object *ob,
/* object mode / weight paint */
MVert *mv, *mv_mirr;
int vidx, vidx_mirr;
- const int use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
if (me->dvert == NULL) {
goto cleanup;
diff --git a/source/blender/editors/object/object_warp.c b/source/blender/editors/object/object_warp.c
index 7413bb07c4c..9f4da87903d 100644
--- a/source/blender/editors/object/object_warp.c
+++ b/source/blender/editors/object/object_warp.c
@@ -275,14 +275,14 @@ static int object_warp_verts_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void OBJECT_OT_vertex_warp(struct wmOperatorType *ot)
+void TRANSFORM_OT_vertex_warp(struct wmOperatorType *ot)
{
PropertyRNA *prop;
/* identifiers */
ot->name = "Warp";
ot->description = "Warp vertices around the cursor";
- ot->idname = "OBJECT_OT_vertex_warp";
+ ot->idname = "TRANSFORM_OT_vertex_warp";
/* api callbacks */
ot->exec = object_warp_verts_exec;
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 6c3952bce83..cf02d2773c0 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -402,12 +402,12 @@ static void PE_set_view3d_data(bContext *C, PEData *data)
/* note, the object argument means the modelview matrix does not account for the objects matrix, use viewmat rather than (obmat * viewmat) */
view3d_get_transformation(data->vc.ar, data->vc.rv3d, NULL, &data->mats);
- if ((data->vc.v3d->drawtype>OB_WIRE) && (data->vc.v3d->flag & V3D_ZBUF_SELECT)) {
+ if (V3D_IS_ZBUF(data->vc.v3d)) {
if (data->vc.v3d->flag & V3D_INVALID_BACKBUF) {
/* needed or else the draw matrix can be incorrect */
view3d_operator_needs_opengl(C);
- view3d_validate_backbuf(&data->vc);
+ ED_view3d_backbuf_validate(&data->vc);
/* we may need to force an update here by setting the rv3d as dirty
* for now it seems ok, but take care!:
* rv3d->depths->dirty = 1; */
@@ -416,18 +416,18 @@ static void PE_set_view3d_data(bContext *C, PEData *data)
}
}
-static void PE_create_shape_tree(PEData *data, Object *shapeob)
+static bool PE_create_shape_tree(PEData *data, Object *shapeob)
{
DerivedMesh *dm = shapeob->derivedFinal;
memset(&data->shape_bvh, 0, sizeof(data->shape_bvh));
if (!dm) {
- return;
+ return false;
}
DM_ensure_tessface(dm);
- bvhtree_from_mesh_faces(&data->shape_bvh, dm, 0.0f, 4, 8);
+ return bvhtree_from_mesh_faces(&data->shape_bvh, dm, 0.0f, 4, 8);
}
static void PE_free_shape_tree(PEData *data)
@@ -445,8 +445,8 @@ static bool key_test_depth(PEData *data, const float co[3], const int screen_co[
float depth;
/* nothing to do */
- if ((v3d->drawtype<=OB_WIRE) || (v3d->flag & V3D_ZBUF_SELECT)==0)
- return 1;
+ if (!V3D_IS_ZBUF(v3d))
+ return true;
/* used to calculate here but all callers have the screen_co already, so pass as arg */
#if 0
@@ -4069,11 +4069,12 @@ void PARTICLE_OT_brush_edit(wmOperatorType *ot)
static int shape_cut_poll(bContext *C)
{
if (PE_hair_poll(C)) {
- Scene *scene= CTX_data_scene(C);
- ParticleEditSettings *pset= PE_settings(scene);
+ Scene *scene = CTX_data_scene(C);
+ ParticleEditSettings *pset = PE_settings(scene);
- if (pset->shape_object)
+ if (pset->shape_object && (pset->shape_object->type == OB_MESH)) {
return true;
+ }
}
return false;
@@ -4103,6 +4104,8 @@ static bool shape_cut_test_point(PEData *data, ParticleCacheKey *key)
userdata.bvhdata = data->shape_bvh;
userdata.num_hits = 0;
+ userdata.bvhdata = data->shape_bvh;
+ userdata.num_hits = 0;
BLI_bvhtree_ray_cast_all(shape_bvh->tree, key->co, dir, 0.0f, point_inside_bvh_cb, &userdata);
/* for any point inside a watertight mesh the number of hits is uneven */
@@ -4188,7 +4191,10 @@ static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
int removed;
PE_set_data(C, &data);
- PE_create_shape_tree(&data, shapeob);
+ if (!PE_create_shape_tree(&data, shapeob)) {
+ /* shapeob may not have faces... */
+ return OPERATOR_CANCELLED;
+ }
if (selected)
foreach_selected_point(&data, shape_cut);
@@ -4454,7 +4460,7 @@ void PE_undo_step(Scene *scene, int step)
DAG_id_tag_update(&OBACT->id, OB_RECALC_DATA);
}
-int PE_undo_valid(Scene *scene)
+bool PE_undo_is_valid(Scene *scene)
{
PTCacheEdit *edit= PE_get_current(scene, OBACT);
@@ -4505,18 +4511,19 @@ void PE_undo_number(Scene *scene, int nr)
/* get name of undo item, return null if no item with this index */
/* if active pointer, set it to 1 if true */
-const char *PE_undo_get_name(Scene *scene, int nr, int *active)
+const char *PE_undo_get_name(Scene *scene, int nr, bool *r_active)
{
PTCacheEdit *edit= PE_get_current(scene, OBACT);
PTCacheUndo *undo;
- if (active) *active= 0;
+ if (r_active) *r_active = false;
if (edit) {
undo= BLI_findlink(&edit->undo, nr);
if (undo) {
- if (active && undo==edit->curundo)
- *active= 1;
+ if (r_active && (undo == edit->curundo)) {
+ *r_active = true;
+ }
return undo->name;
}
}
@@ -4842,3 +4849,89 @@ void PARTICLE_OT_edited_clear(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
}
+/************************ Propagate Shape Key *************************/
+
+static int PE_count_keys(PTCacheEdit *edit)
+{
+ int totkey = 0, p;
+ for (p = 0; p < edit->totpoint; ++p) {
+ totkey += edit->points[p].totkey;
+ }
+ return totkey;
+}
+
+static void shape_propagate(PTCacheEdit *edit, int totkey, KeyBlock *kb, wmOperator *UNUSED(op))
+{
+ PTCacheEditPoint *point;
+ float *fp;
+ int i, k;
+
+ if (kb->totelem != totkey)
+ return;
+
+ fp = kb->data;
+ point = edit->points;
+ for (i = 0; i < edit->totpoint; ++i, ++point) {
+ PTCacheEditKey *key = point->keys;
+ const bool use_point = !(point->flag & PEP_HIDE);
+
+ for (k = 0; k < point->totkey; ++k, ++key) {
+ const bool use_key = (key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE);
+
+ if (use_point && use_key) {
+ copy_v3_v3(fp, key->co);
+
+ point->flag |= PEP_EDIT_RECALC;
+ }
+
+ fp += 3;
+ }
+ }
+}
+
+static int particle_shape_propagate_to_all_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ParticleEditSettings *pset = PE_settings(scene);
+ Object *ob = ED_object_context(C);
+ ParticleSystem *psys = psys_get_current(ob);
+ PTCacheEdit *edit = psys->edit;
+ Key *key = psys->key;
+ KeyBlock *kb;
+ const int totkey = PE_count_keys(edit);
+
+ if (!key)
+ return OPERATOR_CANCELLED;
+
+ /* we might need world space coordinates, update to be sure */
+ update_world_cos(ob, edit);
+
+ for (kb = key->block.first; kb; kb = kb->next)
+ shape_propagate(edit, totkey, kb, op);
+
+ update_world_cos(ob, edit);
+ PE_update_object(scene, ob, 1);
+
+ if (!(pset->flag & PE_KEEP_LENGTHS))
+ recalc_lengths(edit);
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+
+void PARTICLE_OT_shape_propagate_to_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Shape Propagate";
+ ot->description = "Apply selected vertex locations to all other shape keys";
+ ot->idname = "PARTICLE_OT_shape_propagate_to_all";
+
+ /* api callbacks */
+ ot->exec = particle_shape_propagate_to_all_exec;
+ ot->poll = PE_hair_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h
index 0d3a86a3f98..1d68a429c06 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -61,6 +61,8 @@ void PARTICLE_OT_shape_cut(struct wmOperatorType *ot);
void PARTICLE_OT_particle_edit_toggle(struct wmOperatorType *ot);
void PARTICLE_OT_edited_clear(struct wmOperatorType *ot);
+void PARTICLE_OT_shape_propagate_to_all(struct wmOperatorType *ot);
+
/* particle_object.c */
void OBJECT_OT_particle_system_add(struct wmOperatorType *ot);
void OBJECT_OT_particle_system_remove(struct wmOperatorType *ot);
diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c
index ef278179774..4d78e745606 100644
--- a/source/blender/editors/physics/physics_ops.c
+++ b/source/blender/editors/physics/physics_ops.c
@@ -69,6 +69,8 @@ static void operatortypes_particle(void)
WM_operatortype_append(PARTICLE_OT_particle_edit_toggle);
WM_operatortype_append(PARTICLE_OT_edited_clear);
+ WM_operatortype_append(PARTICLE_OT_shape_propagate_to_all);
+
WM_operatortype_append(OBJECT_OT_particle_system_add);
WM_operatortype_append(OBJECT_OT_particle_system_remove);
diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c
index 9b4f128ef86..c8b944f7d2a 100644
--- a/source/blender/editors/physics/rigidbody_object.c
+++ b/source/blender/editors/physics/rigidbody_object.c
@@ -348,6 +348,7 @@ static int rigidbody_objects_shape_change_exec(bContext *C, wmOperator *op)
if (changed) {
/* send updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
/* done */
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h
index f9377d576bf..54429f9f066 100644
--- a/source/blender/editors/render/render_intern.h
+++ b/source/blender/editors/render/render_intern.h
@@ -32,9 +32,9 @@
#ifndef __RENDER_INTERN_H__
#define __RENDER_INTERN_H__
+struct bContext;
+struct RenderEngine;
struct wmOperatorType;
-struct RenderResult;
-struct Scene;
struct ScrArea;
/* render_shading.c */
@@ -44,6 +44,7 @@ void OBJECT_OT_material_slot_assign(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_select(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_deselect(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_copy(struct wmOperatorType *ot);
+void OBJECT_OT_material_slot_move(struct wmOperatorType *ot);
void MATERIAL_OT_new(struct wmOperatorType *ot);
void TEXTURE_OT_new(struct wmOperatorType *ot);
@@ -55,6 +56,9 @@ void MATERIAL_OT_paste(struct wmOperatorType *ot);
void SCENE_OT_render_layer_add(struct wmOperatorType *ot);
void SCENE_OT_render_layer_remove(struct wmOperatorType *ot);
+void SCENE_OT_render_view_add(struct wmOperatorType *ot);
+void SCENE_OT_render_view_remove(struct wmOperatorType *ot);
+
#ifdef WITH_FREESTYLE
void SCENE_OT_freestyle_module_add(struct wmOperatorType *ot);
void SCENE_OT_freestyle_module_remove(struct wmOperatorType *ot);
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 8fcd91b7791..dc4c2c71878 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -48,6 +48,7 @@
#include "DNA_userdef_types.h"
#include "BKE_blender.h"
+#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_colortools.h"
#include "BKE_depsgraph.h"
@@ -116,7 +117,7 @@ typedef struct RenderJob {
} RenderJob;
/* called inside thread! */
-static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibuf, ImageUser *iuser, volatile rcti *renrect)
+static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibuf, ImageUser *iuser, volatile rcti *renrect, const char *viewname)
{
Scene *scene = rj->scene;
const float *rectf = NULL;
@@ -187,12 +188,16 @@ static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibu
* - sergey -
*/
/* TODO(sergey): Need to check has_combined here? */
- if (iuser->pass == 0) {
+ if (iuser->passtype == SCE_PASS_COMBINED) {
+ RenderView *rv;
+ size_t view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
+ rv = RE_RenderViewGetById(rr, view_id);
+
/* find current float rect for display, first case is after composite... still weak */
- if (rr->rectf)
- rectf = rr->rectf;
+ if (rv->rectf)
+ rectf = rv->rectf;
else {
- if (rr->rect32) {
+ if (rv->rect32) {
/* special case, currently only happens with sequencer rendering,
* which updates the whole frame, so we can only mark display buffer
* as invalid here (sergey)
@@ -201,8 +206,8 @@ static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibu
return;
}
else {
- if (rr->renlay == NULL || rr->renlay->rectf == NULL) return;
- rectf = rr->renlay->rectf;
+ if (rr->renlay == NULL) return;
+ rectf = RE_RenderLayerGetPass(rr->renlay, SCE_PASS_COMBINED, viewname);
}
}
if (rectf == NULL) return;
@@ -518,7 +523,6 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr,
}
}
- iuser->pass = sima->iuser.pass;
iuser->layer = sima->iuser.layer;
RE_ReleaseResult(rj->re);
@@ -531,6 +535,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
Image *ima = rj->image;
ImBuf *ibuf;
void *lock;
+ const char *viewname = RE_GetActiveRenderView(rj->re);
/* only update if we are displaying the slot being rendered */
if (ima->render_slot != ima->last_render_slot) {
@@ -563,7 +568,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
ibuf->channels == 1 ||
U.image_draw_method != IMAGE_DRAW_METHOD_GLSL)
{
- image_buffer_rect_update(rj, rr, ibuf, &rj->iuser, renrect);
+ image_buffer_rect_update(rj, rr, ibuf, &rj->iuser, renrect, viewname);
}
/* make jobs timer to send notifier */
@@ -891,6 +896,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
rj->write_still = is_write_still && !is_animation;
rj->iuser.scene = scene;
rj->iuser.ok = 1;
+ rj->iuser.passtype = SCE_PASS_COMBINED;
rj->reports = op->reports;
rj->orig_layer = 0;
rj->last_layer = 0;
@@ -1227,10 +1233,10 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
if ((update_flag & (PR_UPDATE_RENDERSIZE | PR_UPDATE_DATABASE)) || rstats->convertdone == 0) {
RenderData rdata;
- /* no osa, blur, seq, layers, etc for preview render */
+ /* no osa, blur, seq, layers, savebuffer etc for preview render */
rdata = rp->scene->r;
rdata.mode &= ~(R_OSA | R_MBLUR | R_BORDER | R_PANORAMA);
- rdata.scemode &= ~(R_DOSEQ | R_DOCOMP | R_FREE_IMAGE);
+ rdata.scemode &= ~(R_DOSEQ | R_DOCOMP | R_FREE_IMAGE | R_EXR_TILE_FILE | R_FULL_SAMPLE);
rdata.scemode |= R_VIEWPORT_PREVIEW;
/* we do use layers, but only active */
@@ -1487,7 +1493,8 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C)
if (re == NULL) return;
}
- RE_AcquireResultImage(re, &rres);
+ /* Viewport render preview doesn't support multiview, view hardcoded to 0 */
+ RE_AcquireResultImage(re, &rres, 0);
if (rres.rectf) {
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -1545,8 +1552,8 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C)
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glPixelZoom(scale_x, scale_y);
glaDrawPixelsAuto(xof, yof, rres.rectx, rres.recty,
- GL_RGBA, GL_UNSIGNED_BYTE,
- GL_NEAREST, display_buffer);
+ GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST,
+ 1.0f, display_buffer);
glPixelZoom(1.0f, 1.0f);
glDisable(GL_BLEND);
@@ -1617,7 +1624,17 @@ Scene *ED_render_job_get_scene(const bContext *C)
RenderJob *rj = (RenderJob *)WM_jobs_customdata_from_type(wm, WM_JOB_TYPE_RENDER);
if (rj)
- return rj->current_scene;
+ return rj->scene;
return NULL;
}
+
+Scene *ED_render_job_get_current_scene(const bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ RenderJob *rj = (RenderJob *)WM_jobs_customdata_from_type(wm, WM_JOB_TYPE_RENDER);
+ if (rj) {
+ return rj->current_scene;
+ }
+ return NULL;
+}
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 9fb83557dc2..c265913f113 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -39,6 +39,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_jitter.h"
+#include "BLI_threads.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -103,11 +104,17 @@ typedef struct OGLRender {
bMovieHandle *mh;
int cfrao, nfra;
+ size_t totvideos;
+
+ /* quick lookup */
+ int view_id;
+
/* wm vars for timer and progress cursor */
wmWindowManager *wm;
wmWindow *win;
wmTimer *timer; /* use to check if running modal or not (invoke'd or exec'd)*/
+ void **movie_ctx_arr;
} OGLRender;
/* added because v3d is not always valid */
@@ -121,25 +128,144 @@ static unsigned int screen_opengl_layers(OGLRender *oglrender)
}
}
-static void screen_opengl_render_apply(OGLRender *oglrender)
+static bool screen_opengl_is_multiview(OGLRender *oglrender)
+{
+ View3D *v3d = oglrender->v3d;
+ RegionView3D *rv3d = oglrender->rv3d;
+ RenderData *rd = &oglrender->scene->r;
+
+ if ((rd == NULL) || ((!oglrender->is_sequencer) && ((rv3d == NULL) || (v3d == NULL))))
+ return false;
+
+ return (rd->scemode & R_MULTIVIEW) && ((oglrender->is_sequencer) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
+}
+
+static void screen_opengl_views_setup(OGLRender *oglrender)
+{
+ RenderResult *rr;
+ RenderView *rv;
+ SceneRenderView *srv;
+ bool is_multiview;
+ Object *camera;
+ View3D *v3d = oglrender->v3d;
+
+ RenderData *rd = &oglrender->scene->r;
+
+ rr = RE_AcquireResultWrite(oglrender->re);
+
+ is_multiview = screen_opengl_is_multiview(oglrender);
+
+ if (!is_multiview) {
+ /* we only have one view when multiview is off */
+ rv = rr->views.first;
+
+ if (rv == NULL) {
+ rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
+ BLI_addtail(&rr->views, rv);
+ }
+
+ while (rv->next) {
+ RenderView *rv_del = rv->next;
+ BLI_remlink(&rr->views, rv_del);
+
+ if (rv_del->rectf)
+ MEM_freeN(rv_del->rectf);
+
+ if (rv_del->rectz)
+ MEM_freeN(rv_del->rectz);
+
+ MEM_freeN(rv_del);
+ }
+ }
+ else {
+ if (!oglrender->is_sequencer)
+ RE_SetOverrideCamera(oglrender->re, V3D_CAMERA_SCENE(oglrender->scene, v3d));
+
+ /* remove all the views that are not needed */
+ rv = rr->views.last;
+ while (rv) {
+ srv = BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name));
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ if (rv->rectf == NULL)
+ rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect");
+ rv = rv->prev;
+ }
+ else {
+ RenderView *rv_del = rv;
+ rv = rv_del->prev;
+
+ BLI_remlink(&rr->views, rv_del);
+
+ if (rv_del->rectf)
+ MEM_freeN(rv_del->rectf);
+
+ if (rv_del->rectz)
+ MEM_freeN(rv_del->rectz);
+
+ MEM_freeN(rv_del);
+ }
+ }
+
+ /* create all the views that are needed */
+ for (srv = rd->views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv) == false)
+ continue;
+
+ rv = BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name));
+
+ if (rv == NULL) {
+ rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
+ BLI_strncpy(rv->name, srv->name, sizeof(rv->name));
+ BLI_addtail(&rr->views, rv);
+ }
+ }
+ }
+
+ for (rv = rr->views.first; rv; rv = rv->next) {
+ if (rv->rectf == NULL) {
+ rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect");
+ }
+ }
+
+ BLI_lock_thread(LOCK_DRAW_IMAGE);
+ if (is_multiview && BKE_scene_multiview_is_stereo3d(rd)) {
+ oglrender->ima->flag |= IMA_IS_STEREO;
+ }
+ else {
+ oglrender->ima->flag &= ~IMA_IS_STEREO;
+ oglrender->iuser.flag &= ~IMA_SHOW_STEREO;
+ }
+ BLI_unlock_thread(LOCK_DRAW_IMAGE);
+
+ /* will only work for non multiview correctly */
+ if (v3d) {
+ camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, "new opengl render view");
+ BKE_render_result_stamp_info(oglrender->scene, camera, rr);
+ }
+ else {
+ BKE_render_result_stamp_info(oglrender->scene, oglrender->scene->camera, rr);
+ }
+
+ RE_ReleaseResult(oglrender->re);
+}
+
+static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
{
Scene *scene = oglrender->scene;
ARegion *ar = oglrender->ar;
View3D *v3d = oglrender->v3d;
RegionView3D *rv3d = oglrender->rv3d;
- RenderResult *rr;
Object *camera = NULL;
ImBuf *ibuf;
- void *lock;
float winmat[4][4];
+ float *rectf = RE_RenderViewGetById(rr, oglrender->view_id)->rectf;
int sizex = oglrender->sizex;
int sizey = oglrender->sizey;
const short view_context = (v3d != NULL);
bool draw_bgpic = true;
- bool draw_sky = (scene->r.alphamode == R_ADDSKY) && v3d && (v3d->flag3 & V3D_SHOW_WORLD);
+ bool draw_sky = (scene->r.alphamode == R_ADDSKY);
unsigned char *rect = NULL;
-
- rr = RE_AcquireResultRead(oglrender->re);
+ const char *viewname = RE_GetActiveRenderView(oglrender->re);
if (oglrender->is_sequencer) {
SeqRenderData context;
@@ -152,6 +278,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
oglrender->sizex, oglrender->sizey, 100.0f,
&context);
+ context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
ibuf = BKE_sequencer_give_ibuf(&context, CFRA, chanshown);
if (ibuf) {
@@ -175,7 +302,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
BKE_sequencer_imbuf_from_sequencer_space(scene, linear_ibuf);
}
- memcpy(rr->rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey);
+ memcpy(rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey);
IMB_freeImBuf(linear_ibuf);
}
@@ -199,10 +326,12 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect);
+ BLI_assert(rectf != NULL);
+
for (i = 0; i < sizex * sizey * 4; i += 4) {
float col_src[4];
rgba_uchar_to_float(col_src, &gp_rect[i]);
- blend_color_mix_float(&rr->rectf[i], &rr->rectf[i], col_src);
+ blend_color_mix_float(&rectf[i], &rectf[i], col_src);
}
GPU_offscreen_unbind(oglrender->ofs, true);
@@ -220,10 +349,17 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
/* render 3d view */
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
- /*int is_ortho = scene->r.mode & R_ORTHO;*/
- camera = v3d->camera;
+#if 0
+ const bool is_ortho = (scene->r.mode & R_ORTHO) != 0;
+#endif
+ camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname);
RE_GetCameraWindow(oglrender->re, camera, scene->r.cfra, winmat);
- is_persp = true;
+ if (camera->type == OB_CAMERA) {
+ Camera *cam = camera->data;
+ is_persp = cam->type == CAM_PERSP;
+ }
+ else
+ is_persp = true;
BKE_camera_to_gpu_dof(camera, &fx_settings);
}
@@ -244,7 +380,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
ED_view3d_draw_offscreen(
scene, v3d, ar, sizex, sizey, NULL, winmat,
draw_bgpic, draw_sky, is_persp,
- oglrender->ofs, oglrender->fx, &fx_settings);
+ oglrender->ofs, oglrender->fx, &fx_settings, viewname);
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
}
else {
@@ -260,7 +396,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
ED_view3d_draw_offscreen(
scene, v3d, ar, sizex, sizey, NULL, winmat,
draw_bgpic, draw_sky, is_persp,
- oglrender->ofs, oglrender->fx, &fx_settings);
+ oglrender->ofs, oglrender->fx, &fx_settings, viewname);
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
for (i = 0; i < sizex * sizey * 4; i++)
@@ -276,7 +412,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
ED_view3d_draw_offscreen(
scene, v3d, ar, sizex, sizey, NULL, winmat_jitter,
draw_bgpic, draw_sky, is_persp,
- oglrender->ofs, oglrender->fx, &fx_settings);
+ oglrender->ofs, oglrender->fx, &fx_settings, viewname);
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
for (i = 0; i < sizex * sizey * 4; i++)
@@ -296,7 +432,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
char err_out[256] = "unknown";
ImBuf *ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, oglrender->sizex, oglrender->sizey,
IB_rect, OB_SOLID, false, true, true,
- (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, err_out);
+ (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, viewname, err_out);
camera = scene->camera;
if (ibuf_view) {
@@ -321,7 +457,8 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
if (rect) {
int profile_to;
-
+ float *rectf = RE_RenderViewGetById(rr, oglrender->view_id)->rectf;
+
if (BKE_scene_check_color_management_enabled(scene))
profile_to = IB_PROFILE_LINEAR_RGB;
else
@@ -329,47 +466,68 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
/* sequencer has got trickier conversion happened above
* also assume opengl's space matches byte buffer color space */
- IMB_buffer_float_from_byte(rr->rectf, rect,
+ IMB_buffer_float_from_byte(rectf, rect,
profile_to, IB_PROFILE_SRGB, true,
oglrender->sizex, oglrender->sizey, oglrender->sizex, oglrender->sizex);
+
+ /* rr->rectf is now filled with image data */
+
+ if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW))
+ BKE_image_stamp_buf(scene, camera, rect, rectf, rr->rectx, rr->recty, 4);
+
+ MEM_freeN(rect);
}
+}
- /* rr->rectf is now filled with image data */
+static void screen_opengl_render_write(OGLRender *oglrender)
+{
+ Scene *scene = oglrender->scene;
+ RenderResult *rr;
+ bool ok;
+ char name[FILE_MAX];
+
+ rr = RE_AcquireResultRead(oglrender->re);
+
+ BKE_image_path_from_imformat(
+ name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
+ &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false, NULL);
+
+ /* write images as individual images or stereo */
+ BKE_render_result_stamp_info(scene, scene->camera, rr);
+ ok = RE_WriteRenderViewsImage(oglrender->reports, rr, scene, false, name);
+
+ RE_ReleaseResultImage(oglrender->re);
+
+ if (ok) printf("OpenGL Render written to '%s'\n", name);
+ else printf("OpenGL Render failed to write '%s'\n", name);
+}
+
+static void screen_opengl_render_apply(OGLRender *oglrender)
+{
+ RenderResult *rr;
+ RenderView *rv;
+ int view_id;
+ ImBuf *ibuf;
+ void *lock;
- if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
- BKE_image_stamp_buf(scene, camera, rect, rr->rectf, rr->rectx, rr->recty, 4);
+ rr = RE_AcquireResultRead(oglrender->re);
+ for (rv = rr->views.first, view_id = 0; rv; rv = rv->next, view_id++) {
+ RE_SetActiveRenderView(oglrender->re, rv->name);
+ oglrender->view_id = view_id;
+ screen_opengl_render_doit(oglrender, rr);
}
RE_ReleaseResult(oglrender->re);
- /* update byte from float buffer */
ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
-
if (ibuf) {
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
-
- /* write file for animation */
- if (oglrender->write_still) {
- char name[FILE_MAX];
- int ok;
-
- if (scene->r.im_format.planes == R_IMF_CHAN_DEPTH_8) {
- IMB_color_to_bw(ibuf);
- }
-
- BKE_image_path_from_imformat(
- name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
- &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false);
- ok = BKE_imbuf_write_as(ibuf, name, &scene->r.im_format, true); /* no need to stamp here */
- if (ok) printf("OpenGL Render written to '%s'\n", name);
- else printf("OpenGL Render failed to write '%s'\n", name);
- }
}
-
BKE_image_release_ibuf(oglrender->ima, ibuf, lock);
- if (rect)
- MEM_freeN(rect);
+ if (oglrender->write_still) {
+ screen_opengl_render_write(oglrender);
+ }
}
static bool screen_opengl_render_init(bContext *C, wmOperator *op)
@@ -381,7 +539,6 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ScrArea *prevsa = CTX_wm_area(C);
ARegion *prevar = CTX_wm_region(C);
- RenderResult *rr;
GPUOffScreen *ofs;
OGLRender *oglrender;
int sizex, sizey;
@@ -454,7 +611,6 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->sseq = CTX_wm_space_seq(C);
}
-
oglrender->prevsa = prevsa;
oglrender->prevar = prevar;
@@ -488,15 +644,17 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
/* create render result */
RE_InitState(oglrender->re, NULL, &scene->r, NULL, sizex, sizey, NULL);
- rr = RE_AcquireResultWrite(oglrender->re);
- if (rr->rectf == NULL)
- rr->rectf = MEM_callocN(sizeof(float) * 4 * sizex * sizey, "screen_opengl_render_init rect");
- RE_ReleaseResult(oglrender->re);
+ /* create render views */
+ screen_opengl_views_setup(oglrender);
/* wm vars */
oglrender->wm = wm;
oglrender->win = win;
+ oglrender->totvideos = 0;
+ oglrender->mh = NULL;
+ oglrender->movie_ctx_arr = NULL;
+
return true;
}
@@ -504,10 +662,19 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
{
Main *bmain = CTX_data_main(C);
Scene *scene = oglrender->scene;
+ size_t i;
if (oglrender->mh) {
- if (BKE_imtype_is_movie(scene->r.im_format.imtype))
- oglrender->mh->end_movie();
+ if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
+ for (i = 0; i < oglrender->totvideos; i++) {
+ oglrender->mh->end_movie(oglrender->movie_ctx_arr[i]);
+ oglrender->mh->context_free(oglrender->movie_ctx_arr[i]);
+ }
+ }
+
+ if (oglrender->movie_ctx_arr) {
+ MEM_freeN(oglrender->movie_ctx_arr);
+ }
}
if (oglrender->timer) { /* exec will not have a timer */
@@ -548,13 +715,27 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
oglrender = op->customdata;
scene = oglrender->scene;
+ oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r);
oglrender->reports = op->reports;
- oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype);
+
if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
- if (!oglrender->mh->start_movie(scene, &scene->r, oglrender->sizex, oglrender->sizey, oglrender->reports)) {
- screen_opengl_render_end(C, oglrender);
- return 0;
+ size_t i, width, height;
+
+ BKE_scene_multiview_videos_dimensions_get(&scene->r, oglrender->sizex, oglrender->sizey, &width, &height);
+ oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies");
+ oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype);
+
+ for (i = 0; i < oglrender->totvideos; i++) {
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
+
+ oglrender->movie_ctx_arr[i] = oglrender->mh->context_create();
+ if (!oglrender->mh->start_movie(oglrender->movie_ctx_arr[i], scene, &scene->r, oglrender->sizex,
+ oglrender->sizey, oglrender->reports, PRVRANGEON != 0, suffix))
+ {
+ screen_opengl_render_end(C, oglrender);
+ return 0;
+ }
}
}
@@ -564,18 +745,17 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
return 1;
}
+
static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
OGLRender *oglrender = op->customdata;
Scene *scene = oglrender->scene;
- ImBuf *ibuf, *ibuf_save = NULL;
- void *lock;
char name[FILE_MAX];
bool ok = false;
const bool view_context = (oglrender->v3d != NULL);
- Object *camera = NULL;
bool is_movie;
+ RenderResult *rr;
/* go to next frame */
if (CFRA < oglrender->nfra)
@@ -595,7 +775,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
if (!is_movie) {
BKE_image_path_from_imformat(
name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
- &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true);
+ &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL);
if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name);
@@ -615,89 +795,41 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
if (BKE_scene_camera_switch_update(scene)) {
oglrender->v3d->camera = scene->camera;
}
-
- camera = oglrender->v3d->camera;
}
}
else {
BKE_scene_camera_switch_update(scene);
-
- camera = scene->camera;
}
/* render into offscreen buffer */
screen_opengl_render_apply(oglrender);
/* save to disk */
- ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
-
- if (ibuf) {
- bool needs_free = false;
-
- ibuf_save = ibuf;
-
- if (is_movie || !BKE_imtype_requires_linear_float(scene->r.im_format.imtype)) {
- ibuf_save = IMB_colormanagement_imbuf_for_write(ibuf, true, true, &scene->view_settings,
- &scene->display_settings, &scene->r.im_format);
-
- needs_free = true;
- }
-
- /* color -> grayscale */
- /* editing directly would alter the render view */
- if (scene->r.im_format.planes == R_IMF_PLANES_BW) {
- ImBuf *ibuf_bw = IMB_dupImBuf(ibuf_save);
- IMB_color_to_bw(ibuf_bw);
-
- if (needs_free)
- IMB_freeImBuf(ibuf_save);
-
- ibuf_save = ibuf_bw;
- }
- else {
- /* this is lightweight & doesnt re-alloc the buffers, only do this
- * to save the correct bit depth since the image is always RGBA */
- ImBuf *ibuf_cpy = IMB_allocImBuf(ibuf_save->x, ibuf_save->y, scene->r.im_format.planes, 0);
-
- ibuf_cpy->rect = ibuf_save->rect;
- ibuf_cpy->rect_float = ibuf_save->rect_float;
- ibuf_cpy->zbuf_float = ibuf_save->zbuf_float;
-
- if (needs_free) {
- ibuf_cpy->mall = ibuf_save->mall;
- ibuf_save->mall = 0;
- IMB_freeImBuf(ibuf_save);
- }
+ rr = RE_AcquireResultRead(oglrender->re);
- ibuf_save = ibuf_cpy;
+ if (is_movie) {
+ ok = RE_WriteRenderViewsMovie(oglrender->reports, rr, scene, &scene->r, oglrender->mh, oglrender->sizex,
+ oglrender->sizey, oglrender->movie_ctx_arr, oglrender->totvideos, PRVRANGEON != 0);
+ if (ok) {
+ printf("Append frame %d", scene->r.cfra);
+ BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra);
}
-
- if (is_movie) {
- ok = oglrender->mh->append_movie(&scene->r, PSFRA, CFRA, (int *)ibuf_save->rect,
- oglrender->sizex, oglrender->sizey, oglrender->reports);
- if (ok) {
- printf("Append frame %d", scene->r.cfra);
- BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra);
- }
+ }
+ else {
+ BKE_render_result_stamp_info(scene, scene->camera, rr);
+ ok = RE_WriteRenderViewsImage(op->reports, rr, scene, true, name);
+ if (ok) {
+ printf("Saved: %s", name);
+ BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name);
}
else {
- ok = BKE_imbuf_write_stamp(scene, camera, ibuf_save, name, &scene->r.im_format);
-
- if (ok == 0) {
- printf("Write error: cannot save %s\n", name);
- BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name);
- }
- else {
- printf("Saved: %s", name);
- BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name);
- }
+ printf("Write error: cannot save %s\n", name);
+ BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name);
}
-
- if (needs_free)
- IMB_freeImBuf(ibuf_save);
}
- BKE_image_release_ibuf(oglrender->ima, ibuf, lock);
+ RE_ReleaseResult(oglrender->re);
+
/* movie stats prints have no line break */
printf("\n");
diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.c
index 0d334082a2b..f98083f7e74 100644
--- a/source/blender/editors/render/render_ops.c
+++ b/source/blender/editors/render/render_ops.c
@@ -47,6 +47,7 @@ void ED_operatortypes_render(void)
WM_operatortype_append(OBJECT_OT_material_slot_select);
WM_operatortype_append(OBJECT_OT_material_slot_deselect);
WM_operatortype_append(OBJECT_OT_material_slot_copy);
+ WM_operatortype_append(OBJECT_OT_material_slot_move);
WM_operatortype_append(MATERIAL_OT_new);
WM_operatortype_append(TEXTURE_OT_new);
@@ -58,6 +59,9 @@ void ED_operatortypes_render(void)
WM_operatortype_append(SCENE_OT_render_layer_add);
WM_operatortype_append(SCENE_OT_render_layer_remove);
+ WM_operatortype_append(SCENE_OT_render_view_add);
+ WM_operatortype_append(SCENE_OT_render_view_remove);
+
#ifdef WITH_FREESTYLE
WM_operatortype_append(SCENE_OT_freestyle_module_add);
WM_operatortype_append(SCENE_OT_freestyle_module_remove);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 99edaff759e..9ed0cec5545 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -79,7 +79,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-
+#include "IMB_thumbs.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -128,7 +128,7 @@ ImBuf *get_brush_icon(Brush *brush)
}
if (brush->icon_imbuf)
- BKE_icon_changed(BKE_icon_getid(&brush->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&brush->id));
}
}
}
@@ -161,6 +161,7 @@ typedef struct ShaderPreview {
unsigned int *pr_rect;
int pr_method;
+ Main *bmain;
Main *pr_main;
} ShaderPreview;
@@ -171,6 +172,7 @@ typedef struct IconPreviewSize {
} IconPreviewSize;
typedef struct IconPreview {
+ Main *bmain;
Scene *scene;
void *owner;
ID *id;
@@ -261,12 +263,14 @@ static Scene *preview_get_scene(Main *pr_main)
/* call this with a pointer to initialize preview scene */
/* call this with NULL to restore assigned ID pointers in preview scene */
-static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPreview *sp)
+static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_type, ShaderPreview *sp)
{
Scene *sce;
Base *base;
Main *pr_main = sp->pr_main;
-
+
+ memcpy(pr_main->name, bmain->name, sizeof(pr_main->name));
+
sce = preview_get_scene(pr_main);
if (sce) {
@@ -423,7 +427,7 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre
Tex *tex = NULL, *origtex = (Tex *)id;
if (origtex) {
- tex = localize_texture(origtex);
+ tex = BKE_texture_localize(origtex);
sp->texcopy = tex;
BLI_addtail(&pr_main->tex, tex);
}
@@ -525,6 +529,7 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre
static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect, rcti *newrect)
{
Render *re;
+ RenderView *rv;
RenderResult rres;
char name[32];
int offx = 0;
@@ -548,9 +553,16 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect,
/* test if something rendered ok */
re = RE_GetRender(name);
- RE_AcquireResultImage(re, &rres);
- if (rres.rectf) {
+ if (re == NULL)
+ return false;
+
+ RE_AcquireResultImageViews(re, &rres);
+
+ /* material preview only needs monoscopy (view 0) */
+ rv = RE_RenderViewGetById(&rres, 0);
+
+ if (rv->rectf) {
if (ABS(rres.rectx - newx) < 2 && ABS(rres.recty - newy) < 2) {
@@ -561,9 +573,11 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect,
unsigned char *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect");
float fx = rect->xmin + offx;
float fy = rect->ymin;
+
+ /* material preview only needs monoscopy (view 0) */
if (re)
- RE_AcquiredResultGet32(re, &rres, (unsigned int *)rect_byte);
-
+ RE_AcquiredResultGet32(re, &rres, (unsigned int *)rect_byte, 0);
+
glaDrawPixelsSafe(fx, fy, rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect_byte);
MEM_freeN(rect_byte);
@@ -573,7 +587,7 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect,
}
}
- RE_ReleaseResultImage(re);
+ RE_ReleaseResultImageViews(re, &rres);
return ok;
}
@@ -702,7 +716,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
}
/* get the stuff from the builtin preview dbase */
- sce = preview_prepare_scene(sp->scene, id, idtype, sp);
+ sce = preview_prepare_scene(sp->bmain, sp->scene, id, idtype, sp);
if (sce == NULL) return;
if (!split || first) sprintf(name, "Preview %p", sp->owner);
@@ -757,7 +771,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
}
/* unassign the pointers, reset vars */
- preview_prepare_scene(sp->scene, NULL, GS(id->name), sp);
+ preview_prepare_scene(sp->bmain, sp->scene, NULL, GS(id->name), sp);
/* XXX bad exception, end-exec is not being called in render, because it uses local main */
// if (idtype == ID_TE) {
@@ -925,65 +939,87 @@ static void set_alpha(char *cp, int sizex, int sizey, char alpha)
static void icon_preview_startjob(void *customdata, short *stop, short *do_update)
{
ShaderPreview *sp = customdata;
- ID *id = sp->id;
- short idtype = GS(id->name);
-
- if (idtype == ID_IM) {
- Image *ima = (Image *)id;
- ImBuf *ibuf = NULL;
- ImageUser iuser = {NULL};
- /* ima->ok is zero when Image cannot load */
- if (ima == NULL || ima->ok == 0)
- return;
+ if (sp->pr_method == PR_ICON_DEFERRED) {
+ PreviewImage *prv = sp->owner;
+ ImBuf *thumb;
+ char *deferred_data = PRV_DEFERRED_DATA(prv);
+ int source = deferred_data[0];
+ char *path = &deferred_data[1];
- /* setup dummy image user */
- iuser.ok = iuser.framenr = 1;
- iuser.scene = sp->scene;
-
- /* elubie: this needs to be changed: here image is always loaded if not
- * already there. Very expensive for large images. Need to find a way to
- * only get existing ibuf */
- ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
- if (ibuf == NULL || ibuf->rect == NULL) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- return;
- }
-
- icon_copy_rect(ibuf, sp->sizex, sp->sizey, sp->pr_rect);
+// printf("generating deferred %d×%d preview for %s\n", sp->sizex, sp->sizey, path);
- *do_update = true;
+ thumb = IMB_thumb_manage(path, THB_LARGE, source);
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ if (thumb) {
+ /* PreviewImage assumes premultiplied alhpa... */
+ IMB_premultiply_alpha(thumb);
+
+ icon_copy_rect(thumb, sp->sizex, sp->sizey, sp->pr_rect);
+ IMB_freeImBuf(thumb);
+ }
}
- else if (idtype == ID_BR) {
- Brush *br = (Brush *)id;
+ else {
+ ID *id = sp->id;
+ short idtype = GS(id->name);
+
+ if (idtype == ID_IM) {
+ Image *ima = (Image *)id;
+ ImBuf *ibuf = NULL;
+ ImageUser iuser = {NULL};
+
+ /* ima->ok is zero when Image cannot load */
+ if (ima == NULL || ima->ok == 0)
+ return;
+
+ /* setup dummy image user */
+ iuser.ok = iuser.framenr = 1;
+ iuser.scene = sp->scene;
+
+ /* elubie: this needs to be changed: here image is always loaded if not
+ * already there. Very expensive for large images. Need to find a way to
+ * only get existing ibuf */
+ ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ if (ibuf == NULL || ibuf->rect == NULL) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ return;
+ }
- br->icon_imbuf = get_brush_icon(br);
+ icon_copy_rect(ibuf, sp->sizex, sp->sizey, sp->pr_rect);
- memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(unsigned int));
+ *do_update = true;
- if (!(br->icon_imbuf) || !(br->icon_imbuf->rect))
- return;
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+ else if (idtype == ID_BR) {
+ Brush *br = (Brush *)id;
- icon_copy_rect(br->icon_imbuf, sp->sizex, sp->sizey, sp->pr_rect);
+ br->icon_imbuf = get_brush_icon(br);
- *do_update = true;
- }
- else {
- /* re-use shader job */
- shader_preview_startjob(customdata, stop, do_update);
+ memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(unsigned int));
+
+ if (!(br->icon_imbuf) || !(br->icon_imbuf->rect))
+ return;
- /* world is rendered with alpha=0, so it wasn't displayed
- * this could be render option for sky to, for later */
- if (idtype == ID_WO) {
- set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
+ icon_copy_rect(br->icon_imbuf, sp->sizex, sp->sizey, sp->pr_rect);
+
+ *do_update = true;
}
- else if (idtype == ID_MA) {
- Material *ma = (Material *)id;
+ else {
+ /* re-use shader job */
+ shader_preview_startjob(customdata, stop, do_update);
- if (ma->material_type == MA_TYPE_HALO)
+ /* world is rendered with alpha=0, so it wasn't displayed
+ * this could be render option for sky to, for later */
+ if (idtype == ID_WO) {
set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
+ }
+ else if (idtype == ID_MA) {
+ Material *ma = (Material *)id;
+
+ if (ma->material_type == MA_TYPE_HALO)
+ set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
+ }
}
}
}
@@ -995,7 +1031,7 @@ static void common_preview_startjob(void *customdata, short *stop, short *do_upd
{
ShaderPreview *sp = customdata;
- if (sp->pr_method == PR_ICON_RENDER)
+ if (ELEM(sp->pr_method, PR_ICON_RENDER, PR_ICON_DEFERRED))
icon_preview_startjob(customdata, stop, do_update);
else
shader_preview_startjob(customdata, stop, do_update);
@@ -1031,29 +1067,35 @@ static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short
const bool use_new_shading = BKE_scene_use_new_shading_nodes(ip->scene);
while (cur_size) {
+ PreviewImage *prv = ip->owner;
ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview");
+ const bool is_render = !prv->use_deferred;
/* construct shader preview from image size and previewcustomdata */
sp->scene = ip->scene;
sp->owner = ip->owner;
sp->sizex = cur_size->sizex;
sp->sizey = cur_size->sizey;
- sp->pr_method = PR_ICON_RENDER;
+ sp->pr_method = is_render ? PR_ICON_RENDER : PR_ICON_DEFERRED;
sp->pr_rect = cur_size->rect;
sp->id = ip->id;
-
- if (use_new_shading) {
- /* texture icon rendering is hardcoded to use BI,
- * so don't even think of using cycle's bmain for
- * texture icons
- */
- if (GS(ip->id->name) != ID_TE)
- sp->pr_main = G_pr_main_cycles;
- else
+ sp->bmain = ip->bmain;
+
+ if (is_render) {
+ BLI_assert(ip->id);
+ if (use_new_shading) {
+ /* texture icon rendering is hardcoded to use BI,
+ * so don't even think of using cycle's bmain for
+ * texture icons
+ */
+ if (GS(ip->id->name) != ID_TE)
+ sp->pr_main = G_pr_main_cycles;
+ else
+ sp->pr_main = G_pr_main;
+ }
+ else {
sp->pr_main = G_pr_main;
- }
- else {
- sp->pr_main = G_pr_main;
+ }
}
common_preview_startjob(sp, stop, do_update, progress);
@@ -1098,12 +1140,13 @@ static void icon_preview_free(void *customdata)
MEM_freeN(ip);
}
-void ED_preview_icon_render(Scene *scene, ID *id, unsigned int *rect, int sizex, int sizey)
+void ED_preview_icon_render(Main *bmain, Scene *scene, ID *id, unsigned int *rect, int sizex, int sizey)
{
IconPreview ip = {NULL};
short stop = false, update = false;
float progress = 0.0f;
+ ip.bmain = bmain;
ip.scene = scene;
ip.owner = id;
ip.id = id;
@@ -1134,8 +1177,9 @@ void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *r
BLI_movelisttolist(&ip->sizes, &old_ip->sizes);
/* customdata for preview thread */
+ ip->bmain = CTX_data_main(C);
ip->scene = CTX_data_scene(C);
- ip->owner = id;
+ ip->owner = owner;
ip->id = id;
icon_preview_add_size(ip, rect, sizex, sizey);
@@ -1175,6 +1219,7 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M
sp->id = id;
sp->parent = parent;
sp->slot = slot;
+ sp->bmain = CTX_data_main(C);
/* hardcoded preview .blend for cycles/internal, this should be solved
* once with custom preview .blend path for external engines */
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index ff90f48d705..3b8b874a462 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -41,8 +41,9 @@
#include "DNA_space_types.h"
#include "DNA_world_types.h"
-#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
#include "BLF_translation.h"
@@ -202,7 +203,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
if (nurbs) {
for (nu = nurbs->first; nu; nu = nu->next)
if (isNurbsel(nu))
- nu->mat_nr = nu->charidx = ob->actcol - 1;
+ nu->mat_nr = ob->actcol - 1;
}
}
else if (ob->type == OB_FONT) {
@@ -381,6 +382,74 @@ void OBJECT_OT_material_slot_copy(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
}
+static int material_slot_move_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+
+ unsigned int *slot_remap;
+ int index_pair[2];
+
+ int dir = RNA_enum_get(op->ptr, "direction");
+
+ if (!ob || ob->totcol < 2) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* up */
+ if (dir == 1 && ob->actcol > 1) {
+ index_pair[0] = ob->actcol - 2;
+ index_pair[1] = ob->actcol - 1;
+ ob->actcol--;
+ }
+ /* down */
+ else if (dir == -1 && ob->actcol < ob->totcol) {
+ index_pair[0] = ob->actcol - 1;
+ index_pair[1] = ob->actcol - 0;
+ ob->actcol++;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+
+ slot_remap = MEM_mallocN(sizeof(unsigned int) * ob->totcol, __func__);
+
+ range_vn_u(slot_remap, ob->totcol, 0);
+
+ slot_remap[index_pair[0]] = index_pair[1];
+ slot_remap[index_pair[1]] = index_pair[0];
+
+ BKE_material_remap_object(ob, slot_remap);
+
+ MEM_freeN(slot_remap);
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | ND_DATA, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_material_slot_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem material_slot_move[] = {
+ {1, "UP", 0, "Up", ""},
+ {-1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Move Material";
+ ot->idname = "OBJECT_OT_material_slot_move";
+ ot->description = "Move the active material up/down in the list";
+
+ /* api callbacks */
+ ot->exec = material_slot_move_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "direction", material_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
+}
+
/********************** new material operator *********************/
static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
@@ -450,7 +519,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
tex = BKE_texture_copy(tex);
}
else {
- tex = add_texture(bmain, DATA_("Texture"));
+ tex = BKE_texture_add(bmain, DATA_("Texture"));
}
/* hook into UI */
@@ -605,6 +674,70 @@ void SCENE_OT_render_layer_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
}
+/********************** render view operators *********************/
+
+static int render_view_remove_poll(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ /* don't allow user to remove "left" and "right" views */
+ return scene->r.actview > 1;
+}
+
+static int render_view_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+
+ BKE_scene_add_render_view(scene, NULL);
+ scene->r.actview = BLI_listbase_count(&scene->r.views) - 1;
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_render_view_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Render View";
+ ot->idname = "SCENE_OT_render_view_add";
+ ot->description = "Add a render view";
+
+ /* api callbacks */
+ ot->exec = render_view_add_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int render_view_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderView *rv = BLI_findlink(&scene->r.views, scene->r.actview);
+
+ if (!BKE_scene_remove_render_view(scene, rv))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_render_view_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Render View";
+ ot->idname = "SCENE_OT_render_view_remove";
+ ot->description = "Remove the selected render view";
+
+ /* api callbacks */
+ ot->exec = render_view_remove_exec;
+ ot->poll = render_view_remove_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
#ifdef WITH_FREESTYLE
static bool freestyle_linestyle_check_report(FreestyleLineSet *lineset, ReportList *reports)
@@ -731,10 +864,11 @@ void SCENE_OT_freestyle_module_move(wmOperatorType *ot)
static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- BKE_freestyle_lineset_add(&srl->freestyleConfig, NULL);
+ BKE_freestyle_lineset_add(bmain, &srl->freestyleConfig, NULL);
DAG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
@@ -893,6 +1027,7 @@ void SCENE_OT_freestyle_lineset_move(wmOperatorType *ot)
static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&srl->freestyleConfig);
@@ -903,10 +1038,10 @@ static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op)
}
if (lineset->linestyle) {
lineset->linestyle->id.us--;
- lineset->linestyle = BKE_linestyle_copy(lineset->linestyle);
+ lineset->linestyle = BKE_linestyle_copy(bmain, lineset->linestyle);
}
else {
- lineset->linestyle = BKE_linestyle_new("LineStyle", NULL);
+ lineset->linestyle = BKE_linestyle_new(bmain, "LineStyle");
}
DAG_id_tag_update(&lineset->linestyle->id, 0);
WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
@@ -1490,7 +1625,7 @@ static int envmap_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
- BKE_free_envmapdata(tex->env);
+ BKE_texture_envmap_free_data(tex->env);
WM_event_add_notifier(C, NC_TEXTURE | NA_EDITED, tex);
@@ -1533,7 +1668,7 @@ static int envmap_clear_all_exec(bContext *C, wmOperator *UNUSED(op))
for (tex = bmain->tex.first; tex; tex = tex->id.next)
if (tex->env)
- BKE_free_envmapdata(tex->env);
+ BKE_texture_envmap_free_data(tex->env);
WM_event_add_notifier(C, NC_TEXTURE | NA_EDITED, tex);
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index be42e2ed518..dedcbb144aa 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -61,6 +61,7 @@
#include "ED_node.h"
#include "ED_render.h"
+#include "ED_view3d.h"
#include "render_intern.h" // own include
@@ -141,26 +142,19 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated)
recursive_check = false;
}
-void ED_render_engine_area_exit(ScrArea *sa)
+void ED_render_engine_area_exit(Main *bmain, ScrArea *sa)
{
/* clear all render engines in this area */
ARegion *ar;
+ wmWindowManager *wm = bmain->wm.first;
if (sa->spacetype != SPACE_VIEW3D)
return;
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- RegionView3D *rv3d;
-
if (ar->regiontype != RGN_TYPE_WINDOW || !(ar->regiondata))
continue;
-
- rv3d = ar->regiondata;
-
- if (rv3d->render_engine) {
- RE_engine_free(rv3d->render_engine);
- rv3d->render_engine = NULL;
- }
+ ED_view3d_stop_render_preview(wm, ar);
}
}
@@ -173,7 +167,7 @@ void ED_render_engine_changed(Main *bmain)
for (sc = bmain->screen.first; sc; sc = sc->id.next)
for (sa = sc->areabase.first; sa; sa = sa->next)
- ED_render_engine_area_exit(sa);
+ ED_render_engine_area_exit(bmain, sa);
RE_FreePersistentData();
@@ -276,7 +270,7 @@ static void material_changed(Main *bmain, Material *ma)
int texture_draw = false;
/* icons */
- BKE_icon_changed(BKE_icon_getid(&ma->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&ma->id));
/* glsl */
if (ma->gpumaterial.first)
@@ -291,7 +285,7 @@ static void material_changed(Main *bmain, Material *ma)
continue;
}
- BKE_icon_changed(BKE_icon_getid(&parent->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&parent->id));
if (parent->gpumaterial.first)
GPU_material_free(&parent->gpumaterial);
@@ -306,7 +300,7 @@ static void material_changed(Main *bmain, Material *ma)
}
/* find textured objects */
- if (texture_draw && !(U.gameflags & USER_DISABLE_VBO)) {
+ if (texture_draw) {
for (ob = bmain->object.first; ob; ob = ob->id.next) {
DerivedMesh *dm = ob->derivedFinal;
Material ***material = give_matarar(ob);
@@ -331,7 +325,7 @@ static void lamp_changed(Main *bmain, Lamp *la)
Material *ma;
/* icons */
- BKE_icon_changed(BKE_icon_getid(&la->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&la->id));
/* glsl */
for (ob = bmain->object.first; ob; ob = ob->id.next)
@@ -367,7 +361,7 @@ static void texture_changed(Main *bmain, Tex *tex)
bool texture_draw = false;
/* icons */
- BKE_icon_changed(BKE_icon_getid(&tex->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&tex->id));
/* paint overlays */
for (scene = bmain->scene.first; scene; scene = scene->id.next)
@@ -378,7 +372,7 @@ static void texture_changed(Main *bmain, Tex *tex)
if (!material_uses_texture(ma, tex))
continue;
- BKE_icon_changed(BKE_icon_getid(&ma->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&ma->id));
if (ma->gpumaterial.first)
GPU_material_free(&ma->gpumaterial);
@@ -409,7 +403,7 @@ static void texture_changed(Main *bmain, Tex *tex)
continue;
}
- BKE_icon_changed(BKE_icon_getid(&wo->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&wo->id));
if (wo->gpumaterial.first)
GPU_material_free(&wo->gpumaterial);
@@ -429,7 +423,7 @@ static void texture_changed(Main *bmain, Tex *tex)
}
/* find textured objects */
- if (texture_draw && !(U.gameflags & USER_DISABLE_VBO)) {
+ if (texture_draw) {
for (ob = bmain->object.first; ob; ob = ob->id.next) {
DerivedMesh *dm = ob->derivedFinal;
Material ***material = give_matarar(ob);
@@ -457,7 +451,7 @@ static void world_changed(Main *bmain, World *wo)
Material *ma;
/* icons */
- BKE_icon_changed(BKE_icon_getid(&wo->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&wo->id));
/* glsl */
for (ma = bmain->mat.first; ma; ma = ma->id.next)
@@ -476,7 +470,7 @@ static void image_changed(Main *bmain, Image *ima)
Tex *tex;
/* icons */
- BKE_icon_changed(BKE_icon_getid(&ima->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&ima->id));
/* textures */
for (tex = bmain->tex.first; tex; tex = tex->id.next)
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index fe357a7a0e2..f5260b8a568 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -63,7 +63,7 @@ static ScrArea *biggest_non_image_area(bContext *C)
for (sa = sc->areabase.first; sa; sa = sa->next) {
if (sa->winx > 30 && sa->winy > 30) {
size = sa->winx * sa->winy;
- if (sa->spacetype == SPACE_BUTS) {
+ if (!sa->full && sa->spacetype == SPACE_BUTS) {
if (foundwin == 0 && size > bwmaxsize) {
bwmaxsize = size;
big = sa;
@@ -245,6 +245,11 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
ScrArea *sa = CTX_wm_area(C);
SpaceImage *sima = sa->spacedata.first;
+ /* ensure image editor fullscreen and area fullscreen states are in sync */
+ if ((sima->flag & SI_FULLWINDOW) && !sa->full) {
+ sima->flag &= ~SI_FULLWINDOW;
+ }
+
/* test if we have a temp screen in front */
if (win->screen->temp) {
wm_window_lower(win);
@@ -258,8 +263,9 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
sima->flag &= ~SI_FULLWINDOW;
ED_screen_full_prevspace(C, sa);
}
- else
+ else {
ED_area_prevspace(C, sa);
+ }
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 90c09070bc3..541c7f21cdc 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -34,6 +34,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_object_types.h"
#include "DNA_userdef_types.h"
#include "BLI_blenlib.h"
@@ -44,6 +45,8 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "RNA_access.h"
@@ -56,16 +59,23 @@
#include "ED_screen.h"
#include "ED_screen_types.h"
#include "ED_space_api.h"
+#include "ED_view3d.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
#include "BLF_api.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "UI_resources.h"
#include "UI_view2d.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
#include "screen_intern.h"
extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); /* xxx temp */
@@ -149,6 +159,34 @@ void ED_area_do_refresh(bContext *C, ScrArea *sa)
}
/**
+ * Action zones are only updated if the mouse is inside of them, but in some cases (currently only fullscreen icon)
+ * it might be needed to update their properties and redraw if the mouse isn't inside.
+ */
+void ED_area_azones_update(ScrArea *sa, const int mouse_xy[2])
+{
+ AZone *az;
+ bool changed = false;
+
+ for (az = sa->actionzones.first; az; az = az->next) {
+ if (az->type == AZONE_FULLSCREEN) {
+ /* only if mouse is not hovering the azone */
+ if (BLI_rcti_isect_pt_v(&az->rect, mouse_xy) == false) {
+ az->alpha = 0.0f;
+ changed = true;
+
+ /* can break since currently only this is handled here */
+ break;
+ }
+ }
+ }
+
+ if (changed) {
+ sa->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
+ ED_area_tag_redraw(sa);
+ }
+}
+
+/**
* \brief Corner widget use for quitting fullscreen.
*/
static void area_draw_azone_fullscreen(short x1, short y1, short x2, short y2, float alpha)
@@ -366,6 +404,11 @@ static void region_draw_azone_tria(AZone *az)
glDisable(GL_BLEND);
}
+static void area_azone_tag_update(ScrArea *sa)
+{
+ sa->flag |= AREA_FLAG_ACTIONZONES_UPDATE;
+}
+
static void region_draw_azones(ScrArea *sa, ARegion *ar)
{
AZone *az;
@@ -406,6 +449,10 @@ static void region_draw_azones(ScrArea *sa, ARegion *ar)
}
else if (az->type == AZONE_FULLSCREEN) {
area_draw_azone_fullscreen(az->x1, az->y1, az->x2, az->y2, az->alpha);
+
+ if (az->alpha != 0.0f) {
+ area_azone_tag_update(sa);
+ }
}
}
}
@@ -493,7 +540,6 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
glDisable(GL_BLEND);
#endif
- ar->do_draw = 0;
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
UI_blocklist_free_inactive(C, &ar->uiblocks);
@@ -507,6 +553,100 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
* maybe silly, but let's try for now
* to keep these tags protected
* ********************************** */
+int ED_match_area_with_refresh(int spacetype, int refresh)
+{
+ switch (spacetype) {
+ case SPACE_TIME:
+ if (refresh & SPACE_TIME)
+ return 1;
+ break;
+ }
+
+ return 0;
+}
+
+int ED_match_region_with_redraws(int spacetype, int regiontype, int redraws)
+{
+ if (regiontype == RGN_TYPE_WINDOW) {
+
+ switch (spacetype) {
+ case SPACE_VIEW3D:
+ if (redraws & TIME_ALL_3D_WIN)
+ return 1;
+ break;
+ case SPACE_IPO:
+ case SPACE_ACTION:
+ case SPACE_NLA:
+ if (redraws & TIME_ALL_ANIM_WIN)
+ return 1;
+ break;
+ case SPACE_TIME:
+ /* if only 1 window or 3d windows, we do timeline too */
+ if (redraws & (TIME_ALL_ANIM_WIN | TIME_REGION | TIME_ALL_3D_WIN))
+ return 1;
+ break;
+ case SPACE_BUTS:
+ if (redraws & TIME_ALL_BUTS_WIN)
+ return 1;
+ break;
+ case SPACE_SEQ:
+ if (redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN))
+ return 1;
+ break;
+ case SPACE_NODE:
+ if (redraws & (TIME_NODES))
+ return 1;
+ break;
+ case SPACE_IMAGE:
+ if (redraws & TIME_ALL_IMAGE_WIN)
+ return 1;
+ break;
+ case SPACE_CLIP:
+ if (redraws & TIME_CLIPS)
+ return 1;
+ break;
+
+ }
+ }
+ else if (regiontype == RGN_TYPE_CHANNELS) {
+ switch (spacetype) {
+ case SPACE_IPO:
+ case SPACE_ACTION:
+ case SPACE_NLA:
+ if (redraws & TIME_ALL_ANIM_WIN)
+ return 1;
+ break;
+ }
+ }
+ else if (regiontype == RGN_TYPE_UI) {
+ if (spacetype == SPACE_CLIP) {
+ /* Track Preview button is on Properties Editor in SpaceClip,
+ * and it's very common case when users want it be refreshing
+ * during playback, so asking people to enable special option
+ * for this is a bit tricky, so add exception here for refreshing
+ * Properties Editor for SpaceClip always */
+ return 1;
+ }
+
+ if (redraws & TIME_ALL_BUTS_WIN)
+ return 1;
+ }
+ else if (regiontype == RGN_TYPE_HEADER) {
+ if (spacetype == SPACE_TIME)
+ return 1;
+ }
+ else if (regiontype == RGN_TYPE_PREVIEW) {
+ switch (spacetype) {
+ case SPACE_SEQ:
+ if (redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN))
+ return 1;
+ break;
+ case SPACE_CLIP:
+ return 1;
+ }
+ }
+ return 0;
+}
void ED_region_tag_redraw(ARegion *ar)
{
@@ -773,7 +913,7 @@ static void region_azone_tab_plus(ScrArea *sa, AZone *az, ARegion *ar)
switch (az->edge) {
case AE_TOP_TO_BOTTOMRIGHT:
- if (ar->winrct.ymax == sa->totrct.ymin) add = 1; else add = 0;
+ add = (ar->winrct.ymax == sa->totrct.ymin) ? 1 : 0;
az->x1 = ar->winrct.xmax - 2.5f * AZONEPAD_TAB_PLUSW;
az->y1 = ar->winrct.ymax - add;
az->x2 = ar->winrct.xmax - 1.5f * AZONEPAD_TAB_PLUSW;
@@ -818,7 +958,7 @@ static void region_azone_tab(ScrArea *sa, AZone *az, ARegion *ar)
switch (az->edge) {
case AE_TOP_TO_BOTTOMRIGHT:
- if (ar->winrct.ymax == sa->totrct.ymin) add = 1; else add = 0;
+ add = (ar->winrct.ymax == sa->totrct.ymin) ? 1 : 0;
az->x1 = ar->winrct.xmax - 2 * AZONEPAD_TABW;
az->y1 = ar->winrct.ymax - add;
az->x2 = ar->winrct.xmax - AZONEPAD_TABW;
@@ -863,7 +1003,7 @@ static void region_azone_tria(ScrArea *sa, AZone *az, ARegion *ar)
switch (az->edge) {
case AE_TOP_TO_BOTTOMRIGHT:
- if (ar->winrct.ymax == sa->totrct.ymin) add = 1; else add = 0;
+ add = (ar->winrct.ymax == sa->totrct.ymin) ? 1 : 0;
az->x1 = ar->winrct.xmax - 2 * AZONEPAD_TRIAW;
az->y1 = ar->winrct.ymax - add;
az->x2 = ar->winrct.xmax - AZONEPAD_TRIAW;
@@ -1224,16 +1364,22 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
if (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) {
ar->winrct = *remainder;
- if (alignment == RGN_ALIGN_TOP)
- ar->winrct.ymin = ar->winrct.ymax;
- else if (alignment == RGN_ALIGN_BOTTOM)
- ar->winrct.ymax = ar->winrct.ymin;
- else if (alignment == RGN_ALIGN_RIGHT)
- ar->winrct.xmin = ar->winrct.xmax;
- else if (alignment == RGN_ALIGN_LEFT)
- ar->winrct.xmax = ar->winrct.xmin;
- else /* prevent winrct to be valid */
- ar->winrct.xmax = ar->winrct.xmin;
+ switch (alignment) {
+ case RGN_ALIGN_TOP:
+ ar->winrct.ymin = ar->winrct.ymax;
+ break;
+ case RGN_ALIGN_BOTTOM:
+ ar->winrct.ymax = ar->winrct.ymin;
+ break;
+ case RGN_ALIGN_RIGHT:
+ ar->winrct.xmin = ar->winrct.xmax;
+ break;
+ case RGN_ALIGN_LEFT:
+ default:
+ /* prevent winrct to be valid */
+ ar->winrct.xmax = ar->winrct.xmin;
+ break;
+ }
}
/* restore prev-split exception */
@@ -2029,6 +2175,196 @@ void ED_region_info_draw(ARegion *ar, const char *text, int block, float fill_co
glScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
}
+#define MAX_METADATA_STR 1024
+
+static const char *meta_data_list[] =
+{
+ "File",
+ "Strip",
+ "Note",
+ "Date",
+ "RenderTime",
+ "Marker",
+ "Time",
+ "Frame",
+ "Camera",
+ "Scene"
+};
+
+BLI_INLINE bool metadata_is_valid(ImBuf *ibuf, char *r_str, short index, int offset)
+{
+ return (IMB_metadata_get_field(ibuf, meta_data_list[index], r_str + offset, MAX_METADATA_STR - offset) && r_str[0]);
+}
+
+static void metadata_draw_imbuf(ImBuf *ibuf, rctf rect, int fontid, const bool is_top)
+{
+ char temp_str[MAX_METADATA_STR];
+ int line_width;
+ int ofs_y = 0;
+ short i;
+ int len;
+ const float height = BLF_height_max(fontid);
+ const float vertical_offset = height + (0.1f * U.widget_unit);
+
+ if (is_top) {
+ for (i = 0; i < 4; i++) {
+ /* first line */
+ if (i == 0) {
+ bool do_newline = false;
+ len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[0]);
+ if (metadata_is_valid(ibuf, temp_str, 0, len)) {
+ BLF_position(fontid, rect.xmin + (0.2f * U.widget_unit),
+ rect.ymax - vertical_offset, 0.0f);
+ BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ do_newline = true;
+ }
+
+ len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[1]);
+ if (metadata_is_valid(ibuf, temp_str, 1, len)) {
+ line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_position(fontid, rect.xmax - line_width - (0.2f * U.widget_unit),
+ rect.ymax - vertical_offset, 0.0f);
+ BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ do_newline = true;
+ }
+
+ if (do_newline)
+ ofs_y += vertical_offset;
+ }
+ else if (i == 1) {
+ len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
+ if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
+ BLF_position(fontid, rect.xmin + (0.2f * U.widget_unit),
+ rect.ymax - vertical_offset - ofs_y, 0.0f);
+ BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ ofs_y += vertical_offset;
+ }
+ }
+ else {
+ len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
+ if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
+ line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_position(fontid, rect.xmax - line_width - (0.2f * U.widget_unit),
+ rect.ymax - vertical_offset - ofs_y, 0.0f);
+ BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ ofs_y += vertical_offset;
+ }
+ }
+ }
+ }
+ else {
+ int ofs_x = 0;
+ for (i = 5; i < 10; i++) {
+ len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i]);
+ if (metadata_is_valid(ibuf, temp_str, i, len)) {
+ BLF_position(fontid, rect.xmin + (0.2f * U.widget_unit) + ofs_x,
+ rect.ymin + (0.3f * U.widget_unit), 0.0f);
+ BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+
+ ofs_x += BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX) + UI_UNIT_X;
+ }
+ }
+ }
+}
+
+static float metadata_box_height_get(ImBuf *ibuf, int fontid, const bool is_top)
+{
+ char str[MAX_METADATA_STR] = "";
+ short i, count = 0;
+ const float height = BLF_height_max(fontid) + 0.1f * U.widget_unit;
+
+ if (is_top) {
+ if (metadata_is_valid(ibuf, str, 0, 0) || metadata_is_valid(ibuf, str, 1, 0)) {
+ count++;
+ }
+ for (i = 2; i < 5; i++) {
+ if (metadata_is_valid(ibuf, str, i, 0)) {
+ count++;
+ }
+ }
+ }
+ else {
+ for (i = 5; i < 10; i++) {
+ if (metadata_is_valid(ibuf, str, i, 0)) {
+ count = 1;
+ }
+ }
+ }
+
+ if (count) {
+ return (height * count + (0.1f * U.widget_unit));
+ }
+
+ return 0;
+}
+
+#undef MAX_METADATA_STR
+
+void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, rctf frame, float zoomx, float zoomy)
+{
+ float box_y;
+ rctf rect;
+ uiStyle *style = UI_style_get_dpi();
+
+ if (!ibuf->metadata)
+ return;
+
+ /* find window pixel coordinates of origin */
+ glPushMatrix();
+
+ /* offset and zoom using ogl */
+ glTranslatef(x, y, 0.0f);
+ glScalef(zoomx, zoomy, 1.0f);
+
+ BLF_size(blf_mono_font, style->widgetlabel.points, U.dpi);
+
+ /* *** upper box*** */
+
+ /* get needed box height */
+ box_y = metadata_box_height_get(ibuf, blf_mono_font, true);
+
+ if (box_y) {
+ UI_ThemeColor(TH_METADATA_BG);
+
+ /* set up rect */
+ BLI_rctf_init(&rect, frame.xmin, frame.xmax, frame.ymax, frame.ymax + box_y);
+ /* draw top box */
+ glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+
+ BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ BLF_enable(blf_mono_font, BLF_CLIPPING);
+
+ UI_ThemeColor(TH_METADATA_TEXT);
+ metadata_draw_imbuf(ibuf, rect, blf_mono_font, true);
+
+ BLF_disable(blf_mono_font, BLF_CLIPPING);
+ }
+
+
+ /* *** lower box*** */
+
+ box_y = metadata_box_height_get(ibuf, blf_mono_font, false);
+
+ if (box_y) {
+ UI_ThemeColor(TH_METADATA_BG);
+
+ /* set up box rect */
+ BLI_rctf_init(&rect, frame.xmin, frame.xmax, frame.ymin - box_y, frame.ymin);
+ /* draw top box */
+ glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+
+ BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ BLF_enable(blf_mono_font, BLF_CLIPPING);
+
+ UI_ThemeColor(TH_METADATA_TEXT);
+ metadata_draw_imbuf(ibuf, rect, blf_mono_font, false);
+
+ BLF_disable(blf_mono_font, BLF_CLIPPING);
+ }
+
+ glPopMatrix();
+}
+
void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy)
{
float gridsize, gridstep = 1.0f / 32.0f;
@@ -2089,6 +2425,47 @@ void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy)
glEnd();
}
+/* uses the viewplane from the given camera and draws it as a backdrop */
+void ED_region_draw_backdrop_view3d(const bContext *C, struct Object *camera, const float alpha,
+ const float width, const float height, const float x, const float y,
+ const float zoomx, const float zoomy, const bool draw_background)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ char err_out[256] = "unknown";
+ struct ImBuf *ibuf;
+
+ BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
+ ibuf = ED_view3d_draw_offscreen_imbuf_simple(scene, camera, width, height, IB_rect,
+ OB_SOLID, false, false, false,
+ R_ADDSKY, NULL, err_out);
+
+ if (ibuf == NULL)
+ return;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glPushMatrix();
+ glScalef(zoomx, zoomy, 0.0f);
+ glTranslatef(x, y, 0.0f);
+
+ /* draw background */
+ if (draw_background) {
+ char col[4];
+
+ UI_GetThemeColorType4ubv(TH_HIGH_GRAD, SPACE_VIEW3D, col);
+ glColor4ub(UNPACK3(col), alpha * 255);
+ glRectf(0, 0, width, height);
+ }
+ /* draw the imbuf itself */
+ glaDrawImBuf_glsl_ctx(C, ibuf, 0.0f, 0.0f, GL_NEAREST, alpha);
+
+ glPopMatrix();
+ glDisable(GL_BLEND);
+
+ IMB_freeImBuf(ibuf);
+}
+
/* If the area has overlapping regions, it returns visible rect for Region *ar */
/* rect gets returned in local region coordinates */
void ED_region_visible_rect(ARegion *ar, rcti *rect)
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index 6001534e88d..ca0fd17c5a7 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -422,6 +422,24 @@ void glutil_draw_filled_arc(float start, float angle, float radius, int nsegment
glEnd();
}
+void glutil_draw_filled_arc_part(float start, float angle, float radius, float radius_inn, int nsegments)
+{
+ int i;
+
+ glBegin(GL_QUAD_STRIP);
+ glVertex2f(cosf(start) * radius_inn, sinf(start) * radius_inn);
+ glVertex2f(cosf(start) * radius, sinf(start) * radius);
+ for (i = 0; i < nsegments; i++) {
+ float t = (float) i / (nsegments - 1);
+ float cur = start + t * angle;
+
+ glVertex2f(cosf(cur) * radius_inn, sinf(cur) * radius_inn);
+ glVertex2f(cosf(cur) * radius, sinf(cur) * radius);
+ }
+ glEnd();
+}
+
+
void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments)
{
int i;
@@ -579,25 +597,25 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
continue;
if (type == GL_FLOAT) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_FLOAT, &f_rect[subpart_y * offset_y * img_w * components + subpart_x * offset_x * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_FLOAT, &f_rect[((size_t)subpart_y) * offset_y * img_w * components + subpart_x * offset_x * components]);
/* add an extra border of pixels so linear looks ok at edges of full image. */
if (subpart_w < tex_w)
- glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_FLOAT, &f_rect[subpart_y * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_FLOAT, &f_rect[((size_t)subpart_y) * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
if (subpart_h < tex_h)
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_FLOAT, &f_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_FLOAT, &f_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]);
if (subpart_w < tex_w && subpart_h < tex_h)
- glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_FLOAT, &f_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_FLOAT, &f_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
}
else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[subpart_y * offset_y * img_w * components + subpart_x * offset_x * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[((size_t)subpart_y) * offset_y * img_w * components + subpart_x * offset_x * components]);
if (subpart_w < tex_w)
- glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[subpart_y * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[((size_t)subpart_y) * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
if (subpart_h < tex_h)
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]);
if (subpart_w < tex_w && subpart_h < tex_h)
- glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
}
glEnable(GL_TEXTURE_2D);
@@ -713,10 +731,11 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
}
/* uses either DrawPixelsSafe or DrawPixelsTex, based on user defined maximum */
-void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect)
+void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format,
+ int type, int zoomfilter, float alpha, void *rect)
{
if (U.image_draw_method != IMAGE_DRAW_METHOD_DRAWPIXELS) {
- glColor4f(1.0, 1.0, 1.0, 1.0);
+ glColor4f(1.0, 1.0, 1.0, alpha);
glaDrawPixelsTex(x, y, img_w, img_h, format, type, zoomfilter, rect);
}
else {
@@ -841,7 +860,7 @@ void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *r_sc_x
/**
* Translate the \a world point from world coordinates into screen space.
*/
-void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int screen_r[2])
+void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int r_screen[2])
{
screen_r[0] = (world[0] - di->world_rect.xmin) * di->wo_to_sc[0];
screen_r[1] = (world[1] - di->world_rect.ymin) * di->wo_to_sc[1];
@@ -991,7 +1010,7 @@ void bgl_get_mats(bglMats *mats)
/**
* \note \a viewdist is only for ortho at the moment.
*/
-void bglPolygonOffset(float viewdist, float dist)
+void bglPolygonOffset(float viewdist, float dist)
{
static float winmat[16], offset = 0.0;
@@ -1007,8 +1026,25 @@ void bglPolygonOffset(float viewdist, float dist)
/* dist is from camera to center point */
- if (winmat[15] > 0.5f) offs = 0.00001f * dist * viewdist; // ortho tweaking
- else offs = 0.0005f * dist; // should be clipping value or so...
+ if (winmat[15] > 0.5f) {
+#if 1
+ offs = 0.00001f * dist * viewdist; // ortho tweaking
+#else
+ static float depth_fac = 0.0f;
+ if (depth_fac == 0.0f) {
+ int depthbits;
+ glGetIntegerv(GL_DEPTH_BITS, &depthbits);
+ depth_fac = 1.0f / (float)((1 << depthbits) - 1);
+ }
+ offs = (-1.0 / winmat[10]) * dist * depth_fac;
+
+ UNUSED_VARS(viewdist);
+#endif
+ }
+ else {
+ /* should be clipping value or so... */
+ offs = 0.0005f * dist;
+ }
winmat[14] -= offs;
offset += offs;
@@ -1040,7 +1076,7 @@ void bglFlush(void)
/* **** Color management helper functions for GLSL display/transform ***** */
/* Draw given image buffer on a screen using GLSL for display transform */
-void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter,
+void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter, float alpha,
ColorManagedViewSettings *view_settings,
ColorManagedDisplaySettings *display_settings)
{
@@ -1080,7 +1116,7 @@ void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter,
if (ok) {
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- glColor4f(1.0, 1.0, 1.0, 1.0);
+ glColor4f(1.0, 1.0, 1.0, alpha);
if (ibuf->rect_float) {
int format = 0;
@@ -1118,20 +1154,20 @@ void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter,
if (display_buffer)
glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE,
- zoomfilter, display_buffer);
+ zoomfilter, alpha, display_buffer);
IMB_display_buffer_release(cache_handle);
}
}
-void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int zoomfilter)
+void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int zoomfilter, float alpha)
{
ColorManagedViewSettings *view_settings;
ColorManagedDisplaySettings *display_settings;
IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings);
- glaDrawImBuf_glsl(ibuf, x, y, zoomfilter, view_settings, display_settings);
+ glaDrawImBuf_glsl(ibuf, x, y, zoomfilter, alpha, view_settings, display_settings);
}
void cpack(unsigned int x)
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 3431ce9f50a..9b40b8b4464 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -47,6 +47,7 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_gpencil.h"
+#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "RNA_access.h"
@@ -59,6 +60,18 @@
#include "screen_intern.h"
+static unsigned int context_layers(bScreen *sc, Scene *scene, ScrArea *sa_ctx)
+{
+ /* needed for 'USE_ALLSELECT' define, otherwise we end up editing off-screen layers. */
+ if (sc && sa_ctx && (sa_ctx->spacetype == SPACE_BUTS)) {
+ const unsigned int lay = BKE_screen_view3d_layer_all(sc);
+ if (lay) {
+ return lay;
+ }
+ }
+ return scene->lay;
+}
+
const char *screen_context_dir[] = {
"scene", "visible_objects", "visible_bases", "selectable_objects", "selectable_bases",
"selected_objects", "selected_bases",
@@ -67,7 +80,7 @@ const char *screen_context_dir[] = {
"visible_pose_bones", "selected_pose_bones", "active_bone", "active_pose_bone",
"active_base", "active_object", "object", "edit_object",
"sculpt_object", "vertex_paint_object", "weight_paint_object",
- "image_paint_object", "particle_edit_object",
+ "image_paint_object", "particle_edit_object", "hair_edit_object",
"sequences", "selected_sequences", "selected_editable_sequences", /* sequencer */
"gpencil_data", "gpencil_data_owner", /* grease pencil data */
"visible_gpencil_layers", "editable_gpencil_layers", "editable_gpencil_strokes",
@@ -81,7 +94,6 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
ScrArea *sa = CTX_wm_area(C);
Scene *scene = sc->scene;
Base *base;
- unsigned int lay = scene->lay;
#if 0 /* Using the context breaks adding objects in the UI. Need to find out why - campbell */
Object *obact = CTX_data_active_object(C);
@@ -102,10 +114,11 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "visible_objects") || CTX_data_equals(member, "visible_bases")) {
+ const unsigned int lay = context_layers(sc, scene, sa);
int visible_objects = CTX_data_equals(member, "visible_objects");
for (base = scene->base.first; base; base = base->next) {
- if (((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) && (base->lay & scene->lay)) {
+ if (((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) && (base->lay & lay)) {
if (visible_objects)
CTX_data_id_list_add(result, &base->object->id);
else
@@ -116,6 +129,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "selectable_objects") || CTX_data_equals(member, "selectable_bases")) {
+ const unsigned int lay = context_layers(sc, scene, sa);
int selectable_objects = CTX_data_equals(member, "selectable_objects");
for (base = scene->base.first; base; base = base->next) {
@@ -132,10 +146,11 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "selected_objects") || CTX_data_equals(member, "selected_bases")) {
+ const unsigned int lay = context_layers(sc, scene, sa);
int selected_objects = CTX_data_equals(member, "selected_objects");
for (base = scene->base.first; base; base = base->next) {
- if ((base->flag & SELECT) && (base->lay & scene->lay)) {
+ if ((base->flag & SELECT) && (base->lay & lay)) {
if (selected_objects)
CTX_data_id_list_add(result, &base->object->id);
else
@@ -146,10 +161,11 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "selected_editable_objects") || CTX_data_equals(member, "selected_editable_bases")) {
+ const unsigned int lay = context_layers(sc, scene, sa);
int selected_editable_objects = CTX_data_equals(member, "selected_editable_objects");
for (base = scene->base.first; base; base = base->next) {
- if ((base->flag & SELECT) && (base->lay & scene->lay)) {
+ if ((base->flag & SELECT) && (base->lay & lay)) {
if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) {
if (0 == BKE_object_is_libdata(base->object)) {
if (selected_editable_objects)
@@ -362,6 +378,12 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
+ else if (CTX_data_equals(member, "hair_edit_object")) {
+ if (obact && (obact->mode & OB_MODE_HAIR_EDIT))
+ CTX_data_id_pointer_set(result, &obact->id);
+
+ return 1;
+ }
else if (CTX_data_equals(member, "sequences")) {
Editing *ed = BKE_sequencer_editing_get(scene, false);
if (ed) {
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index d590ead733c..6e51d21b8d7 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -59,6 +59,7 @@
#include "ED_screen.h"
#include "ED_screen_types.h"
#include "ED_clip.h"
+#include "ED_node.h"
#include "ED_render.h"
#include "UI_interface.h"
@@ -1749,7 +1750,9 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
newsa = sa;
}
}
-
+
+ BLI_assert(newsa);
+
if (sa && (sa->spacetype != type)) {
newsa->flag |= AREA_FLAG_TEMP_TYPE;
}
@@ -1767,6 +1770,7 @@ void ED_screen_full_prevspace(bContext *C, ScrArea *sa)
if (sa->flag & AREA_FLAG_STACKED_FULLSCREEN) {
/* stacked fullscreen -> only go back to previous screen and don't toggle out of fullscreen */
ED_area_prevspace(C, sa);
+ sa->flag &= ~AREA_FLAG_TEMP_TYPE;
}
else {
ED_screen_restore_temp_type(C, sa);
@@ -1806,8 +1810,7 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa)
else {
ED_screen_state_toggle(C, win, sa, state);
}
-
- sa->flag &= ~AREA_FLAG_TEMP_TYPE;
+ /* warning: 'sa' may be freed */
}
/* otherwise just tile the area again */
else {
@@ -1815,7 +1818,11 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa)
}
}
-/* this function toggles: if area is maximized/full then the parent will be restored */
+/**
+ * this function toggles: if area is maximized/full then the parent will be restored
+ *
+ * \warning \a sa may be freed.
+ */
ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const short state)
{
bScreen *sc, *oldscreen;
@@ -2120,4 +2127,85 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
}
+/*
+ * return true if any active area requires to see in 3D
+ */
+bool ED_screen_stereo3d_required(bScreen *screen)
+{
+ ScrArea *sa;
+ Scene *sce = screen->scene;
+ const bool is_multiview = (sce->r.scemode & R_MULTIVIEW) != 0;
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ switch (sa->spacetype) {
+ case SPACE_VIEW3D:
+ {
+ View3D *v3d;
+
+ if (!is_multiview)
+ continue;
+
+ v3d = sa->spacedata.first;
+ if (v3d->camera && v3d->stereo3d_camera == STEREO_3D_ID) {
+ ARegion *ar;
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiondata && ar->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = ar->regiondata;
+ if (rv3d->persp == RV3D_CAMOB) {
+ return true;
+ }
+ }
+ }
+ }
+ break;
+ }
+ case SPACE_IMAGE:
+ {
+ SpaceImage *sima;
+
+ /* images should always show in stereo, even if
+ * the file doesn't have views enabled */
+ sima = sa->spacedata.first;
+ if (sima->image && (sima->image->flag & IMA_IS_STEREO) &&
+ (sima->iuser.flag & IMA_SHOW_STEREO))
+ {
+ return true;
+ }
+ break;
+ }
+ case SPACE_NODE:
+ {
+ SpaceNode *snode;
+
+ if (!is_multiview)
+ continue;
+
+ snode = sa->spacedata.first;
+ if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
+ return true;
+ }
+ break;
+ }
+ case SPACE_SEQ:
+ {
+ SpaceSeq *sseq;
+
+ if (!is_multiview)
+ continue;
+
+ sseq = sa->spacedata.first;
+ if (ELEM(sseq->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW)) {
+ return true;
+ }
+
+ if (sseq->draw_flag & SEQ_DRAW_OVERDROP) {
+ return true;
+ }
+
+ break;
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index 79036d3356f..ccb6d5a6dca 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -32,8 +32,6 @@
#define __SCREEN_INTERN_H__
/* internal exports only */
-struct wmWindow;
-struct Scene;
#define AZONESPOT (0.6f * U.widget_unit)
#define AZONEFADEIN (5.0f * U.widget_unit) /* when azone is totally visible */
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 2133681f8f9..1c6d46d231d 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -717,7 +717,7 @@ static void actionzone_apply(bContext *C, wmOperator *op, int type)
else
event.type = EVT_ACTIONZONE_REGION;
- event.val = 0;
+ event.val = KM_NOTHING;
event.customdata = op->customdata;
event.customdatafree = true;
op->customdata = NULL;
@@ -990,6 +990,7 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
rect.ymax = rect.ymin + BLI_rcti_size_y(&rect) / U.pixelsize;
newwin = WM_window_open(C, &rect);
+ *newwin->stereo3d_format = *win->stereo3d_format;
/* allocs new screen and adds to newly created window, using window size */
newsc = ED_screen_add(newwin, CTX_data_scene(C), sc->id.name + 2);
@@ -2099,7 +2100,7 @@ static int frame_offset_exec(bContext *C, wmOperator *op)
areas_do_frame_follow(C, false);
- sound_seek_scene(bmain, scene);
+ BKE_sound_seek_scene(bmain, scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
@@ -2151,7 +2152,7 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
areas_do_frame_follow(C, true);
- sound_seek_scene(bmain, scene);
+ BKE_sound_seek_scene(bmain, scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
@@ -2257,7 +2258,7 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
else {
areas_do_frame_follow(C, true);
- sound_seek_scene(bmain, scene);
+ BKE_sound_seek_scene(bmain, scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
@@ -2319,7 +2320,7 @@ static int marker_jump_exec(bContext *C, wmOperator *op)
areas_do_frame_follow(C, true);
- sound_seek_scene(bmain, scene);
+ BKE_sound_seek_scene(bmain, scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
@@ -3318,105 +3319,17 @@ static void SCREEN_OT_header_toolbox(wmOperatorType *ot)
/* ****************** anim player, with timer ***************** */
-static int match_area_with_refresh(int spacetype, int refresh)
-{
- switch (spacetype) {
- case SPACE_TIME:
- if (refresh & SPACE_TIME)
- return 1;
- break;
- }
-
- return 0;
-}
-
-static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
-{
- if (regiontype == RGN_TYPE_WINDOW) {
-
- switch (spacetype) {
- case SPACE_VIEW3D:
- if (redraws & TIME_ALL_3D_WIN)
- return 1;
- break;
- case SPACE_IPO:
- case SPACE_ACTION:
- case SPACE_NLA:
- if (redraws & TIME_ALL_ANIM_WIN)
- return 1;
- break;
- case SPACE_TIME:
- /* if only 1 window or 3d windows, we do timeline too */
- if (redraws & (TIME_ALL_ANIM_WIN | TIME_REGION | TIME_ALL_3D_WIN))
- return 1;
- break;
- case SPACE_BUTS:
- if (redraws & TIME_ALL_BUTS_WIN)
- return 1;
- break;
- case SPACE_SEQ:
- if (redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN))
- return 1;
- break;
- case SPACE_NODE:
- if (redraws & (TIME_NODES))
- return 1;
- break;
- case SPACE_IMAGE:
- if (redraws & TIME_ALL_IMAGE_WIN)
- return 1;
- break;
- case SPACE_CLIP:
- if (redraws & TIME_CLIPS)
- return 1;
- break;
-
- }
- }
- else if (regiontype == RGN_TYPE_CHANNELS) {
- switch (spacetype) {
- case SPACE_IPO:
- case SPACE_ACTION:
- case SPACE_NLA:
- if (redraws & TIME_ALL_ANIM_WIN)
- return 1;
- break;
- }
- }
- else if (regiontype == RGN_TYPE_UI) {
- if (spacetype == SPACE_CLIP) {
- /* Track Preview button is on Properties Editor in SpaceClip,
- * and it's very common case when users want it be refreshing
- * during playback, so asking people to enable special option
- * for this is a bit tricky, so add exception here for refreshing
- * Properties Editor for SpaceClip always */
- return 1;
- }
-
- if (redraws & TIME_ALL_BUTS_WIN)
- return 1;
- }
- else if (regiontype == RGN_TYPE_HEADER) {
- if (spacetype == SPACE_TIME)
- return 1;
- }
- else if (regiontype == RGN_TYPE_PREVIEW) {
- switch (spacetype) {
- case SPACE_SEQ:
- if (redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN))
- return 1;
- break;
- case SPACE_CLIP:
- return 1;
- }
- }
- return 0;
-}
+//#define PROFILE_AUDIO_SYNCH
static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
+#ifdef PROFILE_AUDIO_SYNCH
+ static int old_frame = 0;
+ int newfra_int;
+#endif
+
if (screen->animtimer && screen->animtimer == event->customdata) {
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -3435,14 +3348,21 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
if ((scene->audio.flag & AUDIO_SYNC) &&
(sad->flag & ANIMPLAY_FLAG_REVERSE) == false &&
- finite(time = sound_sync_scene(scene)))
+ finite(time = BKE_sound_sync_scene(scene)))
{
- double newfra = (double)time * FPS;
- /* give some space here to avoid jumps */
- if (newfra + 0.5 > scene->r.cfra && newfra - 0.5 < scene->r.cfra)
- scene->r.cfra++;
- else
- scene->r.cfra = newfra + 0.5;
+ scene->r.cfra = (double)time * FPS;
+
+#ifdef PROFILE_AUDIO_SYNCH
+ newfra_int = scene->r.cfra;
+ if (newfra_int < old_frame) {
+ printf("back jump detected, frame %d!\n", newfra_int);
+ }
+ else if (newfra_int > old_frame + 1) {
+ printf("forward jump detected, frame %d!\n", newfra_int);
+ }
+ fflush(stdout);
+ old_frame = newfra_int;
+#endif
}
else {
if (sync) {
@@ -3509,8 +3429,12 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
sad->flag |= ANIMPLAY_FLAG_JUMPED;
}
- if (sad->flag & ANIMPLAY_FLAG_JUMPED)
- sound_seek_scene(bmain, scene);
+ if (sad->flag & ANIMPLAY_FLAG_JUMPED) {
+ BKE_sound_seek_scene(bmain, scene);
+#ifdef PROFILE_AUDIO_SYNCH
+ old_frame = CFRA;
+#endif
+ }
/* since we follow drawflags, we can't send notifier but tag regions ourselves */
ED_update_for_newframe(bmain, scene, 1);
@@ -3523,7 +3447,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
if (ar == sad->ar) {
redraw = true;
}
- else if (match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws)) {
+ else if (ED_match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws)) {
redraw = true;
}
@@ -3549,7 +3473,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
}
}
- if (match_area_with_refresh(sa->spacetype, sad->refresh))
+ if (ED_match_area_with_refresh(sa->spacetype, sad->refresh))
ED_area_tag_refresh(sa);
}
}
@@ -3593,6 +3517,19 @@ bScreen *ED_screen_animation_playing(const wmWindowManager *wm)
wmWindow *win;
for (win = wm->windows.first; win; win = win->next) {
+ if (win->screen->animtimer || win->screen->scrubbing) {
+ return win->screen;
+ }
+ }
+
+ return NULL;
+}
+
+bScreen *ED_screen_animation_no_scrub(const wmWindowManager *wm)
+{
+ wmWindow *win;
+
+ for (win = wm->windows.first; win; win = win->next) {
if (win->screen->animtimer) {
return win->screen;
}
@@ -3601,6 +3538,7 @@ bScreen *ED_screen_animation_playing(const wmWindowManager *wm)
return NULL;
}
+
/* toggle operator */
int ED_screen_animation_play(bContext *C, int sync, int mode)
{
@@ -3610,7 +3548,7 @@ int ED_screen_animation_play(bContext *C, int sync, int mode)
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
/* stop playback now */
ED_screen_animation_timer(C, 0, 0, 0, 0);
- sound_stop_scene(scene);
+ BKE_sound_stop_scene(scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
@@ -3618,7 +3556,7 @@ int ED_screen_animation_play(bContext *C, int sync, int mode)
int refresh = SPACE_TIME; /* these settings are currently only available from a menu in the TimeLine */
if (mode == 1) /* XXX only play audio forwards!? */
- sound_play_scene(scene);
+ BKE_sound_play_scene(scene);
ED_screen_animation_timer(C, screen->redraws_flag, refresh, sync, mode);
@@ -4228,6 +4166,8 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_CTRL, 0);
WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", EVT_ACTIONZONE_FULLSCREEN, 0, 0, 0);
+ RNA_boolean_set(kmi->ptr, "use_hide_panels", true);
/* area move after action zones */
WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
@@ -4255,8 +4195,6 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_SHIFT, 0);
kmi = WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", F10KEY, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "use_hide_panels", true);
- kmi = WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", EVT_ACTIONZONE_FULLSCREEN, 0, 0, 0);
- RNA_boolean_set(kmi->ptr, "use_hide_panels", true);
WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 9c05f1d4780..4644f0ae0b8 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -303,6 +303,7 @@ typedef struct ScreenshotJob {
const short *stop;
const short *do_update;
ReportList reports;
+ void *movie_ctx;
} ScreenshotJob;
@@ -312,7 +313,10 @@ static void screenshot_freejob(void *sjv)
if (sj->dumprect)
MEM_freeN(sj->dumprect);
-
+
+ if (sj->movie_ctx)
+ MEM_freeN(sj->movie_ctx);
+
MEM_freeN(sj);
}
@@ -337,20 +341,21 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
{
ScreenshotJob *sj = sjv;
RenderData rd = sj->scene->r;
- bMovieHandle *mh = BKE_movie_handle_get(sj->scene->r.im_format.imtype);
-
+ bMovieHandle *mh = NULL;
+
/* we need this as local variables for renderdata */
rd.frs_sec = U.scrcastfps;
rd.frs_sec_base = 1.0f;
if (BKE_imtype_is_movie(rd.im_format.imtype)) {
- if (!mh->start_movie(sj->scene, &rd, sj->dumpsx, sj->dumpsy, &sj->reports)) {
+ mh = BKE_movie_handle_get(sj->scene->r.im_format.imtype);
+ sj->movie_ctx = mh->context_create();
+
+ if (!mh->start_movie(sj->movie_ctx, sj->scene, &rd, sj->dumpsx, sj->dumpsy, &sj->reports, false, "")) {
printf("screencast job stopped\n");
return;
}
}
- else
- mh = NULL;
sj->stop = stop;
sj->do_update = do_update;
@@ -362,8 +367,8 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
if (sj->dumprect) {
if (mh) {
- if (mh->append_movie(&rd, rd.sfra, rd.cfra, (int *)sj->dumprect,
- sj->dumpsx, sj->dumpsy, &sj->reports))
+ if (mh->append_movie(sj->movie_ctx, &rd, rd.sfra, rd.cfra, (int *)sj->dumprect,
+ sj->dumpsx, sj->dumpsy, "", &sj->reports))
{
BKE_reportf(&sj->reports, RPT_INFO, "Appended frame: %d", rd.cfra);
printf("Appended frame %d\n", rd.cfra);
@@ -379,7 +384,7 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
BKE_image_path_from_imformat(
name, rd.pic, sj->bmain->name, rd.cfra,
- &rd.im_format, (rd.scemode & R_EXTENSION) != 0, true);
+ &rd.im_format, (rd.scemode & R_EXTENSION) != 0, true, NULL);
ibuf->rect = sj->dumprect;
ok = BKE_imbuf_write(ibuf, name, &rd.im_format);
@@ -410,8 +415,10 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
PIL_sleep_ms(U.scrcastwait);
}
- if (mh)
- mh->end_movie();
+ if (mh) {
+ mh->end_movie(sj->movie_ctx);
+ mh->context_free(sj->movie_ctx);
+ }
BKE_report(&sj->reports, RPT_INFO, "Screencast job stopped");
}
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 886e4e5ef8c..30ab00a72c2 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -955,21 +955,30 @@ static void paint_cursor_on_hit(UnifiedPaintSettings *ups, Brush *brush, ViewCon
}
}
+static bool ommit_cursor_drawing(Paint *paint, PaintMode mode, Brush *brush)
+{
+ if (paint->flags & PAINT_SHOW_BRUSH) {
+ if (ELEM(mode, PAINT_TEXTURE_2D, PAINT_TEXTURE_PROJECTIVE) && brush->imagepaint_tool == PAINT_TOOL_FILL)
+ return true;
+ }
+ return false;
+}
+
static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
{
Scene *scene = CTX_data_scene(C);
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
Paint *paint = BKE_paint_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
ViewContext vc;
- PaintMode mode;
float final_radius;
float translation[2];
float outline_alpha, *outline_col;
float zoomx, zoomy;
-
+
/* check that brush drawing is enabled */
- if (!(paint->flags & PAINT_SHOW_BRUSH))
+ if (ommit_cursor_drawing(paint, mode, brush))
return;
/* can't use stroke vc here because this will be called during
@@ -978,7 +987,6 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
get_imapaint_zoom(C, &zoomx, &zoomy);
zoomx = max_ff(zoomx, zoomy);
- mode = BKE_paintmode_get_active_from_context(C);
/* skip everything and draw brush here */
if (brush->flag & BRUSH_CURVE) {
@@ -1018,8 +1026,8 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* check if brush is subtracting, use different color then */
/* TODO: no way currently to know state of pen flip or
* invert key modifier without starting a stroke */
- if ((!(ups->draw_inverted) ^
- !(brush->flag & BRUSH_DIR_IN)) &&
+ if (((ups->draw_inverted == 0) ^
+ ((brush->flag & BRUSH_DIR_IN) == 0)) &&
ELEM(brush->sculpt_tool, SCULPT_TOOL_DRAW,
SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY,
SCULPT_TOOL_PINCH, SCULPT_TOOL_CREASE))
diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c
index 439c2a639bd..8c754d7adf3 100644
--- a/source/blender/editors/sculpt_paint/paint_curve.c
+++ b/source/blender/editors/sculpt_paint/paint_curve.c
@@ -222,6 +222,28 @@ static int paintcurve_point_co_index(char sel)
return i;
}
+static char paintcurve_point_side_index(const BezTriple *bezt, const bool is_first, const char fallback)
+{
+ /* when matching, guess based on endpoint side */
+ if (BEZSELECTED(bezt)) {
+ if ((bezt->f1 & SELECT) == (bezt->f3 & SELECT)) {
+ return is_first ? SEL_F1 : SEL_F3;
+ }
+ else if (bezt->f1 & SELECT) {
+ return SEL_F1;
+ }
+ else if (bezt->f3 & SELECT) {
+ return SEL_F3;
+ }
+ else {
+ return fallback;
+ }
+ }
+ else {
+ return 0;
+ }
+}
+
/******************* Operators *********************************/
static int paintcurve_new_exec(bContext *C, wmOperator *UNUSED(op))
@@ -295,10 +317,17 @@ static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2])
for (i = 0; i < pc->tot_points; i++) {
pcp[i].bez.f1 = pcp[i].bez.f2 = pcp[i].bez.f3 = 0;
}
- pcp[add_index].bez.f3 = SELECT;
- pcp[add_index].bez.h2 = HD_ALIGN;
- pc->add_index = add_index + 1;
+ BKE_paint_curve_clamp_endpoint_add_index(pc, add_index);
+
+ if (pc->add_index != 0) {
+ pcp[add_index].bez.f3 = SELECT;
+ pcp[add_index].bez.h2 = HD_ALIGN;
+ }
+ else {
+ pcp[add_index].bez.f1 = SELECT;
+ pcp[add_index].bez.h1 = HD_ALIGN;
+ }
WM_paint_cursor_tag_redraw(window, ar);
}
@@ -384,7 +413,7 @@ static int paintcurve_delete_point_exec(bContext *C, wmOperator *op)
points_new[j] = pc->points[i];
if ((i + 1) == pc->add_index) {
- pc->add_index = j + 1;
+ BKE_paint_curve_clamp_endpoint_add_index(pc, j);
}
j++;
}
@@ -469,7 +498,7 @@ static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2
pcp = paintcurve_point_get_closest(pc, loc_fl, false, PAINT_CURVE_SELECT_THRESHOLD, &selflag);
if (pcp) {
- pc->add_index = (pcp - pc->points) + 1;
+ BKE_paint_curve_clamp_endpoint_add_index(pc, pcp - pc->points);
if (selflag == SEL_F2) {
if (extend)
@@ -599,9 +628,8 @@ static int paintcurve_slide_invoke(bContext *C, wmOperator *op, const wmEvent *e
pcp = NULL;
/* just find first selected point */
for (i = 0; i < pc->tot_points; i++) {
- if (pc->points[i].bez.f1 || pc->points[i].bez.f2 || pc->points[i].bez.f3) {
+ if ((select = paintcurve_point_side_index(&pc->points[i].bez, i == 0, SEL_F3))) {
pcp = &pc->points[i];
- select = SEL_F3;
break;
}
}
@@ -631,7 +659,7 @@ static int paintcurve_slide_invoke(bContext *C, wmOperator *op, const wmEvent *e
/* only select the active point */
PAINT_CURVE_POINT_SELECT(pcp, psd->select);
- pc->add_index = (pcp - pc->points) + 1;
+ BKE_paint_curve_clamp_endpoint_add_index(pc, pcp - pc->points);
WM_event_add_modal_handler(C, op);
WM_paint_cursor_tag_redraw(window, ar);
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index f1c91d0fcb5..52a60347f9f 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -150,7 +150,7 @@ static void partialvis_update_grids(Object *ob,
/* get PBVH data */
BKE_pbvh_node_get_grids(pbvh, node,
&grid_indices, &totgrid, NULL, NULL,
- &grids, NULL);
+ &grids);
grid_hidden = BKE_pbvh_grid_hidden(pbvh);
BKE_pbvh_get_grid_key(pbvh, &key);
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 5cfbd164153..346be5b336e 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -215,7 +215,7 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi
return NULL;
}
-void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **mask, bool **valid, bool proj)
+void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **mask, bool **valid, bool proj, bool find_prev)
{
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
UndoImageTile *tile;
@@ -226,7 +226,7 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile,
/* check if tile is already pushed */
/* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
- if (!proj) {
+ if (find_prev) {
data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, mask, true);
if (data)
return data;
@@ -445,7 +445,7 @@ void imapaint_region_tiles(ImBuf *ibuf, int x, int y, int w, int h, int *tx, int
*ty = (y >> IMAPAINT_TILE_BITS);
}
-void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
+void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h, bool find_old)
{
ImBuf *tmpibuf = NULL;
int tilex, tiley, tilew, tileh, tx, ty;
@@ -474,7 +474,7 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
for (ty = tiley; ty <= tileh; ty++)
for (tx = tilex; tx <= tilew; tx++)
- image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false);
+ image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
ibuf->userflags |= IB_BITMAPDIRTY;
@@ -499,7 +499,7 @@ void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short te
int w = imapaintpartial.x2 - imapaintpartial.x1;
int h = imapaintpartial.y2 - imapaintpartial.y1;
/* Testing with partial update in uv editor too */
- GPU_paint_update_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h); //!texpaint);
+ GPU_paint_update_image(image, (sima ? &sima->iuser : NULL), imapaintpartial.x1, imapaintpartial.y1, w, h); //!texpaint);
}
}
@@ -1393,7 +1393,7 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
if (ma && ma->texpaintslot)
ima = ma->texpaintslot[ma->paint_active_slot].ima;
}
- else if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
+ else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
ima = imapaint->canvas;
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index b0fd6a9fa6b..1ad700b2964 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -345,8 +345,8 @@ static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter, int d
{
Brush *brush = painter->brush;
- int xoff = -diameter * 0.5f + 0.5f;
- int yoff = -diameter * 0.5f + 0.5f;
+ int xoff = -radius;
+ int yoff = -radius;
unsigned short *mask, *m;
int x, y;
@@ -889,7 +889,7 @@ static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb,
/* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
* colored speckles appearing in final image, and also to check for threshold */
- outrgb[0] = outrgb[1] = outrgb[2] = rgb_to_grayscale(outrgb);
+ outrgb[0] = outrgb[1] = outrgb[2] = IMB_colormanagement_get_luminance(outrgb);
if (fabsf(outrgb[0]) > threshold) {
float mask = BKE_brush_alpha_get(s->scene, s->brush);
float alpha = rgba[3];
@@ -996,8 +996,8 @@ static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[2])
{
- ipos[0] = (int)floorf((pos[0] - ibufb->x / 2) + 1.0f);
- ipos[1] = (int)floorf((pos[1] - ibufb->y / 2) + 1.0f);
+ ipos[0] = (int)floorf((pos[0] - ibufb->x / 2));
+ ipos[1] = (int)floorf((pos[1] - ibufb->y / 2));
}
static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsigned short *texmaskb, const float lastpos[2], const float pos[2])
@@ -1049,7 +1049,7 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign
for (a = 0; a < tot; a++) {
ED_imapaint_dirty_region(s->image, s->canvas,
region[a].destx, region[a].desty,
- region[a].width, region[a].height);
+ region[a].width, region[a].height, true);
if (s->do_masking) {
/* masking, find original pixels tiles from undo buffer to composite over */
@@ -1109,7 +1109,7 @@ static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
if (ima == NULL) {
return 0;
}
- else if (ima->packedfile && ima->rr) {
+ else if (BKE_image_has_packedfile(ima) && ima->rr) {
s->warnpackedfile = ima->id.name + 2;
return 0;
}
@@ -1306,12 +1306,12 @@ static void paint_2d_fill_add_pixel_byte(
const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched,
const float color[4], float threshold_sq)
{
- int coordinate;
+ size_t coordinate;
if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
return;
- coordinate = y_px * ibuf->x + x_px;
+ coordinate = ((size_t)y_px) * ibuf->x + x_px;
if (!BLI_BITMAP_TEST(touched, coordinate)) {
float color_f[4];
@@ -1329,12 +1329,12 @@ static void paint_2d_fill_add_pixel_float(
const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched,
const float color[4], float threshold_sq)
{
- int coordinate;
+ size_t coordinate;
if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
return;
- coordinate = y_px * ibuf->x + x_px;
+ coordinate = ((size_t)y_px) * ibuf->x + x_px;
if (!BLI_BITMAP_TEST(touched, coordinate)) {
if (compare_len_squared_v3v3(ibuf->rect_float + 4 * coordinate, color, threshold_sq)) {
@@ -1386,21 +1386,21 @@ void paint_2d_bucket_fill(
if (!mouse_init || !br) {
/* first case, no image UV, fill the whole image */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
if (do_float) {
for (x_px = 0; x_px < ibuf->x; x_px++) {
for (y_px = 0; y_px < ibuf->y; y_px++) {
- blend_color_mix_float(ibuf->rect_float + 4 * (y_px * ibuf->x + x_px),
- ibuf->rect_float + 4 * (y_px * ibuf->x + x_px), color_f);
+ blend_color_mix_float(ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
+ ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px), color_f);
}
}
}
else {
for (x_px = 0; x_px < ibuf->x; x_px++) {
for (y_px = 0; y_px < ibuf->y; y_px++) {
- blend_color_mix_byte((unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px),
- (unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px), (unsigned char *)&color_b);
+ blend_color_mix_byte((unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px), (unsigned char *)&color_b);
}
}
}
@@ -1410,7 +1410,7 @@ void paint_2d_bucket_fill(
* value is within the brush fill threshold from the fill color */
BLI_Stack *stack;
BLI_bitmap *touched;
- int coordinate;
+ size_t coordinate;
int width = ibuf->x;
float image_init[2];
int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0;
@@ -1428,12 +1428,12 @@ void paint_2d_bucket_fill(
}
/* change image invalidation method later */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
- stack = BLI_stack_new(sizeof(int), __func__);
- touched = BLI_BITMAP_NEW(ibuf->x * ibuf->y, "bucket_fill_bitmap");
+ stack = BLI_stack_new(sizeof(size_t), __func__);
+ touched = BLI_BITMAP_NEW(((size_t)ibuf->x) * ibuf->y, "bucket_fill_bitmap");
- coordinate = (y_px * ibuf->x + x_px);
+ coordinate = (((size_t)y_px) * ibuf->x + x_px);
if (do_float) {
copy_v4_v4(pixel_color, ibuf->rect_float + 4 * coordinate);
@@ -1566,7 +1566,7 @@ void paint_2d_gradient_fill(
do_float = (ibuf->rect_float != NULL);
/* this will be substituted by something else when selection is available */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
if (do_float) {
for (x_px = 0; x_px < ibuf->x; x_px++) {
@@ -1590,8 +1590,8 @@ void paint_2d_gradient_fill(
/* convert to premultiplied */
mul_v3_fl(color_f, color_f[3]);
color_f[3] *= br->alpha;
- IMB_blend_color_float(ibuf->rect_float + 4 * (y_px * ibuf->x + x_px),
- ibuf->rect_float + 4 * (y_px * ibuf->x + x_px),
+ IMB_blend_color_float(ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
+ ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
color_f, br->blend);
}
}
@@ -1619,8 +1619,8 @@ void paint_2d_gradient_fill(
linearrgb_to_srgb_v3_v3(color_f, color_f);
rgba_float_to_uchar((unsigned char *)&color_b, color_f);
((unsigned char *)&color_b)[3] *= br->alpha;
- IMB_blend_color_byte((unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px),
- (unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px),
+ IMB_blend_color_byte((unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
(unsigned char *)&color_b, br->blend);
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 098f0d04d78..58f1ebb9eac 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -43,6 +43,7 @@
#include "BLI_blenlib.h"
#include "BLI_linklist.h"
#include "BLI_math.h"
+#include "BLI_math_bits.h"
#include "BLI_math_color_blend.h"
#include "BLI_memarena.h"
#include "BLI_threads.h"
@@ -134,6 +135,8 @@ BLI_INLINE unsigned char f_to_char(const float val)
//#define PROJ_DEBUG_PRINT_CLIP 1
#define PROJ_DEBUG_WINCLIP 1
+
+#ifndef PROJ_DEBUG_NOSEAMBLEED
/* projectFaceSeamFlags options */
//#define PROJ_FACE_IGNORE (1<<0) /* When the face is hidden, backfacing or occluded */
//#define PROJ_FACE_INIT (1<<1) /* When we have initialized the faces data */
@@ -151,6 +154,13 @@ BLI_INLINE unsigned char f_to_char(const float val)
#define PROJ_FACE_WINDING_INIT 1
#define PROJ_FACE_WINDING_CW 2
+/* a slightly scaled down face is used to get fake 3D location for edge pixels in the seams
+ * as this number approaches 1.0f the likelihood increases of float precision errors where
+ * it is occluded by an adjacent face */
+#define PROJ_FACE_SCALE_SEAM 0.99f
+#endif /* PROJ_DEBUG_NOSEAMBLEED */
+
+
#define PROJ_SRC_VIEW 1
#define PROJ_SRC_IMAGE_CAM 2
#define PROJ_SRC_IMAGE_VIEW 3
@@ -159,12 +169,6 @@ BLI_INLINE unsigned char f_to_char(const float val)
#define PROJ_VIEW_DATA_ID "view_data"
#define PROJ_VIEW_DATA_SIZE (4 * 4 + 4 * 4 + 3) /* viewmat + winmat + clipsta + clipend + is_ortho */
-
-/* a slightly scaled down face is used to get fake 3D location for edge pixels in the seams
- * as this number approaches 1.0f the likelihood increases of float precision errors where
- * it is occluded by an adjacent face */
-#define PROJ_FACE_SCALE_SEAM 0.99f
-
#define PROJ_BUCKET_NULL 0
#define PROJ_BUCKET_INIT (1 << 0)
// #define PROJ_BUCKET_CLONE_INIT (1<<1)
@@ -190,9 +194,32 @@ typedef struct ProjPaintImage {
unsigned short **maskRect; /* the mask accumulation must happen on canvas, not on space screen bucket.
* Here we store the mask rectangle */
bool **valid; /* store flag to enforce validation of undo rectangle */
- int touch;
+ bool touch;
} ProjPaintImage;
+/**
+ * Handle for stroke (operator customdata)
+ */
+typedef struct ProjStrokeHandle {
+ /* Support for painting from multiple views at once,
+ * currently used to impliment summetry painting,
+ * we can assume at least the first is set while painting. */
+ struct ProjPaintState *ps_views[8];
+ int ps_views_tot;
+ int symmetry_flags;
+
+ int orig_brush_size;
+
+ bool need_redraw;
+
+ /* trick to bypass regular paint and allow clone picking */
+ bool is_clone_cursor_pick;
+
+ /* In ProjPaintState, only here for convenience */
+ Scene *scene;
+ Brush *brush;
+} ProjStrokeHandle;
+
/* Main projection painting struct passed to all projection painting functions */
typedef struct ProjPaintState {
View3D *v3d;
@@ -208,24 +235,14 @@ typedef struct ProjPaintState {
Brush *brush;
short tool, blend, mode;
- int orig_brush_size;
+
float brush_size;
Object *ob;
+ /* for symmetry, we need to store modified object matrix */
+ float obmat[4][4];
+ float obmat_imat[4][4];
/* end similarities with ImagePaintState */
- DerivedMesh *dm;
- int dm_totface;
- int dm_totedge;
- int dm_totvert;
- int dm_release;
-
- MVert *dm_mvert;
- MEdge *dm_medge;
- MFace *dm_mface;
- MTFace **dm_mtface;
- MTFace **dm_mtface_clone; /* other UV map, use for cloning between layers */
- MTFace *dm_mtface_stencil;
-
Image *stencil_ima;
Image *canvas_ima;
Image *clone_ima;
@@ -236,24 +253,16 @@ typedef struct ProjPaintState {
LinkNode **bucketRect; /* screen sized 2D array, each pixel has a linked list of ProjPixel's */
LinkNode **bucketFaces; /* bucketRect aligned array linkList of faces overlapping each bucket */
unsigned char *bucketFlags; /* store if the bucks have been initialized */
-#ifndef PROJ_DEBUG_NOSEAMBLEED
- char *faceSeamFlags; /* store info about faces, if they are initialized etc*/
- char *faceWindingFlags; /* save the winding of the face in uv space, helps as an extra validation step for seam detection */
- float (*faceSeamUVs)[4][2]; /* expanded UVs for faces to use as seams */
- LinkNode **vertFaces; /* Only needed for when seam_bleed_px is enabled, use to find UV seams */
-#endif
+
char *vertFlags; /* store options per vert, now only store if the vert is pointing away from the view */
int buckets_x; /* The size of the bucket grid, the grid span's screenMin/screenMax so you can paint outsize the screen or with 2 brushes at once */
int buckets_y;
- ProjPaintImage *projImages;
-
int pixel_sizeof; /* result of project_paint_pixel_sizeof(), constant per stroke */
int image_tot; /* size of projectImages array */
float (*screenCoords)[4]; /* verts projected into floating point screen space */
- float *cavities; /* cavity amount for vertices */
float screenMin[2]; /* 2D bounds for mesh verts on the screen's plane (screenspace) */
float screenMax[2];
float screen_width; /* Calculated from screenMin & screenMax */
@@ -272,12 +281,15 @@ typedef struct ProjPaintState {
bool do_mask_normal; /* mask out pixels based on their normals */
bool do_mask_cavity; /* mask out pixels based on cavity */
bool do_new_shading_nodes; /* cache BKE_scene_use_new_shading_nodes value */
- float normal_angle; /* what angle to mask at*/
+ float normal_angle; /* what angle to mask at */
+ float normal_angle__cos; /* cos(normal_angle), faster to compare */
float normal_angle_inner;
+ float normal_angle_inner__cos;
float normal_angle_range; /* difference between normal_angle and normal_angle_inner, for easy access */
bool do_face_sel; /* quick access to (me->editflag & ME_EDIT_PAINT_FACE_SEL) */
bool is_ortho;
+ bool is_flip_object; /* the object is negative scaled */
bool do_masking; /* use masking during painting. Some operations such as airbrush may disable */
bool is_texbrush; /* only to avoid running */
bool is_maskbrush; /* mask brush is applied before masking */
@@ -302,13 +314,51 @@ typedef struct ProjPaintState {
int bucketMax[2];
int context_bucket_x, context_bucket_y; /* must lock threads while accessing these */
- /* redraw */
- bool need_redraw;
-
struct CurveMapping *cavity_curve;
BlurKernel *blurkernel;
+
+
+ /* -------------------------------------------------------------------- */
+ /* Vars shared between multiple views (keep last) */
+ /**
+ * This data is owned by ``ProjStrokeHandle.ps_views[0]``,
+ * all other views re-use the data.
+ */
+
+#define PROJ_PAINT_STATE_SHARED_MEMCPY(ps_dst, ps_src) \
+ MEMCPY_STRUCT_OFS(ps_dst, ps_src, is_shared_user)
+
+#define PROJ_PAINT_STATE_SHARED_CLEAR(ps) \
+ MEMSET_STRUCT_OFS(ps, 0, is_shared_user)
+
+ bool is_shared_user;
+
+ ProjPaintImage *projImages;
+ float *cavities; /* cavity amount for vertices */
+
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+ char *faceSeamFlags; /* store info about faces, if they are initialized etc*/
+ char *faceWindingFlags; /* save the winding of the face in uv space, helps as an extra validation step for seam detection */
+ float (*faceSeamUVs)[4][2]; /* expanded UVs for faces to use as seams */
+ LinkNode **vertFaces; /* Only needed for when seam_bleed_px is enabled, use to find UV seams */
+#endif
+
SpinLock *tile_lock;
+
+ DerivedMesh *dm;
+ int dm_totface;
+ int dm_totedge;
+ int dm_totvert;
+ int dm_release;
+
+ MVert *dm_mvert;
+ MEdge *dm_medge;
+ MFace *dm_mface;
+ MTFace *dm_mtface_stencil;
+
+ MTFace **dm_mtface;
+ MTFace **dm_mtface_clone; /* other UV map, use for cloning between layers */
} ProjPaintState;
typedef union pixelPointer {
@@ -326,25 +376,27 @@ typedef union pixelStore {
typedef struct ProjPixel {
float projCoSS[2]; /* the floating point screen projection of this pixel */
float worldCoSS[3];
+
+ short x_px, y_px;
+
+ unsigned short image_index; /* if anyone wants to paint onto more than 65535 images they can bite me */
+ unsigned char bb_cell_index;
+
+ /* for various reasons we may want to mask out painting onto this pixel */
+ unsigned short mask;
+
/* Only used when the airbrush is disabled.
* Store the max mask value to avoid painting over an area with a lower opacity
* with an advantage that we can avoid touching the pixel at all, if the
* new mask value is lower then mask_accum */
unsigned short *mask_accum;
- /* for various reasons we may want to mask out painting onto this pixel */
- unsigned short mask;
-
- short x_px, y_px;
/* horrible hack, store tile valid flag pointer here to re-validate tiles used for anchored and drag-dot strokes */
bool *valid;
PixelPointer origColor;
PixelStore newColor;
PixelPointer pixel;
-
- short image_index; /* if anyone wants to paint onto more than 32768 images they can bite me */
- unsigned char bb_cell_index;
} ProjPixel;
typedef struct ProjPixelClone {
@@ -474,7 +526,9 @@ static float VecZDepthPersp(
/* Return the top-most face index that the screen space coord 'pt' touches (or -1) */
-static int project_paint_PickFace(const ProjPaintState *ps, const float pt[2], float w[3], int *side)
+static int project_paint_PickFace(
+ const ProjPaintState *ps, const float pt[2],
+ float w[3], int *r_side)
{
LinkNode *node;
float w_tmp[3];
@@ -531,7 +585,7 @@ static int project_paint_PickFace(const ProjPaintState *ps, const float pt[2], f
}
}
- *side = best_side;
+ *r_side = best_side;
return best_face_index; /* will be -1 or a valid face */
}
@@ -718,7 +772,7 @@ static bool project_bucket_point_occluded(
int face_index;
int isect_ret;
float w[3]; /* not needed when clipping */
- const short do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
+ const bool do_clip = ps->rv3d ? (ps->rv3d->rflag & RV3D_CLIPPING) != 0 : 0;
/* we could return 0 for 1 face buckets, as long as this function assumes
* that the point its testing is only every originated from an existing face */
@@ -1228,22 +1282,22 @@ static void screen_px_from_persp(
static void project_face_pixel(
const MTFace *tf_other, ImBuf *ibuf_other, const float w[3],
- int side, unsigned char rgba_ub[4], float rgba_f[4])
+ bool side, unsigned char rgba_ub[4], float rgba_f[4])
{
const float *uvCo1, *uvCo2, *uvCo3;
float uv_other[2], x, y;
- uvCo1 = (float *)tf_other->uv[0];
+ uvCo1 = tf_other->uv[0];
if (side == 1) {
- uvCo2 = (float *)tf_other->uv[2];
- uvCo3 = (float *)tf_other->uv[3];
+ uvCo2 = tf_other->uv[2];
+ uvCo3 = tf_other->uv[3];
}
else {
- uvCo2 = (float *)tf_other->uv[1];
- uvCo3 = (float *)tf_other->uv[2];
+ uvCo2 = tf_other->uv[1];
+ uvCo3 = tf_other->uv[2];
}
- interp_v2_v2v2v2(uv_other, uvCo1, uvCo2, uvCo3, (float *)w);
+ interp_v2_v2v2v2(uv_other, uvCo1, uvCo2, uvCo3, w);
/* use */
uvco_to_wrapped_pxco(uv_other, ibuf_other->x, ibuf_other->y, &x, &y);
@@ -1262,7 +1316,7 @@ static void project_face_pixel(
static float project_paint_uvpixel_mask(
const ProjPaintState *ps,
const int face_index,
- const int side,
+ const bool side,
const float w[3])
{
float mask;
@@ -1327,7 +1381,7 @@ static float project_paint_uvpixel_mask(
/* calculate mask */
if (ps->do_mask_normal) {
MFace *mf = &ps->dm_mface[face_index];
- float no[3], angle;
+ float no[3], angle_cos;
if (mf->flag & ME_SMOOTH) {
const short *no1, *no2, *no3;
no1 = ps->dm_mvert[mf->v1].no;
@@ -1366,9 +1420,13 @@ static float project_paint_uvpixel_mask(
#endif
}
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(no);
+ }
+
/* now we can use the normal as a mask */
if (ps->is_ortho) {
- angle = angle_normalized_v3v3(ps->viewDir, no);
+ angle_cos = dot_v3v3(ps->viewDir, no);
}
else {
/* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */
@@ -1389,15 +1447,18 @@ static float project_paint_uvpixel_mask(
viewDirPersp[1] = (ps->viewPos[1] - (w[0] * co1[1] + w[1] * co2[1] + w[2] * co3[1]));
viewDirPersp[2] = (ps->viewPos[2] - (w[0] * co1[2] + w[1] * co2[2] + w[2] * co3[2]));
normalize_v3(viewDirPersp);
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(viewDirPersp);
+ }
- angle = angle_normalized_v3v3(viewDirPersp, no);
+ angle_cos = dot_v3v3(viewDirPersp, no);
}
- if (angle >= ps->normal_angle) {
+ if (angle_cos <= ps->normal_angle__cos) {
return 0.0f; /* outsize the normal limit*/
}
- else if (angle > ps->normal_angle_inner) {
- mask *= (ps->normal_angle - angle) / ps->normal_angle_range;
+ else if (angle_cos < ps->normal_angle_inner__cos) {
+ mask *= (ps->normal_angle - acosf(angle_cos)) / ps->normal_angle_range;
} /* otherwise no mask normal is needed, were within the limit */
}
@@ -1440,10 +1501,10 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
if (generate_tile) {
volatile void *undorect;
if (tinf->masked) {
- undorect = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, &pjIma->maskRect[tile_index], &pjIma->valid[tile_index], true);
+ undorect = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, &pjIma->maskRect[tile_index], &pjIma->valid[tile_index], true, false);
}
else {
- undorect = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, NULL, &pjIma->valid[tile_index], true);
+ undorect = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, NULL, &pjIma->valid[tile_index], true, false);
}
pjIma->ibuf->userflags |= IB_BITMAPDIRTY;
@@ -1470,7 +1531,7 @@ static ProjPixel *project_paint_uvpixel_init(
const int face_index,
const float pixelScreenCo[4],
const float world_spaceCo[3],
- const int side,
+ const bool side,
const float w[3])
{
ProjPixel *projPixel;
@@ -1591,7 +1652,7 @@ static ProjPixel *project_paint_uvpixel_init(
}
else {
float co[2];
- sub_v2_v2v2(co, projPixel->projCoSS, (float *)ps->cloneOffset);
+ sub_v2_v2v2(co, projPixel->projCoSS, ps->cloneOffset);
/* no need to initialize the bucket, we're only checking buckets faces and for this
* the faces are already initialized in project_paint_delayed_face_init(...) */
@@ -1619,13 +1680,14 @@ static ProjPixel *project_paint_uvpixel_init(
}
static bool line_clip_rect2f(
+ const rctf *cliprect,
const rctf *rect,
const float l1[2], const float l2[2],
float l1_clip[2], float l2_clip[2])
{
/* first account for horizontal, then vertical lines */
/* horiz */
- if (fabsf(l1[1] - l2[1]) < PROJ_GEOM_TOLERANCE) {
+ if (fabsf(l1[1] - l2[1]) < PROJ_PIXEL_TOLERANCE) {
/* is the line out of range on its Y axis? */
if (l1[1] < rect->ymin || l1[1] > rect->ymax) {
return 0;
@@ -1636,7 +1698,7 @@ static bool line_clip_rect2f(
}
- if (fabsf(l1[0] - l2[0]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/
+ if (fabsf(l1[0] - l2[0]) < PROJ_PIXEL_TOLERANCE) { /* this is a single point (or close to)*/
if (BLI_rctf_isect_pt_v(rect, l1)) {
copy_v2_v2(l1_clip, l1);
copy_v2_v2(l2_clip, l2);
@@ -1653,7 +1715,7 @@ static bool line_clip_rect2f(
CLAMP(l2_clip[0], rect->xmin, rect->xmax);
return 1;
}
- else if (fabsf(l1[0] - l2[0]) < PROJ_GEOM_TOLERANCE) {
+ else if (fabsf(l1[0] - l2[0]) < PROJ_PIXEL_TOLERANCE) {
/* is the line out of range on its X axis? */
if (l1[0] < rect->xmin || l1[0] > rect->xmax) {
return 0;
@@ -1664,7 +1726,7 @@ static bool line_clip_rect2f(
return 0;
}
- if (fabsf(l1[1] - l2[1]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/
+ if (fabsf(l1[1] - l2[1]) < PROJ_PIXEL_TOLERANCE) { /* this is a single point (or close to)*/
if (BLI_rctf_isect_pt_v(rect, l1)) {
copy_v2_v2(l1_clip, l1);
copy_v2_v2(l2_clip, l2);
@@ -1703,7 +1765,7 @@ static bool line_clip_rect2f(
if (ok1 && ok2) return 1;
/* top/bottom */
- if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) {
+ if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= cliprect->xmin) && (isect <= cliprect->xmax)) {
if (l1[1] < l2[1]) { /* line 1 is outside */
l1_clip[0] = isect;
l1_clip[1] = rect->ymin;
@@ -1718,7 +1780,7 @@ static bool line_clip_rect2f(
if (ok1 && ok2) return 1;
- if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) {
+ if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= cliprect->xmin) && (isect <= cliprect->xmax)) {
if (l1[1] > l2[1]) { /* line 1 is outside */
l1_clip[0] = isect;
l1_clip[1] = rect->ymax;
@@ -1734,7 +1796,7 @@ static bool line_clip_rect2f(
if (ok1 && ok2) return 1;
/* left/right */
- if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) {
+ if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= cliprect->ymin) && (isect <= cliprect->ymax)) {
if (l1[0] < l2[0]) { /* line 1 is outside */
l1_clip[0] = rect->xmin;
l1_clip[1] = isect;
@@ -1749,7 +1811,7 @@ static bool line_clip_rect2f(
if (ok1 && ok2) return 1;
- if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) {
+ if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= cliprect->ymin) && (isect <= cliprect->ymax)) {
if (l1[0] > l2[0]) { /* line 1 is outside */
l1_clip[0] = rect->xmax;
l1_clip[1] = isect;
@@ -1964,7 +2026,7 @@ static float angle_2d_clockwise(const float p1[2], const float p2[2], const floa
v1[0] = p1[0] - p2[0]; v1[1] = p1[1] - p2[1];
v2[0] = p3[0] - p2[0]; v2[1] = p3[1] - p2[1];
- return -atan2(v1[0] * v2[1] - v1[1] * v2[0], v1[0] * v2[0] + v1[1] * v2[1]);
+ return -atan2f(v1[0] * v2[1] - v1[1] * v2[0], v1[0] * v2[0] + v1[1] * v2[1]);
}
#endif
@@ -1976,7 +2038,10 @@ static float angle_2d_clockwise(const float p1[2], const float p2[2], const floa
#define ISECT_ALL4 ((1 << 4) - 1)
/* limit must be a fraction over 1.0f */
-static bool IsectPT2Df_limit(float pt[2], float v1[2], float v2[2], float v3[2], float limit)
+static bool IsectPT2Df_limit(
+ const float pt[2],
+ const float v1[2], const float v2[2], const float v3[2],
+ const float limit)
{
return ((area_tri_v2(pt, v1, v2) +
area_tri_v2(pt, v2, v3) +
@@ -2043,9 +2108,10 @@ static bool line_rect_clip(
static void project_bucket_clip_face(
- const bool is_ortho,
+ const bool is_ortho, const bool is_flip_object,
+ const rctf *cliprect,
const rctf *bucket_bounds,
- float *v1coSS, float *v2coSS, float *v3coSS,
+ const float *v1coSS, const float *v2coSS, const float *v3coSS,
const float *uv1co, const float *uv2co, const float *uv3co,
float bucket_bounds_uv[8][2],
int *tot, bool cull)
@@ -2071,7 +2137,8 @@ static void project_bucket_clip_face(
inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v3coSS) << 2;
if (inside_bucket_flag == ISECT_ALL3) {
- flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) !=
+ /* is_flip_object is used here because we use the face winding */
+ flip = (((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != is_flip_object) !=
(line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
/* all screenspace points are inside the bucket bounding box,
@@ -2193,7 +2260,7 @@ static void project_bucket_clip_face(
float cent[2] = {0.0f, 0.0f};
/*float up[2] = {0.0f, 1.0f};*/
int i;
- short doubles;
+ bool doubles;
(*tot) = 0;
@@ -2207,21 +2274,21 @@ static void project_bucket_clip_face(
if (inside_bucket_flag & ISECT_3) { copy_v2_v2(isectVCosSS[*tot], v3coSS); (*tot)++; }
if ((inside_bucket_flag & (ISECT_1 | ISECT_2)) != (ISECT_1 | ISECT_2)) {
- if (line_clip_rect2f(bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) {
+ if (line_clip_rect2f(cliprect, bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) {
if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
}
}
if ((inside_bucket_flag & (ISECT_2 | ISECT_3)) != (ISECT_2 | ISECT_3)) {
- if (line_clip_rect2f(bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) {
+ if (line_clip_rect2f(cliprect, bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) {
if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
}
}
if ((inside_bucket_flag & (ISECT_3 | ISECT_1)) != (ISECT_3 | ISECT_1)) {
- if (line_clip_rect2f(bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) {
+ if (line_clip_rect2f(cliprect, bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) {
if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
}
@@ -2404,7 +2471,7 @@ static bool IsectPoly2Df(const float pt[2], float uv[][2], const int tot)
static bool IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot)
{
int i;
- int side = (line_point_side_v2(uv[tot - 1], uv[0], pt) > 0.0f);
+ bool side = (line_point_side_v2(uv[tot - 1], uv[0], pt) > 0.0f);
for (i = 1; i < tot; i++) {
if ((line_point_side_v2(uv[i - 1], uv[i], pt) > 0.0f) != side)
@@ -2423,7 +2490,8 @@ static bool IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot
static void project_paint_face_init(
const ProjPaintState *ps,
const int thread_index, const int bucket_index, const int face_index, const int image_index,
- const rctf *bucket_bounds, ImBuf *ibuf, ImBuf **tmpibuf, const short clamp_u, const short clamp_v)
+ const rctf *clip_rect, const rctf *bucket_bounds, ImBuf *ibuf, ImBuf **tmpibuf,
+ const bool clamp_u, const bool clamp_v)
{
/* Projection vars, to get the 3D locations into screen space */
MemArena *arena = ps->arena_mt[thread_index];
@@ -2448,8 +2516,8 @@ static void project_paint_face_init(
float mask;
float uv[2]; /* Image floating point UV - same as x, y but from 0.0-1.0 */
- int side;
- float *v1coSS, *v2coSS, *v3coSS; /* vert co screen-space, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */
+ bool side;
+ const float *v1coSS, *v2coSS, *v3coSS; /* vert co screen-space, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */
float *vCo[4]; /* vertex screenspace coords */
@@ -2468,11 +2536,10 @@ static void project_paint_face_init(
int has_x_isect = 0, has_isect = 0; /* for early loop exit */
- int i1, i2, i3;
-
float uv_clip[8][2];
int uv_clip_tot;
const bool is_ortho = ps->is_ortho;
+ const bool is_flip_object = ps->is_flip_object;
const bool do_backfacecull = ps->do_backfacecull;
const bool do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
@@ -2517,6 +2584,8 @@ static void project_paint_face_init(
}
do {
+ int i1, i2, i3;
+
if (side == 1) {
i1 = 0; i2 = 2; i3 = 3;
}
@@ -2534,11 +2603,12 @@ static void project_paint_face_init(
/* This funtion gives is a concave polyline in UV space from the clipped quad and tri*/
project_bucket_clip_face(
- is_ortho, bucket_bounds,
+ is_ortho, is_flip_object,
+ clip_rect, bucket_bounds,
v1coSS, v2coSS, v3coSS,
uv1co, uv2co, uv3co,
uv_clip, &uv_clip_tot,
- ps->do_backfacecull || ps->do_occlude);
+ do_backfacecull || ps->do_occlude);
/* sometimes this happens, better just allow for 8 intersectiosn even though there should be max 6 */
#if 0
@@ -2674,7 +2744,7 @@ static void project_paint_face_init(
int fidx1, fidx2; /* face edge pairs - loop throuh these ((0,1), (1,2), (2,3), (3,0)) or ((0,1), (1,2), (2,0)) for a tri */
float seam_subsection[4][2];
- float fac1, fac2, ftot;
+ float fac1, fac2;
if (outset_uv[0][0] == FLT_MAX) /* first time initialize */
uv_image_outset(tf_uv_pxoffset, outset_uv, ps->seam_bleed_px, ibuf->x, ibuf->y, mf->v4 != 0, (ps->faceWindingFlags[face_index] & PROJ_FACE_WINDING_CW) == 0);
@@ -2706,19 +2776,16 @@ static void project_paint_face_init(
else fidx2 = (fidx1 == 2) ? 0 : fidx1 + 1; /* next fidx in the face (0,1,2) -> (1,2,0) */
if ((face_seam_flag & (1 << fidx1)) && /* 1<<fidx1 -> PROJ_FACE_SEAM# */
- line_clip_rect2f(bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1]))
+ line_clip_rect2f(clip_rect, bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1]))
{
-
- ftot = len_v2v2(vCoSS[fidx1], vCoSS[fidx2]); /* screenspace edge length */
-
- if (ftot > 0.0f) { /* avoid div by zero */
+ if (len_squared_v2v2(vCoSS[fidx1], vCoSS[fidx2]) > FLT_EPSILON) { /* avoid div by zero */
if (mf->v4) {
- if (fidx1 == 2 || fidx2 == 2) side = 1;
+ if (fidx1 == 3 || fidx2 == 3) side = 1;
else side = 0;
}
- fac1 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[0]) / ftot;
- fac2 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[1]) / ftot;
+ fac1 = line_point_factor_v2(bucket_clip_edges[0], vCoSS[fidx1], vCoSS[fidx2]);
+ fac2 = line_point_factor_v2(bucket_clip_edges[1], vCoSS[fidx1], vCoSS[fidx2]);
interp_v2_v2v2(seam_subsection[0], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac1);
interp_v2_v2v2(seam_subsection[1], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac2);
@@ -2760,11 +2827,8 @@ static void project_paint_face_init(
/* Since this is a seam we need to work out where on the line this pixel is */
//fac = line_point_factor_v2(uv, uv_seam_quad[0], uv_seam_quad[1]);
-
- fac = line_point_factor_v2(uv, seam_subsection[0], seam_subsection[1]);
- if (fac < 0.0f) { copy_v3_v3(pixelScreenCo, edge_verts_inset_clip[0]); }
- else if (fac > 1.0f) { copy_v3_v3(pixelScreenCo, edge_verts_inset_clip[1]); }
- else { interp_v3_v3v3(pixelScreenCo, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac); }
+ fac = resolve_quad_u_v2(uv, UNPACK4(seam_subsection));
+ interp_v3_v3v3(pixelScreenCo, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac);
if (!is_ortho) {
pixelScreenCo[3] = 1.0f;
@@ -2779,24 +2843,20 @@ static void project_paint_face_init(
{
/* Only bother calculating the weights if we intersect */
if (ps->do_mask_normal || ps->dm_mtface_clone) {
-#if 1
+ const float uv_fac = fac1 + (fac * (fac2 - fac1));
+#if 0
/* get the UV on the line since we want to copy the pixels from there for bleeding */
float uv_close[2];
- float uv_fac = closest_to_line_v2(uv_close, uv, tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2]);
- if (uv_fac < 0.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx1]);
- else if (uv_fac > 1.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx2]);
-
+ interp_v2_v2v2(uv_close, tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], uv_fac);
if (side) {
barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[2], tf_uv_pxoffset[3], uv_close, w);
}
else {
barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[1], tf_uv_pxoffset[2], uv_close, w);
}
-#else /* this is buggy with quads, don't use for now */
+#else
/* Cheat, we know where we are along the edge so work out the weights from that */
- uv_fac = fac1 + (uv_fac * (fac2 - fac1));
-
w[0] = w[1] = w[2] = 0.0;
if (side) {
w[fidx1 ? fidx1 - 1 : 0] = 1.0f - uv_fac;
@@ -2811,8 +2871,8 @@ static void project_paint_face_init(
/* a pity we need to get the worldspace pixel location here */
if (do_clip || do_3d_mapping) {
- if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w);
- else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w);
+ if (side) interp_v3_v3v3v3(wco, vCo[0], vCo[2], vCo[3], w);
+ else interp_v3_v3v3v3(wco, vCo[0], vCo[1], vCo[2], w);
if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, true)) {
continue; /* Watch out that no code below this needs to run */
@@ -2851,6 +2911,8 @@ static void project_paint_face_init(
}
}
}
+#else
+ UNUSED_VARS(vCo, threaded);
#endif // PROJ_DEBUG_NOSEAMBLEED
}
@@ -2887,7 +2949,7 @@ static void project_bucket_bounds(const ProjPaintState *ps, const int bucket_x,
/* Fill this bucket with pixels from the faces that intersect it.
*
* have bucket_bounds as an argument so we don't need to give bucket_x/y the rect function needs */
-static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const rctf *bucket_bounds)
+static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const rctf *clip_rect, const rctf *bucket_bounds)
{
LinkNode *node;
int face_index, image_index = 0;
@@ -2902,7 +2964,10 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
ima = ps->projImages[0].ima;
for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
- project_paint_face_init(ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0, bucket_bounds, ibuf, &tmpibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V);
+ project_paint_face_init(
+ ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0,
+ clip_rect, bucket_bounds, ibuf, &tmpibuf,
+ (ima->tpageflag & IMA_CLAMP_U) != 0, (ima->tpageflag & IMA_CLAMP_V) != 0);
}
}
else {
@@ -2926,7 +2991,10 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
}
/* context switching done */
- project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf, &tmpibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V);
+ project_paint_face_init(
+ ps, thread_index, bucket_index, face_index, image_index,
+ clip_rect, bucket_bounds, ibuf, &tmpibuf,
+ (ima->tpageflag & IMA_CLAMP_U) != 0, (ima->tpageflag & IMA_CLAMP_V) != 0);
}
}
@@ -3078,7 +3146,8 @@ static void proj_paint_state_non_cddm_init(ProjPaintState *ps)
}
}
-static void proj_paint_state_viewport_init(ProjPaintState *ps)
+static void proj_paint_state_viewport_init(
+ ProjPaintState *ps, const char symmetry_flag)
{
float mat[3][3];
float viewmat[4][4];
@@ -3088,7 +3157,19 @@ static void proj_paint_state_viewport_init(ProjPaintState *ps)
ps->viewDir[1] = 0.0f;
ps->viewDir[2] = 1.0f;
- invert_m4_m4(ps->ob->imat, ps->ob->obmat);
+ copy_m4_m4(ps->obmat, ps->ob->obmat);
+
+ if (symmetry_flag) {
+ int i;
+ for (i = 0; i < 3; i++) {
+ if ((symmetry_flag >> i) & 1) {
+ negate_v3(ps->obmat[i]);
+ ps->is_flip_object = !ps->is_flip_object;
+ }
+ }
+ }
+
+ invert_m4_m4(ps->obmat_imat, ps->obmat);
if (ELEM(ps->source, PROJ_SRC_VIEW, PROJ_SRC_VIEW_FILL)) {
/* normal drawing */
@@ -3098,7 +3179,7 @@ static void proj_paint_state_viewport_init(ProjPaintState *ps)
copy_m4_m4(viewmat, ps->rv3d->viewmat);
copy_m4_m4(viewinv, ps->rv3d->viewinv);
- ED_view3d_ob_project_mat_get(ps->rv3d, ps->ob, ps->projectMat);
+ ED_view3d_ob_project_mat_get_from_obmat(ps->rv3d, ps->obmat, ps->projectMat);
ps->is_ortho = ED_view3d_clip_range_get(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true);
}
@@ -3151,24 +3232,27 @@ static void proj_paint_state_viewport_init(ProjPaintState *ps)
}
/* same as #ED_view3d_ob_project_mat_get */
- mul_m4_m4m4(vmat, viewmat, ps->ob->obmat);
+ mul_m4_m4m4(vmat, viewmat, ps->obmat);
mul_m4_m4m4(ps->projectMat, winmat, vmat);
}
/* viewDir - object relative */
- invert_m4_m4(ps->ob->imat, ps->ob->obmat);
copy_m3_m4(mat, viewinv);
mul_m3_v3(mat, ps->viewDir);
- copy_m3_m4(mat, ps->ob->imat);
+ copy_m3_m4(mat, ps->obmat_imat);
mul_m3_v3(mat, ps->viewDir);
normalize_v3(ps->viewDir);
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(ps->viewDir);
+ }
+
/* viewPos - object relative */
copy_v3_v3(ps->viewPos, viewinv[3]);
- copy_m3_m4(mat, ps->ob->imat);
+ copy_m3_m4(mat, ps->obmat_imat);
mul_m3_v3(mat, ps->viewPos);
- add_v3_v3(ps->viewPos, ps->ob->imat[3]);
+ add_v3_v3(ps->viewPos, ps->obmat_imat[3]);
}
static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int diameter)
@@ -3234,6 +3318,8 @@ static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int di
CLAMP(ps->screenMin[1], (float)(-diameter), (float)(ps->winy + diameter));
CLAMP(ps->screenMax[1], (float)(-diameter), (float)(ps->winy + diameter));
+#else
+ UNUSED_VARS(diameter);
#endif
}
else if (ps->source != PROJ_SRC_VIEW_FILL) { /* re-projection, use bounds */
@@ -3313,12 +3399,14 @@ static void proj_paint_state_thread_init(ProjPaintState *ps, const bool reset_th
if (reset_threads)
ps->thread_tot = 1;
- if (ps->thread_tot > 1) {
- ps->tile_lock = MEM_mallocN(sizeof(SpinLock), "projpaint_tile_lock");
- BLI_spin_init(ps->tile_lock);
- }
+ if (ps->is_shared_user == false) {
+ if (ps->thread_tot > 1) {
+ ps->tile_lock = MEM_mallocN(sizeof(SpinLock), "projpaint_tile_lock");
+ BLI_spin_init(ps->tile_lock);
+ }
- image_undo_init_locks();
+ image_undo_init_locks();
+ }
for (a = 0; a < ps->thread_tot; a++) {
ps->arena_mt[a] = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "project paint arena");
@@ -3337,16 +3425,22 @@ static void proj_paint_state_vert_flags_init(ProjPaintState *ps)
for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++) {
normal_short_to_float_v3(no, mv->no);
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(no);
+ }
if (ps->is_ortho) {
- if (angle_normalized_v3v3(ps->viewDir, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */
+ if (dot_v3v3(ps->viewDir, no) <= ps->normal_angle__cos) { /* 1 vert of this face is towards us */
ps->vertFlags[a] |= PROJ_VERT_CULL;
}
}
else {
sub_v3_v3v3(viewDirPersp, ps->viewPos, mv->co);
normalize_v3(viewDirPersp);
- if (angle_normalized_v3v3(viewDirPersp, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */
+ if (UNLIKELY(ps->is_flip_object)) {
+ negate_v3(viewDirPersp);
+ }
+ if (dot_v3v3(viewDirPersp, no) <= ps->normal_angle__cos) { /* 1 vert of this face is towards us */
ps->vertFlags[a] |= PROJ_VERT_CULL;
}
}
@@ -3628,7 +3722,7 @@ static bool project_paint_backface_cull(
}
}
else {
- if (line_point_side_v2(coSS->v1, coSS->v2, coSS->v3) < 0.0f) {
+ if ((line_point_side_v2(coSS->v1, coSS->v2, coSS->v3) < 0.0f) != ps->is_flip_object) {
return true;
}
@@ -3670,7 +3764,8 @@ static void project_paint_prepare_all_faces(
ProjPaintState *ps, MemArena *arena,
const ProjPaintFaceLookup *face_lookup,
ProjPaintLayerClone *layer_clone,
- MTFace *tf_base)
+ MTFace *tf_base,
+ const bool is_multi_view)
{
/* Image Vars - keep track of images we have used */
LinkNode *image_LinkList = NULL;
@@ -3729,20 +3824,21 @@ static void project_paint_prepare_all_faces(
ProjPaintFaceCoSS coSS;
proj_paint_face_coSS_init(ps, mf, &coSS);
- if (project_paint_flt_max_cull(ps, &coSS)) {
- continue;
- }
+ if (is_multi_view == false) {
+ if (project_paint_flt_max_cull(ps, &coSS)) {
+ continue;
+ }
#ifdef PROJ_DEBUG_WINCLIP
- if (project_paint_winclip(ps, mf, &coSS)) {
- continue;
- }
+ if (project_paint_winclip(ps, mf, &coSS)) {
+ continue;
+ }
#endif //PROJ_DEBUG_WINCLIP
-
- if (project_paint_backface_cull(ps, mf, &coSS)) {
- continue;
+ if (project_paint_backface_cull(ps, mf, &coSS)) {
+ continue;
+ }
}
if (tpage_last != tpage) {
@@ -3767,18 +3863,22 @@ static void project_paint_prepare_all_faces(
}
/* build an array of images we use*/
- project_paint_build_proj_ima(ps, arena, image_LinkList);
+ if (ps->is_shared_user == false) {
+ project_paint_build_proj_ima(ps, arena, image_LinkList);
+ }
/* we have built the array, discard the linked list */
BLI_linklist_free(image_LinkList, NULL);
}
/* run once per stroke before projection painting */
-static void project_paint_begin(ProjPaintState *ps)
+static void project_paint_begin(
+ ProjPaintState *ps,
+ const bool is_multi_view, const char symmetry_flag)
{
ProjPaintLayerClone layer_clone;
ProjPaintFaceLookup face_lookup;
- MTFace *tf_base;
+ MTFace *tf_base = NULL;
MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */
@@ -3792,10 +3892,13 @@ static void project_paint_begin(ProjPaintState *ps)
ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat); /* faster clipping lookups */
ps->do_face_sel = ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) != 0);
+ ps->is_flip_object = (ps->ob->transflag & OB_NEG_SCALE) != 0;
/* paint onto the derived mesh */
- if (!proj_paint_state_dm_init(ps)) {
- return;
+ if (ps->is_shared_user == false) {
+ if (!proj_paint_state_dm_init(ps)) {
+ return;
+ }
}
proj_paint_face_lookup_init(ps, &face_lookup);
@@ -3817,11 +3920,13 @@ static void project_paint_begin(ProjPaintState *ps)
}
/* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
- proj_paint_state_non_cddm_init(ps);
+ if (ps->is_shared_user == false) {
+ proj_paint_state_non_cddm_init(ps);
- proj_paint_state_cavity_init(ps);
+ proj_paint_state_cavity_init(ps);
+ }
- proj_paint_state_viewport_init(ps);
+ proj_paint_state_viewport_init(ps, symmetry_flag);
/* calculate vert screen coords
* run this early so we can calculate the x/y resolution of our bucket rect */
@@ -3850,7 +3955,9 @@ static void project_paint_begin(ProjPaintState *ps)
ps->bucketFlags = MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
#ifndef PROJ_DEBUG_NOSEAMBLEED
- proj_paint_state_seam_bleed_init(ps);
+ if (ps->is_shared_user == false) {
+ proj_paint_state_seam_bleed_init(ps);
+ }
#endif
proj_paint_state_thread_init(ps, reset_threads);
@@ -3858,7 +3965,7 @@ static void project_paint_begin(ProjPaintState *ps)
proj_paint_state_vert_flags_init(ps);
- project_paint_prepare_all_faces(ps, arena, &face_lookup, &layer_clone, tf_base);
+ project_paint_prepare_all_faces(ps, arena, &face_lookup, &layer_clone, tf_base, is_multi_view);
}
static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
@@ -3867,7 +3974,7 @@ static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
if (ps->tool == PAINT_TOOL_CLONE) {
float projCo[4];
copy_v3_v3(projCo, ED_view3d_cursor3d_get(ps->scene, ps->v3d));
- mul_m4_v3(ps->ob->imat, projCo);
+ mul_m4_v3(ps->obmat_imat, projCo);
projCo[3] = 1.0f;
mul_m4_v4(ps->projectMat, projCo);
@@ -3879,14 +3986,16 @@ static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
static void project_paint_end(ProjPaintState *ps)
{
int a;
- ProjPaintImage *projIma;
image_undo_remove_masks();
/* dereference used image buffers */
- for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
- BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL);
- DAG_id_tag_update(&projIma->ima->id, 0);
+ if (ps->is_shared_user == false) {
+ ProjPaintImage *projIma;
+ for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
+ BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL);
+ DAG_id_tag_update(&projIma->ima->id, 0);
+ }
}
BKE_image_release_ibuf(ps->reproject_image, ps->reproject_ibuf, NULL);
@@ -3895,68 +4004,81 @@ static void project_paint_end(ProjPaintState *ps)
MEM_freeN(ps->bucketRect);
MEM_freeN(ps->bucketFaces);
MEM_freeN(ps->bucketFlags);
- MEM_freeN(ps->dm_mtface);
- if (ps->do_layer_clone)
- MEM_freeN(ps->dm_mtface_clone);
- if (ps->thread_tot > 1) {
- BLI_spin_end(ps->tile_lock);
- MEM_freeN((void *)ps->tile_lock);
- }
- image_undo_end_locks();
+
+ if (ps->is_shared_user == false) {
+
+ /* must be set for non-shared */
+ BLI_assert(ps->dm_mtface || ps->is_shared_user);
+ if (ps->dm_mtface)
+ MEM_freeN(ps->dm_mtface);
+
+ if (ps->do_layer_clone)
+ MEM_freeN(ps->dm_mtface_clone);
+ if (ps->thread_tot > 1) {
+ BLI_spin_end(ps->tile_lock);
+ MEM_freeN((void *)ps->tile_lock);
+ }
+
+ image_undo_end_locks();
#ifndef PROJ_DEBUG_NOSEAMBLEED
- if (ps->seam_bleed_px > 0.0f) {
- MEM_freeN(ps->vertFaces);
- MEM_freeN(ps->faceSeamFlags);
- MEM_freeN(ps->faceWindingFlags);
- MEM_freeN(ps->faceSeamUVs);
- }
+ if (ps->seam_bleed_px > 0.0f) {
+ MEM_freeN(ps->vertFaces);
+ MEM_freeN(ps->faceSeamFlags);
+ MEM_freeN(ps->faceWindingFlags);
+ MEM_freeN(ps->faceSeamUVs);
+ }
+#endif
+
+ if (ps->do_mask_cavity) {
+ MEM_freeN(ps->cavities);
+ }
+
+ /* copy for subsurf/multires, so throw away */
+ if (ps->dm->type != DM_TYPE_CDDM) {
+ if (ps->dm_mvert) MEM_freeN(ps->dm_mvert);
+ if (ps->dm_mface) MEM_freeN(ps->dm_mface);
+ /* looks like these don't need copying */
+#if 0
+ if (ps->dm_mtface) MEM_freeN(ps->dm_mtface);
+ if (ps->dm_mtface_clone) MEM_freeN(ps->dm_mtface_clone);
+ if (ps->dm_mtface_stencil) MEM_freeN(ps->dm_mtface_stencil);
#endif
+ }
+
+ if (ps->dm_release)
+ ps->dm->release(ps->dm);
+ }
if (ps->blurkernel) {
paint_delete_blur_kernel(ps->blurkernel);
MEM_freeN(ps->blurkernel);
}
- if (ps->do_mask_cavity) {
- MEM_freeN(ps->cavities);
- }
-
if (ps->vertFlags) MEM_freeN(ps->vertFlags);
for (a = 0; a < ps->thread_tot; a++) {
BLI_memarena_free(ps->arena_mt[a]);
}
+}
- /* copy for subsurf/multires, so throw away */
- if (ps->dm->type != DM_TYPE_CDDM) {
- if (ps->dm_mvert) MEM_freeN(ps->dm_mvert);
- if (ps->dm_mface) MEM_freeN(ps->dm_mface);
- /* looks like these don't need copying */
-#if 0
- if (ps->dm_mtface) MEM_freeN(ps->dm_mtface);
- if (ps->dm_mtface_clone) MEM_freeN(ps->dm_mtface_clone);
- if (ps->dm_mtface_stencil) MEM_freeN(ps->dm_mtface_stencil);
-#endif
- }
+/* 1 = an undo, -1 is a redo. */
+static void partial_redraw_single_init(ImagePaintPartialRedraw *pr)
+{
+ pr->x1 = 10000000;
+ pr->y1 = 10000000;
- if (ps->dm_release)
- ps->dm->release(ps->dm);
+ pr->x2 = -1;
+ pr->y2 = -1;
+
+ pr->enabled = 1;
}
-/* 1 = an undo, -1 is a redo. */
static void partial_redraw_array_init(ImagePaintPartialRedraw *pr)
{
int tot = PROJ_BOUNDBOX_SQUARED;
while (tot--) {
- pr->x1 = 10000000;
- pr->y1 = 10000000;
-
- pr->x2 = -1;
- pr->y2 = -1;
-
- pr->enabled = 1;
-
+ partial_redraw_single_init(pr);
pr++;
}
}
@@ -4000,6 +4122,8 @@ static bool project_image_refresh_tagged(ProjPaintState *ps)
imapaint_image_update(NULL, projIma->ima, projIma->ibuf, true);
redraw = 1;
}
+
+ partial_redraw_single_init(pr);
}
projIma->touch = 0; /* clear for reuse */
@@ -4207,7 +4331,7 @@ static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, f
/* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
* colored speckles appearing in final image, and also to check for threshold */
- rgba[0] = rgba[1] = rgba[2] = rgb_to_grayscale(rgba);
+ rgba[0] = rgba[1] = rgba[2] = IMB_colormanagement_get_luminance(rgba);
if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
float alpha = projPixel->pixel.f_pt[3];
projPixel->pixel.f_pt[3] = rgba[3] = mask;
@@ -4268,7 +4392,7 @@ static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, flo
sub_v3_v3v3(rgba, rgba_pixel, rgba);
/* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
* colored speckles appearing in final image, and also to check for threshold */
- rgba[0] = rgba[1] = rgba[2] = rgb_to_grayscale(rgba);
+ rgba[0] = rgba[1] = rgba[2] = IMB_colormanagement_get_luminance(rgba);
if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
float alpha = rgba_pixel[3];
rgba[3] = rgba_pixel[3] = mask;
@@ -4414,7 +4538,8 @@ static void *do_projectpaint_thread(void *ph_v)
const float brush_radius = ps->brush_size;
const float brush_radius_sq = brush_radius * brush_radius; /* avoid a square root with every dist comparison */
- short lock_alpha = ELEM(brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ? 0 : brush->flag & BRUSH_LOCK_ALPHA;
+ const bool lock_alpha = ELEM(brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ?
+ 0 : (brush->flag & BRUSH_LOCK_ALPHA) != 0;
LinkNode *smearPixels = NULL;
LinkNode *smearPixels_f = NULL;
@@ -4440,8 +4565,13 @@ static void *do_projectpaint_thread(void *ph_v)
/* Check this bucket and its faces are initialized */
if (ps->bucketFlags[bucket_index] == PROJ_BUCKET_NULL) {
+ rctf clip_rect = bucket_bounds;
+ clip_rect.xmin -= PROJ_PIXEL_TOLERANCE;
+ clip_rect.xmax += PROJ_PIXEL_TOLERANCE;
+ clip_rect.ymin -= PROJ_PIXEL_TOLERANCE;
+ clip_rect.ymax += PROJ_PIXEL_TOLERANCE;
/* No pixels initialized */
- project_bucket_init(ps, thread_index, bucket_index, &bucket_bounds);
+ project_bucket_init(ps, thread_index, bucket_index, &clip_rect, &bucket_bounds);
}
if (ps->source != PROJ_SRC_VIEW) {
@@ -4531,8 +4661,17 @@ static void *do_projectpaint_thread(void *ph_v)
}
if (lock_alpha) {
- if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f_pt[3];
- else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
+ if (is_floatbuf) {
+ /* slightly more involved case since floats are in premultiplied space we need
+ * to make sure alpha is consistent, see T44627 */
+ float rgb_straight[4];
+ premul_to_straight_v4_v4(rgb_straight, projPixel->pixel.f_pt);
+ rgb_straight[3] = projPixel->origColor.f_pt[3];
+ straight_to_premul_v4_v4(projPixel->pixel.f_pt, rgb_straight);
+ }
+ else {
+ projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
+ }
}
last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
@@ -4697,11 +4836,20 @@ static void *do_projectpaint_thread(void *ph_v)
else do_projectpaint_draw(ps, projPixel, texrgb, mask, ps->dither, projPixel->x_px, projPixel->y_px);
break;
}
- }
- if (lock_alpha) {
- if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f_pt[3];
- else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
+ if (lock_alpha) {
+ if (is_floatbuf) {
+ /* slightly more involved case since floats are in premultiplied space we need
+ * to make sure alpha is consistent, see T44627 */
+ float rgb_straight[4];
+ premul_to_straight_v4_v4(rgb_straight, projPixel->pixel.f_pt);
+ rgb_straight[3] = projPixel->origColor.f_pt[3];
+ straight_to_premul_v4_v4(projPixel->pixel.f_pt, rgb_straight);
+ }
+ else {
+ projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
+ }
+ }
}
/* done painting */
@@ -4818,7 +4966,8 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
/* calculate pivot for rotation around seletion if needed */
if (U.uiflag & USER_ORBIT_SELECTION) {
float w[3];
- int side, index;
+ int index;
+ int side;
index = project_paint_PickFace(ps, pos, w, &side);
@@ -4837,7 +4986,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
}
ups->average_stroke_counter++;
- mul_m4_v3(ps->ob->obmat, world);
+ mul_m4_v3(ps->obmat, world);
add_v3_v3(ups->average_stroke_accum, world);
ups->last_stroke_valid = true;
}
@@ -4847,33 +4996,21 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
}
-void paint_proj_stroke(const bContext *C, void *pps, const float prev_pos[2], const float pos[2], const bool eraser, float pressure, float distance, float size)
+static void paint_proj_stroke_ps(
+ const bContext *UNUSED(C), void *ps_handle_p, const float prev_pos[2], const float pos[2],
+ const bool eraser, float pressure, float distance, float size,
+ /* extra view */
+ ProjPaintState *ps
+ )
{
- ProjPaintState *ps = pps;
+ ProjStrokeHandle *ps_handle = ps_handle_p;
Brush *brush = ps->brush;
Scene *scene = ps->scene;
- int a;
ps->brush_size = size;
ps->blend = brush->blend;
if (eraser)
ps->blend = IMB_BLEND_ERASE_ALPHA;
-
- /* clone gets special treatment here to avoid going through image initialization */
- if (ps->tool == PAINT_TOOL_CLONE && ps->mode == BRUSH_STROKE_INVERT) {
- View3D *v3d = ps->v3d;
- float *cursor = ED_view3d_cursor3d_get(scene, v3d);
- int mval_i[2] = {(int)pos[0], (int)pos[1]};
-
- view3d_operator_needs_opengl(C);
-
- if (!ED_view3d_autodist(scene, ps->ar, v3d, mval_i, cursor, false, NULL))
- return;
-
- ED_region_tag_redraw(ps->ar);
-
- return;
- }
/* handle gradient and inverted stroke color here */
if (ps->tool == PAINT_TOOL_DRAW) {
@@ -4894,14 +5031,42 @@ void paint_proj_stroke(const bContext *C, void *pps, const float prev_pos[2], co
}
}
- /* continue adding to existing partial redraw rects until redraw */
- if (!ps->need_redraw) {
- for (a = 0; a < ps->image_tot; a++)
- partial_redraw_array_init(ps->projImages[a].partRedrawRect);
+ if (project_paint_op(ps, prev_pos, pos)) {
+ ps_handle->need_redraw = true;
+ project_image_refresh_tagged(ps);
}
+}
+
+
+void paint_proj_stroke(
+ const bContext *C, void *ps_handle_p, const float prev_pos[2], const float pos[2],
+ const bool eraser, float pressure, float distance, float size)
+{
+ int i;
+ ProjStrokeHandle *ps_handle = ps_handle_p;
+
+ /* clone gets special treatment here to avoid going through image initialization */
+ if (ps_handle->is_clone_cursor_pick) {
+ Scene *scene = ps_handle->scene;
+ View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+ float *cursor = ED_view3d_cursor3d_get(scene, v3d);
+ int mval_i[2] = {(int)pos[0], (int)pos[1]};
- if (project_paint_op(ps, prev_pos, pos))
- ps->need_redraw = true;
+ view3d_operator_needs_opengl(C);
+
+ if (!ED_view3d_autodist(scene, ar, v3d, mval_i, cursor, false, NULL))
+ return;
+
+ ED_region_tag_redraw(ar);
+
+ return;
+ }
+
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = ps_handle->ps_views[i];
+ paint_proj_stroke_ps(C, ps_handle_p, prev_pos, pos, eraser, pressure, distance, size, ps);
+ }
}
@@ -4920,7 +5085,7 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
ps->blend = brush->blend;
/* only check for inversion for the soften tool, elsewhere, a resident brush inversion flag can cause issues */
if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) {
- ps->mode = ((ps->mode == BRUSH_STROKE_INVERT) ^ ((brush->flag & BRUSH_DIR_IN) != 0) ?
+ ps->mode = (((ps->mode == BRUSH_STROKE_INVERT) ^ ((brush->flag & BRUSH_DIR_IN) != 0)) ?
BRUSH_STROKE_INVERT : BRUSH_STROKE_NORMAL);
ps->blurkernel = paint_new_blur_kernel(brush, true);
@@ -5001,6 +5166,9 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
if (ps->normal_angle_range <= 0.0f)
ps->do_mask_normal = false; /* no need to do blending */
+ ps->normal_angle__cos = cosf(ps->normal_angle);
+ ps->normal_angle_inner__cos = cosf(ps->normal_angle_inner);
+
ps->dither = settings->imapaint.dither;
return;
@@ -5008,51 +5176,116 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int mode)
{
- ProjPaintState *ps = MEM_callocN(sizeof(ProjPaintState), "ProjectionPaintState");
+ ProjStrokeHandle *ps_handle;
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *settings = scene->toolsettings;
+ int i;
+ bool is_multi_view;
+ char symmetry_flag_views[ARRAY_SIZE(ps_handle->ps_views)] = {0};
- project_state_init(C, ob, ps, mode);
+ ps_handle = MEM_callocN(sizeof(ProjStrokeHandle), "ProjStrokeHandle");
+ ps_handle->scene = scene;
+ ps_handle->brush = BKE_paint_brush(&settings->imapaint.paint);
- if (ps->tool == PAINT_TOOL_CLONE && mode == BRUSH_STROKE_INVERT) {
+ /* bypass regular stroke logic */
+ if ((ps_handle->brush->imagepaint_tool == PAINT_TOOL_CLONE) &&
+ (mode == BRUSH_STROKE_INVERT))
+ {
view3d_operator_needs_opengl(C);
- return ps;
+ ps_handle->is_clone_cursor_pick = true;
+ return ps_handle;
}
- paint_brush_init_tex(ps->brush);
+ ps_handle->orig_brush_size = BKE_brush_size_get(scene, ps_handle->brush);
- ps->source = (ps->tool == PAINT_TOOL_FILL) ? PROJ_SRC_VIEW_FILL : PROJ_SRC_VIEW;
+ ps_handle->symmetry_flags = settings->imapaint.paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ ps_handle->ps_views_tot = 1 + (pow_i(2, count_bits_i(ps_handle->symmetry_flags)) - 1);
+ is_multi_view = (ps_handle->ps_views_tot != 1);
- if (ps->ob == NULL || !(ps->ob->lay & ps->v3d->lay)) {
- MEM_freeN(ps);
- return NULL;
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = MEM_callocN(sizeof(ProjPaintState), "ProjectionPaintState");
+ ps_handle->ps_views[i] = ps;
+ }
+
+ if (ps_handle->symmetry_flags) {
+ int index = 0;
+
+ int x = 0;
+ do {
+ int y = 0;
+ do {
+ int z = 0;
+ do {
+ symmetry_flag_views[index++] = (
+ (x ? PAINT_SYMM_X : 0) |
+ (y ? PAINT_SYMM_Y : 0) |
+ (z ? PAINT_SYMM_Z : 0));
+ BLI_assert(index <= ps_handle->ps_views_tot);
+ } while ((z++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_Z));
+ } while ((y++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_Y));
+ } while ((x++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_X));
+ BLI_assert(index == ps_handle->ps_views_tot);
}
- ps->orig_brush_size = BKE_brush_size_get(ps->scene, ps->brush);
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = ps_handle->ps_views[i];
+
+ project_state_init(C, ob, ps, mode);
+
+ if (ps->ob == NULL || !(ps->ob->lay & ps->v3d->lay)) {
+ ps_handle->ps_views_tot = i + 1;
+ goto fail;
+ }
+ }
/* Don't allow brush size below 2 */
- if (BKE_brush_size_get(ps->scene, ps->brush) < 2)
- BKE_brush_size_set(ps->scene, ps->brush, 2 * U.pixelsize);
+ if (BKE_brush_size_get(scene, ps_handle->brush) < 2)
+ BKE_brush_size_set(scene, ps_handle->brush, 2 * U.pixelsize);
/* allocate and initialize spatial data structures */
- project_paint_begin(ps);
- if (ps->dm == NULL) {
- MEM_freeN(ps);
- return NULL;
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = ps_handle->ps_views[i];
+
+ ps->source = (ps->tool == PAINT_TOOL_FILL) ? PROJ_SRC_VIEW_FILL : PROJ_SRC_VIEW;
+ project_image_refresh_tagged(ps);
+
+ /* re-use! */
+ if (i != 0) {
+ ps->is_shared_user = true;
+ PROJ_PAINT_STATE_SHARED_MEMCPY(ps, ps_handle->ps_views[0]);
+ }
+
+ project_paint_begin(ps, is_multi_view, symmetry_flag_views[i]);
+
+ paint_proj_begin_clone(ps, mouse);
+
+ if (ps->dm == NULL) {
+ goto fail;
+ return NULL;
+ }
}
- paint_proj_begin_clone(ps, mouse);
+ paint_brush_init_tex(ps_handle->brush);
+
+ return ps_handle;
+
- return ps;
+fail:
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps = ps_handle->ps_views[i];
+ MEM_freeN(ps);
+ }
+ MEM_freeN(ps_handle);
+ return NULL;
}
-void paint_proj_redraw(const bContext *C, void *pps, bool final)
+void paint_proj_redraw(const bContext *C, void *ps_handle_p, bool final)
{
- ProjPaintState *ps = pps;
-
- if (ps->need_redraw) {
- project_image_refresh_tagged(ps);
+ ProjStrokeHandle *ps_handle = ps_handle_p;
- ps->need_redraw = false;
+ if (ps_handle->need_redraw) {
+ ps_handle->need_redraw = false;
}
else if (!final) {
return;
@@ -5067,19 +5300,34 @@ void paint_proj_redraw(const bContext *C, void *pps, bool final)
}
}
-void paint_proj_stroke_done(void *pps)
+void paint_proj_stroke_done(void *ps_handle_p)
{
- ProjPaintState *ps = pps;
- if (ps->tool == PAINT_TOOL_CLONE && ps->mode == BRUSH_STROKE_INVERT) {
- MEM_freeN(ps);
+ ProjStrokeHandle *ps_handle = ps_handle_p;
+ Scene *scene = ps_handle->scene;
+ int i;
+
+ if (ps_handle->is_clone_cursor_pick) {
+ MEM_freeN(ps_handle);
return;
}
- BKE_brush_size_set(ps->scene, ps->brush, ps->orig_brush_size);
- paint_brush_exit_tex(ps->brush);
+ for (i = 1; i < ps_handle->ps_views_tot; i++) {
+ PROJ_PAINT_STATE_SHARED_CLEAR(ps_handle->ps_views[i]);
+ }
+
+ BKE_brush_size_set(scene, ps_handle->brush, ps_handle->orig_brush_size);
+
+ paint_brush_exit_tex(ps_handle->brush);
+
+ for (i = 0; i < ps_handle->ps_views_tot; i++) {
+ ProjPaintState *ps;
+ ps = ps_handle->ps_views[i];
+ project_paint_end(ps);
+ MEM_freeN(ps);
+
+ }
- project_paint_end(ps);
- MEM_freeN(ps);
+ MEM_freeN(ps_handle);
}
/* use project paint to re-apply an image */
static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
@@ -5159,7 +5407,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
ED_image_undo_restore, ED_image_undo_free, NULL);
/* allocate and initialize spatial data structures */
- project_paint_begin(&ps);
+ project_paint_begin(&ps, false, 0);
if (ps.dm == NULL) {
BKE_brush_size_set(scene, ps.brush, orig_brush_size);
@@ -5233,7 +5481,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
if (w > maxsize) w = maxsize;
if (h > maxsize) h = maxsize;
- ibuf = ED_view3d_draw_offscreen_imbuf(scene, CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, false, R_ALPHAPREMUL, err_out);
+ ibuf = ED_view3d_draw_offscreen_imbuf(scene, CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, false, R_ALPHAPREMUL, NULL, err_out);
if (!ibuf) {
/* Mostly happens when OpenGL offscreen buffer was failed to create, */
/* but could be other reasons. Should be handled in the future. nazgul */
@@ -5241,7 +5489,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- image = BKE_image_add_from_imbuf(ibuf);
+ image = BKE_image_add_from_imbuf(ibuf, "image_view");
/* Drop reference to ibuf so that the image owns it */
IMB_freeImBuf(ibuf);
@@ -5271,8 +5519,6 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
array[2] = is_ortho ? 1.0f : 0.0f;
IDP_AddToGroup(idgroup, view_data);
-
- rename_id(&image->id, "image_view");
}
return OPERATOR_FINISHED;
@@ -5444,7 +5690,7 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain)
RNA_string_get(op->ptr, "name", imagename);
}
ima = BKE_image_add_generated(bmain, width, height, imagename, alpha ? 32 : 24, use_float,
- gen_type, color);
+ gen_type, color, false);
return ima;
}
@@ -5487,7 +5733,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
ntreeUpdateTree(CTX_data_main(C), ntree);
}
else {
- MTex *mtex = add_mtex_id(&ma->id, -1);
+ MTex *mtex = BKE_texture_mtex_add_id(&ma->id, -1);
/* successful creation of mtex layer, now create set */
if (mtex) {
@@ -5506,7 +5752,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
}
}
- mtex->tex = add_texture(bmain, DATA_(layer_type_items[type_id].name));
+ mtex->tex = BKE_texture_add(bmain, DATA_(layer_type_items[type_id].name));
mtex->mapto = type;
if (mtex->tex) {
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 9e558092f73..fd7e053fea3 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -34,14 +34,11 @@
struct ARegion;
struct bContext;
-struct bglMats;
struct Brush;
struct ImagePool;
struct ColorSpace;
struct ColorManagedDisplay;
struct ListBase;
-struct Material;
-struct Mesh;
struct MTex;
struct Object;
struct PaintStroke;
@@ -55,7 +52,6 @@ struct ViewContext;
struct wmEvent;
struct wmOperator;
struct wmOperatorType;
-struct ImagePaintState;
struct wmWindowManager;
struct DMCoNo;
enum PaintMode;
@@ -149,7 +145,7 @@ typedef struct ImagePaintPartialRedraw {
int image_texture_paint_poll(struct bContext *C);
void *image_undo_find_tile(struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate);
-void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **, bool **valid, bool proj);
+void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **, bool **valid, bool proj, bool find_prev);
void image_undo_remove_masks(void);
void image_undo_init_locks(void);
void image_undo_end_locks(void);
@@ -164,7 +160,7 @@ void paint_2d_redraw(const bContext *C, void *ps, bool final);
void paint_2d_stroke_done(void *ps);
void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], const bool eraser, float pressure, float distance, float size);
void paint_2d_bucket_fill(const struct bContext *C, const float color[3], struct Brush *br, const float mouse_init[2], void *ps);
-void paint_2d_gradient_fill (const struct bContext *C, struct Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps);
+void paint_2d_gradient_fill(const struct bContext *C, struct Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps);
void *paint_proj_new_stroke(struct bContext *C, struct Object *ob, const float mouse[2], int mode);
void paint_proj_stroke(const struct bContext *C, void *ps, const float prevmval_i[2], const float mval_i[2], const bool eraser, float pressure, float distance, float size);
void paint_proj_redraw(const struct bContext *C, void *pps, bool final);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 121b0b83a4b..b95951a4d7a 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -44,6 +44,7 @@
#include "ED_screen.h"
#include "ED_image.h"
#include "UI_resources.h"
+#include "UI_interface.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -60,19 +61,39 @@
#include <stddef.h>
/* Brush operators */
+
static int brush_add_exec(bContext *C, wmOperator *UNUSED(op))
{
/*int type = RNA_enum_get(op->ptr, "type");*/
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *br = BKE_paint_brush(paint);
Main *bmain = CTX_data_main(C);
-
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ Paint *paint = NULL;
+ HairEditSettings *hair_edit = NULL;
+ Brush *br = NULL;
+
+ /* get active brush context */
+ if (ob->mode == OB_MODE_HAIR_EDIT) {
+ hair_edit = &scene->toolsettings->hair_edit;
+ br = hair_edit->brush;
+ }
+ else {
+ paint = BKE_paint_get_active_from_context(C);
+ br = BKE_paint_brush(paint);
+ }
+
if (br)
br = BKE_brush_copy(br);
else
br = BKE_brush_add(bmain, "Brush");
- BKE_paint_brush_set(paint, br);
+ /* set new brush pointer in the context */
+ if (ob->mode == OB_MODE_HAIR_EDIT) {
+ hair_edit->brush = br;
+ }
+ else {
+ BKE_paint_brush_set(paint, br);
+ }
return OPERATOR_FINISHED;
}
@@ -95,11 +116,20 @@ static void BRUSH_OT_add(wmOperatorType *ot)
static int brush_scale_size_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *brush = BKE_paint_brush(paint);
- // Object *ob = CTX_data_active_object(C);
+ Object *ob = CTX_data_active_object(C);
+ Brush *brush;
float scalar = RNA_float_get(op->ptr, "scalar");
+ /* get active brush context */
+ if (ob->mode == OB_MODE_HAIR_EDIT) {
+ HairEditSettings *hair_edit = &scene->toolsettings->hair_edit;
+ brush = hair_edit->brush;
+ }
+ else {
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ brush = BKE_paint_brush(paint);
+ }
+
if (brush) {
// pixel radius
{
@@ -196,7 +226,10 @@ static int palette_color_add_exec(bContext *C, wmOperator *UNUSED(op))
Brush *brush = paint->brush;
PaintMode mode = BKE_paintmode_get_active_from_context(C);
Palette *palette = paint->palette;
- PaletteColor *color = BKE_palette_color_add(palette);
+ PaletteColor *color;
+
+ color = BKE_palette_color_add(palette);
+ palette->active_color = BLI_listbase_count(&palette->colors) - 1;
if (ELEM(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX)) {
copy_v3_v3(color->rgb, BKE_brush_color_get(scene, brush));
@@ -231,7 +264,9 @@ static int palette_color_delete_exec(bContext *C, wmOperator *UNUSED(op))
Palette *palette = paint->palette;
PaletteColor *color = BLI_findlink(&palette->colors, palette->active_color);
- BKE_palette_color_remove(palette, color);
+ if (color) {
+ BKE_palette_color_remove(palette, color);
+ }
return OPERATOR_FINISHED;
}
@@ -462,7 +497,7 @@ static int brush_select_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
if (ob) {
/* select current paint mode */
- paint_mode = ob->mode & OB_MODE_ALL_PAINT;
+ paint_mode = ob->mode & OB_MODE_ALL_BRUSH;
}
else {
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index bfd429d0924..21beb97ffae 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -68,7 +68,7 @@
#include <float.h>
#include <math.h>
-// #define DEBUG_TIME
+#define DEBUG_TIME
#ifdef DEBUG_TIME
# include "PIL_time_utildefines.h"
@@ -347,7 +347,8 @@ static bool paint_brush_update(bContext *C,
if (!stroke->brush_init) {
copy_v2_v2(ups->last_rake, mouse_init);
}
- else {
+ /* curve strokes do their own rake calculation */
+ else if (!(brush->flag & BRUSH_CURVE)) {
paint_calculate_rake_rotation(ups, brush, mouse_init);
}
}
@@ -671,9 +672,8 @@ PaintStroke *paint_stroke_new(bContext *C,
get_imapaint_zoom(C, &zoomx, &zoomy);
stroke->zoom_2d = max_ff(zoomx, zoomy);
- if (stroke->stroke_mode == BRUSH_STROKE_INVERT)
- {
- if (br->flag & (BRUSH_CURVE | BRUSH_LINE)) {
+ if (stroke->stroke_mode == BRUSH_STROKE_INVERT) {
+ if (br->flag & (BRUSH_CURVE)) {
RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL);
}
}
@@ -955,6 +955,7 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
Brush *br = stroke->brush;
if (br->flag & BRUSH_CURVE) {
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
const Scene *scene = CTX_data_scene(C);
const float spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
PaintCurve *pc = br->paint_curve;
@@ -975,18 +976,39 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
for (i = 0; i < pc->tot_points - 1; i++, pcp++) {
int j;
float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
+ float tangents[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
PaintCurvePoint *pcp_next = pcp + 1;
+ bool do_rake = false;
- for (j = 0; j < 2; j++)
+ for (j = 0; j < 2; j++) {
BKE_curve_forward_diff_bezier(
pcp->bez.vec[1][j],
pcp->bez.vec[2][j],
pcp_next->bez.vec[0][j],
pcp_next->bez.vec[1][j],
data + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
+ }
+ if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) ||
+ (br->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE))
+ {
+ do_rake = true;
+ for (j = 0; j < 2; j++) {
+ BKE_curve_forward_diff_tangent_bezier(
+ pcp->bez.vec[1][j],
+ pcp->bez.vec[2][j],
+ pcp_next->bez.vec[0][j],
+ pcp_next->bez.vec[1][j],
+ tangents + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
+ }
+ }
for (j = 0; j < PAINT_CURVE_NUM_SEGMENTS; j++) {
+ if (do_rake) {
+ float rotation = atan2f(tangents[2 * j], tangents[2 * j + 1]);
+ paint_update_brush_rake_rotation(ups, br, rotation);
+ }
+
if (!stroke->stroke_started) {
stroke->last_pressure = 1.0;
copy_v2_v2(stroke->last_mouse_position, data + 2 * j);
@@ -1015,14 +1037,14 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
return false;
}
-static void paint_stroke_line_constrain (PaintStroke *stroke, float mouse[2])
+static void paint_stroke_line_constrain(PaintStroke *stroke, float mouse[2])
{
if (stroke->constrain_line) {
float line[2];
float angle, len, res;
sub_v2_v2v2(line, mouse, stroke->last_mouse_position);
- angle = atan2(line[1], line[0]);
+ angle = atan2f(line[1], line[0]);
len = len_v2(line);
/* divide angle by PI/4 */
@@ -1129,7 +1151,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_FINISHED;
}
else if (br->flag & BRUSH_LINE) {
- if (event->ctrl)
+ if (event->alt)
stroke->constrain_line = true;
else
stroke->constrain_line = false;
@@ -1137,8 +1159,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
paint_stroke_line_constrain(stroke, mouse);
- if (stroke->stroke_started && (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))))
- {
+ if (stroke->stroke_started && (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)))) {
if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position);
}
diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c
index 0293a0bfc00..42f0aaab173 100644
--- a/source/blender/editors/sculpt_paint/paint_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_undo.c
@@ -331,32 +331,33 @@ void ED_undo_paint_step_num(bContext *C, int type, int step)
undo_step_num(C, &MeshUndoStack, step);
}
-static char *undo_stack_get_name(UndoStack *stack, int nr, int *active)
+static char *undo_stack_get_name(UndoStack *stack, int nr, bool *r_active)
{
UndoElem *uel;
- if (active) *active = 0;
+ if (r_active) *r_active = false;
uel = BLI_findlink(&stack->elems, nr);
if (uel) {
- if (active && uel == stack->current)
- *active = 1;
+ if (r_active && (uel == stack->current)) {
+ *r_active = true;
+ }
return uel->name;
}
return NULL;
}
-const char *ED_undo_paint_get_name(bContext *C, int type, int nr, int *active)
+const char *ED_undo_paint_get_name(bContext *C, int type, int nr, bool *r_active)
{
if (type == UNDO_PAINT_IMAGE) {
undo_stack_cleanup(&ImageUndoStack, C);
- return undo_stack_get_name(&ImageUndoStack, nr, active);
+ return undo_stack_get_name(&ImageUndoStack, nr, r_active);
}
else if (type == UNDO_PAINT_MESH) {
undo_stack_cleanup(&MeshUndoStack, C);
- return undo_stack_get_name(&MeshUndoStack, nr, active);
+ return undo_stack_get_name(&MeshUndoStack, nr, r_active);
}
return NULL;
}
@@ -379,7 +380,7 @@ bool ED_undo_paint_empty(int type)
return false;
}
-int ED_undo_paint_valid(int type, const char *name)
+bool ED_undo_paint_is_valid(int type, const char *name)
{
UndoStack *stack;
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index c0ed5005397..bdf11de0f87 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -379,7 +379,7 @@ static int imapaint_pick_face(ViewContext *vc, const int mval[2], unsigned int *
return 0;
/* sample only on the exact position */
- *r_index = view3d_sample_backbuf(vc, mval[0], mval[1]);
+ *r_index = ED_view3d_backbuf_sample(vc, mval[0], mval[1]);
if ((*r_index) == 0 || (*r_index) > (unsigned int)totpoly) {
return 0;
@@ -439,6 +439,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
}
color = BKE_palette_color_add(palette);
+ palette->active_color = BLI_listbase_count(&palette->colors) - 1;
}
@@ -486,12 +487,15 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
if (u < 0.0f) u += 1.0f;
if (v < 0.0f) v += 1.0f;
- u = u * ibuf->x - 0.5f;
- v = v * ibuf->y - 0.5f;
+ u = u * ibuf->x;
+ v = v * ibuf->y;
if (ibuf->rect_float) {
float rgba_f[4];
- bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
+ if (U.gameflags & USER_DISABLE_MIPMAP)
+ nearest_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
+ else
+ bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
straight_to_premul_v4(rgba_f);
if (use_palette) {
linearrgb_to_srgb_v3_v3(color->rgb, rgba_f);
@@ -503,7 +507,10 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
}
else {
unsigned char rgba[4];
- bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
+ if (U.gameflags & USER_DISABLE_MIPMAP)
+ nearest_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
+ else
+ bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
if (use_palette) {
rgb_uchar_to_float(color->rgb, rgba);
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index e87dd6c2810..1a31442faf4 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -37,6 +37,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "IMB_colormanagement.h"
#include "DNA_armature_types.h"
#include "DNA_mesh_types.h"
@@ -208,7 +209,7 @@ static void do_shared_vertex_tesscol(Mesh *me, bool *mfacetag)
{
/* if no mcol: do not do */
/* if tface: only the involved faces, otherwise all */
- const int use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL);
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
MFace *mface;
int a;
short *scolmain, *scol;
@@ -279,7 +280,7 @@ static void do_shared_vertex_tesscol(Mesh *me, bool *mfacetag)
static void do_shared_vertexcol(Mesh *me, bool *mlooptag, bool *mfacetag, const bool do_tessface)
{
- const int use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL);
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
MPoly *mp;
int (*scol)[4];
int i, j;
@@ -768,7 +769,7 @@ BLI_INLINE unsigned int mcol_lighten(unsigned int col1, unsigned int col2, int f
/* See if are lighter, if so mix, else don't do anything.
* if the paint col is darker then the original, then ignore */
- if (rgb_to_grayscale_byte(cp1) > rgb_to_grayscale_byte(cp2)) {
+ if (IMB_colormanagement_get_luminance_byte(cp1) > IMB_colormanagement_get_luminance_byte(cp2)) {
return col1;
}
@@ -801,7 +802,7 @@ BLI_INLINE unsigned int mcol_darken(unsigned int col1, unsigned int col2, int fa
/* See if were darker, if so mix, else don't do anything.
* if the paint col is brighter then the original, then ignore */
- if (rgb_to_grayscale_byte(cp1) < rgb_to_grayscale_byte(cp2)) {
+ if (IMB_colormanagement_get_luminance_byte(cp1) < IMB_colormanagement_get_luminance_byte(cp2)) {
return col1;
}
@@ -877,7 +878,7 @@ static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x
* brushes with size > 64, why is this here? */
/*if (size > 64.0) size = 64.0;*/
- ibuf = view3d_read_backbuf(vc, x - size, y - size, x + size, y + size);
+ ibuf = ED_view3d_backbuf_read(vc, x - size, y - size, x + size, y + size);
if (ibuf) {
unsigned int *rt = ibuf->rect;
@@ -1090,7 +1091,7 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *even
me = BKE_mesh_from_object(vc.obact);
if (me && me->dvert && vc.v3d && vc.rv3d) {
- const int use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
int v_idx_best = -1;
unsigned int index;
@@ -1176,7 +1177,7 @@ static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA
if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) {
const int defbase_tot = BLI_listbase_count(&vc.obact->defbase);
- const int use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
int *groups = MEM_callocN(defbase_tot * sizeof(int), "groups");
bool found = false;
unsigned int index;
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_proj.c b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
index ae729248f7e..c939eb6df35 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
@@ -186,7 +186,7 @@ static void vpaint_proj_dm_map_cosnos_update(struct VertProjHandle *vp_handle,
/* highly unlikely this will become unavailable once painting starts (perhaps with animated modifiers) */
if (LIKELY(dm->foreachMappedVert)) {
- fill_vn_fl(vp_handle->dists_sq, me->totvert, FLT_MAX);
+ copy_vn_fl(vp_handle->dists_sq, me->totvert, FLT_MAX);
dm->foreachMappedVert(dm, vpaint_proj_dm_map_cosnos_update__map_cb, &vp_update, DM_FOREACH_USE_NORMAL);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index c0925eeca39..ede90b6e1f1 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -56,6 +56,7 @@
#include "BKE_ccg.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_library.h"
@@ -115,6 +116,13 @@ static int system_physical_thread_count(void)
}
#endif /* __APPLE__ */
+/** \name Tool Capabilities
+ *
+ * Avoid duplicate checks, internal logic only,
+ * share logic with #rna_def_sculpt_capabilities where possible.
+ *
+ * \{ */
+
/* Check if there are any active modifiers in stack (used for flushing updates at enter/exit sculpt mode) */
static bool sculpt_has_active_modifiers(Scene *scene, Object *ob)
{
@@ -132,6 +140,43 @@ static bool sculpt_has_active_modifiers(Scene *scene, Object *ob)
return 0;
}
+static bool sculpt_tool_needs_original(const char sculpt_tool)
+{
+ return ELEM(sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_LAYER);
+}
+
+static bool sculpt_tool_is_proxy_used(const char sculpt_tool)
+{
+ return ELEM(sculpt_tool,
+ SCULPT_TOOL_SMOOTH,
+ SCULPT_TOOL_LAYER);
+}
+
+/**
+ * Test whether the #StrokeCache.sculpt_normal needs update in #do_brush_action
+ */
+static int sculpt_brush_needs_normal(const Brush *brush)
+{
+ return ((SCULPT_TOOL_HAS_NORMAL_WEIGHT(brush->sculpt_tool) &&
+ (brush->normal_weight > 0)) ||
+
+ ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_BLOB,
+ SCULPT_TOOL_CREASE,
+ SCULPT_TOOL_DRAW,
+ SCULPT_TOOL_LAYER,
+ SCULPT_TOOL_NUDGE,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB) ||
+
+ (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA));
+}
+
+/** \} */
typedef enum StrokeFlags {
@@ -181,8 +226,6 @@ typedef struct StrokeCache {
ViewContext *vc;
Brush *brush;
- float (*face_norms)[3]; /* Copy of the mesh faces' normals */
-
float special_rotation;
float grab_delta[3], grab_delta_symmetry[3];
float old_grab_location[3], orig_grab_location[3];
@@ -284,30 +327,70 @@ static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data,
PBVHVertexIter *iter)
{
if (orig_data->unode->type == SCULPT_UNDO_COORDS) {
- if (orig_data->coords) {
- orig_data->co = orig_data->coords[iter->i];
+ if (orig_data->bm_log) {
+ BM_log_original_vert_data(
+ orig_data->bm_log, iter->bm_vert,
+ &orig_data->co, &orig_data->no);
}
else {
- orig_data->co = BM_log_original_vert_co(orig_data->bm_log, iter->bm_vert);
- }
-
- if (orig_data->normals) {
+ orig_data->co = orig_data->coords[iter->i];
orig_data->no = orig_data->normals[iter->i];
}
- else {
- orig_data->no = BM_log_original_vert_no(orig_data->bm_log, iter->bm_vert);
- }
}
else if (orig_data->unode->type == SCULPT_UNDO_MASK) {
- if (orig_data->vmasks) {
- orig_data->mask = orig_data->vmasks[iter->i];
+ if (orig_data->bm_log) {
+ orig_data->mask = BM_log_original_mask(orig_data->bm_log, iter->bm_vert);
}
else {
- orig_data->mask = BM_log_original_mask(orig_data->bm_log, iter->bm_vert);
+ orig_data->mask = orig_data->vmasks[iter->i];
}
}
}
+/** \name SculptProjectVector
+ *
+ * Fast-path for #project_plane_v3_v3v3
+ *
+ * \{ */
+
+typedef struct SculptProjectVector {
+ float plane[3];
+ float len_sq;
+ float len_sq_inv_neg;
+ bool is_valid;
+
+} SculptProjectVector;
+
+/**
+ * \param plane Direction, can be any length.
+ */
+static void sculpt_project_v3_cache_init(
+ SculptProjectVector *spvc, const float plane[3])
+{
+ copy_v3_v3(spvc->plane, plane);
+ spvc->len_sq = len_squared_v3(spvc->plane);
+ spvc->is_valid = (spvc->len_sq > FLT_EPSILON);
+ spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f;
+}
+
+/**
+ * Calculate the projection.
+ */
+static void sculpt_project_v3(
+ const SculptProjectVector *spvc, const float vec[3],
+ float r_vec[3])
+{
+#if 0
+ project_plane_v3_v3v3(r_vec, vec, spvc->plane);
+#else
+ /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */
+ madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg);
+#endif
+}
+
+/** \} */
+
+
/**********************************************************************/
/* Returns true if the stroke will use dynamic topology, false
@@ -316,8 +399,8 @@ static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data,
* Factors: some brushes like grab cannot do dynamic topology.
* Others, like smooth, are better without. Same goes for alt-
* key smoothing. */
-static int sculpt_stroke_dynamic_topology(const SculptSession *ss,
- const Brush *brush)
+static bool sculpt_stroke_is_dynamic_topology(
+ const SculptSession *ss, const Brush *brush)
{
return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
@@ -327,20 +410,8 @@ static int sculpt_stroke_dynamic_topology(const SculptSession *ss,
* dynamic-topology */
!(brush->flag & BRUSH_ANCHORED) &&
!(brush->flag & BRUSH_DRAG_DOT) &&
-
- (!ELEM(brush->sculpt_tool,
- /* These brushes, as currently coded, cannot
- * support dynamic topology */
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER,
-
- /* These brushes could handle dynamic topology,
- * but user feedback indicates it's better not
- * to */
- SCULPT_TOOL_SMOOTH,
- SCULPT_TOOL_MASK)));
+
+ SCULPT_TOOL_HAS_DYNTOPO(brush->sculpt_tool));
}
/*** paint mesh ***/
@@ -348,17 +419,11 @@ static int sculpt_stroke_dynamic_topology(const SculptSession *ss,
static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
{
SculptSession *ss = ob->sculpt;
- StrokeCache *cache = ss->cache;
const Brush *brush = BKE_paint_brush(&sd->paint);
- int i;
PBVHNode **nodes;
int n, totnode;
-#ifndef _OPENMP
- (void)sd; /* quied unused warning */
-#endif
-
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
/* Disable OpenMP when dynamic-topology is enabled. Otherwise, new
@@ -403,12 +468,6 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
}
}
- if (ss->face_normals) {
- for (i = 0; i < ss->totpoly; i++) {
- copy_v3_v3(ss->face_normals[i], cache->face_norms[i]);
- }
- }
-
if (nodes)
MEM_freeN(nodes);
}
@@ -508,7 +567,7 @@ static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
}
}
-BLI_INLINE bool sculpt_brush_test_clipping(SculptBrushTest *test, const float co[3])
+BLI_INLINE bool sculpt_brush_test_clipping(const SculptBrushTest *test, const float co[3])
{
RegionView3D *rv3d = test->clip_rv3d;
return (rv3d && (ED_view3d_clipping_test(rv3d, co, true)));
@@ -546,7 +605,7 @@ static bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3])
}
}
-static bool sculpt_brush_test_fast(SculptBrushTest *test, float co[3])
+static bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3])
{
if (sculpt_brush_test_clipping(test, co)) {
return 0;
@@ -554,7 +613,7 @@ static bool sculpt_brush_test_fast(SculptBrushTest *test, float co[3])
return len_squared_v3v3(co, test->location) <= test->radius_squared;
}
-static bool sculpt_brush_test_cube(SculptBrushTest *test, float co[3], float local[4][4])
+static bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4])
{
float side = M_SQRT1_2;
float local_co[3];
@@ -607,7 +666,7 @@ static float frontface(Brush *br, const float sculpt_normal[3],
#if 0
-static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float location[3], float an[3])
+static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float location[3], const float area_no[3])
{
if (sculpt_brush_test_fast(test, co)) {
float t1[3], t2[3], t3[3], dist;
@@ -615,7 +674,7 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float loca
sub_v3_v3v3(t1, location, co);
sub_v3_v3v3(t2, x2, location);
- cross_v3_v3v3(t3, an, t1);
+ cross_v3_v3v3(t3, area_no, t1);
dist = len_v3(t3) / len_v3(t2);
@@ -701,18 +760,447 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
}
}
+/** \name Calculate Normal and Center
+ *
+ * Calculate geometry surrounding the brush center.
+ * (optionally using original coordinates).
+ *
+ * Functions are:
+ * - #calc_area_center
+ * - #calc_area_normal
+ * - #calc_area_normal_and_center
+ *
+ * \note These are all _very_ similar, when changing one, check others.
+ * \{ */
+
+static void calc_area_center(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_co[3])
+{
+ const Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
+ int n;
+
+ /* 0=towards view, 1=flipped */
+ float area_co[2][3] = {{0.0f}};
+
+ int count[2] = {0};
+
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
+ for (n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptUndoNode *unode;
+ float private_co[2][3] = {{0.0f}};
+ int private_count[2] = {0};
+ bool use_original;
+
+ unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
+ sculpt_brush_test_init(ss, &test);
+
+ use_original = (ss->cache->original && (unode->co || unode->bm_entry));
+
+ /* when the mesh is edited we can't rely on original coords
+ * (original mesh may not even have verts in brush radius) */
+ if (use_original && has_bm_orco) {
+ float (*orco_coords)[3];
+ int (*orco_tris)[3];
+ int orco_tris_num;
+ int i;
+
+ BKE_pbvh_node_get_bm_orco_data(
+ nodes[n],
+ &orco_tris, &orco_tris_num, &orco_coords);
+
+ for (i = 0; i < orco_tris_num; i++) {
+ const float *co_tri[3] = {
+ orco_coords[orco_tris[i][0]],
+ orco_coords[orco_tris[i][1]],
+ orco_coords[orco_tris[i][2]],
+ };
+ float co[3];
+
+ closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no[3];
+ int flip_index;
+
+ cross_tri_v3(no, UNPACK3(co_tri));
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_co[flip_index], co);
+ private_count[flip_index] += 1;
+ }
+ }
+ }
+ else {
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float *co;
+ const short *no_s; /* bm_vert only */
+
+ if (use_original) {
+ if (unode->bm_entry) {
+ BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
+ }
+ else {
+ co = unode->co[vd.i];
+ no_s = unode->no[vd.i];
+ }
+ }
+ else {
+ co = vd.co;
+ }
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no_buf[3];
+ const float *no;
+ int flip_index;
+
+ if (use_original) {
+ normal_short_to_float_v3(no_buf, no_s);
+ no = no_buf;
+ }
+ else {
+ if (vd.no) {
+ normal_short_to_float_v3(no_buf, vd.no);
+ no = no_buf;
+ }
+ else {
+ no = vd.fno;
+ }
+ }
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_co[flip_index], co);
+ private_count[flip_index] += 1;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+#pragma omp critical
+ {
+ /* for flatten center */
+ add_v3_v3(area_co[0], private_co[0]);
+ add_v3_v3(area_co[1], private_co[1]);
+
+ /* weights */
+ count[0] += private_count[0];
+ count[1] += private_count[1];
+ }
+ }
+
+ /* for flatten center */
+ for (n = 0; n < ARRAY_SIZE(area_co); n++) {
+ if (count[n] != 0) {
+ mul_v3_v3fl(r_area_co, area_co[n], 1.0f / count[n]);
+ break;
+ }
+ }
+ if (n == 2) {
+ zero_v3(r_area_co);
+ }
+}
+
+
+static void calc_area_normal(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_no[3])
+{
+ const Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
+ int n;
+
+ /* 0=towards view, 1=flipped */
+ float area_no[2][3] = {{0.0f}};
+
+ int count[2] = {0};
+
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
+ for (n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptUndoNode *unode;
+ float private_no[2][3] = {{0.0f}};
+ int private_count[2] = {0};
+ bool use_original;
+
+ unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
+ sculpt_brush_test_init(ss, &test);
+
+ use_original = (ss->cache->original && (unode->co || unode->bm_entry));
+
+ /* when the mesh is edited we can't rely on original coords
+ * (original mesh may not even have verts in brush radius) */
+ if (use_original && has_bm_orco) {
+ float (*orco_coords)[3];
+ int (*orco_tris)[3];
+ int orco_tris_num;
+ int i;
+
+ BKE_pbvh_node_get_bm_orco_data(
+ nodes[n],
+ &orco_tris, &orco_tris_num, &orco_coords);
+
+ for (i = 0; i < orco_tris_num; i++) {
+ const float *co_tri[3] = {
+ orco_coords[orco_tris[i][0]],
+ orco_coords[orco_tris[i][1]],
+ orco_coords[orco_tris[i][2]],
+ };
+ float co[3];
+
+ closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no[3];
+ int flip_index;
+
+ normal_tri_v3(no, UNPACK3(co_tri));
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
+ }
+ }
+ }
+ else {
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float *co;
+ const short *no_s; /* bm_vert only */
+
+ if (use_original) {
+ if (unode->bm_entry) {
+ BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
+ }
+ else {
+ co = unode->co[vd.i];
+ no_s = unode->no[vd.i];
+ }
+ }
+ else {
+ co = vd.co;
+ }
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no_buf[3];
+ const float *no;
+ int flip_index;
+
+ if (use_original) {
+ normal_short_to_float_v3(no_buf, no_s);
+ no = no_buf;
+ }
+ else {
+ if (vd.no) {
+ normal_short_to_float_v3(no_buf, vd.no);
+ no = no_buf;
+ }
+ else {
+ no = vd.fno;
+ }
+ }
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+#pragma omp critical
+ {
+ /* for area normal */
+ add_v3_v3(area_no[0], private_no[0]);
+ add_v3_v3(area_no[1], private_no[1]);
+
+ /* weights */
+ count[0] += private_count[0];
+ count[1] += private_count[1];
+ }
+ }
+
+ /* for area normal */
+ for (n = 0; n < ARRAY_SIZE(area_no); n++) {
+ if (normalize_v3_v3(r_area_no, area_no[n]) != 0.0f) {
+ break;
+ }
+ }
+}
+
+/* this calculates flatten center and area normal together,
+ * amortizing the memory bandwidth and loop overhead to calculate both at the same time */
+static void calc_area_normal_and_center(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_no[3], float r_area_co[3])
+{
+ const Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
+ int n;
+
+ /* 0=towards view, 1=flipped */
+ float area_co[2][3] = {{0.0f}};
+ float area_no[2][3] = {{0.0f}};
+
+ int count[2] = {0};
+
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
+ for (n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptUndoNode *unode;
+ float private_co[2][3] = {{0.0f}};
+ float private_no[2][3] = {{0.0f}};
+ int private_count[2] = {0};
+ bool use_original;
+
+ unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
+ sculpt_brush_test_init(ss, &test);
+
+ use_original = (ss->cache->original && (unode->co || unode->bm_entry));
+
+ /* when the mesh is edited we can't rely on original coords
+ * (original mesh may not even have verts in brush radius) */
+ if (use_original && has_bm_orco) {
+ float (*orco_coords)[3];
+ int (*orco_tris)[3];
+ int orco_tris_num;
+ int i;
+
+ BKE_pbvh_node_get_bm_orco_data(
+ nodes[n],
+ &orco_tris, &orco_tris_num, &orco_coords);
+
+ for (i = 0; i < orco_tris_num; i++) {
+ const float *co_tri[3] = {
+ orco_coords[orco_tris[i][0]],
+ orco_coords[orco_tris[i][1]],
+ orco_coords[orco_tris[i][2]],
+ };
+ float co[3];
+
+ closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no[3];
+ int flip_index;
+
+ normal_tri_v3(no, UNPACK3(co_tri));
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_co[flip_index], co);
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
+ }
+ }
+ }
+ else {
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float *co;
+ const short *no_s; /* bm_vert only */
+
+ if (use_original) {
+ if (unode->bm_entry) {
+ BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
+ }
+ else {
+ co = unode->co[vd.i];
+ no_s = unode->no[vd.i];
+ }
+ }
+ else {
+ co = vd.co;
+ }
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no_buf[3];
+ const float *no;
+ int flip_index;
+
+ if (use_original) {
+ normal_short_to_float_v3(no_buf, no_s);
+ no = no_buf;
+ }
+ else {
+ if (vd.no) {
+ normal_short_to_float_v3(no_buf, vd.no);
+ no = no_buf;
+ }
+ else {
+ no = vd.fno;
+ }
+ }
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ add_v3_v3(private_co[flip_index], co);
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+#pragma omp critical
+ {
+ /* for flatten center */
+ add_v3_v3(area_co[0], private_co[0]);
+ add_v3_v3(area_co[1], private_co[1]);
+
+ /* for area normal */
+ add_v3_v3(area_no[0], private_no[0]);
+ add_v3_v3(area_no[1], private_no[1]);
+
+ /* weights */
+ count[0] += private_count[0];
+ count[1] += private_count[1];
+ }
+ }
+
+ /* for flatten center */
+ for (n = 0; n < ARRAY_SIZE(area_co); n++) {
+ if (count[n] != 0) {
+ mul_v3_v3fl(r_area_co, area_co[n], 1.0f / count[n]);
+ break;
+ }
+ }
+ if (n == 2) {
+ zero_v3(r_area_co);
+ }
+
+ /* for area normal */
+ for (n = 0; n < ARRAY_SIZE(area_no); n++) {
+ if (normalize_v3_v3(r_area_no, area_no[n]) != 0.0f) {
+ break;
+ }
+ }
+}
+
+/** \} */
+
+
/* 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(Sculpt *sd, StrokeCache *cache, float feather, UnifiedPaintSettings *ups)
+static float brush_strength(const Sculpt *sd, const StrokeCache *cache, const float feather, const UnifiedPaintSettings *ups)
{
const Scene *scene = cache->vc->scene;
- Brush *brush = BKE_paint_brush(&sd->paint);
+ const Brush *brush = BKE_paint_brush((Paint *)&sd->paint);
/* Primary strength input; square it to make lower values more sensitive */
const float root_alpha = BKE_brush_alpha_get(scene, brush);
float alpha = root_alpha * root_alpha;
- float dir = brush->flag & BRUSH_DIR_IN ? -1 : 1;
+ float dir = (brush->flag & BRUSH_DIR_IN) ? -1 : 1;
float pressure = BKE_brush_use_alpha_pressure(scene, brush) ? cache->pressure : 1;
float pen_flip = cache->pen_flip ? -1 : 1;
float invert = cache->invert ? -1 : 1;
@@ -926,132 +1414,34 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float co[3], const float
}
}
-static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], float fno[3])
-{
- if ((dot_v3v3(view_vec, fno)) > 0) {
- add_v3_v3(out, fno);
- }
- else {
- add_v3_v3(out_flip, fno); /* out_flip is used when out is {0,0,0} */
- }
-}
-
-static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nodes, int totnode)
-{
- float out_flip[3] = {0.0f, 0.0f, 0.0f};
-
- SculptSession *ss = ob->sculpt;
- const Brush *brush = BKE_paint_brush(&sd->paint);
- int n;
- bool original;
-
- /* Grab brush requires to test on original data (see r33888 and
- * bug #25371) */
- original = (BKE_paint_brush(&sd->paint)->sculpt_tool == SCULPT_TOOL_GRAB ?
- true : ss->cache->original);
-
- /* In general the original coords are not available with dynamic
- * topology
- *
- * Mask tool could not use undo nodes to get coordinates from
- * since the coordinates are not stored in those odes.
- * And mask tool is not gonna to modify vertex coordinates,
- * so we don't actually need to use modified coords.
- */
- if (ss->bm || brush->sculpt_tool == SCULPT_TOOL_MASK)
- original = false;
-
- (void)sd; /* unused w/o openmp */
-
- zero_v3(an);
-
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
- float private_an[3] = {0.0f, 0.0f, 0.0f};
- float private_out_flip[3] = {0.0f, 0.0f, 0.0f};
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- if (original) {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
- float fno[3];
-
- normal_short_to_float_v3(fno, unode->no[vd.i]);
- add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, vd.co)) {
- if (vd.no) {
- float fno[3];
-
- normal_short_to_float_v3(fno, vd.no);
- add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
- }
- else {
- add_norm_if(ss->cache->view_normal, private_an, private_out_flip, vd.fno);
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-
-#pragma omp critical
- {
- add_v3_v3(an, private_an);
- add_v3_v3(out_flip, private_out_flip);
- }
- }
-
- if (is_zero_v3(an))
- copy_v3_v3(an, out_flip);
-
- normalize_v3(an);
-}
-
/* Calculate primary direction of movement for many brushes */
-static void calc_sculpt_normal(Sculpt *sd, Object *ob,
- PBVHNode **nodes, int totnode,
- float an[3])
+static void calc_sculpt_normal(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_no[3])
{
const Brush *brush = BKE_paint_brush(&sd->paint);
const SculptSession *ss = ob->sculpt;
switch (brush->sculpt_plane) {
case SCULPT_DISP_DIR_VIEW:
- copy_v3_v3(an, ss->cache->true_view_normal);
+ copy_v3_v3(r_area_no, ss->cache->true_view_normal);
break;
case SCULPT_DISP_DIR_X:
- an[1] = 0.0;
- an[2] = 0.0;
- an[0] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 1, 0, 0);
break;
case SCULPT_DISP_DIR_Y:
- an[0] = 0.0;
- an[2] = 0.0;
- an[1] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 0, 1, 0);
break;
case SCULPT_DISP_DIR_Z:
- an[0] = 0.0;
- an[1] = 0.0;
- an[2] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 0, 0, 1);
break;
case SCULPT_DISP_DIR_AREA:
- calc_area_normal(sd, ob, an, nodes, totnode);
+ calc_area_normal(sd, ob, nodes, totnode, r_area_no);
break;
default:
@@ -1152,27 +1542,6 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob)
}
}
-/* Test whether the StrokeCache.sculpt_normal needs update in
- * do_brush_action() */
-static int brush_needs_sculpt_normal(const Brush *brush)
-{
- return ((ELEM(brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_SNAKE_HOOK) &&
- (brush->normal_weight > 0)) ||
-
- ELEM(brush->sculpt_tool,
- SCULPT_TOOL_BLOB,
- SCULPT_TOOL_CREASE,
- SCULPT_TOOL_DRAW,
- SCULPT_TOOL_LAYER,
- SCULPT_TOOL_NUDGE,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB) ||
-
- (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA));
-}
-
/* For the smooth brush, uses the neighboring vertices around vert to calculate
* a smoothed location for vert. Skips corner vertices (used by only one
* polygon.) */
@@ -1182,20 +1551,19 @@ static void neighbor_average(SculptSession *ss, float avg[3], unsigned vert)
const MVert *mvert = ss->mvert;
float (*deform_co)[3] = ss->deform_cos;
- zero_v3(avg);
-
/* Don't modify corner vertices */
if (vert_map->count > 1) {
int i, total = 0;
+ zero_v3(avg);
+
for (i = 0; i < vert_map->count; i++) {
const MPoly *p = &ss->mpoly[vert_map->indices[i]];
- unsigned f_adj_v[3];
+ unsigned f_adj_v[2];
if (poly_get_adj_loops_from_vert(f_adj_v, p, ss->mloop, vert) != -1) {
int j;
-
- for (j = 0; j < 3; j++) {
+ for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
if (vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2) {
add_v3_v3(avg, deform_co ? deform_co[f_adj_v[j]] :
mvert[f_adj_v[j]].co);
@@ -1226,12 +1594,11 @@ static float neighbor_average_mask(SculptSession *ss, unsigned vert)
for (i = 0; i < ss->pmap[vert].count; i++) {
const MPoly *p = &ss->mpoly[ss->pmap[vert].indices[i]];
- unsigned f_adj_v[3];
+ unsigned f_adj_v[2];
if (poly_get_adj_loops_from_vert(f_adj_v, p, ss->mloop, vert) != -1) {
int j;
-
- for (j = 0; j < 3; j++) {
+ for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
avg += vmask[f_adj_v[j]];
total++;
}
@@ -1247,22 +1614,24 @@ static float neighbor_average_mask(SculptSession *ss, unsigned vert)
/* Same logic as neighbor_average(), but for bmesh rather than mesh */
static void bmesh_neighbor_average(float avg[3], BMVert *v)
{
- const int vfcount = BM_vert_face_count(v);
+ /* logic for 3 or more is identical */
+ const int vfcount = BM_vert_face_count_ex(v, 3);
- zero_v3(avg);
-
/* Don't modify corner vertices */
if (vfcount > 1) {
BMIter liter;
BMLoop *l;
int i, total = 0;
+ zero_v3(avg);
+
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- BMVert *adj_v[3] = {l->prev->v, v, l->next->v};
+ const BMVert *adj_v[2] = {l->prev->v, l->next->v};
- for (i = 0; i < 3; i++) {
- if (vfcount != 2 || BM_vert_face_count(adj_v[i]) <= 2) {
- add_v3_v3(avg, adj_v[i]->co);
+ for (i = 0; i < ARRAY_SIZE(adj_v); i++) {
+ const BMVert *v_other = adj_v[i];
+ if (vfcount != 2 || BM_vert_face_count_ex(v_other, 2) <= 2) {
+ add_v3_v3(avg, v_other->co);
total++;
}
}
@@ -1278,7 +1647,7 @@ static void bmesh_neighbor_average(float avg[3], BMVert *v)
}
/* Same logic as neighbor_average_mask(), but for bmesh rather than mesh */
-static float bmesh_neighbor_average_mask(BMesh *bm, BMVert *v)
+static float bmesh_neighbor_average_mask(BMVert *v, const int cd_vert_mask_offset)
{
BMIter liter;
BMLoop *l;
@@ -1286,13 +1655,12 @@ static float bmesh_neighbor_average_mask(BMesh *bm, BMVert *v)
int i, total = 0;
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- BMVert *adj_v[3] = {l->prev->v, v, l->next->v};
+ /* skip this vertex */
+ const BMVert *adj_v[2] = {l->prev->v, l->next->v};
- for (i = 0; i < 3; i++) {
- BMVert *v2 = adj_v[i];
- float *vmask = CustomData_bmesh_get(&bm->vdata,
- v2->head.data,
- CD_PAINT_MASK);
+ for (i = 0; i < ARRAY_SIZE(adj_v); i++) {
+ const BMVert *v_other = adj_v[i];
+ const float *vmask = BM_ELEM_CD_GET_VOID_P(v_other, cd_vert_mask_offset);
avg += (*vmask);
total++;
}
@@ -1302,9 +1670,7 @@ static float bmesh_neighbor_average_mask(BMesh *bm, BMVert *v)
return avg / (float)total;
}
else {
- float *vmask = CustomData_bmesh_get(&bm->vdata,
- v->head.data,
- CD_PAINT_MASK);
+ const float *vmask = BM_ELEM_CD_GET_VOID_P(v, cd_vert_mask_offset);
return (*vmask);
}
}
@@ -1367,7 +1733,7 @@ static void do_bmesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
vd.no, vd.fno,
smooth_mask ? 0 : *vd.mask);
if (smooth_mask) {
- float val = bmesh_neighbor_average_mask(ss->bm, vd.bm_vert) - *vd.mask;
+ float val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask;
val *= fade * bstrength;
*vd.mask += val;
CLAMP(*vd.mask, 0, 1);
@@ -1398,12 +1764,11 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
SculptBrushTest test;
CCGElem **griddata, *data;
CCGKey key;
- DMGridAdjacency *gridadj, *adj;
float (*tmpgrid_co)[3], (*tmprow_co)[3];
float *tmpgrid_mask, *tmprow_mask;
int v1, v2, v3, v4;
int thread_num;
- BLI_bitmap **grid_hidden;
+ BLI_bitmap * const *grid_hidden;
int *grid_indices, totgrid, gridsize, i, x, y;
sculpt_brush_test_init(ss, &test);
@@ -1411,7 +1776,7 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
CLAMP(bstrength, 0.0f, 1.0f);
BKE_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid,
- NULL, &gridsize, &griddata, &gridadj);
+ NULL, &gridsize, &griddata);
BKE_pbvh_get_grid_key(ss->pbvh, &key);
grid_hidden = BKE_pbvh_grid_hidden(ss->pbvh);
@@ -1428,9 +1793,8 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
for (i = 0; i < totgrid; ++i) {
int gi = grid_indices[i];
- BLI_bitmap *gh = grid_hidden[gi];
+ const BLI_bitmap *gh = grid_hidden[gi];
data = griddata[gi];
- adj = &gridadj[gi];
if (smooth_mask)
memset(tmpgrid_mask, 0, sizeof(float) * gridsize * gridsize);
@@ -1496,18 +1860,6 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
continue;
}
- if (x == 0 && adj->index[0] == -1)
- continue;
-
- if (x == gridsize - 1 && adj->index[2] == -1)
- continue;
-
- if (y == 0 && adj->index[3] == -1)
- continue;
-
- if (y == gridsize - 1 && adj->index[1] == -1)
- continue;
-
index = x + y * gridsize;
co = CCG_elem_offset_co(&key, data, index);
fno = CCG_elem_offset_no(&key, data, index);
@@ -1698,6 +2050,8 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float brush_alpha;
int n;
+ SculptProjectVector spvc;
+
/* offset with as much as possible factored in already */
mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
mul_v3_v3(offset, ss->cache->scale);
@@ -1714,6 +2068,10 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
if (brush->sculpt_tool == SCULPT_TOOL_BLOB) flippedbstrength *= -1.0f;
+ /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single point.
+ * Without this we get a 'flat' surface surrounding the pinch */
+ sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm);
+
/* threaded loop over nodes */
#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
@@ -1738,6 +2096,8 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
sub_v3_v3v3(val1, test.location, vd.co);
mul_v3_fl(val1, fade * flippedbstrength);
+ sculpt_project_v3(&spvc, val1, val1);
+
/* then we draw */
mul_v3_v3fl(val2, offset, fade);
@@ -2131,233 +2491,10 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
}
}
-static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float fc[3])
-{
- SculptSession *ss = ob->sculpt;
- int n;
-
- int count = 0;
- int count_flip = 0;
-
- float fc_flip[3] = {0.0, 0.0, 0.0};
-
- (void)sd; /* unused w/o openmp */
-
- zero_v3(fc);
-
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
- float private_fc[3] = {0.0f, 0.0f, 0.0f};
- float private_fc_flip[3] = {0.0f, 0.0f, 0.0f};
- int private_count = 0;
- int private_count_flip = 0;
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- if (ss->cache->original && unode->co) {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
- float fno[3];
-
- normal_short_to_float_v3(fno, unode->no[vd.i]);
- if (dot_v3v3(ss->cache->view_normal, fno) > 0) {
- add_v3_v3(private_fc, unode->co[vd.i]);
- private_count++;
- }
- else {
- add_v3_v3(private_fc_flip, unode->co[vd.i]);
- private_count_flip++;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, vd.co)) {
- /* for area normal */
- if (vd.no) {
- float fno[3];
-
- normal_short_to_float_v3(fno, vd.no);
-
- if (dot_v3v3(ss->cache->view_normal, fno) > 0) {
- add_v3_v3(private_fc, vd.co);
- private_count++;
- }
- else {
- add_v3_v3(private_fc_flip, vd.co);
- private_count_flip++;
- }
- }
- else {
- if (dot_v3v3(ss->cache->view_normal, vd.fno) > 0) {
- add_v3_v3(private_fc, vd.co);
- private_count++;
- }
- else {
- add_v3_v3(private_fc_flip, vd.co);
- private_count_flip++;
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-
-#pragma omp critical
- {
- add_v3_v3(fc, private_fc);
- add_v3_v3(fc_flip, private_fc_flip);
- count += private_count;
- count_flip += private_count_flip;
- }
- }
- if (count != 0)
- mul_v3_fl(fc, 1.0f / count);
- else if (count_flip != 0)
- mul_v3_v3fl(fc, fc_flip, 1.0f / count_flip);
- else
- zero_v3(fc);
-}
-
-/* this calculates flatten center and area normal together,
- * amortizing the memory bandwidth and loop overhead to calculate both at the same time */
-static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob,
- PBVHNode **nodes, int totnode,
- float an[3], float fc[3])
-{
- SculptSession *ss = ob->sculpt;
- int n;
-
- /* for area normal */
- float out_flip[3] = {0.0f, 0.0f, 0.0f};
- float fc_flip[3] = {0.0f, 0.0f, 0.0f};
-
- /* for flatten center */
- int count = 0;
- int count_flipped = 0;
-
- (void)sd; /* unused w/o openmp */
-
- /* for area normal */
- zero_v3(an);
-
- /* for flatten center */
- zero_v3(fc);
-
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
- float private_an[3] = {0.0f, 0.0f, 0.0f};
- float private_out_flip[3] = {0.0f, 0.0f, 0.0f};
- float private_fc[3] = {0.0f, 0.0f, 0.0f};
- float private_fc_flip[3] = {0.0f, 0.0f, 0.0f};
- int private_count = 0;
- int private_count_flip = 0;
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- if (ss->cache->original && unode->co) {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
- /* for area normal */
- float fno[3];
-
- normal_short_to_float_v3(fno, unode->no[vd.i]);
-
- if (dot_v3v3(ss->cache->view_normal, fno) > 0) {
- add_v3_v3(private_an, fno);
- add_v3_v3(private_fc, unode->co[vd.i]);
- private_count++;
- }
- else {
- add_v3_v3(private_out_flip, fno);
- add_v3_v3(private_fc_flip, unode->co[vd.i]);
- private_count_flip++;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, vd.co)) {
- /* for area normal */
- if (vd.no) {
- float fno[3];
-
- normal_short_to_float_v3(fno, vd.no);
-
- if (dot_v3v3(ss->cache->view_normal, fno) > 0) {
- add_v3_v3(private_an, fno);
- add_v3_v3(private_fc, vd.co);
- private_count++;
- }
- else {
- add_v3_v3(private_out_flip, fno);
- add_v3_v3(private_fc_flip, vd.co);
- private_count_flip++;
- }
- }
- else {
- if (dot_v3v3(ss->cache->view_normal, vd.fno) > 0) {
- add_v3_v3(private_an, vd.fno);
- add_v3_v3(private_fc, vd.co);
- private_count++;
- }
- else {
- add_v3_v3(private_out_flip, vd.fno);
- add_v3_v3(private_fc_flip, vd.co);
- private_count_flip++;
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-
-#pragma omp critical
- {
- /* for area normal */
- add_v3_v3(an, private_an);
- add_v3_v3(out_flip, private_out_flip);
-
- /* for flatten center */
- add_v3_v3(fc, private_fc);
- add_v3_v3(fc_flip, private_fc_flip);
- count += private_count;
- count_flipped += private_count_flip;
- }
- }
-
- /* for area normal */
- if (is_zero_v3(an))
- copy_v3_v3(an, out_flip);
-
- normalize_v3(an);
-
- /* for flatten center */
- if (count != 0)
- mul_v3_fl(fc, 1.0f / count);
- else if (count_flipped != 0)
- mul_v3_v3fl(fc, fc_flip, 1.0f / count_flipped);
- else
- zero_v3(fc);
-}
-
-static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float an[3], float fc[3])
+static void calc_sculpt_plane(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_no[3], float r_area_co[3])
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
@@ -2368,29 +2505,23 @@ static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
{
switch (brush->sculpt_plane) {
case SCULPT_DISP_DIR_VIEW:
- copy_v3_v3(an, ss->cache->true_view_normal);
+ copy_v3_v3(r_area_no, ss->cache->true_view_normal);
break;
case SCULPT_DISP_DIR_X:
- an[1] = 0.0;
- an[2] = 0.0;
- an[0] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 1, 0, 0);
break;
case SCULPT_DISP_DIR_Y:
- an[0] = 0.0;
- an[2] = 0.0;
- an[1] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 0, 1, 0);
break;
case SCULPT_DISP_DIR_Z:
- an[0] = 0.0;
- an[1] = 0.0;
- an[2] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 0, 0, 1);
break;
case SCULPT_DISP_DIR_AREA:
- calc_area_normal_and_flatten_center(sd, ob, nodes, totnode, an, fc);
+ calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
break;
default:
@@ -2400,50 +2531,54 @@ static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
/* for flatten center */
/* flatten center has not been calculated yet if we are not using the area normal */
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA)
- calc_flatten_center(sd, ob, nodes, totnode, fc);
+ calc_area_center(sd, ob, nodes, totnode, r_area_co);
/* for area normal */
- copy_v3_v3(ss->cache->sculpt_normal, an);
+ copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
/* for flatten center */
- copy_v3_v3(ss->cache->last_center, fc);
+ copy_v3_v3(ss->cache->last_center, r_area_co);
}
else {
/* for area normal */
- copy_v3_v3(an, ss->cache->sculpt_normal);
+ copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
/* for flatten center */
- copy_v3_v3(fc, ss->cache->last_center);
+ copy_v3_v3(r_area_co, ss->cache->last_center);
/* for area normal */
- flip_v3(an, ss->cache->mirror_symmetry_pass);
+ flip_v3(r_area_no, ss->cache->mirror_symmetry_pass);
/* for flatten center */
- flip_v3(fc, ss->cache->mirror_symmetry_pass);
+ flip_v3(r_area_co, ss->cache->mirror_symmetry_pass);
/* for area normal */
- mul_m4_v3(ss->cache->symm_rot_mat, an);
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_no);
/* for flatten center */
- mul_m4_v3(ss->cache->symm_rot_mat, fc);
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_co);
}
}
/* Projects a point onto a plane along the plane's normal */
-static void point_plane_project(float intr[3], float co[3], float plane_normal[3], float plane_center[3])
+static void point_plane_project(
+ float intr[3],
+ const float co[3], const float plane_normal[3], const float plane_center[3])
{
sub_v3_v3v3(intr, co, plane_center);
mul_v3_v3fl(intr, plane_normal, dot_v3v3(plane_normal, intr));
sub_v3_v3v3(intr, co, intr);
}
-static int plane_trim(StrokeCache *cache, Brush *brush, float val[3])
+static int plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3])
{
return (!(brush->flag & BRUSH_PLANE_TRIM) ||
((dot_v3v3(val, val) <= cache->radius_squared * cache->plane_trim_squared)));
}
-static int plane_point_side_flip(float co[3], float plane_normal[3], float plane_center[3], int flip)
+static bool plane_point_side_flip(
+ const float co[3], const float plane_normal[3], const float plane_center[3],
+ const bool flip)
{
float delta[3];
float d;
@@ -2456,7 +2591,7 @@ static int plane_point_side_flip(float co[3], float plane_normal[3], float plane
return d <= 0.0f;
}
-static int plane_point_side(float co[3], float plane_normal[3], float plane_center[3])
+static int plane_point_side(const float co[3], const float plane_normal[3], const float plane_center[3])
{
float delta[3];
@@ -2485,8 +2620,8 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
- float an[3];
- float fc[3];
+ float area_no[3];
+ float area_co[3];
float offset = get_offset(sd, ss);
@@ -2496,13 +2631,13 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
displace = radius * offset;
- mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ add_v3_v3(area_co, temp);
#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
@@ -2520,7 +2655,7 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, an, fc);
+ point_plane_project(intr, vd.co, area_no, area_co);
sub_v3_v3v3(val, intr, vd.co);
@@ -2550,16 +2685,16 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float displace;
- float an[3];
- float fc[3];
+ float area_no[3];
+ float area_co[3];
int n;
float temp[3];
- int flip;
+ bool flip;
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
flip = bstrength < 0;
@@ -2570,11 +2705,11 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
displace = radius * (0.25f + offset);
- mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ add_v3_v3(area_co, temp);
- /* add_v3_v3v3(p, ss->cache->location, an); */
+ /* add_v3_v3v3(p, ss->cache->location, area_no); */
#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
@@ -2589,15 +2724,17 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq(&test, vd.co)) {
- if (plane_point_side_flip(vd.co, an, fc, flip)) {
+ if (plane_point_side_flip(vd.co, area_no, area_co, flip)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, an, fc);
+ point_plane_project(intr, vd.co, area_no, area_co);
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
+ /* note, the normal from the vertices is ignored,
+ * causes glitch with planes, see: T44390 */
const float fade = bstrength * tex_strength(ss, brush, vd.co, sqrtf(test.dist),
vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
@@ -2624,9 +2761,9 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
float displace;
- float sn[3];
- float an[3];
- float fc[3];
+ float area_no_sp[3]; /* the sculpt-plane normal (whatever its set to) */
+ float area_no[3]; /* geometry normal */
+ float area_co[3];
int n;
@@ -2635,14 +2772,14 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
float scale[4][4];
float tmat[4][4];
- int flip;
+ bool flip;
- calc_sculpt_plane(sd, ob, nodes, totnode, sn, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL))
- calc_area_normal(sd, ob, an, nodes, totnode);
+ calc_area_normal(sd, ob, nodes, totnode, area_no);
else
- copy_v3_v3(an, sn);
+ copy_v3_v3(area_no, area_no_sp);
/* delay the first daub because grab delta is not setup */
if (ss->cache->first_time)
@@ -2657,16 +2794,16 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
displace = radius * (0.25f + offset);
- mul_v3_v3v3(temp, sn, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ add_v3_v3(area_co, temp);
/* init mat */
- cross_v3_v3v3(mat[0], an, ss->cache->grab_delta_symmetry);
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
mat[0][3] = 0;
- cross_v3_v3v3(mat[1], an, mat[0]);
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
mat[1][3] = 0;
- copy_v3_v3(mat[2], an);
+ copy_v3_v3(mat[2], area_no);
mat[2][3] = 0;
copy_v3_v3(mat[3], ss->cache->location);
mat[3][3] = 1;
@@ -2690,15 +2827,17 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_cube(&test, vd.co, mat)) {
- if (plane_point_side_flip(vd.co, sn, fc, flip)) {
+ if (plane_point_side_flip(vd.co, area_no_sp, area_co, flip)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, sn, fc);
+ point_plane_project(intr, vd.co, area_no_sp, area_co);
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
+ /* note, the normal from the vertices is ignored,
+ * causes glitch with planes, see: T44390 */
const float fade = bstrength * tex_strength(ss, brush, vd.co,
ss->cache->radius * test.dist,
vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
@@ -2723,8 +2862,8 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
- float an[3];
- float fc[3];
+ float area_no[3];
+ float area_co[3];
float offset = get_offset(sd, ss);
float displace;
@@ -2733,13 +2872,13 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
displace = radius * offset;
- mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ add_v3_v3(area_co, temp);
#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
@@ -2754,11 +2893,11 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq(&test, vd.co)) {
- if (plane_point_side(vd.co, an, fc)) {
+ if (plane_point_side(vd.co, area_no, area_co)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, an, fc);
+ point_plane_project(intr, vd.co, area_no, area_co);
sub_v3_v3v3(val, intr, vd.co);
@@ -2787,8 +2926,8 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
- float an[3];
- float fc[3];
+ float area_no[3];
+ float area_co[3];
float offset = get_offset(sd, ss);
float displace;
@@ -2797,13 +2936,13 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
displace = -radius * offset;
- mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ add_v3_v3(area_co, temp);
#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
@@ -2818,11 +2957,11 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq(&test, vd.co)) {
- if (!plane_point_side(vd.co, an, fc)) {
+ if (!plane_point_side(vd.co, area_no, area_co)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, an, fc);
+ point_plane_project(intr, vd.co, area_no, area_co);
sub_v3_v3v3(val, intr, vd.co);
@@ -2848,7 +2987,7 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3]/*, an[3]*/;
+ float offset[3]/*, area_no[3]*/;
int n;
float gravity_vector[3];
@@ -2945,11 +3084,7 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, Unified
radius = ss->cache->radius * 1.25f;
data.radius_squared = radius * radius;
- data.original = ELEM(brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER) ? true : ss->cache->original;
+ data.original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original;
BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
@@ -2980,9 +3115,11 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, Unified
}
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
- BKE_pbvh_bmesh_update_topology(ss->pbvh, mode,
- ss->cache->location,
- ss->cache->radius);
+ BKE_pbvh_bmesh_update_topology(
+ ss->pbvh, mode,
+ ss->cache->location,
+ (brush->flag & BRUSH_FRONTFACE) ? ss->cache->view_normal : NULL,
+ ss->cache->radius);
}
MEM_freeN(nodes);
@@ -3004,11 +3141,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
data.ss = ss;
data.sd = sd;
data.radius_squared = ss->cache->radius_squared;
- data.original = ELEM(brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER) ? true : ss->cache->original;
+ data.original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original;
BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
/* Only act if some verts are inside the brush area */
@@ -3023,7 +3156,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
BKE_pbvh_node_mark_update(nodes[n]);
}
- if (brush_needs_sculpt_normal(brush))
+ if (sculpt_brush_needs_normal(brush))
update_sculpt_normal(sd, ob, nodes, totnode);
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)
@@ -3143,8 +3276,8 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
/* first line is tools that don't support proxies */
- if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER) ||
- ss->cache->supports_gravity)
+ if (ss->cache->supports_gravity ||
+ (sculpt_tool_is_proxy_used(brush->sculpt_tool) == false))
{
/* these brushes start from original coordinates */
const bool use_orco = ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB,
@@ -3222,7 +3355,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- if (ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER)) {
+ if (sculpt_tool_is_proxy_used(brush->sculpt_tool)) {
/* this brushes aren't using proxies, so sculpt_combine_proxies() wouldn't
* propagate needed deformation to original base */
@@ -3483,8 +3616,6 @@ static const char *sculpt_tool_name(Sculpt *sd)
static void sculpt_cache_free(StrokeCache *cache)
{
- if (cache->face_norms)
- MEM_freeN(cache->face_norms);
if (cache->dial)
MEM_freeN(cache->dial);
MEM_freeN(cache);
@@ -3556,7 +3687,7 @@ static void sculpt_omp_start(Sculpt *sd, SculptSession *ss)
if (ss->multires) {
int i, gridsize, array_mem_size;
BKE_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL,
- &gridsize, NULL, NULL);
+ &gridsize, NULL);
array_mem_size = cache->num_threads * sizeof(void *);
@@ -3744,21 +3875,10 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
/* Make copies of the mesh vertex locations and normals for some tools */
if (brush->flag & BRUSH_ANCHORED) {
- if (ss->face_normals) {
- cache->face_norms = MEM_mallocN(sizeof(float) * 3 * ss->totpoly, "Sculpt face norms");
- for (i = 0; i < ss->totpoly; ++i) {
- copy_v3_v3(cache->face_norms[i], ss->face_normals[i]);
- }
- }
-
cache->original = 1;
}
- if (ELEM(brush->sculpt_tool,
- SCULPT_TOOL_DRAW, SCULPT_TOOL_CREASE, SCULPT_TOOL_BLOB,
- SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY,
- SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_ROTATE, SCULPT_TOOL_FLATTEN))
- {
+ if (SCULPT_TOOL_HAS_ACCUMULATE(brush->sculpt_tool)) {
if (!(brush->flag & BRUSH_ACCUMULATE)) {
cache->original = 1;
}
@@ -4250,6 +4370,9 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st
if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) {
BKE_pbvh_bmesh_detail_size_set(ss->pbvh, sd->constant_detail / 100.0f);
}
+ else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, ss->cache->radius * sd->detail_percent / 100.0f);
+ }
else {
BKE_pbvh_bmesh_detail_size_set(
ss->pbvh,
@@ -4258,7 +4381,7 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st
(float)(sd->detail_size * U.pixelsize) / 0.4f);
}
- if (sculpt_stroke_dynamic_topology(ss, brush)) {
+ if (sculpt_stroke_is_dynamic_topology(ss, brush)) {
do_symmetrical_brush_actions(sd, ob, sculpt_topology_update, ups);
}
@@ -4650,7 +4773,7 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
- if (!GPU_vertex_buffer_support()) {
+ if (!G.background && !GPU_vertex_buffer_support()) {
return OPERATOR_CANCELLED;
}
@@ -4745,7 +4868,7 @@ static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, co
/* exception for shape keys because we can edit those */
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
if (mti->type == eModifierTypeType_Constructive) {
@@ -4837,6 +4960,9 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
sd->symmetrize_direction, 0.00001f);
sculpt_dynamic_topology_triangulate(ss->bm);
+ /* bisect operator flags edges (keep tags clean for edge queue) */
+ BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
+
/* Finish undo */
BM_log_all_added(ss->bm, ss->bm_log);
sculpt_undo_push_end();
@@ -4911,7 +5037,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
/* Leave sculptmode */
ob->mode &= ~mode_flag;
- BKE_free_sculptsession(ob);
+ BKE_sculptsession_free(ob);
paint_cursor_delete_textures();
}
@@ -4940,16 +5066,16 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE;
}
- if (!ts->sculpt->detail_size) {
+ if (!ts->sculpt->detail_size)
ts->sculpt->detail_size = 12;
- }
-
+ if (!ts->sculpt->detail_percent)
+ ts->sculpt->detail_percent = 25;
if (ts->sculpt->constant_detail == 0.0f)
ts->sculpt->constant_detail = 30.0f;
/* Create sculpt mode session data */
if (ob->sculpt)
- BKE_free_sculptsession(ob);
+ BKE_sculptsession_free(ob);
sculpt_init_session(scene, ob);
@@ -5032,7 +5158,10 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
sculpt_undo_push_begin("Dynamic topology flood fill");
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS);
- while (BKE_pbvh_bmesh_update_topology(ss->pbvh, PBVH_Collapse | PBVH_Subdivide, bb_min, size)) {
+ while (BKE_pbvh_bmesh_update_topology(
+ ss->pbvh, PBVH_Collapse | PBVH_Subdivide,
+ bb_min, NULL, size))
+ {
for (i = 0; i < totnodes; i++)
BKE_pbvh_node_mark_topology_update(nodes[i]);
}
@@ -5176,6 +5305,10 @@ static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
set_brush_rc_props(&props_ptr, "sculpt", "constant_detail", NULL, 0);
RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail");
}
+ else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
+ set_brush_rc_props(&props_ptr, "sculpt", "constant_detail", NULL, 0);
+ RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_percent");
+ }
else {
set_brush_rc_props(&props_ptr, "sculpt", "detail_size", NULL, 0);
RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_size");
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index a61f571fdf6..8f1a4655c37 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -41,14 +41,8 @@
#include "BKE_pbvh.h"
struct bContext;
-struct Brush;
struct KeyBlock;
-struct Mesh;
-struct MultiresModifierData;
struct Object;
-struct Scene;
-struct Sculpt;
-struct SculptStroke;
struct SculptUndoNode;
int sculpt_mode_poll(struct bContext *C);
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index a4adbc6bca8..2f0957c3b60 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -484,7 +484,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
BKE_mesh_calc_normals_tessface(mesh->mvert, mesh->totvert,
mesh->mface, mesh->totface, NULL);
- BKE_free_sculptsession_deformMats(ss);
+ BKE_sculptsession_free_deformMats(ss);
tag_update |= true;
}
@@ -581,7 +581,7 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh,
grid_hidden = BKE_pbvh_grid_hidden(pbvh);
BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid,
- NULL, NULL, NULL, NULL);
+ NULL, NULL, NULL);
unode->grid_hidden = MEM_mapallocN(sizeof(*unode->grid_hidden) * totgrid,
"unode->grid_hidden");
@@ -610,7 +610,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node,
if (node) {
BKE_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert);
BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
- &maxgrid, &gridsize, NULL, NULL);
+ &maxgrid, &gridsize, NULL);
unode->totvert = totvert;
}
@@ -842,7 +842,7 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node,
if (unode->grids) {
int totgrid, *grids;
BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
- NULL, NULL, NULL, NULL);
+ NULL, NULL, NULL);
memcpy(unode->grids, grids, sizeof(int) * totgrid);
}
else {
diff --git a/source/blender/editors/sound/sound_intern.h b/source/blender/editors/sound/sound_intern.h
index e8a8ec55ab5..ace173abdee 100644
--- a/source/blender/editors/sound/sound_intern.h
+++ b/source/blender/editors/sound/sound_intern.h
@@ -32,7 +32,6 @@
#ifndef __SOUND_INTERN_H__
#define __SOUND_INTERN_H__
-struct wmOperatorType;
#endif /* __SOUND_INTERN_H__ */
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index f3c6781b0fa..8a3b48125d0 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -51,6 +51,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "BKE_library.h"
#include "BKE_packedFile.h"
#include "BKE_scene.h"
#include "BKE_sound.h"
@@ -100,13 +101,14 @@ static int sound_open_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
RNA_string_get(op->ptr, "filepath", path);
- sound = sound_new_file(bmain, path);
+ sound = BKE_sound_new_file(bmain, path);
if (!op->customdata)
sound_open_init(C, op);
- if (sound == NULL || sound->playback_handle == NULL) {
+ if (sound->playback_handle == NULL) {
if (op->customdata) MEM_freeN(op->customdata);
+ BKE_libblock_free(bmain, sound);
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
return OPERATOR_CANCELLED;
}
@@ -114,7 +116,7 @@ static int sound_open_exec(bContext *C, wmOperator *op)
info = AUD_getInfo(sound->playback_handle);
if (info.specs.channels == AUD_CHANNELS_INVALID) {
- sound_delete(bmain, sound);
+ BKE_sound_delete(bmain, sound);
if (op->customdata) MEM_freeN(op->customdata);
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
return OPERATOR_CANCELLED;
@@ -122,11 +124,11 @@ static int sound_open_exec(bContext *C, wmOperator *op)
if (RNA_boolean_get(op->ptr, "mono")) {
sound->flags |= SOUND_FLAGS_MONO;
- sound_load(bmain, sound);
+ BKE_sound_load(bmain, sound);
}
if (RNA_boolean_get(op->ptr, "cache")) {
- sound_cache(sound);
+ BKE_sound_cache(sound);
}
/* hook into UI */
@@ -690,7 +692,7 @@ static int sound_pack_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
sound->packedfile = newPackedFile(op->reports, sound->name, ID_BLEND_PATH(bmain, &sound->id));
- sound_load(bmain, sound);
+ BKE_sound_load(bmain, sound);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_action/CMakeLists.txt b/source/blender/editors/space_action/CMakeLists.txt
index 50cf84079d2..68e56490217 100644
--- a/source/blender/editors/space_action/CMakeLists.txt
+++ b/source/blender/editors/space_action/CMakeLists.txt
@@ -36,6 +36,7 @@ set(INC_SYS
)
set(SRC
+ action_data.c
action_draw.c
action_edit.c
action_ops.c
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
new file mode 100644
index 00000000000..6e3e456f67d
--- /dev/null
+++ b/source/blender/editors/space_action/action_data.c
@@ -0,0 +1,908 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_action/action_data.c
+ * \ingroup spaction
+ */
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <float.h>
+
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BLF_translation.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_mask_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "BKE_animsys.h"
+#include "BKE_action.h"
+#include "BKE_fcurve.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_key.h"
+#include "BKE_main.h"
+#include "BKE_nla.h"
+#include "BKE_scene.h"
+#include "BKE_context.h"
+#include "BKE_report.h"
+
+#include "UI_view2d.h"
+
+#include "ED_anim_api.h"
+#include "ED_gpencil.h"
+#include "ED_keyframing.h"
+#include "ED_keyframes_edit.h"
+#include "ED_screen.h"
+#include "ED_markers.h"
+#include "ED_mask.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+
+#include "action_intern.h"
+
+/* ************************************************************************** */
+/* ACTION CREATION */
+
+/* Helper function to find the active AnimData block from the Action Editor context */
+AnimData *ED_actedit_animdata_from_context(bContext *C)
+{
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ Object *ob = CTX_data_active_object(C);
+ AnimData *adt = NULL;
+
+ /* Get AnimData block to use */
+ if (saction->mode == SACTCONT_ACTION) {
+ /* Currently, "Action Editor" means object-level only... */
+ if (ob) {
+ adt = ob->adt;
+ }
+ }
+ else if (saction->mode == SACTCONT_SHAPEKEY) {
+ Key *key = BKE_key_from_object(ob);
+ if (key) {
+ adt = key->adt;
+ }
+ }
+
+ return adt;
+}
+
+/* -------------------------------------------------------------------- */
+
+/* Create new action */
+static bAction *action_create_new(bContext *C, bAction *oldact)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ bAction *action;
+
+ /* create action - the way to do this depends on whether we've got an
+ * existing one there already, in which case we make a copy of it
+ * (which is useful for "versioning" actions within the same file)
+ */
+ if (oldact && GS(oldact->id.name) == ID_AC) {
+ /* make a copy of the existing action */
+ action = BKE_action_copy(oldact);
+ }
+ else {
+ /* just make a new (empty) action */
+ action = add_empty_action(CTX_data_main(C), "Action");
+ }
+
+ /* when creating new ID blocks, there is already 1 user (as for all new datablocks),
+ * but the RNA pointer code will assign all the proper users instead, so we compensate
+ * for that here
+ */
+ BLI_assert(action->id.us == 1);
+ action->id.us--;
+
+ /* set ID-Root type */
+ if (sa->spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
+
+ if (saction->mode == SACTCONT_SHAPEKEY)
+ action->idroot = ID_KE;
+ else
+ action->idroot = ID_OB;
+ }
+
+ return action;
+}
+
+/* Change the active action used by the action editor */
+static void actedit_change_action(bContext *C, bAction *act)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+
+ PointerRNA ptr, idptr;
+ PropertyRNA *prop;
+
+ /* create RNA pointers and get the property */
+ RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, saction, &ptr);
+ prop = RNA_struct_find_property(&ptr, "action");
+
+ /* NOTE: act may be NULL here, so better to just use a cast here */
+ RNA_id_pointer_create((ID *)act, &idptr);
+
+ /* set the new pointer, and force a refresh */
+ RNA_property_pointer_set(&ptr, prop, idptr);
+ RNA_property_update(C, &ptr, prop);
+}
+
+/* ******************** New Action Operator *********************** */
+
+/* Criteria:
+ * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions...
+ * OR
+ * The NLA Editor is active (i.e. Animation Data panel -> new action)
+ * 2) The associated AnimData block must not be in tweakmode
+ */
+static int action_new_poll(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */
+ /* NOTE: unlike for pushdown, this operator needs to be run when creating an action from nothing... */
+ if (ED_operator_action_active(C)) {
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ Object *ob = CTX_data_active_object(C);
+
+ /* For now, actions are only for the active object, and on object and shapekey levels... */
+ if (saction->mode == SACTCONT_ACTION) {
+ /* XXX: This assumes that actions are assigned to the active object in this mode */
+ if (ob) {
+ if ((ob->adt == NULL) || (ob->adt->flag & ADT_NLA_EDIT_ON) == 0)
+ return true;
+ }
+ }
+ else if (saction->mode == SACTCONT_SHAPEKEY) {
+ Key *key = BKE_key_from_object(ob);
+ if (key) {
+ if ((key->adt == NULL) || (key->adt->flag & ADT_NLA_EDIT_ON) == 0)
+ return true;
+ }
+ }
+ }
+ else if (ED_operator_nla_active(C)) {
+ if (!(scene->flag & SCE_NLA_EDIT_ON)) {
+ return true;
+ }
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ PointerRNA ptr, idptr;
+ PropertyRNA *prop;
+
+ /* hook into UI */
+ UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
+
+ if (prop) {
+ bAction *action = NULL, *oldact = NULL;
+ AnimData *adt = NULL;
+ PointerRNA oldptr;
+
+ oldptr = RNA_property_pointer_get(&ptr, prop);
+ oldact = (bAction *)oldptr.id.data;
+
+ /* stash the old action to prevent it from being lost */
+ if (ptr.type == &RNA_AnimData) {
+ adt = ptr.data;
+ }
+ else if (ptr.type == &RNA_SpaceDopeSheetEditor) {
+ adt = ED_actedit_animdata_from_context(C);
+ }
+
+ /* Perform stashing operation - But only if there is an action */
+ if (adt && oldact) {
+ /* stash the action */
+ if (BKE_nla_action_stash(adt)) {
+ /* The stash operation will remove the user already
+ * (and unlink the action from the AnimData action slot).
+ * Hence, we must unset the ref to the action in the
+ * action editor too (if this is where we're being called from)
+ * first before setting the new action once it is created,
+ * or else the user gets decremented twice!
+ */
+ if (ptr.type == &RNA_SpaceDopeSheetEditor) {
+ SpaceAction *saction = (SpaceAction *)ptr.data;
+ saction->action = NULL;
+ }
+ }
+ else {
+ //printf("WARNING: Failed to stash %s. It may already exist in the NLA stack though\n", oldact->id.name);
+ }
+ }
+
+ /* create action */
+ action = action_create_new(C, oldact);
+
+ /* set this new action
+ * NOTE: we can't use actedit_change_action, as this function is also called from the NLA
+ */
+ RNA_id_pointer_create(&action->id, &idptr);
+ RNA_property_pointer_set(&ptr, prop, idptr);
+ RNA_property_update(C, &ptr, prop);
+ }
+
+ /* set notifier that keyframes have changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_new(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "New Action";
+ ot->idname = "ACTION_OT_new";
+ ot->description = "Create new action";
+
+ /* api callbacks */
+ ot->exec = action_new_exec;
+ ot->poll = action_new_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ******************* Action Push-Down Operator ******************** */
+
+/* Criteria:
+ * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions
+ * 2) There must be an action active
+ * 3) The associated AnimData block must not be in tweakmode
+ */
+static int action_pushdown_poll(bContext *C)
+{
+ if (ED_operator_action_active(C)) {
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Check for AnimData, Actions, and that tweakmode is off */
+ if (adt && saction->action) {
+ /* NOTE: We check this for the AnimData block in question and not the global flag,
+ * as the global flag may be left dirty by some of the browsing ops here.
+ */
+ if (!(adt->flag & ADT_NLA_EDIT_ON))
+ return true;
+ }
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_pushdown_exec(bContext *C, wmOperator *op)
+{
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Do the deed... */
+ if (adt) {
+ /* Perform the pushdown operation
+ * - This will deal with all the AnimData-side usercounts
+ */
+ if (action_has_motion(adt->action) == 0) {
+ /* action may not be suitable... */
+ BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* action can be safely added */
+ BKE_nla_action_pushdown(adt);
+ }
+
+ /* Stop displaying this action in this editor
+ * NOTE: The editor itself doesn't set a user...
+ */
+ saction->action = NULL;
+ }
+
+ /* Send notifiers that stuff has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_push_down(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Push Down Action";
+ ot->idname = "ACTION_OT_push_down";
+ ot->description = "Push action down on to the NLA stack as a new strip";
+
+ /* callbacks */
+ ot->exec = action_pushdown_exec;
+ ot->poll = action_pushdown_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ******************* Action Stash Operator ******************** */
+
+static int action_stash_exec(bContext *C, wmOperator *op)
+{
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Perform stashing operation */
+ if (adt) {
+ /* don't do anything if this action is empty... */
+ if (action_has_motion(adt->action) == 0) {
+ /* action may not be suitable... */
+ BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* stash the action */
+ if (BKE_nla_action_stash(adt)) {
+ /* The stash operation will remove the user already,
+ * so the flushing step later shouldn't double up
+ * the usercount fixes. Hence, we must unset this ref
+ * first before setting the new action.
+ */
+ saction->action = NULL;
+ }
+ else {
+ /* action has already been added - simply warn about this, and clear */
+ BKE_report(op->reports, RPT_ERROR, "Action has already been stashed");
+ }
+
+ /* clear action refs from editor, and then also the backing data (not necessary) */
+ actedit_change_action(C, NULL);
+ }
+ }
+
+ /* Send notifiers that stuff has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_stash(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Stash Action";
+ ot->idname = "ACTION_OT_stash";
+ ot->description = "Store this action in the NLA stack as a non-contributing strip for later use";
+
+ /* callbacks */
+ ot->exec = action_stash_exec;
+ ot->poll = action_pushdown_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_boolean(ot->srna, "create_new", true, "Create New Action",
+ "Create a new action once the existing one has been safely stored");
+}
+
+/* ----------------- */
+
+/* Criteria:
+ * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions
+ * 2) The associated AnimData block must not be in tweakmode
+ */
+static int action_stash_create_poll(bContext *C)
+{
+ if (ED_operator_action_active(C)) {
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */
+ /* NOTE: unlike for pushdown, this operator needs to be run when creating an action from nothing... */
+ if (adt) {
+ if (!(adt->flag & ADT_NLA_EDIT_ON))
+ return true;
+ }
+ else {
+ /* There may not be any action/animdata yet, so, just fallback to the global setting
+ * (which may not be totally valid yet if the action editor was used and things are
+ * now in an inconsistent state)
+ */
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ Scene *scene = CTX_data_scene(C);
+
+ if (!(scene->flag & SCE_NLA_EDIT_ON)) {
+ /* For now, actions are only for the active object, and on object and shapekey levels... */
+ return ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY);
+ }
+ }
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_stash_create_exec(bContext *C, wmOperator *op)
+{
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Check for no action... */
+ if (saction->action == NULL) {
+ /* just create a new action */
+ bAction *action = action_create_new(C, NULL);
+ actedit_change_action(C, action);
+ }
+ else if (adt) {
+ /* Perform stashing operation */
+ if (action_has_motion(adt->action) == 0) {
+ /* don't do anything if this action is empty... */
+ BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* stash the action */
+ if (BKE_nla_action_stash(adt)) {
+ bAction *new_action = NULL;
+
+ /* create new action not based on the old one (since the "new" operator already does that) */
+ new_action = action_create_new(C, NULL);
+
+ /* The stash operation will remove the user already,
+ * so the flushing step later shouldn't double up
+ * the usercount fixes. Hence, we must unset this ref
+ * first before setting the new action.
+ */
+ saction->action = NULL;
+ actedit_change_action(C, new_action);
+ }
+ else {
+ /* action has already been added - simply warn about this, and clear */
+ BKE_report(op->reports, RPT_ERROR, "Action has already been stashed");
+ actedit_change_action(C, NULL);
+ }
+ }
+ }
+
+ /* Send notifiers that stuff has changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_stash_and_create(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Stash Action";
+ ot->idname = "ACTION_OT_stash_and_create";
+ ot->description = "Store this action in the NLA stack as a non-contributing strip for later use, and create a new action";
+
+ /* callbacks */
+ ot->exec = action_stash_create_exec;
+ ot->poll = action_stash_create_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ************************************************************************** */
+/* ACTION UNLINK */
+
+/* ******************* Action Unlink Operator ******************** */
+/* We use a custom unlink operator here, as there are some technicalities which need special care:
+ * 1) When in Tweak Mode, it shouldn't be possible to unlink the active action,
+ * or else, everything turns to custard.
+ * 2) If the Action doesn't have any other users, the user should at least get
+ * a warning that it is going to get lost.
+ * 3) We need a convenient way to exit Tweak Mode from the Action Editor
+ */
+
+void ED_animedit_unlink_action(bContext *C, ID *id, AnimData *adt, bAction *act, ReportList *reports)
+{
+ ScrArea *sa = CTX_wm_area(C);
+
+ /* If the old action only has a single user (that it's about to lose),
+ * warn user about it
+ *
+ * TODO: Maybe we should just save it for them? But then, there's the problem of
+ * trying to get rid of stuff that's actually unwanted!
+ */
+ if (act->id.us == 1) {
+ BKE_reportf(reports, RPT_WARNING,
+ "Action '%s' will not be saved, create Fake User or Stash in NLA Stack to retain",
+ act->id.name + 2);
+ }
+
+ /* If in Tweak Mode, don't unlink. Instead, this
+ * becomes a shortcut to exit Tweak Mode instead
+ */
+ if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) {
+ /* Exit Tweak Mode */
+ BKE_nla_tweakmode_exit(adt);
+
+ /* Flush this to the Action Editor (if that's where this change was initiated) */
+ if (sa->spacetype == SPACE_ACTION) {
+ actedit_change_action(C, NULL);
+ }
+ }
+ else {
+ /* Unlink normally - Setting it to NULL should be enough to get the old one unlinked */
+ if (sa->spacetype == SPACE_ACTION) {
+ /* clear action editor -> action */
+ actedit_change_action(C, NULL);
+ }
+ else {
+ /* clear AnimData -> action */
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ /* create AnimData RNA pointers */
+ RNA_pointer_create(id, &RNA_AnimData, adt, &ptr);
+ prop = RNA_struct_find_property(&ptr, "action");
+
+ /* clear... */
+ RNA_property_pointer_set(&ptr, prop, PointerRNA_NULL);
+ RNA_property_update(C, &ptr, prop);
+ }
+ }
+}
+
+/* -------------------------- */
+
+static int action_unlink_poll(bContext *C)
+{
+ if (ED_operator_action_active(C)) {
+ SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ /* Only when there's an active action, in the right modes... */
+ if (saction->action && adt)
+ return true;
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_unlink_exec(bContext *C, wmOperator *op)
+{
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+
+ if (adt && adt->action) {
+ ED_animedit_unlink_action(C, NULL, adt, adt->action, op->reports);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_unlink(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Unlink Action";
+ ot->idname = "ACTION_OT_unlink";
+ ot->description = "Unlink this action from the active action slot (and/or exit Tweak Mode)";
+
+ /* callbacks */
+ ot->exec = action_unlink_exec;
+ ot->poll = action_unlink_poll;
+}
+
+/* ************************************************************************** */
+/* ACTION BROWSING */
+
+/* Try to find NLA Strip to use for action layer up/down tool */
+static NlaStrip *action_layer_get_nlastrip(ListBase *strips, float ctime)
+{
+ NlaStrip *strip;
+
+ for (strip = strips->first; strip; strip = strip->next) {
+ /* Can we use this? */
+ if (IN_RANGE_INCL(ctime, strip->start, strip->end)) {
+ /* in range - use this one */
+ return strip;
+ }
+ else if ((ctime < strip->start) && (strip->prev == NULL)) {
+ /* before first - use this one */
+ return strip;
+ }
+ else if ((ctime > strip->end) && (strip->next == NULL)) {
+ /* after last - use this one */
+ return strip;
+ }
+ }
+
+ /* nothing suitable found... */
+ return NULL;
+}
+
+/* Switch NLA Strips/Actions */
+static void action_layer_switch_strip(AnimData *adt,
+ NlaTrack *old_track, NlaStrip *old_strip,
+ NlaTrack *nlt, NlaStrip *strip)
+{
+ /* Exit tweakmode on old strip
+ * NOTE: We need to manually clear this stuff ourselves, as tweakmode exit doesn't do it
+ */
+ BKE_nla_tweakmode_exit(adt);
+
+ if (old_strip) {
+ old_strip->flag &= ~(NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT);
+ }
+ if (old_track) {
+ old_track->flag &= ~(NLATRACK_ACTIVE | NLATRACK_SELECTED);
+ }
+
+ /* Make this one the active one instead */
+ strip->flag |= (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT);
+ nlt->flag |= NLATRACK_ACTIVE;
+
+ /* Copy over "solo" flag - This is useful for stashed actions... */
+ if (old_track) {
+ if (old_track->flag & NLATRACK_SOLO) {
+ old_track->flag &= ~NLATRACK_SOLO;
+ nlt->flag |= NLATRACK_SOLO;
+ }
+ }
+ else {
+ /* NLA muting <==> Solo Tracks */
+ if (adt->flag & ADT_NLA_EVAL_OFF) {
+ /* disable NLA muting */
+ adt->flag &= ~ADT_NLA_EVAL_OFF;
+
+ /* mark this track as being solo */
+ adt->flag |= ADT_NLA_SOLO_TRACK;
+ nlt->flag |= NLATRACK_SOLO;
+
+ // TODO: Needs restpose flushing (when we get reference track)
+ }
+ }
+
+ /* Enter tweakmode again - hopefully we're now "it" */
+ BKE_nla_tweakmode_enter(adt);
+ BLI_assert(adt->actstrip == strip);
+}
+
+/* ********************** One Layer Up Operator ************************** */
+
+static int action_layer_next_poll(bContext *C)
+{
+ /* Action Editor's action editing modes only */
+ if (ED_operator_action_active(C)) {
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+ if (adt) {
+ /* only allow if we're in tweakmode, and there's something above us... */
+ if (adt->flag & ADT_NLA_EDIT_ON) {
+ /* We need to check if there are any tracks above the active one
+ * since the track the action comes from is not stored in AnimData
+ */
+ if (adt->nla_tracks.last) {
+ NlaTrack *nlt = (NlaTrack *)adt->nla_tracks.last;
+
+ if (nlt->flag & NLATRACK_DISABLED) {
+ /* A disabled track will either be the track itself,
+ * or one of the ones above it.
+ *
+ * If this is the top-most one, there is the possibility
+ * that there is no active action. For now, we let this
+ * case return true too, so that there is a natural way
+ * to "move to an empty layer", even though this means
+ * that we won't actually have an action.
+ */
+ // return (adt->tmpact != NULL);
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_layer_next_exec(bContext *C, wmOperator *op)
+{
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+ NlaTrack *act_track;
+
+ Scene *scene = CTX_data_scene(C);
+ float ctime = BKE_scene_frame_get(scene);
+
+ /* Get active track */
+ act_track = BKE_nlatrack_find_tweaked(adt);
+
+ if (act_track == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Could not find current NLA Track");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Find next action, and hook it up */
+ if (act_track->next) {
+ NlaTrack *nlt;
+
+ /* Find next action to use */
+ for (nlt = act_track->next; nlt; nlt = nlt->next) {
+ NlaStrip *strip = action_layer_get_nlastrip(&nlt->strips, ctime);
+
+ if (strip) {
+ action_layer_switch_strip(adt, act_track, adt->actstrip, nlt, strip);
+ break;
+ }
+ }
+ }
+ else {
+ /* No more actions (strips) - Go back to editing the original active action
+ * NOTE: This will mean exiting tweakmode...
+ */
+ BKE_nla_tweakmode_exit(adt);
+
+ /* Deal with solo flags...
+ * Assume: Solo Track == NLA Muting
+ */
+ if (adt->flag & ADT_NLA_SOLO_TRACK) {
+ /* turn off solo flags on tracks */
+ act_track->flag &= ~NLATRACK_SOLO;
+ adt->flag &= ~ADT_NLA_SOLO_TRACK;
+
+ /* turn on NLA muting (to keep same effect) */
+ adt->flag |= ADT_NLA_EVAL_OFF;
+
+ // TODO: Needs restpose flushing (when we get reference track)
+ }
+ }
+
+ /* Update the action that this editor now uses
+ * NOTE: The calls above have already handled the usercount/animdata side of things
+ */
+ actedit_change_action(C, adt->action);
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_layer_next(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Next Layer";
+ ot->idname = "ACTION_OT_layer_next";
+ ot->description = "Switch to editing action in animation layer above the current action in the NLA Stack";
+
+ /* callbacks */
+ ot->exec = action_layer_next_exec;
+ ot->poll = action_layer_next_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************* One Layer Down Operator ************************* */
+
+static int action_layer_prev_poll(bContext *C)
+{
+ /* Action Editor's action editing modes only */
+ if (ED_operator_action_active(C)) {
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+ if (adt) {
+ if (adt->flag & ADT_NLA_EDIT_ON) {
+ /* Tweak Mode: We need to check if there are any tracks below the active one that we can move to */
+ if (adt->nla_tracks.first) {
+ NlaTrack *nlt = (NlaTrack *)adt->nla_tracks.first;
+
+ /* Since the first disabled track is the track being tweaked/edited,
+ * we can simplify things by only checking the first track:
+ * - If it is disabled, this is the track being tweaked,
+ * so there can't be anything below it
+ * - Otherwise, there is at least 1 track below the tweaking
+ * track that we can descend to
+ */
+ if ((nlt->flag & NLATRACK_DISABLED) == 0) {
+ /* not disabled = there are actions below the one being tweaked */
+ return true;
+ }
+ }
+ }
+ else {
+ /* Normal Mode: If there are any tracks, we can try moving to those */
+ return (adt->nla_tracks.first != NULL);
+ }
+ }
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int action_layer_prev_exec(bContext *C, wmOperator *op)
+{
+ AnimData *adt = ED_actedit_animdata_from_context(C);
+ NlaTrack *act_track;
+ NlaTrack *nlt;
+
+ Scene *scene = CTX_data_scene(C);
+ float ctime = BKE_scene_frame_get(scene);
+
+ /* Sanity Check */
+ if (adt == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Internal Error: Could not find Animation Data/NLA Stack to use");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Get active track */
+ act_track = BKE_nlatrack_find_tweaked(adt);
+
+ /* If there is no active track, that means we are using the active action... */
+ if (act_track) {
+ /* Active Track - Start from the one below it */
+ nlt = act_track->prev;
+ }
+ else {
+ /* Active Action - Use the top-most track */
+ nlt = adt->nla_tracks.last;
+ }
+
+ /* Find previous action and hook it up */
+ for (; nlt; nlt = nlt->prev) {
+ NlaStrip *strip = action_layer_get_nlastrip(&nlt->strips, ctime);
+
+ if (strip) {
+ action_layer_switch_strip(adt, act_track, adt->actstrip, nlt, strip);
+ break;
+ }
+ }
+
+ /* Update the action that this editor now uses
+ * NOTE: The calls above have already handled the usercount/animdata side of things
+ */
+ actedit_change_action(C, adt->action);
+ return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_layer_prev(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Previous Layer";
+ ot->idname = "ACTION_OT_layer_prev";
+ ot->description = "Switch to editing action in animation layer below the current action in the NLA Stack";
+
+ /* callbacks */
+ ot->exec = action_layer_prev_exec;
+ ot->poll = action_layer_prev_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ************************************************************************** */
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index a17cfa4d87c..10748c2fe15 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -93,6 +93,8 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
/* loop through channels, and set up drawing depending on their type */
{ /* first pass: just the standard GL-drawing for backdrop + text */
+ size_t channel_index = 0;
+
y = (float)ACHANNEL_FIRST;
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -104,11 +106,12 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
{
/* draw all channels using standard channel-drawing API */
- ANIM_channel_draw(ac, ale, yminc, ymaxc);
+ ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index);
}
/* adjust y-position for next one */
y -= ACHANNEL_STEP;
+ channel_index++;
}
}
{ /* second pass: widgets */
@@ -210,7 +213,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
{
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
int sel = 0;
/* determine if any need to draw channel */
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 76c955d8bca..a28b4c1a4f2 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -80,418 +80,6 @@
#include "action_intern.h"
-/* ************************************************************************** */
-/* ACTION MANAGEMENT */
-
-/* Helper function to find the active AnimData block from the Action Editor context */
-static AnimData *actedit_animdata_from_context(bContext *C)
-{
- SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
- Object *ob = CTX_data_active_object(C);
- AnimData *adt = NULL;
-
- /* Get AnimData block to use */
- if (saction->mode == SACTCONT_ACTION) {
- /* Currently, "Action Editor" means object-level only... */
- adt = ob->adt;
- }
- else if (saction->mode == SACTCONT_SHAPEKEY) {
- Key *key = BKE_key_from_object(ob);
- adt = key->adt;
- }
-
- return adt;
-}
-
-/* Create new action */
-static bAction *action_create_new(bContext *C, bAction *oldact)
-{
- ScrArea *sa = CTX_wm_area(C);
- bAction *action;
-
- /* create action - the way to do this depends on whether we've got an
- * existing one there already, in which case we make a copy of it
- * (which is useful for "versioning" actions within the same file)
- */
- if (oldact && GS(oldact->id.name) == ID_AC) {
- /* make a copy of the existing action */
- action = BKE_action_copy(oldact);
- }
- else {
- /* just make a new (empty) action */
- action = add_empty_action(CTX_data_main(C), "Action");
- }
-
- /* when creating new ID blocks, there is already 1 user (as for all new datablocks),
- * but the RNA pointer code will assign all the proper users instead, so we compensate
- * for that here
- */
- BLI_assert(action->id.us == 1);
- action->id.us--;
-
- /* set ID-Root type */
- if (sa->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
-
- if (saction->mode == SACTCONT_SHAPEKEY)
- action->idroot = ID_KE;
- else
- action->idroot = ID_OB;
- }
-
- return action;
-}
-
-/* Change the active action used by the action editor */
-static void actedit_change_action(bContext *C, bAction *act)
-{
- bScreen *screen = CTX_wm_screen(C);
- SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
-
- PointerRNA ptr, idptr;
- PropertyRNA *prop;
-
- /* create RNA pointers and get the property */
- RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, saction, &ptr);
- prop = RNA_struct_find_property(&ptr, "action");
-
- /* NOTE: act may be NULL here, so better to just use a cast here */
- RNA_id_pointer_create((ID *)act, &idptr);
-
- /* set the new pointer, and force a refresh */
- RNA_property_pointer_set(&ptr, prop, idptr);
- RNA_property_update(C, &ptr, prop);
-}
-
-/* ******************** New Action Operator *********************** */
-
-/* Criteria:
- * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions...
- * OR
- * The NLA Editor is active (i.e. Animation Data panel -> new action)
- * 2) The associated AnimData block must not be in tweakmode
- */
-static int action_new_poll(bContext *C)
-{
- Scene *scene = CTX_data_scene(C);
-
- /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */
- /* NOTE: unlike for pushdown, this operator needs to be run when creating an action from nothing... */
- if (!(scene->flag & SCE_NLA_EDIT_ON)) {
- if (ED_operator_action_active(C)) {
- SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
-
- /* For now, actions are only for the active object, and on object and shapekey levels... */
- return ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY);
- }
- else if (ED_operator_nla_active(C)) {
- return true;
- }
- }
-
- /* something failed... */
- return false;
-}
-
-static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
-{
- PointerRNA ptr, idptr;
- PropertyRNA *prop;
-
- /* hook into UI */
- UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
-
- if (prop) {
- bAction *action = NULL, *oldact = NULL;
- AnimData *adt = NULL;
- PointerRNA oldptr;
-
- oldptr = RNA_property_pointer_get(&ptr, prop);
- oldact = (bAction *)oldptr.id.data;
-
- /* stash the old action to prevent it from being lost */
- if (ptr.type == &RNA_AnimData) {
- adt = ptr.data;
- }
- else if (ptr.type == &RNA_SpaceDopeSheetEditor) {
- adt = actedit_animdata_from_context(C);
- }
-
- /* Perform stashing operation - But only if there is an action */
- if (adt && oldact) {
- /* stash the action */
- if (BKE_nla_action_stash(adt)) {
- /* The stash operation will remove the user already
- * (and unlink the action from the AnimData action slot).
- * Hence, we must unset the ref to the action in the
- * action editor too (if this is where we're being called from)
- * first before setting the new action once it is created,
- * or else the user gets decremented twice!
- */
- if (ptr.type == &RNA_SpaceDopeSheetEditor) {
- SpaceAction *saction = (SpaceAction *)ptr.data;
- saction->action = NULL;
- }
- }
- else {
- //printf("WARNING: Failed to stash %s. It may already exist in the NLA stack though\n", oldact->id.name);
- }
- }
-
- /* create action */
- action = action_create_new(C, oldact);
-
- /* set this new action
- * NOTE: we can't use actedit_change_action, as this function is also called from the NLA
- */
- RNA_id_pointer_create(&action->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr);
- RNA_property_update(C, &ptr, prop);
- }
-
- /* set notifier that keyframes have changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void ACTION_OT_new(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "New Action";
- ot->idname = "ACTION_OT_new";
- ot->description = "Create new action";
-
- /* api callbacks */
- ot->exec = action_new_exec;
- ot->poll = action_new_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ******************* Action Push-Down Operator ******************** */
-
-/* Criteria:
- * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions
- * 2) There must be an action active
- * 3) The associated AnimData block must not be in tweakmode
- */
-static int action_pushdown_poll(bContext *C)
-{
- if (ED_operator_action_active(C)) {
- SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
-
- /* Check for actions and that tweakmode is off */
- if ((saction->action) && !(scene->flag & SCE_NLA_EDIT_ON)) {
- /* For now, actions are only for the active object, and on object and shapekey levels... */
- if (saction->mode == SACTCONT_ACTION) {
- return (ob->adt != NULL);
- }
- else if (saction->mode == SACTCONT_SHAPEKEY) {
- Key *key = BKE_key_from_object(ob);
-
- return (key && key->adt);
- }
- }
- }
-
- /* something failed... */
- return false;
-}
-
-static int action_pushdown_exec(bContext *C, wmOperator *op)
-{
- SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
- AnimData *adt = actedit_animdata_from_context(C);
-
- /* Do the deed... */
- if (adt) {
- /* Perform the pushdown operation
- * - This will deal with all the AnimData-side usercounts
- */
- if (action_has_motion(adt->action) == 0) {
- /* action may not be suitable... */
- BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
- return OPERATOR_CANCELLED;
- }
- else {
- /* action can be safely added */
- BKE_nla_action_pushdown(adt);
- }
-
- /* Stop displaying this action in this editor
- * NOTE: The editor itself doesn't set a user...
- */
- saction->action = NULL;
- }
-
- /* Send notifiers that stuff has changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
- return OPERATOR_FINISHED;
-}
-
-void ACTION_OT_push_down(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Push Down Action";
- ot->idname = "ACTION_OT_push_down";
- ot->description = "Push action down on to the NLA stack as a new strip";
-
- /* callbacks */
- ot->exec = action_pushdown_exec;
- ot->poll = action_pushdown_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ******************* Action Stash Operator ******************** */
-
-static int action_stash_exec(bContext *C, wmOperator *op)
-{
- SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
- AnimData *adt = actedit_animdata_from_context(C);
-
- /* Perform stashing operation */
- if (adt) {
- /* don't do anything if this action is empty... */
- if (action_has_motion(adt->action) == 0) {
- /* action may not be suitable... */
- BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
- return OPERATOR_CANCELLED;
- }
- else {
- /* stash the action */
- if (BKE_nla_action_stash(adt)) {
- /* The stash operation will remove the user already,
- * so the flushing step later shouldn't double up
- * the usercount fixes. Hence, we must unset this ref
- * first before setting the new action.
- */
- saction->action = NULL;
- }
- else {
- /* action has already been added - simply warn about this, and clear */
- BKE_report(op->reports, RPT_ERROR, "Action has already been stashed");
- }
-
- /* clear action refs from editor, and then also the backing data (not necessary) */
- actedit_change_action(C, NULL);
- }
- }
-
- /* Send notifiers that stuff has changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
- return OPERATOR_FINISHED;
-}
-
-void ACTION_OT_stash(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Stash Action";
- ot->idname = "ACTION_OT_stash";
- ot->description = "Store this action in the NLA stack as a non-contributing strip for later use";
-
- /* callbacks */
- ot->exec = action_stash_exec;
- ot->poll = action_pushdown_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_boolean(ot->srna, "create_new", true, "Create New Action",
- "Create a new action once the existing one has been safely stored");
-}
-
-/* ----------------- */
-
-/* Criteria:
- * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions
- * 2) The associated AnimData block must not be in tweakmode
- */
-static int action_stash_create_poll(bContext *C)
-{
- if (ED_operator_action_active(C)) {
- SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
- Scene *scene = CTX_data_scene(C);
-
- /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */
- /* NOTE: unlike for pushdown, this operator needs to be run when creating an action from nothing... */
- if (!(scene->flag & SCE_NLA_EDIT_ON)) {
- /* For now, actions are only for the active object, and on object and shapekey levels... */
- return ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY);
- }
- }
-
- /* something failed... */
- return false;
-}
-
-static int action_stash_create_exec(bContext *C, wmOperator *op)
-{
- SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
- AnimData *adt = actedit_animdata_from_context(C);
-
- /* Check for no action... */
- if (saction->action == NULL) {
- /* just create a new action */
- bAction *action = action_create_new(C, NULL);
- actedit_change_action(C, action);
- }
- else if (adt) {
- /* Perform stashing operation */
- if (action_has_motion(adt->action) == 0) {
- /* don't do anything if this action is empty... */
- BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
- return OPERATOR_CANCELLED;
- }
- else {
- /* stash the action */
- if (BKE_nla_action_stash(adt)) {
- bAction *new_action = NULL;
-
- /* create new action not based on the old one (since the "new" operator already does that) */
- new_action = action_create_new(C, NULL);
-
- /* The stash operation will remove the user already,
- * so the flushing step later shouldn't double up
- * the usercount fixes. Hence, we must unset this ref
- * first before setting the new action.
- */
- saction->action = NULL;
- actedit_change_action(C, new_action);
- }
- else {
- /* action has already been added - simply warn about this, and clear */
- BKE_report(op->reports, RPT_ERROR, "Action has already been stashed");
- actedit_change_action(C, NULL);
- }
- }
- }
-
- /* Send notifiers that stuff has changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
- return OPERATOR_FINISHED;
-}
-
-void ACTION_OT_stash_and_create(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Stash Action";
- ot->idname = "ACTION_OT_stash_and_create";
- ot->description = "Store this action in the NLA stack as a non-contributing strip for later use, and create a new action";
-
- /* callbacks */
- ot->exec = action_stash_create_exec;
- ot->poll = action_stash_create_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
/* ************************************************************************** */
/* POSE MARKERS STUFF */
@@ -738,7 +326,7 @@ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min,
y = (float)ACHANNEL_FIRST;
for (ale = anim_data.first; ale; ale = ale->next) {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* must be selected... */
if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) &&
@@ -837,7 +425,15 @@ static int actkeys_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
/* only selected */
return actkeys_viewall(C, true);
}
-
+
+static int actkeys_view_frame_exec(bContext *C, wmOperator *op)
+{
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ANIM_center_frame(C, smooth_viewtx);
+
+ return OPERATOR_FINISHED;
+}
+
void ACTION_OT_view_all(wmOperatorType *ot)
{
/* identifiers */
@@ -868,6 +464,21 @@ void ACTION_OT_view_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+void ACTION_OT_view_frame(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "View Frame";
+ ot->idname = "ACTION_OT_view_frame";
+ ot->description = "Reset viewable area to show range around current frame";
+
+ /* api callbacks */
+ ot->exec = actkeys_view_frame_exec;
+ ot->poll = ED_operator_action_active; /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ************************************************************************** */
/* GENERAL STUFF */
@@ -1068,8 +679,13 @@ static void insert_action_keys(bAnimContext *ac, short mode)
else
cfra = (float)CFRA;
- /* if there's an id */
- if (ale->id)
+ /* read value from property the F-Curve represents, or from the curve only?
+ * - ale->id != NULL: Typically, this means that we have enough info to try resolving the path
+ * - ale->owner != NULL: If this is set, then the path may not be resolvable from the ID alone,
+ * so it's easier for now to just read the F-Curve directly.
+ * (TODO: add the full-blown PointerRNA relative parsing case here...)
+ */
+ if (ale->id && !ale->owner)
insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
else
insert_vert_fcurve(fcu, cfra, fcu->curval, 0);
@@ -1142,7 +758,7 @@ static void duplicate_action_keys(bAnimContext *ac)
/* loop through filtered data and delete selected keys */
for (ale = anim_data.first; ale; ale = ale->next) {
- if (ale->type == ANIMTYPE_FCURVE)
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE))
duplicate_fcurve_keys((FCurve *)ale->key_data);
else if (ale->type == ANIMTYPE_GPLAYER)
ED_gplayer_frames_duplicate((bGPDlayer *)ale->data);
@@ -1176,13 +792,6 @@ static int actkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-
-static int actkeys_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- actkeys_duplicate_exec(C, op);
-
- return OPERATOR_FINISHED;
-}
void ACTION_OT_duplicate(wmOperatorType *ot)
{
@@ -1192,7 +801,6 @@ void ACTION_OT_duplicate(wmOperatorType *ot)
ot->description = "Make a copy of all selected keyframes";
/* api callbacks */
- ot->invoke = actkeys_duplicate_invoke;
ot->exec = actkeys_duplicate_exec;
ot->poll = ED_operator_action_active;
@@ -1290,7 +898,7 @@ void ACTION_OT_delete(wmOperatorType *ot)
/* ******************** Clean Keyframes Operator ************************* */
-static void clean_action_keys(bAnimContext *ac, float thresh)
+static void clean_action_keys(bAnimContext *ac, float thresh, bool clean_chan)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -1302,7 +910,7 @@ static void clean_action_keys(bAnimContext *ac, float thresh)
/* loop through filtered data and clean curves */
for (ale = anim_data.first; ale; ale = ale->next) {
- clean_fcurve((FCurve *)ale->key_data, thresh);
+ clean_fcurve(ac, ale, thresh, clean_chan);
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -1317,6 +925,7 @@ static int actkeys_clean_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
float thresh;
+ bool clean_chan;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -1329,9 +938,10 @@ static int actkeys_clean_exec(bContext *C, wmOperator *op)
/* get cleaning threshold */
thresh = RNA_float_get(op->ptr, "threshold");
+ clean_chan = RNA_boolean_get(op->ptr, "channels");
/* clean keyframes */
- clean_action_keys(&ac, thresh);
+ clean_action_keys(&ac, thresh, clean_chan);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -1356,6 +966,7 @@ void ACTION_OT_clean(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
+ RNA_def_boolean(ot->srna, "channels", false, "Channels", "");
}
/* ******************** Sample Keyframes Operator *********************** */
diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h
index 61d4249ae20..17f1f404225 100644
--- a/source/blender/editors/space_action/action_intern.h
+++ b/source/blender/editors/space_action/action_intern.h
@@ -35,10 +35,7 @@ struct bContext;
struct bAnimContext;
struct SpaceAction;
struct ARegion;
-struct wmWindowManager;
struct wmOperatorType;
-struct ActKeysInc;
-struct bAnimListElem;
/* internal exports only */
@@ -80,6 +77,7 @@ enum eActKeys_ColumnSelect_Mode {
void ACTION_OT_previewrange_set(struct wmOperatorType *ot);
void ACTION_OT_view_all(struct wmOperatorType *ot);
void ACTION_OT_view_selected(struct wmOperatorType *ot);
+void ACTION_OT_view_frame(struct wmOperatorType *ot);
void ACTION_OT_copy(struct wmOperatorType *ot);
void ACTION_OT_paste(struct wmOperatorType *ot);
@@ -101,10 +99,15 @@ void ACTION_OT_snap(struct wmOperatorType *ot);
void ACTION_OT_mirror(struct wmOperatorType *ot);
void ACTION_OT_new(struct wmOperatorType *ot);
+void ACTION_OT_unlink(struct wmOperatorType *ot);
+
void ACTION_OT_push_down(struct wmOperatorType *ot);
void ACTION_OT_stash(struct wmOperatorType *ot);
void ACTION_OT_stash_and_create(struct wmOperatorType *ot);
+void ACTION_OT_layer_next(struct wmOperatorType *ot);
+void ACTION_OT_layer_prev(struct wmOperatorType *ot);
+
void ACTION_OT_markers_make_local(struct wmOperatorType *ot);
/* defines for snap keyframes
diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c
index 8c706d8da57..59b147c6f6c 100644
--- a/source/blender/editors/space_action/action_ops.c
+++ b/source/blender/editors/space_action/action_ops.c
@@ -79,14 +79,20 @@ void action_operatortypes(void)
WM_operatortype_append(ACTION_OT_paste);
WM_operatortype_append(ACTION_OT_new);
+ WM_operatortype_append(ACTION_OT_unlink);
+
WM_operatortype_append(ACTION_OT_push_down);
WM_operatortype_append(ACTION_OT_stash);
WM_operatortype_append(ACTION_OT_stash_and_create);
+ WM_operatortype_append(ACTION_OT_layer_next);
+ WM_operatortype_append(ACTION_OT_layer_prev);
+
WM_operatortype_append(ACTION_OT_previewrange_set);
WM_operatortype_append(ACTION_OT_view_all);
WM_operatortype_append(ACTION_OT_view_selected);
-
+ WM_operatortype_append(ACTION_OT_view_frame);
+
WM_operatortype_append(ACTION_OT_markers_make_local);
}
@@ -101,6 +107,7 @@ void ED_operatormacros_action(void)
WM_operatortype_macro_define(ot, "ACTION_OT_duplicate");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_transform");
RNA_enum_set(otmacro->ptr, "mode", TFM_TIME_DUPLICATE);
+ RNA_enum_set(otmacro->ptr, "proportional", PROP_EDIT_OFF);
}
/* ************************** registration - keymaps **********************************/
@@ -197,11 +204,10 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
WM_keymap_add_item(keymap, "ACTION_OT_keyframe_type", RKEY, KM_PRESS, 0, 0);
/* destructive */
- WM_keymap_add_item(keymap, "ACTION_OT_clean", OKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACTION_OT_sample", OKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "ACTION_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ACTION_OT_delete", DELKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "DOPESHEET_MT_delete", XKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "DOPESHEET_MT_delete", DELKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACTION_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ACTION_OT_keyframe_insert", IKEY, KM_PRESS, 0, 0);
@@ -223,6 +229,8 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
WM_keymap_add_item(keymap, "ACTION_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACTION_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACTION_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "ACTION_OT_view_frame", PAD0, KM_PRESS, 0, 0);
+
/* animation module */
/* channels list
@@ -236,6 +244,9 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
/* transform system */
transform_keymap_for_space(keyconf, keymap, SPACE_ACTION);
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", OKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_proportional_action");
+
/* special markers hotkeys for anim editors: see note in definition of this function */
ED_marker_keymap_animedit_conflictfree(keymap);
}
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index ddfca98a119..0f94baff082 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -1221,11 +1221,11 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
agrp->flag |= AGRP_SELECTED;
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
}
- else if (ale->type == ANIMTYPE_FCURVE) {
+ else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
FCurve *fcu = ale->data;
fcu->flag |= FCURVE_SELECTED;
- ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
+ ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
}
}
}
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index c606ae52c4e..d827761f473 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -103,6 +103,7 @@ void ED_spacetypes_init(void)
ED_operatortypes_anim();
ED_operatortypes_animchannels();
ED_operatortypes_gpencil();
+ ED_operatortypes_hair();
ED_operatortypes_object();
ED_operatortypes_mesh();
ED_operatortypes_sculpt();
@@ -182,6 +183,7 @@ void ED_spacetypes_keymap(wmKeyConfig *keyconf)
ED_keymap_anim(keyconf);
ED_keymap_animchannels(keyconf);
ED_keymap_gpencil(keyconf);
+ ED_keymap_hair(keyconf);
ED_keymap_object(keyconf); /* defines lattice also */
ED_keymap_mesh(keyconf);
ED_keymap_uvedit(keyconf);
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 73091e7f261..bc42f1dd5bb 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -59,6 +59,7 @@
#include "RNA_access.h"
+#include "ED_buttons.h"
#include "ED_armature.h"
#include "ED_screen.h"
#include "ED_physics.h"
@@ -1179,3 +1180,33 @@ ID *buttons_context_id_path(const bContext *C)
return NULL;
}
+
+void ED_buttons_id_unref(SpaceButs *sbuts, const ID *id)
+{
+ if (sbuts->pinid == id) {
+ sbuts->pinid = NULL;
+ sbuts->flag &= ~SB_PIN_CONTEXT;
+ }
+
+ if (sbuts->path) {
+ ButsContextPath *path = sbuts->path;
+ int i;
+
+ for (i = 0; i < path->len; i++) {
+ if (path->ptr[i].id.data == id) {
+ break;
+ }
+ }
+
+ if (i == path->len) {
+ /* pass */
+ }
+ else if (i == 0) {
+ MEM_SAFE_FREE(sbuts->path);
+ }
+ else {
+ memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
+ path->len = i;
+ }
+ }
+}
diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h
index f294729ae97..7fc35a6b1e7 100644
--- a/source/blender/editors/space_buttons/buttons_intern.h
+++ b/source/blender/editors/space_buttons/buttons_intern.h
@@ -34,7 +34,6 @@
#include "DNA_listBase.h"
#include "RNA_types.h"
-struct ARegion;
struct ARegionType;
struct ID;
struct SpaceButs;
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 6c55d8d034e..6bd7788a958 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -307,7 +307,7 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar,
/* set zoom */
glPixelZoom(zoomx * width / ibuf->x, zoomy * height / ibuf->y);
- glaDrawImBuf_glsl_ctx(C, ibuf, x, y, filter);
+ glaDrawImBuf_glsl_ctx(C, ibuf, x, y, filter, 1.0f);
/* reset zoom */
glPixelZoom(1.0f, 1.0f);
@@ -1123,7 +1123,9 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane
{
bool tiny = (sc->flag & SC_SHOW_TINY_MARKER) != 0;
bool is_selected_track = (plane_track->flag & SELECT) != 0;
- bool draw_plane_quad = plane_track->image == NULL || plane_track->image_opacity == 0.0f;
+ const bool has_image = plane_track->image != NULL &&
+ BKE_image_has_ibuf(plane_track->image, NULL);
+ const bool draw_plane_quad = !has_image || plane_track->image_opacity == 0.0f;
float px[2];
if (draw_outline) {
@@ -1692,29 +1694,29 @@ void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar)
}
if (sc->flag & SC_SHOW_STABLE) {
+ float translation[2];
+ float aspect = clip->tracking.camera.pixel_aspect;
float smat[4][4], ismat[4][4];
- ibuf = ED_space_clip_get_stable_buffer(sc, sc->loc, &sc->scale, &sc->angle);
-
- if (ibuf) {
- float translation[2];
- float aspect = clip->tracking.camera.pixel_aspect;
+ if ((sc->flag & SC_MUTE_FOOTAGE) == 0) {
+ ibuf = ED_space_clip_get_stable_buffer(sc, sc->loc,
+ &sc->scale, &sc->angle);
+ }
- if (width != ibuf->x)
- mul_v2_v2fl(translation, sc->loc, (float)width / ibuf->x);
- else
- copy_v2_v2(translation, sc->loc);
+ if (ibuf != NULL && width != ibuf->x)
+ mul_v2_v2fl(translation, sc->loc, (float)width / ibuf->x);
+ else
+ copy_v2_v2(translation, sc->loc);
- BKE_tracking_stabilization_data_to_mat4(width, height, aspect,
- translation, sc->scale, sc->angle, sc->stabmat);
+ BKE_tracking_stabilization_data_to_mat4(width, height, aspect, translation,
+ sc->scale, sc->angle, sc->stabmat);
- unit_m4(smat);
- smat[0][0] = 1.0f / width;
- smat[1][1] = 1.0f / height;
- invert_m4_m4(ismat, smat);
+ unit_m4(smat);
+ smat[0][0] = 1.0f / width;
+ smat[1][1] = 1.0f / height;
+ invert_m4_m4(ismat, smat);
- mul_m4_series(sc->unistabmat, smat, sc->stabmat, ismat);
- }
+ mul_m4_series(sc->unistabmat, smat, sc->stabmat, ismat);
}
else if ((sc->flag & SC_MUTE_FOOTAGE) == 0) {
ibuf = ED_space_clip_get_buffer(sc);
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 89693a403fe..d67c03f3622 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -626,8 +626,9 @@ static bool check_prefetch_break(void)
}
/* read file for specified frame number to the memory */
-static unsigned char *prefetch_read_file_to_memory(MovieClip *clip, int current_frame, short render_size,
- short render_flag, size_t *size_r)
+static unsigned char *prefetch_read_file_to_memory(
+ MovieClip *clip, int current_frame, short render_size, short render_flag,
+ size_t *r_size)
{
MovieClipUser user = {0};
char name[FILE_MAX];
@@ -660,7 +661,7 @@ static unsigned char *prefetch_read_file_to_memory(MovieClip *clip, int current_
return NULL;
}
- *size_r = size;
+ *r_size = size;
close(file);
@@ -698,8 +699,9 @@ static int prefetch_find_uncached_frame(MovieClip *clip, int from_frame, int end
}
/* get memory buffer for first uncached frame within prefetch frame range */
-static unsigned char *prefetch_thread_next_frame(PrefetchQueue *queue, MovieClip *clip,
- size_t *size_r, int *current_frame_r)
+static unsigned char *prefetch_thread_next_frame(
+ PrefetchQueue *queue, MovieClip *clip,
+ size_t *r_size, int *r_current_frame)
{
unsigned char *mem = NULL;
@@ -728,9 +730,9 @@ static unsigned char *prefetch_thread_next_frame(PrefetchQueue *queue, MovieClip
int frames_processed;
mem = prefetch_read_file_to_memory(clip, current_frame, queue->render_size,
- queue->render_flag, size_r);
+ queue->render_flag, r_size);
- *current_frame_r = current_frame;
+ *r_current_frame = current_frame;
queue->current_frame = current_frame;
@@ -765,13 +767,15 @@ static void prefetch_task_func(TaskPool *pool, void *task_data, int UNUSED(threa
int flag = IB_rect | IB_alphamode_detect;
int result;
char *colorspace_name = NULL;
+ const bool use_proxy = (clip->flag & MCLIP_USE_PROXY) &&
+ (queue->render_size != MCLIP_PROXY_RENDER_SIZE_FULL);
user.framenr = current_frame;
user.render_size = queue->render_size;
user.render_flag = queue->render_flag;
/* Proxies are stored in the display space. */
- if (queue->render_flag & MCLIP_USE_PROXY) {
+ if (!use_proxy) {
colorspace_name = clip->colorspace_settings.name;
}
diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c
index 2a2f15c94bb..e781d199d35 100644
--- a/source/blender/editors/space_clip/clip_graph_ops.c
+++ b/source/blender/editors/space_clip/clip_graph_ops.c
@@ -200,10 +200,18 @@ static bool mouse_select_knot(bContext *C, float co[2], bool extend)
toggle_selection_cb);
}
- if (userdata.coord == 0)
- userdata.marker->flag |= MARKER_GRAPH_SEL_X;
- else
- userdata.marker->flag |= MARKER_GRAPH_SEL_Y;
+ if (userdata.coord == 0) {
+ if (extend && (userdata.marker->flag & MARKER_GRAPH_SEL_X) != 0)
+ userdata.marker->flag &= ~MARKER_GRAPH_SEL_X;
+ else
+ userdata.marker->flag |= MARKER_GRAPH_SEL_X;
+ }
+ else {
+ if (extend && (userdata.marker->flag & MARKER_GRAPH_SEL_Y) != 0)
+ userdata.marker->flag &= ~MARKER_GRAPH_SEL_Y;
+ else
+ userdata.marker->flag |= MARKER_GRAPH_SEL_Y;
+ }
return true;
}
@@ -238,10 +246,12 @@ static bool mouse_select_curve(bContext *C, float co[2], bool extend)
else if (act_track != userdata.track) {
SelectUserData selectdata = {SEL_DESELECT};
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
tracking->act_track = userdata.track;
- BKE_tracking_track_select(tracksbase, userdata.track, TRACK_AREA_ALL, true);
+ if ((sc->flag & SC_SHOW_GRAPH_SEL_ONLY) == 0) {
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
+ BKE_tracking_track_select(tracksbase, userdata.track, TRACK_AREA_ALL, false);
+ }
/* deselect all knots on newly selected curve */
clip_graph_tracking_iterate(sc,
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 322825ccc84..232b2fe7e1e 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -658,7 +658,7 @@ void CLIP_OT_view_zoom(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
/* properties */
prop = RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX, "Factor",
@@ -912,7 +912,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
SUBFRA = 0.0f;
/* do updates */
- sound_seek_scene(CTX_data_main(C), scene);
+ BKE_sound_seek_scene(CTX_data_main(C), scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
@@ -999,7 +999,7 @@ void CLIP_OT_change_frame(wmOperatorType *ot)
ot->poll = change_frame_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO;
+ ot->flag = OPTYPE_BLOCKING;
/* rna */
RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index 5f919c9b51d..48f8f587106 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -177,9 +177,7 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
MovieTracking *tracking = &clip->tracking;
MovieTrackingStabilization *stab = &tracking->stabilization;
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
- MovieTrackingPlaneTrack *plane_track, *next_plane_track;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
bool has_bundle = false, update_stab = false;
char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2];
@@ -197,49 +195,7 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
has_bundle = true;
/* Make sure no plane will use freed track */
- for (plane_track = plane_tracks_base->first;
- plane_track;
- plane_track = next_plane_track)
- {
- bool found = false;
- int i;
-
- next_plane_track = plane_track->next;
-
- for (i = 0; i < plane_track->point_tracksnr; i++) {
- if (plane_track->point_tracks[i] == track) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- continue;
- }
-
- if (plane_track->point_tracksnr > 4) {
- int track_index;
- MovieTrackingTrack **new_point_tracks;
-
- new_point_tracks = MEM_mallocN(sizeof(*new_point_tracks) * plane_track->point_tracksnr,
- "new point tracks array");
-
- for (i = 0, track_index = 0; i < plane_track->point_tracksnr; i++) {
- if (plane_track->point_tracks[i] != track) {
- new_point_tracks[track_index++] = plane_track->point_tracks[i];
- }
- }
-
- MEM_freeN(plane_track->point_tracks);
- plane_track->point_tracks = new_point_tracks;
- plane_track->point_tracksnr--;
- }
- else {
- /* Delete planes with less than 3 point tracks in it. */
- BKE_tracking_plane_track_free(plane_track);
- BLI_freelinkN(plane_tracks_base, plane_track);
- }
- }
+ BKE_tracking_plane_tracks_remove_point_track(tracking, track);
/* Delete f-curves associated with the track (such as weight, i.e.) */
BLI_strescape(track_name_escaped, track->name, sizeof(track_name_escaped));
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index fc2c0d3d45c..5ba82f7f71f 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -206,7 +206,7 @@ static void clip_scopes_tag_refresh(ScrArea *sa)
if (sc->mode != SC_MODE_TRACKING)
return;
- /* only while proeprties are visible */
+ /* only while properties are visible */
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->regiontype == RGN_TYPE_UI && ar->flag & RGN_FLAG_HIDDEN)
return;
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index 742e58d80dd..538c1a4e5ea 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -825,12 +825,8 @@ static void apply_mouse_slide(bContext *C, SlideMarkerData *data)
plane_track = plane_track->next)
{
if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
- int i;
- for (i = 0; i < plane_track->point_tracksnr; i++) {
- if (plane_track->point_tracks[i] == data->track) {
- BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
- break;
- }
+ if (BKE_tracking_plane_track_has_point_track(plane_track, data->track)) {
+ BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
}
}
}
@@ -1070,7 +1066,7 @@ void CLIP_OT_slide_marker(wmOperatorType *ot)
ot->modal = slide_marker_modal;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
/* properties */
RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
@@ -1883,7 +1879,7 @@ void CLIP_OT_clear_track_path(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* proeprties */
+ /* properties */
RNA_def_enum(ot->srna, "action", clear_path_actions, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
RNA_def_boolean(ot->srna, "clear_active", 0, "Clear Active", "Clear active track only instead of all selected tracks");
}
@@ -2042,7 +2038,7 @@ static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat
bool found = false;
for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (!cti)
continue;
@@ -2073,7 +2069,7 @@ static Object *object_solver_camera(Scene *scene, Object *ob)
bConstraint *con;
for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (!cti)
continue;
@@ -3054,7 +3050,7 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
if (CFRA != sc->user.framenr) {
CFRA = sc->user.framenr;
- sound_seek_scene(CTX_data_main(C), scene);
+ BKE_sound_seek_scene(CTX_data_main(C), scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
@@ -3117,6 +3113,12 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
if (tracking->stabilization.rot_track == track)
tracking->stabilization.rot_track = act_track;
+ /* TODO(sergey): Re-evaluate planes with auto-key. */
+ BKE_tracking_plane_tracks_replace_point_track(tracking,
+ track,
+ act_track);
+
+
BKE_tracking_track_free(track);
BLI_freelinkN(tracksbase, track);
}
@@ -4181,7 +4183,7 @@ void CLIP_OT_slide_plane_marker(wmOperatorType *ot)
ot->modal = slide_plane_marker_modal;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
}
/********************** Insert track keyframe operator *********************/
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index bc6ac507f03..8a2bf17c667 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -62,7 +62,6 @@ static float dist_to_crns(float co[2], float pos[2], float crns[4][2]);
static int mouse_on_side(float co[2], float x1, float y1, float x2, float y2, float epsx, float epsy)
{
if (x1 > x2)
-
SWAP(float, x1, x2);
if (y1 > y2)
@@ -998,6 +997,6 @@ void CLIP_OT_select_grouped(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* proeprties */
+ /* properties */
RNA_def_enum(ot->srna, "group", select_group_items, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
}
diff --git a/source/blender/editors/space_console/console_intern.h b/source/blender/editors/space_console/console_intern.h
index 00f1f8c21c9..d8a4a6fd2bb 100644
--- a/source/blender/editors/space_console/console_intern.h
+++ b/source/blender/editors/space_console/console_intern.h
@@ -31,7 +31,6 @@
struct ConsoleLine;
struct wmOperatorType;
-struct ReportList;
struct bContext;
/* console_draw.c */
@@ -66,6 +65,7 @@ void CONSOLE_OT_history_cycle(struct wmOperatorType *ot);
void CONSOLE_OT_copy(struct wmOperatorType *ot);
void CONSOLE_OT_paste(struct wmOperatorType *ot);
void CONSOLE_OT_select_set(struct wmOperatorType *ot);
+void CONSOLE_OT_select_word(struct wmOperatorType *ot);
enum { LINE_BEGIN, LINE_END, PREV_CHAR, NEXT_CHAR, PREV_WORD, NEXT_WORD };
enum { DEL_ALL, DEL_NEXT_CHAR, DEL_PREV_CHAR, DEL_NEXT_WORD, DEL_PREV_WORD, DEL_SELECTION, DEL_NEXT_SEL, DEL_PREV_SEL };
diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c
index 8263268898f..92731c2f135 100644
--- a/source/blender/editors/space_console/console_ops.c
+++ b/source/blender/editors/space_console/console_ops.c
@@ -262,6 +262,40 @@ static int console_line_insert(ConsoleLine *ci, char *str)
return len;
}
+/**
+ * Take an absolute index and give the line/column info.
+ *
+ * \note be sure to call console_scrollback_prompt_begin first
+ */
+static bool console_line_column_from_index(
+ SpaceConsole *sc, const int pos,
+ ConsoleLine **r_cl, int *r_cl_offset, int *r_col)
+{
+ ConsoleLine *cl;
+ int offset = 0;
+
+ for (cl = sc->scrollback.last; cl; cl = cl->prev) {
+ offset += cl->len + 1;
+ if (offset >= pos) {
+ break;
+ }
+ }
+
+ if (cl) {
+ offset -= 1;
+ *r_cl = cl;
+ *r_cl_offset = offset;
+ *r_col = offset - pos;
+ return true;
+ }
+ else {
+ *r_cl = NULL;
+ *r_cl_offset = -1;
+ *r_col = -1;
+ return false;
+ }
+}
+
/* static funcs for text editing */
/* similar to the text editor, with some not used. keep compatible */
@@ -1134,3 +1168,57 @@ void CONSOLE_OT_select_set(wmOperatorType *ot)
ot->cancel = console_modal_select_cancel;
ot->poll = ED_operator_console_active;
}
+
+static int console_selectword_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ SpaceConsole *sc = CTX_wm_space_console(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ ConsoleLine cl_dummy = {NULL};
+ ConsoleLine *cl;
+ int ret = OPERATOR_CANCELLED;
+ int pos, offset, n;
+
+ pos = console_char_pick(sc, ar, event->mval);
+
+ console_scrollback_prompt_begin(sc, &cl_dummy);
+
+ if (console_line_column_from_index(sc, pos, &cl, &offset, &n)) {
+ int sel[2] = {n, n};
+
+ BLI_str_cursor_step_utf8(
+ cl->line, cl->len,
+ &sel[0], STRCUR_DIR_NEXT,
+ STRCUR_JUMP_DELIM, true);
+
+ BLI_str_cursor_step_utf8(
+ cl->line, cl->len,
+ &sel[1], STRCUR_DIR_PREV,
+ STRCUR_JUMP_DELIM, true);
+
+ sel[0] = offset - sel[0];
+ sel[1] = offset - sel[1];
+
+ if ((sel[0] != sc->sel_start) || (sel[1] != sc->sel_end)) {
+ sc->sel_start = sel[0];
+ sc->sel_end = sel[1];
+ ED_area_tag_redraw(CTX_wm_area(C));
+ ret = OPERATOR_FINISHED;
+ }
+ }
+
+ console_scrollback_prompt_end(sc, &cl_dummy);
+ return ret;
+}
+
+void CONSOLE_OT_select_word(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Word";
+ ot->description = "Select word at cursor position";
+ ot->idname = "CONSOLE_OT_select_word";
+
+ /* api callbacks */
+ ot->invoke = console_selectword_invoke;
+ ot->poll = ED_operator_console_active;
+}
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index e4a61a8f06e..a592f35f629 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -270,6 +270,7 @@ static void console_operatortypes(void)
WM_operatortype_append(CONSOLE_OT_copy);
WM_operatortype_append(CONSOLE_OT_paste);
WM_operatortype_append(CONSOLE_OT_select_set);
+ WM_operatortype_append(CONSOLE_OT_select_word);
}
static void console_keymap(struct wmKeyConfig *keyconf)
@@ -348,6 +349,7 @@ static void console_keymap(struct wmKeyConfig *keyconf)
#endif
WM_keymap_add_item(keymap, "CONSOLE_OT_select_set", LEFTMOUSE, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "CONSOLE_OT_select_word", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
RNA_string_set(WM_keymap_add_item(keymap, "CONSOLE_OT_insert", TABKEY, KM_PRESS, KM_CTRL, 0)->ptr, "text", "\t"); /* fake tabs */
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 98c7ddeff77..db10aa14060 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -64,6 +64,7 @@
#include "UI_resources.h"
#include "UI_view2d.h"
+#include "WM_api.h"
#include "WM_types.h"
#include "filelist.h"
@@ -254,8 +255,13 @@ static int get_file_icon(struct direntry *file)
return ICON_FILE_BLEND;
else if (file->flags & FILE_TYPE_BLENDER_BACKUP)
return ICON_FILE_BACKUP;
- else if (file->flags & FILE_TYPE_IMAGE)
- return ICON_FILE_IMAGE;
+ else if (file->flags & FILE_TYPE_IMAGE) {
+ if (file->selflag & FILE_SEL_COLLAPSED) {
+ return ICON_FILE_MOVIE;
+ }
+ else
+ return ICON_FILE_IMAGE;
+ }
else if (file->flags & FILE_TYPE_MOVIE)
return ICON_FILE_MOVIE;
else if (file->flags & FILE_TYPE_PYSCRIPT)
@@ -295,22 +301,29 @@ static void file_draw_icon(uiBlock *block, char *path, int sx, int sy, int icon,
static void file_draw_string(int sx, int sy, const char *string, float width, int height, short align)
{
- uiStyle *style = UI_style_get();
- uiFontStyle fs = style->widgetlabel;
+ uiStyle *style;
+ uiFontStyle fs;
rcti rect;
char fname[FILE_MAXFILE];
+ if (string[0] == '\0') {
+ return;
+ }
+
+ style = UI_style_get();
+ fs = style->widgetlabel;
+
fs.align = align;
BLI_strncpy(fname, string, FILE_MAXFILE);
- file_shorten_string(fname, width + 1.0f, 0);
+ UI_text_clip_middle_ex(&fs, fname, width, UI_DPI_ICON_SIZE, sizeof(fname), '\0');
/* no text clipping needed, UI_fontstyle_draw does it but is a bit too strict (for buttons it works) */
rect.xmin = sx;
- rect.xmax = (int)(sx + ceil(width + 4.0f));
+ rect.xmax = (int)(sx + ceil(width + 5.0f / UI_DPI_FAC));
rect.ymin = sy - height;
rect.ymax = sy;
-
+
UI_fontstyle_draw(&fs, &rect, fname);
}
@@ -323,35 +336,40 @@ void file_calc_previews(const bContext *C, ARegion *ar)
UI_view2d_totRect_set(v2d, sfile->layout->width, sfile->layout->height);
}
-static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int sy, ImBuf *imb, FileLayout *layout, bool dropshadow, bool drag)
+static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int sy, ImBuf *imb, FileLayout *layout, bool is_icon, bool drag, bool play)
{
uiBut *but;
float fx, fy;
float dx, dy;
int xco, yco;
+ float ui_imbx, ui_imby;
float scaledx, scaledy;
float scale;
int ex, ey;
+ bool use_dropshadow = !is_icon && (file->flags & FILE_TYPE_IMAGE);
BLI_assert(imb != NULL);
- if ((imb->x * UI_DPI_FAC > layout->prv_w) ||
- (imb->y * UI_DPI_FAC > layout->prv_h))
+ ui_imbx = imb->x * UI_DPI_FAC;
+ ui_imby = imb->y * UI_DPI_FAC;
+ /* Unlike thumbnails, icons are not scaled up. */
+ if (((ui_imbx > layout->prv_w) || (ui_imby > layout->prv_h)) ||
+ (!is_icon && ((ui_imbx < layout->prv_w) || (ui_imby < layout->prv_h))))
{
if (imb->x > imb->y) {
scaledx = (float)layout->prv_w;
- scaledy = ( (float)imb->y / (float)imb->x) * layout->prv_w;
+ scaledy = ((float)imb->y / (float)imb->x) * layout->prv_w;
scale = scaledx / imb->x;
}
else {
scaledy = (float)layout->prv_h;
- scaledx = ( (float)imb->x / (float)imb->y) * layout->prv_h;
+ scaledx = ((float)imb->x / (float)imb->y) * layout->prv_h;
scale = scaledy / imb->y;
}
}
else {
- scaledx = (float)imb->x * UI_DPI_FAC;
- scaledy = (float)imb->y * UI_DPI_FAC;
+ scaledx = ui_imbx;
+ scaledy = ui_imby;
scale = UI_DPI_FAC;
}
@@ -367,17 +385,23 @@ static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
/* shadow */
- if (dropshadow)
+ if (use_dropshadow) {
UI_draw_box_shadow(220, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
+ }
glEnable(GL_BLEND);
/* the image */
- glColor4f(1.0, 1.0, 1.0, 1.0);
+ if (!is_icon && file->flags & FILE_TYPE_FTFONT) {
+ UI_ThemeColor(TH_TEXT);
+ }
+ else {
+ glColor4f(1.0, 1.0, 1.0, 1.0);
+ }
glaDrawPixelsTexScaled((float)xco, (float)yco, imb->x, imb->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, imb->rect, scale, scale);
/* border */
- if (dropshadow) {
+ if (use_dropshadow) {
glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
fdrawbox((float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
}
@@ -388,6 +412,24 @@ static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int
UI_but_drag_set_image(but, file->path, get_file_icon(file), imb, scale);
}
+ if (play && !is_icon) {
+ float r = MIN2(ey, ex) / 6.0f;
+ float yr = sqrt(3) / 2 * r;
+ float xr = r / 2;
+ glPushMatrix();
+ glTranslatef(xco + ex / 2.0f, yco + ey / 2.0f, 0.0);
+ glColor4f(1.0f, 1.0f, 1.0f, 0.8);
+ glutil_draw_filled_arc(0.0f, 2.0f * M_PI, ey / 4.0f, 32);
+ glColor4f(0.3f, 0.3f, 1.0f, 0.8f);
+ glutil_draw_filled_arc_part(0.0f, 2.0f * M_PI, ey / 4.0f, ey / 5.0f, 32);
+ glBegin(GL_TRIANGLES);
+ glVertex2f(-xr, yr);
+ glVertex2f(-xr, -yr);
+ glVertex2f(r, 0.0f);
+ glEnd();
+ glPopMatrix();
+ }
+
glDisable(GL_BLEND);
}
@@ -485,6 +527,7 @@ void file_draw_list(const bContext *C, ARegion *ar)
bool is_icon;
short align;
bool do_drag;
+ bool do_play;
int column_space = 0.6f * UI_UNIT_X;
numfiles = filelist_numfiles(files);
@@ -542,14 +585,24 @@ void file_draw_list(const bContext *C, ARegion *ar)
do_drag = !(FILENAME_IS_CURRPAR(file->relname));
if (FILE_IMGDISPLAY == params->display) {
- is_icon = 0;
+ is_icon = false;
imb = filelist_getimage(files, i);
if (!imb) {
imb = filelist_geticon(files, i);
- is_icon = 1;
+ is_icon = true;
}
- file_draw_preview(block, file, sx, sy, imb, layout, !is_icon && (file->flags & FILE_TYPE_IMAGE), do_drag);
+ do_play = (file->selflag & FILE_SEL_COLLAPSED) && !(file->selflag & FILE_SEL_PLAYING);
+
+ file_draw_preview(block, file, sx, sy, imb, layout, is_icon, do_drag, do_play);
+
+ if ((file->selflag & FILE_SEL_COLLAPSED) && (file->selflag & FILE_SEL_PLAYING)) {
+ /* refresh to keep movie playing */
+ file->collapsed_info.curfra++;
+ file->collapsed_info.curfra %= file->collapsed_info.totfiles;
+
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+ }
}
else {
file_draw_icon(block, file->path, sx, sy - (UI_UNIT_Y / 6), get_file_icon(file), ICON_DEFAULT_WIDTH_SCALE, ICON_DEFAULT_HEIGHT_SCALE, do_drag);
@@ -587,43 +640,71 @@ void file_draw_list(const bContext *C, ARegion *ar)
if (!(file->selflag & FILE_SEL_EDITING)) {
int tpos = (FILE_IMGDISPLAY == params->display) ? sy - layout->tile_h + layout->textheight : sy;
- file_draw_string(sx + 1, tpos, file->relname, (float)textwidth, textheight, align);
+ if (file->selflag & FILE_SEL_COLLAPSED) {
+ char fname[PATH_MAX];
+ char finalname[PATH_MAX];
+ char ext[PATH_MAX];
+ CollapsedEntry *collapsed = &file->collapsed_info;
+ BLI_strncpy(fname, file->relname, sizeof(fname));
+ BLI_path_frame_strip(fname, false, ext);
+ BLI_snprintf(finalname, sizeof(finalname), "%s%.*d-%.*d%s",
+ fname, collapsed->numdigits, collapsed->minframe, collapsed->numdigits, collapsed->maxframe, ext);
+ file_draw_string(sx + 1, tpos, finalname, (float)textwidth, textheight, align);
+ }
+ else
+ file_draw_string(sx + 1, tpos, file->relname, (float)textwidth, textheight, align);
}
if (params->display == FILE_SHORTDISPLAY) {
sx += (int)layout->column_widths[COLUMN_NAME] + column_space;
if (!(file->type & S_IFDIR)) {
- file_draw_string(sx, sy, file->size, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
+ if (file->selflag & FILE_SEL_COLLAPSED) {
+ CollapsedEntry *collapsed = &file->collapsed_info;
+ char sizestr[16];
+ BLI_file_size_string(collapsed->totalsize, sizestr, sizeof(sizestr));
+ file_draw_string(sx, sy, sizestr, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
+ }
+ else
+ file_draw_string(sx, sy, file->size, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
}
}
else if (params->display == FILE_LONGDISPLAY) {
sx += (int)layout->column_widths[COLUMN_NAME] + column_space;
+ /* for collapsed files it doesn't make sense to display all info */
+ if (file->selflag & FILE_SEL_COLLAPSED) {
+ char sizestr[16];
+ CollapsedEntry *collapsed = &file->collapsed_info;
+ BLI_file_size_string(collapsed->totalsize, sizestr, sizeof(sizestr));
+ file_draw_string(sx, sy, sizestr, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
+ }
+ else {
#ifndef WIN32
- /* rwx rwx rwx */
- file_draw_string(sx, sy, file->mode1, layout->column_widths[COLUMN_MODE1], layout->tile_h, align);
- sx += layout->column_widths[COLUMN_MODE1] + column_space;
+ /* rwx rwx rwx */
+ file_draw_string(sx, sy, file->mode1, layout->column_widths[COLUMN_MODE1], layout->tile_h, align);
+ sx += layout->column_widths[COLUMN_MODE1] + column_space;
- file_draw_string(sx, sy, file->mode2, layout->column_widths[COLUMN_MODE2], layout->tile_h, align);
- sx += layout->column_widths[COLUMN_MODE2] + column_space;
+ file_draw_string(sx, sy, file->mode2, layout->column_widths[COLUMN_MODE2], layout->tile_h, align);
+ sx += layout->column_widths[COLUMN_MODE2] + column_space;
- file_draw_string(sx, sy, file->mode3, layout->column_widths[COLUMN_MODE3], layout->tile_h, align);
- sx += layout->column_widths[COLUMN_MODE3] + column_space;
+ file_draw_string(sx, sy, file->mode3, layout->column_widths[COLUMN_MODE3], layout->tile_h, align);
+ sx += layout->column_widths[COLUMN_MODE3] + column_space;
- file_draw_string(sx, sy, file->owner, layout->column_widths[COLUMN_OWNER], layout->tile_h, align);
- sx += layout->column_widths[COLUMN_OWNER] + column_space;
+ file_draw_string(sx, sy, file->owner, layout->column_widths[COLUMN_OWNER], layout->tile_h, align);
+ sx += layout->column_widths[COLUMN_OWNER] + column_space;
#endif
- file_draw_string(sx, sy, file->date, layout->column_widths[COLUMN_DATE], layout->tile_h, align);
- sx += (int)layout->column_widths[COLUMN_DATE] + column_space;
+ file_draw_string(sx, sy, file->date, layout->column_widths[COLUMN_DATE], layout->tile_h, align);
+ sx += (int)layout->column_widths[COLUMN_DATE] + column_space;
- file_draw_string(sx, sy, file->time, layout->column_widths[COLUMN_TIME], layout->tile_h, align);
- sx += (int)layout->column_widths[COLUMN_TIME] + column_space;
+ file_draw_string(sx, sy, file->time, layout->column_widths[COLUMN_TIME], layout->tile_h, align);
+ sx += (int)layout->column_widths[COLUMN_TIME] + column_space;
- if (!(file->type & S_IFDIR)) {
- file_draw_string(sx, sy, file->size, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
- sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
+ if (!(file->type & S_IFDIR)) {
+ file_draw_string(sx, sy, file->size, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
+ sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
+ }
}
}
}
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index e7a6cd62a33..dbb5e8a773d 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -59,7 +59,6 @@ bool file_draw_check_exists(SpaceFile *sfile);
/* file_ops.h */
struct wmOperatorType;
struct wmOperator;
-struct wmEvent;
void FILE_OT_highlight(struct wmOperatorType *ot);
void FILE_OT_select(struct wmOperatorType *ot);
void FILE_OT_select_all_toggle(struct wmOperatorType *ot);
@@ -102,7 +101,6 @@ void file_operator_to_sfile(struct SpaceFile *sfile, struct wmOperator *op);
/* filesel.c */
-float file_shorten_string(char *string, float w, int front);
float file_string_width(const char *str);
float file_font_pointsize(void);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index f8d13bb6adb..19dbaefa258 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -224,7 +224,7 @@ static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select,
/* flag the files as selected in the filelist */
filelist_select(sfile->files, &sel, select, FILE_SEL_SELECTED, check_type);
-
+
/* Don't act on multiple selected files */
if (sel.first != sel.last) select = 0;
@@ -274,6 +274,7 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *
if (FILENAME_IS_CURRPAR(file->relname)) {
file->selflag &= ~FILE_SEL_HIGHLIGHTED;
+ file->collapsed_info.curfra = 0;
}
/* active_file gets highlighted as well - make sure it is no readonly file */
@@ -370,7 +371,15 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
else {
/* single select, deselect all selected first */
- if (!extend) file_deselect_all(sfile, FILE_SEL_SELECTED);
+ if (!(file->type & S_IFDIR) && (file->selflag & FILE_SEL_COLLAPSED)&& (file->selflag & FILE_SEL_SELECTED)) {
+ if (file->selflag & FILE_SEL_PLAYING) {
+ file->collapsed_info.curfra = 0;
+ }
+ file->selflag ^= FILE_SEL_PLAYING;
+ }
+ if (!extend) {
+ file_deselect_all(sfile, FILE_SEL_SELECTED);
+ }
}
}
}
@@ -803,6 +812,17 @@ int file_cancel_exec(bContext *C, wmOperator *UNUSED(unused))
SpaceFile *sfile = CTX_wm_space_file(C);
wmOperator *op = sfile->op;
+ if (op) {
+ PropertyRNA *prop;
+ if ((prop = RNA_struct_find_property(op->ptr, "collapse_images")) &&
+ (sfile->params->flag & FILE_COLLAPSE_IMAGES_TMP))
+ {
+ /* turn off collapsed flag if evoked from operator */
+ sfile->params->flag &= ~FILE_COLLAPSE_IMAGES_TMP;
+ sfile->params->flag &= ~FILE_COLLAPSE_IMAGES;
+ }
+ }
+
sfile->op = NULL;
WM_event_fileselect_event(wm, op, EVT_FILESELECT_CANCEL);
@@ -868,9 +888,26 @@ void file_sfile_to_operator(wmOperator *op, SpaceFile *sfile, char *filepath)
for (i = 0; i < numfiles; i++) {
if (filelist_is_selected(sfile->files, i, CHECK_FILES)) {
struct direntry *file = filelist_file(sfile->files, i);
- RNA_property_collection_add(op->ptr, prop, &itemptr);
- RNA_string_set(&itemptr, "name", file->relname);
- num_files++;
+
+ if (file->selflag & FILE_SEL_COLLAPSED) {
+ int j = 0;
+ CollapsedEntry *collapsed = &file->collapsed_info;
+
+ for (; j < collapsed->totfiles; j++) {
+ struct direntry *file_tmp = collapsed->darray[j];
+ RNA_property_collection_add(op->ptr, prop, &itemptr);
+ RNA_string_set(&itemptr, "name", file_tmp->relname);
+ num_files++;
+ }
+
+ MEM_freeN(collapsed->darray);
+ collapsed->darray = NULL;
+ }
+ else {
+ RNA_property_collection_add(op->ptr, prop, &itemptr);
+ RNA_string_set(&itemptr, "name", file->relname);
+ num_files++;
+ }
}
}
/* make sure the file specified in the filename button is added even if no files selected */
@@ -900,7 +937,13 @@ void file_sfile_to_operator(wmOperator *op, SpaceFile *sfile, char *filepath)
}
}
-
+ if ((prop = RNA_struct_find_property(op->ptr, "collapse_images")) &&
+ (sfile->params->flag & FILE_COLLAPSE_IMAGES_TMP))
+ {
+ /* turn off collapsed flag if evoked from operator */
+ sfile->params->flag &= ~FILE_COLLAPSE_IMAGES_TMP;
+ sfile->params->flag &= ~FILE_COLLAPSE_IMAGES;
+ }
}
}
@@ -1673,9 +1716,11 @@ static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
int numfiles = filelist_numfiles(sfile->files);
if ( (0 <= idx) && (idx < numfiles) ) {
struct direntry *file = filelist_file(sfile->files, idx);
- filelist_select_file(sfile->files, idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
- BLI_strncpy(sfile->params->renameedit, file->relname, FILE_MAXFILE);
- sfile->params->renamefile[0] = '\0';
+ if (!(file->selflag & FILE_SEL_COLLAPSED)) {
+ filelist_select_file(sfile->files, idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
+ BLI_strncpy(sfile->params->renameedit, file->relname, FILE_MAXFILE);
+ sfile->params->renamefile[0] = '\0';
+ }
}
ED_area_tag_redraw(sa);
}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 66acd7d05e3..ee42e14c86c 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -35,6 +35,7 @@
#include <stdlib.h>
#include <math.h>
#include <string.h>
+#include <ctype.h>
#ifndef WIN32
# include <unistd.h>
@@ -49,6 +50,7 @@
#include "BLI_fnmatch.h"
#include "BLI_linklist.h"
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
#ifdef WIN32
# include "BLI_winstuff.h"
@@ -208,9 +210,11 @@ typedef struct FileImage {
typedef struct FileListFilter {
bool hide_dot;
bool hide_parent;
+ bool collapse_ima_seq;
unsigned int filter;
char filter_glob[64];
- char filter_search[66]; /* + 2 for heading/trailing implicit '*' wildcards. */
+ char filter_search[66]; /* + 2 for heading/trailing implicit '*' wildcards. */
+ GHash *unique_image_list; /* hash that stores unique filename */
} FileListFilter;
typedef struct FileList {
@@ -464,6 +468,55 @@ static bool is_filtered_file(struct direntry *file, const char *UNUSED(root), Fi
}
}
+ if (is_filtered && !(file->type & S_IFDIR) && filter->collapse_ima_seq) {
+ if (file->relname) {
+ struct direntry *ofile;
+ int frame, numdigits;
+
+ if (BLI_path_frame_get(file->relname, &frame, &numdigits)) {
+ char filename[PATH_MAX];
+
+ BLI_strncpy(filename, file->relname, sizeof(filename));
+ BLI_path_frame_strip(filename, false, NULL);
+
+ if ((ofile = BLI_ghash_lookup(filter->unique_image_list, filename)) &&
+ numdigits == ofile->collapsed_info.numdigits)
+ {
+ CollapsedEntry *collapsed = &ofile->collapsed_info;
+ is_filtered = false;
+ ofile->selflag |= FILE_SEL_COLLAPSED;
+ file->selflag |= FILE_SEL_COLLAPSED;
+ file->frame = frame;
+ BLI_addhead(&collapsed->list, BLI_genericNodeN(file));
+ collapsed->totalsize += file->realsize;
+ collapsed->maxframe = MAX2(frame, collapsed->maxframe);
+ collapsed->minframe = MIN2(frame, collapsed->minframe);
+ collapsed->totfiles++;
+ }
+ else {
+ if (file->collapsed_info.darray) {
+ MEM_freeN(file->collapsed_info.darray);
+ file->collapsed_info.darray = NULL;
+ }
+ BLI_ghash_insert(filter->unique_image_list, BLI_strdup(filename), file);
+ file->frame = frame;
+ file->collapsed_info.totalsize = file->realsize;
+ file->collapsed_info.maxframe = file->collapsed_info.minframe = frame;
+ file->collapsed_info.numdigits = numdigits;
+ file->collapsed_info.totfiles = 1;
+ }
+ }
+ }
+ }
+ else {
+ if (file->collapsed_info.darray) {
+ MEM_freeN(file->collapsed_info.darray);
+ file->collapsed_info.darray = NULL;
+ }
+ /* may have been set in a previous filtering iteration, so always clear */
+ file->selflag &= ~FILE_SEL_COLLAPSED;
+ }
+
return is_filtered;
}
@@ -500,6 +553,17 @@ static void filelist_filter_clear(FileList *filelist)
filelist->numfiltered = 0;
}
+static int compareFrame(const void *pa, const void *pb)
+{
+ struct direntry *a = *((struct direntry **)pa);
+ struct direntry *b = *((struct direntry **)pb);
+ if (a->frame < b->frame)
+ return -1;
+ if (a->frame > b->frame)
+ return 1;
+ return 0;
+}
+
void filelist_filter(FileList *filelist)
{
int num_filtered = 0;
@@ -517,6 +581,11 @@ void filelist_filter(FileList *filelist)
fidx_tmp = MEM_mallocN(sizeof(*fidx_tmp) * (size_t)filelist->numfiles, __func__);
+ /* */
+ if (filelist->filter_data.collapse_ima_seq) {
+ filelist->filter_data.unique_image_list = BLI_ghash_str_new("image_seq_hash");
+ }
+
/* Filter remap & count how many files are left after filter in a single loop. */
for (i = 0; i < filelist->numfiles; ++i) {
struct direntry *file = &filelist->filelist[i];
@@ -526,6 +595,33 @@ void filelist_filter(FileList *filelist)
}
}
+ if (filelist->filter_data.unique_image_list) {
+ BLI_ghash_free(filelist->filter_data.unique_image_list, MEM_freeN, NULL);
+ filelist->filter_data.unique_image_list = NULL;
+ }
+
+ /* extra step, need to sort the file list according to frame */
+ if (filelist->filter_data.collapse_ima_seq) {
+ for (i = 0; i < num_filtered; i++) {
+ struct direntry *file = &filelist->filelist[fidx_tmp[i]];
+ if (file->selflag & FILE_SEL_COLLAPSED) {
+ LinkData *fdata = file->collapsed_info.list.first;
+ int j = 1;
+ file->collapsed_info.darray =
+ MEM_mallocN(sizeof(struct direntry *) * file->collapsed_info.totfiles, "collapsed files");
+ file->collapsed_info.darray[0] = file;
+
+ for (; fdata; fdata = fdata->next, j++) {
+ file->collapsed_info.darray[j] = fdata->data;
+ }
+ qsort(file->collapsed_info.darray, file->collapsed_info.totfiles, sizeof(struct direntry *), compareFrame);
+ if (file->collapsed_info.list.first) {
+ BLI_freelistN(&file->collapsed_info.list);
+ }
+ }
+ }
+ }
+
/* Note: maybe we could even accept filelist->fidx to be filelist->numfiles -len allocated? */
filelist->fidx = MEM_mallocN(sizeof(*filelist->fidx) * (size_t)num_filtered, __func__);
memcpy(filelist->fidx, fidx_tmp, sizeof(*filelist->fidx) * (size_t)num_filtered);
@@ -535,17 +631,20 @@ void filelist_filter(FileList *filelist)
}
void filelist_setfilter_options(FileList *filelist, const bool hide_dot, const bool hide_parent,
+ const bool collapse_ima_seq,
const unsigned int filter,
const char *filter_glob, const char *filter_search)
{
if ((filelist->filter_data.hide_dot != hide_dot) ||
(filelist->filter_data.hide_parent != hide_parent) ||
+ (filelist->filter_data.collapse_ima_seq != collapse_ima_seq) ||
(filelist->filter_data.filter != filter) ||
!STREQ(filelist->filter_data.filter_glob, filter_glob) ||
(BLI_strcmp_ignore_pad(filelist->filter_data.filter_search, filter_search, '*') != 0))
{
filelist->filter_data.hide_dot = hide_dot;
filelist->filter_data.hide_parent = hide_parent;
+ filelist->filter_data.collapse_ima_seq = collapse_ima_seq;
filelist->filter_data.filter = filter;
BLI_strncpy(filelist->filter_data.filter_glob, filter_glob, sizeof(filelist->filter_data.filter_glob));
@@ -611,6 +710,7 @@ ImBuf *filelist_getimage(struct FileList *filelist, const int index)
{
ImBuf *ibuf = NULL;
int fidx = 0;
+ struct direntry *file;
BLI_assert(G.background == false);
@@ -618,8 +718,15 @@ ImBuf *filelist_getimage(struct FileList *filelist, const int index)
return NULL;
}
fidx = filelist->fidx[index];
- ibuf = filelist->filelist[fidx].image;
+ file = filelist->filelist + fidx;
+ if (file->selflag & FILE_SEL_COLLAPSED) {
+ int curfra = file->collapsed_info.curfra;
+ ibuf = file->collapsed_info.darray[curfra]->image;
+ }
+ else {
+ ibuf = filelist->filelist[fidx].image;
+ }
return ibuf;
}
@@ -654,7 +761,7 @@ ImBuf *filelist_geticon(struct FileList *filelist, const int index)
if (file->flags & FILE_TYPE_BLENDER) {
ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE];
}
- else if ((file->flags & FILE_TYPE_MOVIE) || (file->flags & FILE_TYPE_MOVIE_ICON)) {
+ else if (file->flags & FILE_TYPE_MOVIE) {
ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE];
}
else if (file->flags & FILE_TYPE_SOUND) {
@@ -670,7 +777,10 @@ ImBuf *filelist_geticon(struct FileList *filelist, const int index)
ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE];
}
else if (file->flags & FILE_TYPE_IMAGE) {
- ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING];
+ if (file->selflag & FILE_SEL_COLLAPSED)
+ ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE];
+ else
+ ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING];
}
else if (file->flags & FILE_TYPE_BLENDER_BACKUP) {
ibuf = gSpecialFileImages[SPECIAL_IMG_BACKUP];
@@ -900,7 +1010,6 @@ static void filelist_setfiletypes(struct FileList *filelist)
file = filelist->filelist;
for (num = 0; num < filelist->numfiles; num++, file++) {
- file->type = file->s.st_mode; /* restore the mess below */
#ifndef __APPLE__
/* Don't check extensions for directories, allow in OSX cause bundles have extensions*/
if (file->type & S_IFDIR) {
@@ -1190,29 +1299,30 @@ static void filelist_from_main(struct FileList *filelist)
filelist->filelist[0].relname = BLI_strdup(FILENAME_PARENT);
filelist->filelist[1].relname = BLI_strdup("Scene");
- filelist->filelist[2].relname = BLI_strdup("Object");
- filelist->filelist[3].relname = BLI_strdup("Mesh");
- filelist->filelist[4].relname = BLI_strdup("Curve");
- filelist->filelist[5].relname = BLI_strdup("Metaball");
- filelist->filelist[6].relname = BLI_strdup("Material");
- filelist->filelist[7].relname = BLI_strdup("Texture");
- filelist->filelist[8].relname = BLI_strdup("Image");
- filelist->filelist[9].relname = BLI_strdup("Ika");
- filelist->filelist[10].relname = BLI_strdup("Wave");
- filelist->filelist[11].relname = BLI_strdup("Lattice");
- filelist->filelist[12].relname = BLI_strdup("Lamp");
- filelist->filelist[13].relname = BLI_strdup("Camera");
- filelist->filelist[14].relname = BLI_strdup("Ipo");
- filelist->filelist[15].relname = BLI_strdup("World");
- filelist->filelist[16].relname = BLI_strdup("Screen");
- filelist->filelist[17].relname = BLI_strdup("VFont");
- filelist->filelist[18].relname = BLI_strdup("Text");
- filelist->filelist[19].relname = BLI_strdup("Armature");
- filelist->filelist[20].relname = BLI_strdup("Action");
- filelist->filelist[21].relname = BLI_strdup("NodeTree");
- filelist->filelist[22].relname = BLI_strdup("Speaker");
+ filelist->filelist[2].relname = BLI_strdup("CacheLibrary");
+ filelist->filelist[3].relname = BLI_strdup("Object");
+ filelist->filelist[4].relname = BLI_strdup("Mesh");
+ filelist->filelist[5].relname = BLI_strdup("Curve");
+ filelist->filelist[6].relname = BLI_strdup("Metaball");
+ filelist->filelist[7].relname = BLI_strdup("Material");
+ filelist->filelist[8].relname = BLI_strdup("Texture");
+ filelist->filelist[9].relname = BLI_strdup("Image");
+ filelist->filelist[10].relname = BLI_strdup("Ika");
+ filelist->filelist[11].relname = BLI_strdup("Wave");
+ filelist->filelist[12].relname = BLI_strdup("Lattice");
+ filelist->filelist[13].relname = BLI_strdup("Lamp");
+ filelist->filelist[14].relname = BLI_strdup("Camera");
+ filelist->filelist[15].relname = BLI_strdup("Ipo");
+ filelist->filelist[16].relname = BLI_strdup("World");
+ filelist->filelist[17].relname = BLI_strdup("Screen");
+ filelist->filelist[18].relname = BLI_strdup("VFont");
+ filelist->filelist[19].relname = BLI_strdup("Text");
+ filelist->filelist[20].relname = BLI_strdup("Armature");
+ filelist->filelist[21].relname = BLI_strdup("Action");
+ filelist->filelist[22].relname = BLI_strdup("NodeTree");
+ filelist->filelist[23].relname = BLI_strdup("Speaker");
#ifdef WITH_FREESTYLE
- filelist->filelist[23].relname = BLI_strdup("FreestyleLineStyle");
+ filelist->filelist[24].relname = BLI_strdup("FreestyleLineStyle");
#endif
}
else {
@@ -1235,7 +1345,7 @@ static void filelist_from_main(struct FileList *filelist)
files = filelist->filelist;
- if (!filelist->filter_data.hide_parent) {
+ if (files && !filelist->filter_data.hide_parent) {
memset(&(filelist->filelist[0]), 0, sizeof(struct direntry));
filelist->filelist[0].relname = BLI_strdup(FILENAME_PARENT);
filelist->filelist[0].type |= S_IFDIR;
@@ -1247,7 +1357,7 @@ static void filelist_from_main(struct FileList *filelist)
for (id = lb->first; id; id = id->next) {
ok = 1;
if (ok) {
- if (!filelist->filter_data.hide_dot || id->name[2] != '.') {
+ if (files && (!filelist->filter_data.hide_dot || id->name[2] != '.')) {
memset(files, 0, sizeof(struct direntry));
if (id->lib == NULL) {
files->relname = BLI_strdup(id->name + 2);
@@ -1334,20 +1444,23 @@ static void thumbnails_startjob(void *tjv, short *stop, short *do_update, float
tj->do_update = do_update;
while ((*stop == 0) && (limg)) {
+ ThumbSource source = 0;
+
+ BLI_assert(limg->flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT |
+ FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP));
if (limg->flags & FILE_TYPE_IMAGE) {
- limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_IMAGE);
+ source = THB_SOURCE_IMAGE;
}
else if (limg->flags & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
- limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_BLEND);
+ source = THB_SOURCE_BLEND;
}
else if (limg->flags & FILE_TYPE_MOVIE) {
- limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_MOVIE);
- if (!limg->img) {
- /* remember that file can't be loaded via IMB_open_anim */
- limg->flags &= ~FILE_TYPE_MOVIE;
- limg->flags |= FILE_TYPE_MOVIE_ICON;
- }
+ source = THB_SOURCE_MOVIE;
}
+ else if (limg->flags & FILE_TYPE_FTFONT) {
+ source = THB_SOURCE_FONT;
+ }
+ limg->img = IMB_thumb_manage(limg->path, THB_LARGE, source);
*do_update = true;
PIL_sleep_ms(10);
limg = limg->next;
@@ -1363,11 +1476,6 @@ static void thumbnails_update(void *tjv)
while (limg) {
if (!limg->done && limg->img) {
tj->filelist->filelist[limg->index].image = IMB_dupImBuf(limg->img);
- /* update flag for movie files where thumbnail can't be created */
- if (limg->flags & FILE_TYPE_MOVIE_ICON) {
- tj->filelist->filelist[limg->index].flags &= ~FILE_TYPE_MOVIE;
- tj->filelist->filelist[limg->index].flags |= FILE_TYPE_MOVIE_ICON;
- }
limg->done = true;
IMB_freeImBuf(limg->img);
limg->img = NULL;
@@ -1408,7 +1516,7 @@ void thumbnails_start(FileList *filelist, const bContext *C)
continue;
}
if (!filelist->filelist[idx].image) {
- if (filelist->filelist[idx].flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE |
+ if (filelist->filelist[idx].flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT |
FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))
{
FileImage *limg = MEM_callocN(sizeof(*limg), __func__);
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index 797d54a89b1..c6c9ed8dcc9 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -40,12 +40,7 @@ extern "C" {
struct BlendHandle;
struct FileList;
struct FileSelection;
-struct FolderList;
-struct Main;
-struct ReportList;
-struct Scene;
struct direntry;
-struct rcti;
struct wmWindowManager;
typedef enum FileSelType {
@@ -74,6 +69,7 @@ bool filelist_need_sorting(struct FileList *filelist);
void filelist_sort(struct FileList *filelist);
void filelist_setfilter_options(struct FileList *filelist, const bool hide_dot, const bool hide_parent,
+ const bool collapse_ima_seq,
const unsigned int filter,
const char *filter_glob, const char *filter_search);
void filelist_filter(struct FileList *filelist);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 14b72eb8f6d..231712b1858 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -102,6 +102,8 @@ short ED_fileselect_set_params(SpaceFile *sfile)
/* set path to most recently opened .blend */
BLI_split_dirfile(G.main->name, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file));
sfile->params->filter_glob[0] = '\0';
+ /* set the default thumbnails size */
+ sfile->params->thumbnail_size = 128;
}
params = sfile->params;
@@ -228,6 +230,15 @@ short ED_fileselect_set_params(SpaceFile *sfile)
}
}
+ if (params->filter & FILE_TYPE_IMAGE) {
+ if ((prop = RNA_struct_find_property(op->ptr, "collapse_images"))) {
+ if (!(params->flag & FILE_COLLAPSE_IMAGES)) {
+ params->flag |= FILE_COLLAPSE_IMAGES_TMP;
+ params->flag |= FILE_COLLAPSE_IMAGES;
+ }
+ }
+ }
+
if (is_relative_path) {
if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) {
if (!RNA_property_is_set_ex(op->ptr, prop, false)) {
@@ -396,63 +407,23 @@ void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y)
}
}
-/* Shorten a string to a given width w.
- * If front is set, shorten from the front,
- * otherwise shorten from the end. */
-float file_shorten_string(char *string, float w, int front)
-{
- char temp[FILE_MAX];
- short shortened = 0;
- float sw = 0;
- float pad = 0;
-
- if (w <= 0) {
- *string = '\0';
- return 0.0;
- }
+float file_string_width(const char *str)
+{
+ uiStyle *style = UI_style_get();
+ float width;
- sw = file_string_width(string);
- if (front == 1) {
- const char *s = string;
- BLI_strncpy(temp, "...", 4);
- pad = file_string_width(temp);
- while ((*s) && (sw + pad > w)) {
- s++;
- sw = file_string_width(s);
- shortened = 1;
- }
- if (shortened) {
- int slen = strlen(s);
- BLI_strncpy(temp + 3, s, slen + 1);
- temp[slen + 4] = '\0';
- BLI_strncpy(string, temp, slen + 4);
- }
+ UI_fontstyle_set(&style->widget);
+ if (style->widget.kerning == 1) { /* for BLF_width */
+ BLF_enable(style->widget.uifont_id, BLF_KERNING_DEFAULT);
}
- else {
- const char *s = string;
- while (sw > w) {
- int slen = strlen(string);
- string[slen - 1] = '\0';
- sw = file_string_width(s);
- shortened = 1;
- }
- if (shortened) {
- int slen = strlen(string);
- if (slen > 3) {
- BLI_strncpy(string + slen - 3, "...", 4);
- }
- }
+ width = BLF_width(style->widget.uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
+
+ if (style->widget.kerning == 1) {
+ BLF_disable(style->widget.uifont_id, BLF_KERNING_DEFAULT);
}
-
- return sw;
-}
-float file_string_width(const char *str)
-{
- uiStyle *style = UI_style_get();
- UI_fontstyle_set(&style->widget);
- return BLF_width(style->widget.uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
+ return width;
}
float file_font_pointsize(void)
@@ -484,7 +455,20 @@ static void column_widths(struct FileList *files, struct FileLayout *layout)
struct direntry *file = filelist_file(files, i);
if (file) {
float len;
- len = file_string_width(file->relname);
+ if (file->selflag & FILE_SEL_COLLAPSED) {
+ char fname[PATH_MAX];
+ char finalname[PATH_MAX];
+ char ext[PATH_MAX];
+ CollapsedEntry *collapsed = &file->collapsed_info;
+ BLI_strncpy(fname, file->relname, sizeof(fname));
+ BLI_path_frame_strip(fname, false, ext);
+ BLI_snprintf(finalname, sizeof(finalname), "%s%.*d-%.*d%s",
+ fname, collapsed->numdigits, collapsed->minframe, collapsed->numdigits, collapsed->maxframe, ext);
+ len = file_string_width(finalname);
+ }
+ else {
+ len = file_string_width(file->relname);
+ }
if (len > layout->column_widths[COLUMN_NAME]) layout->column_widths[COLUMN_NAME] = len;
len = file_string_width(file->date);
if (len > layout->column_widths[COLUMN_DATE]) layout->column_widths[COLUMN_DATE] = len;
@@ -527,8 +511,8 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
layout->textheight = textheight;
if (params->display == FILE_IMGDISPLAY) {
- layout->prv_w = 4.8f * UI_UNIT_X;
- layout->prv_h = 4.8f * UI_UNIT_Y;
+ layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X;
+ layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y;
layout->tile_border_x = 0.3f * UI_UNIT_X;
layout->tile_border_y = 0.3f * UI_UNIT_X;
layout->prv_border_x = 0.3f * UI_UNIT_X;
@@ -642,8 +626,8 @@ int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matche
*/
for (i = 0; i < n; i++) {
file = filelist_file(sfile->files, i);
- /* use same rule as 'FileCheckType.CHECK_FILES' */
- if (S_ISREG(file->type) && (fnmatch(pattern, file->relname, 0) == 0)) {
+ /* Do not check wether file is a file or dir here! Causes T44243 (we do accept dirs at this stage). */
+ if (fnmatch(pattern, file->relname, 0) == 0) {
file->selflag |= FILE_SEL_SELECTED;
if (!match) {
BLI_strncpy(matched_file, file->relname, FILE_MAX);
@@ -694,13 +678,8 @@ int autocomplete_directory(struct bContext *C, char *str, void *UNUSED(arg_v))
closedir(dir);
match = UI_autocomplete_end(autocpl, str);
- if (match) {
- if (match == AUTOCOMPLETE_FULL_MATCH) {
- BLI_add_slash(str);
- }
- else {
- BLI_strncpy(sfile->params->dir, str, sizeof(sfile->params->dir));
- }
+ if (match == AUTOCOMPLETE_FULL_MATCH) {
+ BLI_add_slash(str);
}
}
}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index c6ee6875403..fdf7b458865 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -565,7 +565,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle);
- if (pathString == NULL || !CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingASCII))
+ if (pathString == NULL || !CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingUTF8))
continue;
/* Exclude "all my files" as it makes no sense in blender fileselector */
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 782b318b8a2..07bf8131433 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -215,8 +215,9 @@ static void file_refresh(const bContext *C, ScrArea *sa)
params->active_file = -1; /* added this so it opens nicer (ton) */
}
filelist_setsorting(sfile->files, params->sort);
- filelist_setfilter_options(sfile->files, params->flag & FILE_HIDE_DOT,
+ filelist_setfilter_options(sfile->files, (params->flag & FILE_HIDE_DOT) != 0,
false, /* TODO hide_parent, should be controllable? */
+ (params->flag & FILE_COLLAPSE_IMAGES) != 0,
params->flag & FILE_FILTER ? params->filter : 0,
params->filter_glob,
params->filter_search);
@@ -254,7 +255,7 @@ static void file_refresh(const bContext *C, ScrArea *sa)
int idx = filelist_find(sfile->files, params->renamefile);
if (idx >= 0) {
struct direntry *file = filelist_file(sfile->files, idx);
- if (file) {
+ if (file && !(file->selflag & FILE_SEL_COLLAPSED)) {
file->selflag |= FILE_SEL_EDITING;
}
}
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index a2b64afdb15..c1e3d855e7d 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -139,6 +139,13 @@ static void graph_panel_view(const bContext *C, Panel *pa)
row = uiLayoutSplit(sub, 0.7f, true);
uiItemR(row, &spaceptr, "cursor_position_y", 0, IFACE_("Cursor Y"), ICON_NONE);
uiItemEnumO(row, "GRAPH_OT_snap", IFACE_("To Keys"), 0, "type", GRAPHKEYS_SNAP_VALUE);
+
+ col = uiLayoutColumn(pa->layout, false);
+ uiItemR(col, &spaceptr, "show_backdrop", 0, NULL, ICON_NONE);
+ col = uiLayoutColumn(pa->layout, false);
+ uiLayoutSetActive(col, RNA_boolean_get(&spaceptr, "show_backdrop"));
+ uiItemR(col, &spaceptr, "backdrop_camera", 0, "Camera", ICON_NONE);
+ uiItemR(col, &spaceptr, "backdrop_opacity", 0, "Opacity", ICON_NONE);
}
/* ******************* active F-Curve ************** */
@@ -165,9 +172,28 @@ static void graph_panel_properties(const bContext *C, Panel *pa)
RNA_pointer_create(ale->id, &RNA_FCurve, fcu, &fcu_ptr);
/* user-friendly 'name' for F-Curve */
- /* TODO: only show the path if this is invalid? */
col = uiLayoutColumn(layout, false);
- icon = getname_anim_fcurve(name, ale->id, fcu);
+ if (ale->type == ANIMTYPE_FCURVE) {
+ /* get user-friendly name for F-Curve */
+ icon = getname_anim_fcurve(name, ale->id, fcu);
+ }
+ else {
+ /* NLA Control Curve, etc. */
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+
+ /* get name */
+ if (acf && acf->name) {
+ acf->name(ale, name);
+ }
+ else {
+ strcpy(name, IFACE_("<invalid>"));
+ icon = ICON_ERROR;
+ }
+
+ /* icon */
+ if (ale->type == ANIMTYPE_NLACURVE)
+ icon = ICON_NLA;
+ }
uiItemL(col, name, icon);
/* RNA-Path Editing - only really should be enabled when things aren't working */
@@ -864,6 +890,7 @@ static void graph_panel_modifiers(const bContext *C, Panel *pa)
FModifier *fcm;
uiLayout *col, *row;
uiBlock *block;
+ bool active;
if (!graph_panel_context(C, &ale, &fcu))
return;
@@ -888,9 +915,11 @@ static void graph_panel_modifiers(const bContext *C, Panel *pa)
uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_fmodifier_paste");
}
+ active = !(fcu->flag & FCURVE_MOD_OFF);
/* draw each modifier */
for (fcm = fcu->modifiers.first; fcm; fcm = fcm->next) {
col = uiLayoutColumn(pa->layout, true);
+ uiLayoutSetActive(col, active);
ANIM_uiTemplate_fmodifier_draw(col, ale->id, &fcu->modifiers, fcm);
}
@@ -898,6 +927,21 @@ static void graph_panel_modifiers(const bContext *C, Panel *pa)
MEM_freeN(ale);
}
+/* ******************* Others ************************ */
+
+/* Graph Editor Backdrop Settings */
+static void UNUSED_FUNCTION(graph_panel_backdrop)(const bContext *C, Panel *UNUSED(pa))
+{
+ bScreen *sc = CTX_wm_screen(C);
+ SpaceIpo *sipo = CTX_wm_space_graph(C);
+ PointerRNA spaceptr;
+ // uiLayout *col;
+
+ /* get RNA pointers for use when creating the UI elements */
+ RNA_pointer_create(&sc->id, &RNA_SpaceGraphEditor, sipo, &spaceptr);
+
+}
+
/* ******************* general ******************************** */
void graph_buttons_register(ARegionType *art)
@@ -909,7 +953,6 @@ void graph_buttons_register(ARegionType *art)
strcpy(pt->label, N_("View Properties"));
strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = graph_panel_view;
- pt->flag |= PNL_DEFAULT_CLOSED;
BLI_addtail(&art->paneltypes, pt);
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index 2d8a0a3da29..87e7cab4d15 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -481,7 +481,7 @@ static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d
ChannelDriver *driver;
float samplefreq;
float stime, etime;
- float unitFac;
+ float unitFac, offset;
float dx, dy;
short mapping_flag = ANIM_get_normalization_flags(ac);
int i, n;
@@ -498,7 +498,7 @@ static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d
fcu->driver = NULL;
/* compute unit correction factor */
- unitFac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag);
+ unitFac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
/* Note about sampling frequency:
* Ideally, this is chosen such that we have 1-2 pixels = 1 segment
@@ -550,7 +550,7 @@ static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d
n = (etime - stime) / samplefreq + 0.5f;
for (i = 0; i <= n; i++) {
float ctime = stime + i * samplefreq;
- glVertex2f(ctime, evaluate_fcurve(fcu, ctime) * unitFac);
+ glVertex2f(ctime, (evaluate_fcurve(fcu, ctime) + offset) * unitFac);
}
glEnd();
@@ -566,13 +566,14 @@ static void draw_fcurve_curve_samples(bAnimContext *ac, ID *id, FCurve *fcu, Vie
FPoint *fpt = prevfpt + 1;
float fac, v[2];
int b = fcu->totvert - 1;
- float unit_scale;
+ float unit_scale, offset;
short mapping_flag = ANIM_get_normalization_flags(ac);
/* apply unit mapping */
glPushMatrix();
- unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag);
+ unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
glScalef(1.0f, unit_scale, 1.0f);
+ glTranslatef(0.0f, offset, 0.0f);
glBegin(GL_LINE_STRIP);
@@ -665,14 +666,15 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
float fac = 0.0f;
int b = fcu->totvert - 1;
int resol;
- float unit_scale;
+ float unit_scale, offset;
short mapping_flag = ANIM_get_normalization_flags(ac);
/* apply unit mapping */
glPushMatrix();
- unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag);
+ unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
glScalef(1.0f, unit_scale, 1.0f);
-
+ glTranslatef(0.0f, offset, 0.0f);
+
glBegin(GL_LINE_STRIP);
/* extrapolate to left? */
@@ -826,7 +828,8 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
ChannelDriver *driver = fcu->driver;
View2D *v2d = &ac->ar->v2d;
short mapping_flag = ANIM_get_normalization_flags(ac);
- float unitfac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag);
+ float offset;
+ float unitfac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
/* for now, only show when debugging driver... */
//if ((driver->flag & DRIVER_FLAG_SHOWDEBUG) == 0)
@@ -850,10 +853,10 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
glBegin(GL_LINES);
{
t = v2d->cur.xmin;
- glVertex2f(t, t * unitfac);
+ glVertex2f(t, (t + offset) * unitfac);
t = v2d->cur.xmax;
- glVertex2f(t, t * unitfac);
+ glVertex2f(t, (t + offset) * unitfac);
}
glEnd();
@@ -908,7 +911,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
glPointSize(7.0);
glBegin(GL_POINTS);
- glVertex2f(x, y);
+ glVertex2f(x, y);
glEnd();
/* inner frame */
@@ -916,7 +919,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
glPointSize(3.0);
glBegin(GL_POINTS);
- glVertex2f(x, y);
+ glVertex2f(x, y);
glEnd();
glPointSize(1.0f);
@@ -1067,10 +1070,12 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid
}
else if (((fcu->bezt) || (fcu->fpt)) && (fcu->totvert)) {
short mapping_flag = ANIM_get_normalization_flags(ac);
- float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
glPushMatrix();
glScalef(1.0f, unit_scale, 1.0f);
+ glTranslatef(0.0f, offset, 0.0f);
if (fcu->bezt) {
bool do_handles = draw_fcurve_handles_check(sipo, fcu);
@@ -1137,6 +1142,8 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
/* loop through channels, and set up drawing depending on their type */
{ /* first pass: just the standard GL-drawing for backdrop + text */
+ size_t channel_index = 0;
+
y = (float)ACHANNEL_FIRST;
for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) {
@@ -1148,11 +1155,12 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
{
/* draw all channels using standard channel-drawing API */
- ANIM_channel_draw(ac, ale, yminc, ymaxc);
+ ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index);
}
/* adjust y-position for next one */
y -= ACHANNEL_STEP;
+ channel_index++;
}
}
{ /* second pass: widgets */
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 2944901663b..f55a9dc45f3 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -59,6 +59,7 @@
#include "BKE_nla.h"
#include "BKE_context.h"
#include "BKE_report.h"
+#include "BKE_screen.h"
#include "UI_view2d.h"
@@ -109,7 +110,7 @@ void get_graph_keyframe_extents(bAnimContext *ac, float *xmin, float *xmax, floa
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
float txmin, txmax, tymin, tymax;
- float unitFac;
+ float unitFac, offset;
/* get range */
if (calc_fcurve_bounds(fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles)) {
@@ -122,7 +123,9 @@ void get_graph_keyframe_extents(bAnimContext *ac, float *xmin, float *xmax, floa
}
/* apply unit corrections */
- unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
+ unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
+ tymin += offset;
+ tymax += offset;
tymin *= unitFac;
tymax *= unitFac;
@@ -256,6 +259,14 @@ static int graphkeys_view_selected_exec(bContext *C, wmOperator *op)
return graphkeys_viewall(C, true, include_handles, smooth_viewtx);
}
+static int graphkeys_view_frame_exec(bContext *C, wmOperator *op)
+{
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ANIM_center_frame(C, smooth_viewtx);
+ return OPERATOR_FINISHED;
+}
+
+
void GRAPH_OT_view_all(wmOperatorType *ot)
{
/* identifiers */
@@ -294,6 +305,21 @@ void GRAPH_OT_view_selected(wmOperatorType *ot)
"Include handles of keyframes when calculating extents");
}
+void GRAPH_OT_view_frame(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "View Frame";
+ ot->idname = "GRAPH_OT_view_frame";
+ ot->description = "Reset viewable area to show range around current frame";
+
+ /* api callbacks */
+ ot->exec = graphkeys_view_frame_exec;
+ ot->poll = ED_operator_graphedit_active; /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ******************** Create Ghost-Curves Operator *********************** */
/* This operator samples the data of the selected F-Curves to F-Points, storing them
* as 'ghost curves' in the active Graph Editor
@@ -327,7 +353,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
ChannelDriver *driver = fcu->driver;
FPoint *fpt;
- float unitFac;
+ float unitFac, offset;
int cfra;
SpaceIpo *sipo = (SpaceIpo *) ac->sl;
short mapping_flag = ANIM_get_normalization_flags(ac);
@@ -336,7 +362,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
fcu->driver = NULL;
/* calculate unit-mapping factor */
- unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
+ unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
/* create samples, but store them in a new curve
* - we cannot use fcurve_store_samples() as that will only overwrite the original curve
@@ -349,7 +375,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
float cfrae = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
fpt->vec[0] = cfrae;
- fpt->vec[1] = fcurve_samplingcb_evalcurve(fcu, NULL, cfrae) * unitFac;
+ fpt->vec[1] = (fcurve_samplingcb_evalcurve(fcu, NULL, cfrae) + offset) * unitFac;
}
/* set color of ghost curve
@@ -498,12 +524,17 @@ static void insert_graph_keys(bAnimContext *ac, short mode)
else
cfra = (float)CFRA;
- /* if there's an id */
- if (ale->id)
+ /* read value from property the F-Curve represents, or from the curve only?
+ * - ale->id != NULL: Typically, this means that we have enough info to try resolving the path
+ * - ale->owner != NULL: If this is set, then the path may not be resolvable from the ID alone,
+ * so it's easier for now to just read the F-Curve directly.
+ * (TODO: add the full-blown PointerRNA relative parsing case here...)
+ */
+ if (ale->id && !ale->owner)
insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
else
insert_vert_fcurve(fcu, cfra, fcu->curval, 0);
-
+
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -582,7 +613,7 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
ListBase anim_data;
short mapping_flag = ANIM_get_normalization_flags(&ac);
-
+ float scale, offset;
/* get frame and value from props */
frame = RNA_float_get(op->ptr, "frame");
val = RNA_float_get(op->ptr, "value");
@@ -592,16 +623,18 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
frame = BKE_nla_tweakedit_remap(adt, frame, NLATIME_CONVERT_UNMAP);
/* apply inverse unit-mapping to value to get correct value for F-Curves */
- val *= ANIM_unit_mapping_get_factor(ac.scene, ale->id, fcu, mapping_flag | ANIM_UNITCONV_RESTORE);
-
+ scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, fcu, mapping_flag | ANIM_UNITCONV_RESTORE, &offset);
+
+ val = val * scale - offset;
+
/* insert keyframe on the specified frame + value */
insert_vert_fcurve(fcu, frame, val, 0);
-
+
ale->update |= ANIM_UPDATE_DEPS;
-
+
BLI_listbase_clear(&anim_data);
BLI_addtail(&anim_data, ale);
-
+
ANIM_animdata_update(&ac, &anim_data);
}
else {
@@ -851,13 +884,6 @@ static int graphkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-static int graphkeys_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- graphkeys_duplicate_exec(C, op);
-
- return OPERATOR_FINISHED;
-}
-
void GRAPH_OT_duplicate(wmOperatorType *ot)
{
/* identifiers */
@@ -866,7 +892,6 @@ void GRAPH_OT_duplicate(wmOperatorType *ot)
ot->description = "Make a copy of all selected keyframes";
/* api callbacks */
- ot->invoke = graphkeys_duplicate_invoke;
ot->exec = graphkeys_duplicate_exec;
ot->poll = graphop_editable_keyframes_poll;
@@ -958,7 +983,7 @@ void GRAPH_OT_delete(wmOperatorType *ot)
/* ******************** Clean Keyframes Operator ************************* */
-static void clean_graph_keys(bAnimContext *ac, float thresh)
+static void clean_graph_keys(bAnimContext *ac, float thresh, bool clean_chan)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -970,7 +995,7 @@ static void clean_graph_keys(bAnimContext *ac, float thresh)
/* loop through filtered data and clean curves */
for (ale = anim_data.first; ale; ale = ale->next) {
- clean_fcurve((FCurve *)ale->key_data, thresh);
+ clean_fcurve(ac, ale, thresh, clean_chan);
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -985,6 +1010,7 @@ static int graphkeys_clean_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
float thresh;
+ bool clean_chan;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -992,9 +1018,9 @@ static int graphkeys_clean_exec(bContext *C, wmOperator *op)
/* get cleaning threshold */
thresh = RNA_float_get(op->ptr, "threshold");
-
+ clean_chan = RNA_boolean_get(op->ptr, "channels");
/* clean keyframes */
- clean_graph_keys(&ac, thresh);
+ clean_graph_keys(&ac, thresh, clean_chan);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -1019,6 +1045,7 @@ void GRAPH_OT_clean(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
+ RNA_def_boolean(ot->srna, "channels", false, "Channels", "");
}
/* ******************** Bake F-Curve Operator *********************** */
@@ -1155,6 +1182,11 @@ static int graphkeys_sound_bake_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "filepath", path);
+ if (!BLI_is_file(path)) {
+ BKE_reportf(op->reports, RPT_ERROR, "File not found '%s'", path);
+ return OPERATOR_CANCELLED;
+ }
+
scene = ac.scene; /* current scene */
/* store necessary data for the baking steps */
@@ -1877,7 +1909,8 @@ static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
short mapping_flag = ANIM_get_normalization_flags(&ac);
KeyframeEditData current_ked;
- float unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS);
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS, &offset);
memset(&current_ked, 0, sizeof(current_ked));
@@ -1891,7 +1924,7 @@ static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
ked.f1 += current_ked.f1;
ked.i1 += current_ked.i1;
- ked.f2 += current_ked.f2 * unit_scale;
+ ked.f2 += (current_ked.f2 + offset) * unit_scale;
ked.i2 += current_ked.i2;
}
@@ -1984,9 +2017,10 @@ static void snap_graph_keys(bAnimContext *ac, short mode)
/* normalise cursor value (for normalised F-Curves display) */
if (mode == GRAPHKEYS_SNAP_VALUE) {
short mapping_flag = ANIM_get_normalization_flags(ac);
- float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag);
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag, &offset);
- ked.f1 = cursor_value / unit_scale;
+ ked.f1 = (cursor_value / unit_scale) - offset;
}
/* perform snapping */
@@ -2111,9 +2145,10 @@ static void mirror_graph_keys(bAnimContext *ac, short mode)
/* apply unit corrections */
if (mode == GRAPHKEYS_MIRROR_VALUE) {
short mapping_flag = ANIM_get_normalization_flags(ac);
- float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS);
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS, &offset);
- ked.f1 = cursor_value * unit_scale;
+ ked.f1 = (cursor_value + offset) * unit_scale;
}
/* perform actual mirroring */
@@ -2243,7 +2278,7 @@ static EnumPropertyItem *graph_fmodifier_itemf(bContext *C, PointerRNA *UNUSED(p
/* start from 1 to skip the 'Invalid' modifier type */
for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
- FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
+ const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
int index;
/* check if modifier is valid for this context */
@@ -2459,3 +2494,154 @@ void GRAPH_OT_fmodifier_paste(wmOperatorType *ot)
}
/* ************************************************************************** */
+
+typedef struct BackDropTransformData {
+ float init_offset[2];
+ float init_zoom;
+ short event_type;
+ wmWidgetGroupType *cagetype;
+} BackDropTransformData;
+
+static int graph_widget_backdrop_transform_poll(bContext *C)
+{
+ SpaceIpo *sipo = CTX_wm_space_graph(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ return ((sipo != NULL) &&
+ (ar->type->regionid == RGN_TYPE_WINDOW) &&
+ (sipo->flag & SIPO_DRAW_BACKDROP) &&
+ (sipo->backdrop_camera));
+}
+
+static void widgetgroup_backdrop_draw(const struct bContext *C, struct wmWidgetGroup *wgroup)
+{
+ ARegion *ar = CTX_wm_region(C);
+ wmOperator *op = wgroup->type->op;
+ Scene *scene = CTX_data_scene(C);
+ int width = (scene->r.size * scene->r.xsch) / 150.0f;
+ int height = (scene->r.size * scene->r.ysch) / 150.0f;
+ float origin[3];
+
+ wmWidget *cage = WIDGET_rect_transform_new(wgroup, WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM |
+ WIDGET_RECT_TRANSFORM_STYLE_TRANSLATE, width, height);
+ WM_widget_property(cage, RECT_TRANSFORM_SLOT_OFFSET, op->ptr, "offset");
+ WM_widget_property(cage, RECT_TRANSFORM_SLOT_SCALE, op->ptr, "scale");
+
+ origin[0] = BLI_rcti_size_x(&ar->winrct) / 2.0f;
+ origin[1] = BLI_rcti_size_y(&ar->winrct) / 2.0f;
+
+ WM_widget_set_origin(cage, origin);
+}
+
+static int graph_widget_backdrop_transform_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ SpaceIpo *sipo = CTX_wm_space_graph(C);
+ /* no poll, lives always for the duration of the operator */
+ wmWidgetGroupType *cagetype = WM_widgetgrouptype_new(NULL, widgetgroup_backdrop_draw, CTX_data_main(C), "Graph_Canvas", SPACE_IPO, RGN_TYPE_WINDOW, false);
+ struct wmEventHandler *handler = WM_event_add_modal_handler(C, op);
+ BackDropTransformData *data = MEM_mallocN(sizeof(BackDropTransformData), "overdrop transform data");
+ WM_modal_handler_attach_widgetgroup(C, handler, cagetype, op);
+
+ RNA_float_set_array(op->ptr, "offset", sipo->backdrop_offset);
+ RNA_float_set(op->ptr, "scale", sipo->backdrop_zoom);
+
+ copy_v2_v2(data->init_offset, sipo->backdrop_offset);
+ data->init_zoom = sipo->backdrop_zoom;
+ data->cagetype = cagetype;
+ data->event_type = event->type;
+
+ op->customdata = data;
+
+ ED_area_headerprint(sa, "Drag to place, and scale, Space/Enter/Caller key to confirm, R to recenter, RClick/Esc to cancel");
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void graph_widget_backdrop_transform_finish(bContext *C, BackDropTransformData *data)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ ED_area_headerprint(sa, NULL);
+ WM_widgetgrouptype_unregister(C, CTX_data_main(C), data->cagetype);
+ MEM_freeN(data);
+}
+
+static void graph_widget_backdrop_transform_cancel(struct bContext *C, struct wmOperator *op)
+{
+ BackDropTransformData *data = op->customdata;
+ graph_widget_backdrop_transform_finish(C, data);
+}
+
+static int graph_widget_backdrop_transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ BackDropTransformData *data = op->customdata;
+
+ if (event->type == data->event_type && event->val == KM_PRESS) {
+ graph_widget_backdrop_transform_finish(C, data);
+ return OPERATOR_FINISHED;
+ }
+
+ switch (event->type) {
+ case EVT_WIDGET_UPDATE: {
+ SpaceIpo *sipo = CTX_wm_space_graph(C);
+ RNA_float_get_array(op->ptr, "offset", sipo->backdrop_offset);
+ sipo->backdrop_zoom = RNA_float_get(op->ptr, "scale");
+ break;
+ }
+ case RKEY:
+ {
+ SpaceIpo *sipo = CTX_wm_space_graph(C);
+ ARegion *ar = CTX_wm_region(C);
+ float zero[2] = {0.0f};
+ RNA_float_set_array(op->ptr, "offset", zero);
+ RNA_float_set(op->ptr, "scale", 1.0f);
+ copy_v2_v2(sipo->backdrop_offset, zero);
+ sipo->backdrop_zoom = 1.0f;
+ ED_region_tag_redraw(ar);
+ /* add a mousemove to refresh the widget */
+ WM_event_add_mousemove(C);
+ break;
+ }
+ case RETKEY:
+ case PADENTER:
+ case SPACEKEY:
+ {
+ graph_widget_backdrop_transform_finish(C, data);
+ return OPERATOR_FINISHED;
+ }
+ case ESCKEY:
+ case RIGHTMOUSE:
+ {
+ SpaceIpo *sipo = CTX_wm_space_graph(C);
+ copy_v2_v2(sipo->backdrop_offset, data->init_offset);
+ sipo->backdrop_zoom = data->init_zoom;
+
+ graph_widget_backdrop_transform_finish(C, data);
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void GRAPH_OT_widget_backdrop_transform(struct wmOperatorType *ot)
+{
+ float default_offset[2] = {0.0f, 0.0f};
+
+ /* identifiers */
+ ot->name = "Transform Backdrop";
+ ot->idname = "GRAPH_OT_widget_backdrop_transform";
+ ot->description = "";
+
+ /* api callbacks */
+ ot->invoke = graph_widget_backdrop_transform_invoke;
+ ot->modal = graph_widget_backdrop_transform_modal;
+ ot->poll = graph_widget_backdrop_transform_poll;
+ ot->cancel = graph_widget_backdrop_transform_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_float_array(ot->srna, "offset", 2, default_offset, FLT_MIN, FLT_MAX, "Offset", "Offset of the backdrop", FLT_MIN, FLT_MAX);
+ RNA_def_float(ot->srna, "scale", 1.0f, 0.0f, FLT_MAX, "Scale", "Scale of the backdrop", 0.0f, FLT_MAX);
+}
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index 50412952139..35267cbf999 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -32,11 +32,8 @@
#define __GRAPH_INTERN_H__
struct bContext;
-struct wmWindowManager;
struct bAnimContext;
struct bAnimListElem;
-struct FCurve;
-struct FModifier;
struct SpaceIpo;
struct ScrArea;
struct ARegion;
@@ -94,6 +91,7 @@ void get_graph_keyframe_extents(struct bAnimContext *ac, float *xmin, float *xma
void GRAPH_OT_previewrange_set(struct wmOperatorType *ot);
void GRAPH_OT_view_all(struct wmOperatorType *ot);
void GRAPH_OT_view_selected(struct wmOperatorType *ot);
+void GRAPH_OT_view_frame(struct wmOperatorType *ot);
void GRAPH_OT_click_insert(struct wmOperatorType *ot);
void GRAPH_OT_keyframe_insert(struct wmOperatorType *ot);
@@ -119,6 +117,8 @@ void GRAPH_OT_frame_jump(struct wmOperatorType *ot);
void GRAPH_OT_snap(struct wmOperatorType *ot);
void GRAPH_OT_mirror(struct wmOperatorType *ot);
+void GRAPH_OT_widget_backdrop_transform(struct wmOperatorType *ot);
+
/* defines for snap keyframes
* NOTE: keep in sync with eEditKeyframes_Snap (in ED_keyframes_edit.h)
*/
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index da308d0b1f1..9b5fa3b744a 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -87,8 +87,9 @@ static void graphview_cursor_apply(bContext *C, wmOperator *op)
* NOTE: sync this part of the code with ANIM_OT_change_frame
*/
CFRA = RNA_int_get(op->ptr, "frame");
+ FRAMENUMBER_MIN_CLAMP(CFRA);
SUBFRA = 0.f;
- sound_seek_scene(bmain, scene);
+ BKE_sound_seek_scene(bmain, scene);
/* set the cursor value */
sipo->cursorVal = RNA_float_get(op->ptr, "value");
@@ -138,12 +139,16 @@ static void graphview_cursor_setprops(bContext *C, wmOperator *op, const wmEvent
/* Modal Operator init */
static int graphview_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ wmWindow *win = CTX_wm_window(C);
/* Change to frame that mouse is over before adding modal handler,
* as user could click on a single frame (jump to frame) as well as
* click-dragging over a range (modal scrubbing).
*/
graphview_cursor_setprops(C, op, event);
-
+
+ if (win->screen)
+ win->screen->scrubbing = true;
+
/* apply these changes first */
graphview_cursor_apply(C, op);
@@ -155,9 +160,13 @@ static int graphview_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *e
/* Modal event handling of cursor changing */
static int graphview_cursor_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
+ wmWindow *win = CTX_wm_window(C);
+
/* execute the events */
switch (event->type) {
case ESCKEY:
+ if (win->screen)
+ win->screen->scrubbing = false;
return OPERATOR_FINISHED;
case MOUSEMOVE:
@@ -172,8 +181,12 @@ static int graphview_cursor_modal(bContext *C, wmOperator *op, const wmEvent *ev
/* we check for either mouse-button to end, as checking for ACTIONMOUSE (which is used to init
* the modal op) doesn't work for some reason
*/
- if (event->val == KM_RELEASE)
+ if (event->val == KM_RELEASE) {
+ if (win->screen)
+ win->screen->scrubbing = false;
+
return OPERATOR_FINISHED;
+ }
break;
}
@@ -380,6 +393,7 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_view_all);
WM_operatortype_append(GRAPH_OT_view_selected);
WM_operatortype_append(GRAPH_OT_properties);
+ WM_operatortype_append(GRAPH_OT_view_frame);
WM_operatortype_append(GRAPH_OT_ghost_curves_create);
WM_operatortype_append(GRAPH_OT_ghost_curves_clear);
@@ -427,6 +441,8 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_fmodifier_add);
WM_operatortype_append(GRAPH_OT_fmodifier_copy);
WM_operatortype_append(GRAPH_OT_fmodifier_paste);
+
+ WM_operatortype_append(GRAPH_OT_widget_backdrop_transform);
}
void ED_operatormacros_graph(void)
@@ -440,6 +456,7 @@ void ED_operatormacros_graph(void)
WM_operatortype_macro_define(ot, "GRAPH_OT_duplicate");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_transform");
RNA_enum_set(otmacro->ptr, "mode", TFM_TIME_DUPLICATE);
+ RNA_enum_set(otmacro->ptr, "proportional", PROP_EDIT_OFF);
}
@@ -562,15 +579,14 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
WM_keymap_add_item(keymap, "GRAPH_OT_easing_type", EKEY, KM_PRESS, KM_CTRL, 0);
/* destructive */
- WM_keymap_add_item(keymap, "GRAPH_OT_clean", OKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_smooth", OKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_sample", OKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_bake", CKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "GRAPH_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "GRAPH_OT_delete", DELKEY, KM_PRESS, 0, 0);
-
+ WM_keymap_add_menu(keymap, "GRAPH_MT_delete", XKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "GRAPH_MT_delete", DELKEY, KM_PRESS, 0, 0);
+
WM_keymap_add_item(keymap, "GRAPH_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
/* insertkey */
@@ -594,7 +610,8 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
WM_keymap_add_item(keymap, "GRAPH_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
-
+ WM_keymap_add_item(keymap, "GRAPH_OT_view_frame", PAD0, KM_PRESS, 0, 0);
+
/* F-Modifiers */
kmi = WM_keymap_add_item(keymap, "GRAPH_OT_fmodifier_add", MKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "only_active", false);
@@ -608,6 +625,9 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
/* transform system */
transform_keymap_for_space(keyconf, keymap, SPACE_IPO);
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", OKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_proportional_fcurve");
+
/* pivot point settings */
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
@@ -661,5 +681,7 @@ void graphedit_keymap(wmKeyConfig *keyconf)
/* keyframes */
keymap = WM_keymap_find(keyconf, "Graph Editor", SPACE_IPO, 0);
graphedit_keymap_keyframes(keyconf, keymap);
+
+ WM_keymap_add_item(keymap, "GRAPH_OT_widget_backdrop_transform", WKEY, KM_PRESS, 0, 0);
}
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index 78dbae7618b..4cf8a1de7ab 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -272,7 +272,8 @@ static void borderselect_graphkeys(
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
- float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
/* apply NLA mapping to all the keyframes, since it's easier than trying to
* guess when a callback might use something different
@@ -282,8 +283,8 @@ static void borderselect_graphkeys(
scaled_rectf.xmin = rectf.xmin;
scaled_rectf.xmax = rectf.xmax;
- scaled_rectf.ymin = rectf.ymin / unit_scale;
- scaled_rectf.ymax = rectf.ymax / unit_scale;
+ scaled_rectf.ymin = rectf.ymin / unit_scale - offset;
+ scaled_rectf.ymax = rectf.ymax / unit_scale - offset;
/* set horizontal range (if applicable)
* NOTE: these values are only used for x-range and y-range but not region
@@ -1089,6 +1090,8 @@ typedef struct tNearestVertInfo {
short hpoint; /* the handle index that we hit (eHandleIndex) */
short sel; /* whether the handle is selected or not */
int dist; /* distance from mouse to vert */
+
+ eAnim_ChannelType ctype; /* type of animation channel this FCurve comes from */
} tNearestVertInfo;
/* Tags for the type of graph vert that we have */
@@ -1116,8 +1119,8 @@ static bool fcurve_handle_sel_check(SpaceIpo *sipo, BezTriple *bezt)
/* check if the given vertex is within bounds or not */
// TODO: should we return if we hit something?
static void nearest_fcurve_vert_store(
- ListBase *matches, View2D *v2d, FCurve *fcu,
- BezTriple *bezt, FPoint *fpt, short hpoint, const int mval[2], float unit_scale)
+ ListBase *matches, View2D *v2d, FCurve *fcu, eAnim_ChannelType ctype,
+ BezTriple *bezt, FPoint *fpt, short hpoint, const int mval[2], float unit_scale, float offset)
{
/* Keyframes or Samples? */
if (bezt) {
@@ -1129,7 +1132,7 @@ static void nearest_fcurve_vert_store(
* 'vec' matrix
*/
if (UI_view2d_view_to_region_clip(v2d,
- bezt->vec[hpoint + 1][0], bezt->vec[hpoint + 1][1] * unit_scale,
+ bezt->vec[hpoint + 1][0], (bezt->vec[hpoint + 1][1] + offset) * unit_scale,
&screen_co[0], &screen_co[1]) &&
/* check if distance from mouse cursor to vert in screen space is within tolerance */
((dist = len_v2v2_int(mval, screen_co)) <= GVERTSEL_TOL))
@@ -1149,6 +1152,8 @@ static void nearest_fcurve_vert_store(
/* store values */
nvi->fcu = fcu;
+ nvi->ctype = ctype;
+
nvi->bezt = bezt;
nvi->hpoint = hpoint;
nvi->dist = dist;
@@ -1189,30 +1194,31 @@ static void get_nearest_fcurve_verts_list(bAnimContext *ac, const int mval[2], L
for (ale = anim_data.first; ale; ale = ale->next) {
FCurve *fcu = (FCurve *)ale->key_data;
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
- float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
-
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
+
/* apply NLA mapping to all the keyframes */
if (adt)
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
-
+
if (fcu->bezt) {
BezTriple *bezt1 = fcu->bezt, *prevbezt = NULL;
int i;
for (i = 0; i < fcu->totvert; i++, prevbezt = bezt1, bezt1++) {
/* keyframe */
- nearest_fcurve_vert_store(matches, v2d, fcu, bezt1, NULL, NEAREST_HANDLE_KEY, mval, unit_scale);
+ nearest_fcurve_vert_store(matches, v2d, fcu, ale->type, bezt1, NULL, NEAREST_HANDLE_KEY, mval, unit_scale, offset);
/* handles - only do them if they're visible */
if (fcurve_handle_sel_check(sipo, bezt1) && (fcu->totvert > 1)) {
/* first handle only visible if previous segment had handles */
if ((!prevbezt && (bezt1->ipo == BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ))) {
- nearest_fcurve_vert_store(matches, v2d, fcu, bezt1, NULL, NEAREST_HANDLE_LEFT, mval, unit_scale);
+ nearest_fcurve_vert_store(matches, v2d, fcu, ale->type, bezt1, NULL, NEAREST_HANDLE_LEFT, mval, unit_scale, offset);
}
/* second handle only visible if this segment is bezier */
if (bezt1->ipo == BEZT_IPO_BEZ) {
- nearest_fcurve_vert_store(matches, v2d, fcu, bezt1, NULL, NEAREST_HANDLE_RIGHT, mval, unit_scale);
+ nearest_fcurve_vert_store(matches, v2d, fcu, ale->type, bezt1, NULL, NEAREST_HANDLE_RIGHT, mval, unit_scale, offset);
}
}
}
@@ -1405,7 +1411,7 @@ static void mouse_graph_keys(bAnimContext *ac, const int mval[2], short select_m
/* needs to be called with (sipo->flag & SIPO_SELCUVERTSONLY) otherwise the active flag won't be set [#26452] */
if (nvi->fcu->flag & FCURVE_SELECTED) {
int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
- ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nvi->fcu, ANIMTYPE_FCURVE);
+ ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nvi->fcu, nvi->ctype);
}
/* free temp sample data for filtering */
diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c
index eea360ced45..0e56dc817e4 100644
--- a/source/blender/editors/space_graph/graph_utils.c
+++ b/source/blender/editors/space_graph/graph_utils.c
@@ -210,13 +210,18 @@ int graphop_active_fcurve_poll(bContext *C)
if (ale == NULL)
return 0;
- /* free temp data... */
- has_fcurve = ((ale->data) && (ale->type == ANIMTYPE_FCURVE));
+ /* do we have a suitable F-Curves?
+ * - For most cases, NLA Control Curves are sufficiently similar to NLA curves to serve this role too.
+ * Under the hood, they are F-Curves too. The only problems which will arise here are if these need to be
+ * in an Action too (but drivers would then also be affected!)
+ */
+ has_fcurve = ((ale->data) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE));
if (has_fcurve) {
FCurve *fcu = (FCurve *)ale->data;
has_fcurve = (fcu->flag & FCURVE_VISIBLE) != 0;
}
+ /* free temp data... */
MEM_freeN(ale);
/* return success */
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index ad6f3ff5c7e..4fd6276a28f 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -103,6 +103,10 @@ static SpaceLink *graph_new(const bContext *C)
sipo->autosnap = SACTSNAP_FRAME;
+ sipo->backdrop_camera = scene->camera;
+ sipo->backdrop_zoom = 1.0f;
+ sipo->backdrop_opacity = 0.7f;
+
/* allocate DopeSheet data for Graph Editor */
sipo->ads = MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet");
sipo->ads->source = (ID *)scene;
@@ -219,18 +223,25 @@ static void graph_main_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
keymap = WM_keymap_find(wm->defaultconf, "Graph Editor Generic", SPACE_IPO, 0);
WM_event_add_keymap_handler(&ar->handlers, keymap);
+
+ /* widgets */
+ if (BLI_listbase_is_empty(&ar->widgetmaps)) {
+ BLI_addhead(&ar->widgetmaps, WM_widgetmap_from_type("Graph_Canvas", SPACE_IPO, RGN_TYPE_WINDOW, false));
+ }
}
static void graph_main_area_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
SpaceIpo *sipo = CTX_wm_space_graph(C);
+ Scene *scene = CTX_data_scene(C);
bAnimContext ac;
View2D *v2d = &ar->v2d;
View2DGrid *grid;
View2DScrollers *scrollers;
float col[3];
short unitx = 0, unity = V2D_UNIT_VALUES, flag = 0;
+ const bool draw_backdrop = ((sipo->flag & SIPO_DRAW_BACKDROP) && (sipo->backdrop_camera != NULL));
/* clear and setup matrix */
UI_GetThemeColor3fv(TH_BACK, col);
@@ -241,11 +252,26 @@ static void graph_main_area_draw(const bContext *C, ARegion *ar)
/* grid */
unitx = (sipo->flag & SIPO_DRAWTIME) ? V2D_UNIT_SECONDS : V2D_UNIT_FRAMESCALE;
- grid = UI_view2d_grid_calc(CTX_data_scene(C), v2d, unitx, V2D_GRID_NOCLAMP, unity, V2D_GRID_NOCLAMP, ar->winx, ar->winy);
+ grid = UI_view2d_grid_calc(scene, v2d, unitx, V2D_GRID_NOCLAMP, unity, V2D_GRID_NOCLAMP, ar->winx, ar->winy);
UI_view2d_grid_draw(v2d, grid, V2D_GRIDLINES_ALL);
ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
-
+
+ if (draw_backdrop) {
+ int width = (scene->r.size * scene->r.xsch) / 150 * sipo->backdrop_zoom;
+ int height = (scene->r.size * scene->r.ysch) / 150 * sipo->backdrop_zoom;
+ float xofs = (BLI_rcti_size_x(&ar->winrct) - width) / 2.0f + sipo->backdrop_offset[0];
+ float yofs = (BLI_rcti_size_y(&ar->winrct) - height) / 2.0f + sipo->backdrop_offset[1];
+
+ /* reset view matrix */
+ UI_view2d_view_restore(C);
+
+ ED_region_draw_backdrop_view3d(C, sipo->backdrop_camera, sipo->backdrop_opacity,
+ width, height, xofs, yofs, 1.0f, 1.0f, true);
+
+ UI_view2d_view_ortho(v2d);
+ }
+
/* draw data */
if (ANIM_animdata_get_context(C, &ac)) {
/* draw ghost curves */
@@ -306,6 +332,10 @@ static void graph_main_area_draw(const bContext *C, ARegion *ar)
/* reset view matrix */
UI_view2d_view_restore(C);
+ /* finally draw any widgets here */
+ WM_widgets_update(C, ar->widgetmaps.first);
+ WM_widgets_draw(C, ar->widgetmaps.first, false);
+
/* scrollers */
// FIXME: args for scrollers depend on the type of data being shown...
scrollers = UI_view2d_scrollers_calc(C, v2d, unitx, V2D_GRID_NOCLAMP, unity, V2D_GRID_NOCLAMP);
@@ -611,6 +641,14 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
}
}
+/* ************************************* */
+
+static void graph_widgets(void)
+{
+ /* create the widgetmap for the area here */
+ WM_widgetmaptype_find("Graph_Canvas", SPACE_IPO, RGN_TYPE_WINDOW, false, true);
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_ipo(void)
{
@@ -628,6 +666,7 @@ void ED_spacetype_ipo(void)
st->keymap = graphedit_keymap;
st->listener = graph_listener;
st->refresh = graph_refresh;
+ st->widgets = graph_widgets;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype graphedit region");
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index fb3c140fddf..e52eea248ed 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -44,6 +44,7 @@
#include "BKE_image.h"
#include "BKE_node.h"
#include "BKE_screen.h"
+#include "BKE_scene.h"
#include "RE_pipeline.h"
@@ -82,9 +83,9 @@ static void image_info(Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf,
else {
if (ima->source == IMA_SRC_MOVIE) {
ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Movie"), len - ofs);
- if (ima->anim)
+ if (BKE_image_has_anim(ima))
ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_(" %d frs"),
- IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN));
+ IMB_anim_get_duration(((ImageAnim *)ima->anims.first)->anim, IMB_TC_RECORD_RUN));
}
else {
ofs += BLI_strncpy_rlen(str, IFACE_("Image"), len - ofs);
@@ -311,10 +312,11 @@ static void ui_imageuser_slot_menu(bContext *UNUSED(C), uiLayout *layout, void *
static const char *ui_imageuser_layer_fake_name(RenderResult *rr)
{
- if (rr->rectf) {
+ RenderView *rv = RE_RenderViewGetById(rr, 0);
+ if (rv->rectf) {
return IFACE_("Composite");
}
- else if (rr->rect32) {
+ else if (rv->rect32) {
return IFACE_("Sequence");
}
else {
@@ -375,7 +377,7 @@ final:
static const char *ui_imageuser_pass_fake_name(RenderLayer *rl)
{
- if (rl == NULL || rl->rectf) {
+ if (rl == NULL) {
return IFACE_("Combined");
}
else {
@@ -383,9 +385,9 @@ static const char *ui_imageuser_pass_fake_name(RenderLayer *rl)
}
}
-static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *ptrpair_p)
+static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
{
- void **rnd_data = ptrpair_p;
+ void **rnd_data = rnd_pt;
uiBlock *block = uiLayoutGetBlock(layout);
Image *image = rnd_data[0];
ImageUser *iuser = rnd_data[1];
@@ -398,6 +400,7 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *
RenderPass *rpass;
const char *fake_name;
int nr;
+ int passflag = 0;
/* may have been freed since drawing */
rr = BKE_image_acquire_renderresult(scene, image);
@@ -419,15 +422,22 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *
fake_name = ui_imageuser_pass_fake_name(rl);
if (fake_name) {
- BLI_strncpy(rpass_fake.name, fake_name, sizeof(rpass_fake.name));
+ BLI_strncpy(rpass_fake.internal_name, fake_name, sizeof(rpass_fake.internal_name));
nr += 1;
}
/* rendered results don't have a Combined pass */
for (rpass = rl ? rl->passes.last : NULL; rpass; rpass = rpass->prev, nr--) {
+
+ /* just show one pass of each kind */
+ if (passflag & rpass->passtype)
+ continue;
+
+ passflag |= rpass->passtype;
+
final:
- uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rpass->name), 0, 0,
- UI_UNIT_X * 5, UI_UNIT_X, &iuser->pass, (float) nr, 0.0, 0, -1, "");
+ uiDefButI(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rpass->internal_name), 0, 0,
+ UI_UNIT_X * 5, UI_UNIT_X, &iuser->passtype, (float) rpass->passtype, 0.0, 0, -1, "");
}
if (fake_name) {
@@ -441,21 +451,81 @@ final:
BKE_image_release_renderresult(scene, image);
}
+/**************************** view menus *****************************/
+static void ui_imageuser_view_menu_rr(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
+{
+ void **rnd_data = rnd_pt;
+ uiBlock *block = uiLayoutGetBlock(layout);
+ Image *image = rnd_data[0];
+ ImageUser *iuser = rnd_data[1];
+ RenderResult *rr;
+ RenderView *rview;
+ int nr;
+ Scene *scene = iuser->scene;
+
+ /* may have been freed since drawing */
+ rr = BKE_image_acquire_renderresult(scene, image);
+ if (UNLIKELY(rr == NULL)) {
+ return;
+ }
+
+ UI_block_layout_set_current(block, layout);
+ uiLayoutColumn(layout, false);
+
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("View"),
+ 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiItemS(layout);
+
+ nr = (rr ? BLI_listbase_count(&rr->views) : 0) - 1;
+ for (rview = rr ? rr->views.last : NULL; rview; rview = rview->prev, nr--) {
+ uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rview->name), 0, 0,
+ UI_UNIT_X * 5, UI_UNIT_X, &iuser->view, (float) nr, 0.0, 0, -1, "");
+ }
+
+ BKE_image_release_renderresult(scene, image);
+}
+
+static void ui_imageuser_view_menu_multiview(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
+{
+ void **rnd_data = rnd_pt;
+ uiBlock *block = uiLayoutGetBlock(layout);
+ Image *image = rnd_data[0];
+ ImageUser *iuser = rnd_data[1];
+ int nr;
+ ImageView *iv;
+
+ UI_block_layout_set_current(block, layout);
+ uiLayoutColumn(layout, false);
+
+ uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("View"),
+ 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiItemS(layout);
+
+ nr = BLI_listbase_count(&image->views) - 1;
+ for (iv = image->views.last; iv; iv = iv->prev, nr--) {
+ uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(iv->name), 0, 0,
+ UI_UNIT_X * 5, UI_UNIT_X, &iuser->view, (float) nr, 0.0, 0, -1, "");
+ }
+}
+
/* 5 layer button callbacks... */
static void image_multi_cb(bContext *C, void *rr_v, void *iuser_v)
{
ImageUser *iuser = iuser_v;
- BKE_image_multilayer_index(rr_v, iuser);
+ BKE_image_multilayer_index(rr_v, iuser);
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
}
+
static void image_multi_inclay_cb(bContext *C, void *rr_v, void *iuser_v)
{
RenderResult *rr = rr_v;
ImageUser *iuser = iuser_v;
int tot = BLI_listbase_count(&rr->layers);
- if (rr->rectf || rr->rect32)
+ if (RE_HasFakeLayer(rr))
tot++; /* fake compo/sequencer layer */
if (iuser->layer < tot - 1) {
@@ -478,32 +548,75 @@ static void image_multi_incpass_cb(bContext *C, void *rr_v, void *iuser_v)
{
RenderResult *rr = rr_v;
ImageUser *iuser = iuser_v;
- RenderLayer *rl = BLI_findlink(&rr->layers, iuser->layer);
+ RenderLayer *rl;
+ RenderPass *rp;
+ RenderPass *next = NULL;
+ int layer = iuser->layer;
- if (rl) {
- int tot = BLI_listbase_count(&rl->passes);
+ if (RE_HasFakeLayer(rr))
+ layer -= 1;
- if (rr->rectf || rr->rect32)
- tot++; /* fake compo/sequencer layer */
+ rl = BLI_findlink(&rr->layers, layer);
- if (iuser->pass < tot - 1) {
- iuser->pass++;
- BKE_image_multilayer_index(rr, iuser);
+ if (rl) {
+ for (rp = rl->passes.first; rp; rp = rp->next) {
+ if (rp->passtype == iuser->passtype) {
+ next = rp->next;
+ if (next != NULL && next->passtype == rp->passtype)
+ next = next->next;
+ break;
+ }
+ }
+
+ if (next != NULL && iuser->passtype != next->passtype) {
+ iuser->passtype = next->passtype;
+ BKE_image_multilayer_index(rr, iuser);
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
}
}
}
static void image_multi_decpass_cb(bContext *C, void *rr_v, void *iuser_v)
{
+ RenderResult *rr = rr_v;
ImageUser *iuser = iuser_v;
+ RenderLayer *rl;
+ RenderPass *rp;
+ RenderPass *prev = NULL;
+ int layer = iuser->layer;
- if (iuser->pass > 0) {
- iuser->pass--;
- BKE_image_multilayer_index(rr_v, iuser);
- WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+ if (RE_HasFakeLayer(rr))
+ layer -= 1;
+
+ rl = BLI_findlink(&rr->layers, layer);
+
+ if (rl) {
+ for (rp = rl->passes.last; rp; rp = rp->prev) {
+ if (rp->passtype == iuser->passtype) {
+ prev = rp->prev;
+ if (prev != NULL && prev->passtype == rp->passtype)
+ prev = prev->prev;
+ break;
+ }
+ }
+
+ if (prev != NULL && iuser->passtype != prev->passtype) {
+ iuser->passtype = prev->passtype;
+ BKE_image_multilayer_index(rr, iuser);
+ WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+ }
}
}
+/* 5 view button callbacks... */
+static void image_multiview_cb(bContext *C, void *ima_v, void *iuser_v)
+{
+ Image *ima = ima_v;
+ ImageUser *iuser = iuser_v;
+
+ BKE_image_multiview_index(ima, iuser);
+ WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+}
+
#if 0
static void image_freecache_cb(bContext *C, void *ima_v, void *unused)
{
@@ -523,13 +636,14 @@ static void image_user_change(bContext *C, void *iuser_v, void *unused)
static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser, int w, short *render_slot)
{
- static void *rnd_pt[3]; /* XXX, workaround */
+ static void *rnd_pt[4]; /* XXX, workaround */
uiBlock *block = uiLayoutGetBlock(layout);
uiBut *but;
RenderLayer *rl = NULL;
- int wmenu1, wmenu2, wmenu3;
+ int wmenu1, wmenu2, wmenu3, wmenu4;
const char *fake_name;
- const char *display_name;
+ const char *display_name = "";
+ const bool show_stereo = (iuser->flag & IMA_SHOW_STEREO);
uiLayoutRow(layout, true);
@@ -537,6 +651,7 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes
wmenu1 = (2 * w) / 5;
wmenu2 = (3 * w) / 5;
wmenu3 = (3 * w) / 6;
+ wmenu4 = (3 * w) / 6;
rnd_pt[0] = image;
rnd_pt[1] = iuser;
@@ -558,6 +673,7 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes
if (rr) {
RenderPass *rpass;
+ RenderView *rview;
int rpass_index;
/* layer */
@@ -566,29 +682,59 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes
rl = BLI_findlink(&rr->layers, rpass_index);
rnd_pt[2] = SET_INT_IN_POINTER(rpass_index);
- 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"));
- UI_but_func_set(but, image_multi_cb, rr, iuser);
- UI_but_type_set_menu_from_pulldown(but);
-
+ 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"));
+ UI_but_func_set(but, image_multi_cb, rr, iuser);
+ UI_but_type_set_menu_from_pulldown(but);
+ }
/* pass */
fake_name = ui_imageuser_pass_fake_name(rl);
- rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass - (fake_name ? 1 : 0)) : NULL);
+ rpass = (rl ? RE_pass_find_by_type(rl, iuser->passtype, ((RenderView *)rr->views.first)->name) : NULL);
- display_name = rpass ? rpass->name : (fake_name ? fake_name : "");
+ display_name = rpass ? rpass->internal_name : (fake_name ? fake_name : "");
but = uiDefMenuBut(block, ui_imageuser_pass_menu, rnd_pt, display_name, 0, 0, wmenu3, UI_UNIT_Y, TIP_("Select Pass"));
UI_but_func_set(but, image_multi_cb, rr, iuser);
UI_but_type_set_menu_from_pulldown(but);
+
+ /* view */
+ if (BLI_listbase_count_ex(&rr->views, 2) > 1 && !show_stereo) {
+ 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);
+ UI_but_type_set_menu_from_pulldown(but);
+ }
+ }
+
+ /* stereo image */
+ else if (((image->flag & IMA_IS_STEREO) && (!show_stereo)) ||
+ ((image->flag & IMA_IS_MULTIVIEW) && ((image->flag & IMA_IS_STEREO) == 0)))
+ {
+ ImageView *iv;
+ int nr = 0;
+
+ for (iv = image->views.first; iv; iv = iv->next) {
+ if (nr++ == iuser->view) {
+ display_name = iv->name;
+ break;
+ }
+ }
+
+ 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);
+ UI_but_type_set_menu_from_pulldown(but);
}
}
-static void uiblock_layer_pass_arrow_buttons(uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser, short *render_slot)
+static void uiblock_layer_pass_arrow_buttons(uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser,
+ int menus_width, short *render_slot)
{
uiBlock *block = uiLayoutGetBlock(layout);
uiLayout *row;
uiBut *but;
- const float dpi_fac = UI_DPI_FAC;
row = uiLayoutRow(layout, true);
@@ -605,7 +751,7 @@ static void uiblock_layer_pass_arrow_buttons(uiLayout *layout, Image *image, Ren
but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_TRIA_RIGHT, 0, 0, 0.90f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Next Layer"));
UI_but_func_set(but, image_multi_inclay_cb, rr, iuser);
- uiblock_layer_pass_buttons(row, image, rr, iuser, 230 * dpi_fac, render_slot);
+ uiblock_layer_pass_buttons(row, image, rr, iuser, menus_width, render_slot);
/* decrease, increase arrows */
but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_TRIA_LEFT, 0, 0, 0.85f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Previous Pass"));
@@ -722,10 +868,17 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
else if (ima->type == IMA_TYPE_R_RESULT) {
/* browse layer/passes */
RenderResult *rr;
+ const float dpi_fac = UI_DPI_FAC;
+ const int menus_width = 230 * dpi_fac;
/* use BKE_image_acquire_renderresult so we get the correct slot in the menu */
rr = BKE_image_acquire_renderresult(scene, ima);
- uiblock_layer_pass_arrow_buttons(layout, ima, rr, iuser, &ima->render_slot);
+ if (rr) {
+ uiblock_layer_pass_arrow_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot);
+ }
+ else {
+ uiblock_layer_pass_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot);
+ }
BKE_image_release_renderresult(scene, ima);
}
}
@@ -734,13 +887,13 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
if (ima->source != IMA_SRC_GENERATED) {
row = uiLayoutRow(layout, true);
- if (ima->packedfile)
+ if (BKE_image_has_packedfile(ima))
uiItemO(row, "", ICON_PACKAGE, "image.unpack");
else
uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack");
row = uiLayoutRow(row, true);
- uiLayoutSetEnabled(row, ima->packedfile == NULL);
+ uiLayoutSetEnabled(row, BKE_image_has_packedfile(ima) == false);
uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE);
uiItemO(row, "", ICON_FILE_REFRESH, "image.reload");
}
@@ -758,7 +911,8 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
/* multilayer? */
if (ima->type == IMA_TYPE_MULTILAYER && ima->rr) {
- uiblock_layer_pass_arrow_buttons(layout, ima, ima->rr, iuser, NULL);
+ const float dpi_fac = UI_DPI_FAC;
+ uiblock_layer_pass_arrow_buttons(layout, ima, ima->rr, iuser, 230 * dpi_fac, NULL);
}
else if (ima->source != IMA_SRC_GENERATED) {
if (compact == 0) {
@@ -784,6 +938,14 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
BKE_image_release_ibuf(ima, ibuf, NULL);
}
+ if ((scene->r.scemode & R_MULTIVIEW) != 0) {
+ uiItemR(layout, &imaptr, "use_multiview", 0, NULL, ICON_NONE);
+
+ if (RNA_boolean_get(&imaptr, "use_multiview")) {
+ uiTemplateImageViews(layout, &imaptr);
+ }
+ }
+
if (has_alpha) {
col = uiLayoutColumn(layout, false);
uiItemR(col, &imaptr, "use_alpha", 0, NULL, ICON_NONE);
@@ -797,8 +959,6 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
uiItemR(col, &imaptr, "use_deinterlace", 0, IFACE_("Deinterlace"), ICON_NONE);
}
- uiItemS(layout);
-
split = uiLayoutSplit(layout, 0.0f, false);
col = uiLayoutColumn(split, false);
@@ -962,18 +1122,118 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_man
}
}
+void uiTemplateImageStereo3d(uiLayout *layout, PointerRNA *stereo3d_format_ptr)
+{
+ Stereo3dFormat *stereo3d_format = stereo3d_format_ptr->data;
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, stereo3d_format_ptr, "display_mode", 0, NULL, ICON_NONE);
+
+ switch (stereo3d_format->display_mode) {
+ case S3D_DISPLAY_ANAGLYPH:
+ {
+ uiItemR(col, stereo3d_format_ptr, "anaglyph_type", 0, NULL, ICON_NONE);
+ break;
+ }
+ case S3D_DISPLAY_INTERLACE:
+ {
+ uiItemR(col, stereo3d_format_ptr, "interlace_type", 0, NULL, ICON_NONE);
+ uiItemR(col, stereo3d_format_ptr, "use_interlace_swap", 0, NULL, ICON_NONE);
+ break;
+ }
+ case S3D_DISPLAY_SIDEBYSIDE:
+ {
+ uiItemR(col, stereo3d_format_ptr, "use_sidebyside_crosseyed", 0, NULL, ICON_NONE);
+ /* fall-through */
+ }
+ case S3D_DISPLAY_TOPBOTTOM:
+ {
+ uiItemR(col, stereo3d_format_ptr, "use_squeezed_frame", 0, NULL, ICON_NONE);
+ break;
+ }
+ }
+}
+
+static void uiTemplateViewsFormat(uiLayout *layout, PointerRNA *ptr, PointerRNA *stereo3d_format_ptr)
+{
+ uiLayout *col, *box;
+
+ col = uiLayoutColumn(layout, false);
+
+ uiItemL(col, IFACE_("Views Format:"), ICON_NONE);
+ uiItemR(uiLayoutRow(col, false), ptr, "views_format", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+
+ if (stereo3d_format_ptr) {
+ box = uiLayoutBox(col);
+ uiLayoutSetActive(box, RNA_enum_get(ptr, "views_format") == R_IMF_VIEWS_STEREO_3D);
+ uiTemplateImageStereo3d(box, stereo3d_format_ptr);
+ }
+}
+
+void uiTemplateImageViews(uiLayout *layout, PointerRNA *imaptr)
+{
+ Image *ima = imaptr->data;
+
+ if (ima->type != IMA_TYPE_MULTILAYER) {
+ PropertyRNA *prop;
+ PointerRNA stereo3d_format_ptr;
+
+ prop = RNA_struct_find_property(imaptr, "stereo_3d_format");
+ stereo3d_format_ptr = RNA_property_pointer_get(imaptr, prop);
+
+ uiTemplateViewsFormat(layout, imaptr, &stereo3d_format_ptr);
+ }
+ else {
+ uiTemplateViewsFormat(layout, imaptr, NULL);
+ }
+}
+
+void uiTemplateImageFormatViews(uiLayout *layout, PointerRNA *imfptr, PointerRNA *ptr)
+{
+ ImageFormatData *imf = imfptr->data;
+
+ if (ptr == NULL)
+ return;
+
+ uiItemR(layout, ptr, "use_multiview", 0, NULL, ICON_NONE);
+
+ if (RNA_boolean_get(ptr, "use_multiview")) {
+ if (imf->imtype != R_IMF_IMTYPE_MULTILAYER) {
+ PropertyRNA *prop;
+ PointerRNA stereo3d_format_ptr;
+
+ prop = RNA_struct_find_property(imfptr, "stereo_3d_format");
+ stereo3d_format_ptr = RNA_property_pointer_get(imfptr, prop);
+
+ uiTemplateViewsFormat(layout, imfptr, &stereo3d_format_ptr);
+ }
+ else {
+ uiTemplateViewsFormat(layout, imfptr, NULL);
+ }
+ }
+}
+
void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser *iuser)
{
Scene *scene = CTX_data_scene(C);
/* render layers and passes */
if (ima && iuser) {
- const float dpi_fac = UI_DPI_FAC;
RenderResult *rr;
+ const float dpi_fac = UI_DPI_FAC;
+ const int menus_width = 160 * dpi_fac;
+ const bool is_render_result = (ima->type == IMA_TYPE_R_RESULT);
/* use BKE_image_acquire_renderresult so we get the correct slot in the menu */
rr = BKE_image_acquire_renderresult(scene, ima);
- uiblock_layer_pass_buttons(layout, ima, rr, iuser, 160 * dpi_fac, (ima->type == IMA_TYPE_R_RESULT) ? &ima->render_slot : NULL);
+ if (rr && is_render_result) {
+ uiblock_layer_pass_arrow_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot);
+ }
+ else {
+ uiblock_layer_pass_buttons(layout, ima, rr, iuser, menus_width,
+ is_render_result ? &ima->render_slot : NULL);
+ }
BKE_image_release_renderresult(scene, ima);
}
}
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 7c5aa349fa0..34e32c150d6 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -68,6 +68,7 @@
#include "ED_gpencil.h"
#include "ED_image.h"
#include "ED_mask.h"
+#include "ED_render.h"
#include "ED_screen.h"
#include "UI_interface.h"
@@ -79,26 +80,36 @@
#include "image_intern.h"
-static void draw_render_info(Scene *scene, Image *ima, ARegion *ar, float zoomx, float zoomy)
+static void draw_render_info(const bContext *C,
+ Scene *scene,
+ Image *ima,
+ ARegion *ar,
+ float zoomx,
+ float zoomy)
{
RenderResult *rr;
Render *re = RE_GetRender(scene->id.name);
RenderData *rd = RE_engine_get_render_data(re);
+ Scene *stats_scene = ED_render_job_get_scene(C);
+ if (stats_scene == NULL) {
+ stats_scene = CTX_data_scene(C);
+ }
- rr = BKE_image_acquire_renderresult(scene, ima);
+ rr = BKE_image_acquire_renderresult(stats_scene, ima);
if (rr && rr->text) {
float fill_color[4] = {0.0f, 0.0f, 0.0f, 0.25f};
ED_region_info_draw(ar, rr->text, 1, fill_color);
}
- BKE_image_release_renderresult(scene, ima);
+ BKE_image_release_renderresult(stats_scene, ima);
if (re) {
int total_tiles;
+ bool need_free_tiles;
rcti *tiles;
- RE_engine_get_current_tiles(re, &total_tiles, &tiles);
+ tiles = RE_engine_get_current_tiles(re, &total_tiles, &need_free_tiles);
if (total_tiles) {
int i, x, y;
@@ -123,7 +134,9 @@ static void draw_render_info(Scene *scene, Image *ima, ARegion *ar, float zoomx,
glaDrawBorderCorners(tile, zoomx, zoomy);
}
- MEM_freeN(tiles);
+ if (need_free_tiles) {
+ MEM_freeN(tiles);
+ }
glPopMatrix();
}
@@ -500,7 +513,7 @@ static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar,
fdrawcheckerboard(x, y, x + ibuf->x * zoomx, y + ibuf->y * zoomy);
}
- glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST);
+ glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST, 1.0f);
if (sima->flag & SI_USE_ALPHA)
glDisable(GL_BLEND);
@@ -770,7 +783,7 @@ void draw_image_main(const bContext *C, ARegion *ar)
Image *ima;
ImBuf *ibuf;
float zoomx, zoomy;
- bool show_viewer, show_render, show_paint;
+ bool show_viewer, show_render, show_paint, show_stereo3d, show_multilayer;
void *lock;
/* XXX can we do this in refresh? */
@@ -800,6 +813,8 @@ void draw_image_main(const bContext *C, ARegion *ar)
show_viewer = (ima && ima->source == IMA_SRC_VIEWER) != 0;
show_render = (show_viewer && ima->type == IMA_TYPE_R_RESULT) != 0;
show_paint = (ima && (sima->mode == SI_MODE_PAINT) && (show_viewer == false) && (show_render == false));
+ show_stereo3d = (ima && (ima->flag & IMA_IS_STEREO) && (sima->iuser.flag & IMA_SHOW_STEREO));
+ show_multilayer = ima && BKE_image_is_multilayer(ima);
if (show_viewer) {
/* use locked draw for drawing viewer image buffer since the compositor
@@ -810,17 +825,41 @@ void draw_image_main(const bContext *C, ARegion *ar)
BLI_lock_thread(LOCK_DRAW_IMAGE);
}
+ if (show_stereo3d) {
+ if (show_multilayer)
+ /* update multiindex and pass for the current eye */
+ BKE_image_multilayer_index(ima->rr, &sima->iuser);
+ else
+ BKE_image_multiview_index(ima, &sima->iuser);
+ }
+
ibuf = ED_space_image_acquire_buffer(sima, &lock);
/* draw the image or grid */
- if (ibuf == NULL)
+ if (ibuf == NULL) {
ED_region_grid_draw(ar, zoomx, zoomy);
- else if (sima->flag & SI_DRAW_TILE)
- draw_image_buffer_repeated(C, sima, ar, scene, ima, ibuf, zoomx, zoomy);
- else if (ima && (ima->tpageflag & IMA_TILES))
- draw_image_buffer_tiled(sima, ar, scene, ima, ibuf, 0.0f, 0.0, zoomx, zoomy);
- else
- draw_image_buffer(C, sima, ar, scene, ibuf, 0.0f, 0.0f, zoomx, zoomy);
+ }
+ else {
+
+ if (sima->flag & SI_DRAW_TILE)
+ draw_image_buffer_repeated(C, sima, ar, scene, ima, ibuf, zoomx, zoomy);
+ else if (ima && (ima->tpageflag & IMA_TILES))
+ draw_image_buffer_tiled(sima, ar, scene, ima, ibuf, 0.0f, 0.0, zoomx, zoomy);
+ else
+ draw_image_buffer(C, sima, ar, scene, ibuf, 0.0f, 0.0f, zoomx, zoomy);
+
+ if (sima->flag & SI_DRAW_METADATA) {
+ int x, y;
+ rctf frame;
+
+ BLI_rctf_init(&frame, 0.0f, ibuf->x, 0.0f, ibuf->y);
+ UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x, &y);
+
+ ED_region_image_metadata_draw(x, y, ibuf, frame, zoomx, zoomy);
+ }
+ }
+
+ ED_space_image_release_buffer(sima, ibuf, lock);
/* paint helpers */
if (show_paint)
@@ -843,15 +882,13 @@ void draw_image_main(const bContext *C, ARegion *ar)
}
#endif
- ED_space_image_release_buffer(sima, ibuf, lock);
-
if (show_viewer) {
BLI_unlock_thread(LOCK_DRAW_IMAGE);
}
/* render info */
if (ima && show_render)
- draw_render_info(sima->iuser.scene, ima, ar, zoomx, zoomy);
+ draw_render_info(C, sima->iuser.scene, ima, ar, zoomx, zoomy);
}
bool ED_space_image_show_cache(SpaceImage *sima)
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index 8e2c6b97a5b..38c9604d14b 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -104,7 +104,7 @@ void ED_space_image_set_mask(bContext *C, SpaceImage *sima, Mask *mask)
}
}
-ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **lock_r)
+ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock)
{
ImBuf *ibuf;
@@ -114,7 +114,7 @@ ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **lock_r)
return BIF_render_spare_imbuf();
else
#endif
- ibuf = BKE_image_acquire_ibuf(sima->image, &sima->iuser, lock_r);
+ ibuf = BKE_image_acquire_ibuf(sima->image, &sima->iuser, r_lock);
if (ibuf) {
if (ibuf->rect || ibuf->rect_float)
@@ -124,7 +124,7 @@ ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **lock_r)
}
}
else
- *lock_r = NULL;
+ *r_lock = NULL;
return NULL;
}
@@ -299,7 +299,7 @@ void ED_space_image_scopes_update(const struct bContext *C, struct SpaceImage *s
/* scope update can be expensive, don't update during paint modes */
if (sima->mode == SI_MODE_PAINT)
return;
- if (ob && ((ob->mode & OB_MODE_TEXTURE_PAINT) != 0))
+ if (ob && ((ob->mode & (OB_MODE_TEXTURE_PAINT | OB_MODE_EDIT)) != 0))
return;
scopes_update(&sima->scopes, ibuf, use_view_settings ? &scene->view_settings : NULL, &scene->display_settings);
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index aecc43f4fdf..6eaad302180 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -38,11 +38,7 @@ struct ARegion;
struct ARegionType;
struct ScrArea;
struct SpaceImage;
-struct Object;
-struct Image;
-struct ImBuf;
struct wmOperatorType;
-struct Scene;
struct bNodeTree;
/* space_image.c */
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 61667b02140..ca2f19cde91 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -30,14 +30,21 @@
#include <stddef.h>
#include <string.h>
+#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
+#ifndef WIN32
+# include <unistd.h>
+#else
+# include <io.h>
+#endif
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_string_utf8.h"
#include "BLF_translation.h"
@@ -60,6 +67,7 @@
#include "BKE_report.h"
#include "BKE_screen.h"
#include "BKE_sound.h"
+#include "BKE_scene.h"
#include "GPU_draw.h"
#include "GPU_buffers.h"
@@ -68,6 +76,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_moviecache.h"
+#include "intern/openexr/openexr_multi.h"
#include "RE_pipeline.h"
@@ -369,7 +378,7 @@ void IMAGE_OT_view_pan(wmOperatorType *ot)
ot->poll = space_image_main_area_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER | OPTYPE_LOCK_BYPASS;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS;
/* properties */
RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
@@ -585,7 +594,7 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
ot->poll = space_image_main_area_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER | OPTYPE_LOCK_BYPASS;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS;
/* properties */
prop = RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX, "Factor",
@@ -711,6 +720,9 @@ void IMAGE_OT_view_all(wmOperatorType *ot)
ot->exec = image_view_all_exec;
ot->poll = space_image_main_area_poll;
+ /* flags */
+ ot->flag = OPTYPE_LOCK_BYPASS;
+
/* properties */
prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
@@ -936,6 +948,7 @@ static void image_filesel(bContext *C, wmOperator *op, const char *path)
typedef struct ImageOpenData {
PropertyPointerRNA pprop;
ImageUser *iuser;
+ ImageFormatData im_format;
} ImageOpenData;
typedef struct ImageFrame {
@@ -946,7 +959,6 @@ typedef struct ImageFrame {
static void image_open_init(bContext *C, wmOperator *op)
{
ImageOpenData *iod;
-
op->customdata = iod = MEM_callocN(sizeof(ImageOpenData), __func__);
iod->iuser = CTX_data_pointer_get_type(C, "image_user", &RNA_ImageUser).data;
UI_context_active_but_prop_get_templateID(C, &iod->pprop.ptr, &iod->pprop.prop);
@@ -1048,7 +1060,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
ImageUser *iuser = NULL;
- ImageOpenData *iod;
+ ImageOpenData *iod = op->customdata;
PointerRNA idptr;
Image *ima = NULL;
char path[FILE_MAX];
@@ -1085,6 +1097,21 @@ static int image_open_exec(bContext *C, wmOperator *op)
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;
+ }
+ else {
+ ima->flag &= ~IMA_USE_VIEWS;
+ ima->flag &= ~IMA_IS_STEREO;
+ ima->flag &= ~IMA_IS_MULTIVIEW;
+ BKE_image_free_views(ima);
+ }
+
/* only image path after save, never ibuf */
if (is_relative_path) {
if (!exists) {
@@ -1128,6 +1155,8 @@ static int image_open_exec(bContext *C, wmOperator *op)
iuser->framenr = 1;
iuser->offset = frame_ofs - 1;
iuser->fie_ima = 2;
+ iuser->scene = scene;
+ BKE_image_init_imageuser(ima, iuser);
}
/* XXX unpackImage frees image buffers */
@@ -1146,7 +1175,8 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
const char *path = U.textudir;
Image *ima = NULL;
-
+ Scene *scene = CTX_data_scene(C);
+ PropertyRNA *prop;
if (sima) {
ima = sima->image;
}
@@ -1185,11 +1215,44 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
image_open_init(C, op);
+ /* show multiview save options only if scene has multiviews */
+ prop = RNA_struct_find_property(op->ptr, "show_multiview");
+ RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
+
image_filesel(C, op, path);
return OPERATOR_RUNNING_MODAL;
}
+static bool image_open_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+
+ return !(STREQ(prop_id, "filepath") ||
+ STREQ(prop_id, "directory") ||
+ STREQ(prop_id, "filename")
+ );
+}
+
+static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ ImageOpenData *iod = op->customdata;
+ ImageFormatData *imf = &iod->im_format;
+ PointerRNA imf_ptr, ptr;
+
+ /* main draw call */
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+ uiDefAutoButsRNA(layout, &ptr, image_open_draw_check_prop, '\0');
+
+ /* image template */
+ RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
+
+ /* multiview template */
+ if (RNA_boolean_get(op->ptr, "show_multiview"))
+ uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
+}
+
/* called by other space types too */
void IMAGE_OT_open(wmOperatorType *ot)
{
@@ -1202,6 +1265,7 @@ void IMAGE_OT_open(wmOperatorType *ot)
ot->exec = image_open_exec;
ot->invoke = image_open_invoke;
ot->cancel = image_open_cancel;
+ ot->ui = image_open_draw;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1233,10 +1297,10 @@ static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
}
- if (!ima || !iuser || !ima->anim)
+ if (!ima || !iuser || !BKE_image_has_anim(ima))
return OPERATOR_CANCELLED;
- iuser->frames = IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN);
+ iuser->frames = IMB_anim_get_duration(((ImageAnim *) ima->anims.first)->anim, IMB_TC_RECORD_RUN);
BKE_image_user_frame_calc(iuser, scene->r.cfra, 0);
return OPERATOR_FINISHED;
@@ -1285,7 +1349,7 @@ static int image_replace_exec(bContext *C, wmOperator *op)
/* XXX unpackImage frees image buffers */
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- BKE_icon_changed(BKE_icon_getid(&sima->image->id));
+ BKE_icon_changed(BKE_icon_id_ensure(&sima->image->id));
BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
@@ -1433,6 +1497,10 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima,
}
}
+ /* use the multiview image settings as the default */
+ simopts->im_format.stereo3d_format = *ima->stereo3d_format;
+ simopts->im_format.views_format = ima->views_format;
+
/* color management */
BKE_color_managed_display_settings_copy(&simopts->im_format.display_settings, &scene->display_settings);
BKE_color_managed_view_settings_copy(&simopts->im_format.view_settings, &scene->view_settings);
@@ -1468,30 +1536,104 @@ static void save_image_options_to_op(SaveImageOptions *simopts, wmOperator *op)
RNA_string_set(op->ptr, "filepath", simopts->filepath);
}
+static void save_image_post(wmOperator *op, ImBuf *ibuf, Image *ima, int ok, int save_copy, const char *relbase, int relative, int do_newpath, const char *filepath)
+{
+ if (ok) {
+ if (!save_copy) {
+ ColorManagedColorspaceSettings old_colorspace_settings;
+
+ if (do_newpath) {
+ BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
+ BLI_strncpy(ima->name, filepath, sizeof(ima->name));
+ }
+
+ ibuf->userflags &= ~IB_BITMAPDIRTY;
+
+ /* change type? */
+ if (ima->type == IMA_TYPE_R_RESULT) {
+ ima->type = IMA_TYPE_IMAGE;
+
+ /* workaround to ensure the render result buffer is no longer used
+ * by this image, otherwise can crash when a new render result is
+ * created. */
+ if (ibuf->rect && !(ibuf->mall & IB_rect))
+ imb_freerectImBuf(ibuf);
+ if (ibuf->rect_float && !(ibuf->mall & IB_rectfloat))
+ imb_freerectfloatImBuf(ibuf);
+ if (ibuf->zbuf && !(ibuf->mall & IB_zbuf))
+ IMB_freezbufImBuf(ibuf);
+ if (ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat))
+ IMB_freezbuffloatImBuf(ibuf);
+ }
+ if (ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
+ ima->source = IMA_SRC_FILE;
+ ima->type = IMA_TYPE_IMAGE;
+ }
+
+ /* only image path, never ibuf */
+ if (relative) {
+ BLI_path_rel(ima->name, relbase); /* only after saving */
+ }
+
+ BKE_color_managed_colorspace_settings_copy(&old_colorspace_settings,
+ &ima->colorspace_settings);
+ IMB_colormanagment_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
+ if (!BKE_color_managed_colorspace_settings_equals(&old_colorspace_settings,
+ &ima->colorspace_settings))
+ {
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_COLORMANAGE);
+ }
+ }
+ }
+ else {
+ BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s", filepath);
+ }
+}
+
+static void save_imbuf_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
+{
+ if (colormanaged_ibuf != ibuf) {
+ /* This guys might be modified by image buffer write functions,
+ * need to copy them back from color managed image buffer to an
+ * original one, so file type of image is being properly updated.
+ */
+ ibuf->ftype = colormanaged_ibuf->ftype;
+ ibuf->planes = colormanaged_ibuf->planes;
+
+ IMB_freeImBuf(colormanaged_ibuf);
+ }
+}
+
/**
* \return success.
* \note ``ima->name`` and ``ibuf->name`` should end up the same.
+ * \note for multiview the first ``ibuf`` is important to get the settings.
*/
static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveImageOptions *simopts, bool do_newpath)
{
Image *ima = ED_space_image(sima);
void *lock;
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
+ Scene *scene;
+ RenderResult *rr = NULL;
bool ok = false;
+ WM_cursor_wait(1);
+
if (ibuf) {
- ImBuf *colormanaged_ibuf;
+ ImBuf *colormanaged_ibuf = NULL;
const char *relbase = ID_BLEND_PATH(CTX_data_main(C), &ima->id);
const bool relative = (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path"));
const bool save_copy = (RNA_struct_find_property(op->ptr, "copy") && RNA_boolean_get(op->ptr, "copy"));
const bool save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") && RNA_boolean_get(op->ptr, "save_as_render"));
ImageFormatData *imf = &simopts->im_format;
+ const bool is_multilayer = imf->imtype == R_IMF_IMTYPE_MULTILAYER;
+ bool is_mono;
+
/* old global to ensure a 2nd save goes to same dir */
BLI_strncpy(G.ima, simopts->filepath, sizeof(G.ima));
- WM_cursor_wait(1);
-
if (ima->type == IMA_TYPE_R_RESULT) {
/* enforce user setting for RGB or RGBA, but skip BW */
if (simopts->im_format.planes == R_IMF_PLANES_RGBA) {
@@ -1512,83 +1654,194 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
}
}
- colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
+ /* we need renderresult for exr and rendered multiview */
+ scene = CTX_data_scene(C);
+ rr = BKE_image_acquire_renderresult(scene, ima);
+ is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : (ima->flag & IMA_IS_MULTIVIEW) == 0;
- if (simopts->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
- Scene *scene = CTX_data_scene(C);
- RenderResult *rr = BKE_image_acquire_renderresult(scene, ima);
- if (rr) {
- ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, simopts->im_format.exr_codec);
- }
- else {
+ /* error handling */
+ if (!rr) {
+ if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
BKE_report(op->reports, RPT_ERROR, "Did not write, no Multilayer Image");
+ goto cleanup;
}
- BKE_image_release_renderresult(scene, ima);
}
else {
- ok = BKE_imbuf_write_as(colormanaged_ibuf, simopts->filepath, &simopts->im_format, save_copy);
- }
-
- if (ok) {
- if (!save_copy) {
- if (do_newpath) {
- BLI_strncpy(ibuf->name, simopts->filepath, sizeof(ibuf->name));
- BLI_strncpy(ima->name, simopts->filepath, sizeof(ima->name));
+ if (imf->views_format == R_IMF_VIEWS_STEREO_3D) {
+ if ((ima->flag & IMA_IS_STEREO) == 0) {
+ BKE_reportf(op->reports, RPT_ERROR, "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
+ STEREO_LEFT_NAME, STEREO_RIGHT_NAME);
+ goto cleanup;
}
- ibuf->userflags &= ~IB_BITMAPDIRTY;
-
- /* change type? */
- if (ima->type == IMA_TYPE_R_RESULT) {
- ima->type = IMA_TYPE_IMAGE;
-
- /* workaround to ensure the render result buffer is no longer used
- * by this image, otherwise can crash when a new render result is
- * created. */
- if (ibuf->rect && !(ibuf->mall & IB_rect))
- imb_freerectImBuf(ibuf);
- if (ibuf->rect_float && !(ibuf->mall & IB_rectfloat))
- imb_freerectfloatImBuf(ibuf);
- if (ibuf->zbuf && !(ibuf->mall & IB_zbuf))
- IMB_freezbufImBuf(ibuf);
- if (ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat))
- IMB_freezbuffloatImBuf(ibuf);
- }
- if (ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
- ima->source = IMA_SRC_FILE;
- ima->type = IMA_TYPE_IMAGE;
+ /* it shouldn't ever happen*/
+ if ((BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name)) == NULL) ||
+ (BLI_findstring(&rr->views, STEREO_RIGHT_NAME, offsetof(RenderView, name)) == NULL))
+ {
+ BKE_reportf(op->reports, RPT_ERROR, "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
+ STEREO_LEFT_NAME, STEREO_RIGHT_NAME);
+ goto cleanup;
}
+ }
+ BKE_imbuf_stamp_info(rr, ibuf);
+ }
- /* only image path, never ibuf */
- if (relative) {
- BLI_path_rel(ima->name, relbase); /* only after saving */
+ /* fancy multiview OpenEXR */
+ if ((imf->imtype == R_IMF_IMTYPE_MULTILAYER) && (imf->views_format == R_IMF_VIEWS_MULTIVIEW)) {
+ ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, true, NULL);
+ save_image_post(op, ibuf, ima, ok, true, relbase, relative, do_newpath, simopts->filepath);
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ }
+ else if ((imf->imtype == R_IMF_IMTYPE_OPENEXR) && (imf->views_format == R_IMF_VIEWS_MULTIVIEW)) {
+ /* treat special Openexr case separetely (this is the singlelayer multiview OpenEXR */
+ BKE_imbuf_write_prepare(ibuf, imf);
+ ok = BKE_image_save_openexr_multiview(ima, ibuf, simopts->filepath, (IB_rect | IB_zbuf | IB_zbuffloat | IB_multiview));
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ }
+ /* regular mono pipeline */
+ else if (is_mono) {
+ if (is_multilayer) {
+ ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, false, NULL);
+ }
+ else {
+ colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
+ IMB_metadata_copy(colormanaged_ibuf, ibuf);
+ ok = BKE_imbuf_write_as(colormanaged_ibuf, simopts->filepath, imf, save_copy);
+ save_imbuf_post(ibuf, colormanaged_ibuf);
+ }
+ save_image_post(op, ibuf, ima, ok, (is_multilayer ? true : save_copy), relbase, relative, do_newpath, simopts->filepath);
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ }
+ /* individual multiview images */
+ else if (imf->views_format == R_IMF_VIEWS_INDIVIDUAL) {
+ size_t i;
+ unsigned char planes = ibuf->planes;
+ const size_t totviews = (rr ? BLI_listbase_count(&rr->views) : BLI_listbase_count(&ima->views));
+
+ if (!is_multilayer) {
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ }
+
+ for (i = 0; i < totviews; i++) {
+ char filepath[FILE_MAX];
+ bool ok_view = false;
+ const char *view = rr ? ((RenderView *) BLI_findlink(&rr->views, i))->name :
+ ((ImageView *) BLI_findlink(&ima->views, i))->name;
+
+ if (is_multilayer) {
+ BKE_scene_multiview_view_filepath_get(&scene->r, simopts->filepath, view, filepath);
+ ok_view = RE_WriteRenderResult(op->reports, rr, filepath, imf, false, view);
+ save_image_post(op, ibuf, ima, ok_view, true, relbase, relative, do_newpath, filepath);
+ }
+ else {
+ /* copy iuser to get the correct ibuf for this view */
+ ImageUser iuser = sima->iuser;
+ iuser.view = i;
+ iuser.flag &= ~IMA_SHOW_STEREO;
+
+ if (rr)
+ BKE_image_multilayer_index(rr, &iuser);
+ else
+ BKE_image_multiview_index(ima, &iuser);
+
+ ibuf = BKE_image_acquire_ibuf(sima->image, &iuser, &lock);
+ ibuf->planes = planes;
+
+ BKE_scene_multiview_view_filepath_get(&scene->r, simopts->filepath, view, filepath);
+
+ colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
+ ok_view = BKE_imbuf_write_as(colormanaged_ibuf, filepath, &simopts->im_format, save_copy);
+ save_imbuf_post(ibuf, colormanaged_ibuf);
+ save_image_post(op, ibuf, ima, ok_view, true, relbase, relative, do_newpath, filepath);
+ BKE_image_release_ibuf(sima->image, ibuf, lock);
}
+ ok &= ok_view;
+ }
- IMB_colormanagment_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
+ if (is_multilayer) {
+ ED_space_image_release_buffer(sima, ibuf, lock);
}
}
- else {
- BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s", simopts->filepath);
- }
+ /* stereo (multiview) images */
+ else if (simopts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
+ if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
+ ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, false, NULL);
+ save_image_post(op, ibuf, ima, ok, true, relbase, relative, do_newpath, simopts->filepath);
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ }
+ else {
+ ImBuf *ibuf_stereo[2] = {NULL};
+ unsigned char planes = ibuf->planes;
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ int i;
- WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
+ /* we need to get the specific per-view buffers */
+ ED_space_image_release_buffer(sima, ibuf, lock);
+
+ for (i = 0; i < 2; i ++) {
+ ImageUser iuser = sima->iuser;
+ iuser.flag &= ~IMA_SHOW_STEREO;
+
+ if (rr) {
+ int id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
+ iuser.view = id;
+ BKE_image_multilayer_index(rr, &iuser);
+ }
+ else {
+ iuser.view = i;
+ BKE_image_multiview_index(ima, &iuser);
+ }
+
+ ibuf = BKE_image_acquire_ibuf(sima->image, &iuser, &lock);
+
+ if (ibuf == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Did not write, unexpected error when saving stereo image");
+ goto cleanup;
+ }
+
+ ibuf->planes = planes;
+
+ /* color manage the ImBuf leaving it ready for saving */
+ colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true,
+ &imf->view_settings, &imf->display_settings, imf);
+
+ BKE_imbuf_write_prepare(colormanaged_ibuf, imf);
+ IMB_prepare_write_ImBuf(IMB_isfloat(colormanaged_ibuf), colormanaged_ibuf);
+
+ /* duplicate buffer to prevent locker issue when using render result */
+ ibuf_stereo[i] = IMB_dupImBuf(colormanaged_ibuf);
+
+ save_imbuf_post(ibuf, colormanaged_ibuf);
+ BKE_image_release_ibuf(sima->image, ibuf, lock);
+ }
+
+ ibuf = IMB_stereo3d_ImBuf(imf, ibuf_stereo[0], ibuf_stereo[1]);
- WM_cursor_wait(0);
+ /* save via traditional path */
+ ok = BKE_imbuf_write_as(ibuf, simopts->filepath, imf, save_copy);
- if (colormanaged_ibuf != ibuf) {
- /* This guys might be modified by image buffer write functions,
- * need to copy them back from color managed image buffer to an
- * original one, so file type of image is being properly updated.
- */
- ibuf->ftype = colormanaged_ibuf->ftype;
- ibuf->planes = colormanaged_ibuf->planes;
+ IMB_freeImBuf(ibuf);
- IMB_freeImBuf(colormanaged_ibuf);
+ for (i = 0; i < 2; i ++) {
+ IMB_freeImBuf(ibuf_stereo[i]);
+ }
+ }
}
+
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
+
+ }
+ else {
+cleanup:
+ ED_space_image_release_buffer(sima, ibuf, lock);
}
- ED_space_image_release_buffer(sima, ibuf, lock);
+ if (rr) {
+ BKE_image_release_renderresult(scene, ima);
+ }
+
+ WM_cursor_wait(0);
return ok;
}
@@ -1636,6 +1889,7 @@ static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
Image *ima = ED_space_image(sima);
Scene *scene = CTX_data_scene(C);
SaveImageOptions simopts;
+ PropertyRNA *prop;
const bool save_as_render = ((ima->source == IMA_SRC_VIEWER) || (ima->flag & IMA_VIEW_AS_RENDER));
if (RNA_struct_property_is_set(op->ptr, "filepath"))
@@ -1657,6 +1911,12 @@ static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
op->customdata = MEM_mallocN(sizeof(simopts.im_format), __func__);
memcpy(op->customdata, &simopts.im_format, sizeof(simopts.im_format));
+ /* show multiview save options only if image has multiviews */
+ prop = RNA_struct_find_property(op->ptr, "show_multiview");
+ RNA_property_boolean_set(op->ptr, prop, (ima->flag & IMA_IS_MULTIVIEW) != 0);
+ prop = RNA_struct_find_property(op->ptr, "use_multiview");
+ RNA_property_boolean_set(op->ptr, prop, (ima->flag & IMA_IS_MULTIVIEW) != 0);
+
image_filesel(C, op, simopts.filepath);
return OPERATOR_RUNNING_MODAL;
@@ -1683,15 +1943,20 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
ImageFormatData *imf = op->customdata;
- PointerRNA ptr;
+ PointerRNA imf_ptr, ptr;
+ const bool is_multiview = RNA_boolean_get(op->ptr, "show_multiview");
/* image template */
- RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &ptr);
- uiTemplateImageSettings(layout, &ptr, false);
+ RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
+ uiTemplateImageSettings(layout, &imf_ptr, false);
/* main draw call */
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
uiDefAutoButsRNA(layout, &ptr, image_save_as_draw_check_prop, '\0');
+
+ /* multiview template */
+ if (is_multiview)
+ uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
}
static int image_save_as_poll(bContext *C)
@@ -1714,8 +1979,6 @@ static int image_save_as_poll(bContext *C)
void IMAGE_OT_save_as(wmOperatorType *ot)
{
-// PropertyRNA *prop;
-
/* identifiers */
ot->name = "Save As Image";
ot->idname = "IMAGE_OT_save_as";
@@ -1932,6 +2195,7 @@ static int image_new_exec(bContext *C, wmOperator *op)
float color[4];
int width, height, floatbuf, gen_type, alpha;
int gen_context;
+ int stereo3d;
/* retrieve state */
sima = CTX_wm_space_image(C);
@@ -1952,11 +2216,12 @@ static int image_new_exec(bContext *C, wmOperator *op)
RNA_float_get_array(op->ptr, "color", color);
alpha = RNA_boolean_get(op->ptr, "alpha");
gen_context = RNA_enum_get(op->ptr, "gen_context");
+ stereo3d = RNA_boolean_get(op->ptr, "use_stereo_3d");
if (!alpha)
color[3] = 1.0f;
- ima = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color);
+ ima = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color, stereo3d);
if (!ima)
return OPERATOR_CANCELLED;
@@ -2036,6 +2301,53 @@ static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e
return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y);
}
+static void image_new_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *split, *col[2];
+ uiLayout *layout = op->layout;
+ PointerRNA ptr;
+#if 0
+ Scene *scene = CTX_data_scene(C);
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
+#endif
+
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+
+ /* copy of WM_operator_props_dialog_popup() layout */
+
+ split = uiLayoutSplit(layout, 0.5f, false);
+ col[0] = uiLayoutColumn(split, false);
+ col[1] = uiLayoutColumn(split, false);
+
+ uiItemL(col[0], IFACE_("Name"), ICON_NONE);
+ uiItemR(col[1], &ptr, "name", 0, "", ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Width"), ICON_NONE);
+ uiItemR(col[1], &ptr, "width", 0, "", ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Height"), ICON_NONE);
+ uiItemR(col[1], &ptr, "height", 0, "", ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Color"), ICON_NONE);
+ uiItemR(col[1], &ptr, "color", 0, "", ICON_NONE);
+
+ uiItemL(col[0], "", ICON_NONE);
+ uiItemR(col[1], &ptr, "alpha", 0, NULL, ICON_NONE);
+
+ uiItemL(col[0], IFACE_("Generated Type"), ICON_NONE);
+ uiItemR(col[1], &ptr, "generated_type", 0, "", ICON_NONE);
+
+ uiItemL(col[0], "", ICON_NONE);
+ uiItemR(col[1], &ptr, "float", 0, NULL, ICON_NONE);
+
+#if 0
+ if (is_multiview) {
+ uiItemL(col[0], "", ICON_NONE);
+ uiItemR(col[1], &ptr, "use_stereo_3d", 0, NULL, ICON_NONE);
+ }
+#endif
+}
+
void IMAGE_OT_new(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -2056,6 +2368,7 @@ void IMAGE_OT_new(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_new_exec;
ot->invoke = image_new_invoke;
+ ot->ui = image_new_draw;
/* flags */
ot->flag = OPTYPE_UNDO;
@@ -2075,7 +2388,8 @@ void IMAGE_OT_new(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
prop = RNA_def_enum(ot->srna, "gen_context", gen_context_items, 0, "Gen Context", "Generation context");
RNA_def_property_flag(prop, PROP_HIDDEN);
-
+ prop = RNA_def_boolean(ot->srna, "use_stereo_3d", 0, "Stereo 3D", "Create an image with left and right views");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
#undef IMA_DEF_NAME
@@ -2103,7 +2417,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
const bool b = RNA_boolean_get(op->ptr, "invert_b");
const bool a = RNA_boolean_get(op->ptr, "invert_a");
- int i;
+ size_t i;
if (ibuf == NULL) /* TODO: this should actually never happen, but does for render-results -> cleanup */
return OPERATOR_CANCELLED;
@@ -2114,13 +2428,13 @@ static int image_invert_exec(bContext *C, wmOperator *op)
/* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles
* but better do this right in case someone copies this for a tool that uses partial redraw better */
ED_imapaint_clear_partial_redraw();
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
}
/* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
if (ibuf->rect_float) {
float *fp = (float *) ibuf->rect_float;
- for (i = ibuf->x * ibuf->y; i > 0; i--, fp += 4) {
+ for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, fp += 4) {
if (r) fp[0] = 1.0f - fp[0];
if (g) fp[1] = 1.0f - fp[1];
if (b) fp[2] = 1.0f - fp[2];
@@ -2134,7 +2448,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
else if (ibuf->rect) {
char *cp = (char *) ibuf->rect;
- for (i = ibuf->x * ibuf->y; i > 0; i--, cp += 4) {
+ for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, cp += 4) {
if (r) cp[0] = 255 - cp[0];
if (g) cp[1] = 255 - cp[1];
if (b) cp[2] = 255 - cp[2];
@@ -2200,7 +2514,7 @@ static bool image_pack_test(bContext *C, wmOperator *op)
if (!ima)
return 0;
- if (!as_png && ima->packedfile)
+ if (!as_png && BKE_image_has_packedfile(ima))
return 0;
if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
@@ -2229,7 +2543,7 @@ static int image_pack_exec(bContext *C, wmOperator *op)
if (as_png)
BKE_image_memorypack(ima);
else
- ima->packedfile = newPackedFile(op->reports, ima->name, ID_BLEND_PATH(bmain, &ima->id));
+ BKE_image_packfiles(op->reports, ima, ID_BLEND_PATH(bmain, &ima->id));
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
@@ -2301,7 +2615,7 @@ static int image_unpack_exec(bContext *C, wmOperator *op)
if (!ima) ima = CTX_data_edit_image(C);
}
- if (!ima || !ima->packedfile)
+ if (!ima || !BKE_image_has_packedfile(ima))
return OPERATOR_CANCELLED;
if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
@@ -2329,7 +2643,7 @@ static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
if (RNA_struct_property_is_set(op->ptr, "id"))
return image_unpack_exec(C, op);
- if (!ima || !ima->packedfile)
+ if (!ima || !BKE_image_has_packedfile(ima))
return OPERATOR_CANCELLED;
if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
@@ -2340,7 +2654,7 @@ static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
if (G.fileflags & G_AUTOPACK)
BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save");
- unpack_menu(C, "IMAGE_OT_unpack", ima->id.name + 2, ima->name, "textures", ima->packedfile);
+ unpack_menu(C, "IMAGE_OT_unpack", ima->id.name + 2, ima->name, "textures", BKE_image_has_packedfile(ima) ? ((ImagePackedFile *)ima->packedfiles.first)->packedfile : NULL);
return OPERATOR_FINISHED;
}
@@ -2609,8 +2923,11 @@ static int image_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case LEFTMOUSE:
case RIGHTMOUSE: // XXX hardcoded
- image_sample_exit(C, op);
- return OPERATOR_CANCELLED;
+ if (event->val == KM_RELEASE) {
+ image_sample_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ break;
case MOUSEMOVE:
image_sample_apply(C, op, event);
break;
@@ -2982,7 +3299,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
SUBFRA = 0.0f;
/* do updates */
- sound_seek_scene(CTX_data_main(C), scene);
+ BKE_sound_seek_scene(CTX_data_main(C), scene);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index af1502509f5..a9a5e601e10 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -156,7 +156,9 @@ static SpaceLink *image_new(const bContext *UNUSED(C))
simage->iuser.ok = true;
simage->iuser.fie_ima = 2;
simage->iuser.frames = 100;
-
+ simage->iuser.flag = IMA_SHOW_STEREO;
+ simage->iuser.passtype = SCE_PASS_COMBINED;
+
scopes_new(&simage->scopes);
simage->sample_line_hist.height = 100;
@@ -681,7 +683,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
View2D *v2d = &ar->v2d;
//View2DScrollers *scrollers;
float col[3];
-
+
/* XXX not supported yet, disabling for now */
scene->r.scemode &= ~R_COMP_CROP;
@@ -693,7 +695,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
/* put scene context variable in iuser */
if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) {
/* for render result, try to use the currently rendering scene */
- Scene *render_scene = ED_render_job_get_scene(C);
+ Scene *render_scene = ED_render_job_get_current_scene(C);
if (render_scene)
sima->iuser.scene = render_scene;
else
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index 240d8baa6f2..a1f90f16bbf 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -134,7 +134,7 @@ static int autopack_toggle_exec(bContext *C, wmOperator *op)
G.fileflags &= ~G_AUTOPACK;
}
else {
- packAll(bmain, op->reports);
+ packAll(bmain, op->reports, true);
G.fileflags |= G_AUTOPACK;
}
@@ -161,7 +161,7 @@ static int pack_all_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- packAll(bmain, op->reports);
+ packAll(bmain, op->reports, true);
G.fileflags |= G_AUTOPACK;
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index a0dfb285a1c..48a39cd79fc 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -56,6 +56,8 @@
#include "ED_info.h"
#include "ED_armature.h"
+#include "GPU_extensions.h"
+
#define MAX_INFO_LEN 512
#define MAX_INFO_NUM_LEN 16
@@ -381,6 +383,7 @@ static void stats_string(Scene *scene)
Object *ob = (scene->basact) ? scene->basact->object : NULL;
uintptr_t mem_in_use, mmap_in_use;
char memstr[MAX_INFO_MEM_LEN];
+ char gpumemstr[MAX_INFO_MEM_LEN] = "";
char *s;
size_t ofs = 0;
@@ -416,11 +419,22 @@ static void stats_string(Scene *scene)
/* get memory statistics */
- s = memstr;
- ofs += BLI_snprintf(s + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" | Mem:%.2fM"),
+ ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, IFACE_(" | Mem:%.2fM"),
(double)((mem_in_use - mmap_in_use) >> 10) / 1024.0);
if (mmap_in_use)
- BLI_snprintf(s + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" (%.2fM)"), (double)((mmap_in_use) >> 10) / 1024.0);
+ BLI_snprintf(memstr + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" (%.2fM)"), (double)((mmap_in_use) >> 10) / 1024.0);
+
+ if (GPU_mem_stats_supported()) {
+ int gpu_free_mem, gpu_tot_memory;
+
+ GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem);
+
+ ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, IFACE_(" | Free GPU Mem:%.2fM"), (double)((gpu_free_mem)) / 1024.0);
+
+ if (gpu_tot_memory) {
+ BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_("/%.2fM"), (double)((gpu_tot_memory)) / 1024.0);
+ }
+ }
s = stats->infostr;
ofs = 0;
@@ -447,22 +461,23 @@ static void stats_string(Scene *scene)
}
ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs);
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
- ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%s/%s %s"),
- stats_fmt.totbonesel, stats_fmt.totbone, memstr);
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%s/%s %s%s"),
+ stats_fmt.totbonesel, stats_fmt.totbone, memstr, gpumemstr);
}
else if (stats_is_object_dynamic_topology_sculpt(ob)) {
- ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s | Tris:%s"), stats_fmt.totvert,
- stats_fmt.tottri);
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s | Tris:%s%s"), stats_fmt.totvert,
+ stats_fmt.tottri, gpumemstr);
}
else {
ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs,
- IFACE_("Verts:%s | Faces:%s | Tris:%s | Objects:%s/%s | Lamps:%s/%s%s"),
+ IFACE_("Verts:%s | Faces:%s | Tris:%s | Objects:%s/%s | Lamps:%s/%s%s%s"),
stats_fmt.totvert, stats_fmt.totface,
stats_fmt.tottri, stats_fmt.totobjsel,
stats_fmt.totobj, stats_fmt.totlampsel,
- stats_fmt.totlamp, memstr);
+ stats_fmt.totlamp, memstr, gpumemstr);
}
if (ob)
diff --git a/source/blender/editors/space_logic/logic_intern.h b/source/blender/editors/space_logic/logic_intern.h
index 38b122f64b6..13146621d1b 100644
--- a/source/blender/editors/space_logic/logic_intern.h
+++ b/source/blender/editors/space_logic/logic_intern.h
@@ -35,12 +35,8 @@
/* internal exports only */
struct bContext;
struct ARegion;
-struct ARegionType;
struct ScrArea;
-struct SpaceLogic;
-struct Object;
struct wmOperatorType;
-struct Scene;
/* space_logic.c */
struct ARegion *logic_has_buttons_region(struct ScrArea *sa);
diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c
index 7204144ce85..e78100f3ceb 100644
--- a/source/blender/editors/space_logic/logic_window.c
+++ b/source/blender/editors/space_logic/logic_window.c
@@ -903,7 +903,7 @@ static void draw_sensor_internal_header(uiLayout *layout, PointerRNA *ptr)
sub = uiLayoutRow(row, false);
uiLayoutSetActive(sub, (RNA_boolean_get(ptr, "use_pulse_true_level") ||
RNA_boolean_get(ptr, "use_pulse_false_level")));
- uiItemR(sub, ptr, "frequency", 0, IFACE_("Freq"), ICON_NONE);
+ uiItemR(sub, ptr, "tick_skip", 0, IFACE_("Skip"), ICON_NONE);
row = uiLayoutRow(split, true);
uiItemR(row, ptr, "use_level", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 66023ce1243..1fb7228dd98 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -159,7 +159,9 @@ bool nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA *nlt_p
}
/* AnimData pointer */
- RNA_pointer_create(id, &RNA_AnimData, ale->adt, adt_ptr);
+ if (adt_ptr) {
+ RNA_pointer_create(id, &RNA_AnimData, ale->adt, adt_ptr);
+ }
/* set found status to -1, since setting to 1 would break the loop
* and potentially skip an active NLA-Track in some cases...
@@ -282,7 +284,7 @@ static void nla_panel_animdata(const bContext *C, Panel *pa)
/* Active Action Properties ------------------------------------- */
/* action */
row = uiLayoutRow(layout, true);
- uiTemplateID(row, (bContext *)C, &adt_ptr, "action", "ACTION_OT_new", NULL, NULL /*"ACTION_OT_unlink"*/); // XXX: need to make these operators
+ uiTemplateID(row, (bContext *)C, &adt_ptr, "action", "ACTION_OT_new", NULL, "NLA_OT_action_unlink");
/* extrapolation */
row = uiLayoutRow(layout, true);
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 5476d1c2683..32a8e660f66 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -291,10 +291,12 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
* the case of users trying to use this to change actions
* - in tweakmode, clicking here gets us out of tweakmode, as changing selection
* while in tweakmode is really evil!
+ * - we disable "solo" flags too, to make it easier to work with stashed actions
+ * with less trouble
*/
if (nlaedit_is_tweakmode_on(ac)) {
/* exit tweakmode immediately */
- nlaedit_disable_tweakmode(ac);
+ nlaedit_disable_tweakmode(ac, true);
/* changes to NLA-Action occurred */
notifierFlags |= ND_NLA_ACTCHANGE;
@@ -504,6 +506,52 @@ void NLA_OT_action_pushdown(wmOperatorType *ot)
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
}
+/* ******************** Action Unlink ******************************** */
+
+static int nla_action_unlink_poll(bContext *C)
+{
+ if (ED_operator_nla_active(C)) {
+ return nla_panel_context(C, NULL, NULL, NULL);
+ }
+
+ /* something failed... */
+ return false;
+}
+
+static int nla_action_unlink_exec(bContext *C, wmOperator *op)
+{
+ PointerRNA adt_ptr;
+ AnimData *adt;
+
+ /* check context and also validity of pointer */
+ if (!nla_panel_context(C, &adt_ptr, NULL, NULL))
+ return OPERATOR_CANCELLED;
+
+ /* get animdata */
+ adt = adt_ptr.data;
+ if (adt == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* do unlinking */
+ if (adt && adt->action) {
+ ED_animedit_unlink_action(C, adt_ptr.id.data, adt, adt->action, op->reports);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void NLA_OT_action_unlink(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Unlink Action";
+ ot->idname = "NLA_OT_action_unlink";
+ ot->description = "Unlink this action from the active action slot (and/or exit Tweak Mode)";
+
+ /* callbacks */
+ ot->exec = nla_action_unlink_exec;
+ ot->poll = nla_action_unlink_poll;
+}
+
/* ******************** Add Tracks Operator ***************************** */
/* Add NLA Tracks to the same AnimData block as a selected track, or above the selected tracks */
@@ -725,7 +773,7 @@ static int nlaedit_objects_add_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
/* ensure that object has AnimData... that's all */
- BKE_id_add_animdata(&ob->id);
+ BKE_animdata_add_id(&ob->id);
}
CTX_DATA_END;
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index aae0e38696c..4d37fcc9276 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -186,7 +186,7 @@ static void nla_strip_get_color_inside(AnimData *adt, NlaStrip *strip, float col
}
else {
/* Action Clip (default/normal type of strip) */
- if ((strip->flag & NLASTRIP_FLAG_ACTIVE) && (adt && (adt->flag & ADT_NLA_EDIT_ON))) {
+ if (adt && (adt->flag & ADT_NLA_EDIT_ON) && (adt->actstrip == strip)) {
/* active strip should be drawn green when it is acting as the tweaking strip.
* however, this case should be skipped for when not in EditMode...
*/
@@ -433,7 +433,7 @@ static void nla_draw_strip_text(AnimData *adt, NlaTrack *nlt, NlaStrip *strip, i
/* just print the name and the range */
if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
- str_len = BLI_snprintf(str, sizeof(str), "%d) Temp-Meta", index);
+ str_len = BLI_snprintf_rlen(str, sizeof(str), "%d) Temp-Meta", index);
}
else {
str_len = BLI_strncpy_rlen(str, strip->name, sizeof(str));
@@ -490,11 +490,11 @@ static void nla_draw_strip_frames_text(NlaTrack *UNUSED(nlt), NlaStrip *strip, V
* while also preserving some accuracy, since we do use floats
*/
/* start frame */
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%.1f", strip->start);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->start);
UI_view2d_text_cache_add(v2d, strip->start - 1.0f, ymaxc + ytol, numstr, numstr_len, col);
/* end frame */
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%.1f", strip->end);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.1f", strip->end);
UI_view2d_text_cache_add(v2d, strip->end, ymaxc + ytol, numstr, numstr_len, col);
}
@@ -650,6 +650,8 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar)
/* draw channels */
{ /* first pass: just the standard GL-drawing for backdrop + text */
+ size_t channel_index = 0;
+
y = (float)(-NLACHANNEL_HEIGHT(snla));
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -661,11 +663,12 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar)
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax) )
{
/* draw all channels using standard channel-drawing API */
- ANIM_channel_draw(ac, ale, yminc, ymaxc);
+ ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index);
}
/* adjust y-position for next one */
y -= NLACHANNEL_STEP(snla);
+ channel_index++;
}
}
{ /* second pass: UI widgets */
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index a883f350f1c..19e6f5a8100 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -111,6 +111,8 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
+
+ const bool do_solo = RNA_boolean_get(op->ptr, "isolate_action");
bool ok = false;
/* get editor data */
@@ -133,6 +135,15 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
/* try entering tweakmode if valid */
ok |= BKE_nla_tweakmode_enter(adt);
+
+ /* mark the active track as being "solo"? */
+ if (do_solo && adt->actstrip) {
+ NlaTrack *nlt = BKE_nlatrack_find_tweaked(adt);
+
+ if (nlt && !(nlt->flag & NLATRACK_SOLO)) {
+ BKE_nlatrack_solo_toggle(adt, nlt);
+ }
+ }
}
/* free temp data */
@@ -159,6 +170,8 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
void NLA_OT_tweakmode_enter(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Enter Tweak Mode";
ot->idname = "NLA_OT_tweakmode_enter";
@@ -170,16 +183,22 @@ void NLA_OT_tweakmode_enter(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "isolate_action", 0, "Isolate Action",
+ "Enable 'solo' on the NLA Track containing the active strip, "
+ "to edit it without seeing the effects of the NLA stack");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ------------- */
/* NLA Editor internal API function for exiting tweakmode */
-bool nlaedit_disable_tweakmode(bAnimContext *ac)
+bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
- int filter;
+ int filter;
/* get a list of the AnimData blocks being shown in the NLA */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
@@ -195,7 +214,14 @@ bool nlaedit_disable_tweakmode(bAnimContext *ac)
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ale->data;
- /* to be sure, just exit tweakmode... */
+ /* clear solo flags */
+ if ((do_solo) & (adt->flag & ADT_NLA_SOLO_TRACK) &&
+ (adt->flag & ADT_NLA_EDIT_ON))
+ {
+ BKE_nlatrack_solo_toggle(adt, NULL);
+ }
+
+ /* to be sure that we're doing everything right, just exit tweakmode... */
BKE_nla_tweakmode_exit(adt);
}
@@ -218,9 +244,11 @@ bool nlaedit_disable_tweakmode(bAnimContext *ac)
}
/* exit tweakmode operator callback */
-static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *UNUSED(op))
+static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
+
+ const bool do_solo = RNA_boolean_get(op->ptr, "isolate_action");
bool ok = false;
/* get editor data */
@@ -228,7 +256,7 @@ static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
/* perform operation */
- ok = nlaedit_disable_tweakmode(&ac);
+ ok = nlaedit_disable_tweakmode(&ac, do_solo);
/* success? */
if (ok)
@@ -239,6 +267,8 @@ static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *UNUSED(op))
void NLA_OT_tweakmode_exit(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Exit Tweak Mode";
ot->idname = "NLA_OT_tweakmode_exit";
@@ -250,6 +280,12 @@ void NLA_OT_tweakmode_exit(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "isolate_action", 0, "Isolate Action",
+ "Disable 'solo' on any of the NLA Tracks after exiting tweak mode "
+ "to get things back to normal");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* *********************************************** */
@@ -382,7 +418,7 @@ static bool nla_channels_get_selected_extents(bAnimContext *ac, float *min, floa
y = (float)NLACHANNEL_FIRST;
for (ale = anim_data.first; ale; ale = ale->next) {
- bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+ const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
/* must be selected... */
if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) &&
@@ -2189,7 +2225,7 @@ static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), const w
/* start from 1 to skip the 'Invalid' modifier type */
for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
- FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
+ const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
/* check if modifier is valid for this context */
if (fmi == NULL)
diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h
index bd96b5a4de5..344580c0d15 100644
--- a/source/blender/editors/space_nla/nla_intern.h
+++ b/source/blender/editors/space_nla/nla_intern.h
@@ -83,7 +83,7 @@ enum eNlaEdit_Snap_Mode {
/* --- */
-bool nlaedit_disable_tweakmode(bAnimContext *ac);
+bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo);
void NLA_OT_tweakmode_enter(wmOperatorType *ot);
void NLA_OT_tweakmode_exit(wmOperatorType *ot);
@@ -137,6 +137,7 @@ bool nlaedit_add_tracks_empty(bAnimContext *ac);
void NLA_OT_channels_click(wmOperatorType *ot);
void NLA_OT_action_pushdown(wmOperatorType *ot);
+void NLA_OT_action_unlink(wmOperatorType *ot);
void NLA_OT_tracks_add(wmOperatorType *ot);
void NLA_OT_tracks_delete(wmOperatorType *ot);
diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c
index b3a875047db..98da10470f8 100644
--- a/source/blender/editors/space_nla/nla_ops.c
+++ b/source/blender/editors/space_nla/nla_ops.c
@@ -114,6 +114,7 @@ void nla_operatortypes(void)
WM_operatortype_append(NLA_OT_channels_click);
WM_operatortype_append(NLA_OT_action_pushdown);
+ WM_operatortype_append(NLA_OT_action_unlink);
WM_operatortype_append(NLA_OT_tracks_add);
WM_operatortype_append(NLA_OT_tracks_delete);
@@ -305,6 +306,7 @@ static void nla_keymap_main(wmKeyConfig *keyconf, wmKeyMap *keymap)
void nla_keymap(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
+ wmKeyMapItem *kmi;
/* keymap for all regions ------------------------------------------- */
keymap = WM_keymap_find(keyconf, "NLA Generic", SPACE_NLA, 0);
@@ -319,6 +321,16 @@ void nla_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "NLA_OT_tweakmode_enter", TABKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "NLA_OT_tweakmode_exit", TABKEY, KM_PRESS, 0, 0);
+ /* tweakmode for stashed actions
+ * - similar to normal tweakmode, except we mark the tracks as being "solo"
+ * too so that the action can be edited in isolation
+ */
+ kmi = WM_keymap_add_item(keymap, "NLA_OT_tweakmode_enter", TABKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "isolate_action", true);
+
+ kmi = WM_keymap_add_item(keymap, "NLA_OT_tweakmode_exit", TABKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "isolate_action", true);
+
/* find (i.e. a shortcut for setting the name filter) */
WM_keymap_add_item(keymap, "ANIM_OT_channels_find", FKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 4f07d0efcb6..76766ce14d8 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -703,7 +703,9 @@ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr,
uiItemR(col, ptr, "use_auto_refresh", 0, NULL, ICON_NONE);
}
- if (RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER) {
+ if (RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER &&
+ RNA_boolean_get(ptr, "has_layers"))
+ {
col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "layer", 0, NULL, ICON_NONE);
}
@@ -862,14 +864,15 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P
if (!(ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER))) {
uiLayout *row = uiLayoutRow(layout, true);
+ const bool is_packed = BKE_image_has_packedfile(ima);
- if (ima->packedfile)
+ if (is_packed)
uiItemO(row, "", ICON_PACKAGE, "image.unpack");
else
uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack");
row = uiLayoutRow(row, true);
- uiLayoutSetEnabled(row, ima->packedfile == NULL);
+ uiLayoutSetEnabled(row, !is_packed);
uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE);
uiItemO(row, "", ICON_FILE_REFRESH, "image.reload");
}
@@ -934,6 +937,27 @@ static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C),
uiItemR(layout, ptr, "coloring", 0, "", ICON_NONE);
}
+static void node_shader_buts_tex_pointdensity(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ bNode *node = ptr->data;
+ NodeShaderTexPointDensity *shader_point_density = node->storage;
+
+ uiItemR(layout, ptr, "point_source", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE);
+
+ if (node->id && shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
+ PointerRNA dataptr;
+ RNA_id_pointer_create((ID *)node->id, &dataptr);
+ uiItemPointerR(layout, ptr, "particle_system", &dataptr, "particle_systems", NULL, ICON_NONE);
+ }
+
+ uiItemR(layout, ptr, "space", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "radius", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "resolution", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "color_source", 0, NULL, ICON_NONE);
+}
+
static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "object", 0, NULL, 0);
@@ -1167,6 +1191,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_TEX_VORONOI:
ntype->draw_buttons = node_shader_buts_tex_voronoi;
break;
+ case SH_NODE_TEX_POINTDENSITY:
+ ntype->draw_buttons = node_shader_buts_tex_pointdensity;
+ break;
case SH_NODE_TEX_COORD:
ntype->draw_buttons = node_shader_buts_tex_coord;
break;
@@ -1214,6 +1241,24 @@ static void node_shader_set_butfunc(bNodeType *ntype)
/* ****************** BUTTON CALLBACKS FOR COMPOSITE NODES ***************** */
+static void node_buts_image_views(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr,
+ PointerRNA *imaptr)
+{
+ uiLayout *col;
+
+ if (!imaptr->data)
+ return;
+
+ col = uiLayoutColumn(layout, false);
+
+ if (RNA_boolean_get(ptr, "has_views")) {
+ if (RNA_enum_get(ptr, "view") == 0)
+ uiItemR(col, ptr, "view", 0, NULL, ICON_CAMERA_STEREO);
+ else
+ uiItemR(col, ptr, "view", 0, NULL, ICON_SCENE);
+ }
+}
+
static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
bNode *node = ptr->data;
@@ -1227,6 +1272,8 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
imaptr = RNA_pointer_get(ptr, "image");
node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr);
+
+ node_buts_image_views(layout, C, ptr, &imaptr);
}
static void node_composit_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -1717,8 +1764,8 @@ static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), Po
static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
PointerRNA imfptr = RNA_pointer_get(ptr, "format");
- int multilayer = (RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER);
-
+ const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
+
if (multilayer)
uiItemL(layout, IFACE_("Path:"), ICON_NONE);
else
@@ -1727,15 +1774,22 @@ static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C)
}
static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
+ Scene *scene = CTX_data_scene(C);
PointerRNA imfptr = RNA_pointer_get(ptr, "format");
PointerRNA active_input_ptr, op_ptr;
uiLayout *row, *col;
int active_index;
- int multilayer = (RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER);
+ const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
node_composit_buts_file_output(layout, C, ptr);
uiTemplateImageSettings(layout, &imfptr, false);
+ /* disable stereo output for multilayer, too much work for something that no one will use */
+ /* if someone asks for that we can implement it */
+ if (is_multiview)
+ uiTemplateImageFormatViews(layout, &imfptr, NULL);
+
uiItemS(layout);
uiItemO(layout, IFACE_("Add Input"), ICON_ZOOMIN, "NODE_OT_output_file_add_socket");
@@ -1797,6 +1851,9 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
col = uiLayoutColumn(layout, false);
uiLayoutSetActive(col, RNA_boolean_get(&active_input_ptr, "use_node_format") == false);
uiTemplateImageSettings(col, &imfptr, false);
+
+ if (is_multiview)
+ uiTemplateImageFormatViews(layout, &imfptr, NULL);
}
}
}
@@ -2090,6 +2147,18 @@ static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), Poi
uiItemR(layout, ptr, "check", 0, NULL, ICON_NONE);
}
+static void node_composit_buts_switch_view_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *UNUSED(ptr))
+{
+ PointerRNA op_ptr;
+ wmOperatorType *ot = WM_operatortype_find("NODE_OT_switch_view_update", 1);
+
+ BLI_assert(ot != 0);
+
+ WM_operator_properties_create_ptr(&op_ptr, ot);
+
+ uiItemFullO_ptr(layout, ot, "Update Views", ICON_FILE_REFRESH, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
+}
+
static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *row;
@@ -2587,6 +2656,9 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_SWITCH:
ntype->draw_buttons = node_composit_buts_switch;
break;
+ case CMP_NODE_SWITCH_VIEW:
+ ntype->draw_buttons_ex = node_composit_buts_switch_view_ex;
+ break;
case CMP_NODE_MASK_BOX:
ntype->draw_buttons = node_composit_buts_boxmask;
ntype->draw_backdrop = node_composit_backdrop_boxmask;
@@ -2959,6 +3031,7 @@ static void node_file_output_socket_draw(bContext *C, uiLayout *layout, PointerR
imfptr = RNA_pointer_get(node_ptr, "format");
imtype = RNA_enum_get(&imfptr, "file_format");
+
if (imtype == R_IMF_IMTYPE_MULTILAYER) {
NodeImageMultiFileSocket *input = sock->storage;
RNA_pointer_create(&ntree->id, &RNA_NodeOutputFileSlotLayer, input, &inputptr);
@@ -3189,7 +3262,7 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPixelZoom(snode->backdrop_zoom, snode->backdrop_zoom);
- glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST);
+ glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST, 1.0f);
glPixelZoom(1.0f, 1.0f);
glDisable(GL_BLEND);
@@ -3197,7 +3270,7 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
else {
glPixelZoom(snode->backdrop_zoom, snode->backdrop_zoom);
- glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST);
+ glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST, 1.0f);
glPixelZoom(1.0f, 1.0f);
}
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index b2020daef4d..d27ddc99851 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -123,7 +123,14 @@ void ED_node_tag_update_id(ID *id)
bNodeTree *ntree = node_tree_from_ID(id);
if (id == NULL || ntree == NULL)
return;
-
+
+ /* TODO(sergey): With the new dependency graph it
+ * should be just enough to only tag ntree itself,
+ * all the users of this tree will have update
+ * flushed from the tree,
+ */
+ DAG_id_tag_update(&ntree->id, 0);
+
if (ntree->type == NTREE_SHADER) {
DAG_id_tag_update(id, 0);
@@ -163,14 +170,14 @@ void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree)
ntreeTexCheckCyclics(ntree);
}
-static int compare_nodes(bNode *a, bNode *b)
+static bool compare_nodes(const bNode *a, const bNode *b)
{
bNode *parent;
/* These tell if either the node or any of the parent nodes is selected.
* A selected parent means an unselected node is also in foreground!
*/
- int a_select = (a->flag & NODE_SELECT), b_select = (b->flag & NODE_SELECT);
- int a_active = (a->flag & NODE_ACTIVE), b_active = (b->flag & NODE_ACTIVE);
+ bool a_select = (a->flag & NODE_SELECT) != 0, b_select = (b->flag & NODE_SELECT) != 0;
+ bool a_active = (a->flag & NODE_ACTIVE) != 0, b_active = (b->flag & NODE_ACTIVE) != 0;
/* if one is an ancestor of the other */
/* XXX there might be a better sorting algorithm for stable topological sort, this is O(n^2) worst case */
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index 0092dc87349..2af1dc01a0e 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -93,7 +93,6 @@ typedef struct CompoJob {
const short *stop;
short *do_update;
float *progress;
- short need_sync;
int recalc_flags;
} CompoJob;
@@ -162,13 +161,12 @@ static int compo_breakjob(void *cjv)
);
}
-/* called by compo, wmJob sends notifier, old compositor system only */
-static void compo_statsdrawjob(void *cjv, char *UNUSED(str))
+/* called by compo, wmJob sends notifier */
+static void compo_statsdrawjob(void *cjv, const char *UNUSED(str))
{
CompoJob *cj = cjv;
*(cj->do_update) = true;
- cj->need_sync = true;
}
/* called by compo, wmJob sends notifier */
@@ -202,17 +200,8 @@ static void compo_initjob(void *cjv)
}
/* called before redraw notifiers, it moves finished previews over */
-static void compo_updatejob(void *cjv)
+static void compo_updatejob(void *UNUSED(cjv))
{
- CompoJob *cj = cjv;
-
- if (cj->need_sync) {
- /* was used by old compositor system only */
- ntreeLocalSync(cj->localtree, cj->ntree);
-
- cj->need_sync = false;
- }
-
WM_main_add_notifier(NC_SCENE | ND_COMPO_RESULT, NULL);
}
@@ -223,13 +212,13 @@ static void compo_progressjob(void *cjv, float progress)
*(cj->progress) = progress;
}
-
/* only this runs inside thread */
static void compo_startjob(void *cjv, short *stop, short *do_update, float *progress)
{
CompoJob *cj = cjv;
bNodeTree *ntree = cj->localtree;
Scene *scene = cj->scene;
+ SceneRenderView *srv;
if (scene->use_nodes == false)
return;
@@ -249,7 +238,16 @@ static void compo_startjob(void *cjv, short *stop, short *do_update, float *prog
// XXX BIF_store_spare();
/* 1 is do_previews */
- ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, &scene->view_settings, &scene->display_settings);
+
+ if ((cj->scene->r.scemode & R_MULTIVIEW) == 0) {
+ ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, &scene->view_settings, &scene->display_settings, "");
+ }
+ else {
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(&scene->r, srv) == false) continue;
+ ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, &scene->view_settings, &scene->display_settings, srv->name);
+ }
+ }
ntree->test_break = NULL;
ntree->stats_draw = NULL;
@@ -742,6 +740,34 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
}
}
+void ED_node_id_unref(SpaceNode *snode, const ID *id)
+{
+ if (GS(id->name) == ID_SCE) {
+ if (snode->id == id) {
+ /* nasty DNA logic for SpaceNode:
+ * ideally should be handled by editor code, but would be bad level call
+ */
+ bNodeTreePath *path, *path_next;
+ for (path = snode->treepath.first; path; path = path_next) {
+ path_next = path->next;
+ MEM_freeN(path);
+ }
+ BLI_listbase_clear(&snode->treepath);
+
+ snode->id = NULL;
+ snode->from = NULL;
+ snode->nodetree = NULL;
+ snode->edittree = NULL;
+ }
+ }
+ else if (GS(id->name) == ID_OB) {
+ if (snode->from == id) {
+ snode->flag &= ~SNODE_PIN;
+ snode->from = NULL;
+ }
+ }
+}
+
void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree))
{
/* XXX This does not work due to layout functions relying on node->block,
@@ -1671,6 +1697,54 @@ void NODE_OT_delete(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* ****************** Switch View ******************* */
+
+static int node_switch_view_poll(bContext *C)
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+
+ if (snode && snode->edittree)
+ return true;
+
+ return false;
+}
+
+static int node_switch_view_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNode *node, *next;
+
+ for (node = snode->edittree->nodes.first; node; node = next) {
+ next = node->next;
+ if (node->flag & SELECT) {
+ /* call the update function from the Switch View node */
+ node->update = NODE_UPDATE_OPERATOR;
+ }
+ }
+
+ ntreeUpdateTree(CTX_data_main(C), snode->edittree);
+
+ snode_notify(C, snode);
+ snode_dag_update(C, snode);
+
+ return OPERATOR_FINISHED;
+}
+
+void NODE_OT_switch_view_update(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Update Views";
+ ot->description = "Update views of selected node";
+ ot->idname = "NODE_OT_switch_view_update";
+
+ /* api callbacks */
+ ot->exec = node_switch_view_exec;
+ ot->poll = node_switch_view_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ****************** Delete with reconnect ******************* */
static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
{
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index b69808d4e81..f1d9d4efcc6 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -456,8 +456,8 @@ static int node_group_separate_selected(bNodeTree *ntree, bNodeTree *ngroup, flo
/* add internal links to the ntree */
for (link = ngroup->links.first; link; link = link_next) {
- int fromselect = (link->fromnode && (link->fromnode->flag & NODE_SELECT));
- int toselect = (link->tonode && (link->tonode->flag & NODE_SELECT));
+ const bool fromselect = (link->fromnode && (link->fromnode->flag & NODE_SELECT));
+ const bool toselect = (link->tonode && (link->tonode->flag & NODE_SELECT));
link_next = link->next;
if (make_copy) {
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index 27c3ab813ae..b15e9025a82 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -42,12 +42,9 @@ struct ARegionType;
struct View2D;
struct bContext;
struct wmWindow;
-struct wmWindowManager;
-struct wmEvent;
struct bNode;
struct bNodeSocket;
struct bNodeLink;
-struct Main;
struct wmKeyConfig;
/* temp data to pass on to modal */
@@ -203,6 +200,8 @@ void NODE_OT_output_file_add_socket(struct wmOperatorType *ot);
void NODE_OT_output_file_remove_active_socket(struct wmOperatorType *ot);
void NODE_OT_output_file_move_active_socket(struct wmOperatorType *ot);
+void NODE_OT_switch_view_update (struct wmOperatorType *ot);
+
/* Note: clipboard_cut is a simple macro of copy + delete */
void NODE_OT_clipboard_copy(struct wmOperatorType *ot);
void NODE_OT_clipboard_paste(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index a7799e79312..474ad4db4af 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -123,6 +123,8 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_viewer_border);
WM_operatortype_append(NODE_OT_clear_viewer_border);
+ WM_operatortype_append(NODE_OT_switch_view_update);
+
WM_operatortype_append(NODE_OT_tree_socket_add);
WM_operatortype_append(NODE_OT_tree_socket_remove);
WM_operatortype_append(NODE_OT_tree_socket_move);
@@ -314,7 +316,7 @@ void node_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "NODE_OT_group_separate", PKEY, KM_PRESS, 0, 0);
kmi = WM_keymap_add_item(keymap, "NODE_OT_group_edit", TABKEY, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "exit", false);
- kmi = WM_keymap_add_item(keymap, "NODE_OT_group_edit", TABKEY, KM_PRESS, KM_SHIFT, 0);
+ kmi = WM_keymap_add_item(keymap, "NODE_OT_group_edit", TABKEY, KM_PRESS, KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "exit", true);
WM_keymap_add_item(keymap, "NODE_OT_read_renderlayers", RKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index 8b68ac013c2..a7fd624d2aa 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -24,6 +24,7 @@
* \ingroup edinterface
*/
+#include <stdlib.h>
#include <string.h>
#include "MEM_guardedalloc.h"
@@ -214,8 +215,22 @@ static void node_socket_add_replace(const bContext *C, bNodeTree *ntree, bNode *
}
else if (!node_from) {
node_from = nodeAddStaticNode(C, ntree, type);
- node_from->locx = node_to->locx - (node_from->typeinfo->width + 50);
- node_from->locy = node_to->locy;
+ if (node_prev != NULL) {
+ /* If we're replacing existing node, use it's location. */
+ node_from->locx = node_prev->locx;
+ node_from->locy = node_prev->locy;
+ node_from->offsetx = node_prev->offsetx;
+ node_from->offsety = node_prev->offsety;
+ }
+ else {
+ /* Avoid exact intersection of nodes.
+ * TODO(sergey): Still not ideal, but better than nothing.
+ */
+ int index = BLI_findindex(&node_to->inputs, sock_to);
+ BLI_assert(index != -1);
+ node_from->locx = node_to->locx - (node_from->typeinfo->width + 50);
+ node_from->locy = node_to->locy - (node_from->typeinfo->height * index);
+ }
node_link_item_apply(node_from, item);
}
diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c
index 8ff16df9bf0..e218776ac8f 100644
--- a/source/blender/editors/space_node/node_view.c
+++ b/source/blender/editors/space_node/node_view.c
@@ -292,7 +292,7 @@ void NODE_OT_backimage_move(wmOperatorType *ot)
ot->cancel = snode_bg_viewmove_cancel;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
}
static int backimage_zoom_exec(bContext *C, wmOperator *op)
@@ -613,8 +613,11 @@ static int sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case LEFTMOUSE:
case RIGHTMOUSE: // XXX hardcoded
- sample_exit(C, op);
- return OPERATOR_CANCELLED;
+ if (event->val == KM_RELEASE) {
+ sample_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ break;
case MOUSEMOVE:
sample_apply(C, op, event);
break;
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index db5d489cfbc..a1980c88d7e 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -208,12 +208,10 @@ void ED_node_tree_path_get_fixedbuf(SpaceNode *snode, char *value, int max_lengt
value[0] = '\0';
for (path = snode->treepath.first, i = 0; path; path = path->next, ++i) {
if (i == 0) {
- BLI_strncpy(value, path->node_name, max_length);
- size = strlen(path->node_name);
+ size = BLI_strncpy_rlen(value, path->node_name, max_length);
}
else {
- BLI_snprintf(value, max_length, "/%s", path->node_name);
- size = strlen(path->node_name) + 1;
+ size = BLI_snprintf_rlen(value, max_length, "/%s", path->node_name);
}
max_length -= size;
if (max_length <= 0)
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 2c61e69d611..420b73cee86 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -198,11 +198,11 @@ static void restrictbutton_recursive_child(bContext *C, Scene *scene, Object *ob
ID *id;
bAction *action;
FCurve *fcu;
- bool driven;
+ bool driven, special;
RNA_id_pointer_create(&ob->id, &ptr);
prop = RNA_struct_find_property(&ptr, rnapropname);
- fcu = rna_get_fcurve_context_ui(C, &ptr, prop, 0, NULL, &action, &driven);
+ fcu = rna_get_fcurve_context_ui(C, &ptr, prop, 0, NULL, &action, &driven, &special);
if (fcu && !driven) {
id = ptr.id.data;
@@ -290,8 +290,7 @@ static void restrictbutton_modifier_cb(bContext *C, void *UNUSED(poin), void *po
Object *ob = (Object *)poin2;
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
}
static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *poin2)
@@ -1122,6 +1121,7 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
UI_icon_draw(x, y, ICON_MOD_BEVEL); break;
case eModifierType_Smooth:
case eModifierType_LaplacianSmooth:
+ case eModifierType_CorrectiveSmooth:
UI_icon_draw(x, y, ICON_MOD_SMOOTH); break;
case eModifierType_SimpleDeform:
UI_icon_draw(x, y, ICON_MOD_SIMPLEDEFORM); break;
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 798dae2cef3..523584e2f2d 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -39,20 +39,24 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_mempool.h"
#include "BLF_translation.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_outliner_treehash.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_material.h"
#include "BKE_group.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_keyframing.h"
@@ -1952,3 +1956,36 @@ void OUTLINER_OT_group_link(wmOperatorType *ot)
/* properties */
RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object");
}
+
+/******** Utils to clear any ref to freed ID... **********/
+
+void ED_outliner_id_unref(SpaceOops *so, const ID *id)
+{
+ /* Some early out checks. */
+ if (!TREESTORE_ID_TYPE(id)) {
+ return; /* ID type is not used by outilner... */
+ }
+
+ if (so->search_tse.id == id) {
+ so->search_tse.id = NULL;
+ }
+
+ if (so->treestore) {
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+ bool changed = false;
+
+ BLI_mempool_iternew(so->treestore, &iter);
+ while ((tselem = BLI_mempool_iterstep(&iter))) {
+ if (tselem->id == id) {
+ tselem->id = NULL;
+ changed = true;
+ }
+ }
+ if (so->treehash && changed) {
+ /* rebuild hash table, because it depends on ids too */
+ /* postpone a full rebuild because this can be called many times on-free */
+ so->storeflag |= SO_TREESTORE_REBUILD;
+ }
+ }
+}
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index 50fecebb742..24842d20573 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -36,12 +36,10 @@
/* internal exports only */
-struct wmWindowManager;
struct wmOperatorType;
struct TreeStoreElem;
struct bContext;
struct Scene;
-struct ARegion;
struct ID;
struct Object;
@@ -59,6 +57,11 @@ typedef struct TreeElement {
PointerRNA rnaptr; // RNA Pointer
} TreeElement;
+#define TREESTORE_ID_TYPE(_id) \
+ (ELEM(GS((_id)->name), ID_SCE, ID_LI, ID_OB, ID_ME, ID_CU, ID_MB, ID_MA, ID_TE, ID_IM, ID_LT, ID_LA, ID_CA) || \
+ ELEM(GS((_id)->name), ID_KE, ID_WO, ID_SPK, ID_GR, ID_AR, ID_AC, ID_BR, ID_PA, ID_GD, ID_LS) || \
+ ELEM(GS((_id)->name), ID_SCR, ID_WM)) /* Only in 'blendfile' mode ... :/ */
+
/* TreeElement->flag */
#define TE_ACTIVE 1
#define TE_ICONROW 2
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 730ee02f448..e52c68b57e9 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -554,10 +554,12 @@ static eOLDrawState tree_element_active_bone(
Object *ob = OBACT;
if (ob) {
if (set != OL_SETSEL_EXTEND) {
- bPoseChannel *pchannel;
/* single select forces all other bones to get unselected */
- for (pchannel = ob->pose->chanbase.first; pchannel; pchannel = pchannel->next)
- pchannel->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ Bone *bone;
+ for (bone = arm->bonebase.first; bone != NULL; bone = bone->next) {
+ bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ do_outliner_bone_select_recursive(arm, bone, false);
+ }
}
}
@@ -618,7 +620,7 @@ static eOLDrawState tree_element_active_ebone(
if (set != OL_SETSEL_NONE) {
if (set == OL_SETSEL_NORMAL) {
if (!(ebone->flag & BONE_HIDDEN_A)) {
- ED_armature_deselect_all(scene->obedit, 0); // deselect
+ ED_armature_deselect_all(scene->obedit);
tree_element_active_ebone__sel(C, scene, arm, ebone, true);
status = OL_DRAWSEL_NORMAL;
}
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 64e00589712..66863b8061b 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -427,8 +427,7 @@ static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te)
{
Group *group = (Group *)tselem->id;
- Object *ob = ED_object_add_type(C, OB_EMPTY, scene->cursor, NULL, false, scene->layact);
- rename_id(&ob->id, group->id.name + 2);
+ Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, scene->cursor, NULL, false, scene->layact);
ob->dup_group = group;
ob->transflag |= OB_DUPLIGROUP;
id_lib_extern(&group->id);
@@ -467,7 +466,7 @@ void outliner_do_object_operation(bContext *C, Scene *scene_act, SpaceOops *soop
static void clear_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te),
TreeStoreElem *tselem, void *UNUSED(arg))
{
- BKE_free_animdata(tselem->id);
+ BKE_animdata_free(tselem->id);
}
@@ -694,23 +693,26 @@ static void outliner_do_data_operation(SpaceOops *soops, int type, int event, Li
}
}
-static void outline_delete_hierarchy(bContext *C, Scene *scene, Base *base)
+static Base *outline_delete_hierarchy(bContext *C, Scene *scene, Base *base)
{
- Base *child_base;
+ Base *child_base, *base_next;
Object *parent;
if (!base) {
- return;
+ return NULL;
}
- for (child_base = scene->base.first; child_base; child_base = child_base->next) {
+ for (child_base = scene->base.first; child_base; child_base = base_next) {
+ base_next = child_base->next;
for (parent = child_base->object->parent; parent && (parent != base->object); parent = parent->parent);
if (parent) {
- outline_delete_hierarchy(C, scene, child_base);
+ base_next = outline_delete_hierarchy(C, scene, child_base);
}
}
+ base_next = base->next;
ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
+ return base_next;
}
static void object_delete_hierarchy_cb(
@@ -943,16 +945,15 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op)
default:
BLI_assert(0);
}
-
if (event == 3) { /* instance */
/* works without this except if you try render right after, see: 22027 */
DAG_relations_tag_update(CTX_data_main(C));
}
-
- ED_undo_push(C, prop_group_op_types[event].name);
+
+ ED_undo_push(C, prop_group_op_types[event - 1].name);
WM_event_add_notifier(C, NC_GROUP, NULL);
-
+
return OPERATOR_FINISHED;
}
@@ -1652,9 +1653,14 @@ static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
+ uiBut *but = UI_context_active_but_get(C);
TreeElement *te;
float fmval[2];
+ if (but) {
+ UI_but_tooltip_timer_remove(C, but);
+ }
+
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
for (te = soops->tree.first; te; te = te->next) {
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 7aac6a7797c..d4bef06cca9 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -66,7 +66,7 @@
#include "BKE_modifier.h"
#include "BKE_sequencer.h"
#include "BKE_idcode.h"
-#include "BKE_treehash.h"
+#include "BKE_outliner_treehash.h"
#include "ED_armature.h"
#include "ED_screen.h"
@@ -104,6 +104,8 @@ static void outliner_storage_cleanup(SpaceOops *soops)
/* cleanup only after reading file or undo step, and always for
* RNA datablocks view in order to save memory */
if (soops->storeflag & SO_TREESTORE_CLEANUP) {
+ soops->storeflag &= ~SO_TREESTORE_CLEANUP;
+
BLI_mempool_iternew(ts, &iter);
while ((tselem = BLI_mempool_iterstep(&iter))) {
if (tselem->id == NULL) unused++;
@@ -114,7 +116,7 @@ static void outliner_storage_cleanup(SpaceOops *soops)
BLI_mempool_destroy(ts);
soops->treestore = NULL;
if (soops->treehash) {
- BKE_treehash_free(soops->treehash);
+ BKE_outliner_treehash_free(soops->treehash);
soops->treehash = NULL;
}
}
@@ -133,7 +135,7 @@ static void outliner_storage_cleanup(SpaceOops *soops)
soops->treestore = new_ts;
if (soops->treehash) {
/* update hash table to fix broken pointers */
- BKE_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
+ BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
}
}
}
@@ -151,12 +153,12 @@ static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short ty
}
if (soops->treehash == NULL) {
- soops->treehash = BKE_treehash_create_from_treestore(soops->treestore);
+ soops->treehash = BKE_outliner_treehash_create_from_treestore(soops->treestore);
}
/* find any unused tree element in treestore and mark it as used
* (note that there may be multiple unused elements in case of linked objects) */
- tselem = BKE_treehash_lookup_unused(soops->treehash, type, nr, id);
+ tselem = BKE_outliner_treehash_lookup_unused(soops->treehash, type, nr, id);
if (tselem) {
te->store_elem = tselem;
tselem->used = 1;
@@ -171,7 +173,7 @@ static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short ty
tselem->used = 0;
tselem->flag = TSE_CLOSED;
te->store_elem = tselem;
- BKE_treehash_add_element(soops->treehash, tselem);
+ BKE_outliner_treehash_add_element(soops->treehash, tselem);
}
/* ********************************************************* */
@@ -216,7 +218,7 @@ TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse)
if (tse->id == NULL) return NULL;
/* check if 'tse' is in treestore */
- tselem = BKE_treehash_lookup_any(soops->treehash, tse->type, tse->nr, tse->id);
+ tselem = BKE_outliner_treehash_lookup_any(soops->treehash, tse->type, tse->nr, tse->id);
if (tselem)
return outliner_find_tree_element(&soops->tree, tselem);
@@ -769,16 +771,16 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor
ten = outliner_add_element(soops, &te->subtree, id, te, TSE_EBONE, a);
ten->directdata = ebone;
ten->name = ebone->name;
- ebone->temp = ten;
+ ebone->temp.p = ten;
}
/* make hierarchy */
- ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp : NULL;
+ ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp.p : NULL;
while (ten) {
TreeElement *nten = ten->next, *par;
ebone = (EditBone *)ten->directdata;
if (ebone->parent) {
BLI_remlink(&te->subtree, ten);
- par = ebone->parent->temp;
+ par = ebone->parent->temp.p;
BLI_addtail(&par->subtree, ten);
ten->parent = par;
}
@@ -855,6 +857,11 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
return NULL;
}
+ if (type == 0) {
+ /* Zero type means real ID, ensure we do not get non-outliner ID types here... */
+ BLI_assert(TREESTORE_ID_TYPE(id));
+ }
+
te = MEM_callocN(sizeof(TreeElement), "tree elem");
/* add to the visual tree */
BLI_addtail(lb, te);
@@ -1573,6 +1580,11 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
else
soops->search_flags &= ~SO_SEARCH_RECURSIVE;
+ if (soops->treehash && (soops->storeflag & SO_TREESTORE_REBUILD)) {
+ soops->storeflag &= ~SO_TREESTORE_REBUILD;
+ BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
+ }
+
if (soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW))
return;
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index e1aea8892b5..7b1ec174a6b 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -41,7 +41,7 @@
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
-#include "BKE_treehash.h"
+#include "BKE_outliner_treehash.h"
#include "ED_space_api.h"
#include "ED_screen.h"
@@ -464,7 +464,7 @@ static void outliner_free(SpaceLink *sl)
BLI_mempool_destroy(soutliner->treestore);
}
if (soutliner->treehash) {
- BKE_treehash_free(soutliner->treehash);
+ BKE_outliner_treehash_free(soutliner->treehash);
}
}
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 38a01bcd78c..5b95a418dc2 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -30,6 +30,7 @@
#include <stdlib.h>
#include <math.h>
#include <string.h>
+#include <ctype.h>
#include "MEM_guardedalloc.h"
@@ -60,6 +61,7 @@
#include "ED_screen.h"
#include "ED_sequencer.h"
+#include "UI_interface.h"
#include "BKE_sound.h"
@@ -70,6 +72,10 @@
/* own include */
#include "sequencer_intern.h"
+typedef struct SequencerAddData {
+ ImageFormatData im_format;
+} SequencerAddData;
+
/* Generic functions, reused by add strip operators */
/* avoid passing multiple args and be more verbose */
@@ -222,6 +228,19 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, wmOperator *op)
}
RNA_PROP_END;
}
+
+ if ((prop = RNA_struct_find_property(op->ptr, "use_multiview")) && RNA_property_boolean_get(op->ptr, prop)) {
+ if (op->customdata) {
+ SequencerAddData *sad = op->customdata;
+ ImageFormatData *imf = &sad->im_format;
+
+ seq_load->views_format = imf->views_format;
+ seq_load->flag |= SEQ_USE_VIEWS;
+
+ /* operator custom data is always released after the SeqLoadInfo, no need to handle the memory here */
+ seq_load->stereo3d_format = &imf->stereo3d_format;
+ }
+ }
}
/**
@@ -287,7 +306,7 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
BLI_strncpy(seq->name + 2, sce_seq->id.name + 2, sizeof(seq->name) - 2);
BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq);
- seq->scene_sound = sound_scene_add_scene_sound(scene, seq, start_frame, start_frame + seq->len, 0);
+ seq->scene_sound = BKE_sound_scene_add_scene_sound(scene, seq, start_frame, start_frame + seq->len, 0);
BKE_sequence_calc_disp(scene, seq);
BKE_sequencer_sort(scene);
@@ -573,6 +592,9 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
return OPERATOR_CANCELLED;
}
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+
BKE_sequencer_sort(scene);
BKE_sequencer_update_muting(ed);
@@ -581,15 +603,40 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
return OPERATOR_FINISHED;
}
+/* add sequencer operators */
+static void sequencer_add_init(bContext *UNUSED(C), wmOperator *op)
+{
+ op->customdata = MEM_callocN(sizeof(SequencerAddData), __func__);
+}
+
+static void sequencer_add_cancel(bContext *UNUSED(C), wmOperator *op)
+{
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+ op->customdata = NULL;
+}
+
+static bool sequencer_add_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+
+ return !(STREQ(prop_id, "filepath") ||
+ STREQ(prop_id, "directory") ||
+ STREQ(prop_id, "filename")
+ );
+}
+
/* add movie operator */
static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op)
{
return sequencer_add_generic_strip_exec(C, op, BKE_sequencer_add_movie_strip);
}
-
static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
+ PropertyRNA *prop;
+ Scene *scene = CTX_data_scene(C);
+
/* This is for drag and drop */
if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) ||
RNA_struct_property_is_set(op->ptr, "filepath"))
@@ -599,13 +646,37 @@ static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, const w
}
sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_MOVIE);
-
+
+ sequencer_add_init(C, op);
+
+ /* show multiview save options only if scene has multiviews */
+ prop = RNA_struct_find_property(op->ptr, "show_multiview");
+ RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
+
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
//return sequencer_add_movie_strip_exec(C, op);
}
+static void sequencer_add_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ SequencerAddData *sad = op->customdata;
+ ImageFormatData *imf = &sad->im_format;
+ PointerRNA imf_ptr, ptr;
+
+ /* main draw call */
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+ uiDefAutoButsRNA(layout, &ptr, sequencer_add_draw_check_prop, '\0');
+
+ /* image template */
+ RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
+
+ /* multiview template */
+ if (RNA_boolean_get(op->ptr, "show_multiview"))
+ uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
+}
void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
{
@@ -618,9 +689,11 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
/* api callbacks */
ot->invoke = sequencer_add_movie_strip_invoke;
ot->exec = sequencer_add_movie_strip_exec;
+ ot->cancel = sequencer_add_cancel;
+ ot->ui = sequencer_add_draw;
ot->poll = ED_operator_sequencer_active_editable;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -679,11 +752,74 @@ void SEQUENCER_OT_sound_strip_add(struct wmOperatorType *ot)
RNA_def_boolean(ot->srna, "cache", false, "Cache", "Cache the sound in memory");
}
+int sequencer_image_seq_get_minmax_frame(wmOperator *op, int sfra, int *r_minframe, int *r_numdigits)
+{
+ int minframe = INT32_MAX, maxframe = INT32_MIN;
+ int numdigits = 0;
+
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ char *filename;
+ int frame;
+ /* just get the first filename */
+ filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
+
+ if (filename) {
+ if (BLI_path_frame_get(filename, &frame, &numdigits)) {
+ minframe = min_ii(minframe, frame);
+ maxframe = max_ii(maxframe, frame);
+ }
+
+ MEM_freeN(filename);
+ }
+ }
+ RNA_END;
+
+ if (minframe == INT32_MAX) {
+ minframe = sfra;
+ maxframe = minframe + 1;
+ }
+
+ *r_minframe = minframe;
+ *r_numdigits = numdigits;
+
+ return maxframe - minframe + 1;
+}
+
+void sequencer_image_seq_reserve_frames(wmOperator *op, StripElem *se, int len, int minframe, int numdigits)
+{
+ int i;
+ char *filename = NULL;
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ /* just get the first filename */
+ filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
+ break;
+ }
+ RNA_END;
+
+ if (filename) {
+ char ext[PATH_MAX];
+ char filename_stripped[PATH_MAX];
+ /* strip the frame from filename and substitute with # */
+ BLI_path_frame_strip(filename, true, ext);
+
+ for (i = 0; i < len; i++, se++) {
+ BLI_strncpy(filename_stripped, filename, sizeof(filename_stripped));
+ BLI_path_frame(filename_stripped, minframe + i, numdigits);
+ BLI_snprintf(se->name, sizeof(se->name), "%s%s", filename_stripped, ext);
+ }
+
+ MEM_freeN(filename);
+ }
+}
+
+
/* add image operator */
static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
{
+ int minframe, numdigits;
/* cant use the generic function for this */
-
Scene *scene = CTX_data_scene(C); /* only for sound */
Editing *ed = BKE_sequencer_editing_get(scene, true);
SeqLoadInfo seq_load;
@@ -691,11 +827,17 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
Strip *strip;
StripElem *se;
+ const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
seq_load_operator_info(&seq_load, op);
/* images are unique in how they handle this - 1 per strip elem */
- seq_load.len = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
+ if (use_placeholders) {
+ seq_load.len = sequencer_image_seq_get_minmax_frame(op, seq_load.start_frame, &minframe, &numdigits);
+ }
+ else {
+ seq_load.len = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
+ }
if (seq_load.len == 0)
return OPERATOR_CANCELLED;
@@ -703,20 +845,24 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
if (seq_load.flag & SEQ_LOAD_REPLACE_SEL)
ED_sequencer_deselect_all(scene);
-
/* main adding function */
seq = BKE_sequencer_add_image_strip(C, ed->seqbasep, &seq_load);
strip = seq->strip;
se = strip->stripdata;
- RNA_BEGIN (op->ptr, itemptr, "files")
- {
- char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
- BLI_strncpy(se->name, filename, sizeof(se->name));
- MEM_freeN(filename);
- se++;
+ if (use_placeholders) {
+ sequencer_image_seq_reserve_frames(op, se, seq_load.len, minframe, numdigits);
+ }
+ else {
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
+ BLI_strncpy(se->name, filename, sizeof(se->name));
+ MEM_freeN(filename);
+ se++;
+ }
+ RNA_END;
}
- RNA_END;
if (seq_load.len == 1) {
if (seq_load.start_frame < seq_load.end_frame) {
@@ -735,6 +881,9 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
sequencer_add_apply_overlap(C, op, seq);
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@@ -742,6 +891,9 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
+ PropertyRNA *prop;
+ Scene *scene = CTX_data_scene(C);
+
/* drag drop has set the names */
if (RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) {
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_ENDFRAME | SEQPROP_NOPATHS, SEQ_TYPE_IMAGE);
@@ -750,6 +902,12 @@ static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, const w
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_ENDFRAME, SEQ_TYPE_IMAGE);
+ sequencer_add_init(C, op);
+
+ /* show multiview save options only if scene has multiviews */
+ prop = RNA_struct_find_property(op->ptr, "show_multiview");
+ RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
+
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
}
@@ -766,6 +924,8 @@ void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot)
/* api callbacks */
ot->invoke = sequencer_add_image_strip_invoke;
ot->exec = sequencer_add_image_strip_exec;
+ ot->cancel = sequencer_add_cancel;
+ ot->ui = sequencer_add_draw;
ot->poll = ED_operator_sequencer_active_editable;
@@ -775,6 +935,39 @@ void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot)
WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE, FILE_SPECIAL, FILE_OPENFILE,
WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY);
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME);
+
+ RNA_def_boolean(ot->srna, "use_placeholders", false, "Use Placeholders", "Use placeholders for missing frames of the strip");
+}
+
+
+void SEQUENCER_OT_image_sequence_add(struct wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Add Image Strip";
+ ot->idname = "SEQUENCER_OT_image_sequence_add";
+ ot->description = "Add an sequence of images with identical names to the sequencer";
+
+ /* api callbacks */
+ ot->invoke = sequencer_add_image_strip_invoke;
+ ot->exec = sequencer_add_image_strip_exec;
+ ot->cancel = sequencer_add_cancel;
+ ot->ui = sequencer_add_draw;
+
+ ot->poll = ED_operator_sequencer_active_editable;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH | WM_FILESEL_FILES | WM_FILESEL_IMAGE_COLLAPSE,
+ FILE_DEFAULTDISPLAY);
+ sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME);
+
+ /* hidden property always set to true */
+ prop = RNA_def_boolean(ot->srna, "use_placeholders", true, "Use Placeholders", "Use placeholders for missing frames of the strip");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 317bc3a99ce..b0d3fadf9d1 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -50,6 +50,7 @@
#include "BKE_main.h"
#include "BKE_sequencer.h"
#include "BKE_sound.h"
+#include "BKE_scene.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
@@ -62,6 +63,7 @@
#include "ED_markers.h"
#include "ED_mask.h"
#include "ED_sequencer.h"
+#include "ED_screen.h"
#include "ED_space_api.h"
#include "UI_interface.h"
@@ -441,12 +443,12 @@ static void draw_seq_handle(View2D *v2d, Sequence *seq, const float handsize_cla
size_t numstr_len;
if (direction == SEQ_LEFTHANDLE) {
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", seq->startdisp);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", seq->startdisp);
x1 = rx1;
y1 -= 0.45f;
}
else {
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", seq->enddisp - 1);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", seq->enddisp - 1);
x1 = x2 - handsize_clamped * 0.75f;
y1 = y2 + 0.05f;
}
@@ -837,20 +839,22 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg
{
drawmeta_contents(scene, seq, x1, y1, x2, y2);
}
-
- /* calculate if seq is long enough to print a name */
- x1 = seq->startdisp + handsize_clamped;
- x2 = seq->enddisp - handsize_clamped;
- /* info text on the strip */
- if (x1 < v2d->cur.xmin) x1 = v2d->cur.xmin;
- else if (x1 > v2d->cur.xmax) x1 = v2d->cur.xmax;
- if (x2 < v2d->cur.xmin) x2 = v2d->cur.xmin;
- else if (x2 > v2d->cur.xmax) x2 = v2d->cur.xmax;
+ if (!(sseq->flag & SEQ_NO_INFO)) {
+ /* calculate if seq is long enough to print a name */
+ x1 = seq->startdisp + handsize_clamped;
+ x2 = seq->enddisp - handsize_clamped;
+
+ /* info text on the strip */
+ if (x1 < v2d->cur.xmin) x1 = v2d->cur.xmin;
+ else if (x1 > v2d->cur.xmax) x1 = v2d->cur.xmax;
+ if (x2 < v2d->cur.xmin) x2 = v2d->cur.xmin;
+ else if (x2 > v2d->cur.xmax) x2 = v2d->cur.xmax;
- /* nice text here would require changing the view matrix for texture text */
- if ((x2 - x1) / pixelx > 32) {
- draw_seq_text(v2d, seq, x1, x2, y1, y2, background_col);
+ /* nice text here would require changing the view matrix for texture text */
+ if ((x2 - x1) / pixelx > 32) {
+ draw_seq_text(v2d, seq, x1, x2, y1, y2, background_col);
+ }
}
}
@@ -879,7 +883,7 @@ void ED_sequencer_special_preview_clear(void)
sequencer_special_update_set(NULL);
}
-ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int cfra, int frame_ofs)
+ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int cfra, int frame_ofs, const char *viewname)
{
SeqRenderData context;
ImBuf *ibuf;
@@ -907,6 +911,7 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int
bmain->eval_ctx, bmain, scene,
rectx, recty, proxy_size,
&context);
+ context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
/* sequencer could start rendering, in this case we need to be sure it wouldn't be canceled
* by Esc pressed somewhere in the past
@@ -971,7 +976,7 @@ static ImBuf *sequencer_make_scope(Scene *scene, ImBuf *ibuf, ImBuf *(*make_scop
return scope;
}
-static void sequencer_display_size(Scene *scene, SpaceSeq *sseq, float r_viewrect[2])
+void sequencer_display_size(Scene *scene, SpaceSeq *sseq, float r_viewrect[2])
{
float render_size, proxy_size;
@@ -997,6 +1002,76 @@ static void sequencer_display_size(Scene *scene, SpaceSeq *sseq, float r_viewrec
}
}
+static void sequencer_draw_gpencil(const bContext *C)
+{
+ /* draw grease-pencil (image aligned) */
+ ED_gpencil_draw_2dimage(C);
+
+ /* ortho at pixel level */
+ UI_view2d_view_restore(C);
+
+ /* draw grease-pencil (screen aligned) */
+ ED_gpencil_draw_view2d(C, 0);
+}
+
+/* draws content borders plus safety borders if needed */
+static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, const Scene *scene)
+{
+ float x1 = v2d->tot.xmin;
+ float y1 = v2d->tot.ymin;
+ float x2 = v2d->tot.xmax;
+ float y2 = v2d->tot.ymax;
+
+ /* border */
+ setlinestyle(3);
+
+ UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 1.0, 0);
+
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(x1 - 0.5f, y1 - 0.5f);
+ glVertex2f(x1 - 0.5f, y2 + 0.5f);
+ glVertex2f(x2 + 0.5f, y2 + 0.5f);
+ glVertex2f(x2 + 0.5f, y1 - 0.5f);
+ glEnd();
+
+ /* safety border */
+ if (sseq->flag & SEQ_SHOW_SAFE_MARGINS) {
+ UI_draw_safe_areas(
+ x1, x2, y1, y2,
+ scene->safe_areas.title,
+ scene->safe_areas.action);
+
+ if (sseq->flag & SEQ_SHOW_SAFE_CENTER) {
+ UI_draw_safe_areas(
+ x1, x2, y1, y2,
+ scene->safe_areas.title_center,
+ scene->safe_areas.action_center);
+ }
+ }
+
+ setlinestyle(0);
+}
+
+/* draws checkerboard background for transparent content */
+static void sequencer_draw_background(const SpaceSeq *sseq, View2D *v2d, const float viewrect[2])
+{
+ /* setting up the view */
+ UI_view2d_totRect_set(v2d, viewrect[0] + 0.5f, viewrect[1] + 0.5f);
+ UI_view2d_curRect_validate(v2d);
+ UI_view2d_view_ortho(v2d);
+
+ /* only draw alpha for main buffer */
+ if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
+ if (sseq->flag & SEQ_USE_ALPHA) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ fdrawcheckerboard(v2d->tot.xmin, v2d->tot.ymin, v2d->tot.xmax, v2d->tot.ymax);
+ glColor4f(1.0, 1.0, 1.0, 1.0);
+ }
+ }
+}
+
void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq, int cfra, int frame_ofs, bool draw_overlay, bool draw_overdrop)
{
struct Main *bmain = CTX_data_main(C);
@@ -1013,6 +1088,10 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
const bool is_imbuf = ED_space_sequencer_check_show_imbuf(sseq);
int format, type;
bool glsl_used = false;
+ const bool draw_gpencil = ((sseq->flag & SEQ_SHOW_GPENCIL) && sseq->gpd);
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ bool draw_metadata = false;
+ rctf metadataframe;
if (G.is_rendering == false && (scene->r.seq_flag & R_SEQ_GL_PREV) == 0) {
/* stop all running jobs, except screen one. currently previews frustrate Render
@@ -1034,6 +1113,9 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
glClear(GL_COLOR_BUFFER_BIT);
}
+ /* without this colors can flicker from previous opengl state */
+ glColor4ub(255, 255, 255, 255);
+
/* only initialize the preview if a render is in progress */
if (G.is_rendering)
return;
@@ -1042,17 +1124,27 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
return;
}
- ibuf = sequencer_ibuf_get(bmain, scene, sseq, cfra, frame_ofs);
-
- if (ibuf == NULL)
- return;
+ /* for now we only support Left/Right */
+ ibuf = sequencer_ibuf_get(bmain, scene, sseq, cfra, frame_ofs, names[sseq->multiview_eye]);
- if (ibuf->rect == NULL && ibuf->rect_float == NULL)
+ if ((ibuf == NULL) ||
+ (ibuf->rect == NULL && ibuf->rect_float == NULL))
+ {
+ /* gpencil can also be drawn if no imbuf is invalid */
+ if (draw_gpencil && is_imbuf) {
+ sequencer_display_size(scene, sseq, viewrect);
+
+ sequencer_draw_background(sseq, v2d, viewrect);
+ sequencer_draw_borders(sseq, v2d, scene);
+
+ sequencer_draw_gpencil(C);
+ }
return;
+ }
sequencer_display_size(scene, sseq, viewrect);
- if (sseq->mainb != SEQ_DRAW_IMG_IMBUF || sseq->zebra != 0) {
+ if (!draw_overdrop && (sseq->mainb != SEQ_DRAW_IMG_IMBUF || sseq->zebra != 0)) {
SequencerScopes *scopes = &sseq->scopes;
sequencer_check_scopes(scopes, ibuf);
@@ -1098,8 +1190,13 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
/* future files may have new scopes we don't catch above */
if (scope) {
scopes->reference_ibuf = ibuf;
- viewrect[0] = scope->x;
- viewrect[1] = scope->y;
+ if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
+ /* scopes drawn in image preview use viewrect from orig ibuf - currently that's only zebra */
+ }
+ else {
+ viewrect[0] = scope->x;
+ viewrect[1] = scope->y;
+ }
}
else {
scopes->reference_ibuf = NULL;
@@ -1127,7 +1224,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
}
}
}
-
+
if (scope) {
IMB_freeImBuf(ibuf);
ibuf = scope;
@@ -1247,20 +1344,27 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
float imagey = (scene->r.size * scene->r.ysch) / 200.0f * sseq->overdrop_zoom;
float xofs = BLI_rcti_size_x(&ar->winrct)/2.0f + sseq->overdrop_offset[0];
float yofs = BLI_rcti_size_y(&ar->winrct)/2.0f + sseq->overdrop_offset[1];
-
+
+ draw_metadata = ((sseq->flag & SEQ_SHOW_METADATA) != 0);
+
+ BLI_rctf_init(&metadataframe, -imagex + xofs, imagex + xofs, -imagey + yofs, imagey + yofs);
+
glTexCoord2f(0.0f, 0.0f); glVertex2f(-imagex + xofs, -imagey + yofs);
glTexCoord2f(0.0f, 1.0f); glVertex2f(-imagex + xofs, imagey + yofs);
glTexCoord2f(1.0f, 1.0f); glVertex2f(imagex + xofs, imagey + yofs);
glTexCoord2f(1.0f, 0.0f); glVertex2f(imagex + xofs, -imagey + yofs);
}
else {
+ draw_metadata = ((sseq->flag & SEQ_SHOW_METADATA) != 0);
+
+ metadataframe = v2d->tot;
glTexCoord2f(0.0f, 0.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymin);
glTexCoord2f(0.0f, 1.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymax);
glTexCoord2f(1.0f, 1.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymax);
glTexCoord2f(1.0f, 0.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymin);
}
glEnd();
-
+
glBindTexture(GL_TEXTURE_2D, last_texid);
glDisable(GL_TEXTURE_2D);
if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA)
@@ -1275,59 +1379,29 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
if (!scope)
IMB_freeImBuf(ibuf);
-
- if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
-
- float x1 = v2d->tot.xmin;
- float y1 = v2d->tot.ymin;
- float x2 = v2d->tot.xmax;
- float y2 = v2d->tot.ymax;
-
- /* border */
- setlinestyle(3);
-
- UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 1.0, 0);
- glBegin(GL_LINE_LOOP);
- glVertex2f(x1 - 0.5f, y1 - 0.5f);
- glVertex2f(x1 - 0.5f, y2 + 0.5f);
- glVertex2f(x2 + 0.5f, y2 + 0.5f);
- glVertex2f(x2 + 0.5f, y1 - 0.5f);
- glEnd();
+ if (draw_metadata) {
+ ED_region_image_metadata_draw(0.0, 0.0, ibuf, metadataframe, 1.0, 1.0);
+ }
- /* safety border */
- if (sseq->flag & SEQ_SHOW_SAFE_MARGINS) {
- UI_draw_safe_areas(
- x1, x2, y1, y2,
- scene->safe_areas.title,
- scene->safe_areas.action);
-
- if (sseq->flag & SEQ_SHOW_SAFE_CENTER) {
- UI_draw_safe_areas(
- x1, x2, y1, y2,
- scene->safe_areas.title_center,
- scene->safe_areas.action_center);
- }
- }
+ if (draw_overdrop) {
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ return;
+ }
- setlinestyle(0);
+ if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
+ sequencer_draw_borders(sseq, v2d, scene);
}
-
- if (sseq->flag & SEQ_SHOW_GPENCIL) {
- if (is_imbuf) {
- /* draw grease-pencil (image aligned) */
- ED_gpencil_draw_2dimage(C);
- }
+
+ if (draw_gpencil && is_imbuf) {
+ sequencer_draw_gpencil(C);
}
-
- /* ortho at pixel level */
- UI_view2d_view_restore(C);
-
- if (sseq->flag & SEQ_SHOW_GPENCIL) {
- if (is_imbuf) {
- /* draw grease-pencil (screen aligned) */
- ED_gpencil_draw_view2d(C, 0);
- }
+ else {
+ /* ortho at pixel level */
+ UI_view2d_view_restore(C);
}
@@ -1477,7 +1551,7 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
{
const Editing *ed = BKE_sequencer_editing_get(scene, false);
const int frame_sta = PSFRA;
- const int frame_end = PEFRA + 1;
+ const int frame_end = PEFRA;
glEnable(GL_BLEND);
@@ -1485,7 +1559,7 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
* frame range used is preview range or scene range */
UI_ThemeColorShadeAlpha(TH_BACK, -25, -100);
- if (frame_sta < frame_end) {
+ if (frame_sta < frame_end + 1) {
glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)frame_sta, v2d->cur.ymax);
glRectf((float)frame_end, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
}
@@ -1595,14 +1669,14 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
}
+ /* callback */
+ ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
+
if (sseq->draw_flag & SEQ_DRAW_OVERDROP) {
draw_image_seq(C, scene, ar, sseq, scene->r.cfra, 0, false, true);
UI_SetTheme(SPACE_SEQ, RGN_TYPE_WINDOW);
UI_view2d_view_ortho(v2d);
}
-
- /* callback */
- ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
/* reset view matrix */
UI_view2d_view_restore(C);
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index d3ec8a3681f..6287c3f5785 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -180,8 +180,6 @@ static void seq_proxy_build_job(const bContext *C)
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
ScrArea *sa = CTX_wm_area(C);
- struct SeqIndexBuildContext *context;
- LinkData *link;
Sequence *seq;
GSet *file_list;
@@ -209,9 +207,7 @@ static void seq_proxy_build_job(const bContext *C)
SEQP_BEGIN (ed, seq)
{
if ((seq->flag & SELECT)) {
- context = BKE_sequencer_proxy_rebuild_context(pj->main, pj->scene, seq, file_list);
- link = BLI_genericNodeN(context);
- BLI_addtail(&pj->queue, link);
+ BKE_sequencer_proxy_rebuild_context(pj->main, pj->scene, seq, file_list, &pj->queue);
}
}
SEQ_END
@@ -3175,7 +3171,7 @@ static void seq_copy_del_sound(Scene *scene, Sequence *seq)
}
}
else if (seq->scene_sound) {
- sound_remove_scene_sound(scene, seq->scene_sound);
+ BKE_sound_remove_scene_sound(scene, seq->scene_sound);
seq->scene_sound = NULL;
}
}
@@ -3332,10 +3328,10 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
}
if (seq_act->scene_sound)
- sound_remove_scene_sound(scene, seq_act->scene_sound);
+ BKE_sound_remove_scene_sound(scene, seq_act->scene_sound);
if (seq_other->scene_sound)
- sound_remove_scene_sound(scene, seq_other->scene_sound);
+ BKE_sound_remove_scene_sound(scene, seq_other->scene_sound);
seq_act->scene_sound = NULL;
seq_other->scene_sound = NULL;
@@ -3343,8 +3339,8 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
BKE_sequence_calc(scene, seq_act);
BKE_sequence_calc(scene, seq_other);
- if (seq_act->sound) sound_add_scene_sound_defaults(scene, seq_act);
- if (seq_other->sound) sound_add_scene_sound_defaults(scene, seq_other);
+ if (seq_act->sound) BKE_sound_add_scene_sound_defaults(scene, seq_act);
+ if (seq_other->sound) BKE_sound_add_scene_sound_defaults(scene, seq_other);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -3452,12 +3448,18 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
SEQP_BEGIN(ed, seq)
{
if ((seq->flag & SELECT)) {
- struct SeqIndexBuildContext *context;
+ ListBase queue = {NULL, NULL};
+ LinkData *link;
short stop = 0, do_update;
float progress;
- context = BKE_sequencer_proxy_rebuild_context(bmain, scene, seq, file_list);
- BKE_sequencer_proxy_rebuild(context, &stop, &do_update, &progress);
- BKE_sequencer_proxy_rebuild_finish(context, 0);
+
+ BKE_sequencer_proxy_rebuild_context(bmain, scene, seq, file_list, &queue);
+
+ for (link = queue.first; link; link = link->next) {
+ struct SeqIndexBuildContext *context = link->data;
+ BKE_sequencer_proxy_rebuild(context, &stop, &do_update, &progress);
+ BKE_sequencer_proxy_rebuild_finish(context, 0);
+ }
BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
}
}
@@ -3702,12 +3704,21 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
Editing *ed = BKE_sequencer_editing_get(scene, false);
Sequence *seq = BKE_sequencer_active_get(scene);
const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
+ const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
+ int minframe, numdigits;
if (seq->type == SEQ_TYPE_IMAGE) {
char directory[FILE_MAX];
- const int len = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
+ int len;
StripElem *se;
+ /* need to find min/max frame for placeholders */
+ if (use_placeholders) {
+ len = sequencer_image_seq_get_minmax_frame(op, seq->sfra, &minframe, &numdigits);
+ }
+ else {
+ len = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
+ }
if (len == 0)
return OPERATOR_CANCELLED;
@@ -3725,14 +3736,19 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
}
seq->strip->stripdata = se = MEM_callocN(len * sizeof(StripElem), "stripelem");
- RNA_BEGIN (op->ptr, itemptr, "files")
- {
- char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
- BLI_strncpy(se->name, filename, sizeof(se->name));
- MEM_freeN(filename);
- se++;
+ if (use_placeholders) {
+ sequencer_image_seq_reserve_frames(op, se, len, minframe, numdigits);
+ }
+ else {
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
+ BLI_strncpy(se->name, filename, sizeof(se->name));
+ MEM_freeN(filename);
+ se++;
+ }
+ RNA_END;
}
- RNA_END;
/* reset these else we wont see all the images */
seq->anim_startofs = seq->anim_endofs = 0;
@@ -3807,4 +3823,5 @@ void SEQUENCER_OT_change_path(struct wmOperatorType *ot)
WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH | WM_FILESEL_FILEPATH | WM_FILESEL_FILES,
FILE_DEFAULTDISPLAY);
+ RNA_def_boolean(ot->srna, "use_placeholders", false, "Use Placeholders", "Use placeholders for missing frames of the strip");
}
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 37b801d0743..2cc7fe55eb8 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -45,7 +45,8 @@ struct ARegion;
struct ARegionType;
struct Scene;
struct Main;
-struct SequencePreview;
+struct wmOperator;
+struct StripElem;
/* space_sequencer.c */
struct ARegion *sequencer_has_buttons_region(struct ScrArea *sa);
@@ -57,13 +58,14 @@ void draw_image_seq(const struct bContext *C, struct Scene *scene, struct ARegi
void color3ubv_from_seq(struct Scene *curscene, struct Sequence *seq, unsigned char col[3]);
void draw_shadedstrip(struct Sequence *seq, unsigned char col[3], float x1, float y1, float x2, float y2);
void draw_sequence_extensions(struct Scene *scene, struct ARegion *ar, struct Sequence *seq);
+void sequencer_display_size(struct Scene *scene, struct SpaceSeq *sseq, float r_viewrect[2]);
void sequencer_special_update_set(Sequence *seq);
/* UNUSED */
// void seq_reset_imageofs(struct SpaceSeq *sseq);
-struct ImBuf *sequencer_ibuf_get(struct Main *bmain, struct Scene *scene, struct SpaceSeq *sseq, int cfra, int frame_ofs);
+struct ImBuf *sequencer_ibuf_get(struct Main *bmain, struct Scene *scene, struct SpaceSeq *sseq, int cfra, int frame_ofs, const char *viewname);
/* sequencer_edit.c */
struct View2D;
@@ -134,6 +136,7 @@ void SEQUENCER_OT_rebuild_proxy(struct wmOperatorType *ot);
void SEQUENCER_OT_enable_proxies(struct wmOperatorType *ot);
void SEQUENCER_OT_overdrop_transform(struct wmOperatorType *ot);
+void SEQUENCER_OT_image_transform_widget(struct wmOperatorType *ot);
/* preview specific operators */
void SEQUENCER_OT_view_all_preview(struct wmOperatorType *ot);
@@ -158,6 +161,7 @@ void SEQUENCER_OT_movieclip_strip_add(struct wmOperatorType *ot);
void SEQUENCER_OT_mask_strip_add(struct wmOperatorType *ot);
void SEQUENCER_OT_sound_strip_add(struct wmOperatorType *ot);
void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot);
+void SEQUENCER_OT_image_sequence_add(struct wmOperatorType *ot);
void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot);
enum {
@@ -205,5 +209,9 @@ void SEQUENCER_OT_sample(struct wmOperatorType *ot);
/* sequencer_preview.c */
void sequencer_preview_add_sound(const struct bContext *C, struct Sequence *seq);
+/* sequencer_add */
+int sequencer_image_seq_get_minmax_frame(struct wmOperator *op, int sfra, int *r_minframe, int *r_numdigits);
+void sequencer_image_seq_reserve_frames(struct wmOperator *op, struct StripElem *se, int len, int minframe, int numdigits);
+
#endif /* __SEQUENCER_INTERN_H__ */
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index 40191905c38..b55ee7987f8 100644
--- a/source/blender/editors/space_sequencer/sequencer_ops.c
+++ b/source/blender/editors/space_sequencer/sequencer_ops.c
@@ -112,6 +112,7 @@ void sequencer_operatortypes(void)
WM_operatortype_append(SEQUENCER_OT_movie_strip_add);
WM_operatortype_append(SEQUENCER_OT_sound_strip_add);
WM_operatortype_append(SEQUENCER_OT_image_strip_add);
+ WM_operatortype_append(SEQUENCER_OT_image_sequence_add);
WM_operatortype_append(SEQUENCER_OT_effect_strip_add);
/* sequencer_buttons.c */
@@ -125,6 +126,7 @@ void sequencer_operatortypes(void)
/* sequencer_view.h */
WM_operatortype_append(SEQUENCER_OT_sample);
WM_operatortype_append(SEQUENCER_OT_overdrop_transform);
+ WM_operatortype_append(SEQUENCER_OT_image_transform_widget);
}
@@ -345,6 +347,8 @@ void sequencer_keymap(wmKeyConfig *keyconf)
/* would prefer to use numpad keys for job */
RNA_float_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_view_zoom_ratio", PAD1, KM_PRESS, 0, 0)->ptr, "ratio", 1.0f);
+// WM_keymap_add_item(keymap, "SEQUENCER_OT_image_transform_widget", VKEY, KM_PRESS, 0, 0);
+
/* Setting zoom levels is not that useful, except for back to zoom level 1, removing keymap because of conflicts for now */
#if 0
RNA_float_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_view_zoom_ratio", PAD8, KM_PRESS, KM_SHIFT, 0)->ptr, "ratio", 8.0f);
@@ -368,5 +372,5 @@ void ED_operatormacros_sequencer(void)
"Duplicate selected strips and move them", OPTYPE_UNDO | OPTYPE_REGISTER);
WM_operatortype_macro_define(ot, "SEQUENCER_OT_duplicate");
- WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ WM_operatortype_macro_define(ot, "TRANSFORM_OT_seq_slide");
}
diff --git a/source/blender/editors/space_sequencer/sequencer_preview.c b/source/blender/editors/space_sequencer/sequencer_preview.c
index c8834d394f5..3f908dc7096 100644
--- a/source/blender/editors/space_sequencer/sequencer_preview.c
+++ b/source/blender/editors/space_sequencer/sequencer_preview.c
@@ -85,7 +85,7 @@ static void preview_startjob(void *data, short *stop, short *do_update, float *p
PreviewJobAudio *preview_next;
bSound *sound = previewjb->sound;
- sound_read_waveform(sound, stop);
+ BKE_sound_read_waveform(sound, stop);
if (*stop || G.is_break) {
BLI_mutex_lock(pj->mutex);
diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c
index 24b3776da6d..c197aabedfd 100644
--- a/source/blender/editors/space_sequencer/sequencer_scopes.c
+++ b/source/blender/editors/space_sequencer/sequencer_scopes.c
@@ -29,9 +29,9 @@
#include <math.h>
#include <string.h>
-#include "BLI_math_color.h"
#include "BLI_utildefines.h"
+#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -167,7 +167,7 @@ static ImBuf *make_waveform_view_from_ibuf_byte(ImBuf *ibuf)
for (x = 0; x < ibuf->x; x++) {
const unsigned char *rgb = src + 4 * (ibuf->x * y + x);
- float v = (float)rgb_to_luma_byte(rgb) / 255.0f;
+ float v = (float)IMB_colormanagement_get_luminance_byte(rgb) / 255.0f;
unsigned char *p = tgt;
p += 4 * (w * ((int) (v * (h - 3)) + 1) + x + 1);
@@ -207,7 +207,7 @@ static ImBuf *make_waveform_view_from_ibuf_float(ImBuf *ibuf)
for (x = 0; x < ibuf->x; x++) {
const float *rgb = src + 4 * (ibuf->x * y + x);
- float v = rgb_to_luma(rgb);
+ float v = IMB_colormanagement_get_luminance(rgb);
unsigned char *p = tgt;
CLAMP(v, 0.0f, 1.0f);
@@ -647,13 +647,13 @@ static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf)
wtable[x] = (unsigned char) (pow(((float) x + 1) / 256, scope_gamma) * 255);
}
- for (x = 0; x <= 255; x++) {
- vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1);
- vectorscope_put_cross(255, x, 0, tgt, w, h, 1);
- vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1);
- vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
- vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
- vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
+ for (x = 0; x < 256; x++) {
+ vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1);
+ vectorscope_put_cross(255, x, 0, tgt, w, h, 1);
+ vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1);
+ vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
+ vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
+ vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
}
for (y = 0; y < ibuf->y; y++) {
@@ -694,12 +694,12 @@ static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf)
}
for (x = 0; x <= 255; x++) {
- vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1);
- vectorscope_put_cross(255, x, 0, tgt, w, h, 1);
- vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1);
- vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
- vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
- vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
+ vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1);
+ vectorscope_put_cross(255, x, 0, tgt, w, h, 1);
+ vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1);
+ vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
+ vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
+ vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
}
for (y = 0; y < ibuf->y; y++) {
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index 71eb64a74f5..a0f0c80883d 100644
--- a/source/blender/editors/space_sequencer/sequencer_view.c
+++ b/source/blender/editors/space_sequencer/sequencer_view.c
@@ -49,6 +49,7 @@
#include "ED_image.h"
#include "ED_screen.h"
#include "ED_space_api.h"
+#include "ED_sequencer.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -98,7 +99,7 @@ static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
Scene *scene = CTX_data_scene(C);
SpaceSeq *sseq = (SpaceSeq *) CTX_wm_space_data(C);
ARegion *ar = CTX_wm_region(C);
- ImBuf *ibuf = sequencer_ibuf_get(bmain, scene, sseq, CFRA, 0);
+ ImBuf *ibuf = sequencer_ibuf_get(bmain, scene, sseq, CFRA, 0, NULL);
ImageSampleInfo *info = op->customdata;
float fx, fy;
@@ -205,8 +206,11 @@ static int sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case LEFTMOUSE:
case RIGHTMOUSE: /* XXX hardcoded */
- sample_exit(C, op);
- return OPERATOR_CANCELLED;
+ if (event->val == KM_RELEASE) {
+ sample_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ break;
case MOUSEMOVE:
sample_apply(C, op, event);
break;
@@ -246,6 +250,8 @@ void SEQUENCER_OT_sample(wmOperatorType *ot)
/******** Backdrop Transform *******/
typedef struct OverDropTransformData {
+ ImBuf *ibuf; /* image to be transformed (preview image transformation widget) */
+ int init_size[2];
float init_zoom;
float init_offset[2];
int event_type;
@@ -395,3 +401,178 @@ void SEQUENCER_OT_overdrop_transform(struct wmOperatorType *ot)
RNA_def_float(ot->srna, "scale", 1.0f, 0.0f, FLT_MAX, "Scale", "Scale of the backdrop", 0.0f, FLT_MAX);
}
+/******** transform widget (preview area) *******/
+
+typedef struct ImageTransformData {
+ ImBuf *ibuf; /* image to be transformed (preview image transformation widget) */
+ int init_size[2];
+ int event_type;
+ wmWidgetGroupType *cagetype;
+} ImageTransformData;
+
+static int sequencer_image_transform_widget_poll(bContext *C)
+{
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ return (sseq && ar && ar->type->regionid == RGN_TYPE_PREVIEW);
+}
+
+static void widgetgroup_image_transform_draw(const struct bContext *C, struct wmWidgetGroup *wgroup)
+{
+ ARegion *ar = CTX_wm_region(C);
+ View2D *v2d = &ar->v2d;
+ wmOperator *op = wgroup->type->op;
+ wmWidget *cage;
+ float origin[3];
+ float viewrect[2];
+ float scale[2];
+
+ sequencer_display_size(CTX_data_scene(C), CTX_wm_space_seq(C), viewrect);
+ UI_view2d_scale_get(v2d, &scale[0], &scale[1]);
+
+ cage = WIDGET_rect_transform_new(wgroup, WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM |
+ WIDGET_RECT_TRANSFORM_STYLE_TRANSLATE,
+ viewrect[0] * scale[0], viewrect[1] * scale[1]);
+ WM_widget_property(cage, RECT_TRANSFORM_SLOT_SCALE, op->ptr, "scale");
+
+ origin[0] = -(v2d->cur.xmin * scale[0]);
+ origin[1] = -(v2d->cur.ymin * scale[1]);
+ WM_widget_set_origin(cage, origin);
+}
+
+static int sequencer_image_transform_widget_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+ Scene *scene = CTX_data_scene(C);
+ /* no poll, lives always for the duration of the operator */
+ wmWidgetGroupType *cagetype = WM_widgetgrouptype_new(NULL, widgetgroup_image_transform_draw, CTX_data_main(C),
+ "Seq_Canvas", SPACE_SEQ, RGN_TYPE_PREVIEW, false);
+ struct wmEventHandler *handler = WM_event_add_modal_handler(C, op);
+ ImageTransformData *data = MEM_mallocN(sizeof(ImageTransformData), "overdrop transform data");
+ ImBuf *ibuf = sequencer_ibuf_get(CTX_data_main(C), scene, sseq, CFRA, 0, NULL);
+
+ if (!ibuf || !ED_space_sequencer_check_show_imbuf(sseq)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ WM_modal_handler_attach_widgetgroup(C, handler, cagetype, op);
+
+ copy_v2_v2_int(data->init_size, &ibuf->x);
+ data->cagetype = cagetype;
+ data->event_type = event->type;
+ data->ibuf = ibuf;
+
+ op->customdata = data;
+
+ ED_area_headerprint(sa, "Drag to place, and scale, Space/Enter/Caller key to confirm, R to recenter, RClick/Esc to cancel");
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void sequencer_image_transform_widget_finish(bContext *C, ImageTransformData *data)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ ED_area_headerprint(sa, NULL);
+ WM_widgetgrouptype_unregister(C, CTX_data_main(C), data->cagetype);
+ MEM_freeN(data);
+}
+
+static void sequencer_image_transform_widget_cancel(struct bContext *C, struct wmOperator *op)
+{
+ ImageTransformData *data = op->customdata;
+ sequencer_image_transform_widget_finish(C, data);
+}
+
+static int sequencer_image_transform_widget_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ImageTransformData *data = op->customdata;
+
+ if (event->type == data->event_type && event->val == KM_PRESS) {
+ sequencer_image_transform_widget_finish(C, data);
+ return OPERATOR_FINISHED;
+ }
+
+ switch (event->type) {
+ case EVT_WIDGET_UPDATE:
+ {
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ wmWidgetMap *wmap = ar->widgetmaps.first;
+ float scale_fac = RNA_float_get(op->ptr, "scale");
+ float new_size[2];
+ float offset[2];
+
+ new_size[0] = (float)data->init_size[0] * scale_fac;
+ new_size[1] = (float)data->init_size[1] * scale_fac;
+
+ /* sale image */
+ IMB_scalefastImBuf(data->ibuf, (unsigned int)new_size[0], (unsigned int)new_size[1]);
+
+ /* update view */
+ scene->r.xsch = (int)(new_size[0] / ((float)scene->r.size / 100));
+ scene->r.ysch = (int)(new_size[1] / ((float)scene->r.size / 100));
+
+ /* no offset needed in this case */
+ offset[0] = offset[1] = 0;
+ WIDGET_rect_transform_set_offset(wmap->active_widget, offset);
+ break;
+ }
+
+ case RKEY:
+ {
+// SpaceSeq *sseq = CTX_wm_space_seq(C);
+ ARegion *ar = CTX_wm_region(C);
+// float zero[2] = {0.0f};
+// RNA_float_set_array(op->ptr, "offset", zero);
+// RNA_float_set(op->ptr, "scale", 1.0f);
+// copy_v2_v2(sseq->overdrop_offset, zero);
+// sseq->overdrop_zoom = 1.0;
+ ED_region_tag_redraw(ar);
+ /* add a mousemove to refresh the widget */
+ WM_event_add_mousemove(C);
+ break;
+ }
+ case RETKEY:
+ case PADENTER:
+ case SPACEKEY:
+ {
+ sequencer_image_transform_widget_finish(C, data);
+ return OPERATOR_FINISHED;
+ }
+
+ case ESCKEY:
+ case RIGHTMOUSE:
+ {
+// SpaceSeq *sseq = CTX_wm_space_seq(C);
+// copy_v2_v2(sseq->overdrop_offset, data->init_offset);
+// sseq->overdrop_zoom = data->init_zoom;
+
+ sequencer_image_transform_widget_finish(C, data);
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void SEQUENCER_OT_image_transform_widget(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Image Transform";
+ ot->idname = "SEQUENCER_OT_image_transform_widget";
+ ot->description = "Transform the image using a widget";
+
+ /* api callbacks */
+ ot->invoke = sequencer_image_transform_widget_invoke;
+ ot->modal = sequencer_image_transform_widget_modal;
+ ot->poll = sequencer_image_transform_widget_poll;
+ ot->cancel = sequencer_image_transform_widget_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_float(ot->srna, "scale", 1.0f, 0.0f, FLT_MAX, "Scale", "Scale of the backdrop", 0.0f, FLT_MAX);
+}
+
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index ad70ec2df3d..92a16ce6b7b 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -183,7 +183,7 @@ static SpaceLink *sequencer_new(const bContext *C)
ar->v2d.min[1] = 0.5f;
ar->v2d.max[0] = MAXFRAMEF;
- ar->v2d.max[1] = MAXSEQ;
+ ar->v2d.max[1] = MAXSEQ * 4;
ar->v2d.minzoom = 0.01f;
ar->v2d.maxzoom = 100.0f;
@@ -564,6 +564,10 @@ static void sequencer_preview_area_init(wmWindowManager *wm, ARegion *ar)
/* own keymap */
keymap = WM_keymap_find(wm->defaultconf, "SequencerPreview", SPACE_SEQ, 0);
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
+
+ if (BLI_listbase_is_empty(&ar->widgetmaps)) {
+ BLI_addhead(&ar->widgetmaps, WM_widgetmap_from_type("Seq_Canvas", SPACE_SEQ, RGN_TYPE_PREVIEW, false));
+ }
}
static void sequencer_preview_area_draw(const bContext *C, ARegion *ar)
@@ -572,7 +576,10 @@ static void sequencer_preview_area_draw(const bContext *C, ARegion *ar)
SpaceSeq *sseq = sa->spacedata.first;
Scene *scene = CTX_data_scene(C);
wmWindowManager *wm = CTX_wm_manager(C);
- int show_split = scene->ed && scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW && sseq->mainb == SEQ_DRAW_IMG_IMBUF;
+ const bool show_split = (
+ scene->ed &&
+ (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) &&
+ (sseq->mainb == SEQ_DRAW_IMG_IMBUF));
/* XXX temp fix for wrong setting in sseq->mainb */
if (sseq->mainb == SEQ_DRAW_SEQUENCE) sseq->mainb = SEQ_DRAW_IMG_IMBUF;
@@ -597,6 +604,9 @@ static void sequencer_preview_area_draw(const bContext *C, ARegion *ar)
ED_region_visible_rect(ar, &rect);
ED_scene_draw_fps(scene, &rect);
}
+
+ WM_widgets_update(C, ar->widgetmaps.first);
+ WM_widgets_draw(C, ar->widgetmaps.first, false);
}
static void sequencer_preview_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
@@ -699,6 +709,8 @@ static void sequencer_widgets(void)
{
/* create the widgetmap for the area here */
WM_widgetmaptype_find("Seq_Canvas", SPACE_SEQ, RGN_TYPE_WINDOW, false, true);
+
+ WM_widgetmaptype_find("Seq_Canvas", SPACE_SEQ, RGN_TYPE_PREVIEW, false, true);
}
diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h
index f577714c480..7ae2617f375 100644
--- a/source/blender/editors/space_text/text_intern.h
+++ b/source/blender/editors/space_text/text_intern.h
@@ -34,15 +34,12 @@
/* internal exports only */
struct ARegion;
-struct ARegionType;
struct bContext;
-struct ReportList;
struct ScrArea;
struct SpaceText;
struct Text;
struct TextLine;
struct wmOperatorType;
-struct wmWindowManager;
/* text_draw.c */
void draw_text_main(struct SpaceText *st, struct ARegion *ar);
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index ad8050a50e8..fce864d975f 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -2233,7 +2233,7 @@ void TEXT_OT_scroll(wmOperatorType *ot)
ot->poll = text_scroll_poll;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER | OPTYPE_INTERNAL;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_INTERNAL;
/* properties */
RNA_def_int(ot->srna, "lines", 1, INT_MIN, INT_MAX, "Lines", "Number of lines to scroll", -100, 100);
diff --git a/source/blender/editors/space_time/time_intern.h b/source/blender/editors/space_time/time_intern.h
index ce52cbbd65e..ced36b2ac2d 100644
--- a/source/blender/editors/space_time/time_intern.h
+++ b/source/blender/editors/space_time/time_intern.h
@@ -34,7 +34,6 @@
/* internal exports only */
-struct wmWindowManager;
/* time_ops.c */
void time_operatortypes(void);
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index ab69e67361d..57c497a2a4d 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
../../makesrna
../../render/extern/include
../../windowmanager
+ ../../depsgraph
../../../../intern/guardedalloc
../../../../intern/glew-mx
../../../../intern/smoke/extern
@@ -45,6 +46,7 @@ set(SRC
drawmesh.c
drawobject.c
drawsimdebug.c
+ drawstrands.c
drawvolume.c
space_view3d.c
view3d_buttons.c
diff --git a/source/blender/editors/space_view3d/SConscript b/source/blender/editors/space_view3d/SConscript
index a21da940906..78f24948070 100644
--- a/source/blender/editors/space_view3d/SConscript
+++ b/source/blender/editors/space_view3d/SConscript
@@ -48,6 +48,7 @@ incs = [
'../../makesrna',
'../../render/extern/include',
'../../windowmanager',
+ '../../depsgraph',
]
if env['WITH_BF_PYTHON']:
diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c
index d8b18140cde..d753ad68fcc 100644
--- a/source/blender/editors/space_view3d/drawanimviz.c
+++ b/source/blender/editors/space_view3d/drawanimviz.c
@@ -51,7 +51,6 @@
#include "BIF_gl.h"
-#include "ED_armature.h"
#include "ED_keyframes_draw.h"
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index 755c633531d..b374ce64319 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -588,15 +588,19 @@ static DMDrawOption draw_tface__set_draw(MTFace *tface, const bool UNUSED(has_mc
return DM_DRAW_OPTION_NORMAL;
}
-static void update_tface_color_layer(DerivedMesh *dm)
+static void update_tface_color_layer(DerivedMesh *dm, bool use_mcol)
{
MTFace *tface = DM_get_tessface_data_layer(dm, CD_MTFACE);
MFace *mface = dm->getTessFaceArray(dm);
MCol *finalCol;
int i, j;
- MCol *mcol = dm->getTessFaceDataArray(dm, CD_PREVIEW_MCOL);
- if (!mcol)
- mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
+ MCol *mcol = NULL;
+
+ if (use_mcol) {
+ mcol = dm->getTessFaceDataArray(dm, CD_PREVIEW_MCOL);
+ if (!mcol)
+ mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
+ }
if (CustomData_has_layer(&dm->faceData, CD_TEXTURE_MCOL)) {
finalCol = CustomData_get_layer(&dm->faceData, CD_TEXTURE_MCOL);
@@ -771,7 +775,7 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
for (a = 0, mp = mface; a < totpoly; a++, mtpoly++, mp++) {
short matnr = mp->mat_nr;
- int mf_smooth = mp->flag & ME_SMOOTH;
+ const bool mf_smooth = (mp->flag & ME_SMOOTH) != 0;
Material *mat = (me->mat) ? me->mat[matnr] : NULL;
int mode = mat ? mat->game.flag : GEMAT_INVISIBLE;
@@ -937,7 +941,7 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
else {
drawTFace_userData userData;
- update_tface_color_layer(dm);
+ update_tface_color_layer(dm, !(ob->mode & OB_MODE_TEXTURE_PAINT));
userData.mf = DM_get_tessface_data_layer(dm, CD_MFACE);
userData.tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
@@ -1103,7 +1107,7 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d,
Mesh *me = ob->data;
TexMatCallback data = {scene, ob, me, dm};
bool (*set_face_cb)(void *, int);
- int glsl, picking = (G.f & G_PICKSEL);
+ bool glsl, picking = (G.f & G_PICKSEL) != 0;
/* face hiding callback depending on mode */
if (ob == scene->obedit)
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index b44da8a70a6..05a2d5b3ddc 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -54,11 +54,13 @@
#include "BKE_anim.h" /* for the where_on_path function */
#include "BKE_armature.h"
#include "BKE_camera.h"
+#include "BKE_colortools.h"
#include "BKE_constraint.h" /* for the get_constraint_target function */
#include "BKE_curve.h"
#include "BKE_DerivedMesh.h"
#include "BKE_deform.h"
#include "BKE_displist.h"
+#include "BKE_editstrands.h"
#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -216,6 +218,7 @@ static void drawcube_size(float size);
static void drawcircle_size(float size);
static void draw_empty_sphere(float size);
static void draw_empty_cone(float size);
+static void draw_box(float vec[8][3], bool solid);
static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac)
{
@@ -302,11 +305,12 @@ bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP)
return true;
- if (BKE_scene_use_new_shading_nodes(scene))
+ if (v3d->drawtype == OB_TEXTURE)
+ return (scene->gm.matmode == GAME_MAT_GLSL && !BKE_scene_use_new_shading_nodes(scene));
+ else if (v3d->drawtype == OB_MATERIAL && dt > OB_SOLID)
+ return true;
+ else
return false;
-
- return ((scene->gm.matmode == GAME_MAT_GLSL && v3d->drawtype == OB_TEXTURE) ||
- (v3d->drawtype == OB_MATERIAL)) && (dt > OB_SOLID);
}
static bool check_alpha_pass(Base *base)
@@ -402,13 +406,13 @@ static const float cosval[CIRCLE_RESOL] = {
static void draw_xyz_wire(const float c[3], float size, int axis)
{
- float v1[3] = {0.f, 0.f, 0.f}, v2[3] = {0.f, 0.f, 0.f};
+ float v1[3] = {0.0f, 0.0f, 0.0f}, v2[3] = {0.0f, 0.0f, 0.0f};
float dim = size * 0.1f;
float dx[3], dy[3], dz[3];
- dx[0] = dim; dx[1] = 0.f; dx[2] = 0.f;
- dy[0] = 0.f; dy[1] = dim; dy[2] = 0.f;
- dz[0] = 0.f; dz[1] = 0.f; dz[2] = dim;
+ dx[0] = dim; dx[1] = 0.0f; dx[2] = 0.0f;
+ dy[0] = 0.0f; dy[1] = dim; dy[2] = 0.0f;
+ dz[0] = 0.0f; dz[1] = 0.0f; dz[2] = dim;
switch (axis) {
case 0: /* x axis */
@@ -424,7 +428,7 @@ static void draw_xyz_wire(const float c[3], float size, int axis)
glVertex3fv(v2);
/* top left to bottom right */
- mul_v3_fl(dy, 2.f);
+ mul_v3_fl(dy, 2.0f);
add_v3_v3(v1, dy);
sub_v3_v3(v2, dy);
@@ -447,7 +451,7 @@ static void draw_xyz_wire(const float c[3], float size, int axis)
glVertex3fv(v2);
/* top left to center */
- mul_v3_fl(dy, 2.f);
+ mul_v3_fl(dy, 2.0f);
add_v3_v3(v1, dy);
copy_v3_v3(v2, c);
@@ -465,12 +469,12 @@ static void draw_xyz_wire(const float c[3], float size, int axis)
glVertex3fv(v1);
- mul_v3_fl(dx, 2.f);
+ mul_v3_fl(dx, 2.0f);
add_v3_v3(v1, dx);
glVertex3fv(v1);
- mul_v3_fl(dz, 2.f);
+ mul_v3_fl(dz, 2.0f);
sub_v3_v3(v1, dx);
sub_v3_v3(v1, dz);
@@ -483,7 +487,6 @@ static void draw_xyz_wire(const float c[3], float size, int axis)
glEnd();
break;
}
-
}
void drawaxes(float size, char drawtype)
@@ -597,10 +600,10 @@ void drawaxes(float size, char drawtype)
}
-/* Function to draw an Image on a empty Object */
+/* Function to draw an Image on an empty Object */
static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4])
{
- Image *ima = (Image *)ob->data;
+ Image *ima = ob->data;
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, ob->iuser, NULL);
float scale, ofs_x, ofs_y, sca_x, sca_y;
@@ -640,16 +643,13 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char
sca_y = 1.0f;
}
- /* Calculate the scale center based on objects origin */
+ /* Calculate the scale center based on object's origin */
ofs_x = ob->ima_ofs[0] * ima_x;
ofs_y = ob->ima_ofs[1] * ima_y;
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
- /* Make sure we are drawing at the origin */
- glTranslatef(0.0f, 0.0f, 0.0f);
-
/* Calculate Image scale */
scale = (ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y));
@@ -943,7 +943,7 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo
/* ******************** primitive drawing ******************* */
-/* draws a cube on given the scaling of the cube, assuming that
+/* draws a cube given the scaling of the cube, assuming that
* all required matrices have been set (used for drawing empties)
*/
static void drawcube_size(float size)
@@ -1025,8 +1025,6 @@ static void drawshadbuflimits(Lamp *la, float mat[4][4])
glPointSize(1.0);
}
-
-
static void spotvolume(float lvec[3], float vvec[3], const float inp)
{
/* camera is at 0,0,0 */
@@ -1035,8 +1033,8 @@ static void spotvolume(float lvec[3], float vvec[3], const float inp)
normalize_v3(lvec);
normalize_v3(vvec); /* is this the correct vector ? */
- cross_v3_v3v3(temp, vvec, lvec); /* equation for a plane through vvec en lvec */
- cross_v3_v3v3(plane, lvec, temp); /* a plane perpendicular to this, parrallel with lvec */
+ cross_v3_v3v3(temp, vvec, lvec); /* equation for a plane through vvec and lvec */
+ cross_v3_v3v3(plane, lvec, temp); /* a plane perpendicular to this, parallel with lvec */
/* vectors are exactly aligned, use the X axis, this is arbitrary */
if (normalize_v3(plane) == 0.0f)
@@ -1149,6 +1147,52 @@ static void draw_transp_spot_volume(Lamp *la, float x, float z)
glCullFace(GL_BACK);
}
+#ifdef WITH_GAMEENGINE
+static void draw_transp_sun_volume(Lamp *la)
+{
+ float box[8][3];
+
+ /* construct box */
+ box[0][0] = box[1][0] = box[2][0] = box[3][0] = -la->shadow_frustum_size;
+ box[4][0] = box[5][0] = box[6][0] = box[7][0] = +la->shadow_frustum_size;
+ box[0][1] = box[1][1] = box[4][1] = box[5][1] = -la->shadow_frustum_size;
+ box[2][1] = box[3][1] = box[6][1] = box[7][1] = +la->shadow_frustum_size;
+ box[0][2] = box[3][2] = box[4][2] = box[7][2] = -la->clipend;
+ box[1][2] = box[2][2] = box[5][2] = box[6][2] = -la->clipsta;
+
+ /* draw edges */
+ draw_box(box, false);
+
+ /* draw faces */
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_BLEND);
+ glDepthMask(0);
+
+ /* draw backside darkening */
+ glCullFace(GL_FRONT);
+
+ glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
+ glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
+
+ draw_box(box, true);
+
+ /* draw front side lighting */
+ glCullFace(GL_BACK);
+
+ glBlendFunc(GL_ONE, GL_ONE);
+ glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
+
+ draw_box(box, true);
+
+ /* restore state */
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_BLEND);
+ glDepthMask(1);
+ glDisable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+}
+#endif
+
static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact)
{
@@ -1161,7 +1205,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
unsigned char curcol[4];
unsigned char col[4];
- /* cone can't be drawn for duplicated lamps, because duplilist would be freed to */
+ /* cone can't be drawn for duplicated lamps, because duplilist would be freed */
/* the moment of view3d_draw_transp() call */
const bool is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object);
const bool drawcone = ((dt > OB_WIRE) &&
@@ -1171,7 +1215,22 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
!(base->flag & OB_FROMDUPLI) &&
!is_view);
- if (drawcone && !v3d->transp) {
+#ifdef WITH_GAMEENGINE
+ const bool drawshadowbox = (
+ (rv3d->rflag & RV3D_IS_GAME_ENGINE) &&
+ (dt > OB_WIRE) &&
+ !(G.f & G_PICKSEL) &&
+ (la->type == LA_SUN) &&
+ ((la->mode & LA_SHAD_BUF) ||
+ (la->mode & LA_SHAD_RAY)) &&
+ (la->mode & LA_SHOW_SHADOW_BOX) &&
+ !(base->flag & OB_FROMDUPLI) &&
+ !is_view);
+#else
+ const bool drawshadowbox = false;
+#endif
+
+ if ((drawcone || drawshadowbox) && !v3d->transp) {
/* in this case we need to draw delayed */
ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
return;
@@ -1310,7 +1369,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
x *= y;
/* draw the circle/square at the end of the cone */
- glTranslatef(0.0, 0.0, x);
+ glTranslatef(0.0, 0.0, x);
if (la->mode & LA_SQUARE) {
float tvec[3];
float z_abs = fabsf(z);
@@ -1416,6 +1475,13 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
dir = -dir;
}
}
+
+#ifdef WITH_GAMEENGINE
+ if (drawshadowbox) {
+ draw_transp_sun_volume(la);
+ }
+#endif
+
}
else if (la->type == LA_AREA) {
setlinestyle(3);
@@ -1499,10 +1565,10 @@ static void draw_limit_line(float sta, float end, const short dflag, unsigned in
static void draw_focus_cross(float dist, float size)
{
glBegin(GL_LINES);
- glVertex3f(-size, 0.f, -dist);
- glVertex3f(size, 0.f, -dist);
- glVertex3f(0.f, -size, -dist);
- glVertex3f(0.f, size, -dist);
+ glVertex3f(-size, 0.0f, -dist);
+ glVertex3f(size, 0.0f, -dist);
+ glVertex3f(0.0f, -size, -dist);
+ glVertex3f(0.0f, size, -dist);
glEnd();
}
@@ -1555,8 +1621,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
BKE_tracking_get_camera_object_matrix(scene, base->object, mat);
/* we're compensating camera size for bundles size,
- * to make it so bundles are always displayed with the same size
- */
+ * to make it so bundles are always displayed with the same size */
copy_v3_v3(camera_size, base->object->size);
if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0)
mul_v3_fl(camera_size, tracking_object->scale);
@@ -1624,7 +1689,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
glColor3ubv(ob_wire_col);
}
- glLineWidth(2.f);
+ glLineWidth(2.0f);
glDisable(GL_LIGHTING);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
@@ -1632,7 +1697,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_LIGHTING);
- glLineWidth(1.f);
+ glLineWidth(1.0f);
}
if ((dflag & DRAW_CONSTCOLOR) == 0) {
@@ -1746,6 +1811,238 @@ static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d,
GPU_select_load_id(base->selcol);
}
+static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], const GLenum mode)
+{
+ glBegin(mode);
+ glVertex3fv(near_plane[0]);
+ glVertex3fv(far_plane[0]);
+ glVertex3fv(far_plane[1]);
+ glVertex3fv(near_plane[1]);
+ glEnd();
+
+ glBegin(mode);
+ glVertex3fv(near_plane[1]);
+ glVertex3fv(far_plane[1]);
+ glVertex3fv(far_plane[2]);
+ glVertex3fv(near_plane[2]);
+ glEnd();
+
+ glBegin(mode);
+ glVertex3fv(near_plane[2]);
+ glVertex3fv(near_plane[1]);
+ glVertex3fv(far_plane[1]);
+ glVertex3fv(far_plane[2]);
+ glEnd();
+
+ glBegin(mode);
+ glVertex3fv(far_plane[0]);
+ glVertex3fv(near_plane[0]);
+ glVertex3fv(near_plane[3]);
+ glVertex3fv(far_plane[3]);
+ glEnd();
+}
+
+/* camera frame */
+static void drawcamera_frame(float vec[4][3], const GLenum mode)
+{
+ glBegin(mode);
+ glVertex3fv(vec[0]);
+ glVertex3fv(vec[1]);
+ glVertex3fv(vec[2]);
+ glVertex3fv(vec[3]);
+ glEnd();
+}
+
+/* center point to camera frame */
+static void drawcamera_framelines(float vec[4][3], float origin[3])
+{
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(vec[1]);
+ glVertex3fv(origin);
+ glVertex3fv(vec[0]);
+ glVertex3fv(vec[3]);
+ glVertex3fv(origin);
+ glVertex3fv(vec[2]);
+ glEnd();
+}
+
+static bool drawcamera_is_stereo3d(Scene *scene, View3D *v3d, Object *ob)
+{
+ return (ob == v3d->camera) &&
+ (scene->r.scemode & R_MULTIVIEW) != 0 &&
+ (v3d->stereo3d_flag);
+}
+
+static void drawcamera_stereo3d(
+ Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const Camera *cam,
+ float vec[4][3], float drawsize, const float scale[3])
+{
+ int i, j;
+ float obmat[4][4];
+ float vec_lr[2][4][3];
+ const float fac = (cam->stereo.pivot == CAM_S3D_PIVOT_CENTER) ? 2.0f : 1.0f;
+ float origin[2][3] = {{0}};
+ float tvec[3];
+ const Camera *cam_lr[2];
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+
+ const bool is_stereo3d_cameras = (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS) && (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
+ const bool is_stereo3d_plane = (v3d->stereo3d_flag & V3D_S3D_DISPPLANE) && (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
+ const bool is_stereo3d_volume = (v3d->stereo3d_flag & V3D_S3D_DISPVOLUME);
+
+ zero_v3(tvec);
+
+ glPushMatrix();
+
+ for (i = 0; i < 2; i++) {
+ ob = BKE_camera_multiview_render(scene, ob, names[i]);
+ cam_lr[i] = ob->data;
+
+ glLoadMatrixf(rv3d->viewmat);
+ BKE_camera_multiview_model_matrix(&scene->r, ob, names[i], obmat);
+ glMultMatrixf(obmat);
+
+ copy_m3_m3(vec_lr[i], vec);
+ copy_v3_v3(vec_lr[i][3], vec[3]);
+
+ if (cam->stereo.convergence_mode == CAM_S3D_OFFAXIS) {
+ const float shift_x =
+ ((BKE_camera_multiview_shift_x(&scene->r, ob, names[i]) - cam->shiftx) *
+ (drawsize * scale[0] * fac));
+
+ for (j = 0; j < 4; j++) {
+ vec_lr[i][j][0] += shift_x;
+ }
+ }
+
+ if (is_stereo3d_cameras) {
+ /* camera frame */
+ drawcamera_frame(vec_lr[i], GL_LINE_LOOP);
+
+ /* center point to camera frame */
+ drawcamera_framelines(vec_lr[i], tvec);
+ }
+
+ /* connecting line */
+ mul_m4_v3(obmat, origin[i]);
+
+ /* convergence plane */
+ if (is_stereo3d_plane || is_stereo3d_volume) {
+ for (j = 0; j < 4; j++) {
+ mul_m4_v3(obmat, vec_lr[i][j]);
+ }
+ }
+ }
+
+
+ /* the remaining drawing takes place in the view space */
+ glLoadMatrixf(rv3d->viewmat);
+
+ if (is_stereo3d_cameras) {
+ /* draw connecting lines */
+ glPushAttrib(GL_ENABLE_BIT);
+
+ glLineStipple(2, 0xAAAA);
+ glEnable(GL_LINE_STIPPLE);
+
+ glBegin(GL_LINES);
+ glVertex3fv(origin[0]);
+ glVertex3fv(origin[1]);
+ glEnd();
+ glPopAttrib();
+ }
+
+ /* draw convergence plane*/
+ if (is_stereo3d_plane) {
+ float axis_center[3], screen_center[3];
+ float world_plane[4][3];
+ float local_plane[4][3];
+ float offset;
+
+ mid_v3_v3v3(axis_center, origin[0], origin[1]);
+
+ for (i = 0; i < 4; i++) {
+ mid_v3_v3v3(world_plane[i], vec_lr[0][i], vec_lr[1][i]);
+ sub_v3_v3v3(local_plane[i], world_plane[i], axis_center);
+ }
+
+ mid_v3_v3v3(screen_center, world_plane[0], world_plane[2]);
+ offset = cam->stereo.convergence_distance / len_v3v3(screen_center, axis_center);
+
+ for (i = 0; i < 4; i++) {
+ mul_v3_fl(local_plane[i], offset);
+ add_v3_v3(local_plane[i], axis_center);
+ }
+
+ glColor3f(0.0f, 0.0f, 0.0f);
+
+ /* camera frame */
+ drawcamera_frame(local_plane, GL_LINE_LOOP);
+
+ if (v3d->stereo3d_convergence_alpha > 0.0f) {
+ glEnable(GL_BLEND);
+ glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
+
+ glColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha);
+
+ drawcamera_frame(local_plane, GL_QUADS);
+
+ glDisable(GL_BLEND);
+ glDepthMask(1); /* restore write in zbuffer */
+ }
+ }
+
+ /* draw convergence plane*/
+ if (is_stereo3d_volume) {
+ float screen_center[3];
+ float near_plane[4][3], far_plane[4][3];
+ float offset;
+ int j;
+
+ for (i = 0; i < 2; i++) {
+ mid_v3_v3v3(screen_center, vec_lr[i][0], vec_lr[i][2]);
+
+ offset = len_v3v3(screen_center, origin[i]);
+
+ for (j = 0; j < 4; j++) {
+ sub_v3_v3v3(near_plane[j], vec_lr[i][j], origin[i]);
+ mul_v3_fl(near_plane[j], cam_lr[i]->clipsta / offset);
+ add_v3_v3(near_plane[j], origin[i]);
+
+ sub_v3_v3v3(far_plane[j], vec_lr[i][j], origin[i]);
+ mul_v3_fl(far_plane[j], cam_lr[i]->clipend / offset);
+ add_v3_v3(far_plane[j], origin[i]);
+ }
+
+ /* camera frame */
+ glColor3f(0.0f, 0.0f, 0.0f);
+
+ drawcamera_frame(near_plane, GL_LINE_LOOP);
+ drawcamera_frame(far_plane, GL_LINE_LOOP);
+ drawcamera_volume(near_plane, far_plane, GL_LINE_LOOP);
+
+ if (v3d->stereo3d_volume_alpha > 0.0f) {
+ glEnable(GL_BLEND);
+ glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
+
+ if (i == 0)
+ glColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha);
+ else
+ glColor4f(1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha);
+
+ drawcamera_frame(near_plane, GL_QUADS);
+ drawcamera_frame(far_plane, GL_QUADS);
+ drawcamera_volume(near_plane, far_plane, GL_QUADS);
+
+ glDisable(GL_BLEND);
+ glDepthMask(1); /* restore write in zbuffer */
+ }
+ }
+ }
+
+ glPopMatrix();
+}
+
/* flag similar to draw_object() */
static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
const short dflag, const unsigned char ob_wire_col[4])
@@ -1760,6 +2057,12 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
const bool is_view = (rv3d->persp == RV3D_CAMOB && ob == v3d->camera);
MovieClip *clip = BKE_object_movieclip_get(scene, base->object, false);
+ const bool is_stereo3d = drawcamera_is_stereo3d(scene, v3d, ob);
+ const bool is_stereo3d_cameras = (ob == scene->camera) &&
+ (scene->r.scemode & R_MULTIVIEW) &&
+ (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) &&
+ (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS);
+
/* draw data for movie clip set as active for scene */
if (clip) {
draw_viewport_reconstruction(scene, base, v3d, clip, dflag, ob_wire_col, false);
@@ -1796,12 +2099,8 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
glDisable(GL_CULL_FACE);
/* camera frame */
- glBegin(GL_LINE_LOOP);
- glVertex3fv(vec[0]);
- glVertex3fv(vec[1]);
- glVertex3fv(vec[2]);
- glVertex3fv(vec[3]);
- glEnd();
+ if (!is_stereo3d_cameras)
+ drawcamera_frame(vec, GL_LINE_LOOP);
if (is_view)
return;
@@ -1809,20 +2108,12 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
zero_v3(tvec);
/* center point to camera frame */
- glBegin(GL_LINE_STRIP);
- glVertex3fv(vec[1]);
- glVertex3fv(tvec);
- glVertex3fv(vec[0]);
- glVertex3fv(vec[3]);
- glVertex3fv(tvec);
- glVertex3fv(vec[2]);
- glEnd();
-
+ if (!is_stereo3d_cameras)
+ drawcamera_framelines(vec, tvec);
/* arrow on top */
tvec[2] = vec[1][2]; /* copy the depth */
-
/* draw an outline arrow for inactive cameras and filled
* for active cameras. We actually draw both outline+filled
* for active cameras so the wire can be seen side-on */
@@ -1872,14 +2163,17 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
glPopMatrix();
}
}
+
+ /* stereo cameras drawing */
+ if (is_stereo3d) {
+ drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale);
+ }
}
/* flag similar to draw_object() */
static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d),
Object *UNUSED(ob), int UNUSED(flag))
{
- //Speaker *spk = ob->data;
-
float vec[3];
int i, j;
@@ -1990,9 +2284,9 @@ static void ensure_curve_cache(Scene *scene, Object *object)
* here, we also need to check whether display list is
* empty or not.
*
- * The trick below tries to optimie calls to displist
+ * The trick below tries to optimize calls to displist
* creation for cases curve is empty. Meaning, if the curve
- * is empty (without splies) bevel list would also be empty.
+ * is empty (without splines) bevel list would also be empty.
* And the thing is, render thread always leaves bevel list
* in a proper state. So if bevel list is here and display
* list is not we need to make display list.
@@ -2270,8 +2564,7 @@ static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
BMVert *eve = BM_vert_at_index(data->bm, index);
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
- /* skin nodes: draw a red circle around the root
- * node(s) */
+ /* skin nodes: draw a red circle around the root node(s) */
if (data->cd_vskin_offset != -1) {
const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, data->cd_vskin_offset);
if (vs->flag & MVERT_SKIN_ROOT) {
@@ -2337,7 +2630,6 @@ static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVer
static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
{
BMEdge *eed;
- //unsigned char **cols = userData, *col;
drawDMEdgesSel_userData *data = userData;
unsigned char *col;
@@ -2354,7 +2646,7 @@ static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
else {
col = data->baseCol;
}
- /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
+ /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
if (col[3] == 0)
return DM_DRAW_OPTION_SKIP;
@@ -2751,7 +3043,7 @@ static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *ba
data.orig_index_mf_to_mpoly = data.orig_index_mp_to_orig = NULL;
}
- dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions, &data, 0);
+ dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, NULL, draw_dm_faces_sel__compareDrawOptions, &data, 0);
}
static DMDrawOption draw_dm_creases__setDrawOptions(void *userData, int index)
@@ -3044,7 +3336,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
}
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- /* draw selected edges, or edges next to selected verts while draging */
+ /* draw selected edges, or edges next to selected verts while dragging */
if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
(do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))))
@@ -3082,7 +3374,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
unit->system, B_UNIT_LENGTH, do_split, false);
}
else {
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), conv_float, len_v3v3(v1, v2));
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, len_v3v3(v1, v2));
}
view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col);
@@ -3101,17 +3393,15 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
}
- // invert_m4_m4(ob->imat, ob->obmat); // this is already called
-
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
BMLoop *l_a, *l_b;
if (BM_edge_loop_pair(eed, &l_a, &l_b)) {
- /* draw selected edges, or edges next to selected verts while draging */
+ /* draw selected edges, or edges next to selected verts while dragging */
if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
(do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
BM_elem_flag_test(eed->v2, BM_ELEM_SELECT) ||
- /* special case, this is useful to show when vertes connected to this edge via a
- * face are being transformed */
+ /* special case, this is useful to show when verts connected to
+ * this edge via a face are being transformed */
BM_elem_flag_test(l_a->next->next->v, BM_ELEM_SELECT) ||
BM_elem_flag_test(l_a->prev->v, BM_ELEM_SELECT) ||
BM_elem_flag_test(l_b->next->next->v, BM_ELEM_SELECT) ||
@@ -3161,7 +3451,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
angle = angle_normalized_v3v3(no_a, no_b);
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col);
}
@@ -3186,7 +3476,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
3, unit->system, B_UNIT_AREA, do_split, false); \
} \
else { \
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), conv_float, area); \
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, area); \
} \
view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col); \
} (void)0
@@ -3304,7 +3594,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
angle = angle_v3v3v3(v1, v2, v3);
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
interp_v3_v3v3(fvec, vmid, v2_local, 0.8f);
view3d_cached_text_draw_add(fvec, numstr, numstr_len, 0, txt_flag, col);
}
@@ -3335,7 +3625,7 @@ static void draw_em_indices(BMEditMesh *em)
UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", i);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
view3d_cached_text_draw_add(v->co, numstr, numstr_len, 0, txt_flag, col);
}
i++;
@@ -3347,7 +3637,7 @@ static void draw_em_indices(BMEditMesh *em)
UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", i);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
mid_v3_v3v3(pos, e->v1->co, e->v2->co);
view3d_cached_text_draw_add(pos, numstr, numstr_len, 0, txt_flag, col);
}
@@ -3361,7 +3651,7 @@ static void draw_em_indices(BMEditMesh *em)
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
BM_face_calc_center_mean(f, pos);
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", i);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
view3d_cached_text_draw_add(pos, numstr, numstr_len, 0, txt_flag, col);
}
i++;
@@ -3417,7 +3707,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
if (em->bm->selected.last) {
BMEditSelection *ese = em->bm->selected.last;
- /* face is handeled above */
+ /* face is handled above */
#if 0
if (ese->type == BM_FACE) {
efa_act = (BMFace *)ese->data;
@@ -3532,11 +3822,14 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
}
else if (efa_act) {
/* even if draw faces is off it would be nice to draw the stipple face
- * Make all other faces zero alpha except for the active
- * */
- /* col4 is only used by WITH_FREESTYLE, but keeping it here spares some #ifdef's... */
- unsigned char col1[4], col2[4], col3[4], col4[4];
- col1[3] = col2[3] = col4[3] = 0; /* don't draw */
+ * Make all other faces zero alpha except for the active */
+ unsigned char col1[4], col2[4], col3[4];
+#ifdef WITH_FREESTYLE
+ unsigned char col4[4];
+ col4[3] = 0; /* don't draw */
+#endif
+ col1[3] = col2[3] = 0; /* don't draw */
+
UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
glEnable(GL_BLEND);
@@ -3550,7 +3843,6 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
glDisable(GL_BLEND);
glDepthMask(1); /* restore write in zbuffer */
-
}
/* here starts all fancy draw-extra over */
@@ -3653,7 +3945,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
{
if ((v3d->transp == false) && /* not when we draw the transparent pass */
- (ob->mode & OB_MODE_ALL_PAINT) == false) /* not when painting (its distracting) - campbell */
+ (ob->mode & OB_MODE_ALL_BRUSH) == false) /* not when painting (its distracting) - campbell */
{
glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
glDepthMask(0);
@@ -3691,7 +3983,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
#endif
Mesh *me = ob->data;
eWireDrawMode draw_wire = OBDRAW_WIRE_OFF;
- int /* totvert,*/ totedge, totface;
+ bool /* no_verts,*/ no_edges, no_faces;
DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
const bool is_obact = (ob == OBACT);
int draw_flags = (is_obact && BKE_paint_select_face_test(ob)) ? DRAW_FACE_SELECT : 0;
@@ -3714,9 +4006,9 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
draw_wire = OBDRAW_WIRE_ON_DEPTH; /* draw wire after solid using zoffset and depth buffer adjusment */
}
- /* totvert = dm->getNumVerts(dm); */ /*UNUSED*/
- totedge = dm->getNumEdges(dm);
- totface = dm->getNumTessFaces(dm);
+ /* check polys instead of tessfaces because of dyntopo where tessfaces don't exist */
+ no_edges = (dm->getNumEdges(dm) == 0);
+ no_faces = (dm->getNumPolys(dm) == 0);
/* vertexpaint, faceselect wants this, but it doesnt work for shaded? */
glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
@@ -3725,15 +4017,15 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_WIRE) == 0)
draw_bounding_volume(ob, ob->boundtype);
}
- else if ((totface == 0 && totedge == 0) ||
+ else if ((no_faces && no_edges) ||
((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob)))
{
glPointSize(1.5);
dm->drawVerts(dm);
glPointSize(1.0);
}
- else if (dt == OB_WIRE || totface == 0) {
- draw_wire = OBDRAW_WIRE_ON; /* draw wire only, no depth buffer stuff */
+ else if ((dt == OB_WIRE) || no_faces) {
+ draw_wire = OBDRAW_WIRE_ON; /* draw wire only, no depth buffer stuff */
}
else if (((is_obact && ob->mode & OB_MODE_TEXTURE_PAINT)) ||
check_object_draw_texture(scene, v3d, dt))
@@ -3775,8 +4067,10 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
else
dm->drawFacesGLSL(dm, GPU_enable_material);
-// if (BKE_bproperty_object_get(ob, "Text"))
-// XXX draw_mesh_text(ob, 1);
+#if 0 /* XXX */
+ if (BKE_bproperty_object_get(ob, "Text"))
+ draw_mesh_text(ob, 1);
+#endif
GPU_disable_material();
glFrontFace(GL_CCW);
@@ -3894,7 +4188,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
}
if ((draw_wire != OBDRAW_WIRE_OFF) && /* draw extra wire */
- /* when overriding with render only, don't bother */
+ /* when overriding with render only, don't bother */
(((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_SOLID) == 0))
{
/* When using wireframe object draw in particle edit mode
@@ -3924,7 +4218,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */
}
- dm->drawEdges(dm, (dt == OB_WIRE || totface == 0), (ob->dtx & OB_DRAW_ALL_EDGES) != 0);
+ dm->drawEdges(dm, ((dt == OB_WIRE) || no_faces), (ob->dtx & OB_DRAW_ALL_EDGES) != 0);
if (dt != OB_WIRE && (draw_wire == OBDRAW_WIRE_ON_DEPTH)) {
glDepthMask(1);
@@ -3933,7 +4227,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
}
if (is_obact && BKE_paint_select_vert_test(ob)) {
- const int use_depth = (v3d->flag & V3D_ZBUF_SELECT);
+ const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) != 0;
glColor3f(0.0f, 0.0f, 0.0f);
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
@@ -3948,7 +4242,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
dm->release(dm);
}
-/* returns 1 if nothing was drawn, for detecting to draw an object center */
+/* returns true if nothing was drawn, for detecting to draw an object center */
static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
const char dt, const unsigned char ob_wire_col[4], const short dflag)
{
@@ -3992,7 +4286,9 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
scene->customdata_mask);
DM_update_materials(finalDM, ob);
- DM_update_materials(cageDM, ob);
+ if (cageDM != finalDM) {
+ DM_update_materials(cageDM, ob);
+ }
if (dt > OB_WIRE) {
const bool glsl = draw_glsl_material(scene, ob, v3d, dt);
@@ -4336,7 +4632,7 @@ static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d,
/**
* Only called by #drawDispList
- * \return 1 when nothing was drawn
+ * \return true when nothing was drawn
*/
static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
const char dt, const short dflag, const unsigned char ob_wire_col[4])
@@ -4980,7 +5276,7 @@ static void draw_particle(ParticleKey *state, int draw_as, short draw, float pix
copy_v3_v3(pdd->vd, vec2); pdd->vd += 3;
vec[2] = 2.0f * pixsize;
- vec[0] = vec[1] = 0.0;
+ vec[0] = vec[1] = 0.0f;
mul_qt_v3(state->rot, vec);
if (draw_as == PART_DRAW_AXIS) {
copy_v3_v3(vec2, state->co);
@@ -5064,7 +5360,7 @@ static void draw_particle_data(ParticleSystem *psys, RegionView3D *rv3d,
if (psys->parent)
mul_m4_v3(psys->parent->obmat, state->co);
- /* create actiual particle data */
+ /* create actual particle data */
if (draw_as == PART_DRAW_BB) {
bb->offset[0] = part->bb_offset[0];
bb->offset[1] = part->bb_offset[1];
@@ -5089,16 +5385,17 @@ static void draw_particle_data(ParticleSystem *psys, RegionView3D *rv3d,
draw_particle(state, draw_as, part->draw, pixsize, imat, part->draw_line, bb, pdd);
}
-/* unified drawing of all new particle systems draw types except dupli ob & group */
-/* mostly tries to use vertex arrays for speed */
-
-/* 1. check that everything is ok & updated */
-/* 2. start initializing things */
-/* 3. initialize according to draw type */
-/* 4. allocate drawing data arrays */
-/* 5. start filling the arrays */
-/* 6. draw the arrays */
-/* 7. clean up */
+/* unified drawing of all new particle systems draw types except dupli ob & group
+ * mostly tries to use vertex arrays for speed
+ *
+ * 1. check that everything is ok & updated
+ * 2. start initializing things
+ * 3. initialize according to draw type
+ * 4. allocate drawing data arrays
+ * 5. start filling the arrays
+ * 6. draw the arrays
+ * 7. clean up
+ */
static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv3d,
Base *base, ParticleSystem *psys,
const char ob_dt, const short dflag)
@@ -5146,6 +5443,12 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
return;
}
+ /* prepare curvemapping tables */
+ if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve)
+ curvemapping_changed_all(psys->part->clumpcurve);
+ if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve)
+ curvemapping_changed_all(psys->part->roughcurve);
+
/* 2. */
sim.scene = scene;
sim.ob = ob;
@@ -5291,7 +5594,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
int create_ndata = 0;
if (!pdd)
- pdd = psys->pdd = MEM_callocN(sizeof(ParticleDrawData), "ParticlDrawData");
+ pdd = psys->pdd = MEM_callocN(sizeof(ParticleDrawData), "ParticleDrawData");
if (part->draw_as == PART_DRAW_REND && part->trail_count > 1) {
tot_vec_size *= part->trail_count;
@@ -5397,6 +5700,12 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
case PART_DRAW_COL_PARENT:
particle_path_color(a, ma_col);
break;
+ case PART_DRAW_COL_TEX: {
+ ParticleTexture ptex;
+ psys_get_texture(&sim, pa, &ptex, PAMAP_COLOR, cfra);
+ copy_v3_v3(ma_col, ptex.color);
+ break;
+ }
default:
weight_to_rgb(ma_col, 1.0f);
BLI_assert(0);
@@ -5459,8 +5768,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
}
if (drawn) {
- /* additional things to draw for each particle */
- /* (velocity, size and number) */
+ /* additional things to draw for each particle
+ * (velocity, size and number) */
if ((part->draw & PART_DRAW_VEL) && pdd && pdd->vedata) {
copy_v3_v3(pdd->ved, state.co);
pdd->ved += 3;
@@ -5488,21 +5797,21 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if (part->draw & PART_DRAW_NUM) {
if (a < totpart && (part->draw & PART_DRAW_HEALTH) && (part->phystype == PART_PHYS_BOIDS)) {
- numstr_len = BLI_snprintf(val_pos, sizeof(numstr), "%d:%.2f", a, pa_health);
+ numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%d:%.2f", a, pa_health);
}
else {
- numstr_len = BLI_snprintf(val_pos, sizeof(numstr), "%d", a);
+ numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%d", a);
}
}
else {
if (a < totpart && (part->draw & PART_DRAW_HEALTH) && (part->phystype == PART_PHYS_BOIDS)) {
- numstr_len = BLI_snprintf(val_pos, sizeof(numstr), "%.2f", pa_health);
+ numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%.2f", pa_health);
}
}
if (numstr[0]) {
- /* in path drawing state.co is the end point */
- /* use worldspace beause object matrix is already applied */
+ /* in path drawing state.co is the end point
+ * use worldspace because object matrix is already applied */
mul_v3_m4v3(vec_txt, ob->imat, state.co);
view3d_cached_text_draw_add(vec_txt, numstr, numstr_len,
10, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, tcol);
@@ -5519,7 +5828,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if (draw_as == PART_DRAW_PATH) {
ParticleCacheKey **cache, *path;
- float /* *cd2=NULL, */ /* UNUSED */ *cdata2 = NULL;
+ float *cdata2 = NULL;
/* setup gl flags */
if (1) { //ob_dt > OB_WIRE) {
@@ -5583,11 +5892,13 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
HairKey *hkey = pa->hair;
glVertexPointer(3, GL_FLOAT, sizeof(HairKey), hkey->world_co);
-
- // XXX use proper theme color here
-// UI_ThemeColor(TH_NORMAL);
+
+#if 0 /* XXX use proper theme color here */
+ UI_ThemeColor(TH_NORMAL);
+#else
glColor3f(0.58f, 0.67f, 1.0f);
-
+#endif
+
glDrawArrays(GL_LINE_STRIP, 0, pa->totkey);
}
}
@@ -5720,6 +6031,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
glColor3fv(col);
}
break;
+ case PART_DRAW_COL_TEX:
+ // TODO
+ break;
default:
break;
}
@@ -5729,7 +6043,6 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1);
}
-
/* restore & clean up */
if (1) { //ob_dt > OB_WIRE) {
if (part->draw_col == PART_DRAW_COL_MAT)
@@ -5737,9 +6050,10 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
glDisable(GL_COLOR_MATERIAL);
}
- if (cdata2)
+ if (cdata2) {
MEM_freeN(cdata2);
- /* cd2 = */ /* UNUSED */ cdata2 = NULL;
+ cdata2 = NULL;
+ }
glLineWidth(1.0f);
@@ -5748,8 +6062,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
float vec_txt[3];
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%i", a);
- /* use worldspace beause object matrix is already applied */
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%i", a);
+ /* use worldspace because object matrix is already applied */
mul_v3_m4v3(vec_txt, ob->imat, cache[a]->co);
view3d_cached_text_draw_add(vec_txt, numstr, numstr_len,
10, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, tcol);
@@ -5877,7 +6191,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
PTCacheEditPoint *point;
PTCacheEditKey *key;
ParticleEditSettings *pset = PE_settings(scene);
- int i, k, totpoint = edit->totpoint, timed = pset->flag & PE_FADE_TIME ? pset->fade_frames : 0;
+ int i, k, totpoint = edit->totpoint, timed = (pset->flag & PE_FADE_TIME) ? pset->fade_frames : 0;
int totkeys = 1;
float sel_col[3];
float nosel_col[3];
@@ -6017,7 +6331,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glColor3fv(nosel_col);
/* has to be like this.. otherwise selection won't work, have try glArrayElement later..*/
glBegin(GL_POINTS);
- glVertex3fv(key->flag & PEK_USE_WCO ? key->world_co : key->co);
+ glVertex3fv((key->flag & PEK_USE_WCO) ? key->world_co : key->co);
glEnd();
}
}
@@ -6033,9 +6347,9 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glShadeModel(GL_FLAT);
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
glLineWidth(1.0f);
- glPointSize(1.0);
+ glPointSize(1.0f);
}
-//static void ob_draw_RE_motion(float com[3],float rotscale[3][3],float tw,float th)
+
static void ob_draw_RE_motion(float com[3], float rotscale[3][3], float itw, float ith, float drw_size)
{
float tr[3][3];
@@ -6439,7 +6753,7 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
Nurb *nu;
BPoint *bp, *bp1;
int a, b, ofs, index;
- Curve *cu = (Curve *)ob->data;
+ Curve *cu = ob->data;
index = 0;
nu = nurb;
@@ -6799,7 +7113,7 @@ static void draw_empty_sphere(float size)
static GLuint displist = 0;
if (displist == 0) {
- GLUquadricObj *qobj;
+ GLUquadricObj *qobj;
displist = glGenLists(1);
glNewList(displist, GL_COMPILE);
@@ -6830,16 +7144,13 @@ static void draw_empty_sphere(float size)
/* draw a cone for use as an empty drawtype */
static void draw_empty_cone(float size)
{
- float cent = 0;
- float radius;
+ const float radius = size;
+
GLUquadricObj *qobj = gluNewQuadric();
gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
-
glPushMatrix();
- radius = size;
- glTranslatef(cent, cent, cent);
glScalef(radius, size * 2.0f, radius);
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(qobj, 1.0, 0.0, 1.0, 8, 1);
@@ -6852,7 +7163,7 @@ static void draw_empty_cone(float size)
static void drawspiral(const float cent[3], float rad, float tmat[4][4], int start)
{
float vec[3], vx[3], vy[3];
- const float tot_inv = (1.0f / (float)CIRCLE_RESOL);
+ const float tot_inv = 1.0f / (float)CIRCLE_RESOL;
int a;
bool inverse = false;
float x, y, fac;
@@ -6916,8 +7227,7 @@ static void drawspiral(const float cent[3], float rad, float tmat[4][4], int sta
}
/* draws a circle on x-z plane given the scaling of the circle, assuming that
- * all required matrices have been set (used for drawing empties)
- */
+ * all required matrices have been set (used for drawing empties) */
static void drawcircle_size(float size)
{
float x, y;
@@ -6925,7 +7235,7 @@ static void drawcircle_size(float size)
glBegin(GL_LINE_LOOP);
- /* coordinates are: cos(degrees * 11.25) = x, sin(degrees*11.25) = y, 0.0f = z */
+ /* coordinates are: cos(degrees * 11.25) = x, sin(degrees * 11.25) = y, 0.0f = z */
for (degrees = 0; degrees < CIRCLE_RESOL; degrees++) {
x = cosval[degrees];
y = sinval[degrees];
@@ -7069,31 +7379,23 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
PartDeflect *pd = ob->pd;
float imat[4][4], tmat[4][4];
float vec[3] = {0.0, 0.0, 0.0};
- float size;
-
/* scale size of circle etc with the empty drawsize */
- if (ob->type == OB_EMPTY) size = ob->empty_drawsize;
- else size = 1.0;
+ const float size = (ob->type == OB_EMPTY) ? ob->empty_drawsize : 1.0f;
/* calculus here, is reused in PFIELD_FORCE */
invert_m4_m4(imat, rv3d->viewmatob);
-// normalize_v3(imat[0]); /* we don't do this because field doesnt scale either... apart from wind! */
-// normalize_v3(imat[1]);
+#if 0
+ normalize_v3(imat[0]); /* we don't do this because field doesnt scale either... apart from wind! */
+ normalize_v3(imat[1]);
+#endif
if (pd->forcefield == PFIELD_WIND) {
- float force_val;
+ float force_val = pd->f_strength;
if ((dflag & DRAW_CONSTCOLOR) == 0) {
ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f);
}
- //if (has_ipo_code(ob->ipo, OB_PD_FSTR))
- // force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, scene->r.cfra);
- //else
- {
- force_val = pd->f_strength;
- }
-
unit_m4(tmat);
force_val *= 0.1f;
drawcircball(GL_LINE_LOOP, vec, size, tmat);
@@ -7107,14 +7409,7 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
}
else if (pd->forcefield == PFIELD_FORCE) {
- float ffall_val;
-
- //if (has_ipo_code(ob->ipo, OB_PD_FFALL))
- // ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, scene->r.cfra);
- //else
- {
- ffall_val = pd->f_power;
- }
+ float ffall_val = pd->f_power;
if ((dflag & DRAW_CONSTCOLOR) == 0) ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f);
drawcircball(GL_LINE_LOOP, vec, size, imat);
@@ -7124,20 +7419,9 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
drawcircball(GL_LINE_LOOP, vec, size * 2.0f, imat);
}
else if (pd->forcefield == PFIELD_VORTEX) {
- float /*ffall_val,*/ force_val;
+ float force_val = pd->f_strength;
unit_m4(tmat);
- //if (has_ipo_code(ob->ipo, OB_PD_FFALL))
- // ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, scene->r.cfra);
- //else
- // ffall_val = pd->f_power;
-
- //if (has_ipo_code(ob->ipo, OB_PD_FSTR))
- // force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, scene->r.cfra);
- //else
- {
- force_val = pd->f_strength;
- }
if ((dflag & DRAW_CONSTCOLOR) == 0) {
ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.7f);
@@ -7155,25 +7439,19 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
else if (pd->forcefield == PFIELD_GUIDE && ob->type == OB_CURVE) {
Curve *cu = ob->data;
if ((cu->flag & CU_PATH) && ob->curve_cache->path && ob->curve_cache->path->data) {
- float mindist, guidevec1[4], guidevec2[3];
-
- //if (has_ipo_code(ob->ipo, OB_PD_FSTR))
- // mindist = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, scene->r.cfra);
- //else
- {
- mindist = pd->f_strength;
- }
+ float guidevec1[4], guidevec2[3];
+ float mindist = pd->f_strength;
if ((dflag & DRAW_CONSTCOLOR) == 0) {
ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f);
}
- /*path end*/
+ /* path end */
setlinestyle(3);
where_on_path(ob, 1.0f, guidevec1, guidevec2, NULL, NULL, NULL);
drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat);
- /*path beginning*/
+ /* path beginning */
setlinestyle(0);
where_on_path(ob, 0.0f, guidevec1, guidevec2, NULL, NULL, NULL);
drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat);
@@ -7244,19 +7522,31 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
setlinestyle(0);
}
-static void draw_box(float vec[8][3])
+static void draw_box(float vec[8][3], bool solid)
{
- glBegin(GL_LINE_STRIP);
- glVertex3fv(vec[0]); glVertex3fv(vec[1]); glVertex3fv(vec[2]); glVertex3fv(vec[3]);
- glVertex3fv(vec[0]); glVertex3fv(vec[4]); glVertex3fv(vec[5]); glVertex3fv(vec[6]);
- glVertex3fv(vec[7]); glVertex3fv(vec[4]);
- glEnd();
+ if (!solid) {
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(vec[0]); glVertex3fv(vec[1]); glVertex3fv(vec[2]); glVertex3fv(vec[3]);
+ glVertex3fv(vec[0]); glVertex3fv(vec[4]); glVertex3fv(vec[5]); glVertex3fv(vec[6]);
+ glVertex3fv(vec[7]); glVertex3fv(vec[4]);
+ glEnd();
- glBegin(GL_LINES);
- glVertex3fv(vec[1]); glVertex3fv(vec[5]);
- glVertex3fv(vec[2]); glVertex3fv(vec[6]);
- glVertex3fv(vec[3]); glVertex3fv(vec[7]);
- glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(vec[1]); glVertex3fv(vec[5]);
+ glVertex3fv(vec[2]); glVertex3fv(vec[6]);
+ glVertex3fv(vec[3]); glVertex3fv(vec[7]);
+ glEnd();
+ }
+ else {
+ glBegin(GL_QUADS);
+ glVertex3fv(vec[0]); glVertex3fv(vec[1]); glVertex3fv(vec[2]); glVertex3fv(vec[3]);
+ glVertex3fv(vec[7]); glVertex3fv(vec[6]); glVertex3fv(vec[5]); glVertex3fv(vec[4]);
+ glVertex3fv(vec[4]); glVertex3fv(vec[5]); glVertex3fv(vec[1]); glVertex3fv(vec[0]);
+ glVertex3fv(vec[3]); glVertex3fv(vec[2]); glVertex3fv(vec[6]); glVertex3fv(vec[7]);
+ glVertex3fv(vec[3]); glVertex3fv(vec[7]); glVertex3fv(vec[4]); glVertex3fv(vec[0]);
+ glVertex3fv(vec[1]); glVertex3fv(vec[5]); glVertex3fv(vec[6]); glVertex3fv(vec[2]);
+ glEnd();
+ }
}
static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin)
@@ -7350,7 +7640,7 @@ static void draw_bounding_volume(Object *ob, char type)
vec[0][2] = vec[3][2] = vec[4][2] = vec[7][2] = -size[2];
vec[1][2] = vec[2][2] = vec[5][2] = vec[6][2] = +size[2];
- draw_box(vec);
+ draw_box(vec, false);
}
else {
draw_bb_quadric(bb, type, true);
@@ -7358,7 +7648,7 @@ static void draw_bounding_volume(Object *ob, char type)
}
else {
if (type == OB_BOUND_BOX)
- draw_box(bb->vec);
+ draw_box(bb->vec, false);
else
draw_bb_quadric(bb, type, false);
}
@@ -7394,7 +7684,7 @@ static void drawtexspace(Object *ob)
setlinestyle(2);
- draw_box(vec);
+ draw_box(vec, false);
setlinestyle(0);
}
@@ -7581,7 +7871,7 @@ static void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_
else {
if (ob->flag & OB_FROMGROUP) {
if (base->flag & (SELECT + BA_WAS_SEL)) {
- /* uses darker active color for non-active + selected*/
+ /* uses darker active color for non-active + selected */
theme_id = TH_GROUP_ACTIVE;
if (scene->basact != base) {
@@ -7701,8 +7991,11 @@ static void draw_object_matcap_check(View3D *v3d, Object *ob)
v3d->defmaterial->preview = NULL;
}
/* first time users */
- if (v3d->matcap_icon == 0)
+ if (v3d->matcap_icon < ICON_MATCAP_01 ||
+ v3d->matcap_icon > ICON_MATCAP_24)
+ {
v3d->matcap_icon = ICON_MATCAP_01;
+ }
if (v3d->defmaterial->preview == NULL)
v3d->defmaterial->preview = UI_icon_to_preview(v3d->matcap_icon);
@@ -7734,7 +8027,7 @@ static void draw_rigidbody_shape(Object *ob)
vec[0][2] = vec[3][2] = vec[4][2] = vec[7][2] = -size[2];
vec[1][2] = vec[2][2] = vec[5][2] = vec[6][2] = +size[2];
- draw_box(vec);
+ draw_box(vec, false);
break;
case RB_SHAPE_SPHERE:
draw_bb_quadric(bb, OB_BOUND_SPHERE, true);
@@ -7773,7 +8066,8 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
const bool is_picking = (G.f & G_PICKSEL) != 0;
const bool has_particles = (ob->particlesystem.first != NULL);
const bool is_wire_color = V3D_IS_WIRECOLOR_OBJECT(scene, v3d, ob);
- bool particle_skip_object = false; /* Draw particles but not their emitter object. */
+ bool skip_object = false; /* Draw particles but not their emitter object. */
+ SmokeModifierData *smd = NULL;
if (ob != scene->obedit) {
if (ob->restrictflag & OB_RESTRICT_VIEW)
@@ -7797,17 +8091,37 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (ob->mode == OB_MODE_OBJECT) {
ParticleSystem *psys;
- particle_skip_object = render_override;
+ skip_object = render_override;
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
/* Once we have found a psys which renders its emitter object, we are done. */
if (psys->part->draw & PART_DRAW_EMITTER) {
- particle_skip_object = false;
+ skip_object = false;
break;
}
}
}
}
+ if ((md = modifiers_findByType(ob, eModifierType_Smoke)) && (modifier_isEnabled(scene, md, eModifierMode_Realtime))) {
+ smd = (SmokeModifierData *)md;
+
+ if (smd->domain) {
+ if (!v3d->transp && (dflag & DRAW_PICKING) == 0) {
+ if (!v3d->xray && !(ob->dtx & OB_DRAWXRAY)) {
+ /* object has already been drawn so skip drawing it */
+ ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
+ return;
+ }
+ else if (v3d->xray) {
+ /* object has already been drawn so skip drawing it */
+ ED_view3d_after_add(&v3d->afterdraw_xraytransp, base, dflag);
+ return;
+ }
+ }
+ }
+ }
+
+
/* xray delay? */
if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
/* don't do xray in particle mode, need the z-buffer */
@@ -7908,13 +8222,12 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (dt >= OB_BOUNDBOX) {
dtx = ob->dtx;
if (ob->mode & OB_MODE_EDIT) {
- // the only 2 extra drawtypes alowed in editmode
+ /* the only 2 extra drawtypes alowed in editmode */
dtx = dtx & (OB_DRAWWIRE | OB_TEXSPACE);
}
-
}
- if (!particle_skip_object) {
+ if (!skip_object) {
/* draw outline for selected objects, mesh does itself */
if ((v3d->flag & V3D_SELECT_OUTLINE) && !render_override && ob->type != OB_MESH) {
if (dt > OB_WIRE && (ob->mode & OB_MODE_EDIT) == 0 && (dflag & DRAW_SCENESET) == 0) {
@@ -7969,9 +8282,6 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
else if (ED_view3d_boundbox_clip(rv3d, ob->bb)) {
empty_object = drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
-
-//XXX old animsys if (cu->path)
-// curve_draw_speed(scene, ob);
}
break;
case OB_MBALL:
@@ -8090,7 +8400,8 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
/* code for new particle system */
if ((ob->particlesystem.first) &&
- (ob != scene->obedit))
+ (ob != scene->obedit) &&
+ !(ob->transflag & OB_IS_DUPLI_CACHE))
{
ParticleSystem *psys;
@@ -8107,14 +8418,16 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
view3d_cached_text_draw_begin();
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- /* run this so that possible child particles get cached */
- if (ob->mode & OB_MODE_PARTICLE_EDIT && is_obact) {
- PTCacheEdit *edit = PE_create_current(scene, ob);
- if (edit && edit->psys == psys)
- draw_update_ptcache_edit(scene, ob, edit);
+ if (!(ob->mode & OB_MODE_HAIR_EDIT)) {
+ /* run this so that possible child particles get cached */
+ if (ob->mode & OB_MODE_PARTICLE_EDIT && is_obact) {
+ PTCacheEdit *edit = PE_create_current(scene, ob);
+ if (edit && edit->psys == psys)
+ draw_update_ptcache_edit(scene, ob, edit);
+ }
+
+ draw_new_particle_system(scene, v3d, rv3d, base, psys, dt, dflag);
}
-
- draw_new_particle_system(scene, v3d, rv3d, base, psys, dt, dflag);
}
invert_m4_m4(ob->imat, ob->obmat);
view3d_cached_text_draw_end(v3d, ar, 0, NULL);
@@ -8139,15 +8452,20 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
glMultMatrixf(ob->obmat);
}
}
+
+ if (ob->mode & OB_MODE_HAIR_EDIT && is_obact) {
+ BMEditStrands *edit = BKE_editstrands_from_object(ob);
+ if (edit) {
+ draw_strands_edit_hair(scene, v3d, ar, edit);
+ }
+ }
}
/* draw code for smoke */
- if ((md = modifiers_findByType(ob, eModifierType_Smoke)) && (modifier_isEnabled(scene, md, eModifierMode_Realtime))) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
-
- // draw collision objects
- if ((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll) {
+ if (smd) {
#if 0
+ /* draw collision objects */
+ if ((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll) {
SmokeCollSettings *scs = smd->coll;
if (scs->points) {
size_t i;
@@ -8174,30 +8492,30 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
if (col) cpack(col);
-
}
-#endif
}
+#endif
/* only draw domains */
if (smd->domain) {
SmokeDomainSettings *sds = smd->domain;
- float p0[3], p1[3], viewnormal[3];
- BoundBox bb;
+ float viewnormal[3];
glLoadMatrixf(rv3d->viewmat);
glMultMatrixf(ob->obmat);
/* draw adaptive domain bounds */
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ if ((sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) && !render_override) {
+ float p0[3], p1[3];
+ BoundBox bb;
/* draw domain max bounds */
VECSUBFAC(p0, sds->p0, sds->cell_size, sds->adapt_res);
VECADDFAC(p1, sds->p1, sds->cell_size, sds->adapt_res);
BKE_boundbox_init_from_minmax(&bb, p0, p1);
- draw_box(bb.vec);
+ draw_box(bb.vec, false);
- /* draw base resolution bounds */
#if 0
+ /* draw base resolution bounds */
BKE_boundbox_init_from_minmax(&bb, sds->p0, sds->p1);
draw_box(bb.vec);
#endif
@@ -8205,16 +8523,16 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
/* don't show smoke before simulation starts, this could be made an option in the future */
if (smd->domain->fluid && CFRA >= smd->domain->point_cache[0]->startframe) {
+ float p0[3], p1[3];
- // get view vector
- copy_v3_v3(viewnormal, rv3d->viewinv[2]);
+ /* get view vector */
invert_m4_m4(ob->imat, ob->obmat);
- mul_mat3_m4_v3(ob->imat, viewnormal);
+ mul_v3_mat3_m4v3(viewnormal, ob->imat, rv3d->viewinv[2]);
normalize_v3(viewnormal);
/* set dynamic boundaries to draw the volume
- * also scale cube to global space to equalize volume slicing on all axises
- * (its scaled back before drawing) */
+ * also scale cube to global space to equalize volume slicing on all axes
+ * (it's scaled back before drawing) */
p0[0] = (sds->p0[0] + sds->cell_size[0] * sds->res_min[0] + sds->obj_shift_f[0]) * fabsf(ob->size[0]);
p0[1] = (sds->p0[1] + sds->cell_size[1] * sds->res_min[1] + sds->obj_shift_f[1]) * fabsf(ob->size[1]);
p0[2] = (sds->p0[2] + sds->cell_size[2] * sds->res_min[2] + sds->obj_shift_f[2]) * fabsf(ob->size[2]);
@@ -8298,7 +8616,6 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
view3d_cached_text_draw_add(zero, ob->id.name + 2, strlen(ob->id.name + 2), 10, 0, ob_wire_col);
}
}
- /*if (dtx & OB_DRAWIMAGE) drawDispListwire(&ob->disp);*/
if ((dtx & OB_DRAWWIRE) && dt >= OB_SOLID) {
if ((dflag & DRAW_CONSTCOLOR) == 0) {
draw_wire_extra(scene, rv3d, ob, ob_wire_col);
@@ -8347,7 +8664,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
/* object centers, need to be drawn in viewmat space for speed, but OK for picking select */
- if (!is_obact || !(ob->mode & OB_MODE_ALL_PAINT)) {
+ if (!is_obact || !(ob->mode & OB_MODE_ALL_BRUSH)) {
int do_draw_center = -1; /* defines below are zero or positive... */
if (render_override) {
@@ -8414,7 +8731,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (ELEM(curcon->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_OBJECTSOLVER)) {
/* special case for object solver and follow track constraints because they don't fill
* constraint targets properly (design limitation -- scene is needed for their target
- * but it can't be accessed from get_targets callvack) */
+ * but it can't be accessed from get_targets callback) */
Object *camob = NULL;
@@ -8439,7 +8756,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
}
else {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
if ((cti && cti->get_constraint_targets) && (curcon->flag & CONSTRAINT_EXPAND)) {
ListBase targets = {NULL, NULL};
@@ -8671,7 +8988,7 @@ static void bbs_mesh_solid_verts(Scene *scene, Object *ob)
static void bbs_mesh_solid_faces(Scene *scene, Object *ob)
{
DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
- Mesh *me = (Mesh *)ob->data;
+ Mesh *me = ob->data;
glColor3ub(0, 0, 0);
diff --git a/source/blender/editors/space_view3d/drawsimdebug.c b/source/blender/editors/space_view3d/drawsimdebug.c
index 6113bfd4143..46320ba6763 100644
--- a/source/blender/editors/space_view3d/drawsimdebug.c
+++ b/source/blender/editors/space_view3d/drawsimdebug.c
@@ -29,28 +29,21 @@
* \ingroup spview3d
*/
-#include "MEM_guardedalloc.h"
-
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
#include "DNA_object_types.h"
-#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BKE_effect.h"
-#include "BKE_global.h"
-#include "BKE_modifier.h"
#include "view3d_intern.h"
#include "BIF_gl.h"
-#include "BIF_glutil.h"
-#include "UI_resources.h"
static void draw_sim_debug_elements(SimDebugData *debug_data, float imat[4][4])
{
diff --git a/source/blender/editors/space_view3d/drawstrands.c b/source/blender/editors/space_view3d/drawstrands.c
new file mode 100644
index 00000000000..af2e04ee3a7
--- /dev/null
+++ b/source/blender/editors/space_view3d/drawstrands.c
@@ -0,0 +1,520 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 by the Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/drawstrands.c
+ * \ingroup spview3d
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_editstrands.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_strands.h"
+
+#include "bmesh.h"
+
+#include "ED_screen.h"
+#include "ED_types.h"
+
+#include "UI_resources.h"
+#include "UI_interface_icons.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "GPU_draw.h"
+#include "GPU_extensions.h"
+#include "GPU_select.h"
+
+#include "view3d_intern.h"
+
+typedef struct StrandsDrawGLState {
+ GLint polygonmode[2];
+} StrandsDrawGLState;
+
+typedef enum StrandsShadeMode {
+ STRANDS_SHADE_FLAT,
+ STRANDS_SHADE_HAIR,
+} StrandsShadeMode;
+
+static void draw_strands_begin(StrandsDrawGLState *state, short dflag)
+{
+ glGetIntegerv(GL_POLYGON_MODE, state->polygonmode);
+ glEnableClientState(GL_VERTEX_ARRAY);
+
+ /* setup gl flags */
+ glEnableClientState(GL_NORMAL_ARRAY);
+
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+// if (part->draw_col == PART_DRAW_COL_MAT)
+// glEnableClientState(GL_COLOR_ARRAY);
+ }
+
+ glColor3f(1,1,1);
+ glEnable(GL_LIGHTING);
+// glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+// glEnable(GL_COLOR_MATERIAL);
+}
+
+static void draw_strands_end(StrandsDrawGLState *state)
+{
+ /* restore & clean up */
+// if (part->draw_col == PART_DRAW_COL_MAT)
+// glDisableClientState(GL_COLOR_ARRAY);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+
+ glLineWidth(1.0f);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+
+ glPolygonMode(GL_FRONT, state->polygonmode[0]);
+ glPolygonMode(GL_BACK, state->polygonmode[1]);
+}
+
+static void draw_strand_lines(Strands *strands, short dflag)
+{
+ const bool has_motion_state = strands->state;
+ StrandsDrawGLState gl_state;
+ StrandIterator it_strand;
+
+ draw_strands_begin(&gl_state, dflag);
+
+ for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+ if (it_strand.tot <= 0)
+ continue;
+
+ if (has_motion_state) {
+ glVertexPointer(3, GL_FLOAT, sizeof(StrandsMotionState), it_strand.state->co);
+ glNormalPointer(GL_FLOAT, sizeof(StrandsMotionState), it_strand.state->nor);
+ }
+ else {
+ glVertexPointer(3, GL_FLOAT, sizeof(StrandsVertex), it_strand.verts->co);
+ glNormalPointer(GL_FLOAT, sizeof(StrandsVertex), it_strand.verts->nor);
+ }
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+// if (part->draw_col == PART_DRAW_COL_MAT) {
+// glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
+// }
+ }
+
+ glDrawArrays(GL_LINE_STRIP, 0, it_strand.curve->numverts);
+ }
+
+ draw_strands_end(&gl_state);
+}
+
+static void draw_strand_child_lines(StrandsChildren *children, short dflag)
+{
+ StrandsDrawGLState gl_state;
+ StrandChildIterator it_strand;
+
+ draw_strands_begin(&gl_state, dflag);
+
+ for (BKE_strand_child_iter_init(&it_strand, children); BKE_strand_child_iter_valid(&it_strand); BKE_strand_child_iter_next(&it_strand)) {
+ StrandsChildCurve *curve = it_strand.curve;
+ const int numverts = curve->cutoff < 0.0f ? curve->numverts : min_ii(curve->numverts, (int)ceilf(curve->cutoff) + 1);
+
+ if (it_strand.tot <= 0)
+ continue;
+
+ glVertexPointer(3, GL_FLOAT, sizeof(StrandsChildVertex), it_strand.verts->co);
+ glNormalPointer(GL_FLOAT, sizeof(StrandsChildVertex), it_strand.verts->nor);
+
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+// if (part->draw_col == PART_DRAW_COL_MAT) {
+// glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
+// }
+ }
+
+
+ glDrawArrays(GL_LINE_STRIP, 0, numverts);
+ }
+
+ draw_strands_end(&gl_state);
+}
+
+void draw_strands(Scene *UNUSED(scene), View3D *UNUSED(v3d), ARegion *ar, Object *ob, Strands *strands, StrandsChildren *children, short dflag)
+{
+ RegionView3D *rv3d = ar->regiondata;
+ float imat[4][4];
+
+ invert_m4_m4(imat, rv3d->viewmatob);
+
+// glDepthMask(GL_FALSE);
+// glEnable(GL_BLEND);
+
+ glPushMatrix();
+
+ glLoadMatrixf(rv3d->viewmat);
+ glMultMatrixf(ob->obmat);
+
+ if (children)
+ draw_strand_child_lines(children, dflag);
+ else
+ draw_strand_lines(strands, dflag);
+
+ glPopMatrix();
+
+// glDepthMask(GL_TRUE);
+// glDisable(GL_BLEND);
+}
+
+/* ------------------------------------------------------------------------- */
+
+typedef struct StrandsDrawInfo {
+ bool has_zbuf;
+ bool use_zbuf_select;
+
+ StrandsShadeMode shade_mode;
+ int select_mode;
+
+ float col_base[4];
+ float col_select[4];
+} StrandsDrawInfo;
+
+BLI_INLINE bool strands_use_normals(const StrandsDrawInfo *info)
+{
+ return ELEM(info->shade_mode, STRANDS_SHADE_HAIR);
+}
+
+static void init_draw_info(StrandsDrawInfo *info, View3D *v3d,
+ StrandsShadeMode shade_mode, int select_mode)
+{
+ info->has_zbuf = v3d->zbuf;
+ info->use_zbuf_select = (v3d->flag & V3D_ZBUF_SELECT);
+
+ info->shade_mode = shade_mode;
+ info->select_mode = select_mode;
+
+ /* get selection theme colors */
+ UI_GetThemeColor4fv(TH_VERTEX, info->col_base);
+ UI_GetThemeColor4fv(TH_VERTEX_SELECT, info->col_select);
+}
+
+static void set_opengl_state_strands(const StrandsDrawInfo *info)
+{
+ if (!info->use_zbuf_select)
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+
+ if (ELEM(info->shade_mode, STRANDS_SHADE_HAIR)) {
+ glEnable(GL_LIGHTING);
+ glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+ glEnable(GL_COLOR_MATERIAL);
+ glShadeModel(GL_SMOOTH);
+ }
+ else {
+ glDisable(GL_LIGHTING);
+ }
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ if (strands_use_normals(info))
+ glEnableClientState(GL_NORMAL_ARRAY);
+}
+
+static void set_opengl_state_dots(const StrandsDrawInfo *info)
+{
+ if (!info->use_zbuf_select)
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+
+ glDisable(GL_LIGHTING);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glPointSize(3.0);
+}
+
+static void restore_opengl_state(const StrandsDrawInfo *info)
+{
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ glShadeModel(GL_FLAT);
+ if (info->has_zbuf)
+ glEnable(GL_DEPTH_TEST);
+ glLineWidth(1.0f);
+ glPointSize(1.0);
+}
+
+/* ------------------------------------------------------------------------- */
+/* strands */
+
+static void setup_gpu_buffers_strands(BMEditStrands *edit, const StrandsDrawInfo *info)
+{
+ const size_t size_v3 = sizeof(float) * 3;
+ const size_t size_vertex = (strands_use_normals(info) ? 2*size_v3 : size_v3);
+
+// int totstrands = BM_strands_count(edit->bm);
+ int totvert = edit->bm->totvert;
+ int totedge = edit->bm->totedge;
+
+ if (!edit->vertex_glbuf)
+ glGenBuffers(1, &edit->vertex_glbuf);
+ if (!edit->elem_glbuf)
+ glGenBuffers(1, &edit->elem_glbuf);
+
+ glBindBuffer(GL_ARRAY_BUFFER, edit->vertex_glbuf);
+ glBufferData(GL_ARRAY_BUFFER, size_vertex * totvert, NULL, GL_DYNAMIC_DRAW);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, edit->elem_glbuf);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * totedge * 2, NULL, GL_DYNAMIC_DRAW);
+
+ glVertexPointer(3, GL_FLOAT, size_vertex, NULL);
+ if (strands_use_normals(info))
+ glNormalPointer(GL_FLOAT, size_vertex, (GLubyte *)NULL + size_v3);
+}
+
+static void unbind_gpu_buffers_strands(void)
+{
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+}
+
+static int write_gpu_buffers_strands(BMEditStrands *edit, const StrandsDrawInfo *info)
+{
+ const size_t size_v3 = sizeof(float) * 3;
+ const size_t size_vertex = (strands_use_normals(info) ? 2*size_v3 : size_v3);
+
+ GLubyte *vertex_data;
+ unsigned int *elem_data;
+ BMVert *root, *v, *vprev;
+ BMIter iter, iter_strand;
+ int index, indexprev, index_edge;
+ int k;
+
+ vertex_data = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+ elem_data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+ if (!vertex_data || !elem_data)
+ return 0;
+
+ BM_mesh_elem_index_ensure(edit->bm, BM_VERT);
+
+ index_edge = 0;
+ BM_ITER_STRANDS(root, &iter, edit->bm, BM_STRANDS_OF_MESH) {
+ BM_ITER_STRANDS_ELEM_INDEX(v, &iter_strand, root, BM_VERTS_OF_STRAND, k) {
+ size_t offset_co;
+
+ index = BM_elem_index_get(v);
+
+ offset_co = index * size_vertex;
+ copy_v3_v3((float *)(vertex_data + offset_co), v->co);
+
+ if (k > 0) {
+ if (strands_use_normals(info)) {
+ size_t offset_nor = offset_co + size_v3;
+ float nor[3];
+ sub_v3_v3v3(nor, v->co, vprev->co);
+ normalize_v3(nor);
+ copy_v3_v3((float *)(vertex_data + offset_nor), nor);
+
+ if (k == 1) {
+ /* define root normal: same as first segment */
+ size_t offset_root_nor = indexprev * size_vertex + size_v3;
+ copy_v3_v3((float *)(vertex_data + offset_root_nor), nor);
+ }
+ }
+
+ {
+ elem_data[index_edge + 0] = indexprev;
+ elem_data[index_edge + 1] = index;
+ index_edge += 2;
+ }
+ }
+
+ vprev = v;
+ indexprev = index;
+ }
+ }
+
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+ return index_edge;
+}
+
+/* ------------------------------------------------------------------------- */
+/* dots */
+
+static void setup_gpu_buffers_dots(BMEditStrands *edit, const StrandsDrawInfo *info, bool selected)
+{
+ const size_t size_v3 = sizeof(float) * 3;
+ const size_t size_vertex = size_v3;
+ BMesh *bm = edit->bm;
+
+ BMVert *v;
+ BMIter iter;
+ int totvert;
+
+ switch (info->select_mode) {
+ case HAIR_SELECT_STRAND:
+ totvert = 0;
+ break;
+ case HAIR_SELECT_VERTEX:
+ totvert = selected ? bm->totvertsel : bm->totvert - bm->totvertsel;
+ break;
+ case HAIR_SELECT_TIP:
+ totvert = 0;
+ BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test_bool(v, BM_ELEM_SELECT) != selected)
+ continue;
+ if (!BM_strands_vert_is_tip(v))
+ continue;
+
+ ++totvert;
+ }
+ break;
+ }
+
+ if (totvert == 0)
+ return;
+
+ if (!edit->dot_glbuf)
+ glGenBuffers(1, &edit->dot_glbuf);
+
+ glBindBuffer(GL_ARRAY_BUFFER, edit->dot_glbuf);
+ glBufferData(GL_ARRAY_BUFFER, size_vertex * totvert, NULL, GL_DYNAMIC_DRAW);
+
+ glVertexPointer(3, GL_FLOAT, size_vertex, NULL);
+}
+
+static void unbind_gpu_buffers_dots(void)
+{
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+static int write_gpu_buffers_dots(BMEditStrands *edit, const StrandsDrawInfo *info, bool selected)
+{
+ const size_t size_v3 = sizeof(float) * 3;
+ const size_t size_vertex = size_v3;
+
+ GLubyte *vertex_data;
+ BMVert *v;
+ BMIter iter;
+ int index_dot;
+
+ if (info->select_mode == HAIR_SELECT_STRAND)
+ return 0;
+
+ vertex_data = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+ if (!vertex_data)
+ return 0;
+
+ BM_mesh_elem_index_ensure(edit->bm, BM_VERT);
+
+ index_dot = 0;
+ switch (info->select_mode) {
+ case HAIR_SELECT_STRAND:
+ /* already exited, but keep the case for the compiler */
+ break;
+ case HAIR_SELECT_VERTEX:
+ BM_ITER_MESH(v, &iter, edit->bm, BM_VERTS_OF_MESH) {
+ size_t offset_co;
+
+ if (BM_elem_flag_test_bool(v, BM_ELEM_SELECT) != selected)
+ continue;
+
+ offset_co = index_dot * size_vertex;
+ copy_v3_v3((float *)(vertex_data + offset_co), v->co);
+ ++index_dot;
+ }
+ break;
+ case HAIR_SELECT_TIP:
+ BM_ITER_MESH(v, &iter, edit->bm, BM_VERTS_OF_MESH) {
+ size_t offset_co;
+
+ if (BM_elem_flag_test_bool(v, BM_ELEM_SELECT) != selected)
+ continue;
+ if (!BM_strands_vert_is_tip(v))
+ continue;
+
+ offset_co = index_dot * size_vertex;
+ copy_v3_v3((float *)(vertex_data + offset_co), v->co);
+ ++index_dot;
+ }
+ break;
+ }
+
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+
+ return index_dot;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void draw_dots(BMEditStrands *edit, const StrandsDrawInfo *info, bool selected)
+{
+ int totelem;
+
+ if (selected)
+ glColor3fv(info->col_select);
+ else
+ glColor3fv(info->col_base);
+
+ setup_gpu_buffers_dots(edit, info, selected);
+ totelem = write_gpu_buffers_dots(edit, info, selected);
+ if (totelem > 0)
+ glDrawArrays(GL_POINTS, 0, totelem);
+}
+
+void draw_strands_edit_hair(Scene *scene, View3D *v3d, ARegion *UNUSED(ar), BMEditStrands *edit)
+{
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+
+ StrandsDrawInfo info;
+ int totelem;
+
+ init_draw_info(&info, v3d, STRANDS_SHADE_HAIR, settings->select_mode);
+
+ set_opengl_state_strands(&info);
+ setup_gpu_buffers_strands(edit, &info);
+ totelem = write_gpu_buffers_strands(edit, &info);
+ if (totelem > 0)
+ glDrawElements(GL_LINES, totelem, GL_UNSIGNED_INT, NULL);
+ unbind_gpu_buffers_strands();
+
+ set_opengl_state_dots(&info);
+ draw_dots(edit, &info, false);
+ draw_dots(edit, &info, true);
+ unbind_gpu_buffers_dots();
+
+ restore_opengl_state(&info);
+}
diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index a220e1e39b0..2ee1241a2a4 100644
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ b/source/blender/editors/space_view3d/drawvolume.c
@@ -48,8 +48,6 @@
#include "GPU_extensions.h"
-#include "ED_mesh.h"
-
#include "view3d_intern.h" // own include
struct GPUTexture;
@@ -107,7 +105,8 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
float cor[3] = {1.0f, 1.0f, 1.0f};
int gl_depth = 0, gl_blend = 0;
- int use_fire = (sds->active_fields & SM_ACTIVE_FIRE);
+ const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) != 0;
+ const float thickness = sds->display_thickness;
/* draw slices of smoke is adapted from c++ code authored
* by: Johannes Schmid and Ingemar Rask, 2006, johnny@grob.org */
@@ -137,76 +136,8 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
unsigned char *spec_data;
float *spec_pixels;
GPUTexture *tex_spec;
-
- /* Fragment program to calculate the view3d of smoke */
- /* using 4 textures, density, shadow, flame and flame spectrum */
- const char *shader_basic =
- "!!ARBfp1.0\n"
- "PARAM dx = program.local[0];\n"
- "PARAM darkness = program.local[1];\n"
- "PARAM render = program.local[2];\n"
- "PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};\n"
- "TEMP temp, shadow, flame, spec, value;\n"
- "TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
- "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
- "TEX flame, fragment.texcoord[0], texture[2], 3D;\n"
- "TEX spec, flame.r, texture[3], 1D;\n"
- /* calculate shading factor from density */
- "MUL value.r, temp.a, darkness.a;\n"
- "MUL value.r, value.r, dx.r;\n"
- "MUL value.r, value.r, f.r;\n"
- "EX2 temp, -value.r;\n"
- /* alpha */
- "SUB temp.a, 1.0, temp.r;\n"
- /* shade colors */
- "MUL temp.r, temp.r, shadow.r;\n"
- "MUL temp.g, temp.g, shadow.r;\n"
- "MUL temp.b, temp.b, shadow.r;\n"
- "MUL temp.r, temp.r, darkness.r;\n"
- "MUL temp.g, temp.g, darkness.g;\n"
- "MUL temp.b, temp.b, darkness.b;\n"
- /* for now this just replace smoke shading if rendering fire */
- "CMP result.color, render.r, temp, spec;\n"
- "END\n";
-
- /* color shader */
- const char *shader_color =
- "!!ARBfp1.0\n"
- "PARAM dx = program.local[0];\n"
- "PARAM darkness = program.local[1];\n"
- "PARAM render = program.local[2];\n"
- "PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041};\n"
- "TEMP temp, shadow, flame, spec, value;\n"
- "TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
- "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
- "TEX flame, fragment.texcoord[0], texture[2], 3D;\n"
- "TEX spec, flame.r, texture[3], 1D;\n"
- /* unpremultiply volume texture */
- "RCP value.r, temp.a;\n"
- "MUL temp.r, temp.r, value.r;\n"
- "MUL temp.g, temp.g, value.r;\n"
- "MUL temp.b, temp.b, value.r;\n"
- /* calculate shading factor from density */
- "MUL value.r, temp.a, darkness.a;\n"
- "MUL value.r, value.r, dx.r;\n"
- "MUL value.r, value.r, f.r;\n"
- "EX2 value.r, -value.r;\n"
- /* alpha */
- "SUB temp.a, 1.0, value.r;\n"
- /* shade colors */
- "MUL temp.r, temp.r, shadow.r;\n"
- "MUL temp.g, temp.g, shadow.r;\n"
- "MUL temp.b, temp.b, shadow.r;\n"
- "MUL temp.r, temp.r, value.r;\n"
- "MUL temp.g, temp.g, value.r;\n"
- "MUL temp.b, temp.b, value.r;\n"
- /* for now this just replace smoke shading if rendering fire */
- "CMP result.color, render.r, temp, spec;\n"
- "END\n";
-
- GLuint prog;
-
-
+ GPUProgram *smoke_program;
+ int progtype = (sds->active_fields & SM_ACTIVE_COLORS) ? GPU_PROGRAM_SMOKE_COLORED : GPU_PROGRAM_SMOKE;
float size[3];
if (!tex) {
@@ -323,8 +254,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);
- glDepthMask(GL_FALSE);
- glDisable(GL_DEPTH_TEST);
+ glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
/* find cube vertex that is closest to the viewer */
@@ -351,24 +281,17 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
// printf("i: %d\n", i);
// printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]);
- if (GL_TRUE == glewIsSupported("GL_ARB_fragment_program")) {
- glEnable(GL_FRAGMENT_PROGRAM_ARB);
- glGenProgramsARB(1, &prog);
-
- glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog);
- /* set shader */
- if (sds->active_fields & SM_ACTIVE_COLORS)
- glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_color), shader_color);
- else
- glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_basic), shader_basic);
+ smoke_program = GPU_shader_get_builtin_program(progtype);
+ if (smoke_program) {
+ GPU_program_bind(smoke_program);
/* cell spacing */
- glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, dx, dx, dx, 1.0);
+ GPU_program_parameter_4f(smoke_program, 0, dx, dx, dx, 1.0);
/* custom parameter for smoke style (higher = thicker) */
if (sds->active_fields & SM_ACTIVE_COLORS)
- glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 1.0, 1.0, 1.0, 10.0);
+ GPU_program_parameter_4f(smoke_program, 1, 1.0, 1.0, 1.0, 10.0 * thickness);
else
- glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0);
+ GPU_program_parameter_4f(smoke_program, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0 * thickness);
}
else
printf("Your gfx card does not support 3D View smoke drawing.\n");
@@ -448,7 +371,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
else
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, 1.0, 0.0, 0.0, 0.0);
+ GPU_program_parameter_4f(smoke_program, 2, 1.0, 0.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glColor3f(1.0, 1.0, 1.0);
for (i = 0; i < numpoints; i++) {
@@ -468,7 +391,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
else
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, -1.0, 0.0, 0.0, 0.0);
+ GPU_program_parameter_4f(smoke_program, 2, -1.0, 0.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glColor3f(1.0, 1.0, 1.0);
for (i = 0; i < numpoints; i++) {
@@ -501,10 +424,8 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
free(spec_data);
free(spec_pixels);
- if (GLEW_ARB_fragment_program) {
- glDisable(GL_FRAGMENT_PROGRAM_ARB);
- glDeleteProgramsARB(1, &prog);
- }
+ if (smoke_program)
+ GPU_program_unbind(smoke_program);
MEM_freeN(points);
@@ -516,8 +437,6 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
if (gl_depth) {
glEnable(GL_DEPTH_TEST);
}
-
- glDepthMask(GL_TRUE);
}
#ifdef SMOKE_DEBUG_VELOCITY
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 447ceee5b13..e4f3e1d75ea 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -84,6 +84,8 @@
# include "BPY_extern.h"
#endif
+#include "DEG_depsgraph.h"
+
#include "view3d_intern.h" /* own include */
/* ******************** manage regions ********************* */
@@ -276,7 +278,7 @@ void ED_view3d_check_mats_rv3d(struct RegionView3D *rv3d)
}
#endif
-static void view3d_stop_render_preview(wmWindowManager *wm, ARegion *ar)
+void ED_view3d_stop_render_preview(wmWindowManager *wm, ARegion *ar)
{
RegionView3D *rv3d = ar->regiondata;
@@ -307,7 +309,7 @@ void ED_view3d_shade_update(Main *bmain, Scene *scene, View3D *v3d, ScrArea *sa)
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->regiondata)
- view3d_stop_render_preview(wm, ar);
+ ED_view3d_stop_render_preview(wm, ar);
}
}
else if (scene->obedit != NULL && scene->obedit->type == OB_MESH) {
@@ -354,7 +356,13 @@ static SpaceLink *view3d_new(const bContext *C)
v3d->bundle_size = 0.2f;
v3d->bundle_drawtype = OB_PLAINAXES;
-
+
+ /* stereo */
+ v3d->stereo3d_camera = STEREO_3D_ID;
+ v3d->stereo3d_flag |= V3D_S3D_DISPPLANE;
+ v3d->stereo3d_convergence_alpha = 0.15f;
+ v3d->stereo3d_volume_alpha = 0.05f;
+
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for view3d");
@@ -552,6 +560,9 @@ static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar)
keymap = WM_keymap_find(wm->defaultconf, "Particle", 0, 0);
WM_event_add_keymap_handler(&ar->handlers, keymap);
+ keymap = WM_keymap_find(wm->defaultconf, "Hair", 0, 0);
+ WM_event_add_keymap_handler(&ar->handlers, keymap);
+
/* editfont keymap swallows all... */
keymap = WM_keymap_find(wm->defaultconf, "Font", 0, 0);
WM_event_add_keymap_handler(&ar->handlers, keymap);
@@ -579,7 +590,7 @@ static void view3d_main_area_exit(wmWindowManager *wm, ARegion *ar)
{
RegionView3D *rv3d = ar->regiondata;
- view3d_stop_render_preview(wm, ar);
+ ED_view3d_stop_render_preview(wm, ar);
if (rv3d->gpuoffscreen) {
GPU_offscreen_free(rv3d->gpuoffscreen);
@@ -1097,7 +1108,8 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
(ob && (ob->mode == OB_MODE_TEXTURE_PAINT)) ||
(v3d->drawtype == OB_TEXTURE &&
(scene->gm.matmode == GAME_MAT_GLSL ||
- BKE_scene_use_new_shading_nodes(scene))))
+ BKE_scene_use_new_shading_nodes(scene))) ||
+ !DEG_depsgraph_use_legacy())
{
ED_region_tag_redraw(ar);
}
@@ -1120,7 +1132,8 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
switch (wmn->data) {
case ND_LIGHTING:
if ((v3d->drawtype == OB_MATERIAL) ||
- (v3d->drawtype == OB_TEXTURE && (scene->gm.matmode == GAME_MAT_GLSL)))
+ (v3d->drawtype == OB_TEXTURE && (scene->gm.matmode == GAME_MAT_GLSL)) ||
+ !DEG_depsgraph_use_legacy())
{
ED_region_tag_redraw(ar);
}
@@ -1177,7 +1190,7 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
break;
case NC_GPENCIL:
- if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
+ if (wmn->data == ND_DATA || ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
ED_region_tag_redraw(ar);
}
break;
@@ -1324,7 +1337,8 @@ static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
ED_region_tag_redraw(ar);
break;
case NC_BRUSH:
- if (wmn->action == NA_EDITED)
+ /* NA_SELECTED is used on brush changes */
+ if (ELEM(wmn->action, NA_EDITED, NA_SELECTED))
ED_region_tag_redraw(ar);
break;
case NC_SPACE:
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index 88f43ab340f..1f8a69adba0 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -68,7 +68,6 @@
#include "RNA_access.h"
#include "ED_armature.h"
-#include "ED_gpencil.h"
#include "ED_mesh.h"
#include "ED_screen.h"
@@ -200,7 +199,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
bool has_skinradius = false;
PointerRNA data_ptr;
- fill_vn_fl(median, NBR_TRANSFORM_PROPERTIES, 0.0f);
+ copy_vn_fl(median, NBR_TRANSFORM_PROPERTIES, 0.0f);
tot = totedgedata = totcurvedata = totlattdata = totcurvebweight = 0;
/* make sure we got storage */
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index db29b08c5a9..5ccb16e514c 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -50,11 +50,13 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_endian_switch.h"
+#include "BLI_threads.h"
#include "BKE_anim.h"
#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_main.h"
@@ -99,6 +101,11 @@
#include "view3d_intern.h" /* own include */
+/* prototypes */
+static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar);
+static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
+ float winmat[4][4], const char *viewname);
+
/* handy utility for drawing shapes in the viewport for arbitrary code.
* could add lines and points too */
// #define DEBUG_DRAW
@@ -207,7 +214,7 @@ void ED_view3d_clipping_enable(void)
}
}
-static bool view3d_clipping_test(const float co[3], float clip[6][4])
+static bool view3d_clipping_test(const float co[3], const float clip[6][4])
{
if (plane_point_side_v3(clip[0], co) > 0.0f)
if (plane_point_side_v3(clip[1], co) > 0.0f)
@@ -220,7 +227,7 @@ static bool view3d_clipping_test(const float co[3], float clip[6][4])
/* for 'local' ED_view3d_clipping_local must run first
* then all comparisons can be done in localspace */
-bool ED_view3d_clipping_test(RegionView3D *rv3d, const float co[3], const bool is_local)
+bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local)
{
return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip);
}
@@ -465,7 +472,7 @@ float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit)
return v3d->grid * ED_scene_grid_scale(scene, grid_unit);
}
-static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit)
+static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth)
{
float grid, grid_scale;
unsigned char col_grid[3];
@@ -477,7 +484,8 @@ static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit)
grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit);
grid = gridlines * grid_scale;
- glDepthMask(GL_FALSE);
+ if (!write_depth)
+ glDepthMask(GL_FALSE);
UI_GetThemeColor3ubv(TH_GRID, col_grid);
@@ -650,7 +658,7 @@ static void draw_rotation_guide(RegionView3D *rv3d)
glEnable(GL_POINT_SMOOTH);
glDepthMask(0); /* don't overwrite zbuf */
- if (rv3d->rot_angle != 0.f) {
+ if (rv3d->rot_angle != 0.0f) {
/* -- draw rotation axis -- */
float scaled_axis[3];
const float scale = rv3d->dist;
@@ -658,19 +666,21 @@ static void draw_rotation_guide(RegionView3D *rv3d)
glBegin(GL_LINE_STRIP);
- color[3] = 0.f; /* more transparent toward the ends */
+ color[3] = 0.0f; /* more transparent toward the ends */
glColor4fv(color);
add_v3_v3v3(end, o, scaled_axis);
glVertex3fv(end);
- // color[3] = 0.2f + fabsf(rv3d->rot_angle); /* modulate opacity with angle */
- // ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2
+#if 0
+ color[3] = 0.2f + fabsf(rv3d->rot_angle); /* modulate opacity with angle */
+ /* ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2 */
+#endif
color[3] = 0.5f; /* more opaque toward the center */
glColor4fv(color);
glVertex3fv(o);
- color[3] = 0.f;
+ color[3] = 0.0f;
glColor4fv(color);
sub_v3_v3v3(end, o, scaled_axis);
glVertex3fv(end);
@@ -681,14 +691,14 @@ static void draw_rotation_guide(RegionView3D *rv3d)
#define ROT_AXIS_DETAIL 13
const float s = 0.05f * scale;
- const float step = 2.f * (float)(M_PI / ROT_AXIS_DETAIL);
+ const float step = 2.0f * (float)(M_PI / ROT_AXIS_DETAIL);
float angle;
int i;
float q[4]; /* rotate ring so it's perpendicular to axis */
const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f;
if (!upright) {
- const float up[3] = {0.f, 0.f, 1.f};
+ const float up[3] = {0.0f, 0.0f, 1.0f};
float vis_angle, vis_axis[3];
cross_v3_v3v3(vis_axis, up, rv3d->rot_axis);
@@ -699,7 +709,7 @@ static void draw_rotation_guide(RegionView3D *rv3d)
color[3] = 0.25f; /* somewhat faint */
glColor4fv(color);
glBegin(GL_LINE_LOOP);
- for (i = 0, angle = 0.f; i < ROT_AXIS_DETAIL; ++i, angle += step) {
+ for (i = 0, angle = 0.0f; i < ROT_AXIS_DETAIL; ++i, angle += step) {
float p[3] = {s * cosf(angle), s * sinf(angle), 0.0f};
if (!upright) {
@@ -725,12 +735,12 @@ static void draw_rotation_guide(RegionView3D *rv3d)
glVertex3fv(o);
glEnd();
- /* find screen coordinates for rotation center, then draw pretty icon */
#if 0
+ /* find screen coordinates for rotation center, then draw pretty icon */
mul_m4_v3(rv3d->persinv, rot_center);
UI_icon_draw(rot_center[0], rot_center[1], ICON_NDOF_TURN);
-#endif
/* ^^ just playing around, does not work */
+#endif
glDisable(GL_BLEND);
glDisable(GL_POINT_SMOOTH);
@@ -949,8 +959,9 @@ static void draw_selected_name(Scene *scene, Object *ob, rcti *rect)
BLF_draw_default(offset, 0.5f * U.widget_unit, 0.0f, info, sizeof(info));
}
-static void view3d_camera_border(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d,
- rctf *r_viewborder, const bool no_shift, const bool no_zoom)
+static void view3d_camera_border(
+ const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
+ rctf *r_viewborder, const bool no_shift, const bool no_zoom)
{
CameraParams params;
rctf rect_view, rect_camera;
@@ -983,7 +994,9 @@ static void view3d_camera_border(Scene *scene, ARegion *ar, View3D *v3d, RegionV
r_viewborder->ymax = ((rect_camera.ymax - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) * ar->winy;
}
-void ED_view3d_calc_camera_border_size(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, float r_size[2])
+void ED_view3d_calc_camera_border_size(
+ const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
+ float r_size[2])
{
rctf viewborder;
@@ -992,8 +1005,9 @@ void ED_view3d_calc_camera_border_size(Scene *scene, ARegion *ar, View3D *v3d, R
r_size[1] = BLI_rctf_size_y(&viewborder);
}
-void ED_view3d_calc_camera_border(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d,
- rctf *r_viewborder, const bool no_shift)
+void ED_view3d_calc_camera_border(
+ const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
+ rctf *r_viewborder, const bool no_shift)
{
view3d_camera_border(scene, ar, v3d, rv3d, r_viewborder, no_shift, false);
}
@@ -1314,12 +1328,12 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
/* do nothing */
}
else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) &&
- v3d->drawtype > OB_WIRE && (v3d->flag & V3D_ZBUF_SELECT))
+ V3D_IS_ZBUF(v3d))
{
/* do nothing */
}
- else if (scene->obedit && v3d->drawtype > OB_WIRE &&
- (v3d->flag & V3D_ZBUF_SELECT))
+ else if (scene->obedit &&
+ V3D_IS_ZBUF(v3d))
{
/* do nothing */
}
@@ -1441,14 +1455,23 @@ static void view3d_opengl_read_Z_pixels(ARegion *ar, int x, int y, int w, int h,
glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data);
}
-void view3d_validate_backbuf(ViewContext *vc)
+void ED_view3d_backbuf_validate(ViewContext *vc)
{
if (vc->v3d->flag & V3D_INVALID_BACKBUF)
backdrawview3d(vc->scene, vc->ar, vc->v3d);
}
+/**
+ * allow for small values [0.5 - 2.5],
+ * and large values, FLT_MAX by clamping by the area size
+ */
+int ED_view3d_backbuf_sample_size_clamp(ARegion *ar, const float dist)
+{
+ return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx));
+}
+
/* samples a single pixel (copied from vpaint) */
-unsigned int view3d_sample_backbuf(ViewContext *vc, int x, int y)
+unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y)
{
unsigned int col;
@@ -1456,7 +1479,7 @@ unsigned int view3d_sample_backbuf(ViewContext *vc, int x, int y)
return 0;
}
- view3d_validate_backbuf(vc);
+ ED_view3d_backbuf_validate(vc);
view3d_opengl_read_pixels(vc->ar, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
glReadBuffer(GL_BACK);
@@ -1469,7 +1492,7 @@ unsigned int view3d_sample_backbuf(ViewContext *vc, int x, int y)
}
/* reads full rect, converts indices */
-ImBuf *view3d_read_backbuf(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
+ImBuf *ED_view3d_backbuf_read(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
{
unsigned int *dr, *rd;
struct ImBuf *ibuf, *ibuf1;
@@ -1477,17 +1500,18 @@ ImBuf *view3d_read_backbuf(ViewContext *vc, short xmin, short ymin, short xmax,
short xminc, yminc, xmaxc, ymaxc, xs, ys;
/* clip */
- if (xmin < 0) xminc = 0; else xminc = xmin;
- if (xmax >= vc->ar->winx) xmaxc = vc->ar->winx - 1; else xmaxc = xmax;
- if (xminc > xmaxc) return NULL;
+ xminc = max_ii(xmin, 0);
+ yminc = max_ii(ymin, 0);
+ xmaxc = min_ii(xmax, vc->ar->winx - 1);
+ ymaxc = min_ii(ymax, vc->ar->winy - 1);
+
+ if (UNLIKELY((xminc > xmaxc) || (yminc > ymaxc))) {
+ return NULL;
+ }
- if (ymin < 0) yminc = 0; else yminc = ymin;
- if (ymax >= vc->ar->winy) ymaxc = vc->ar->winy - 1; else ymaxc = ymax;
- if (yminc > ymaxc) return NULL;
-
ibuf = IMB_allocImBuf((xmaxc - xminc + 1), (ymaxc - yminc + 1), 32, IB_rect);
- view3d_validate_backbuf(vc);
+ ED_view3d_backbuf_validate(vc);
view3d_opengl_read_pixels(vc->ar,
xminc, yminc,
@@ -1527,23 +1551,21 @@ ImBuf *view3d_read_backbuf(ViewContext *vc, short xmin, short ymin, short xmax,
}
/* smart function to sample a rect spiralling outside, nice for backbuf selection */
-unsigned int view3d_sample_backbuf_rect(ViewContext *vc, const int mval[2], int size,
- unsigned int min, unsigned int max, float *r_dist, short strict,
- void *handle, bool (*indextest)(void *handle, unsigned int index))
+unsigned int ED_view3d_backbuf_sample_rect(
+ ViewContext *vc, const int mval[2], int size,
+ unsigned int min, unsigned int max, float *r_dist)
{
struct ImBuf *buf;
- unsigned int *bufmin, *bufmax, *tbuf;
+ const unsigned int *bufmin, *bufmax, *tbuf;
int minx, miny;
int a, b, rc, nr, amount, dirvec[4][2];
- int distance = 0;
unsigned int index = 0;
- bool indexok = false;
amount = (size - 1) / 2;
minx = mval[0] - (amount + 1);
miny = mval[1] - (amount + 1);
- buf = view3d_read_backbuf(vc, minx, miny, minx + size - 1, miny + size - 1);
+ buf = ED_view3d_backbuf_read(vc, minx, miny, minx + size - 1, miny + size - 1);
if (!buf) return 0;
rc = 0;
@@ -1561,21 +1583,19 @@ unsigned int view3d_sample_backbuf_rect(ViewContext *vc, const int mval[2], int
for (nr = 1; nr <= size; nr++) {
for (a = 0; a < 2; a++) {
- for (b = 0; b < nr; b++, distance++) {
- if (*tbuf && *tbuf >= min && *tbuf < max) { /* we got a hit */
- if (strict) {
- indexok = indextest(handle, *tbuf - min + 1);
- if (indexok) {
- *r_dist = sqrtf((float)distance);
- index = *tbuf - min + 1;
- goto exit;
- }
- }
- else {
- *r_dist = sqrtf((float)distance); /* XXX, this distance is wrong - */
- index = *tbuf - min + 1; /* messy yah, but indices start at 1 */
- goto exit;
- }
+ for (b = 0; b < nr; b++) {
+ if (*tbuf && *tbuf >= min && *tbuf < max) {
+ /* we got a hit */
+
+ /* get x,y pixel coords from the offset
+ * (manhatten distance in keeping with other screen-based selection) */
+ *r_dist = (float)(
+ abs(((int)(tbuf - buf->rect) % size) - (size / 2)) +
+ abs(((int)(tbuf - buf->rect) / size) - (size / 2)));
+
+ /* indices start at 1 here */
+ index = (*tbuf - min) + 1;
+ goto exit;
}
tbuf += (dirvec[rc][0] + dirvec[rc][1]);
@@ -1597,6 +1617,26 @@ exit:
/* ************************************************************* */
+static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser)
+{
+ if ((ima->flag & IMA_IS_STEREO)) {
+ iuser->flag |= IMA_SHOW_STEREO;
+
+ if ((scene->r.scemode & R_MULTIVIEW) == 0) {
+ iuser->multiview_eye = STEREO_LEFT_ID;
+ }
+ else if (v3d->stereo3d_camera != STEREO_3D_ID) {
+ /* show only left or right camera */
+ iuser->multiview_eye = v3d->stereo3d_camera;
+ }
+
+ BKE_image_multiview_index(ima, iuser);
+ }
+ else {
+ iuser->flag &= ~IMA_SHOW_STEREO;
+ }
+}
+
static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
const bool do_foreground, const bool do_camera_frame)
{
@@ -1620,6 +1660,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
ImBuf *ibuf = NULL, *freeibuf, *releaseibuf;
void *lock;
+ rctf clip_rect;
Image *ima = NULL;
MovieClip *clip = NULL;
@@ -1639,6 +1680,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
ibuf = NULL; /* frame is out of range, dont show */
}
else {
+ view3d_stereo_bgpic_setup(scene, v3d, ima, &bgpic->iuser);
ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, &lock);
releaseibuf = ibuf;
}
@@ -1782,8 +1824,12 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
}
/* complete clip? */
+ BLI_rctf_init(&clip_rect, x1, x2, y1, y2);
+ if (bgpic->rotation) {
+ BLI_rctf_rotate_expand(&clip_rect, &clip_rect, bgpic->rotation);
+ }
- if (x2 < 0 || y2 < 0 || x1 > ar->winx || y1 > ar->winy) {
+ if (clip_rect.xmax < 0 || clip_rect.ymax < 0 || clip_rect.xmin > ar->winx || clip_rect.ymin > ar->winy) {
if (freeibuf)
IMB_freeImBuf(freeibuf);
if (releaseibuf)
@@ -1830,9 +1876,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
ED_region_pixelspace(ar);
glTranslatef(centx, centy, 0.0);
- if (rv3d->persp != RV3D_CAMOB) {
- glRotatef(RAD2DEGF(-bgpic->rotation), 0.0f, 0.0f, 1.0f);
- }
+ glRotatef(RAD2DEGF(-bgpic->rotation), 0.0f, 0.0f, 1.0f);
if (bgpic->flag & V3D_BGPIC_FLIP_X) {
zoomx *= -1.0f;
@@ -2063,6 +2107,27 @@ int dupli_ob_sort(void *arg1, void *arg2)
}
#endif
+static void draw_dupli_object(Scene *scene, ARegion *ar, View3D *v3d,
+ Base *base, DupliObject *UNUSED(dob), DupliObjectData *dob_data,
+ short dflag, bool draw_dupli_strands)
+{
+ draw_object(scene, ar, v3d, base, dflag);
+
+ if (dob_data) {
+
+ /* draw strands only when not editing */
+ if (draw_dupli_strands) {
+ DupliObjectDataStrands *link;
+
+ for (link = dob_data->strands.first; link; link = link->next) {
+ struct Strands *strands = link->strands;
+ struct StrandsChildren *children = link->strands_children;
+
+ draw_strands(scene, v3d, ar, base->object, strands, children, dflag);
+ }
+ }
+ }
+}
static DupliObject *dupli_step(DupliObject *dob)
{
@@ -2084,6 +2149,7 @@ static void draw_dupli_objects_color(
GLuint displist = 0;
unsigned char color_rgb[3];
const short dflag_dupli = dflag | DRAW_CONSTCOLOR;
+ const bool draw_dupli_strands = !(base->object->mode & OB_MODE_HAIR_EDIT);
short transflag;
bool use_displist = false; /* -1 is initialize */
char dt;
@@ -2101,17 +2167,22 @@ static void draw_dupli_objects_color(
UI_GetThemeColorBlend3ubv(color, TH_BACK, 0.5f, color_rgb);
}
- tbase.flag = OB_FROMDUPLI | base->flag;
+ tbase.flag |= OB_FROMDUPLI;
lb = object_duplilist(G.main->eval_ctx, scene, base->object);
// BLI_listbase_sort(lb, dupli_ob_sort); /* might be nice to have if we have a dupli list with mixed objects. */
- apply_data = duplilist_apply(base->object, lb);
+ apply_data = duplilist_apply(base->object, scene, lb);
dob = dupli_step(lb->first);
if (dob) dob_next = dupli_step(dob->next);
for (; dob; dob_prev = dob, dob = dob_next, dob_next = dob_next ? dupli_step(dob_next->next) : NULL) {
+ /* for restoring after override */
+ DupliObjectData *dob_data = NULL;
+ DerivedMesh *store_final_dm;
+
tbase.object = dob->ob;
+ store_final_dm = dob->ob->derivedFinal;
/* Make sure lod is updated from dupli's position */
@@ -2148,6 +2219,21 @@ static void draw_dupli_objects_color(
glColor3ubv(color_rgb);
}
+ /* override final DM */
+ bb_tmp = NULL;
+ tbase.object->transflag &= ~OB_IS_DUPLI_CACHE;
+ if (base->object->dup_cache) {
+ dob_data = BKE_dupli_cache_find_data(base->object->dup_cache, tbase.object);
+ if (dob_data && dob_data->dm) {
+ tbase.object->transflag |= OB_IS_DUPLI_CACHE;
+
+ tbase.object->derivedFinal = dob_data->dm;
+ bb_tmp = &dob_data->bb;
+ }
+ }
+ if (!bb_tmp)
+ bb_tmp = BKE_object_boundbox_get(dob->ob);
+
/* generate displist, test for new object */
if (dob_prev && dob_prev->ob != dob->ob) {
if (use_displist == true)
@@ -2156,7 +2242,7 @@ static void draw_dupli_objects_color(
use_displist = false;
}
- if ((bb_tmp = BKE_object_boundbox_get(dob->ob))) {
+ if (bb_tmp) {
bb = *bb_tmp; /* must make a copy */
testbb = true;
}
@@ -2194,7 +2280,7 @@ static void draw_dupli_objects_color(
displist = glGenLists(1);
glNewList(displist, GL_COMPILE);
- draw_object(scene, ar, v3d, &tbase, dflag_dupli);
+ draw_dupli_object(scene, ar, v3d, &tbase, dob, dob_data, dflag_dupli, draw_dupli_strands);
glEndList();
use_displist = true;
@@ -2210,8 +2296,24 @@ static void draw_dupli_objects_color(
}
else {
copy_m4_m4(dob->ob->obmat, dob->mat);
- draw_object(scene, ar, v3d, &tbase, dflag_dupli);
+ draw_dupli_object(scene, ar, v3d, &tbase, dob, dob_data, dflag_dupli, draw_dupli_strands);
+ }
+ }
+
+ /* restore final DM */
+ if (tbase.object->transflag & OB_IS_DUPLI_CACHE) {
+ DerivedMesh *cur = tbase.object->derivedFinal;
+
+ /* in some cases drawing code can recreate the derivedFinal,
+ * make sure we free those first before restoring
+ */
+ if (cur && cur != dob_data->dm) {
+ cur->needsFree = 1;
+ cur->release(cur);
}
+
+ tbase.object->transflag &= ~OB_IS_DUPLI_CACHE;
+ tbase.object->derivedFinal = store_final_dm;
}
tbase.object->dt = dt;
@@ -2551,13 +2653,14 @@ static void gpu_render_lamp_update(Scene *scene, View3D *v3d, Object *ob, Object
}
}
-static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
+static void gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d)
{
ListBase shadows;
View3DShadow *shadow;
Scene *sce_iter;
Base *base;
Object *ob;
+ World *world = scene->world;
SceneRenderLayer *srl = v3d->scenelock ? BLI_findlink(&scene->r.layers, scene->r.actlay) : NULL;
BLI_listbase_clear(&shadows);
@@ -2613,7 +2716,7 @@ static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
ED_view3d_draw_offscreen(
scene, v3d, &ar, winsize, winsize, viewmat, winmat,
false, false, true,
- NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL);
GPU_lamp_shadow_buffer_unbind(shadow->lamp);
v3d->drawtype = drawtype;
@@ -2622,11 +2725,19 @@ static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
}
BLI_freelistN(&shadows);
+
+ /* update world values */
+ if (world) {
+ GPU_mist_update_enable(world->mode & WO_MIST);
+ GPU_mist_update_values(world->mistype, world->miststa, world->mistdist, world->misi, &world->horr);
+ GPU_horizon_update_color(&world->horr);
+ GPU_ambient_update_color(&world->ambr);
+ }
}
/* *********************** customdata **************** */
-CustomDataMask ED_view3d_datamask(Scene *scene, View3D *v3d)
+CustomDataMask ED_view3d_datamask(const Scene *scene, const View3D *v3d)
{
CustomDataMask mask = 0;
@@ -2652,16 +2763,16 @@ CustomDataMask ED_view3d_datamask(Scene *scene, View3D *v3d)
}
/* goes over all modes and view3d settings */
-CustomDataMask ED_view3d_screen_datamask(bScreen *screen)
+CustomDataMask ED_view3d_screen_datamask(const bScreen *screen)
{
- Scene *scene = screen->scene;
+ const Scene *scene = screen->scene;
CustomDataMask mask = CD_MASK_BAREMESH;
- ScrArea *sa;
+ const ScrArea *sa;
/* check if we need tfaces & mcols due to view mode */
for (sa = screen->areabase.first; sa; sa = sa->next) {
if (sa->spacetype == SPACE_VIEW3D) {
- mask |= ED_view3d_datamask(scene, (View3D *)sa->spacedata.first);
+ mask |= ED_view3d_datamask(scene, sa->spacedata.first);
}
}
@@ -2747,7 +2858,7 @@ static void view3d_draw_objects(
const bool draw_grids = !draw_offscreen && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0;
const bool draw_floor = (rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO);
/* only draw grids after in solid modes, else it hovers over mesh wires */
- const bool draw_grids_after = draw_grids && draw_floor && (v3d->drawtype > OB_WIRE);
+ const bool draw_grids_after = draw_grids && draw_floor && (v3d->drawtype > OB_WIRE) && fx;
bool do_composite_xray = false;
bool xrayclear = true;
@@ -2796,8 +2907,8 @@ static void view3d_draw_objects(
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(rv3d->viewmat);
}
- else {
- drawfloor(scene, v3d, grid_unit);
+ else if (!draw_grids_after) {
+ drawfloor(scene, v3d, grid_unit, true);
}
}
@@ -2879,7 +2990,7 @@ static void view3d_draw_objects(
/* perspective floor goes last to use scene depth and avoid writing to depth buffer */
if (draw_grids_after) {
- drawfloor(scene, v3d, grid_unit);
+ drawfloor(scene, v3d, grid_unit, false);
}
/* must be before xray draw which clears the depth buffer */
@@ -2948,39 +3059,57 @@ void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d)
{
/* shadow buffers, before we setup matrices */
if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype))
- gpu_update_lamps_shadows(scene, v3d);
+ gpu_update_lamps_shadows_world(scene, v3d);
}
/*
* Function to clear the view
*/
-static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar, bool force)
+static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar)
{
const bool is_wire_color = V3D_IS_WIRECOLOR(scene, v3d);
-
- /* clear background */
- if (scene->world && ((v3d->flag3 & V3D_SHOW_WORLD) || force)) {
- float alpha = (force) ? 1.0f : 0.0f;
+
+ if (scene->world && (v3d->flag3 & V3D_SHOW_WORLD)) {
bool glsl = GPU_glsl_support() && BKE_scene_use_new_shading_nodes(scene) && scene->world->nodetree && scene->world->use_nodes;
if (glsl) {
RegionView3D *rv3d = ar->regiondata;
GPUMaterial *gpumat = GPU_material_world(scene, scene->world);
+ bool material_not_bound;
/* calculate full shader for background */
GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0));
+ material_not_bound = !GPU_material_bound(gpumat);
+
+ if (material_not_bound) {
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
+ }
+
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
glShadeModel(GL_SMOOTH);
- glBegin(GL_QUADS);
+ glBegin(GL_TRIANGLE_STRIP);
glVertex3f(-1.0, -1.0, 1.0);
glVertex3f(1.0, -1.0, 1.0);
- glVertex3f(1.0, 1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0);
+ glVertex3f(1.0, 1.0, 1.0);
glEnd();
glShadeModel(GL_FLAT);
+ if (material_not_bound) {
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ }
+
GPU_material_unbind(gpumat);
glDepthFunc(GL_LEQUAL);
@@ -3073,7 +3202,7 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar, bool
interp_v3_v3v3(col_fl, col_hor, col_zen, col_fac);
rgb_float_to_uchar(col_ub, col_fl);
- col_ub[3] = alpha * 255;
+ col_ub[3] = 255;
}
}
@@ -3114,7 +3243,7 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar, bool
IMB_colormanagement_pixel_to_display_space_v3(col_hor, &scene->world->horr, &scene->view_settings,
&scene->display_settings);
- glClearColor(col_hor[0], col_hor[1], col_hor[2], alpha);
+ glClearColor(col_hor[0], col_hor[1], col_hor[2], 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (is_wire_color) {
@@ -3167,7 +3296,7 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar, bool
float col[3];
UI_GetThemeColor3fv(TH_HIGH_GRAD, col);
- UI_ThemeClearColor(TH_HIGH_GRAD);
+ UI_ThemeClearColorAlpha(TH_HIGH_GRAD, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (is_wire_color) {
@@ -3185,7 +3314,8 @@ void ED_view3d_draw_offscreen(
float viewmat[4][4], float winmat[4][4],
bool do_bgpic, bool do_sky, bool is_persp,
GPUOffScreen *ofs,
- GPUFX *fx, GPUFXSettings *fx_settings)
+ GPUFX *fx, GPUFXSettings *fx_settings,
+ const char *viewname)
{
struct bThemeState theme_state;
int bwinx, bwiny;
@@ -3220,16 +3350,29 @@ void ED_view3d_draw_offscreen(
}
/* setup view matrices before fx or unbinding the offscreen buffers will cause issues */
- view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat);
+ if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) && rv3d->persp == RV3D_CAMOB && v3d->camera)
+ view3d_stereo3d_setup_offscreen(scene, v3d, ar, winmat, viewname);
+ else
+ view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat);
/* framebuffer fx needed, we need to draw offscreen first */
if (v3d->fx_settings.fx_flag && fx) {
+ GPUSSAOSettings *ssao = NULL;
+
+ if (v3d->drawtype < OB_SOLID) {
+ ssao = v3d->fx_settings.ssao;
+ v3d->fx_settings.ssao = NULL;
+ }
+
do_compositing = GPU_fx_compositor_initialize_passes(fx, &ar->winrct, NULL, fx_settings);
+
+ if (ssao)
+ v3d->fx_settings.ssao = ssao;
}
/* clear opengl buffers */
if (do_sky) {
- view3d_main_area_clear(scene, v3d, ar, true);
+ view3d_main_area_clear(scene, v3d, ar);
}
else {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -3274,13 +3417,16 @@ void ED_view3d_draw_offscreen(
/* utility func for ED_view3d_draw_offscreen */
ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, int sizex, int sizey, unsigned int flag,
- bool draw_background, int alpha_mode, char err_out[256])
+ bool draw_background, int alpha_mode, const char *viewname, char err_out[256])
{
RegionView3D *rv3d = ar->regiondata;
ImBuf *ibuf;
GPUOffScreen *ofs;
bool draw_sky = (alpha_mode == R_ADDSKY) && v3d && (v3d->flag3 & V3D_SHOW_WORLD);
+ if (UNLIKELY(v3d == NULL))
+ return NULL;
+
/* state changes make normal drawing go weird otherwise */
glPushAttrib(GL_LIGHTING_BIT);
@@ -3298,14 +3444,15 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, in
/* render 3d view */
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
CameraParams params;
- GPUFXSettings fx_settings = {0};
- Object *camera = v3d->camera;
+ GPUFXSettings fx_settings = {NULL};
+ Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
BKE_camera_params_init(&params);
/* fallback for non camera objects */
params.clipsta = v3d->near;
params.clipend = v3d->far;
- BKE_camera_params_from_object(&params, v3d->camera);
+ BKE_camera_params_from_object(&params, camera);
+ BKE_camera_multiview_params(&scene->r, &params, camera, viewname);
BKE_camera_params_compute_viewplane(&params, sizex, sizey, scene->r.xasp, scene->r.yasp);
BKE_camera_params_compute_matrix(&params);
@@ -3314,13 +3461,13 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, in
ED_view3d_draw_offscreen(
scene, v3d, ar, sizex, sizey, NULL, params.winmat,
draw_background, draw_sky, !params.is_ortho,
- ofs, NULL, &fx_settings);
+ ofs, NULL, &fx_settings, viewname);
}
else {
ED_view3d_draw_offscreen(
scene, v3d, ar, sizex, sizey, NULL, NULL,
draw_background, draw_sky, true,
- ofs, NULL, NULL);
+ ofs, NULL, NULL, viewname);
}
/* read in pixels & stamp */
@@ -3345,7 +3492,8 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, in
/* creates own 3d views, used by the sequencer */
ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int width, int height, unsigned int flag, int drawtype,
- bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode, char err_out[256])
+ bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode,
+ const char *viewname, char err_out[256])
{
View3D v3d = {NULL};
ARegion ar = {NULL};
@@ -3375,9 +3523,11 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int w
{
CameraParams params;
+ Object *camera = BKE_camera_multiview_render(scene, v3d.camera, viewname);
BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, v3d.camera);
+ BKE_camera_params_from_object(&params, camera);
+ BKE_camera_multiview_params(&scene->r, &params, camera, viewname);
BKE_camera_params_compute_viewplane(&params, width, height, scene->r.xasp, scene->r.yasp);
BKE_camera_params_compute_matrix(&params);
@@ -3391,7 +3541,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int w
invert_m4_m4(rv3d.persinv, rv3d.viewinv);
return ED_view3d_draw_offscreen_imbuf(scene, &v3d, &ar, width, height, flag,
- draw_background, alpha_mode, err_out);
+ draw_background, alpha_mode, viewname, err_out);
// seq_view3d_cb(scene, cfra, render_size, seqrectx, seqrecty);
}
@@ -3596,6 +3746,103 @@ static void view3d_main_area_draw_engine_info(View3D *v3d, RegionView3D *rv3d, A
ED_region_info_draw(ar, rv3d->render_engine->text, 1, fill_color);
}
+static bool view3d_stereo3d_active(const bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d)
+{
+ wmWindow *win = CTX_wm_window(C);
+
+ if ((scene->r.scemode & R_MULTIVIEW) == 0)
+ return false;
+
+ if (WM_stereo3d_enabled(win, true) == false)
+ return false;
+
+ if ((v3d->camera == NULL) || (v3d->camera->type != OB_CAMERA) || rv3d->persp != RV3D_CAMOB)
+ return false;
+
+ if (scene->r.views_format & SCE_VIEWS_FORMAT_MULTIVIEW) {
+ if (v3d->stereo3d_camera == STEREO_MONO_ID)
+ return false;
+
+ return BKE_scene_multiview_is_stereo3d(&scene->r);
+ }
+
+ return true;
+}
+
+/* setup the view and win matrices for the multiview cameras
+ *
+ * unlike view3d_stereo3d_setup_offscreen, when view3d_stereo3d_setup is called
+ * we have no winmatrix (i.e., projection matrix) defined at that time.
+ * Since the camera and the camera shift are needed for the winmat calculation
+ * we do a small hack to replace it temporarily so we don't need to change the
+ * view3d)main_area_setup_view() code to account for that.
+ */
+static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar)
+{
+ bool is_left;
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ const char *viewname;
+
+ /* show only left or right camera */
+ if (v3d->stereo3d_camera != STEREO_3D_ID)
+ v3d->multiview_eye = v3d->stereo3d_camera;
+
+ is_left = v3d->multiview_eye == STEREO_LEFT_ID;
+ viewname = names[is_left ? STEREO_LEFT_ID : STEREO_RIGHT_ID];
+
+ /* update the viewport matrices with the new camera */
+ if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
+ Camera *data;
+ float viewmat[4][4];
+ float shiftx;
+
+ data = (Camera *)v3d->camera->data;
+ shiftx = data->shiftx;
+
+ BLI_lock_thread(LOCK_VIEW3D);
+ data->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname);
+
+ BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
+ view3d_main_area_setup_view(scene, v3d, ar, viewmat, NULL);
+
+ data->shiftx = shiftx;
+ BLI_unlock_thread(LOCK_VIEW3D);
+ }
+ else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
+ float viewmat[4][4];
+ Object *view_ob = v3d->camera;
+ Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
+
+ BLI_lock_thread(LOCK_VIEW3D);
+ v3d->camera = camera;
+
+ BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
+ view3d_main_area_setup_view(scene, v3d, ar, viewmat, NULL);
+
+ v3d->camera = view_ob;
+ BLI_unlock_thread(LOCK_VIEW3D);
+ }
+}
+
+static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
+ float winmat[4][4], const char *viewname)
+{
+ /* update the viewport matrices with the new camera */
+ if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
+ float viewmat[4][4];
+ const bool is_left = STREQ(viewname, STEREO_LEFT_NAME);
+
+ BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
+ view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat);
+ }
+ else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
+ float viewmat[4][4];
+ Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
+
+ BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
+ view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat);
+ }
+}
#ifdef WITH_GAMEENGINE
static void update_lods(Scene *scene, float camera_pos[3])
@@ -3622,16 +3869,19 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3
/* shadow buffers, before we setup matrices */
if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype))
- gpu_update_lamps_shadows(scene, v3d);
-
+ gpu_update_lamps_shadows_world(scene, v3d);
+
/* reset default OpenGL lights if needed (i.e. after preferences have been altered) */
if (rv3d->rflag & RV3D_GPULIGHT_UPDATE) {
rv3d->rflag &= ~RV3D_GPULIGHT_UPDATE;
GPU_default_lights();
}
- /* setup view matrices */
- view3d_main_area_setup_view(scene, v3d, ar, NULL, NULL);
+ /* setup the view matrix */
+ if (view3d_stereo3d_active(C, scene, v3d, rv3d))
+ view3d_stereo3d_setup(scene, v3d, ar);
+ else
+ view3d_main_area_setup_view(scene, v3d, ar, NULL, NULL);
rv3d->rflag &= ~RV3D_IS_GAME_ENGINE;
#ifdef WITH_GAMEENGINE
@@ -3644,7 +3894,7 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3
#endif
/* framebuffer fx needed, we need to draw offscreen first */
- if (v3d->fx_settings.fx_flag) {
+ if (v3d->fx_settings.fx_flag && v3d->drawtype >= OB_SOLID) {
GPUFXSettings fx_settings;
BKE_screen_gpu_fx_validate(&v3d->fx_settings);
fx_settings = v3d->fx_settings;
@@ -3656,11 +3906,12 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3
else {
fx_settings.dof = NULL;
}
+
do_compositing = GPU_fx_compositor_initialize_passes(rv3d->compositor, &ar->winrct, &ar->drawrct, &fx_settings);
}
/* clear the background */
- view3d_main_area_clear(scene, v3d, ar, false);
+ view3d_main_area_clear(scene, v3d, ar);
/* enables anti-aliasing for 3D view drawing */
if (U.ogl_multisamples != USER_MULTISAMPLE_NONE) {
@@ -3715,7 +3966,7 @@ static bool is_cursor_visible(Scene *scene)
else if (ob->mode & OB_MODE_TEXTURE_PAINT) {
const Paint *p = BKE_paint_get_active(scene);
- if (p && p->brush->imagepaint_tool == PAINT_TOOL_CLONE) {
+ if (p && p->brush && p->brush->imagepaint_tool == PAINT_TOOL_CLONE) {
if ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) == 0) {
return true;
}
@@ -3785,7 +4036,7 @@ static void view3d_main_area_draw_info(const bContext *C, Scene *scene,
if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
wmWindowManager *wm = CTX_wm_manager(C);
- if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_playing(wm)) {
+ if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) {
ED_scene_draw_fps(scene, &rect);
}
else if (U.uiflag & USER_SHOW_VIEWPORTNAME) {
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 39541c108ff..b8add39b0e6 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -28,7 +28,6 @@
* \ingroup spview3d
*/
-
#include <string.h>
#include <stdio.h>
#include <math.h>
@@ -38,7 +37,6 @@
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "DNA_camera_types.h"
#include "MEM_guardedalloc.h"
@@ -75,7 +73,6 @@
#include "ED_transform.h"
#include "ED_mesh.h"
#include "ED_view3d.h"
-#include "ED_sculpt.h"
#include "UI_resources.h"
@@ -83,7 +80,7 @@
#include "view3d_intern.h" /* own include */
-bool ED_view3d_offset_lock_check(struct View3D *v3d, struct RegionView3D *rv3d)
+bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d)
{
return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre);
}
@@ -103,7 +100,7 @@ static bool view3d_operator_offset_lock_check(bContext *C, wmOperator *op)
/* ********************** view3d_edit: view manipulations ********************* */
-bool ED_view3d_camera_lock_check(View3D *v3d, RegionView3D *rv3d)
+bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
{
return ((v3d->camera) &&
(v3d->camera->id.lib == NULL) &&
@@ -520,6 +517,7 @@ void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip)
typedef struct ViewOpsData {
/* context pointers (assigned by viewops_data_alloc) */
+ Scene *scene;
ScrArea *sa;
ARegion *ar;
View3D *v3d;
@@ -592,6 +590,7 @@ static void viewops_data_alloc(bContext *C, wmOperator *op)
/* store data */
op->customdata = vod;
+ vod->scene = CTX_data_scene(C);
vod->sa = CTX_wm_area(C);
vod->ar = CTX_wm_region(C);
vod->v3d = vod->sa->spacedata.first;
@@ -1313,7 +1312,7 @@ void VIEW3D_OT_rotate(wmOperatorType *ot)
ot->cancel = viewrotate_cancel;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
}
/** \name NDOF Utility Functions
@@ -2056,7 +2055,7 @@ void VIEW3D_OT_move(wmOperatorType *ot)
ot->cancel = viewmove_cancel;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
}
/* ************************ viewzoom ******************************** */
@@ -2096,16 +2095,63 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom");
}
-static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my)
+static void view_zoom_mouseloc_camera(
+ Scene *scene, View3D *v3d,
+ ARegion *ar, float dfac, int mx, int my)
{
RegionView3D *rv3d = ar->regiondata;
+ const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
+ const float zoomfac_new = CLAMPIS(zoomfac * (1.0f / dfac), RV3D_CAMZOOM_MIN_FACTOR, RV3D_CAMZOOM_MAX_FACTOR);
+ const float camzoom_new = BKE_screen_view3d_zoom_from_fac(zoomfac_new);
+
+
+ if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
+ float zoomfac_px;
+ rctf camera_frame_old;
+ rctf camera_frame_new;
+
+ const float pt_src[2] = {mx, my};
+ float pt_dst[2];
+ float delta_px[2];
+
+ ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_old, false);
+ BLI_rctf_translate(&camera_frame_old, ar->winrct.xmin, ar->winrct.ymin);
+
+ rv3d->camzoom = camzoom_new;
+ CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
+
+ ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_new, false);
+ BLI_rctf_translate(&camera_frame_new, ar->winrct.xmin, ar->winrct.ymin);
+
+ BLI_rctf_transform_pt_v(&camera_frame_new, &camera_frame_old, pt_dst, pt_src);
+ sub_v2_v2v2(delta_px, pt_dst, pt_src);
+
+ /* translate the camera offset using pixel space delta
+ * mapped back to the camera (same logic as panning in camera view) */
+ zoomfac_px = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom) * 2.0f;
+
+ rv3d->camdx += delta_px[0] / (ar->winx * zoomfac_px);
+ rv3d->camdy += delta_px[1] / (ar->winy * zoomfac_px);
+ CLAMP(rv3d->camdx, -1.0f, 1.0f);
+ CLAMP(rv3d->camdy, -1.0f, 1.0f);
+ }
+ else {
+ rv3d->camzoom = camzoom_new;
+ CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
+ }
+}
+
+static void view_zoom_mouseloc_3d(ARegion *ar, float dfac, int mx, int my)
+{
+ RegionView3D *rv3d = ar->regiondata;
+ const float dist_new = rv3d->dist * dfac;
if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
float dvec[3];
float tvec[3];
float tpos[3];
float mval_f[2];
- float new_dist;
+
float zfac;
negate_v3_v3(tpos, rv3d->ofs);
@@ -2122,105 +2168,133 @@ static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my)
negate_v3(tvec);
/* Offset to target position and dolly */
- new_dist = rv3d->dist * dfac;
-
copy_v3_v3(rv3d->ofs, tvec);
- rv3d->dist = new_dist;
+ rv3d->dist = dist_new;
/* Calculate final offset */
madd_v3_v3v3fl(rv3d->ofs, tvec, dvec, dfac);
}
else {
- rv3d->dist *= dfac;
+ rv3d->dist = dist_new;
}
}
-
-static void viewzoom_apply(ViewOpsData *vod, const int xy[2], const short viewzoom, const short zoom_invert)
+static float viewzoom_scale_value(
+ const rcti *winrct,
+ const short viewzoom,
+ const bool zoom_invert, const bool zoom_invert_force,
+ const int xy[2], const int xy_orig[2],
+ const float val, const float val_orig,
+ double *r_timer_lastdraw)
{
- float zfac = 1.0;
- bool use_cam_zoom;
- float dist_range[2];
-
- use_cam_zoom = (vod->rv3d->persp == RV3D_CAMOB) && !(vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d));
-
- ED_view3d_dist_range_get(vod->v3d, dist_range);
-
- if (use_cam_zoom) {
- float delta;
- delta = (xy[0] - vod->origx + xy[1] - vod->origy) / 10.0f;
- vod->rv3d->camzoom = vod->camzoom_prev + (zoom_invert ? -delta : delta);
-
- CLAMP(vod->rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
- }
+ float zfac;
if (viewzoom == USER_ZOOM_CONT) {
double time = PIL_check_seconds_timer();
- float time_step = (float)(time - vod->timer_lastdraw);
+ float time_step = (float)(time - *r_timer_lastdraw);
float fac;
if (U.uiflag & USER_ZOOM_HORIZ) {
- fac = (float)(vod->origx - xy[0]);
+ fac = (float)(xy_orig[0] - xy[0]);
}
else {
- fac = (float)(vod->origy - xy[1]);
+ fac = (float)(xy_orig[1] - xy[1]);
}
- if (zoom_invert) {
+ if (zoom_invert != zoom_invert_force) {
fac = -fac;
}
/* oldstyle zoom */
zfac = 1.0f + ((fac / 20.0f) * time_step);
- vod->timer_lastdraw = time;
+ *r_timer_lastdraw = time;
}
else if (viewzoom == USER_ZOOM_SCALE) {
/* method which zooms based on how far you move the mouse */
const int ctr[2] = {
- BLI_rcti_cent_x(&vod->ar->winrct),
- BLI_rcti_cent_y(&vod->ar->winrct),
+ BLI_rcti_cent_x(winrct),
+ BLI_rcti_cent_y(winrct),
};
- const float len_new = 5 + len_v2v2_int(ctr, xy);
- const float len_old = 5 + len_v2v2_int(ctr, &vod->origx);
- zfac = vod->dist_prev * ((len_old + 5) / (len_new + 5)) / vod->rv3d->dist;
+ float len_new = 5 + len_v2v2_int(ctr, xy);
+ float len_old = 5 + len_v2v2_int(ctr, xy_orig);
+
+ /* intentionally ignore 'zoom_invert' for scale */
+ if (zoom_invert_force) {
+ SWAP(float, len_new, len_old);
+ }
+
+ zfac = val_orig * (len_old / max_ff(len_new, 1.0f)) / val;
}
else { /* USER_ZOOM_DOLLY */
- float len1, len2;
+ float len_new = 5;
+ float len_old = 5;
if (U.uiflag & USER_ZOOM_HORIZ) {
- len1 = (vod->ar->winrct.xmax - xy[0]) + 5;
- len2 = (vod->ar->winrct.xmax - vod->origx) + 5;
+ len_new += (winrct->xmax - xy[0]);
+ len_old += (winrct->xmax - xy_orig[0]);
}
else {
- len1 = (vod->ar->winrct.ymax - xy[1]) + 5;
- len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
- }
- if (zoom_invert) {
- SWAP(float, len1, len2);
+ len_new += (winrct->ymax - xy[1]);
+ len_old += (winrct->ymax - xy_orig[1]);
}
- if (use_cam_zoom) {
- /* zfac is ignored in this case, see below */
-#if 0
- zfac = vod->camzoom_prev * (2.0f * ((len1 / len2) - 1.0f) + 1.0f) / vod->rv3d->camzoom;
-#endif
- }
- else {
- zfac = vod->dist_prev * (2.0f * ((len1 / len2) - 1.0f) + 1.0f) / vod->rv3d->dist;
+ if (zoom_invert != zoom_invert_force) {
+ SWAP(float, len_new, len_old);
}
+
+ zfac = val_orig * (2.0f * ((len_new / max_ff(len_old, 1.0f)) - 1.0f) + 1.0f) / val;
}
- if (!use_cam_zoom) {
- if (zfac != 1.0f) {
- const float zfac_min = dist_range[0] / vod->rv3d->dist;
- const float zfac_max = dist_range[1] / vod->rv3d->dist;
- CLAMP(zfac, zfac_min, zfac_max);
- if (zfac != 1.0f) {
- view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy);
- }
- }
+ return zfac;
+}
+
+static void viewzoom_apply_camera(
+ ViewOpsData *vod, const int xy[2],
+ const short viewzoom, const bool zoom_invert)
+{
+ float zfac;
+ float zoomfac_prev = BKE_screen_view3d_zoom_to_fac(vod->camzoom_prev) * 2.0f;
+ float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f;
+
+ zfac = viewzoom_scale_value(
+ &vod->ar->winrct, viewzoom, zoom_invert, true, xy, &vod->origx,
+ zoomfac, zoomfac_prev,
+ &vod->timer_lastdraw);
+
+ if (zfac != 1.0f && zfac != 0.0f) {
+ /* calculate inverted, then invert again (needed because of camera zoom scaling) */
+ zfac = 1.0f / zfac;
+ view_zoom_mouseloc_camera(
+ vod->scene, vod->v3d,
+ vod->ar, zfac, vod->oldx, vod->oldy);
+ }
+
+ ED_region_tag_redraw(vod->ar);
+}
+
+static void viewzoom_apply_3d(
+ ViewOpsData *vod, const int xy[2],
+ const short viewzoom, const bool zoom_invert)
+{
+ float zfac;
+ float dist_range[2];
+
+ ED_view3d_dist_range_get(vod->v3d, dist_range);
+
+ zfac = viewzoom_scale_value(
+ &vod->ar->winrct, viewzoom, zoom_invert, false, xy, &vod->origx,
+ vod->rv3d->dist, vod->dist_prev,
+ &vod->timer_lastdraw);
+
+ if (zfac != 1.0f) {
+ const float zfac_min = dist_range[0] / vod->rv3d->dist;
+ const float zfac_max = dist_range[1] / vod->rv3d->dist;
+ CLAMP(zfac, zfac_min, zfac_max);
+
+ view_zoom_mouseloc_3d(
+ vod->ar, zfac, vod->oldx, vod->oldy);
}
/* these limits were in old code too */
@@ -2234,6 +2308,19 @@ static void viewzoom_apply(ViewOpsData *vod, const int xy[2], const short viewzo
ED_region_tag_redraw(vod->ar);
}
+static void viewzoom_apply(
+ ViewOpsData *vod, const int xy[2],
+ const short viewzoom, const bool zoom_invert)
+{
+ if ((vod->rv3d->persp == RV3D_CAMOB) &&
+ (vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) == 0)
+ {
+ viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert);
+ }
+ else {
+ viewzoom_apply_3d(vod, xy, viewzoom, zoom_invert);
+ }
+}
static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -2294,6 +2381,7 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
static int viewzoom_exec(bContext *C, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
View3D *v3d;
RegionView3D *rv3d;
ScrArea *sa;
@@ -2326,22 +2414,26 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
ED_view3d_dist_range_get(v3d, dist_range);
if (delta < 0) {
+ const float step = 1.2f;
/* this min and max is also in viewmove() */
if (use_cam_zoom) {
- rv3d->camzoom -= 10.0f;
- if (rv3d->camzoom < RV3D_CAMZOOM_MIN) rv3d->camzoom = RV3D_CAMZOOM_MIN;
+ view_zoom_mouseloc_camera(scene, v3d, ar, step, mx, my);
}
- else if (rv3d->dist < dist_range[1]) {
- view_zoom_mouseloc(ar, 1.2f, mx, my);
+ else {
+ if (rv3d->dist < dist_range[1]) {
+ view_zoom_mouseloc_3d(ar, step, mx, my);
+ }
}
}
else {
+ const float step = 1.0f / 1.2f;
if (use_cam_zoom) {
- rv3d->camzoom += 10.0f;
- if (rv3d->camzoom > RV3D_CAMZOOM_MAX) rv3d->camzoom = RV3D_CAMZOOM_MAX;
+ view_zoom_mouseloc_camera(scene, v3d, ar, step, mx, my);
}
- else if (rv3d->dist > dist_range[0]) {
- view_zoom_mouseloc(ar, 0.83333f, mx, my);
+ else {
+ if (rv3d->dist > dist_range[0]) {
+ view_zoom_mouseloc_3d(ar, step, mx, my);
+ }
}
}
@@ -2471,7 +2563,7 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
ot->cancel = viewzoom_cancel;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
@@ -2725,7 +2817,7 @@ void VIEW3D_OT_dolly(wmOperatorType *ot)
ot->cancel = viewdolly_cancel;
/* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR;
RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
@@ -2748,29 +2840,15 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar,
size = max_fff(afm[0], afm[1], afm[2]);
if (ok_dist) {
- /* fix up zoom distance if needed */
+ char persp;
if (rv3d->is_persp) {
- float lens, sensor_size;
- /* offset the view based on the lens */
if (rv3d->persp == RV3D_CAMOB && ED_view3d_camera_lock_check(v3d, rv3d)) {
- CameraParams params;
- BKE_camera_params_init(&params);
- params.clipsta = v3d->near;
- params.clipend = v3d->far;
- BKE_camera_params_from_object(&params, v3d->camera);
-
- lens = params.lens;
- sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y);
+ persp = RV3D_CAMOB;
}
else {
- lens = v3d->lens;
- sensor_size = DEFAULT_SENSOR_WIDTH;
+ persp = RV3D_PERSP;
}
- size = ED_view3d_radius_to_persp_dist(focallength_to_fov(lens, sensor_size), size / 2.0f) * VIEW3D_MARGIN;
-
- /* do not zoom closer than the near clipping plane */
- size = max_ff(size, v3d->near * 1.5f);
}
else { /* ortho */
if (size < 0.0001f) {
@@ -2779,7 +2857,15 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar,
}
else {
/* adjust zoom so it looks nicer */
- size = ED_view3d_radius_to_ortho_dist(v3d->lens, size / 2.0f) * VIEW3D_MARGIN;
+ persp = RV3D_ORTHO;
+ }
+ }
+
+ if (ok_dist) {
+ new_dist = ED_view3d_radius_to_dist(v3d, ar, persp, true, (size / 2) * VIEW3D_MARGIN);
+ if (rv3d->is_persp) {
+ /* don't zoom closer than the near clipping plane */
+ new_dist = max_ff(new_dist, v3d->near * 1.5f);
}
}
}
@@ -2787,15 +2873,6 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar,
mid_v3_v3v3(new_ofs, min, max);
negate_v3(new_ofs);
- new_dist = size;
-
- /* correction for window aspect ratio */
- if (ar->winy > 2 && ar->winx > 2) {
- size = (float)ar->winx / (float)ar->winy;
- if (size < 1.0f) size = 1.0f / size;
- new_dist *= size;
- }
-
if (rv3d->persp == RV3D_CAMOB && !ED_view3d_camera_lock_check(v3d, rv3d)) {
rv3d->persp = RV3D_PERSP;
ED_view3d_smooth_view(C, v3d, ar, v3d->camera, NULL,
@@ -3703,22 +3780,6 @@ static void axis_set_view(bContext *C, View3D *v3d, ARegion *ar,
}
if (align_active == false) {
- /* normal operation */
- if (rv3d->viewlock & RV3D_LOCKED) {
- /* only pass on if */
-
- /* nice confusing if-block */
- if (!((rv3d->view == RV3D_VIEW_FRONT && view == RV3D_VIEW_BACK) ||
- (rv3d->view == RV3D_VIEW_BACK && view == RV3D_VIEW_FRONT) ||
- (rv3d->view == RV3D_VIEW_RIGHT && view == RV3D_VIEW_LEFT) ||
- (rv3d->view == RV3D_VIEW_LEFT && view == RV3D_VIEW_RIGHT) ||
- (rv3d->view == RV3D_VIEW_BOTTOM && view == RV3D_VIEW_TOP) ||
- (rv3d->view == RV3D_VIEW_TOP && view == RV3D_VIEW_BOTTOM)))
- {
- return;
- }
- }
-
rv3d->view = view;
}
@@ -3765,10 +3826,6 @@ static int viewnumpad_exec(bContext *C, wmOperator *op)
viewnum = RNA_enum_get(op->ptr, "type");
align_active = RNA_boolean_get(op->ptr, "align_active");
- /* set this to zero, gets handled in axis_set_view */
- if (rv3d->viewlock & RV3D_LOCKED)
- align_active = false;
-
/* Use this to test if we started out with a camera */
if (rv3d->persp == RV3D_CAMOB) {
@@ -3894,23 +3951,37 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
ARegion *ar;
RegionView3D *rv3d;
int orbitdir;
+ char view_opposite;
+ PropertyRNA *prop_angle = RNA_struct_find_property(op->ptr, "angle");
+ float angle = RNA_property_is_set(op->ptr, prop_angle) ?
+ RNA_property_float_get(op->ptr, prop_angle) : DEG2RADF((float)U.pad_rot_angle);
/* no NULL check is needed, poll checks */
- ED_view3d_context_user_region(C, &v3d, &ar);
+ v3d = CTX_wm_view3d(C);
+ ar = CTX_wm_region(C);
rv3d = ar->regiondata;
+ /* support for switching to the opposite view (even when in locked views) */
+ view_opposite = (fabsf(angle) == (float)M_PI) ? ED_view3d_axis_view_opposite(rv3d->view) : RV3D_VIEW_USER;
orbitdir = RNA_enum_get(op->ptr, "type");
- if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
+ if ((rv3d->viewlock & RV3D_LOCKED) && (view_opposite == RV3D_VIEW_USER)) {
+ /* no NULL check is needed, poll checks */
+ ED_view3d_context_user_region(C, &v3d, &ar);
+ rv3d = ar->regiondata;
+ }
+
+ if ((rv3d->viewlock & RV3D_LOCKED) == 0 || (view_opposite != RV3D_VIEW_USER)) {
if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) {
int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
- float angle = DEG2RADF((float)U.pad_rot_angle);
float quat_mul[4];
float quat_new[4];
float ofs_new[3];
float *ofs_new_pt = NULL;
- view3d_ensure_persp(v3d, ar);
+ if (view_opposite == RV3D_VIEW_USER) {
+ view3d_ensure_persp(v3d, ar);
+ }
if (ELEM(orbitdir, V3D_VIEW_STEPLEFT, V3D_VIEW_STEPRIGHT)) {
const float zvec[3] = {0.0f, 0.0f, 1.0f};
@@ -3933,7 +4004,15 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
}
mul_qt_qtqt(quat_new, rv3d->viewquat, quat_mul);
- rv3d->view = RV3D_VIEW_USER;
+
+ if (view_opposite != RV3D_VIEW_USER) {
+ rv3d->view = view_opposite;
+ /* avoid float in-precision, just get a new orientation */
+ ED_view3d_quat_from_axis_view(view_opposite, quat_new);
+ }
+ else {
+ rv3d->view = RV3D_VIEW_USER;
+ }
if (U.uiflag & USER_ORBIT_SELECTION) {
float dyn_ofs[3];
@@ -3964,6 +4043,8 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
void VIEW3D_OT_view_orbit(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "View Orbit";
ot->description = "Orbit the view";
@@ -3977,7 +4058,11 @@ void VIEW3D_OT_view_orbit(wmOperatorType *ot)
ot->flag = 0;
/* properties */
+ prop = RNA_def_float(ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
ot->prop = RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit");
+
}
@@ -4429,20 +4514,6 @@ void VIEW3D_OT_background_image_remove(wmOperatorType *ot)
/* ********************* set clipping operator ****************** */
-static void calc_clipping_plane(float clip[6][4], const BoundBox *clipbb, const bool is_flip)
-{
- int val;
-
- for (val = 0; val < 4; val++) {
- normal_tri_v3(clip[val], clipbb->vec[val], clipbb->vec[val == 3 ? 0 : val + 1], clipbb->vec[val + 4]);
- if (UNLIKELY(is_flip)) {
- negate_v3(clip[val]);
- }
-
- clip[val][3] = -dot_v3v3(clip[val], clipbb->vec[val]);
- }
-}
-
static void calc_local_clipping(float clip_local[6][4], BoundBox *clipbb, float mat[4][4])
{
BoundBox clipbb_local;
@@ -4455,7 +4526,7 @@ static void calc_local_clipping(float clip_local[6][4], BoundBox *clipbb, float
mul_v3_m4v3(clipbb_local.vec[i], imat, clipbb->vec[i]);
}
- calc_clipping_plane(clip_local, &clipbb_local, is_negative_m4(mat));
+ ED_view3d_clipping_calc_from_boundbox(clip_local, &clipbb_local, is_negative_m4(mat));
}
void ED_view3d_clipping_local(RegionView3D *rv3d, float mat[4][4])
@@ -4536,7 +4607,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2])
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ RegionView3D *rv3d = ar->regiondata;
bool flip;
bool depth_used = false;
@@ -4571,9 +4642,28 @@ void ED_view3d_cursor3d_update(bContext *C, const int mval[2])
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
- float *fp = ED_view3d_cursor3d_get(scene, v3d);
- ED_view3d_cursor3d_position(C, fp, mval);
+ float *fp_curr = ED_view3d_cursor3d_get(scene, v3d);
+ float fp_prev[3];
+
+ copy_v3_v3(fp_prev, fp_curr);
+
+ ED_view3d_cursor3d_position(C, fp_curr, mval);
+
+ /* offset the cursor lock to avoid jumping to new offset */
+ if (v3d->ob_centre_cursor) {
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ float co_curr[2], co_prev[2];
+
+ if ((ED_view3d_project_float_global(ar, fp_prev, co_prev, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) &&
+ (ED_view3d_project_float_global(ar, fp_curr, co_curr, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK))
+ {
+ rv3d->ofs_lock[0] += (co_curr[0] - co_prev[0]) / (ar->winx * 0.5f);
+ rv3d->ofs_lock[1] += (co_curr[1] - co_prev[1]) / (ar->winy * 0.5f);
+ }
+ }
if (v3d && v3d->localvd)
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
@@ -4599,7 +4689,7 @@ void VIEW3D_OT_cursor3d(wmOperatorType *ot)
/* api callbacks */
ot->invoke = view3d_cursor3d_invoke;
- ot->poll = ED_operator_view3d_active;
+ ot->poll = ED_operator_region_view3d_active;
/* flags */
// ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -4725,16 +4815,24 @@ bool ED_view3d_autodist(Scene *scene, ARegion *ar, View3D *v3d,
bglMats mats; /* ZBuffer depth vars */
float depth_close;
double cent[2], p[3];
+ int margin_arr[] = {0, 2, 4};
+ int i;
+ bool depth_ok = false;
/* Get Z Depths, needed for perspective, nice for ortho */
bgl_get_mats(&mats);
ED_view3d_draw_depth(scene, ar, v3d, alphaoverride);
- depth_close = view_autodist_depth_margin(ar, mval, 4);
+ /* Attempt with low margin's first */
+ i = 0;
+ do {
+ depth_close = view_autodist_depth_margin(ar, mval, margin_arr[i++] * U.pixelsize);
+ depth_ok = (depth_close != FLT_MAX);
+ } while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr)));
- if (depth_close != FLT_MAX) {
- cent[0] = (double)mval[0];
- cent[1] = (double)mval[1];
+ if (depth_ok) {
+ cent[0] = (double)mval[0] + 0.5;
+ cent[1] = (double)mval[1] + 0.5;
if (gluUnProject(cent[0], cent[1], depth_close,
mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
@@ -4785,8 +4883,8 @@ bool ED_view3d_autodist_simple(ARegion *ar, const int mval[2], float mouse_world
if (depth == FLT_MAX)
return false;
- cent[0] = (double)mval[0];
- cent[1] = (double)mval[1];
+ cent[0] = (double)mval[0] + 0.5;
+ cent[1] = (double)mval[1] + 0.5;
bgl_get_mats(&mats);
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index da77c4f75f7..469a7e63903 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -296,10 +296,10 @@ static void fly_update_header(bContext *C, FlyInfo *fly)
"Ctrl: free look, "
"X: Upright x axis (%s), "
"Z: Upright z axis (%s), "
- "(+/- | Wheel): speed"),
+ "(+/- | Wheel): speed"),
WM_bool_as_string(fly->xlock != FLY_AXISLOCK_STATE_OFF),
- WM_bool_as_string(fly->zlock != FLY_AXISLOCK_STATE_OFF));
+ WM_bool_as_string(fly->zlock != FLY_AXISLOCK_STATE_OFF));
ED_area_headerprint(CTX_wm_area(C), header);
#undef HEADER_LENGTH
@@ -806,7 +806,7 @@ static int flyApply(bContext *C, FlyInfo *fly)
copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f);
mul_m3_v3(mat, upvec);
/* Rotate about the relative up vec */
- axis_angle_to_quat(tmp_quat, upvec, (float)moffset[1] * time_redraw * -FLY_ROTATE_FAC);
+ axis_angle_to_quat(tmp_quat, upvec, moffset[1] * time_redraw * -FLY_ROTATE_FAC);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
if (fly->xlock != FLY_AXISLOCK_STATE_OFF)
@@ -836,7 +836,7 @@ static int flyApply(bContext *C, FlyInfo *fly)
}
/* Rotate about the relative up vec */
- axis_angle_to_quat(tmp_quat, upvec, (float)moffset[0] * time_redraw * FLY_ROTATE_FAC);
+ axis_angle_to_quat(tmp_quat, upvec, moffset[0] * time_redraw * FLY_ROTATE_FAC);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
if (fly->xlock != FLY_AXISLOCK_STATE_OFF)
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 11ed9867e2f..95532bc09a5 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -105,8 +105,8 @@ static void view3d_layers_editmode_ensure(Scene *scene, View3D *v3d)
if (scene->obedit && (scene->obedit->lay & v3d->lay) == 0) {
int bit;
for (bit = 0; bit < 32; bit++) {
- if (scene->obedit->lay & (1 << bit)) {
- v3d->lay |= 1 << bit;
+ if (scene->obedit->lay & (1u << bit)) {
+ v3d->lay |= (1u << bit);
break;
}
}
@@ -161,8 +161,8 @@ static int view3d_layers_exec(bContext *C, wmOperator *op)
v3d->layact = 1 << nr;
else if ((v3d->lay & v3d->layact) == 0) {
for (bit = 0; bit < 32; bit++) {
- if (v3d->lay & (1 << bit)) {
- v3d->layact = 1 << bit;
+ if (v3d->lay & (1u << bit)) {
+ v3d->layact = (1u << bit);
break;
}
}
@@ -340,7 +340,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
}
/* Manipulators aren't used in paint modes */
- if (!ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_PARTICLE_EDIT)) {
+ if (!ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_PARTICLE_EDIT, OB_MODE_HAIR_EDIT)) {
/* masks aren't used for sculpt and particle painting */
PointerRNA meshptr;
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index a9b6d96d5d1..f4ecde79365 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -41,14 +41,14 @@ struct BoundBox;
struct DerivedMesh;
struct Object;
struct SmokeDomainSettings;
-struct ViewContext;
struct bAnimVizSettings;
struct bContext;
struct bMotionPath;
struct bPoseChannel;
-struct bScreen;
struct Mesh;
-struct SimDebugData;
+struct BMEditStrands;
+struct Strands;
+struct StrandsChildren;
struct wmNDOFMotionData;
struct wmOperatorType;
struct wmWindowManager;
@@ -184,6 +184,10 @@ void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d,
/* drawsimdebug.c */
void draw_sim_debug_data(Scene *scene, View3D *v3d, ARegion *ar);
+/* drawstrands.c */
+void draw_strands(Scene *scene, View3D *v3d, ARegion *ar, struct Object *ob, struct Strands *strands, struct StrandsChildren *children, short dflag);
+void draw_strands_edit_hair(Scene *scene, View3D *v3d, ARegion *ar, struct BMEditStrands *edit);
+
/* view3d_draw.c */
void view3d_main_area_draw(const struct bContext *C, struct ARegion *ar);
void ED_view3d_draw_depth(Scene *scene, struct ARegion *ar, View3D *v3d, bool alphaoverride);
@@ -210,7 +214,7 @@ void VIEW3D_OT_localview(struct wmOperatorType *ot);
void VIEW3D_OT_game_start(struct wmOperatorType *ot);
-bool ED_view3d_boundbox_clip_ex(RegionView3D *rv3d, const struct BoundBox *bb, float obmat[4][4]);
+bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const struct BoundBox *bb, float obmat[4][4]);
bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const struct BoundBox *bb);
void ED_view3d_smooth_view_ex(
@@ -227,8 +231,8 @@ void ED_view3d_smooth_view(
const float *ofs, const float *quat, const float *dist, const float *lens,
const int smooth_viewtx);
-void view3d_winmatrix_set(ARegion *ar, View3D *v3d, const rctf *rect);
-void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d);
+void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect);
+void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d);
void fly_modal_keymap(struct wmKeyConfig *keyconf);
void walk_modal_keymap(struct wmKeyConfig *keyconf);
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 64124a136e8..56faf945fb9 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -236,8 +236,9 @@ void view3d_keymap(wmKeyConfig *keyconf)
WM_keymap_verify_item(keymap, "VIEW3D_OT_navigate", FKEY, KM_PRESS, KM_SHIFT, 0);
+ /* value is set to KM_NOTHING to avoid conflicts with click type (see T44251) */
WM_keymap_verify_item(keymap, "VIEW3D_OT_smoothview", TIMER1, KM_ANY, KM_ANY, 0);
-
+
WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEPAN, 0, 0, 0);
WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEROTATE, 0, 0, 0);
WM_keymap_add_item(keymap, "VIEW3D_OT_move", MOUSEPAN, 0, KM_SHIFT, 0);
@@ -299,6 +300,9 @@ void view3d_keymap(wmKeyConfig *keyconf)
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD8, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANUP);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD4, KM_PRESS, KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPLEFT);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD6, KM_PRESS, KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPRIGHT);
+ kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", PAD9, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "type", V3D_VIEW_STEPRIGHT);
+ RNA_float_set(kmi->ptr, "angle", (float)M_PI);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELUPMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANRIGHT);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANLEFT);
@@ -523,3 +527,4 @@ void view3d_keymap(wmKeyConfig *keyconf)
viewzoom_modal_keymap(keyconf);
viewdolly_modal_keymap(keyconf);
}
+
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index 74e3fde0eec..ba0626c58ea 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -605,6 +605,14 @@ void ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, Object *ob, float pm
mul_m4_m4m4(pmat, (float (*)[4])rv3d->winmat, vmat);
}
+void ED_view3d_ob_project_mat_get_from_obmat(const RegionView3D *rv3d, float obmat[4][4], float pmat[4][4])
+{
+ float vmat[4][4];
+
+ mul_m4_m4m4(vmat, (float (*)[4])rv3d->viewmat, obmat);
+ mul_m4_m4m4(pmat, (float (*)[4])rv3d->winmat, vmat);
+}
+
/**
* Uses window coordinates (x,y) and depth component z to find a point in
* modelspace */
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index eba31866f54..98b1e846c70 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -187,8 +187,9 @@ typedef struct RulerInfo {
/* wm state */
wmWindow *win;
- ARegion *ar;
+ ScrArea *sa;
void *draw_handle_pixel;
+ ARegion *ar; /* re-assigned every modal update */
} RulerInfo;
/* -------------------------------------------------------------------- */
@@ -435,7 +436,7 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a
UnitSettings *unit = &scene->unit;
RulerItem *ruler_item;
RulerInfo *ruler_info = arg;
- RegionView3D *rv3d = ruler_info->ar->regiondata;
+ RegionView3D *rv3d = ar->regiondata;
// ARegion *ar = ruler_info->ar;
const float cap_size = 4.0f;
const float bg_margin = 4.0f * U.pixelsize;
@@ -798,12 +799,14 @@ static int view3d_ruler_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
op->customdata = ruler_info;
ruler_info->win = win;
- ruler_info->ar = ar;
+ ruler_info->sa = sa;
ruler_info->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ruler_info_draw_pixel,
ruler_info, REGION_DRAW_POST_PIXEL);
view3d_ruler_header_update(sa);
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+
WM_cursor_modal_set(win, BC_CROSSCURSOR);
WM_event_add_modal_handler(C, op);
@@ -825,15 +828,17 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
int exit_code = OPERATOR_RUNNING_MODAL;
RulerInfo *ruler_info = op->customdata;
ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = ruler_info->ar;
+ ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = ar->regiondata;
/* its possible to change spaces while running the operator [#34894] */
- if (UNLIKELY(ar != CTX_wm_region(C))) {
+ if (UNLIKELY(sa != ruler_info->sa)) {
exit_code = OPERATOR_FINISHED;
goto exit;
}
+ ruler_info->ar = ar;
+
switch (event->type) {
case LEFTMOUSE:
if (event->val == KM_RELEASE) {
@@ -1019,6 +1024,13 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
+ if (ruler_info->state == RULER_STATE_DRAG) {
+ op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
+ }
+ else {
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ }
+
if (do_draw) {
view3d_ruler_header_update(sa);
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index d0f22ba58c5..1847de3c6a2 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -85,9 +85,11 @@
#include "ED_armature.h"
#include "ED_curve.h"
+#include "ED_physics.h"
#include "ED_particle.h"
#include "ED_mesh.h"
#include "ED_object.h"
+#include "ED_physics.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
#include "ED_mball.h"
@@ -725,7 +727,7 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData, MVert *mv,
}
static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
{
- const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT);
+ const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
Object *ob = vc->obact;
Mesh *me = ob->data;
rcti rect;
@@ -834,6 +836,8 @@ static void view3d_lasso_select(bContext *C, ViewContext *vc,
}
else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT))
PE_lasso_select(C, mcords, moves, extend, select);
+ else if (ob && (ob->mode & OB_MODE_HAIR_EDIT))
+ ED_hair_lasso_select(C, mcords, moves, extend, select);
else {
do_lasso_select_objects(vc, mcords, moves, extend, select);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene);
@@ -1641,7 +1645,7 @@ static void do_paintvert_box_select__doSelectVert(void *userData, MVert *mv, con
}
static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, bool extend)
{
- const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT);
+ const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
Mesh *me;
MVert *mvert;
struct ImBuf *ibuf;
@@ -1662,7 +1666,7 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo
if (use_zbuf) {
selar = MEM_callocN(me->totvert + 1, "selar");
- view3d_validate_backbuf(vc);
+ ED_view3d_backbuf_validate(vc);
ibuf = IMB_allocImBuf(sx, sy, 32, IB_rect);
rt = ibuf->rect;
@@ -2146,6 +2150,9 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op)
else if (vc.obact && vc.obact->mode & OB_MODE_PARTICLE_EDIT) {
ret = PE_border_select(C, &rect, select, extend);
}
+ else if (vc.obact && vc.obact->mode & OB_MODE_HAIR_EDIT) {
+ ret = ED_hair_border_select(C, &rect, select, extend);
+ }
else { /* object mode with none active */
ret = do_object_pose_box_select(C, &vc, &rect, select, extend);
}
@@ -2185,7 +2192,7 @@ void VIEW3D_OT_select_border(wmOperatorType *ot)
static bool mouse_weight_paint_vertex_select(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, Object *obact)
{
View3D *v3d = CTX_wm_view3d(C);
- const int use_zbuf = (v3d->flag & V3D_ZBUF_SELECT);
+ const bool use_zbuf = (v3d->flag & V3D_ZBUF_SELECT) != 0;
Mesh *me = obact->data; /* already checked for NULL */
unsigned int index = 0;
@@ -2276,6 +2283,8 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
}
else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT)
return PE_mouse_particles(C, location, extend, deselect, toggle);
+ else if (obact && obact->mode & OB_MODE_HAIR_EDIT)
+ return ED_hair_mouse_select(C, location, extend, deselect, toggle);
else if (obact && BKE_paint_select_face_test(obact))
retval = paintface_mouse_select(C, obact, location, extend, deselect, toggle);
else if (BKE_paint_select_vert_test(obact))
@@ -2453,7 +2462,7 @@ static void paint_vertsel_circle_select_doSelectVert(void *userData, MVert *mv,
}
static void paint_vertsel_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad)
{
- const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT);
+ const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
Object *ob = vc->obact;
Mesh *me = ob->data;
bool bbsel;
@@ -2791,7 +2800,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
RNA_int_get(op->ptr, "y")};
if (CTX_data_edit_object(C) || BKE_paint_select_elem_test(obact) ||
- (obact && (obact->mode & (OB_MODE_PARTICLE_EDIT | OB_MODE_POSE))) )
+ (obact && (obact->mode & (OB_MODE_PARTICLE_EDIT | OB_MODE_POSE | OB_MODE_HAIR_EDIT))) )
{
ViewContext vc;
@@ -2811,10 +2820,16 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
paint_vertsel_circle_select(&vc, select, mval, (float)radius);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
}
- else if (obact->mode & OB_MODE_POSE)
+ else if (obact->mode & OB_MODE_POSE) {
pose_circle_select(&vc, select, mval, (float)radius);
- else
+ }
+ else if (obact->mode & OB_MODE_HAIR_EDIT) {
+ ED_hair_circle_select(C, select, mval, (float)radius);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
+ }
+ else {
return PE_circle_select(C, select, mval, (float)radius);
+ }
}
else if (obact && obact->mode & OB_MODE_SCULPT) {
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index 0608c35129d..8bb84d00c83 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -31,9 +31,7 @@
#include "DNA_armature_types.h"
-#include "DNA_curve_types.h"
#include "DNA_object_types.h"
-#include "DNA_meta_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -43,11 +41,9 @@
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
-#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_object.h"
-#include "BKE_editmesh.h"
#include "BKE_tracking.h"
#include "WM_api.h"
@@ -60,7 +56,6 @@
#include "ED_transverts.h"
#include "ED_keyframing.h"
#include "ED_screen.h"
-#include "ED_curve.h"
#include "view3d_intern.h"
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 5a3893f733f..e9cb6dcdc44 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -44,6 +44,7 @@
#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
#include "BKE_object.h"
#include "BKE_global.h"
#include "BKE_main.h"
@@ -609,6 +610,20 @@ void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
/* ********************************** */
+void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip)
+{
+ int val;
+
+ for (val = 0; val < 4; val++) {
+ normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]);
+ if (UNLIKELY(is_flip)) {
+ negate_v3(clip[val]);
+ }
+
+ clip[val][3] = -dot_v3v3(clip[val], bb->vec[val]);
+ }
+}
+
void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], bglMats *mats, const rcti *rect)
{
float modelview[4][4];
@@ -644,16 +659,7 @@ void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], bglMats *mats, co
((float *)modelview)[a] = mats->modelview[a];
flip_sign = is_negative_m4(modelview);
- /* then plane equations */
- for (val = 0; val < 4; val++) {
-
- normal_tri_v3(planes[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]);
-
- if (flip_sign)
- negate_v3(planes[val]);
-
- planes[val][3] = -dot_v3v3(planes[val], bb->vec[val]);
- }
+ ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign);
}
static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4])
@@ -683,7 +689,7 @@ static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4])
return false;
}
-bool ED_view3d_boundbox_clip_ex(RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4])
+bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4])
{
/* return 1: draw */
@@ -692,7 +698,7 @@ bool ED_view3d_boundbox_clip_ex(RegionView3D *rv3d, const BoundBox *bb, float ob
if (bb == NULL) return true;
if (bb->flag & BOUNDBOX_DISABLED) return true;
- mul_m4_m4m4(persmatob, rv3d->persmat, obmat);
+ mul_m4_m4m4(persmatob, (float(*)[4])rv3d->persmat, obmat);
return view3d_boundbox_clip_m4(bb, persmatob);
}
@@ -705,7 +711,7 @@ bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb)
return view3d_boundbox_clip_m4(bb, rv3d->persmatob);
}
-float ED_view3d_depth_read_cached(ViewContext *vc, int x, int y)
+float ED_view3d_depth_read_cached(const ViewContext *vc, int x, int y)
{
ViewDepths *vd = vc->rv3d->depths;
@@ -724,16 +730,19 @@ void ED_view3d_depth_tag_update(RegionView3D *rv3d)
rv3d->depths->damaged = true;
}
-void ED_view3d_dist_range_get(struct View3D *v3d,
- float r_dist_range[2])
+void ED_view3d_dist_range_get(
+ const View3D *v3d,
+ float r_dist_range[2])
{
r_dist_range[0] = v3d->grid * 0.001f;
r_dist_range[1] = v3d->far * 10.0f;
}
/* copies logic of get_view3d_viewplane(), keep in sync */
-bool ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *r_clipsta, float *r_clipend,
- const bool use_ortho_factor)
+bool ED_view3d_clip_range_get(
+ const View3D *v3d, const RegionView3D *rv3d,
+ float *r_clipsta, float *r_clipend,
+ const bool use_ortho_factor)
{
CameraParams params;
@@ -753,8 +762,9 @@ bool ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *r_clipsta,
}
/* also exposed in previewrender.c */
-bool ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winx, int winy,
- rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize)
+bool ED_view3d_viewplane_get(
+ const View3D *v3d, const RegionView3D *rv3d, int winx, int winy,
+ rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize)
{
CameraParams params;
@@ -792,7 +802,7 @@ void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
/**
* \param rect optional for picking (can be NULL).
*/
-void view3d_winmatrix_set(ARegion *ar, View3D *v3d, const rctf *rect)
+void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect)
{
RegionView3D *rv3d = ar->regiondata;
rctf viewplane;
@@ -891,13 +901,28 @@ char ED_view3d_lock_view_from_index(int index)
}
+char ED_view3d_axis_view_opposite(char view)
+{
+ switch (view) {
+ case RV3D_VIEW_FRONT: return RV3D_VIEW_BACK;
+ case RV3D_VIEW_BACK: return RV3D_VIEW_FRONT;
+ case RV3D_VIEW_LEFT: return RV3D_VIEW_RIGHT;
+ case RV3D_VIEW_RIGHT: return RV3D_VIEW_LEFT;
+ case RV3D_VIEW_TOP: return RV3D_VIEW_BOTTOM;
+ case RV3D_VIEW_BOTTOM: return RV3D_VIEW_TOP;
+ }
+
+ return RV3D_VIEW_USER;
+}
+
+
bool ED_view3d_lock(RegionView3D *rv3d)
{
return ED_view3d_quat_from_axis_view(rv3d->view, rv3d->viewquat);
}
/* don't set windows active in here, is used by renderwin too */
-void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d)
+void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d)
{
if (rv3d->persp == RV3D_CAMOB) { /* obs/camera */
if (v3d->camera) {
@@ -936,7 +961,7 @@ void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d)
}
else if (v3d->ob_centre_cursor) {
float vec[3];
- copy_v3_v3(vec, ED_view3d_cursor3d_get(scene, v3d));
+ copy_v3_v3(vec, ED_view3d_cursor3d_get(scene, (View3D *)v3d));
translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
use_lock_ofs = true;
}
@@ -1006,23 +1031,55 @@ static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegi
lb = object_duplilist(G.main->eval_ctx, scene, base->object);
for (dob = lb->first; dob; dob = dob->next) {
- float omat[4][4];
+ /* for restoring after override */
+ DupliObjectData *dob_data = NULL;
+ DerivedMesh *store_final_dm;
+ float store_obmat[4][4];
tbase.object = dob->ob;
- copy_m4_m4(omat, dob->ob->obmat);
+ copy_m4_m4(store_obmat, dob->ob->obmat);
copy_m4_m4(dob->ob->obmat, dob->mat);
+ store_final_dm = dob->ob->derivedFinal;
/* extra service: draw the duplicator in drawtype of parent */
/* MIN2 for the drawtype to allow bounding box objects in groups for lods */
dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt);
dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx;
+ /* override final DM */
+ tbase.object->transflag &= ~OB_IS_DUPLI_CACHE;
+ if (base->object->dup_cache) {
+ dob_data = BKE_dupli_cache_find_data(base->object->dup_cache, tbase.object);
+ if (dob_data && dob_data->dm) {
+ tbase.object->transflag |= OB_IS_DUPLI_CACHE;
+
+ tbase.object->derivedFinal = dob_data->dm;
+ }
+ }
+
draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR);
+ /* restore final DM */
+ if (tbase.object->transflag & OB_IS_DUPLI_CACHE) {
+ DerivedMesh *cur = tbase.object->derivedFinal;
+
+ /* in some cases drawing code can recreate the derivedFinal,
+ * make sure we free those first before restoring
+ */
+ if (cur && cur != dob_data->dm) {
+ cur->needsFree = 1;
+ cur->release(cur);
+ }
+
+ tbase.object->transflag &= ~OB_IS_DUPLI_CACHE;
+ tbase.object->derivedFinal = store_final_dm;
+ }
+
tbase.object->dt = dt;
tbase.object->dtx = dtx;
- copy_m4_m4(dob->ob->obmat, omat);
+ /* restore obmat and final DM */
+ copy_m4_m4(dob->ob->obmat, store_obmat);
}
free_object_duplilist(lb);
}
@@ -1194,7 +1251,7 @@ static bool view3d_localview_init(
View3D *v3d = sa->spacedata.first;
Base *base;
float min[3], max[3], box[3], mid[3];
- float size = 0.0f, size_persp = 0.0f, size_ortho = 0.0f;
+ float size = 0.0f;
unsigned int locallay;
bool ok = false;
@@ -1232,13 +1289,6 @@ static bool view3d_localview_init(
sub_v3_v3v3(box, max, min);
size = max_fff(box[0], box[1], box[2]);
-
- /* do not zoom closer than the near clipping plane */
- size = max_ff(size, v3d->near * 1.5f);
-
- /* perspective size (we always switch out of camera view so no need to use its lens size) */
- size_persp = ED_view3d_radius_to_persp_dist(focallength_to_fov(v3d->lens, DEFAULT_SENSOR_WIDTH), size / 2.0f) * VIEW3D_MARGIN;
- size_ortho = ED_view3d_radius_to_ortho_dist(v3d->lens, size / 2.0f) * VIEW3D_MARGIN;
}
if (ok == true) {
@@ -1255,6 +1305,7 @@ static bool view3d_localview_init(
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = ar->regiondata;
+ bool ok_dist = true;
/* new view values */
Object *camera_old = NULL;
@@ -1270,25 +1321,24 @@ static bool view3d_localview_init(
camera_old = v3d->camera;
}
- /* perspective should be a bit farther away to look nice */
- if (rv3d->persp != RV3D_ORTHO) {
- dist_new = size_persp;
- }
- else {
- dist_new = size_ortho;
+ if (rv3d->persp == RV3D_ORTHO) {
+ if (size < 0.0001f) {
+ ok_dist = false;
+ }
}
- /* correction for window aspect ratio */
- if (ar->winy > 2 && ar->winx > 2) {
- float asp = (float)ar->winx / (float)ar->winy;
- if (asp < 1.0f) asp = 1.0f / asp;
- dist_new *= asp;
+ if (ok_dist) {
+ dist_new = ED_view3d_radius_to_dist(v3d, ar, rv3d->persp, true, (size / 2) * VIEW3D_MARGIN);
+ if (rv3d->persp == RV3D_PERSP) {
+ /* don't zoom closer than the near clipping plane */
+ dist_new = max_ff(dist_new, v3d->near * 1.5f);
+ }
}
ED_view3d_smooth_view_ex(
wm, win, sa,
v3d, ar, camera_old, NULL,
- ofs_new, NULL, &dist_new, NULL,
+ ofs_new, NULL, ok_dist ? &dist_new : NULL, NULL,
smooth_viewtx);
}
}
@@ -1695,21 +1745,116 @@ void VIEW3D_OT_game_start(wmOperatorType *ot)
/* ************************************** */
-float ED_view3d_pixel_size(RegionView3D *rv3d, const float co[3])
+float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3])
{
- return mul_project_m4_v3_zfac(rv3d->persmat, co) * rv3d->pixsize * U.pixelsize;
+ return mul_project_m4_v3_zfac((float(*)[4])rv3d->persmat, co) * rv3d->pixsize * U.pixelsize;
}
-float ED_view3d_radius_to_persp_dist(const float angle, const float radius)
+float ED_view3d_radius_to_dist_persp(const float angle, const float radius)
{
- return (radius / 2.0f) * fabsf(1.0f / cosf((((float)M_PI) - angle) / 2.0f));
+ return radius * (1.0f / tanf(angle / 2.0f));
}
-float ED_view3d_radius_to_ortho_dist(const float lens, const float radius)
+float ED_view3d_radius_to_dist_ortho(const float lens, const float radius)
{
return radius / (DEFAULT_SENSOR_WIDTH / lens);
}
+/**
+ * Return a new RegionView3D.dist value to fit the \a radius.
+ *
+ * \note Depth isn't taken into account, this will fit a flat plane exactly,
+ * but points towards the view (with a perspective projection),
+ * may be within the radius but outside the view. eg:
+ *
+ * <pre>
+ * +
+ * pt --> + /^ radius
+ * / |
+ * / |
+ * view + +
+ * \ |
+ * \ |
+ * \|
+ * +
+ * </pre>
+ *
+ * \param ar Can be NULL if \a use_aspect is false.
+ * \param persp Allow the caller to tell what kind of perspective to use (ortho/view/camera)
+ * \param use_aspect Increase the distance to account for non 1:1 view aspect.
+ * \param radius The radius will be fitted exactly, typically pre-scaled by a margin (#VIEW3D_MARGIN).
+ */
+float ED_view3d_radius_to_dist(
+ const View3D *v3d, const ARegion *ar,
+ const char persp, const bool use_aspect,
+ const float radius)
+{
+ float dist;
+
+ BLI_assert(ELEM(persp, RV3D_ORTHO, RV3D_PERSP, RV3D_CAMOB));
+ BLI_assert((persp != RV3D_CAMOB) || v3d->camera);
+
+ if (persp == RV3D_ORTHO) {
+ dist = ED_view3d_radius_to_dist_ortho(v3d->lens, radius);
+ }
+ else {
+ float lens, sensor_size, zoom;
+ float angle;
+
+ if (persp == RV3D_CAMOB) {
+ CameraParams params;
+ BKE_camera_params_init(&params);
+ params.clipsta = v3d->near;
+ params.clipend = v3d->far;
+ BKE_camera_params_from_object(&params, v3d->camera);
+
+ lens = params.lens;
+ sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y);
+
+ /* ignore 'rv3d->camzoom' because we wan't to fit to the cameras frame */
+ zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB;
+ }
+ else {
+ lens = v3d->lens;
+ sensor_size = DEFAULT_SENSOR_WIDTH;
+ zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
+ }
+
+ angle = focallength_to_fov(lens, sensor_size);
+
+ /* zoom influences lens, correct this by scaling the angle as a distance (by the zoom-level) */
+ angle = atanf(tanf(angle / 2.0f) * zoom) * 2.0f;
+
+ dist = ED_view3d_radius_to_dist_persp(angle, radius);
+ }
+
+ if (use_aspect) {
+ const RegionView3D *rv3d = ar->regiondata;
+
+ float winx, winy;
+
+ if (persp == RV3D_CAMOB) {
+ /* camera frame x/y in pixels */
+ winx = ar->winx / rv3d->viewcamtexcofac[0];
+ winy = ar->winy / rv3d->viewcamtexcofac[1];
+ }
+ else {
+ winx = ar->winx;
+ winy = ar->winy;
+ }
+
+ if (winx && winy) {
+ float aspect = winx / winy;
+ if (aspect < 1.0f) {
+ aspect = 1.0f / aspect;
+ }
+ dist *= aspect;
+ }
+ }
+
+ return dist;
+}
+
/* view matrix properties utilities */
/* unused */
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 191eeb05c71..1d5c2a3a169 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -26,8 +26,6 @@
/* defines VIEW3D_OT_navigate - walk modal operator */
-//#define NDOF_WALK_DEBUG
-//#define NDOF_WALK_DRAW_TOOMUCH /* is this needed for ndof? - commented so redraw doesnt thrash - campbell */
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -58,6 +56,11 @@
#include "view3d_intern.h" /* own include */
+//#define NDOF_WALK_DEBUG
+//#define NDOF_WALK_DRAW_TOOMUCH /* is this needed for ndof? - commented so redraw doesnt thrash - campbell */
+
+#define USE_TABLET_SUPPORT
+
/* prototypes */
static float getVelocityZeroTime(const float gravity, const float velocity);
@@ -220,8 +223,7 @@ void walk_modal_keymap(wmKeyConfig *keyconf)
}
-typedef struct WalkTeleport
-{
+typedef struct WalkTeleport {
eWalkTeleportState state;
float duration; /* from user preferences */
float origin[3];
@@ -277,6 +279,14 @@ typedef struct WalkInfo {
/* mouse reverse */
bool is_reversed;
+#ifdef USE_TABLET_SUPPORT
+ /* check if we had a cursor event before */
+ bool is_cursor_first;
+
+ /* tablet devices (we can't relocate the cursor) */
+ bool is_cursor_absolute;
+#endif
+
/* gravity system */
eWalkGravityState gravity_state;
float gravity;
@@ -345,7 +355,7 @@ static void walk_update_header(bContext *C, WalkInfo *walk)
char header[HEADER_LENGTH];
BLI_snprintf(header, HEADER_LENGTH, IFACE_("LMB/Return: confirm, Esc/RMB: cancel, "
- "Tab: gravity (%s), "
+ "Tab: gravity (%s), "
"WASD: move around, "
"Shift: fast, Alt: slow, "
"QE: up and down, MMB/Space: teleport, V: jump, "
@@ -520,6 +530,12 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->is_reversed = ((U.walk_navigation.flag & USER_WALK_MOUSE_REVERSE) != 0);
+#ifdef USE_TABLET_SUPPORT
+ walk->is_cursor_first = true;
+
+ walk->is_cursor_absolute = false;
+#endif
+
walk->active_directions = 0;
#ifdef NDOF_WALK_DRAW_TOOMUCH
@@ -587,10 +603,16 @@ static int walkEnd(bContext *C, WalkInfo *walk)
/* restore the cursor */
WM_cursor_modal_restore(win);
- /* center the mouse */
- WM_cursor_warp(win,
- walk->ar->winrct.xmin + walk->center_mval[0],
- walk->ar->winrct.ymin + walk->center_mval[1]);
+#ifdef USE_TABLET_SUPPORT
+ if (walk->is_cursor_absolute == false)
+#endif
+ {
+ /* center the mouse */
+ WM_cursor_warp(
+ win,
+ walk->ar->winrct.xmin + walk->center_mval[0],
+ walk->ar->winrct.ymin + walk->center_mval[1]);
+ }
if (walk->state == WALK_CONFIRM) {
MEM_freeN(walk);
@@ -618,6 +640,27 @@ static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const
}
else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+#ifdef USE_TABLET_SUPPORT
+ if (walk->is_cursor_first) {
+ /* wait until we get the 'warp' event */
+ if ((walk->center_mval[0] == event->mval[0]) &&
+ (walk->center_mval[1] == event->mval[1]))
+ {
+ walk->is_cursor_first = false;
+ }
+ return;
+ }
+
+ if ((walk->is_cursor_absolute == false) && WM_event_is_absolute(event)) {
+ walk->is_cursor_absolute = true;
+ copy_v2_v2_int(walk->prev_mval, event->mval);
+ copy_v2_v2_int(walk->center_mval, event->mval);
+ /* without this we can't turn 180d */
+ CLAMP_MIN(walk->mouse_speed, 4.0f);
+ }
+#endif /* USE_TABLET_SUPPORT */
+
+
walk->moffset[0] += event->mval[0] - walk->prev_mval[0];
walk->moffset[1] += event->mval[1] - walk->prev_mval[1];
@@ -628,6 +671,12 @@ static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const
{
walk->redraw = true;
+#ifdef USE_TABLET_SUPPORT
+ if (walk->is_cursor_absolute) {
+ /* pass */
+ }
+ else
+#endif
if (wm_event_is_last_mousemove(event)) {
wmWindow *win = CTX_wm_window(C);
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index 0c360474b78..0bc38f81dd7 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -55,6 +55,10 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_LEGACY_DEPSGRAPH)
+ add_definitions(-DWITH_LEGACY_DEPSGRAPH)
+endif()
+
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_editor_transform "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/transform/SConscript b/source/blender/editors/transform/SConscript
index d1bc95819f8..d1931399055 100644
--- a/source/blender/editors/transform/SConscript
+++ b/source/blender/editors/transform/SConscript
@@ -51,4 +51,7 @@ defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_LEGACY_DEPSGRAPH']:
+ defs.append('WITH_LEGACY_DEPSGRAPH')
+
env.BlenderLib ( 'bf_editors_transform', sources, incs, defs, libtype=['core'], priority=[40] )
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 3eb080f1667..38fb35bbb1a 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -54,6 +54,7 @@
#include "BLI_memarena.h"
#include "BKE_nla.h"
+#include "BKE_editmesh.h"
#include "BKE_editmesh_bvh.h"
#include "BKE_context.h"
#include "BKE_constraint.h"
@@ -99,11 +100,13 @@ static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg)
static void doEdgeSlide(TransInfo *t, float perc);
static void doVertSlide(TransInfo *t, float perc);
-static void drawEdgeSlide(const struct bContext *C, TransInfo *t);
-static void drawVertSlide(const struct bContext *C, TransInfo *t);
+static void drawEdgeSlide(TransInfo *t);
+static void drawVertSlide(TransInfo *t);
static void len_v3_ensure(float v[3], const float length);
static void postInputRotation(TransInfo *t, float values[3]);
+static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short around);
+
/* Transform Callbacks */
static void initBend(TransInfo *t);
@@ -730,7 +733,6 @@ static void view_editmove(unsigned short UNUSED(event))
switch (event) {
case WHEELUPMOUSE:
-
if (G.qual & LR_SHIFTKEY) {
if (G.qual & LR_ALTKEY) {
G.qual &= ~LR_SHIFTKEY;
@@ -796,35 +798,38 @@ static void view_editmove(unsigned short UNUSED(event))
/* ************************************************* */
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
-#define TFM_MODAL_CANCEL 1
-#define TFM_MODAL_CONFIRM 2
-#define TFM_MODAL_TRANSLATE 3
-#define TFM_MODAL_ROTATE 4
-#define TFM_MODAL_RESIZE 5
-#define TFM_MODAL_SNAP_INV_ON 6
-#define TFM_MODAL_SNAP_INV_OFF 7
-#define TFM_MODAL_SNAP_TOGGLE 8
-#define TFM_MODAL_AXIS_X 9
-#define TFM_MODAL_AXIS_Y 10
-#define TFM_MODAL_AXIS_Z 11
-#define TFM_MODAL_PLANE_X 12
-#define TFM_MODAL_PLANE_Y 13
-#define TFM_MODAL_PLANE_Z 14
-#define TFM_MODAL_CONS_OFF 15
-#define TFM_MODAL_ADD_SNAP 16
-#define TFM_MODAL_REMOVE_SNAP 17
-/* 18 and 19 used by numinput, defined in transform.h
- * */
-#define TFM_MODAL_PROPSIZE_UP 20
-#define TFM_MODAL_PROPSIZE_DOWN 21
-#define TFM_MODAL_AUTOIK_LEN_INC 22
-#define TFM_MODAL_AUTOIK_LEN_DEC 23
-
-#define TFM_MODAL_EDGESLIDE_UP 24
-#define TFM_MODAL_EDGESLIDE_DOWN 25
+enum {
+ TFM_MODAL_CANCEL = 1,
+ TFM_MODAL_CONFIRM = 2,
+ TFM_MODAL_TRANSLATE = 3,
+ TFM_MODAL_ROTATE = 4,
+ TFM_MODAL_RESIZE = 5,
+ TFM_MODAL_SNAP_INV_ON = 6,
+ TFM_MODAL_SNAP_INV_OFF = 7,
+ TFM_MODAL_SNAP_TOGGLE = 8,
+ TFM_MODAL_AXIS_X = 9,
+ TFM_MODAL_AXIS_Y = 10,
+ TFM_MODAL_AXIS_Z = 11,
+ TFM_MODAL_PLANE_X = 12,
+ TFM_MODAL_PLANE_Y = 13,
+ TFM_MODAL_PLANE_Z = 14,
+ TFM_MODAL_CONS_OFF = 15,
+ TFM_MODAL_ADD_SNAP = 16,
+ TFM_MODAL_REMOVE_SNAP = 17,
+
+/* 18 and 19 used by numinput, defined in transform.h */
+
+ TFM_MODAL_PROPSIZE_UP = 20,
+ TFM_MODAL_PROPSIZE_DOWN = 21,
+ TFM_MODAL_AUTOIK_LEN_INC = 22,
+ TFM_MODAL_AUTOIK_LEN_DEC = 23,
+
+ TFM_MODAL_EDGESLIDE_UP = 24,
+ TFM_MODAL_EDGESLIDE_DOWN = 25,
/* for analog input, like trackpad */
-#define TFM_MODAL_PROPSIZE 26
+ TFM_MODAL_PROPSIZE = 26,
+};
/* called in transform_ops.c, on each regeneration of keymaps */
wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
@@ -869,8 +874,8 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
/* items for modal map */
WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CANCEL);
WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
+ WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
+ WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
WM_modalkeymap_add_item(keymap, GKEY, KM_PRESS, 0, 0, TFM_MODAL_TRANSLATE);
WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, TFM_MODAL_ROTATE);
@@ -889,8 +894,12 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP);
WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
+ WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_UP);
+ WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_DOWN);
WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP);
WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
+ WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_UP);
+ WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_DOWN);
WM_modalkeymap_add_item(keymap, MOUSEPAN, 0, 0, 0, TFM_MODAL_PROPSIZE);
WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_UP);
@@ -908,7 +917,7 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
{
if (!(t->flag & T_NO_CONSTRAINT)) {
int constraint_axis, constraint_plane;
- int edit_2d = (t->flag & T_2D_EDIT);
+ const bool edit_2d = (t->flag & T_2D_EDIT) != 0;
const char *msg1 = "", *msg2 = "", *msg3 = "";
char axis;
@@ -1231,7 +1240,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_PROPSIZE_UP:
if (t->flag & T_PROP_EDIT) {
- t->prop_size *= 1.1f;
+ t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
calculatePropRatio(t);
@@ -1241,17 +1250,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_PROPSIZE_DOWN:
if (t->flag & T_PROP_EDIT) {
- t->prop_size *= 0.90909090f;
+ t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
calculatePropRatio(t);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
- case TFM_MODAL_EDGESLIDE_UP:
- case TFM_MODAL_EDGESLIDE_DOWN:
- t->redraw |= TREDRAW_HARD;
- handled = true;
- break;
case TFM_MODAL_AUTOIK_LEN_INC:
if (t->flag & T_AUTOIK) {
transform_autoik_update(t, 1);
@@ -1266,6 +1270,9 @@ int transformEvent(TransInfo *t, const wmEvent *event)
handled = true;
}
break;
+ /* Those two are only handled in transform's own handler, see T44634! */
+ case TFM_MODAL_EDGESLIDE_UP:
+ case TFM_MODAL_EDGESLIDE_DOWN:
default:
break;
}
@@ -1414,7 +1421,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case PADPLUSKEY:
if (event->alt && t->flag & T_PROP_EDIT) {
- t->prop_size *= 1.1f;
+ t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
calculatePropRatio(t);
@@ -1435,7 +1442,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case PADMINUS:
if (event->alt && t->flag & T_PROP_EDIT) {
- t->prop_size *= 0.90909090f;
+ t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
calculatePropRatio(t);
t->redraw = TREDRAW_HARD;
handled = true;
@@ -1825,8 +1832,8 @@ static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), voi
drawSnapping(C, t);
/* edge slide, vert slide */
- drawEdgeSlide(C, t);
- drawVertSlide(C, t);
+ drawEdgeSlide(t);
+ drawVertSlide(t);
}
/* just draw a little warning message in the top-right corner of the viewport to warn that autokeying is enabled */
@@ -1935,7 +1942,11 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
if ((prop = RNA_struct_find_property(op->ptr, "proportional")) &&
!RNA_property_is_set(op->ptr, prop))
{
- if (t->obedit)
+ if (t->spacetype == SPACE_IPO)
+ ts->proportional_fcurve = proportional;
+ else if (t->spacetype == SPACE_ACTION)
+ ts->proportional_action = proportional;
+ else if (t->obedit)
ts->proportional = proportional;
else if (t->options & CTX_MASK)
ts->proportional_mask = (proportional != PROP_EDIT_OFF);
@@ -1986,7 +1997,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
if ((prop = RNA_struct_find_property(op->ptr, "mirror"))) {
- RNA_property_boolean_set(op->ptr, prop, t->flag & T_MIRROR);
+ RNA_property_boolean_set(op->ptr, prop, (t->flag & T_MIRROR) != 0);
}
if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
@@ -2014,6 +2025,18 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
RNA_property_boolean_set_array(op->ptr, prop, constraint_axis);
}
+
+ {
+ const char *prop_id = NULL;
+ if (t->mode == TFM_SHRINKFATTEN) {
+ prop_id = "use_even_offset";
+ }
+
+ if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id))) {
+
+ RNA_property_boolean_set(op->ptr, prop, (t->flag & T_ALT_TRANSFORM) != 0);
+ }
+ }
}
static void initSnappingAspect(TransInfo *t)
@@ -2115,6 +2138,18 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
}
+ else if (t->spacetype == SPACE_IPO) {
+ unit_m3(t->spacemtx);
+ t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
+ //t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
+ }
+ else if (t->spacetype == SPACE_ACTION) {
+ unit_m3(t->spacemtx);
+ t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
+ //t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
+ t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
+ }
else
unit_m3(t->spacemtx);
@@ -2565,8 +2600,8 @@ static void protectedQuaternionBits(short protectflag, float quat[4], const floa
static void constraintTransLim(TransInfo *t, TransData *td)
{
if (td->con) {
- bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_LOCLIMIT);
- bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_DISTLIMIT);
+ const bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_LOCLIMIT);
+ const bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_DISTLIMIT);
bConstraintOb cob = {NULL};
bConstraint *con;
@@ -2581,7 +2616,7 @@ static void constraintTransLim(TransInfo *t, TransData *td)
/* Evaluate valid constraints */
for (con = td->con; con; con = con->next) {
- bConstraintTypeInfo *cti = NULL;
+ const bConstraintTypeInfo *cti = NULL;
ListBase targets = {NULL, NULL};
/* only consider constraint if enabled */
@@ -2668,7 +2703,7 @@ static void constraintob_from_transdata(bConstraintOb *cob, TransData *td)
static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
{
if (td->con) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_ROTLIMIT);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_ROTLIMIT);
bConstraintOb cob;
bConstraint *con;
bool do_limit = false;
@@ -2735,7 +2770,7 @@ static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
static void constraintSizeLim(TransInfo *t, TransData *td)
{
if (td->con && td->ext) {
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_SIZELIMIT);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_SIZELIMIT);
bConstraintOb cob = {NULL};
bConstraint *con;
float size_sign[3], size_abs[3];
@@ -2859,7 +2894,7 @@ static void initBend(TransInfo *t)
t->num.unit_type[0] = B_UNIT_ROTATION;
t->num.unit_type[1] = B_UNIT_LENGTH;
- t->flag |= T_NO_CONSTRAINT;
+ t->flag |= T_NO_CONSTRAINT | T_FREE_CUSTOMDATA;
//copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
calculateCenterCursor(t, t->center);
@@ -3010,6 +3045,13 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
add_v3_v3(vec, pivot);
mul_m3_v3(td->smtx, vec);
+
+ /* rotation */
+ if ((t->flag & T_POINTS) == 0) {
+ ElementRotation(t, td, mat, V3D_LOCAL);
+ }
+
+ /* location */
copy_v3_v3(td->loc, vec);
}
@@ -5309,9 +5351,10 @@ static void slide_origdata_create_data_vert(
loop_weights = BLI_array_alloca(loop_weights, l_num);
for (j = 0; j < l_num; j++) {
BMLoop *l = BM_iter_step(&liter);
- if (!BLI_ghash_haskey(sod->origfaces, l->f)) {
+ void **val_p;
+ if (!BLI_ghash_ensure_p(sod->origfaces, l->f, &val_p)) {
BMFace *f_copy = BM_face_copy(sod->bm_origfaces, bm, l->f, true, true);
- BLI_ghash_insert(sod->origfaces, l->f, f_copy);
+ *val_p = f_copy;
}
loop_weights[j] = BM_loop_calc_face_angle(l);
}
@@ -5476,6 +5519,19 @@ static void slide_origdata_free_date(
/** \name Transform Edge Slide
* \{ */
+static void calcEdgeSlideCustomPoints(struct TransInfo *t)
+{
+ EdgeSlideData *sld = t->customData;
+
+ setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start);
+
+ /* setCustomPoints isn't normally changing as the mouse moves,
+ * in this case apply mouse input immediatly so we don't refresh
+ * with the value from the previous points */
+ applyMouseInput(t, &t->mouse, t->mval, t->values);
+}
+
+
static BMEdge *get_other_edge(BMVert *v, BMEdge *e)
{
BMIter iter;
@@ -5491,7 +5547,7 @@ static BMEdge *get_other_edge(BMVert *v, BMEdge *e)
}
/* interpoaltes along a line made up of 2 segments (used for edge slide) */
-static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float t)
+static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], float t)
{
float t_mid, t_delta;
@@ -5499,17 +5555,28 @@ static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[
t_mid = line_point_factor_v3(v2, v1, v3);
t_delta = t - t_mid;
- if (fabsf(t_delta) < FLT_EPSILON) {
- copy_v3_v3(p, v2);
- }
- else if (t_delta < 0.0f) {
- interp_v3_v3v3(p, v1, v2, t / t_mid);
+ if (t_delta < 0.0f) {
+ if (UNLIKELY(fabsf(t_mid) < FLT_EPSILON)) {
+ copy_v3_v3(p, v2);
+ }
+ else {
+ interp_v3_v3v3(p, v1, v2, t / t_mid);
+ }
}
else {
- interp_v3_v3v3(p, v2, v3, (t - t_mid) / (1.0f - t_mid));
+ t = t - t_mid;
+ t_mid = 1.0f - t_mid;
+
+ if (UNLIKELY(fabsf(t_mid) < FLT_EPSILON)) {
+ copy_v3_v3(p, v3);
+ }
+ else {
+ interp_v3_v3v3(p, v2, v3, t / t_mid);
+ }
}
}
+
static void len_v3_ensure(float v[3], const float length)
{
normalize_v3(v);
@@ -5684,7 +5751,7 @@ static void calcNonProportionalEdgeSlide(TransInfo *t, EdgeSlideData *sld, const
for (i = 0; i < sld->totsv; i++, sv++) {
/* Set length */
- sv->edge_len = len_v3v3(sv->dir_a, sv->dir_b);
+ sv->edge_len = len_v3v3(sv->dir_side[0], sv->dir_side[1]);
ED_view3d_project_float_v2_m4(ar, sv->v->co, v_proj, projectMat);
dist_sq = len_squared_v2v2(mval, v_proj);
@@ -5717,7 +5784,7 @@ static bool createEdgeSlideVerts(TransInfo *t)
float projectMat[4][4];
float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
float mval_start[2], mval_end[2];
- float mval_dir[3], maxdist, (*loop_dir)[3], *loop_maxdist;
+ float mval_dir[3], dist_best_sq, (*loop_dir)[3], *loop_maxdist;
int numsel, i, j, loop_nr, l_nr;
int use_btree_disp;
@@ -5912,14 +5979,14 @@ static bool createEdgeSlideVerts(TransInfo *t)
if (l_a || l_a_prev) {
BMLoop *l_tmp = BM_loop_other_edge_loop(l_a ? l_a : l_a_prev, v);
- sv->v_a = BM_edge_other_vert(l_tmp->e, v);
- copy_v3_v3(sv->dir_a, vec_a);
+ sv->v_side[0] = BM_edge_other_vert(l_tmp->e, v);
+ copy_v3_v3(sv->dir_side[0], vec_a);
}
if (l_b || l_b_prev) {
BMLoop *l_tmp = BM_loop_other_edge_loop(l_b ? l_b : l_b_prev, v);
- sv->v_b = BM_edge_other_vert(l_tmp->e, v);
- copy_v3_v3(sv->dir_b, vec_b);
+ sv->v_side[1] = BM_edge_other_vert(l_tmp->e, v);
+ copy_v3_v3(sv->dir_side[1], vec_b);
}
v_prev = v;
@@ -5938,23 +6005,23 @@ static bool createEdgeSlideVerts(TransInfo *t)
if (l_a) {
BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v);
- sv->v_a = BM_edge_other_vert(l_tmp->e, v);
+ sv->v_side[0] = BM_edge_other_vert(l_tmp->e, v);
if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
- get_next_loop(v, l_a, e_prev, l_tmp->e, sv->dir_a);
+ get_next_loop(v, l_a, e_prev, l_tmp->e, sv->dir_side[0]);
}
else {
- sub_v3_v3v3(sv->dir_a, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
+ sub_v3_v3v3(sv->dir_side[0], BM_edge_other_vert(l_tmp->e, v)->co, v->co);
}
}
if (l_b) {
BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v);
- sv->v_b = BM_edge_other_vert(l_tmp->e, v);
+ sv->v_side[1] = BM_edge_other_vert(l_tmp->e, v);
if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
- get_next_loop(v, l_b, e_prev, l_tmp->e, sv->dir_b);
+ get_next_loop(v, l_b, e_prev, l_tmp->e, sv->dir_side[1]);
}
else {
- sub_v3_v3v3(sv->dir_b, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
+ sub_v3_v3v3(sv->dir_side[1], BM_edge_other_vert(l_tmp->e, v)->co, v->co);
}
}
@@ -6044,17 +6111,17 @@ static bool createEdgeSlideVerts(TransInfo *t)
/* find mouse vectors, the global one, and one per loop in case we have
* multiple loops selected, in case they are oriented different */
zero_v3(mval_dir);
- maxdist = -1.0f;
+ dist_best_sq = -1.0f;
loop_dir = MEM_callocN(sizeof(float) * 3 * loop_nr, "sv loop_dir");
loop_maxdist = MEM_mallocN(sizeof(float) * loop_nr, "sv loop_maxdist");
- fill_vn_fl(loop_maxdist, loop_nr, -1.0f);
+ copy_vn_fl(loop_maxdist, loop_nr, -1.0f);
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
BMIter iter2;
BMEdge *e2;
- float d;
+ float dist_sq;
/* search cross edges for visible edge to the mouse cursor,
* then use the shared vertex to calculate screen vector*/
@@ -6075,36 +6142,36 @@ static bool createEdgeSlideVerts(TransInfo *t)
BLI_assert(sv_table[BM_elem_index_get(v)] != -1);
j = sv_table[BM_elem_index_get(v)];
- if (sv_array[j].v_b) {
- ED_view3d_project_float_v3_m4(ar, sv_array[j].v_b->co, sco_b, projectMat);
+ if (sv_array[j].v_side[1]) {
+ ED_view3d_project_float_v3_m4(ar, sv_array[j].v_side[1]->co, sco_b, projectMat);
}
else {
- add_v3_v3v3(sco_b, v->co, sv_array[j].dir_b);
+ add_v3_v3v3(sco_b, v->co, sv_array[j].dir_side[1]);
ED_view3d_project_float_v3_m4(ar, sco_b, sco_b, projectMat);
}
- if (sv_array[j].v_a) {
- ED_view3d_project_float_v3_m4(ar, sv_array[j].v_a->co, sco_a, projectMat);
+ if (sv_array[j].v_side[0]) {
+ ED_view3d_project_float_v3_m4(ar, sv_array[j].v_side[0]->co, sco_a, projectMat);
}
else {
- add_v3_v3v3(sco_a, v->co, sv_array[j].dir_a);
+ add_v3_v3v3(sco_a, v->co, sv_array[j].dir_side[0]);
ED_view3d_project_float_v3_m4(ar, sco_a, sco_a, projectMat);
}
/* global direction */
- d = dist_to_line_segment_v2(mval, sco_b, sco_a);
- if ((maxdist == -1.0f) ||
+ dist_sq = dist_squared_to_line_segment_v2(mval, sco_b, sco_a);
+ if ((dist_best_sq == -1.0f) ||
/* intentionally use 2d size on 3d vector */
- (d < maxdist && (len_squared_v2v2(sco_b, sco_a) > 0.1f)))
+ (dist_sq < dist_best_sq && (len_squared_v2v2(sco_b, sco_a) > 0.1f)))
{
- maxdist = d;
+ dist_best_sq = dist_sq;
sub_v3_v3v3(mval_dir, sco_b, sco_a);
}
/* per loop direction */
l_nr = sv_array[j].loop_nr;
- if (loop_maxdist[l_nr] == -1.0f || d < loop_maxdist[l_nr]) {
- loop_maxdist[l_nr] = d;
+ if (loop_maxdist[l_nr] == -1.0f || dist_sq < loop_maxdist[l_nr]) {
+ loop_maxdist[l_nr] = dist_sq;
sub_v3_v3v3(loop_dir[l_nr], sco_b, sco_a);
}
}
@@ -6128,8 +6195,8 @@ static bool createEdgeSlideVerts(TransInfo *t)
/* switch a/b if loop direction is different from global direction */
l_nr = sv_array->loop_nr;
if (dot_v3v3(loop_dir[l_nr], mval_dir) < 0.0f) {
- swap_v3_v3(sv_array->dir_a, sv_array->dir_b);
- SWAP(BMVert *, sv_array->v_a, sv_array->v_b);
+ swap_v3_v3(sv_array->dir_side[0], sv_array->dir_side[1]);
+ SWAP(BMVert *, sv_array->v_side[0], sv_array->v_side[1]);
}
}
@@ -6222,7 +6289,7 @@ static void initEdgeSlide(TransInfo *t)
t->customFree = freeEdgeSlideVerts;
/* set custom point first if you want value to be initialized by init */
- setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start);
+ calcEdgeSlideCustomPoints(t);
initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO_FLIP);
t->idx_max = 0;
@@ -6248,35 +6315,40 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven
case EKEY:
if (event->val == KM_PRESS) {
sld->is_proportional = !sld->is_proportional;
+ calcEdgeSlideCustomPoints(t);
return TREDRAW_HARD;
}
break;
case FKEY:
- {
if (event->val == KM_PRESS) {
if (sld->is_proportional == false) {
sld->flipped_vtx = !sld->flipped_vtx;
}
+ calcEdgeSlideCustomPoints(t);
+ return TREDRAW_HARD;
+ }
+ break;
+ case CKEY:
+ /* use like a modifier key */
+ if (event->val == KM_PRESS) {
+ t->flag ^= T_ALT_TRANSFORM;
+ calcEdgeSlideCustomPoints(t);
return TREDRAW_HARD;
}
break;
- }
case EVT_MODAL_MAP:
- {
switch (event->val) {
case TFM_MODAL_EDGESLIDE_DOWN:
- {
sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
- break;
- }
+ return TREDRAW_HARD;
case TFM_MODAL_EDGESLIDE_UP:
- {
sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
- break;
- }
+ return TREDRAW_HARD;
}
break;
- }
+ case MOUSEMOVE:
+ calcEdgeSlideCustomPoints(t);
+ break;
default:
break;
}
@@ -6285,23 +6357,16 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven
return TREDRAW_NOTHING;
}
-static void drawEdgeSlide(const struct bContext *C, TransInfo *t)
+static void drawEdgeSlide(TransInfo *t)
{
- if (t->mode == TFM_EDGE_SLIDE) {
- EdgeSlideData *sld = (EdgeSlideData *)t->customData;
+ if ((t->mode == TFM_EDGE_SLIDE) && t->customData) {
+ EdgeSlideData *sld = t->customData;
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+
/* Non-Prop mode */
- if (sld && sld->is_proportional == false) {
- View3D *v3d = CTX_wm_view3d(C);
- float co_a[3], co_b[3], co_mark[3];
- TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
- const float fac = (sld->perc + 1.0f) / 2.0f;
- const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
- const float guide_size = ctrl_size - 0.5f;
+ if ((sld->is_proportional == false) || (is_clamp == false)) {
+ View3D *v3d = t->view;
const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
- const int alpha_shade = -30;
-
- add_v3_v3v3(co_a, curr_sv->v_co_orig, curr_sv->dir_a);
- add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_b);
if (v3d && v3d->zbuf)
glDisable(GL_DEPTH_TEST);
@@ -6314,42 +6379,88 @@ static void drawEdgeSlide(const struct bContext *C, TransInfo *t)
glMultMatrixf(t->obedit->obmat);
- glLineWidth(line_size);
- UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
- glBegin(GL_LINES);
- if (curr_sv->v_a) {
- glVertex3fv(curr_sv->v_a->co);
- glVertex3fv(curr_sv->v_co_orig);
- }
- if (curr_sv->v_b) {
- glVertex3fv(curr_sv->v_b->co);
- glVertex3fv(curr_sv->v_co_orig);
- }
- bglEnd();
+ if (sld->is_proportional == false) {
+ float co_a[3], co_b[3], co_mark[3];
+ TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
+ const float fac = (sld->perc + 1.0f) / 2.0f;
+ const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
+ const float guide_size = ctrl_size - 0.5f;
+ const int alpha_shade = -30;
+
+ add_v3_v3v3(co_a, curr_sv->v_co_orig, curr_sv->dir_side[0]);
+ add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_side[1]);
+
+ glLineWidth(line_size);
+ UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+ glBegin(GL_LINES);
+ if (curr_sv->v_side[0]) {
+ glVertex3fv(curr_sv->v_side[0]->co);
+ glVertex3fv(curr_sv->v_co_orig);
+ }
+ if (curr_sv->v_side[1]) {
+ glVertex3fv(curr_sv->v_side[1]->co);
+ glVertex3fv(curr_sv->v_co_orig);
+ }
+ glEnd();
+ UI_ThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
+ glPointSize(ctrl_size);
+ bglBegin(GL_POINTS);
+ if (sld->flipped_vtx) {
+ if (curr_sv->v_side[1]) bglVertex3fv(curr_sv->v_side[1]->co);
+ }
+ else {
+ if (curr_sv->v_side[0]) bglVertex3fv(curr_sv->v_side[0]->co);
+ }
+ bglEnd();
- UI_ThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
- glPointSize(ctrl_size);
- bglBegin(GL_POINTS);
- if (sld->flipped_vtx) {
- if (curr_sv->v_b) bglVertex3fv(curr_sv->v_b->co);
+ UI_ThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade);
+ glPointSize(guide_size);
+ bglBegin(GL_POINTS);
+#if 0
+ interp_v3_v3v3(co_mark, co_b, co_a, fac);
+ bglVertex3fv(co_mark);
+#endif
+ interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac);
+ bglVertex3fv(co_mark);
+ bglEnd();
}
else {
- if (curr_sv->v_a) bglVertex3fv(curr_sv->v_a->co);
- }
- bglEnd();
+ if (is_clamp == false) {
+ const int side_index = sld->curr_side_unclamp;
+ TransDataEdgeSlideVert *sv;
+ int i;
+ const int alpha_shade = -160;
+
+ glLineWidth(line_size);
+ UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+ glBegin(GL_LINES);
+
+ sv = sld->sv;
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ float a[3], b[3];
+
+ if (!is_zero_v3(sv->dir_side[side_index])) {
+ copy_v3_v3(a, sv->dir_side[side_index]);
+ }
+ else {
+ copy_v3_v3(a, sv->dir_side[!side_index]);
+ }
- UI_ThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade);
- glPointSize(guide_size);
- bglBegin(GL_POINTS);
-#if 0
- interp_v3_v3v3(co_mark, co_b, co_a, fac);
- bglVertex3fv(co_mark);
-#endif
- interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac);
- bglVertex3fv(co_mark);
- bglEnd();
+ mul_v3_fl(a, 100.0f);
+ negate_v3_v3(b, a);
+ add_v3_v3(a, sv->v_co_orig);
+ add_v3_v3(b, sv->v_co_orig);
+ glVertex3fv(a);
+ glVertex3fv(b);
+ }
+ glEnd();
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
glPopMatrix();
glPopAttrib();
@@ -6372,17 +6483,30 @@ static void doEdgeSlide(TransInfo *t, float perc)
sv = svlist;
if (sld->is_proportional == true) {
- for (i = 0; i < sld->totsv; i++, sv++) {
- float vec[3];
- if (perc > 0.0f) {
- copy_v3_v3(vec, sv->dir_a);
- mul_v3_fl(vec, perc);
- add_v3_v3v3(sv->v->co, sv->v_co_orig, vec);
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+ if (is_clamp) {
+ const int side_index = (perc < 0.0f);
+ const float perc_final = fabsf(perc);
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, sv->dir_side[side_index], perc_final);
}
- else {
- copy_v3_v3(vec, sv->dir_b);
- mul_v3_fl(vec, -perc);
- add_v3_v3v3(sv->v->co, sv->v_co_orig, vec);
+
+ sld->curr_side_unclamp = side_index;
+ }
+ else {
+ const int side_index = sld->curr_side_unclamp;
+ const float perc_init = fabsf(perc) * ((sld->curr_side_unclamp == (perc < 0.0f)) ? 1 : -1);
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ float dir_flip[3];
+ float perc_final = perc_init;
+ if (!is_zero_v3(sv->dir_side[side_index])) {
+ copy_v3_v3(dir_flip, sv->dir_side[side_index]);
+ }
+ else {
+ copy_v3_v3(dir_flip, sv->dir_side[!side_index]);
+ perc_final *= -1;
+ }
+ madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, dir_flip, perc_final);
}
}
}
@@ -6392,7 +6516,7 @@ static void doEdgeSlide(TransInfo *t, float perc)
* a/b verts, this could be changed/improved so the distance is still met but the verts are moved along
* their original path (which may not be straight), however how it works now is OK and matches 2.4x - Campbell
*
- * \note len_v3v3(curr_sv->dir_a, curr_sv->dir_b)
+ * \note len_v3v3(curr_sv->dir_side[0], curr_sv->dir_side[1])
* is the same as the distance between the original vert locations, same goes for the lines below.
*/
TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
@@ -6405,8 +6529,8 @@ static void doEdgeSlide(TransInfo *t, float perc)
if (sv->edge_len > FLT_EPSILON) {
const float fac = min_ff(sv->edge_len, curr_length_perc) / sv->edge_len;
- add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_a);
- add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_b);
+ add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_side[0]);
+ add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_side[1]);
if (sld->flipped_vtx) {
interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac);
@@ -6424,44 +6548,41 @@ static void doEdgeSlide(TransInfo *t, float perc)
static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
{
char str[MAX_INFO_LEN];
+ size_t ofs = 0;
float final;
EdgeSlideData *sld = t->customData;
bool flipped = sld->flipped_vtx;
bool is_proportional = sld->is_proportional;
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+ const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
final = t->values[0];
snapGridIncrement(t, &final);
/* only do this so out of range values are not displayed */
- CLAMP(final, -1.0f, 1.0f);
+ if (is_constrained) {
+ CLAMP(final, -1.0f, 1.0f);
+ }
applyNumInput(&t->num, &final);
+ /* header string */
+ ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Edge Slide: "), MAX_INFO_LEN - ofs);
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
-
outputNumInput(&(t->num), c, &t->scene->unit);
-
- if (is_proportional) {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %s (E)ven: %s"),
- &c[0], WM_bool_as_string(!is_proportional));
- }
- else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %s (E)ven: %s, (F)lipped: %s"),
- &c[0], WM_bool_as_string(!is_proportional), WM_bool_as_string(flipped));
- }
- }
- else if (is_proportional) {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %.4f (E)ven: %s"),
- final, WM_bool_as_string(!is_proportional));
+ ofs += BLI_strncpy_rlen(str + ofs, &c[0], MAX_INFO_LEN - ofs);
}
else {
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %.4f (E)ven: %s, (F)lipped: %s"),
- final, WM_bool_as_string(!is_proportional), WM_bool_as_string(flipped));
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final);
}
-
- CLAMP(final, -1.0f, 1.0f);
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(!is_proportional));
+ if (!is_proportional) {
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
+ }
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
+ /* done with header string */
t->values[0] = final;
@@ -6485,10 +6606,20 @@ static void calcVertSlideCustomPoints(struct TransInfo *t)
{
VertSlideData *sld = t->customData;
TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index];
- const float *co_orig = sv->co_orig_2d;
- const float *co_curr = sv->co_link_orig_2d[sv->co_link_curr];
- const int mval_start[2] = {co_orig[0], co_orig[1]};
- const int mval_end[2] = {co_curr[0], co_curr[1]};
+
+ const float *co_orig_3d = sv->co_orig_3d;
+ const float *co_curr_3d = sv->co_link_orig_3d[sv->co_link_curr];
+
+ float co_curr_2d[2], co_orig_2d[2];
+
+ int mval_ofs[2], mval_start[2], mval_end[2];
+
+ ED_view3d_project_float_v2_m4(t->ar, co_orig_3d, co_orig_2d, sld->proj_mat);
+ ED_view3d_project_float_v2_m4(t->ar, co_curr_3d, co_curr_2d, sld->proj_mat);
+
+ ARRAY_SET_ITEMS(mval_ofs, t->imval[0] - co_orig_2d[0], t->imval[1] - co_orig_2d[1]);
+ ARRAY_SET_ITEMS(mval_start, co_orig_2d[0] + mval_ofs[0], co_orig_2d[1] + mval_ofs[1]);
+ ARRAY_SET_ITEMS(mval_end, co_curr_2d[0] + mval_ofs[0], co_curr_2d[1] + mval_ofs[1]);
if (sld->flipped_vtx && sld->is_proportional == false) {
setCustomPoints(t, &t->mouse, mval_start, mval_end);
@@ -6496,6 +6627,11 @@ static void calcVertSlideCustomPoints(struct TransInfo *t)
else {
setCustomPoints(t, &t->mouse, mval_end, mval_start);
}
+
+ /* setCustomPoints isn't normally changing as the mouse moves,
+ * in this case apply mouse input immediatly so we don't refresh
+ * with the value from the previous points */
+ applyMouseInput(t, &t->mouse, t->mval, t->values);
}
/**
@@ -6513,28 +6649,39 @@ static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2])
int i;
for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) {
- dist_sq = len_squared_v2v2(mval_fl, sv->co_orig_2d);
+ float co_2d[2];
+
+ ED_view3d_project_float_v2_m4(t->ar, sv->co_orig_3d, co_2d, sld->proj_mat);
+
+ dist_sq = len_squared_v2v2(mval_fl, co_2d);
if (dist_sq < dist_min_sq) {
dist_min_sq = dist_sq;
sld->curr_sv_index = i;
}
}
}
+
/**
* Run while moving the mouse to slide along the edge matching the mouse direction
*/
static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2])
{
VertSlideData *sld = t->customData;
- float mval_fl[2] = {UNPACK2(mval)};
+ float imval_fl[2] = {UNPACK2(t->imval)};
+ float mval_fl[2] = {UNPACK2(mval)};
- float dir[2];
+ float dir[3];
TransDataVertSlideVert *sv;
int i;
- /* first get the direction of the original vertex */
- sub_v2_v2v2(dir, sld->sv[sld->curr_sv_index].co_orig_2d, mval_fl);
- normalize_v2(dir);
+ /* first get the direction of the original mouse position */
+ sub_v2_v2v2(dir, imval_fl, mval_fl);
+ ED_view3d_win_to_delta(t->ar, dir, dir, t->zfac);
+
+ invert_m4_m4(t->obedit->imat, t->obedit->obmat);
+ mul_mat3_m4_v3(t->obedit->imat, dir);
+
+ normalize_v3(dir);
for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) {
if (sv->co_link_tot > 1) {
@@ -6543,11 +6690,14 @@ static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2]
int j;
for (j = 0; j < sv->co_link_tot; j++) {
- float tdir[2];
+ float tdir[3];
float dir_dot;
- sub_v2_v2v2(tdir, sv->co_orig_2d, sv->co_link_orig_2d[j]);
- normalize_v2(tdir);
- dir_dot = dot_v2v2(dir, tdir);
+
+ sub_v3_v3v3(tdir, sv->co_orig_3d, sv->co_link_orig_3d[j]);
+ project_plane_v3_v3v3(tdir, tdir, t->viewinv[2]);
+
+ normalize_v3(tdir);
+ dir_dot = dot_v3v3(dir, tdir);
if (dir_dot > dir_dot_best) {
dir_dot_best = dir_dot;
co_link_curr_best = j;
@@ -6571,32 +6721,14 @@ static bool createVertSlideVerts(TransInfo *t)
BMVert *v;
TransDataVertSlideVert *sv_array;
VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
-// View3D *v3d = NULL;
- RegionView3D *rv3d = NULL;
- ARegion *ar = t->ar;
- float projectMat[4][4];
int j;
- if (t->spacetype == SPACE_VIEW3D) {
- /* background mode support */
-// v3d = t->sa ? t->sa->spacedata.first : NULL;
- rv3d = ar ? ar->regiondata : NULL;
- }
-
slide_origdata_init_flag(t, &sld->orig_data);
sld->is_proportional = true;
sld->curr_sv_index = 0;
sld->flipped_vtx = false;
- if (!rv3d) {
- /* ok, let's try to survive this */
- unit_m4(projectMat);
- }
- else {
- ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
- }
-
j = 0;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
bool ok = false;
@@ -6640,7 +6772,6 @@ static bool createVertSlideVerts(TransInfo *t)
}
sv_array[j].co_link_orig_3d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_3d) * k, __func__);
- sv_array[j].co_link_orig_2d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_2d) * k, __func__);
sv_array[j].co_link_tot = k;
k = 0;
@@ -6648,31 +6779,9 @@ static bool createVertSlideVerts(TransInfo *t)
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
BMVert *v_other = BM_edge_other_vert(e, v);
copy_v3_v3(sv_array[j].co_link_orig_3d[k], v_other->co);
- if (ar) {
- ED_view3d_project_float_v2_m4(ar,
- sv_array[j].co_link_orig_3d[k],
- sv_array[j].co_link_orig_2d[k],
- projectMat);
- }
- else {
- copy_v2_v2(sv_array[j].co_link_orig_2d[k],
- sv_array[j].co_link_orig_3d[k]);
- }
k++;
}
}
-
- if (ar) {
- ED_view3d_project_float_v2_m4(ar,
- sv_array[j].co_orig_3d,
- sv_array[j].co_orig_2d,
- projectMat);
- }
- else {
- copy_v2_v2(sv_array[j].co_orig_2d,
- sv_array[j].co_orig_3d);
- }
-
j++;
}
}
@@ -6690,7 +6799,19 @@ static bool createVertSlideVerts(TransInfo *t)
t->customData = sld;
- if (rv3d) {
+ /* most likely will be set below */
+ unit_m4(sld->proj_mat);
+
+ if (t->spacetype == SPACE_VIEW3D) {
+ /* view vars */
+ RegionView3D *rv3d = NULL;
+ ARegion *ar = t->ar;
+
+ rv3d = ar ? ar->regiondata : NULL;
+ if (rv3d) {
+ ED_view3d_ob_project_mat_get(rv3d, t->obedit, sld->proj_mat);
+ }
+
calcVertSlideMouseActiveVert(t, t->mval);
calcVertSlideMouseActiveEdges(t, t->mval);
}
@@ -6730,7 +6851,6 @@ void freeVertSlideVerts(TransInfo *t)
TransDataVertSlideVert *sv = sld->sv;
int i = 0;
for (i = 0; i < sld->totsv; i++, sv++) {
- MEM_freeN(sv->co_link_orig_2d);
MEM_freeN(sv->co_link_orig_3d);
}
}
@@ -6797,16 +6917,13 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven
}
break;
case FKEY:
- {
if (event->val == KM_PRESS) {
sld->flipped_vtx = !sld->flipped_vtx;
calcVertSlideCustomPoints(t);
return TREDRAW_HARD;
}
break;
- }
case CKEY:
- {
/* use like a modifier key */
if (event->val == KM_PRESS) {
t->flag ^= T_ALT_TRANSFORM;
@@ -6814,23 +6931,17 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven
return TREDRAW_HARD;
}
break;
- }
#if 0
case EVT_MODAL_MAP:
- {
switch (event->val) {
case TFM_MODAL_EDGESLIDE_DOWN:
- {
sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
break;
- }
case TFM_MODAL_EDGESLIDE_UP:
- {
sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
break;
- }
}
- }
+ break;
#endif
case MOUSEMOVE:
{
@@ -6850,19 +6961,20 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven
return TREDRAW_NOTHING;
}
-static void drawVertSlide(const struct bContext *C, TransInfo *t)
+static void drawVertSlide(TransInfo *t)
{
- if (t->mode == TFM_VERT_SLIDE) {
- VertSlideData *sld = (VertSlideData *)t->customData;
+ if ((t->mode == TFM_VERT_SLIDE) && t->customData) {
+ VertSlideData *sld = t->customData;
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+
/* Non-Prop mode */
- if (sld) {
- View3D *v3d = CTX_wm_view3d(C);
+ {
+ View3D *v3d = t->view;
TransDataVertSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
TransDataVertSlideVert *sv;
const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
const int alpha_shade = -160;
- const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
int i;
if (v3d && v3d->zbuf)
@@ -6910,11 +7022,40 @@ static void drawVertSlide(const struct bContext *C, TransInfo *t)
curr_sv->co_orig_3d);
bglEnd();
+ glDisable(GL_BLEND);
+
+ /* direction from active vertex! */
+ if ((t->mval[0] != t->imval[0]) ||
+ (t->mval[1] != t->imval[1]))
+ {
+ float zfac = ED_view3d_calc_zfac(t->ar->regiondata, curr_sv->co_orig_3d, NULL);
+ float mval_ofs[2];
+ float co_dest_3d[3];
+
+ mval_ofs[0] = t->mval[0] - t->imval[0];
+ mval_ofs[1] = t->mval[1] - t->imval[1];
+
+ ED_view3d_win_to_delta(t->ar, mval_ofs, co_dest_3d, zfac);
+
+ invert_m4_m4(t->obedit->imat, t->obedit->obmat);
+ mul_mat3_m4_v3(t->obedit->imat, co_dest_3d);
+
+ add_v3_v3(co_dest_3d, curr_sv->co_orig_3d);
+
+ glLineWidth(1);
+ setlinestyle(1);
+
+ cpack(0xffffff);
+ glBegin(GL_LINES);
+ glVertex3fv(curr_sv->co_orig_3d);
+ glVertex3fv(co_dest_3d);
+
+ glEnd();
+ }
+
glPopMatrix();
glPopAttrib();
- glDisable(GL_BLEND);
-
if (v3d && v3d->zbuf)
glEnable(GL_DEPTH_TEST);
}
@@ -7360,40 +7501,28 @@ static void headerSeqSlide(TransInfo *t, const float val[2], char str[MAX_INFO_L
WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
}
-static void applySeqSlideValue(TransInfo *t, const float val[2], int frame)
+static void applySeqSlideValue(TransInfo *t, const float val[2])
{
TransData *td = t->data;
int i;
- TransSeq *ts = t->customData;
for (i = 0; i < t->total; i++, td++) {
- float tvec[2];
-
if (td->flag & TD_NOACTION)
break;
if (td->flag & TD_SKIP)
continue;
- copy_v2_v2(tvec, val);
-
- mul_v2_fl(tvec, td->factor);
-
- if (t->modifiers & MOD_SNAP_INVERT) {
- td->loc[0] = frame + td->factor * (td->iloc[0] - ts->min);
- }
- else {
- td->loc[0] = td->iloc[0] + tvec[0];
- }
-
- td->loc[1] = td->iloc[1] + tvec[1];
+ madd_v2_v2v2fl(td->loc, td->iloc, val, td->factor);
}
}
static void applySeqSlide(TransInfo *t, const int mval[2])
{
char str[MAX_INFO_LEN];
- int snap_frame = 0;
+
+ snapSequenceBounds(t, mval);
+
if (t->con.mode & CON_APPLY) {
float pvec[3] = {0.0f, 0.0f, 0.0f};
float tvec[3];
@@ -7401,7 +7530,6 @@ static void applySeqSlide(TransInfo *t, const int mval[2])
copy_v3_v3(t->values, tvec);
}
else {
- snap_frame = snapSequenceBounds(t, mval);
// snapGridIncrement(t, t->values);
applyNumInput(&t->num, t->values);
}
@@ -7410,7 +7538,7 @@ static void applySeqSlide(TransInfo *t, const int mval[2])
t->values[1] = floor(t->values[1] + 0.5f);
headerSeqSlide(t, t->values, str);
- applySeqSlideValue(t, t->values, snap_frame);
+ applySeqSlideValue(t, t->values);
recalcData(t);
@@ -7573,6 +7701,7 @@ static void initTimeTranslate(TransInfo *t)
static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN])
{
char tvec[NUM_STR_REP_LEN * 3];
+ int ofs = 0;
/* if numeric input is active, use results from that, otherwise apply snapping to result */
if (hasNumInput(&t->num)) {
@@ -7608,10 +7737,14 @@ static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN])
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val);
}
- BLI_snprintf(str, MAX_INFO_LEN, IFACE_("DeltaX: %s"), &tvec[0]);
+ ofs += BLI_snprintf(str, MAX_INFO_LEN, IFACE_("DeltaX: %s"), &tvec[0]);
+
+ if (t->flag & T_PROP_EDIT_ALL) {
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ }
}
-static void applyTimeTranslateValue(TransInfo *t, float UNUSED(sval))
+static void applyTimeTranslateValue(TransInfo *t)
{
TransData *td = t->data;
TransData2D *td2d = t->data2d;
@@ -7645,7 +7778,7 @@ static void applyTimeTranslateValue(TransInfo *t, float UNUSED(sval))
}
val = BKE_nla_tweakedit_remap(adt, td->ival, NLATIME_CONVERT_MAP);
- val += deltax;
+ val += deltax * td->factor;
*(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP);
}
else {
@@ -7669,15 +7802,17 @@ static void applyTimeTranslateValue(TransInfo *t, float UNUSED(sval))
static void applyTimeTranslate(TransInfo *t, const int mval[2])
{
View2D *v2d = (View2D *)t->view;
- float cval[2], sval[2];
char str[MAX_INFO_LEN];
/* calculate translation amount from mouse movement - in 'time-grid space' */
- UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]);
- UI_view2d_region_to_view(v2d, t->imval[0], t->imval[0], &sval[0], &sval[1]);
+ if (t->flag & T_MODAL) {
+ float cval[2], sval[2];
+ UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]);
+ UI_view2d_region_to_view(v2d, t->imval[0], t->imval[0], &sval[0], &sval[1]);
- /* we only need to calculate effect for time (applyTimeTranslate only needs that) */
- t->values[0] = cval[0] - sval[0];
+ /* we only need to calculate effect for time (applyTimeTranslate only needs that) */
+ t->values[0] = cval[0] - sval[0];
+ }
/* handle numeric-input stuff */
t->vec[0] = t->values[0];
@@ -7685,7 +7820,7 @@ static void applyTimeTranslate(TransInfo *t, const int mval[2])
t->values[0] = t->vec[0];
headerTimeTranslate(t, str);
- applyTimeTranslateValue(t, sval[0]);
+ applyTimeTranslateValue(t);
recalcData(t);
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index bc12e16bf44..33b4e2b5448 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -39,9 +39,6 @@
#include "DNA_listBase.h"
-#include "BLI_smallhash.h"
-#include "BKE_editmesh.h"
-
/* ************************** Types ***************************** */
struct TransInfo;
@@ -216,10 +213,10 @@ typedef struct TransDataEdgeSlideVert {
float edge_len;
- struct BMVert *v_a, *v_b;
+ struct BMVert *v_side[2];
/* add origvert.co to get the original locations */
- float dir_a[3], dir_b[3];
+ float dir_side[2][3];
int loop_nr;
} TransDataEdgeSlideVert;
@@ -256,19 +253,20 @@ typedef struct EdgeSlideData {
bool flipped_vtx;
int curr_sv_index;
+
+ /** when un-clamped - use this index: #TransDataEdgeSlideVert.dir_side */
+ int curr_side_unclamp;
} EdgeSlideData;
typedef struct TransDataVertSlideVert {
/* TransDataGenericSlideVert */
- BMVert *v;
+ struct BMVert *v;
struct LinkNode **cd_loop_groups;
float co_orig_3d[3];
/* end generic */
- float co_orig_2d[2];
float (*co_link_orig_3d)[3];
- float (*co_link_orig_2d)[2];
int co_link_tot;
int co_link_curr;
} TransDataVertSlideVert;
@@ -287,6 +285,9 @@ typedef struct VertSlideData {
bool flipped_vtx;
int curr_sv_index;
+
+ /* result of ED_view3d_ob_project_mat_get */
+ float proj_mat[4][4];
} VertSlideData;
typedef struct BoneInitData {
@@ -566,6 +567,7 @@ void flushTransGraphData(TransInfo *t);
void remake_graph_transdata(TransInfo *t, struct ListBase *anim_data);
void flushTransUVs(TransInfo *t);
void flushTransParticles(TransInfo *t);
+void flushTransStrands(TransInfo *t);
bool clipUVTransform(TransInfo *t, float vec[2], const bool resize);
void clipUVData(TransInfo *t);
void flushTransNodes(TransInfo *t);
@@ -634,7 +636,7 @@ typedef enum {
void snapGridIncrement(TransInfo *t, float *val);
void snapGridIncrementAction(TransInfo *t, float *val, GearsType action);
-int snapSequenceBounds(TransInfo *t, const int mval[2]);
+void snapSequenceBounds(TransInfo *t, const int mval[2]);
bool activeSnap(TransInfo *t);
bool validSnap(TransInfo *t);
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index ccb81c7342b..03d626fe179 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -46,6 +46,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_string.h"
+#include "BLI_rect.h"
#include "BKE_context.h"
@@ -757,12 +758,22 @@ void drawPropCircle(const struct bContext *C, TransInfo *t)
ED_space_image_get_aspect(t->sa->spacedata.first, &aspx, &aspy);
}
else if (t->options & CTX_PAINT_CURVE) {
- aspx = aspy = 1.0;
+ aspx = aspy = 1.0f;
}
else {
ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
}
- glScalef(1.0f / aspx, 1.0f / aspy, 1.0);
+ glScalef(1.0f / aspx, 1.0f / aspy, 1.0f);
+ }
+ else if (ELEM(t->spacetype, SPACE_IPO, SPACE_ACTION)) {
+ /* only scale y */
+ rcti *mask = &t->ar->v2d.mask;
+ rctf *datamask = &t->ar->v2d.cur;
+ float xsize = BLI_rctf_size_x(datamask);
+ float ysize = BLI_rctf_size_y(datamask);
+ float xmask = BLI_rcti_size_x(mask);
+ float ymask = BLI_rcti_size_y(mask);
+ glScalef(1.0f, (ysize / xsize) * (xmask / ymask), 1.0f);
}
depth_test_enabled = glIsEnabled(GL_DEPTH_TEST);
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 3fbc4f2c107..aa0d86e5b3f 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -31,6 +31,7 @@
#include <string.h>
#include <math.h>
+#include <limits.h>
#include "DNA_anim_types.h"
#include "DNA_brush_types.h"
@@ -58,6 +59,7 @@
#include "BLI_linklist_stack.h"
#include "BLI_string.h"
#include "BLI_bitmap.h"
+#include "BLI_rect.h"
#include "BKE_DerivedMesh.h"
#include "BKE_action.h"
@@ -67,6 +69,7 @@
#include "BKE_crazyspace.h"
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
+#include "BKE_editstrands.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
@@ -340,20 +343,20 @@ static void createTransEdge(TransInfo *t)
BMIter iter;
float mtx[3][3], smtx[3][3];
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
int cd_edge_float_offset;
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) countsel++;
- if (propmode) count++;
+ if (is_prop_edit) count++;
}
}
if (countsel == 0)
return;
- if (propmode) {
+ if (is_prop_edit) {
t->total = count;
}
else {
@@ -379,7 +382,7 @@ static void createTransEdge(TransInfo *t)
BLI_assert(cd_edge_float_offset != -1);
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && (BM_elem_flag_test(eed, BM_ELEM_SELECT) || propmode)) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && (BM_elem_flag_test(eed, BM_ELEM_SELECT) || is_prop_edit)) {
float *fl_ptr;
/* need to set center for center calculations */
mid_v3_v3v3(td->center, eed->v1->co, eed->v2->co);
@@ -1332,18 +1335,18 @@ static void createTransMBallVerts(TransInfo *t)
TransDataExtension *tx;
float mtx[3][3], smtx[3][3];
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
/* count totals */
for (ml = mb->editelems->first; ml; ml = ml->next) {
if (ml->flag & SELECT) countsel++;
- if (propmode) count++;
+ if (is_prop_edit) count++;
}
/* note: in prop mode we need at least 1 selected */
if (countsel == 0) return;
- if (propmode) t->total = count;
+ if (is_prop_edit) t->total = count;
else t->total = countsel;
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(MBall EditMode)");
@@ -1353,7 +1356,7 @@ static void createTransMBallVerts(TransInfo *t)
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
for (ml = mb->editelems->first; ml; ml = ml->next) {
- if (propmode || (ml->flag & SELECT)) {
+ if (is_prop_edit || (ml->flag & SELECT)) {
td->loc = &ml->x;
copy_v3_v3(td->iloc, td->loc);
copy_v3_v3(td->center, td->loc);
@@ -1466,7 +1469,7 @@ static void createTransCurveVerts(TransInfo *t)
float mtx[3][3], smtx[3][3];
int a;
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
short hide_handles = (cu->drawflag & CU_HIDE_HANDLES);
ListBase *nurbs;
@@ -1481,13 +1484,13 @@ static void createTransCurveVerts(TransInfo *t)
if (bezt->hide == 0) {
if (hide_handles) {
if (bezt->f2 & SELECT) countsel += 3;
- if (propmode) count += 3;
+ if (is_prop_edit) count += 3;
}
else {
if (bezt->f1 & SELECT) countsel++;
if (bezt->f2 & SELECT) countsel++;
if (bezt->f3 & SELECT) countsel++;
- if (propmode) count += 3;
+ if (is_prop_edit) count += 3;
}
}
}
@@ -1495,7 +1498,7 @@ static void createTransCurveVerts(TransInfo *t)
else {
for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
if (bp->hide == 0) {
- if (propmode) count++;
+ if (is_prop_edit) count++;
if (bp->f1 & SELECT) countsel++;
}
}
@@ -1504,7 +1507,7 @@ static void createTransCurveVerts(TransInfo *t)
/* note: in prop mode we need at least 1 selected */
if (countsel == 0) return;
- if (propmode) t->total = count;
+ if (is_prop_edit) t->total = count;
else t->total = countsel;
t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Curve EditMode)");
@@ -1539,7 +1542,7 @@ static void createTransCurveVerts(TransInfo *t)
}
}
- if (propmode ||
+ if (is_prop_edit ||
((bezt->f2 & SELECT) && hide_handles) ||
((bezt->f1 & SELECT) && hide_handles == 0))
{
@@ -1573,7 +1576,7 @@ static void createTransCurveVerts(TransInfo *t)
}
/* This is the Curve Point, the other two are handles */
- if (propmode || (bezt->f2 & SELECT)) {
+ if (is_prop_edit || (bezt->f2 & SELECT)) {
copy_v3_v3(td->iloc, bezt->vec[1]);
td->loc = bezt->vec[1];
copy_v3_v3(td->center, td->loc);
@@ -1609,7 +1612,7 @@ static void createTransCurveVerts(TransInfo *t)
count++;
tail++;
}
- if (propmode ||
+ if (is_prop_edit ||
((bezt->f2 & SELECT) && hide_handles) ||
((bezt->f3 & SELECT) && hide_handles == 0))
{
@@ -1646,12 +1649,12 @@ static void createTransCurveVerts(TransInfo *t)
(void)hdata; /* quiet warning */
}
- else if (propmode && head != tail) {
+ else if (is_prop_edit && head != tail) {
calc_distanceCurveVerts(head, tail - 1);
head = tail;
}
}
- if (propmode && head != tail)
+ if (is_prop_edit && head != tail)
calc_distanceCurveVerts(head, tail - 1);
/* TODO - in the case of tilt and radius we can also avoid allocating the initTransDataCurveHandles
@@ -1666,7 +1669,7 @@ static void createTransCurveVerts(TransInfo *t)
head = tail = td;
for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
if (bp->hide == 0) {
- if (propmode || (bp->f1 & SELECT)) {
+ if (is_prop_edit || (bp->f1 & SELECT)) {
copy_v3_v3(td->iloc, bp->vec);
td->loc = bp->vec;
copy_v3_v3(td->center, td->loc);
@@ -1691,12 +1694,12 @@ static void createTransCurveVerts(TransInfo *t)
tail++;
}
}
- else if (propmode && head != tail) {
+ else if (is_prop_edit && head != tail) {
calc_distanceCurveVerts(head, tail - 1);
head = tail;
}
}
- if (propmode && head != tail)
+ if (is_prop_edit && head != tail)
calc_distanceCurveVerts(head, tail - 1);
}
}
@@ -1712,14 +1715,14 @@ static void createTransLatticeVerts(TransInfo *t)
float mtx[3][3], smtx[3][3];
int a;
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
bp = latt->def;
a = latt->pntsu * latt->pntsv * latt->pntsw;
while (a--) {
if (bp->hide == 0) {
if (bp->f1 & SELECT) countsel++;
- if (propmode) count++;
+ if (is_prop_edit) count++;
}
bp++;
}
@@ -1727,7 +1730,7 @@ static void createTransLatticeVerts(TransInfo *t)
/* note: in prop mode we need at least 1 selected */
if (countsel == 0) return;
- if (propmode) t->total = count;
+ if (is_prop_edit) t->total = count;
else t->total = countsel;
t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Lattice EditMode)");
@@ -1738,7 +1741,7 @@ static void createTransLatticeVerts(TransInfo *t)
bp = latt->def;
a = latt->pntsu * latt->pntsv * latt->pntsw;
while (a--) {
- if (propmode || (bp->f1 & SELECT)) {
+ if (is_prop_edit || (bp->f1 & SELECT)) {
if (bp->hide == 0) {
copy_v3_v3(td->iloc, bp->vec);
td->loc = bp->vec;
@@ -1779,7 +1782,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
float mat[4][4];
int i, k, transformparticle;
int count = 0, hasselected = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
if (edit == NULL || t->settings->particle.selectmode == SCE_SELECT_PATH) return;
@@ -1801,7 +1804,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
hasselected = 1;
transformparticle = 1;
}
- else if (propmode)
+ else if (is_prop_edit)
transformparticle = 1;
}
}
@@ -1851,7 +1854,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
if (key->flag & PEK_SELECT)
td->flag |= TD_SELECTED;
- else if (!propmode)
+ else if (!is_prop_edit)
td->flag |= TD_SKIP;
unit_m3(td->mtx);
@@ -1880,7 +1883,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
tx++;
tail++;
}
- if (propmode && head != tail)
+ if (is_prop_edit && head != tail)
calc_distanceCurveVerts(head, tail - 1);
}
}
@@ -1896,7 +1899,8 @@ void flushTransParticles(TransInfo *t)
PTCacheEditKey *key;
TransData *td;
float mat[4][4], imat[4][4], co[3];
- int i, k, propmode = t->flag & T_PROP_EDIT;
+ int i, k;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
if (psys)
psmd = psys_get_modifier(ob, psys);
@@ -1917,7 +1921,7 @@ void flushTransParticles(TransInfo *t)
/* optimization for proportional edit */
- if (!propmode || !compare_v3v3(key->co, co, 0.0001f)) {
+ if (!is_prop_edit || !compare_v3v3(key->co, co, 0.0001f)) {
copy_v3_v3(key->co, co);
point->flag |= PEP_EDIT_RECALC;
}
@@ -1930,6 +1934,211 @@ void flushTransParticles(TransInfo *t)
PE_update_object(scene, OBACT, 1);
}
+
+/* ******************* hair edit **************** */
+
+static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float *dists);
+static struct TransIslandData *bmesh_islands_info_calc(BMesh *bm, short selectmode, int *r_island_tot, int **r_island_vert_map);
+
+static void StrandVertsToTransData(TransInfo *t, TransData *td,
+ BMEditStrands *UNUSED(edit), BMVert *eve, const float nor[3], const float tang[3],
+ struct TransIslandData *v_island)
+{
+ BLI_assert(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) == 0);
+
+ td->flag = 0;
+ td->loc = eve->co;
+ copy_v3_v3(td->iloc, td->loc);
+
+ if (v_island) {
+ copy_v3_v3(td->center, v_island->co);
+ copy_m3_m3(td->axismtx, v_island->axismtx);
+ }
+ else if (t->around == V3D_LOCAL) {
+ copy_v3_v3(td->center, td->loc);
+ createSpaceNormalTangent(td->axismtx, nor, tang);
+ }
+ else {
+ copy_v3_v3(td->center, td->loc);
+
+ /* Setting normals */
+ copy_v3_v3(td->axismtx[2], nor);
+ td->axismtx[0][0] =
+ td->axismtx[0][1] =
+ td->axismtx[0][2] =
+ td->axismtx[1][0] =
+ td->axismtx[1][1] =
+ td->axismtx[1][2] = 0.0f;
+ }
+
+ td->ext = NULL;
+ td->val = NULL;
+ td->extra = NULL;
+}
+
+static void createTransStrandVerts(TransInfo *t)
+{
+ Scene *scene = t->scene;
+ Object *ob = OBACT;
+ BMEditStrands *edit = BKE_editstrands_from_object(ob);
+ BMesh *bm = edit->bm;
+ TransData *tob = NULL;
+ BMVert *eve;
+ BMIter iter;
+ float mtx[3][3], smtx[3][3];
+ float *dists = NULL;
+ int a;
+ int propmode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
+ int mirror = 0;
+
+ struct TransIslandData *island_info = NULL;
+ int island_info_tot;
+ int *island_vert_map = NULL;
+
+ if (t->flag & T_MIRROR) {
+#if 0 // TODO mirror relies on EDBM functions which don't have an equivalent for editstrands yet
+ EDBM_verts_mirror_cache_begin(em, 0, false, (t->flag & T_PROP_EDIT) == 0, false);
+ mirror = 1;
+#endif
+ }
+
+ /* quick check if we can transform */
+ /* note: in prop mode we need at least 1 selected */
+ if (bm->totvertsel == 0) {
+ goto cleanup;
+ }
+
+ if (propmode) {
+ unsigned int count = 0;
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ count++;
+ }
+ }
+
+ t->total = count;
+
+ /* allocating scratch arrays */
+ if (propmode & T_PROP_CONNECTED)
+ dists = MEM_mallocN(bm->totvert * sizeof(float), "scratch nears");
+ }
+ else {
+ t->total = bm->totvertsel;
+ }
+
+ tob = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Strands EditMode)");
+
+ copy_m3_m4(mtx, ob->obmat);
+ /* we use a pseudoinverse so that when one of the axes is scaled to 0,
+ * matrix inversion still works and we can still moving along the other */
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+
+ if (propmode & T_PROP_CONNECTED) {
+ editmesh_set_connectivity_distance(bm, mtx, dists);
+ }
+
+ if (t->around == V3D_LOCAL) {
+ island_info = bmesh_islands_info_calc(edit->bm, SCE_SELECT_VERTEX, &island_info_tot, &island_vert_map);
+ }
+
+ /* find out which half we do */
+ if (mirror) {
+#if 0 // TODO
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve->co[0] != 0.0f) {
+ if (eve->co[0] < 0.0f) {
+ t->mirror = -1;
+ mirror = -1;
+ }
+ break;
+ }
+ }
+#endif
+ }
+
+ t->customData = BKE_editstrands_get_locations(edit);
+ t->flag |= T_FREE_CUSTOMDATA;
+
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ if (propmode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ struct TransIslandData *v_island = (island_info && island_vert_map[a] != -1) ?
+ &island_info[island_vert_map[a]] : NULL;
+ /* XXX TODO calculate normal and tangent along the strand */
+ float nor[3], tang[3];
+ nor[0] = 0.0f; nor[1] = 0.0f; nor[2] = 1.0f;
+ tang[0] = 0.0f; tang[1] = 1.0f; tang[2] = 0.0f;
+
+ StrandVertsToTransData(t, tob, edit, eve, nor, tang, v_island);
+
+ /* selected */
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT))
+ tob->flag |= TD_SELECTED;
+
+ if (propmode) {
+ if (propmode & T_PROP_CONNECTED) {
+ tob->dist = dists[a];
+ }
+ else {
+ tob->flag |= TD_NOTCONNECTED;
+ tob->dist = FLT_MAX;
+ }
+ }
+
+ copy_m3_m3(tob->smtx, smtx);
+ copy_m3_m3(tob->mtx, mtx);
+
+ /* Mirror? */
+ if ((mirror > 0 && tob->iloc[0] > 0.0f) || (mirror < 0 && tob->iloc[0] < 0.0f)) {
+#if 0 // TODO
+ BMVert *vmir = EDBM_verts_mirror_get(em, eve);
+ if (vmir && vmir != eve) {
+ tob->extra = vmir;
+ }
+#endif
+ }
+ tob++;
+ }
+ }
+ }
+
+ if (island_info) {
+ MEM_freeN(island_info);
+ MEM_freeN(island_vert_map);
+ }
+
+ if (mirror != 0) {
+#if 0 // TODO
+ tob = t->data;
+ for (a = 0; a < t->total; a++, tob++) {
+ if (ABS(tob->loc[0]) <= 0.00001f) {
+ tob->flag |= TD_MIRROR_EDGE;
+ }
+ }
+#endif
+ }
+
+cleanup:
+ if (dists)
+ MEM_freeN(dists);
+
+ if (t->flag & T_MIRROR) {
+#if 0 // TODO
+ EDBM_verts_mirror_cache_end(em);
+#endif
+ }
+}
+
+void flushTransStrands(TransInfo *t)
+{
+ Scene *scene = t->scene;
+ Object *ob = OBACT;
+ BMEditStrands *edit = BKE_editstrands_from_object(ob);
+ BMEditStrandsLocations origlocs = t->customData;
+
+ BKE_editstrands_solve_constraints(ob, edit, origlocs);
+}
+
/* ********************* mesh ****************** */
static bool bmesh_test_dist_add(BMVert *v, BMVert *v_other,
@@ -1975,17 +2184,19 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
int i;
BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ float dist;
BM_elem_index_set(v, i); /* set_inline */
BM_elem_flag_disable(v, BM_ELEM_TAG);
if (BM_elem_flag_test(v, BM_ELEM_SELECT) == 0 || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
- dists[i] = FLT_MAX;
+ dist = FLT_MAX;
}
else {
BLI_LINKSTACK_PUSH(queue, v);
-
- dists[i] = 0.0f;
+ dist = 0.0f;
}
+
+ dists[i] = dists_prev[i] = dist;
}
bm->elem_index_dirty &= ~BM_VERT;
}
@@ -1994,55 +2205,77 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
BMVert *v;
LinkNode *lnk;
+ /* this is correct but slow to do each iteration,
+ * instead sync the dist's while clearing BM_ELEM_TAG (below) */
+#if 0
memcpy(dists_prev, dists, sizeof(float) * bm->totvert);
+#endif
while ((v = BLI_LINKSTACK_POP(queue))) {
- /* quick checks */
- bool has_edges = (v->e != NULL);
- bool has_faces = false;
+ BLI_assert(dists[BM_elem_index_get(v)] != FLT_MAX);
/* connected edge-verts */
- if (has_edges) {
- BMIter iter;
- BMEdge *e;
+ if (v->e != NULL) {
+ BMEdge *e_iter, *e_first;
+
+ e_iter = e_first = v->e;
+
+ /* would normally use BM_EDGES_OF_VERT, but this runs so often,
+ * its faster to iterate on the data directly */
+ do {
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- has_faces |= (BM_edge_is_wire(e) == false);
+ if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == 0) {
- if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == 0) {
- BMVert *v_other = BM_edge_other_vert(e, v);
+ /* edge distance */
+ BMVert *v_other = BM_edge_other_vert(e_iter, v);
if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) {
if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
BM_elem_flag_enable(v_other, BM_ELEM_TAG);
BLI_LINKSTACK_PUSH(queue_next, v_other);
}
}
- }
- }
- }
-
- /* imaginary edge diagonally across quad */
- if (has_faces) {
- BMIter iter;
- BMLoop *l;
- BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
- if ((BM_elem_flag_test(l->f, BM_ELEM_HIDDEN) == 0) && (l->f->len == 4)) {
- BMVert *v_other = l->next->next->v;
- if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) {
- if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
- BM_elem_flag_enable(v_other, BM_ELEM_TAG);
- BLI_LINKSTACK_PUSH(queue_next, v_other);
- }
+ /* face distance */
+ if (e_iter->l) {
+ BMLoop *l_iter_radial, *l_first_radial;
+ /**
+ * imaginary edge diagonally across quad,
+ * \note, this takes advantage of the rules of winding that we
+ * know 2 or more of a verts edges wont reference the same face twice.
+ * Also, if the edge is hidden, the face will be hidden too.
+ */
+ l_iter_radial = l_first_radial = e_iter->l;
+
+ do {
+ if ((l_iter_radial->v == v) &&
+ (l_iter_radial->f->len == 4) &&
+ (BM_elem_flag_test(l_iter_radial->f, BM_ELEM_HIDDEN) == 0))
+ {
+ BMVert *v_other = l_iter_radial->next->next->v;
+ if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) {
+ if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
+ BM_elem_flag_enable(v_other, BM_ELEM_TAG);
+ BLI_LINKSTACK_PUSH(queue_next, v_other);
+ }
+ }
+ }
+ } while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial);
}
}
- }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
}
}
+
/* clear for the next loop */
for (lnk = queue_next; lnk; lnk = lnk->next) {
- BM_elem_flag_disable((BMVert *)lnk->link, BM_ELEM_TAG);
+ BMVert *v = lnk->link;
+ const int i = BM_elem_index_get(v);
+
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+
+ /* keep in sync, avoid having to do full memcpy each iteration */
+ dists_prev[i] = dists[i];
}
BLI_LINKSTACK_SWAP(queue, queue_next);
@@ -2058,9 +2291,8 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
MEM_freeN(dists_prev);
}
-static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em, int *r_island_tot, int **r_island_vert_map)
+static struct TransIslandData *bmesh_islands_info_calc(BMesh *bm, short selectmode, int *r_island_tot, int **r_island_vert_map)
{
- BMesh *bm = em->bm;
struct TransIslandData *trans_islands;
char htype;
char itype;
@@ -2074,7 +2306,7 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em, int *r
int *vert_map;
- if (em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
+ if (selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totedgesel, __func__);
group_tot = BM_mesh_calc_edge_groups(bm, groups_array, &group_index,
NULL, NULL,
@@ -2100,7 +2332,7 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em, int *r
vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__);
/* we shouldn't need this, but with incorrect selection flushing
* its possible we have a selected vertex thats not in a face, for now best not crash in that case. */
- fill_vn_i(vert_map, bm->totvert, -1);
+ copy_vn_i(vert_map, bm->totvert, -1);
BM_mesh_elem_table_ensure(bm, htype);
ele_array = (htype == BM_FACE) ? (void **)bm->ftable : (void **)bm->etable;
@@ -2260,7 +2492,7 @@ static void createTransEditVerts(TransInfo *t)
float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
float *dists = NULL;
int a;
- int propmode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
+ const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
int mirror = 0;
int cd_vert_bweight_offset = -1;
bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
@@ -2300,7 +2532,7 @@ static void createTransEditVerts(TransInfo *t)
cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
}
- if (propmode) {
+ if (prop_mode) {
unsigned int count = 0;
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
@@ -2311,7 +2543,7 @@ static void createTransEditVerts(TransInfo *t)
t->total = count;
/* allocating scratch arrays */
- if (propmode & T_PROP_CONNECTED)
+ if (prop_mode & T_PROP_CONNECTED)
dists = MEM_mallocN(em->bm->totvert * sizeof(float), "scratch nears");
}
else {
@@ -2333,12 +2565,12 @@ static void createTransEditVerts(TransInfo *t)
* matrix inversion still works and we can still moving along the other */
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
- if (propmode & T_PROP_CONNECTED) {
+ if (prop_mode & T_PROP_CONNECTED) {
editmesh_set_connectivity_distance(em->bm, mtx, dists);
}
if (t->around == V3D_LOCAL) {
- island_info = editmesh_islands_info_calc(em, &island_info_tot, &island_vert_map);
+ island_info = bmesh_islands_info_calc(em->bm, em->selectmode, &island_info_tot, &island_vert_map);
}
/* detect CrazySpace [tm] */
@@ -2362,7 +2594,7 @@ static void createTransEditVerts(TransInfo *t)
{
mappedcos = BKE_crazyspace_get_mapped_editverts(t->scene, t->obedit);
quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats");
- BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !propmode);
+ BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode);
if (mappedcos)
MEM_freeN(mappedcos);
}
@@ -2387,7 +2619,7 @@ static void createTransEditVerts(TransInfo *t)
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- if (propmode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
struct TransIslandData *v_island = (island_info && island_vert_map[a] != -1) ?
&island_info[island_vert_map[a]] : NULL;
float *bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) : NULL;
@@ -2400,8 +2632,8 @@ static void createTransEditVerts(TransInfo *t)
if (BM_elem_flag_test(eve, BM_ELEM_SELECT))
tob->flag |= TD_SELECTED;
- if (propmode) {
- if (propmode & T_PROP_CONNECTED) {
+ if (prop_mode) {
+ if (prop_mode & T_PROP_CONNECTED) {
tob->dist = dists[a];
}
else {
@@ -2706,15 +2938,15 @@ static void createTransUVs(bContext *C, TransInfo *t)
UvElementMap *elementmap = NULL;
BLI_bitmap *island_enabled = NULL;
int count = 0, countsel = 0, count_rejected = 0;
- const bool propmode = (t->flag & T_PROP_EDIT) != 0;
- const bool propconnected = (t->flag & T_PROP_CONNECTED) != 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
if (!ED_space_image_show_uvedit(sima, t->obedit)) return;
/* count */
- if (propconnected) {
+ if (is_prop_connected) {
/* create element map with island information */
if (ts->uv_flag & UV_SYNC_SELECTION) {
elementmap = BM_uv_element_map_create(em->bm, false, true);
@@ -2738,14 +2970,14 @@ static void createTransUVs(bContext *C, TransInfo *t)
if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
countsel++;
- if (propconnected) {
+ if (is_prop_connected) {
UvElement *element = BM_uv_element_get(elementmap, efa, l);
BLI_BITMAP_ENABLE(island_enabled, element->island);
}
}
- if (propmode) {
+ if (is_prop_edit) {
count++;
}
}
@@ -2753,13 +2985,13 @@ static void createTransUVs(bContext *C, TransInfo *t)
/* note: in prop mode we need at least 1 selected */
if (countsel == 0) {
- if (propconnected) {
+ if (is_prop_connected) {
MEM_freeN(island_enabled);
}
return;
}
- t->total = (propmode) ? count : countsel;
+ t->total = (is_prop_edit) ? count : countsel;
t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(UV Editing)");
/* for each 2d uv coord a 3d vector is allocated, so that they can be
* treated just as if they were 3d verts */
@@ -2776,10 +3008,10 @@ static void createTransUVs(bContext *C, TransInfo *t)
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (!propmode && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
+ if (!is_prop_edit && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
continue;
- if (propconnected) {
+ if (is_prop_connected) {
UvElement *element = BM_uv_element_get(elementmap, efa, l);
if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
count_rejected++;
@@ -2792,7 +3024,7 @@ static void createTransUVs(bContext *C, TransInfo *t)
}
}
- if (propconnected) {
+ if (is_prop_connected) {
t->total -= count_rejected;
BM_uv_element_map_free(elementmap);
MEM_freeN(island_enabled);
@@ -3307,76 +3539,90 @@ static void posttrans_action_clean(bAnimContext *ac, bAction *act)
/* ----------------------------- */
/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_fcurve_keys(FCurve *fcu, char side, float cfra)
+static int count_fcurve_keys(FCurve *fcu, char side, float cfra, bool is_prop_edit)
{
BezTriple *bezt;
- int i, count = 0;
+ int i, count = 0, count_all = 0;
if (ELEM(NULL, fcu, fcu->bezt))
return count;
/* only include points that occur on the right side of cfra */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
- if (bezt->f2 & SELECT) {
+ if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
/* no need to adjust the handle selection since they are assumed
* selected (like graph editor with SIPO_NOHANDLES) */
- if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
- count += 1;
- }
+ if (bezt->f2 & SELECT)
+ count++;
+
+ count_all++;
}
}
- return count;
+ if (is_prop_edit && count > 0)
+ return count_all;
+ else return count;
}
/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra)
+static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra, bool is_prop_edit)
{
bGPDframe *gpf;
- int count = 0;
+ int count = 0, count_all = 0;
if (gpl == NULL)
return count;
/* only include points that occur on the right side of cfra */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (gpf->flag & GP_FRAME_SELECT) {
- if (FrameOnMouseSide(side, (float)gpf->framenum, cfra))
+ if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
+ if (gpf->flag & GP_FRAME_SELECT)
count++;
+ count_all++;
}
}
- return count;
+ if (is_prop_edit && count > 0)
+ return count_all;
+ else
+ return count;
}
/* fully select selected beztriples, but only include if it's on the right side of cfra */
-static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra)
+static int count_masklayer_frames(MaskLayer *masklay, char side, float cfra, bool is_prop_edit)
{
MaskLayerShape *masklayer_shape;
- int count = 0;
+ int count = 0, count_all = 0;
if (masklay == NULL)
return count;
/* only include points that occur on the right side of cfra */
for (masklayer_shape = masklay->splines_shapes.first; masklayer_shape; masklayer_shape = masklayer_shape->next) {
- if (masklayer_shape->flag & MASK_SHAPE_SELECT) {
- if (FrameOnMouseSide(side, (float)masklayer_shape->frame, cfra))
+ if (FrameOnMouseSide(side, (float)masklayer_shape->frame, cfra)) {
+ if (masklayer_shape->flag & MASK_SHAPE_SELECT)
count++;
+ count_all++;
}
}
- return count;
+ if (is_prop_edit && count > 0)
+ return count_all;
+ else
+ return count;
}
/* This function assigns the information to transdata */
-static void TimeToTransData(TransData *td, float *time, AnimData *adt)
+static void TimeToTransData(TransData *td, float *time, AnimData *adt, float ypos)
{
/* memory is calloc'ed, so that should zero everything nicely for us */
td->val = time;
td->ival = *(time);
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
/* store the AnimData where this keyframe exists as a keyframe of the
* active action as td->extra.
*/
@@ -3390,7 +3636,7 @@ static void TimeToTransData(TransData *td, float *time, AnimData *adt)
* The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
* on the named side are used.
*/
-static TransData *ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FCurve *fcu, AnimData *adt, char side, float cfra)
+static TransData *ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FCurve *fcu, AnimData *adt, char side, float cfra, bool is_prop_edit, float ypos)
{
BezTriple *bezt;
TransData2D *td2d = *td2dv;
@@ -3401,11 +3647,14 @@ static TransData *ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FC
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
/* only add selected keyframes (for now, proportional edit is not enabled) */
- if (bezt->f2 & SELECT) { /* note this MUST match count_fcurve_keys(), so can't use BEZSELECTED() macro */
+ if (is_prop_edit || (bezt->f2 & SELECT)) { /* note this MUST match count_fcurve_keys(), so can't use BEZSELECTED() macro */
/* only add if on the right 'side' of the current frame */
if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
- TimeToTransData(td, bezt->vec[1], adt);
+ TimeToTransData(td, bezt->vec[1], adt, ypos);
+ if (bezt->f2 & SELECT)
+ td->flag |= TD_SELECTED;
+
/*set flags to move handles as necessary*/
td->flag |= TD_MOVEHANDLE1 | TD_MOVEHANDLE2;
td2d->h1 = bezt->vec[0];
@@ -3456,19 +3705,22 @@ void flushTransIntFrameActionData(TransInfo *t)
* The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
* on the named side are used.
*/
-static int GPLayerToTransData(TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl, char side, float cfra)
+static int GPLayerToTransData(TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl, char side, float cfra, bool is_prop_edit, float ypos)
{
bGPDframe *gpf;
int count = 0;
/* check for select frames on right side of current frame */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (gpf->flag & GP_FRAME_SELECT) {
+ if (is_prop_edit || (gpf->flag & GP_FRAME_SELECT)) {
if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
/* memory is calloc'ed, so that should zero everything nicely for us */
td->val = &tfd->val;
td->ival = (float)gpf->framenum;
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
tfd->val = (float)gpf->framenum;
tfd->sdata = &gpf->framenum;
@@ -3484,19 +3736,22 @@ static int GPLayerToTransData(TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl,
}
/* refer to comment above #GPLayerToTransData, this is the same but for masks */
-static int MaskLayerToTransData(TransData *td, tGPFtransdata *tfd, MaskLayer *masklay, char side, float cfra)
+static int MaskLayerToTransData(TransData *td, tGPFtransdata *tfd, MaskLayer *masklay, char side, float cfra, bool is_prop_edit, float ypos)
{
MaskLayerShape *masklay_shape;
int count = 0;
/* check for select frames on right side of current frame */
for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
- if (masklay_shape->flag & MASK_SHAPE_SELECT) {
+ if (is_prop_edit || (masklay_shape->flag & MASK_SHAPE_SELECT)) {
if (FrameOnMouseSide(side, (float)masklay_shape->frame, cfra)) {
/* memory is calloc'ed, so that should zero everything nicely for us */
td->val = &tfd->val;
td->ival = (float)masklay_shape->frame;
+ td->center[0] = td->ival;
+ td->center[1] = ypos;
+
tfd->val = (float)masklay_shape->frame;
tfd->sdata = &masklay_shape->frame;
@@ -3518,15 +3773,25 @@ static void createTransActionData(bContext *C, TransInfo *t)
TransData *td = NULL;
TransData2D *td2d = NULL;
tGPFtransdata *tfd = NULL;
-
+
+ rcti *mask = &t->ar->v2d.mask;
+ rctf *datamask = &t->ar->v2d.cur;
+
+ float xsize = BLI_rctf_size_x(datamask);
+ float ysize = BLI_rctf_size_y(datamask);
+ float xmask = BLI_rcti_size_x(mask);
+ float ymask = BLI_rcti_size_y(mask);
+
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
-
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
int count = 0;
float cfra;
-
+ float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->ar->v2d.cur);
+
/* determine what type of data we are operating on */
if (ANIM_animdata_get_context(C, &ac) == 0)
return;
@@ -3554,7 +3819,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
/* loop 1: fully select ipo-keys and count how many BezTriples are selected */
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
-
+ int adt_count = 0;
/* convert current-frame to action-time (slightly less accurate, especially under
* higher scaling ratios, but is faster than converting all points)
*/
@@ -3563,14 +3828,19 @@ static void createTransActionData(bContext *C, TransInfo *t)
else
cfra = (float)CFRA;
- if (ale->type == ANIMTYPE_FCURVE)
- count += count_fcurve_keys(ale->key_data, t->frame_side, cfra);
+ if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE))
+ adt_count = count_fcurve_keys(ale->key_data, t->frame_side, cfra, is_prop_edit);
else if (ale->type == ANIMTYPE_GPLAYER)
- count += count_gplayer_frames(ale->data, t->frame_side, cfra);
+ adt_count = count_gplayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
else if (ale->type == ANIMTYPE_MASKLAYER)
- count += count_masklayer_frames(ale->data, t->frame_side, cfra);
+ adt_count = count_masklayer_frames(ale->data, t->frame_side, cfra, is_prop_edit);
else
BLI_assert(0);
+
+ if (adt_count > 0) {
+ count += adt_count;
+ ale->tag = true;
+ }
}
/* stop if trying to build list if nothing selected */
@@ -3607,11 +3877,22 @@ static void createTransActionData(bContext *C, TransInfo *t)
/* loop 2: build transdata array */
for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt;
+
+ if (is_prop_edit && !ale->tag)
+ continue;
+
+ adt = ANIM_nla_mapping_get(&ac, ale);
+ if (adt)
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ else
+ cfra = (float)CFRA;
+
if (ale->type == ANIMTYPE_GPLAYER) {
bGPDlayer *gpl = (bGPDlayer *)ale->data;
int i;
- i = GPLayerToTransData(td, tfd, gpl, t->frame_side, cfra);
+ i = GPLayerToTransData(td, tfd, gpl, t->frame_side, cfra, is_prop_edit, ypos);
td += i;
tfd += i;
}
@@ -3619,7 +3900,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
MaskLayer *masklay = (MaskLayer *)ale->data;
int i;
- i = MaskLayerToTransData(td, tfd, masklay, t->frame_side, cfra);
+ i = MaskLayerToTransData(td, tfd, masklay, t->frame_side, cfra, is_prop_edit, ypos);
td += i;
tfd += i;
}
@@ -3627,15 +3908,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
- /* convert current-frame to action-time (slightly less accurate, especially under
- * higher scaling ratios, but is faster than converting all points)
- */
- if (adt)
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- else
- cfra = (float)CFRA;
-
- td = ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra);
+ td = ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra, is_prop_edit, ypos);
}
}
@@ -3664,6 +3937,109 @@ static void createTransActionData(bContext *C, TransInfo *t)
*((float *)(t->customData) + 1) = max;
}
+ /* calculate distances for proportional editing */
+ if (is_prop_edit) {
+ td = t->data;
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt;
+
+ /* F-Curve may not have any keyframes */
+ if (!ale->tag)
+ continue;
+
+ adt = ANIM_nla_mapping_get(&ac, ale);
+ if (adt)
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ else
+ cfra = (float)CFRA;
+
+ if (ale->type == ANIMTYPE_GPLAYER) {
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+ bGPDframe *gpf;
+
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (gpf->flag & GP_FRAME_SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ bGPDframe *gpf_iter;
+ int min = INT_MAX;
+ for (gpf_iter = gpl->frames.first; gpf_iter; gpf_iter = gpf->next) {
+ if (gpf_iter->flag & GP_FRAME_SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)gpf_iter->framenum, cfra)) {
+ int val = abs(gpf->framenum - gpf_iter->framenum);
+ if (val < min) {
+ min = val;
+ }
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
+ MaskLayer *masklay = (MaskLayer *)ale->data;
+ MaskLayerShape *masklay_shape;
+
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) {
+ if (FrameOnMouseSide(t->frame_side, (float)masklay_shape->frame, cfra)) {
+ if (masklay_shape->flag & MASK_SHAPE_SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ MaskLayerShape *masklay_iter;
+ int min = INT_MAX;
+ for (masklay_iter = masklay->splines_shapes.first; masklay_iter; masklay_iter = masklay_iter->next) {
+ if (masklay_iter->flag & MASK_SHAPE_SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)masklay_iter->frame, cfra)) {
+ int val = abs(masklay_shape->frame - masklay_iter->frame);
+ if (val < min) {
+ min = val;
+ }
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ }
+ else {
+ FCurve *fcu = (FCurve *)ale->key_data;
+ BezTriple *bezt;
+ int i;
+
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ if (bezt->f2 & SELECT) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ BezTriple *bezt_iter;
+ int j;
+ float min = FLT_MAX;
+ for (j = 0, bezt_iter = fcu->bezt; j < fcu->totvert; j++, bezt_iter++) {
+ if (bezt_iter->f2 & SELECT) {
+ if (FrameOnMouseSide(t->frame_side, (float)bezt_iter->vec[1][0], cfra)) {
+ float val = fabs(bezt->vec[1][0] - bezt_iter->vec[1][0]);
+ if (val < min)
+ min = val;
+ }
+ }
+ }
+ td->dist = td->rdist = min;
+ }
+ td++;
+ }
+ }
+ }
+ }
+ }
+
/* cleanup temp list */
ANIM_animdata_freelist(&anim_data);
}
@@ -3672,6 +4048,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
typedef struct TransDataGraph {
float unit_scale;
+ float offset;
} TransDataGraph;
/* Helper function for createTransGraphEditData, which is responsible for associating
@@ -3680,7 +4057,7 @@ typedef struct TransDataGraph {
static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph *tdg,
AnimData *adt, BezTriple *bezt,
int bi, bool selected, bool ishandle, bool intvals,
- float mtx[3][3], float smtx[3][3], float unit_scale)
+ float mtx[3][3], float smtx[3][3], float unit_scale, float offset)
{
float *loc = bezt->vec[bi];
const float *cent = bezt->vec[1];
@@ -3694,26 +4071,26 @@ static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph *
if (adt) {
td2d->loc[0] = BKE_nla_tweakedit_remap(adt, loc[0], NLATIME_CONVERT_MAP);
- td2d->loc[1] = loc[1] * unit_scale;
+ td2d->loc[1] = (loc[1] + offset) * unit_scale;
td2d->loc[2] = 0.0f;
td2d->loc2d = loc;
td->loc = td2d->loc;
td->center[0] = BKE_nla_tweakedit_remap(adt, cent[0], NLATIME_CONVERT_MAP);
- td->center[1] = cent[1] * unit_scale;
+ td->center[1] = (cent[1] + offset) * unit_scale;
td->center[2] = 0.0f;
copy_v3_v3(td->iloc, td->loc);
}
else {
td2d->loc[0] = loc[0];
- td2d->loc[1] = loc[1] * unit_scale;
+ td2d->loc[1] = (loc[1] + offset) * unit_scale;
td2d->loc[2] = 0.0f;
td2d->loc2d = loc;
td->loc = td2d->loc;
copy_v3_v3(td->center, cent);
- td->center[1] *= unit_scale;
+ td->center[1] = (td->center[1] + offset) * unit_scale;
copy_v3_v3(td->iloc, td->loc);
}
@@ -3753,6 +4130,7 @@ static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph *
copy_m3_m3(td->smtx, smtx);
tdg->unit_scale = unit_scale;
+ tdg->offset = offset;
}
static bool graph_edit_is_translation_mode(TransInfo *t)
@@ -3765,6 +4143,29 @@ static bool graph_edit_use_local_center(TransInfo *t)
return (t->around == V3D_LOCAL) && !graph_edit_is_translation_mode(t);
}
+
+static void graph_key_shortest_dist(TransInfo *t, FCurve *fcu, TransData *td_start, TransData *td, int cfra, bool use_handle)
+{
+ int j = 0;
+ TransData *td_iter = td_start;
+
+ td->dist = FLT_MAX;
+ for (; j < fcu->totvert; j++) {
+ BezTriple *bezt = fcu->bezt + j;
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ if (sel1 || sel2 || sel3) {
+ td->dist = td->rdist = min_ff(td->dist, fabs(td_iter->center[0] - td->center[0]));
+ }
+
+ td_iter += 3;
+ }
+ }
+}
+
static void createTransGraphEditData(bContext *C, TransInfo *t)
{
SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
@@ -3787,6 +4188,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
const bool is_translation_mode = graph_edit_is_translation_mode(t);
const bool use_handle = !(sipo->flag & SIPO_NOHANDLES);
const bool use_local_center = graph_edit_use_local_center(t);
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
short anim_map_flag = ANIM_UNITCONV_ONLYSEL | ANIM_UNITCONV_SELVERTS;
/* determine what type of data we are operating on */
@@ -3818,6 +4220,8 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
float cfra;
+ int curvecount = 0;
+ bool selected = false;
/* F-Curve may not have any keyframes */
if (fcu->bezt == NULL)
@@ -3838,20 +4242,34 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
- if (!is_translation_mode || !(sel2)) {
- if (sel1) {
- count++;
+ if (is_prop_edit) {
+ curvecount += 3;
+ if (sel2 || sel1 || sel3)
+ selected = true;
+ }
+ else {
+ if (!is_translation_mode || !(sel2)) {
+ if (sel1) {
+ count++;
+ }
+
+ if (sel3) {
+ count++;
+ }
}
- if (sel3) {
+ /* only include main vert if selected */
+ if (sel2 && !use_local_center) {
count++;
}
}
+ }
+ }
- /* only include main vert if selected */
- if (sel2 && !use_local_center) {
- count++;
- }
+ if (is_prop_edit) {
+ if (selected) {
+ count += curvecount;
+ ale->tag = true;
}
}
}
@@ -3900,11 +4318,11 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
bool intvals = (fcu->flag & FCURVE_INT_VALUES) != 0;
- float unit_scale;
+ float unit_scale, offset;
float cfra;
/* F-Curve may not have any keyframes */
- if (fcu->bezt == NULL)
+ if (fcu->bezt == NULL || (is_prop_edit && ale->tag == 0))
continue;
/* convert current-frame to action-time (slightly less accurate, especially under
@@ -3915,7 +4333,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
else
cfra = (float)CFRA;
- unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, anim_map_flag);
+ unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, anim_map_flag, &offset);
/* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse (if applicable) */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
@@ -3927,66 +4345,135 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
TransDataCurveHandleFlags *hdata = NULL;
/* short h1=1, h2=1; */ /* UNUSED */
- /* only include handles if selected, irrespective of the interpolation modes.
- * also, only treat handles specially if the center point isn't selected.
- */
- if (!is_translation_mode || !(sel2)) {
- if (sel1) {
- hdata = initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 0, sel1, true, intvals, mtx, smtx, unit_scale);
+ if (is_prop_edit) {
+ bool is_sel = (sel2 || sel1 || sel3);
+ /* we always select all handles for proportional editing if central handle is selected */
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 0, is_sel, true, intvals, mtx, smtx, unit_scale, offset);
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 1, is_sel, false, intvals, mtx, smtx, unit_scale, offset);
+ initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 2, is_sel, true, intvals, mtx, smtx, unit_scale, offset);
+ }
+ else {
+ /* only include handles if selected, irrespective of the interpolation modes.
+ * also, only treat handles specially if the center point isn't selected.
+ */
+ if (!is_translation_mode || !(sel2)) {
+ if (sel1) {
+ hdata = initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 0, sel1, true, intvals, mtx, smtx, unit_scale, offset);
+ }
+ else {
+ /* h1 = 0; */ /* UNUSED */
+ }
+
+ if (sel3) {
+ if (hdata == NULL)
+ hdata = initTransDataCurveHandles(td, bezt);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 2, sel3, true, intvals, mtx, smtx, unit_scale, offset);
+ }
+ else {
+ /* h2 = 0; */ /* UNUSED */
+ }
}
- else {
- /* h1 = 0; */ /* UNUSED */
+
+ /* only include main vert if selected */
+ if (sel2 && !use_local_center) {
+ /* move handles relative to center */
+ if (is_translation_mode) {
+ if (sel1) td->flag |= TD_MOVEHANDLE1;
+ if (sel3) td->flag |= TD_MOVEHANDLE2;
+ }
+
+ /* if handles were not selected, store their selection status */
+ if (!(sel1) || !(sel3)) {
+ if (hdata == NULL)
+ hdata = initTransDataCurveHandles(td, bezt);
+ }
+
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 1, sel2, false, intvals, mtx, smtx, unit_scale, offset);
+
}
-
- if (sel3) {
- if (hdata == NULL)
- hdata = initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 2, sel3, true, intvals, mtx, smtx, unit_scale);
+ /* special hack (must be done after initTransDataCurveHandles(), as that stores handle settings to restore...):
+ * - Check if we've got entire BezTriple selected and we're scaling/rotating that point,
+ * then check if we're using auto-handles.
+ * - If so, change them auto-handles to aligned handles so that handles get affected too
+ */
+ if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) &&
+ ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM) &&
+ ELEM(t->mode, TFM_ROTATION, TFM_RESIZE))
+ {
+ if (hdata && (sel1) && (sel3)) {
+ bezt->h1 = HD_ALIGN;
+ bezt->h2 = HD_ALIGN;
+ }
+ }
+ }
+ }
+ }
+
+ /* Sets handles based on the selection */
+ testhandles_fcurve(fcu, use_handle);
+ }
+
+ if (is_prop_edit) {
+ /* loop 2: build transdata arrays */
+ td = t->data;
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+ TransData *td_start = td;
+ float cfra;
+
+ /* F-Curve may not have any keyframes */
+ if (fcu->bezt == NULL || (ale->tag == 0))
+ continue;
+
+ /* convert current-frame to action-time (slightly less accurate, especially under
+ * higher scaling ratios, but is faster than converting all points)
+ */
+ if (adt)
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ else
+ cfra = (float)CFRA;
+
+ /* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse (if applicable) */
+ for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+ if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+ const bool sel2 = (bezt->f2 & SELECT) != 0;
+ const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+ const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+ if (sel1 || sel2) {
+ td->dist = td->rdist = 0.0f;
}
else {
- /* h2 = 0; */ /* UNUSED */
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
}
- }
-
- /* only include main vert if selected */
- if (sel2 && !use_local_center) {
- /* move handles relative to center */
- if (is_translation_mode) {
- if (sel1) td->flag |= TD_MOVEHANDLE1;
- if (sel3) td->flag |= TD_MOVEHANDLE2;
+ td++;
+
+ if (sel2) {
+ td->dist = td->rdist = 0.0f;
}
-
- /* if handles were not selected, store their selection status */
- if (!(sel1) || !(sel3)) {
- if (hdata == NULL)
- hdata = initTransDataCurveHandles(td, bezt);
+ else {
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
}
-
- bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 1, sel2, false, intvals, mtx, smtx, unit_scale);
-
- }
- /* special hack (must be done after initTransDataCurveHandles(), as that stores handle settings to restore...):
- * - Check if we've got entire BezTriple selected and we're scaling/rotating that point,
- * then check if we're using auto-handles.
- * - If so, change them auto-handles to aligned handles so that handles get affected too
- */
- if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) &&
- ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM) &&
- ELEM(t->mode, TFM_ROTATION, TFM_RESIZE))
- {
- if (hdata && (sel1) && (sel3)) {
- bezt->h1 = HD_ALIGN;
- bezt->h2 = HD_ALIGN;
+ td++;
+
+ if (sel3 || sel2) {
+ td->dist = td->rdist = 0.0f;
+ }
+ else {
+ graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
}
+ td++;
}
}
}
-
- /* Sets handles based on the selection */
- testhandles_fcurve(fcu, use_handle);
}
-
+
/* cleanup temp list */
ANIM_animdata_freelist(&anim_data);
}
@@ -4270,7 +4757,7 @@ void flushTransGraphData(TransInfo *t)
if (td->flag & TD_INTVALUES)
td2d->loc2d[1] = floorf(td2d->loc[1] + 0.5f);
else
- td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale;
+ td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale - tdg->offset;
if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) {
td2d->h1[0] = td2d->ih1[0] + td->loc[0] - td->iloc[0];
@@ -5094,7 +5581,9 @@ static void set_trans_object_base_flags(TransInfo *t)
}
/* all recalc flags get flushed to all layers, so a layer flip later on works fine */
+#ifdef WITH_LEGACY_DEPSGRAPH
DAG_scene_flush_update(G.main, t->scene, -1, 0);
+#endif
/* and we store them temporal in base (only used for transform code) */
/* this because after doing updates, the object->recalc is cleared */
@@ -5171,7 +5660,9 @@ static int count_proportional_objects(TransInfo *t)
/* all recalc flags get flushed to all layers, so a layer flip later on works fine */
DAG_scene_relations_update(G.main, t->scene);
+#ifdef WITH_LEGACY_DEPSGRAPH
DAG_scene_flush_update(G.main, t->scene, -1, 0);
+#endif
/* and we store them temporal in base (only used for transform code) */
/* this because after doing updates, the object->recalc is cleared */
@@ -6138,6 +6629,13 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
{
/* do nothing */
}
+ else if ((t->scene->basact) &&
+ (ob = t->scene->basact->object) &&
+ (ob->mode & OB_MODE_HAIR_EDIT) &&
+ BKE_editstrands_from_object(ob))
+ {
+ /* do nothing */
+ }
else { /* Objects */
int i;
@@ -6221,7 +6719,7 @@ static void createTransObject(bContext *C, TransInfo *t)
TransData *td = NULL;
TransDataExtension *tx;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
set_trans_object_base_flags(t);
@@ -6234,7 +6732,7 @@ static void createTransObject(bContext *C, TransInfo *t)
return;
}
- if (propmode) {
+ if (is_prop_edit) {
t->total += count_proportional_objects(t);
}
@@ -6267,7 +6765,7 @@ static void createTransObject(bContext *C, TransInfo *t)
}
CTX_DATA_END;
- if (propmode) {
+ if (is_prop_edit) {
View3D *v3d = t->view;
Base *base;
@@ -7024,9 +7522,10 @@ static void MaskHandleToTransData(MaskSplinePoint *point, eMaskWhichHandle which
}
}
-static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point,
- TransData *td, TransData2D *td2d, TransDataMasking *tdm,
- const int propmode, const float asp[2])
+static void MaskPointToTransData(
+ Scene *scene, MaskSplinePoint *point,
+ TransData *td, TransData2D *td2d, TransDataMasking *tdm,
+ const bool is_prop_edit, const float asp[2])
{
BezTriple *bezt = &point->bezt;
const bool is_sel_point = MASKPOINT_ISSEL_KNOT(point);
@@ -7036,7 +7535,7 @@ static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point,
BKE_mask_point_parent_matrix_get(point, CFRA, parent_matrix);
invert_m3_m3(parent_inverse_matrix, parent_matrix);
- if (propmode || is_sel_point) {
+ if (is_prop_edit || is_sel_point) {
int i;
tdm->point = point;
@@ -7156,7 +7655,7 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
TransData2D *td2d = NULL;
TransDataMasking *tdm = NULL;
int count = 0, countsel = 0;
- int propmode = t->flag & T_PROP_EDIT;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT);
float asp[2];
t->total = 0;
@@ -7206,7 +7705,7 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
}
}
- if (propmode)
+ if (is_prop_edit)
count += 3;
}
}
@@ -7219,7 +7718,7 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
- t->total = (propmode) ? count : countsel;
+ t->total = (is_prop_edit) ? count : countsel;
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Mask Editing)");
/* for each 2d uv coord a 3d vector is allocated, so that they can be
* treated just as if they were 3d verts */
@@ -7242,10 +7741,10 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
for (i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
- if (propmode || MASKPOINT_ISSEL_ANY(point)) {
- MaskPointToTransData(scene, point, td, td2d, tdm, propmode, asp);
+ if (is_prop_edit || MASKPOINT_ISSEL_ANY(point)) {
+ MaskPointToTransData(scene, point, td, td2d, tdm, is_prop_edit, asp);
- if (propmode || MASKPOINT_ISSEL_KNOT(point)) {
+ if (is_prop_edit || MASKPOINT_ISSEL_KNOT(point)) {
td += 3;
td2d += 3;
tdm += 3;
@@ -7488,8 +7987,8 @@ static void createTransGPencil(bContext *C, TransInfo *t)
const Scene *scene = CTX_data_scene(C);
const int cfra = CFRA;
- const int propedit = (t->flag & T_PROP_EDIT);
- const int propedit_connected = (t->flag & T_PROP_CONNECTED);
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
/* == Grease Pencil Strokes to Transform Data ==
@@ -7520,9 +8019,9 @@ static void createTransGPencil(bContext *C, TransInfo *t)
continue;
}
- if (propedit) {
+ if (is_prop_edit) {
/* Proportional Editing... */
- if (propedit_connected) {
+ if (is_prop_edit_connected) {
/* connected only - so only if selected */
if (gps->flag & GP_STROKE_SELECT)
t->total += gps->totpoints;
@@ -7629,8 +8128,8 @@ static void createTransGPencil(bContext *C, TransInfo *t)
}
/* What we need to include depends on proportional editing settings... */
- if (propedit) {
- if (propedit_connected) {
+ if (is_prop_edit) {
+ if (is_prop_edit_connected) {
/* A) "Connected" - Only those in selected strokes */
stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
}
@@ -7649,7 +8148,7 @@ static void createTransGPencil(bContext *C, TransInfo *t)
bGPDspoint *pt;
int i;
-#if 0 /* XXX: this isn't needed anymore; cannot calculate center this way or propedit breaks */
+#if 0 /* XXX: this isn't needed anymore; cannot calculate center this way or is_prop_edit breaks */
const float ninv = 1.0f / gps->totpoints;
float center[3] = {0.0f};
@@ -7664,7 +8163,7 @@ static void createTransGPencil(bContext *C, TransInfo *t)
bool point_ok;
/* include point? */
- if (propedit) {
+ if (is_prop_edit) {
/* Always all points in strokes that get included */
point_ok = true;
}
@@ -7707,7 +8206,7 @@ static void createTransGPencil(bContext *C, TransInfo *t)
}
/* March over these points, and calculate the proportional editing distances */
- if (propedit && (head != tail)) {
+ if (is_prop_edit && (head != tail)) {
/* XXX: for now, we are similar enough that this works... */
calc_distanceCurveVerts(head, tail - 1);
}
@@ -7776,6 +8275,12 @@ void createTransData(bContext *C, TransInfo *t)
else if (t->spacetype == SPACE_ACTION) {
t->flag |= T_POINTS | T_2D_EDIT;
createTransActionData(C, t);
+
+ if (t->data && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data(t); // makes selected become first in array
+ //set_prop_dist(t, false); /* don't do that, distance has been set in createTransActionData already */
+ sort_trans_data_dist(t);
+ }
}
else if (t->spacetype == SPACE_NLA) {
t->flag |= T_POINTS | T_2D_EDIT;
@@ -7789,13 +8294,12 @@ void createTransData(bContext *C, TransInfo *t)
else if (t->spacetype == SPACE_IPO) {
t->flag |= T_POINTS | T_2D_EDIT;
createTransGraphEditData(C, t);
-#if 0
+
if (t->data && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
- set_prop_dist(t, 1);
+ set_prop_dist(t, false); /* don't do that, distance has been set in createTransGraphEditData already */
sort_trans_data_dist(t);
}
-#endif
}
else if (t->spacetype == SPACE_NODE) {
t->flag |= T_POINTS | T_2D_EDIT;
@@ -7895,6 +8399,16 @@ void createTransData(bContext *C, TransInfo *t)
sort_trans_data_dist(t);
}
}
+ else if (ob && (ob->mode & OB_MODE_HAIR_EDIT) && BKE_editstrands_from_object(ob)) {
+ createTransStrandVerts(t);
+ t->flag |= T_POINTS;
+
+ if (t->data && t->flag & T_PROP_EDIT) {
+ sort_trans_data(t); // makes selected become first in array
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
if ((t->options & CTX_PAINT_CURVE) && !ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
t->flag |= T_POINTS | T_2D_EDIT;
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 78a6ca1ae84..537e76baa7e 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -71,6 +71,7 @@
#include "BKE_armature.h"
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
+#include "BKE_editstrands.h"
#include "BKE_fcurve.h"
#include "BKE_lattice.h"
#include "BKE_nla.h"
@@ -80,6 +81,7 @@
#include "BKE_editmesh.h"
#include "BKE_tracking.h"
#include "BKE_mask.h"
+#include "BKE_utildefines.h"
#include "ED_anim_api.h"
#include "ED_armature.h"
@@ -808,6 +810,10 @@ static void recalcData_objects(TransInfo *t)
ebo->rad_head *= ebo->length / ebo->oldlength;
ebo->rad_tail *= ebo->length / ebo->oldlength;
ebo->oldlength = ebo->length;
+
+ if (ebo_parent) {
+ ebo_parent->rad_tail = ebo->rad_head;
+ }
}
}
@@ -888,6 +894,12 @@ static void recalcData_objects(TransInfo *t)
}
flushTransParticles(t);
}
+ else if (base && (base->object->mode & OB_MODE_HAIR_EDIT) && BKE_editstrands_from_object(base->object)) {
+ if (t->state != TRANS_CANCEL) {
+ applyProject(t);
+ }
+ flushTransStrands(t);
+ }
else {
int i;
@@ -1065,6 +1077,8 @@ static int initTransInfo_edit_pet_to_flag(const int proportional)
* Setup internal data, mouse, vectors
*
* \note \a op and \a event can be NULL
+ *
+ * \see #saveTransform does the reverse.
*/
void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event)
{
@@ -1156,6 +1170,19 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->spacetype = sa->spacetype;
}
+ /* handle T_ALT_TRANSFORM initialization, we may use for different operators */
+ if (op) {
+ const char *prop_id = NULL;
+ if (t->mode == TFM_SHRINKFATTEN) {
+ prop_id = "use_even_offset";
+ }
+
+ if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id)) &&
+ RNA_property_is_set(op->ptr, prop))
+ {
+ BKE_BIT_TEST_SET(t->flag, RNA_property_boolean_get(op->ptr, prop), T_ALT_TRANSFORM);
+ }
+ }
if (t->spacetype == SPACE_VIEW3D) {
View3D *v3d = sa->spacedata.first;
@@ -1322,7 +1349,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
/* use settings from scene only if modal */
if (t->flag & T_MODAL) {
if ((t->options & CTX_NO_PET) == 0) {
- if (t->obedit) {
+ if (t->spacetype == SPACE_IPO) {
+ t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_fcurve);
+ }
+ else if (t->spacetype == SPACE_ACTION) {
+ t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_action);
+ }
+ else if (t->obedit) {
t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional);
}
else if (t->options & CTX_GPENCIL_STROKES) {
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index 562e9e292e4..667c0f01c18 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -513,7 +513,7 @@ static int calc_manipulator_stats(const bContext *C)
for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) {
if (ek->flag & PEK_SELECT) {
- calc_tw_center(scene, ek->flag & PEK_USE_WCO ? ek->world_co : ek->co);
+ calc_tw_center(scene, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co);
totsel++;
}
}
@@ -896,6 +896,11 @@ static void postOrtho(const bool ortho)
}
}
+BLI_INLINE bool manipulator_rotate_is_visible(const int drawflags)
+{
+ return (drawflags & (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z));
+}
+
static void draw_manipulator_rotate(
View3D *v3d, RegionView3D *rv3d, const int drawflags, const int combo,
const bool is_moving, const bool is_picksel)
@@ -909,8 +914,8 @@ static void draw_manipulator_rotate(
const int colcode = (is_moving) ? MAN_MOVECOL : MAN_RGB;
bool ortho;
- /* when called while moving in mixed mode, do not draw when... */
- if ((drawflags & MAN_ROT_C) == 0) return;
+ /* skip drawing if all axes are locked */
+ if (manipulator_rotate_is_visible(drawflags) == false) return;
/* Init stuff */
glDisable(GL_DEPTH_TEST);
@@ -1052,8 +1057,6 @@ static void draw_manipulator_rotate(
glRotatef(90.0, 1.0, 0.0, 0.0);
postOrtho(ortho);
}
-
- if (arcs) glDisable(GL_CLIP_PLANE0);
}
// donut arcs
if (arcs) {
@@ -1449,8 +1452,8 @@ static void draw_manipulator_rotate_cyl(
int axis_order[3] = {2, 0, 1};
int i;
- /* when called while moving in mixed mode, do not draw when... */
- if ((drawflags & MAN_ROT_C) == 0) return;
+ /* skip drawing if all axes are locked */
+ if (manipulator_rotate_is_visible(drawflags) == false) return;
manipulator_axis_order(rv3d, axis_order);
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index c63ec9cb23d..62fa1b5a989 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -38,6 +38,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_report.h"
+#include "BKE_editmesh.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -63,23 +64,23 @@ typedef struct TransformModeItem {
static const float VecOne[3] = {1, 1, 1};
-static char OP_TRANSLATION[] = "TRANSFORM_OT_translate";
-static char OP_ROTATION[] = "TRANSFORM_OT_rotate";
-static char OP_TOSPHERE[] = "TRANSFORM_OT_tosphere";
-static char OP_RESIZE[] = "TRANSFORM_OT_resize";
-static char OP_SKIN_RESIZE[] = "TRANSFORM_OT_skin_resize";
-static char OP_SHEAR[] = "TRANSFORM_OT_shear";
-static char OP_BEND[] = "TRANSFORM_OT_bend";
-static char OP_SHRINK_FATTEN[] = "TRANSFORM_OT_shrink_fatten";
-static char OP_PUSH_PULL[] = "TRANSFORM_OT_push_pull";
-static char OP_TILT[] = "TRANSFORM_OT_tilt";
-static char OP_TRACKBALL[] = "TRANSFORM_OT_trackball";
-static char OP_MIRROR[] = "TRANSFORM_OT_mirror";
-static char OP_EDGE_SLIDE[] = "TRANSFORM_OT_edge_slide";
-static char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide";
-static char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease";
-static char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight";
-static char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide";
+static const char OP_TRANSLATION[] = "TRANSFORM_OT_translate";
+static const char OP_ROTATION[] = "TRANSFORM_OT_rotate";
+static const char OP_TOSPHERE[] = "TRANSFORM_OT_tosphere";
+static const char OP_RESIZE[] = "TRANSFORM_OT_resize";
+static const char OP_SKIN_RESIZE[] = "TRANSFORM_OT_skin_resize";
+static const char OP_SHEAR[] = "TRANSFORM_OT_shear";
+static const char OP_BEND[] = "TRANSFORM_OT_bend";
+static const char OP_SHRINK_FATTEN[] = "TRANSFORM_OT_shrink_fatten";
+static const char OP_PUSH_PULL[] = "TRANSFORM_OT_push_pull";
+static const char OP_TILT[] = "TRANSFORM_OT_tilt";
+static const char OP_TRACKBALL[] = "TRANSFORM_OT_trackball";
+static const char OP_MIRROR[] = "TRANSFORM_OT_mirror";
+static const char OP_EDGE_SLIDE[] = "TRANSFORM_OT_edge_slide";
+static const char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide";
+static const char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease";
+static const char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight";
+static const char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide";
static void TRANSFORM_OT_translate(struct wmOperatorType *ot);
@@ -489,7 +490,7 @@ static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* add temp handler */
WM_event_add_modal_handler(C, op);
- op->flag |= OP_GRAB_POINTER; // XXX maybe we want this with the manipulator only?
+ op->flag |= OP_IS_MODAL_GRAB_CURSOR; // XXX maybe we want this with the manipulator only?
return OPERATOR_RUNNING_MODAL;
}
}
@@ -791,6 +792,8 @@ static void TRANSFORM_OT_shrink_fatten(struct wmOperatorType *ot)
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX);
+ RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness");
+
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP);
}
@@ -846,9 +849,9 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
ot->exec = transform_exec;
ot->modal = transform_modal;
ot->cancel = transform_cancel;
- ot->poll = ED_operator_editmesh;
+ ot->poll = ED_operator_editmesh_region_view3d;
- RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f);
+ RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f);
Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV);
}
@@ -866,7 +869,7 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
ot->exec = transform_exec;
ot->modal = transform_modal;
ot->cancel = transform_cancel;
- ot->poll = ED_operator_editmesh;
+ ot->poll = ED_operator_editmesh_region_view3d;
RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f);
@@ -1115,6 +1118,11 @@ void transform_keymap_for_space(wmKeyConfig *keyconf, wmKeyMap *keymap, int spac
/* XXX release_confirm is set in the macro operator definition */
WM_keymap_add_item(keymap, "NODE_OT_move_detach_links_release", EVT_TWEAK_A, KM_ANY, KM_ALT, 0);
WM_keymap_add_item(keymap, "NODE_OT_move_detach_links", EVT_TWEAK_S, KM_ANY, KM_ALT, 0);
+
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", TABKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_snap");
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", TABKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+ RNA_string_set(kmi->ptr, "data_path", "tool_settings.snap_node_element");
break;
case SPACE_SEQ:
WM_keymap_add_item(keymap, OP_SEQ_SLIDE, GKEY, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 7fea8e163fd..030e29d0ebb 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -1010,7 +1010,7 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
result = ORIENTATION_EDGE;
}
}
- else if (ob && (ob->mode & (OB_MODE_ALL_PAINT | OB_MODE_PARTICLE_EDIT))) {
+ else if (ob && (ob->mode & (OB_MODE_ALL_BRUSH | OB_MODE_PARTICLE_EDIT))) {
/* pass */
}
else {
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index be9bbd8f150..fae5654db79 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -577,6 +577,10 @@ static void initSnappingMode(TransInfo *t)
t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
}
}
+ else if (t->spacetype == SPACE_SEQ) {
+ /* We do our own snapping currently, so nothing here */
+ t->tsnap.mode = SCE_SNAP_MODE_GRID; /* Dummy, should we rather add a NOP mode? */
+ }
else {
/* Always grid outside of 3D view */
t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
@@ -949,9 +953,9 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
// last_p = LAST_SNAP_POINT;
// }
// else
-// {
+ {
last_p = t->tsnap.snapPoint;
-// }
+ }
for (p1 = depth_peels.first; p1; p1 = p1->next) {
@@ -1396,11 +1400,8 @@ static bool snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *ar
invert_m4_m4(imat, obmat);
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
-
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
+ mul_v3_m4v3(ray_start_local, imat, ray_start);
+ mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
if (arm->edbo) {
EditBone *eBone;
@@ -1758,11 +1759,8 @@ static bool snapEmpty(short snap_mode, ARegion *ar, Object *ob, float obmat[4][4
invert_m4_m4(imat, obmat);
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
-
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
+ mul_v3_m4v3(ray_start_local, imat, ray_start);
+ mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
switch (snap_mode) {
case SCE_SNAP_MODE_VERTEX:
@@ -2107,12 +2105,8 @@ static bool peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[4][4],
transpose_m3_m4(timat, imat);
- copy_v3_v3(ray_start_local, ray_start);
- copy_v3_v3(ray_normal_local, ray_normal);
-
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
-
+ mul_v3_m4v3(ray_start_local, imat, ray_start);
+ mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
/* If number of vert is more than an arbitrary limit,
* test against boundbox first
@@ -2431,7 +2425,7 @@ void snapGridIncrement(TransInfo *t, float *val)
snapGridIncrementAction(t, val, action);
}
-int snapSequenceBounds(TransInfo *t, const int mval[2])
+void snapSequenceBounds(TransInfo *t, const int mval[2])
{
float xmouse, ymouse;
int frame;
@@ -2439,7 +2433,7 @@ int snapSequenceBounds(TransInfo *t, const int mval[2])
TransSeq *ts = t->customData;
/* reuse increment, strictly speaking could be another snap mode, but leave as is */
if (!(t->modifiers & MOD_SNAP_INVERT))
- return 0;
+ return;
/* convert to frame range */
UI_view2d_region_to_view(&t->ar->v2d, mval[0], mval[1], &xmouse, &ymouse);
@@ -2450,7 +2444,7 @@ int snapSequenceBounds(TransInfo *t, const int mval[2])
if (!ts->snap_left)
frame = frame - (ts->max - ts->min);
- return frame;
+ t->values[0] = frame - ts->min;
}
static void applyGridIncrement(TransInfo *t, float *val, int max_index, const float fac[3], GearsType action)
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index f4189a18da4..47894e1bc1f 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenkernel
../../blenlib
../../bmesh
+ ../../imbuf
../../gpu
../../makesdna
../../makesrna
@@ -69,6 +70,7 @@ set(SRC
../include/ED_node.h
../include/ED_numinput.h
../include/ED_object.h
+ ../include/ED_outliner.h
../include/ED_paint.h
../include/ED_particle.h
../include/ED_physics.h
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 438eb1f3864..433c7603f35 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -38,6 +38,7 @@
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "DNA_scene_types.h"
#include "DNA_packedFile_types.h"
@@ -58,9 +59,12 @@
#include "BKE_paint.h"
#include "ED_armature.h"
+#include "ED_buttons.h"
#include "ED_image.h"
#include "ED_mesh.h"
+#include "ED_node.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_paint.h"
#include "ED_space_api.h"
#include "ED_util.h"
@@ -318,3 +322,25 @@ void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *ar, void *arg_info
glEnd();
setlinestyle(0);
}
+
+/**
+ * Use to free ID references within runtime data (stored outside of DNA)
+ *
+ * \note Typically notifiers take care of this,
+ * but there are times we have to free references immediately, see: T44376
+ */
+void ED_spacedata_id_unref(struct SpaceLink *sl, const ID *id)
+{
+
+ switch (sl->spacetype) {
+ case SPACE_OUTLINER:
+ ED_outliner_id_unref((SpaceOops *)sl, id);
+ break;
+ case SPACE_BUTS:
+ ED_buttons_id_unref((SpaceButs *)sl, id);
+ break;
+ case SPACE_NODE:
+ ED_node_id_unref((SpaceNode *)sl, id);
+ break;
+ }
+}
diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c
index 7f5edb5ea9e..7c4db697b01 100644
--- a/source/blender/editors/util/editmode_undo.c
+++ b/source/blender/editors/util/editmode_undo.c
@@ -84,6 +84,7 @@ typedef struct UndoElem {
void *undodata;
uintptr_t undosize;
char name[BKE_UNDO_STR_MAX];
+ Object *(*get_object)(const bContext *C);
void * (*getdata)(bContext * C);
void (*freedata)(void *);
void (*to_editmode)(void *, void *, void *);
@@ -106,14 +107,15 @@ static void undo_restore(UndoElem *undo, void *editdata, void *obdata)
/* name can be a dynamic string */
void undo_editmode_push(bContext *C, const char *name,
- void * (*getdata)(bContext * C),
+ Object *(*get_object)(const bContext *C),
+ void * (*getdata)(bContext *C),
void (*freedata)(void *),
void (*to_editmode)(void *, void *, void *),
void *(*from_editmode)(void *, void *),
int (*validate_undo)(void *, void *))
{
UndoElem *uel;
- Object *obedit = CTX_data_edit_object(C);
+ Object *obedit = get_object(C);
void *editdata;
int nr;
uintptr_t memused, totmem, maxmem;
@@ -133,6 +135,7 @@ void undo_editmode_push(bContext *C, const char *name,
BLI_strncpy(uel->name, name, sizeof(uel->name));
BLI_addtail(&undobase, uel);
+ uel->get_object = get_object;
uel->getdata = getdata;
uel->freedata = freedata;
uel->to_editmode = to_editmode;
@@ -193,19 +196,19 @@ void undo_editmode_push(bContext *C, const char *name,
static void undo_clean_stack(bContext *C)
{
UndoElem *uel, *next;
- Object *obedit = CTX_data_edit_object(C);
/* global undo changes pointers, so we also allow identical names */
/* side effect: when deleting/renaming object and start editing new one with same name */
uel = undobase.first;
while (uel) {
+ Object *obedit = uel->get_object(C);
void *editdata = uel->getdata(C);
bool is_valid = false;
next = uel->next;
/* for when objects are converted, renamed, or global undo changes pointers... */
- if (uel->type == obedit->type) {
+ if (obedit && uel->type == obedit->type) {
if (STREQ(uel->id.name, obedit->id.name)) {
if (uel->validate_undo == NULL)
is_valid = true;
@@ -232,12 +235,13 @@ static void undo_clean_stack(bContext *C)
/* 1 = an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation */
void undo_editmode_step(bContext *C, int step)
{
- Object *obedit = CTX_data_edit_object(C);
+ Object *obedit;
/* prevent undo to happen on wrong object, stack can be a mix */
undo_clean_stack(C);
if (step == 0) {
+ obedit = curundo->get_object(C);
undo_restore(curundo, curundo->getdata(C), obedit->data);
}
else if (step == 1) {
@@ -248,6 +252,7 @@ void undo_editmode_step(bContext *C, int step)
else {
if (G.debug & G_DEBUG) printf("undo %s\n", curundo->name);
curundo = curundo->prev;
+ obedit = curundo->get_object(C);
undo_restore(curundo, curundo->getdata(C), obedit->data);
}
}
@@ -258,15 +263,19 @@ void undo_editmode_step(bContext *C, int step)
error("No more steps to redo");
}
else {
+ obedit = curundo->get_object(C);
undo_restore(curundo->next, curundo->getdata(C), obedit->data);
curundo = curundo->next;
if (G.debug & G_DEBUG) printf("redo %s\n", curundo->name);
}
}
+ obedit = curundo->get_object(C);
+
/* special case for editmesh, mode must be copied back to the scene */
if (obedit->type == OB_MESH) {
- EDBM_selectmode_to_scene(C);
+ if (obedit == CTX_data_edit_object(C))
+ EDBM_selectmode_to_scene(C);
}
DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
@@ -315,7 +324,7 @@ void undo_editmode_name(bContext *C, const char *undoname)
}
/* undoname optionally, if NULL it just checks for existing undo steps */
-int undo_editmode_valid(const char *undoname)
+bool undo_editmode_is_valid(const char *undoname)
{
if (undoname) {
UndoElem *uel;
@@ -332,19 +341,20 @@ int undo_editmode_valid(const char *undoname)
/* get name of undo item, return null if no item with this index */
/* if active pointer, set it to 1 if true */
-const char *undo_editmode_get_name(bContext *C, int nr, int *active)
+const char *undo_editmode_get_name(bContext *C, int nr, bool *r_active)
{
UndoElem *uel;
/* prevent wrong numbers to be returned */
undo_clean_stack(C);
- if (active) *active = 0;
+ if (r_active) *r_active = false;
uel = BLI_findlink(&undobase, nr);
if (uel) {
- if (active && uel == curundo)
- *active = 1;
+ if (r_active && (uel == curundo)) {
+ *r_active = true;
+ }
return uel->name;
}
return NULL;
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index 050631362b4..effb45a61ab 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -73,14 +73,14 @@ void initNumInput(NumInput *n)
{
n->idx_max = 0;
n->unit_sys = USER_UNIT_NONE;
- fill_vn_i(n->unit_type, NUM_MAX_ELEMENTS, B_UNIT_NONE);
+ copy_vn_i(n->unit_type, NUM_MAX_ELEMENTS, B_UNIT_NONE);
n->unit_use_radians = false;
n->flag = 0;
- fill_vn_short(n->val_flag, NUM_MAX_ELEMENTS, 0);
+ copy_vn_short(n->val_flag, NUM_MAX_ELEMENTS, 0);
zero_v3(n->val);
- fill_vn_fl(n->val_org, NUM_MAX_ELEMENTS, 0.0f);
- fill_vn_fl(n->val_inc, NUM_MAX_ELEMENTS, 1.0f);
+ copy_vn_fl(n->val_org, NUM_MAX_ELEMENTS, 0.0f);
+ copy_vn_fl(n->val_inc, NUM_MAX_ELEMENTS, 1.0f);
n->idx = 0;
n->str[0] = '\0';
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index ab882a388ad..3eef8401db9 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -55,6 +55,7 @@
#include "ED_mball.h"
#include "ED_mesh.h"
#include "ED_object.h"
+#include "ED_physics.h"
#include "ED_render.h"
#include "ED_screen.h"
#include "ED_paint.h"
@@ -104,11 +105,14 @@ void ED_undo_push(bContext *C, const char *str)
PE_undo_push(CTX_data_scene(C), str);
}
+ else if (obact && obact->mode & OB_MODE_HAIR_EDIT) {
+ undo_push_strands(C, str);
+ }
else if (obact && obact->mode & OB_MODE_SCULPT) {
/* do nothing for now */
}
else {
- BKE_write_undo(C, str);
+ BKE_undo_write(C, str);
}
if (wm->file_saved) {
@@ -189,6 +193,14 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
else
PE_redo(scene);
}
+ else if (obact && obact->mode & OB_MODE_HAIR_EDIT) {
+ if (undoname)
+ undo_editmode_name(C, undoname);
+ else
+ undo_editmode_step(C, step);
+
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
+ }
else if (U.uiflag & USER_GLOBALUNDO) {
// note python defines not valid here anymore.
//#ifdef WITH_PYTHON
@@ -244,7 +256,7 @@ void ED_undo_pop_op(bContext *C, wmOperator *op)
}
/* name optionally, function used to check for operator redo panel */
-int ED_undo_valid(const bContext *C, const char *undoname)
+bool ED_undo_is_valid(const bContext *C, const char *undoname)
{
Object *obedit = CTX_data_edit_object(C);
Object *obact = CTX_data_active_object(C);
@@ -263,7 +275,7 @@ int ED_undo_valid(const bContext *C, const char *undoname)
}
else if (obedit) {
if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) {
- return undo_editmode_valid(undoname);
+ return undo_editmode_is_valid(undoname);
}
}
else {
@@ -271,19 +283,19 @@ int ED_undo_valid(const bContext *C, const char *undoname)
/* if below tests fail, global undo gets executed */
if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) {
- if (ED_undo_paint_valid(UNDO_PAINT_IMAGE, undoname))
+ if (ED_undo_paint_is_valid(UNDO_PAINT_IMAGE, undoname))
return 1;
}
else if (obact && obact->mode & OB_MODE_SCULPT) {
- if (ED_undo_paint_valid(UNDO_PAINT_MESH, undoname))
+ if (ED_undo_paint_is_valid(UNDO_PAINT_MESH, undoname))
return 1;
}
else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
- return PE_undo_valid(CTX_data_scene(C));
+ return PE_undo_is_valid(CTX_data_scene(C));
}
if (U.uiflag & USER_GLOBALUNDO) {
- return BKE_undo_valid(undoname);
+ return BKE_undo_is_valid(undoname);
}
}
return 0;
@@ -487,7 +499,8 @@ static int get_undo_system(bContext *C)
static EnumPropertyItem *rna_undo_itemf(bContext *C, int undosys, int *totitem)
{
EnumPropertyItem item_tmp = {0}, *item = NULL;
- int active, i = 0;
+ int i = 0;
+ bool active;
while (true) {
const char *name = NULL;
diff --git a/source/blender/editors/util/util_intern.h b/source/blender/editors/util/util_intern.h
index d366ad7997f..0f650330951 100644
--- a/source/blender/editors/util/util_intern.h
+++ b/source/blender/editors/util/util_intern.h
@@ -35,12 +35,12 @@
/* internal exports only */
/* editmode_undo.c */
-void undo_editmode_name (struct bContext *C, const char *undoname);
-int undo_editmode_valid (const char *undoname);
-const char *undo_editmode_get_name (struct bContext *C, int nr, int *active);
-void *undo_editmode_get_prev (struct Object *ob);
-void undo_editmode_step (struct bContext *C, int step);
-void undo_editmode_number (struct bContext *C, int nr);
+void undo_editmode_name(struct bContext *C, const char *undoname);
+bool undo_editmode_is_valid(const char *undoname);
+const char *undo_editmode_get_name(struct bContext *C, int nr, bool *r_active);
+void *undo_editmode_get_prev(struct Object *ob);
+void undo_editmode_step(struct bContext *C, int step);
+void undo_editmode_number(struct bContext *C, int nr);
#endif /* __UTIL_INTERN_H__ */
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index d1fd8d969a4..e028c08091c 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -34,18 +34,13 @@
struct MTexPoly;
struct Image;
-struct MTFace;
struct Object;
struct Scene;
struct SpaceImage;
-struct UvElementMap;
struct wmOperatorType;
struct BMEditMesh;
-struct BMesh;
struct BMFace;
struct BMLoop;
-struct BMEdge;
-struct BMVert;
/* visibility and selection */
bool uvedit_face_visible_nolocal(struct Scene *scene, struct BMFace *efa);
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index c70fcdbbd94..6ef9ed9352c 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -53,6 +53,8 @@
#include "BLI_blenlib.h"
#include "BLI_array.h"
+#include "BLF_translation.h"
+
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_depsgraph.h"
@@ -80,6 +82,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
#include "UI_view2d.h"
#include "uvedit_intern.h"
@@ -1028,7 +1032,7 @@ static int uv_select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestH
/* setup */
BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, 0, limit);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
@@ -1114,7 +1118,7 @@ static int uv_select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestH
/*********************** linked select ***********************/
-static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const float limit[2], NearestHit *hit, bool extend)
+static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const float limit[2], NearestHit *hit, bool extend, bool select_faces)
{
BMFace *efa;
BMLoop *l;
@@ -1131,7 +1135,7 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
- vmap = BM_uv_vert_map_create(em->bm, 1, limit);
+ vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false);
if (vmap == NULL)
return;
@@ -1144,15 +1148,24 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
if (uvedit_face_visible_test(scene, ima, efa, tf)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
+ if (select_faces) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
stack[stacksize] = a;
stacksize++;
flag[a] = 1;
+ }
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- break;
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+
+ break;
+ }
}
}
}
@@ -1204,13 +1217,21 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
if (!extend) {
BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
+ if (select_faces) {
if (flag[a])
- luv->flag |= MLOOPUV_VERTSEL;
+ BM_face_select_set(em->bm, efa, true);
else
- luv->flag &= ~MLOOPUV_VERTSEL;
+ BM_face_select_set(em->bm, efa, false);
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (flag[a])
+ luv->flag |= MLOOPUV_VERTSEL;
+ else
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
}
}
}
@@ -1219,17 +1240,23 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
if (!flag[a]) {
continue;
}
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
+
+ if (select_faces) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
break;
- }
}
-
- if (l) {
- break;
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ break;
+ }
+ }
+
+ if (l) {
+ break;
+ }
}
}
@@ -1239,10 +1266,15 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
continue;
}
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- luv->flag &= ~MLOOPUV_VERTSEL;
+ if (select_faces) {
+ BM_face_select_set(em->bm, efa, false);
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
}
}
}
@@ -1252,10 +1284,15 @@ static void uv_select_linked(Scene *scene, Image *ima, BMEditMesh *em, const flo
continue;
}
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- luv->flag |= MLOOPUV_VERTSEL;
+ if (select_faces) {
+ BM_face_select_set(em->bm, efa, true);
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
}
}
}
@@ -2087,7 +2124,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
/* mark 1 vertex as being hit */
hitv = BLI_array_alloca(hitv, hit.efa->len);
hituv = BLI_array_alloca(hituv, hit.efa->len);
- fill_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
+ copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
hituv[hit.lindex] = hit.luv->uv;
@@ -2104,7 +2141,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
/* mark 2 edge vertices as being hit */
hitv = BLI_array_alloca(hitv, hit.efa->len);
hituv = BLI_array_alloca(hituv, hit.efa->len);
- fill_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
+ copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v);
@@ -2154,7 +2191,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
flush = uv_select_edgeloop(scene, ima, em, &hit, limit, extend);
}
else if (selectmode == UV_SELECT_ISLAND) {
- uv_select_linked(scene, ima, em, limit, &hit, extend);
+ uv_select_linked(scene, ima, em, limit, &hit, extend, false);
}
else if (extend) {
if (selectmode == UV_SELECT_VERTEX) {
@@ -2375,11 +2412,12 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
BMEditMesh *em = BKE_editmesh_from_object(obedit);
float limit[2];
int extend;
+ bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
NearestHit hit, *hit_p = NULL;
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- BKE_report(op->reports, RPT_ERROR, "Cannot select linked when sync selection is enabled");
+ if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) {
+ BKE_report(op->reports, RPT_ERROR, "Select linked only works in face select mode when sync selection is enabled");
return OPERATOR_CANCELLED;
}
@@ -2405,7 +2443,7 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
hit_p = &hit;
}
- uv_select_linked(scene, ima, em, limit, hit_p, extend);
+ uv_select_linked(scene, ima, em, limit, hit_p, extend, select_faces);
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
@@ -2680,7 +2718,7 @@ static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object
uvedit_pixel_to_float(sima, limit, 0.05);
BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, 0, limit);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
if (vmap == NULL) {
return;
}
@@ -2771,7 +2809,7 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object
uvedit_pixel_to_float(sima, limit, 0.05);
BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, 0, limit);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
if (vmap == NULL) {
return;
}
@@ -3064,9 +3102,10 @@ static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short mo
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int use_face_center = (ts->uv_flag & UV_SYNC_SELECTION) ?
- (ts->selectmode == SCE_SELECT_FACE) :
- (ts->uv_selectmode == UV_SELECT_FACE);
+ const bool use_face_center = (
+ (ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_FACE) :
+ (ts->uv_selectmode == UV_SELECT_FACE));
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
@@ -4002,7 +4041,7 @@ static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
/* This code sets editvert->tmp.l to the index. This will be useful later on. */
BM_mesh_elem_table_ensure(bm, BM_FACE);
- vmap = BM_uv_vert_map_create(bm, 0, limit);
+ vmap = BM_uv_vert_map_create(bm, limit, false, false);
BM_ITER_MESH (editedge, &iter, bm, BM_EDGES_OF_MESH) {
/* flags to determine if we uv is separated from first editface match */
@@ -4107,7 +4146,7 @@ static void UV_OT_seams_from_islands(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "mark_sharp", 0, "Mark Sharp", "Mark boundary edges as sharp");
}
-static int uv_mark_seam_exec(bContext *C, wmOperator *UNUSED(op))
+static int uv_mark_seam_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
@@ -4117,13 +4156,17 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *UNUSED(op))
BMFace *efa;
BMLoop *loop;
BMIter iter, liter;
+ bool clear = RNA_boolean_get(op->ptr, "clear");
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) {
- BM_elem_flag_enable(loop->e, BM_ELEM_SEAM);
+ if (clear)
+ BM_elem_flag_disable(loop->e, BM_ELEM_SEAM);
+ else
+ BM_elem_flag_enable(loop->e, BM_ELEM_SEAM);
}
}
}
@@ -4139,10 +4182,27 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
+static int uv_mark_seam_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ uiPopupMenu *pup;
+ uiLayout *layout;
+
+ pup = UI_popup_menu_begin(C, IFACE_("Edges"), ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
+
+ uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
+ uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Mark Seam"), ICON_NONE, op->type->idname, "clear", false);
+ uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Seam"), ICON_NONE, op->type->idname, "clear", true);
+
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+}
+
static void UV_OT_mark_seam(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Mark Seams";
+ ot->name = "Mark Seam";
ot->description = "Mark selected UV edges as seams";
ot->idname = "UV_OT_mark_seam";
@@ -4151,7 +4211,10 @@ static void UV_OT_mark_seam(wmOperatorType *ot)
/* api callbacks */
ot->exec = uv_mark_seam_exec;
+ ot->invoke = uv_mark_seam_invoke;
ot->poll = ED_operator_uvedit;
+
+ RNA_def_boolean(ot->srna, "clear", false, "Clear Seams", "Clear instead of marking seams");
}
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 793f84b05ec..f915a4b2e51 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -681,7 +681,7 @@ void UV_OT_minimize_stretch(wmOperatorType *ot)
/* identifiers */
ot->name = "Minimize Stretch";
ot->idname = "UV_OT_minimize_stretch";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
ot->description = "Reduce UV stretching by relaxing angles";
/* api callbacks */
diff --git a/source/blender/freestyle/CMakeLists.txt b/source/blender/freestyle/CMakeLists.txt
index 7fbb219af08..c14a5c53734 100644
--- a/source/blender/freestyle/CMakeLists.txt
+++ b/source/blender/freestyle/CMakeLists.txt
@@ -491,6 +491,7 @@ set(SRC
intern/system/TimeUtils.h
intern/view_map/ArbitraryGridDensityProvider.cpp
intern/view_map/ArbitraryGridDensityProvider.h
+ intern/view_map/AutoPtrHelper.h
intern/view_map/AverageAreaGridDensityProvider.cpp
intern/view_map/AverageAreaGridDensityProvider.h
intern/view_map/BoxGrid.cpp
diff --git a/source/blender/freestyle/FRS_freestyle.h b/source/blender/freestyle/FRS_freestyle.h
index 9766372507b..975b1212695 100644
--- a/source/blender/freestyle/FRS_freestyle.h
+++ b/source/blender/freestyle/FRS_freestyle.h
@@ -45,9 +45,10 @@ void FRS_initialize(void);
void FRS_set_context(struct bContext *C);
void FRS_read_file(struct bContext *C);
int FRS_is_freestyle_enabled(struct SceneRenderLayer *srl);
-void FRS_init_stroke_rendering(struct Render *re);
+void FRS_init_stroke_renderer(struct Render *re);
+void FRS_begin_stroke_rendering(struct Render *re);
struct Render *FRS_do_stroke_rendering(struct Render *re, struct SceneRenderLayer *srl, int render);
-void FRS_finish_stroke_rendering(struct Render *re);
+void FRS_end_stroke_rendering(struct Render *re);
void FRS_free_view_map_cache(void);
void FRS_composite_result(struct Render *re, struct SceneRenderLayer *srl, struct Render *freestyle_render);
void FRS_exit(void);
diff --git a/source/blender/freestyle/intern/application/AppView.cpp b/source/blender/freestyle/intern/application/AppView.cpp
index ae202412c09..9de426b91ab 100644
--- a/source/blender/freestyle/intern/application/AppView.cpp
+++ b/source/blender/freestyle/intern/application/AppView.cpp
@@ -58,7 +58,7 @@ extern "C" {
namespace Freestyle {
-AppView::AppView(const char *iName)
+AppView::AppView(const char * /*iName*/)
{
_Fovy = DEG2RADF(30.0f);
_ModelRootNode = new NodeDrawingStyle;
diff --git a/source/blender/freestyle/intern/application/AppView.h b/source/blender/freestyle/intern/application/AppView.h
index 14101909ca1..6338ace53c0 100644
--- a/source/blender/freestyle/intern/application/AppView.h
+++ b/source/blender/freestyle/intern/application/AppView.h
@@ -100,12 +100,12 @@ public:
_SilhouetteRootNode->AddChild(iSilhouette);
}
- inline void Add2DSilhouette(NodeGroup *iSilhouette)
+ inline void Add2DSilhouette(NodeGroup * /*iSilhouette*/)
{
//_pFENode->AddChild(iSilhouette);
}
- inline void Add2DVisibleSilhouette(NodeGroup *iVSilhouette)
+ inline void Add2DVisibleSilhouette(NodeGroup * /*iVSilhouette*/)
{
//_pVisibleSilhouetteNode->AddChild(iVSilhouette);
}
diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp
index 8d9b1a4fb52..5cd2e16847d 100644
--- a/source/blender/freestyle/intern/application/Controller.cpp
+++ b/source/blender/freestyle/intern/application/Controller.cpp
@@ -927,13 +927,19 @@ void Controller::InsertStyleModule(unsigned index, const char *iFileName)
_Canvas->InsertStyleModule(index, sm);
}
+void Controller::InsertStyleModule(unsigned index, const char *iName, const char *iBuffer)
+{
+ StyleModule *sm = new BufferedStyleModule(iBuffer, iName, _inter);
+ _Canvas->InsertStyleModule(index, sm);
+}
+
void Controller::InsertStyleModule(unsigned index, const char *iName, struct Text *iText)
{
StyleModule *sm = new BlenderStyleModule(iText, iName, _inter);
_Canvas->InsertStyleModule(index, sm);
}
-void Controller::AddStyleModule(const char *iFileName)
+void Controller::AddStyleModule(const char * /*iFileName*/)
{
//_pStyleWindow->Add(iFileName);
}
@@ -1003,7 +1009,7 @@ void Controller::toggleEdgeTesselationNature(Nature::EdgeNature iNature)
ComputeViewMap();
}
-void Controller::setModelsDir(const string& dir)
+void Controller::setModelsDir(const string& /*dir*/)
{
//_current_dirs->setValue("models/dir", dir);
}
@@ -1015,7 +1021,7 @@ string Controller::getModelsDir() const
return dir;
}
-void Controller::setModulesDir(const string& dir)
+void Controller::setModulesDir(const string& /*dir*/)
{
//_current_dirs->setValue("modules/dir", dir);
}
diff --git a/source/blender/freestyle/intern/application/Controller.h b/source/blender/freestyle/intern/application/Controller.h
index 9fe57d92cf4..a09964a4e79 100644
--- a/source/blender/freestyle/intern/application/Controller.h
+++ b/source/blender/freestyle/intern/application/Controller.h
@@ -90,6 +90,7 @@ public:
Render *RenderStrokes(Render *re, bool render);
void SwapStyleModules(unsigned i1, unsigned i2);
void InsertStyleModule(unsigned index, const char *iFileName);
+ void InsertStyleModule(unsigned index, const char *iName, const char *iBuffer);
void InsertStyleModule(unsigned index, const char *iName, struct Text *iText);
void AddStyleModule(const char *iFileName);
void RemoveStyleModule(unsigned index);
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
index dfcc77d3b23..bcb38bc5971 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
@@ -64,12 +64,11 @@ NodeGroup *BlenderFileLoader::Load()
_viewplane_bottom = _re->viewplane.ymin;
_viewplane_top = _re->viewplane.ymax;
- if ((_re->r.scemode & R_VIEWPORT_PREVIEW) && (_re->r.mode & R_ORTHO)) {
+ if (_re->clipsta < 0.f) {
// Adjust clipping start/end and set up a Z offset when the viewport preview
// is used with the orthographic view. In this case, _re->clipsta is negative,
// while Freestyle assumes that imported mesh data are in the camera coordinate
// system with the view point located at origin [bug #36009].
- BLI_assert(_re->clipsta < 0.f);
_z_near = -0.001f;
_z_offset = _re->clipsta + _z_near;
_z_far = -_re->clipend + _z_offset;
@@ -256,6 +255,7 @@ void BlenderFileLoader::clipTriangle(int numTris, float triCoords[][3], float v1
}
}
BLI_assert(k == 2 + numTris);
+ (void)numTris; /* Ignored in release builds. */
}
void BlenderFileLoader::addTriangle(struct LoaderState *ls, float v1[3], float v2[3], float v3[3],
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index f304e8ae9bd..64ef49d74a3 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -94,7 +94,7 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
//freestyle_scene->r.maximsize = old_scene->r.maximsize; /* DEPRECATED */
freestyle_scene->r.ocres = old_scene->r.ocres;
freestyle_scene->r.color_mgt_flag = 0; // old_scene->r.color_mgt_flag;
- freestyle_scene->r.scemode = old_scene->r.scemode & ~(R_SINGLE_LAYER | R_NO_FRAME_UPDATE);
+ freestyle_scene->r.scemode = old_scene->r.scemode & ~(R_SINGLE_LAYER | R_NO_FRAME_UPDATE | R_MULTIVIEW);
freestyle_scene->r.flag = old_scene->r.flag;
freestyle_scene->r.threads = old_scene->r.threads;
freestyle_scene->r.border.xmin = old_scene->r.border.xmin;
@@ -126,7 +126,8 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
BKE_scene_set_background(freestyle_bmain, freestyle_scene);
// Camera
- Object *object_camera = BKE_object_add(freestyle_bmain, freestyle_scene, OB_CAMERA);
+ Object *object_camera = BKE_object_add(freestyle_bmain, freestyle_scene, OB_CAMERA, NULL);
+ DAG_relations_tag_update(freestyle_bmain);
Camera *camera = (Camera *)object_camera->data;
camera->type = CAM_ORTHO;
@@ -506,6 +507,7 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
// If still no material, create one
if (!has_mat) {
Material *ma = BKE_material_add(freestyle_bmain, "stroke_material");
+ DAG_relations_tag_update(freestyle_bmain);
ma->mode |= MA_VERTEXCOLP;
ma->mode |= MA_TRANSP;
ma->mode |= MA_SHLESS;
@@ -668,6 +670,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
{
#if 0
Object *object_mesh = BKE_object_add(freestyle_bmain, freestyle_scene, OB_MESH);
+ DAG_relations_tag_update(freestyle_bmain);
#else
Object *object_mesh = NewMesh();
#endif
@@ -938,6 +941,7 @@ Object *BlenderStrokeRenderer::NewMesh() const
ob->lay = 1;
base = BKE_scene_base_add(freestyle_scene, ob);
+ DAG_relations_tag_update(freestyle_bmain);
#if 0
BKE_scene_base_deselect_all(scene);
BKE_scene_base_select(scene, base);
@@ -950,7 +954,7 @@ Object *BlenderStrokeRenderer::NewMesh() const
return ob;
}
-Render *BlenderStrokeRenderer::RenderScene(Render *re, bool render)
+Render *BlenderStrokeRenderer::RenderScene(Render * /*re*/, bool render)
{
Camera *camera = (Camera *)freestyle_scene->camera->data;
if (camera->clipend < _z)
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h b/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h
index 21776396ebc..1d73125f627 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h
@@ -31,12 +31,39 @@
extern "C" {
#include "BLI_utildefines.h" // BLI_assert()
-struct Scene;
struct Text;
}
namespace Freestyle {
+class BufferedStyleModule : public StyleModule
+{
+public:
+ BufferedStyleModule(const string& buffer, const string& file_name, Interpreter *inter) : StyleModule(file_name, inter)
+ {
+ _buffer = buffer;
+ }
+
+ virtual ~BufferedStyleModule()
+ {
+ }
+
+protected:
+ virtual int interpret()
+ {
+ PythonInterpreter *py_inter = dynamic_cast<PythonInterpreter*>(_inter);
+ BLI_assert(py_inter != 0);
+ return py_inter->interpretString(_buffer, getFileName());
+ }
+
+private:
+ string _buffer;
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BufferedStyleModule")
+#endif
+};
+
class BlenderStyleModule : public StyleModule
{
public:
@@ -63,7 +90,6 @@ private:
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BlenderStyleModule")
#endif
-
};
} /* namespace Freestyle */
diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
index 32b4c5455a7..46724ff530a 100644
--- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
+++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
@@ -87,7 +87,7 @@ int freestyle_viewport[4];
// current scene
Scene *freestyle_scene;
-static void load_post_callback(struct Main *main, struct ID *id, void *arg)
+static void load_post_callback(struct Main * /*main*/, struct ID * /*id*/, void * /*arg*/)
{
lineset_copied = false;
}
@@ -211,16 +211,12 @@ static char *escape_quotes(char *name)
return s;
}
-static Text *create_lineset_handler(Main *bmain, char *layer_name, char *lineset_name)
+static char * create_lineset_handler(char *layer_name, char *lineset_name)
{
+ const char *fmt = "__import__('parameter_editor').process('%s', '%s')\n";
char *s1 = escape_quotes(layer_name);
char *s2 = escape_quotes(lineset_name);
- Text *text = BKE_text_add(bmain, lineset_name);
- BKE_text_write(text, "import parameter_editor; parameter_editor.process('");
- BKE_text_write(text, s1);
- BKE_text_write(text, "', '");
- BKE_text_write(text, s2);
- BKE_text_write(text, "')\n");
+ char *text = BLI_sprintfN(fmt, s1, s2);
MEM_freeN(s1);
MEM_freeN(s2);
return text;
@@ -293,7 +289,7 @@ static bool test_edge_type_conditions(struct edge_type_condition *conditions,
return true;
}
-static void prepare(Main *bmain, Render *re, SceneRenderLayer *srl)
+static void prepare(Render *re, SceneRenderLayer *srl)
{
// load mesh
re->i.infostr = "Freestyle: Mesh loading";
@@ -369,9 +365,10 @@ static void prepare(Main *bmain, Render *re, SceneRenderLayer *srl)
cout << " " << layer_count+1 << ": " << lineset->name << " - " <<
(lineset->linestyle ? (lineset->linestyle->id.name + 2) : "<NULL>") << endl;
}
- Text *text = create_lineset_handler(bmain, srl->name, lineset->name);
- controller->InsertStyleModule(layer_count, lineset->name, text);
+ char *buffer = create_lineset_handler(srl->name, lineset->name);
+ controller->InsertStyleModule(layer_count, lineset->name, buffer);
controller->toggleLayer(layer_count, true);
+ MEM_freeN(buffer);
if (!(lineset->selection & FREESTYLE_SEL_EDGE_TYPES) || !lineset->edge_types) {
++use_ridges_and_valleys;
++use_suggestive_contours;
@@ -494,13 +491,20 @@ void FRS_composite_result(Render *re, SceneRenderLayer *srl, Render *freestyle_r
return;
rl = render_get_active_layer( freestyle_render, freestyle_render->result );
- if (!rl || rl->rectf == NULL) {
+ if (!rl) {
if (G.debug & G_DEBUG_FREESTYLE) {
- cout << "No Freestyle result image to composite" << endl;
+ cout << "No source render layer to composite" << endl;
+ }
+ return;
+ }
+
+ src = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, freestyle_render->viewname);
+ if (!src) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "No source result image to composite" << endl;
}
return;
}
- src = rl->rectf;
#if 0
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "src: " << rl->rectx << " x " << rl->recty << endl;
@@ -508,13 +512,19 @@ void FRS_composite_result(Render *re, SceneRenderLayer *srl, Render *freestyle_r
#endif
rl = RE_GetRenderLayer(re->result, srl->name);
- if (!rl || rl->rectf == NULL) {
+ if (!rl) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "No destination render layer to composite to" << endl;
+ }
+ return;
+ }
+ dest = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, re->viewname);
+ if (!dest) {
if (G.debug & G_DEBUG_FREESTYLE) {
- cout << "No layer to composite to" << endl;
+ cout << "No destination result image to composite to" << endl;
}
return;
}
- dest = rl->rectf;
#if 0
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "dest: " << rl->rectx << " x " << rl->recty << endl;
@@ -566,7 +576,7 @@ int FRS_is_freestyle_enabled(SceneRenderLayer *srl)
return (!(srl->layflag & SCE_LAY_DISABLE) && srl->layflag & SCE_LAY_FRS && displayed_layer_count(srl) > 0);
}
-void FRS_init_stroke_rendering(Render *re)
+void FRS_init_stroke_renderer(Render *re)
{
if (G.debug & G_DEBUG_FREESTYLE) {
cout << endl;
@@ -576,16 +586,18 @@ void FRS_init_stroke_rendering(Render *re)
}
init_view(re);
- init_camera(re);
controller->ResetRenderCount();
}
+void FRS_begin_stroke_rendering(Render *re)
+{
+ init_camera(re);
+}
+
Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
{
- Main *freestyle_bmain = re->freestyle_bmain;
Render *freestyle_render = NULL;
- Text *text, *next_text;
if (!render)
return controller->RenderStrokes(re, false);
@@ -606,7 +618,7 @@ Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
// - add style modules
// - set parameters
// - compute view map
- prepare(freestyle_bmain, re, srl);
+ prepare(re, srl);
if (re->test_break(re->tbh)) {
controller->CloseFile();
@@ -634,18 +646,10 @@ Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
}
}
- // Free temp main (currently only text blocks are stored there)
- for (text = (Text *)freestyle_bmain->text.first; text; text = next_text) {
- next_text = (Text *) text->id.next;
-
- BKE_text_unlink(freestyle_bmain, text);
- BKE_libblock_free(freestyle_bmain, text);
- }
-
return freestyle_render;
}
-void FRS_finish_stroke_rendering(Render *re)
+void FRS_end_stroke_rendering(Render * /*re*/)
{
// clear canvas
controller->Clear();
diff --git a/source/blender/freestyle/intern/geometry/GeomUtils.cpp b/source/blender/freestyle/intern/geometry/GeomUtils.cpp
index a750cf2f7cf..3eb92c559fe 100644
--- a/source/blender/freestyle/intern/geometry/GeomUtils.cpp
+++ b/source/blender/freestyle/intern/geometry/GeomUtils.cpp
@@ -495,7 +495,7 @@ bool intersectRayBBox(const Vec3r& orig, const Vec3r& dir, // ray origin an
real t0, real t1,
real& tmin, // I0 = orig + tmin * dir is the first intersection
real& tmax, // I1 = orig + tmax * dir is the second intersection
- real epsilon)
+ real /*epsilon*/)
{
float tymin, tymax, tzmin, tzmax;
Vec3r inv_direction(1.0 / dir[0], 1.0 / dir[1], 1.0 / dir[2]);
diff --git a/source/blender/freestyle/intern/geometry/Grid.h b/source/blender/freestyle/intern/geometry/Grid.h
index c1d04f6b4cc..62c0e58232a 100644
--- a/source/blender/freestyle/intern/geometry/Grid.h
+++ b/source/blender/freestyle/intern/geometry/Grid.h
@@ -97,11 +97,11 @@ class GridVisitor
public:
virtual ~GridVisitor() {}; //soc
- virtual void discoverCell(Cell *cell) {}
+ virtual void discoverCell(Cell * /*cell*/) {}
- virtual void examineOccluder(Polygon3r *occ) {}
+ virtual void examineOccluder(Polygon3r * /*occ*/) {}
- virtual void finishCell(Cell *cell) {}
+ virtual void finishCell(Cell * /*cell*/) {}
virtual bool stop() {
return false;
diff --git a/source/blender/freestyle/intern/image/Image.h b/source/blender/freestyle/intern/image/Image.h
index 577dc0fb866..2e78e784214 100644
--- a/source/blender/freestyle/intern/image/Image.h
+++ b/source/blender/freestyle/intern/image/Image.h
@@ -134,7 +134,7 @@ public:
return _height;
}
- /*! Returns the grey value for pixel x,y */
+ /*! Returns the gray value for pixel x,y */
virtual float pixel(unsigned x, unsigned y) const = 0;
/*! Sets the array.
diff --git a/source/blender/freestyle/intern/image/ImagePyramid.cpp b/source/blender/freestyle/intern/image/ImagePyramid.cpp
index 251f47bc44c..b81f8303945 100644
--- a/source/blender/freestyle/intern/image/ImagePyramid.cpp
+++ b/source/blender/freestyle/intern/image/ImagePyramid.cpp
@@ -42,7 +42,7 @@ ImagePyramid::ImagePyramid(const GrayImage& level0, unsigned nbLevels)
}
#endif
-ImagePyramid::ImagePyramid(const ImagePyramid& iBrother)
+ImagePyramid::ImagePyramid(const ImagePyramid& /*iBrother*/)
{
if (!_levels.empty()) {
for (vector<GrayImage*>::iterator im = _levels.begin(), imend = _levels.end(); im != imend; ++im) {
diff --git a/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp b/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp
index ad54a81f156..50d82656819 100644
--- a/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp
+++ b/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp
@@ -46,7 +46,7 @@ static char ContextFunctions_get_time_stamp___doc__[] =
" :rtype: int\n";
static PyObject *
-ContextFunctions_get_time_stamp(PyObject *self)
+ContextFunctions_get_time_stamp(PyObject * /*self*/)
{
return PyLong_FromLong(ContextFunctions::GetTimeStampCF());
}
@@ -60,7 +60,7 @@ static char ContextFunctions_get_canvas_width___doc__[] =
" :rtype: int\n";
static PyObject *
-ContextFunctions_get_canvas_width(PyObject *self)
+ContextFunctions_get_canvas_width(PyObject * /*self*/)
{
return PyLong_FromLong(ContextFunctions::GetCanvasWidthCF());
}
@@ -74,7 +74,7 @@ static char ContextFunctions_get_canvas_height___doc__[] =
" :rtype: int\n";
static PyObject *
-ContextFunctions_get_canvas_height(PyObject *self)
+ContextFunctions_get_canvas_height(PyObject * /*self*/)
{
return PyLong_FromLong(ContextFunctions::GetCanvasHeightCF());
}
@@ -88,7 +88,7 @@ static char ContextFunctions_get_border___doc__[] =
" :rtype: tuple\n";
static PyObject *
-ContextFunctions_get_border(PyObject *self)
+ContextFunctions_get_border(PyObject * /*self*/)
{
BBox<Vec2i> border(ContextFunctions::GetBorderCF());
PyObject *v = PyTuple_New(4);
@@ -117,7 +117,7 @@ static char ContextFunctions_load_map___doc__[] =
" :type sigma: float\n";
static PyObject *
-ContextFunctions_load_map(PyObject *self, PyObject *args, PyObject *kwds)
+ContextFunctions_load_map(PyObject * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"file_name", "map_name", "num_levels", "sigma", NULL};
char *fileName, *mapName;
@@ -150,7 +150,7 @@ static char ContextFunctions_read_map_pixel___doc__[] =
" :rtype: float\n";
static PyObject *
-ContextFunctions_read_map_pixel(PyObject *self, PyObject *args, PyObject *kwds)
+ContextFunctions_read_map_pixel(PyObject * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"map_name", "level", "x", "y", NULL};
char *mapName;
@@ -180,7 +180,7 @@ static char ContextFunctions_read_complete_view_map_pixel___doc__[] =
" :rtype: float\n";
static PyObject *
-ContextFunctions_read_complete_view_map_pixel(PyObject *self, PyObject *args, PyObject *kwds)
+ContextFunctions_read_complete_view_map_pixel(PyObject * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"level", "x", "y", NULL};
int level;
@@ -212,7 +212,7 @@ static char ContextFunctions_read_directional_view_map_pixel___doc__[] =
" :rtype: float\n";
static PyObject *
-ContextFunctions_read_directional_view_map_pixel(PyObject *self, PyObject *args, PyObject *kwds)
+ContextFunctions_read_directional_view_map_pixel(PyObject * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"orientation", "level", "x", "y", NULL};
int orientation, level;
@@ -232,7 +232,7 @@ static char ContextFunctions_get_selected_fedge___doc__[] =
" :rtype: :class:`FEdge`\n";
static PyObject *
-ContextFunctions_get_selected_fedge(PyObject *self)
+ContextFunctions_get_selected_fedge(PyObject * /*self*/)
{
FEdge *fe = ContextFunctions::GetSelectedFEdgeCF();
if (fe)
diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
index 487a473b7bd..d22632040f4 100644
--- a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
@@ -72,7 +72,7 @@ static char Freestyle_getCurrentScene___doc__[] =
" :return: The current scene.\n"
" :rtype: :class:`bpy.types.Scene`\n";
-static PyObject *Freestyle_getCurrentScene(PyObject *self)
+static PyObject *Freestyle_getCurrentScene(PyObject * /*self*/)
{
if (!freestyle_scene) {
PyErr_SetString(PyExc_TypeError, "current scene not available");
@@ -126,7 +126,7 @@ static char Freestyle_blendRamp___doc__[] =
" :return: Blended color in RGB format.\n"
" :rtype: :class:`mathutils.Vector`\n";
-static PyObject *Freestyle_blendRamp(PyObject *self, PyObject *args)
+static PyObject *Freestyle_blendRamp(PyObject * /*self*/, PyObject *args)
{
PyObject *obj1, *obj2;
char *s;
@@ -170,7 +170,7 @@ static char Freestyle_evaluateColorRamp___doc__[] =
" :return: color in RGBA format.\n"
" :rtype: :class:`mathutils.Vector`\n";
-static PyObject *Freestyle_evaluateColorRamp(PyObject *self, PyObject *args)
+static PyObject *Freestyle_evaluateColorRamp(PyObject * /*self*/, PyObject *args)
{
BPy_StructRNA *py_srna;
ColorBand *coba;
@@ -207,7 +207,7 @@ static char Freestyle_evaluateCurveMappingF___doc__[] =
" :return: Mapped output value.\n"
" :rtype: float\n";
-static PyObject *Freestyle_evaluateCurveMappingF(PyObject *self, PyObject *args)
+static PyObject *Freestyle_evaluateCurveMappingF(PyObject * /*self*/, PyObject *args)
{
BPy_StructRNA *py_srna;
CurveMapping *cumap;
diff --git a/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp b/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp
index 4d0d140474a..a36d446fcb7 100644
--- a/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp
+++ b/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp
@@ -30,6 +30,9 @@
extern "C" {
#endif
+#include "BLI_hash_mm2a.h"
+
+
///////////////////////////////////////////////////////////////////////////////////////////
//-------------------MODULE INITIALIZATION--------------------------------
@@ -478,6 +481,48 @@ static PyGetSetDef BPy_FrsMaterial_getseters[] = {
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
+static PyObject *BPy_FrsMaterial_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
+{
+ const BPy_FrsMaterial *matA = NULL, *matB = NULL;
+ bool result = 0;
+
+ if (!BPy_FrsMaterial_Check(objectA) || !BPy_FrsMaterial_Check(objectB)) {
+ if (comparison_type == Py_NE) {
+ Py_RETURN_TRUE;
+ }
+ else {
+ Py_RETURN_FALSE;
+ }
+ }
+
+ matA = (BPy_FrsMaterial *)objectA;
+ matB = (BPy_FrsMaterial *)objectB;
+
+ switch (comparison_type) {
+ case Py_NE:
+ result = (*matA->m) != (*matB->m);
+ break;
+ case Py_EQ:
+ result = (*matA->m) == (*matB->m);
+ break;
+ default:
+ PyErr_SetString(PyExc_TypeError, "Material does not support this comparison type");
+ return NULL;
+ }
+
+ if (result == true) {
+ Py_RETURN_TRUE;
+ }
+ else {
+ Py_RETURN_FALSE;
+ }
+}
+
+
+static Py_hash_t FrsMaterial_hash(PyObject *self)
+{
+ return (Py_uhash_t)BLI_hash_mm2((const unsigned char *)self, sizeof(*self), 0);
+}
/*-----------------------BPy_FrsMaterial type definition ------------------------------*/
PyTypeObject FrsMaterial_Type = {
@@ -494,7 +539,7 @@ PyTypeObject FrsMaterial_Type = {
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
- 0, /* tp_hash */
+ (hashfunc)FrsMaterial_hash, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
@@ -504,7 +549,7 @@ PyTypeObject FrsMaterial_Type = {
FrsMaterial_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
- 0, /* tp_richcompare */
+ (richcmpfunc)BPy_FrsMaterial_richcmpr, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
diff --git a/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp b/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp
index 7a3624f248e..0db25753caa 100644
--- a/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp
+++ b/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp
@@ -63,7 +63,7 @@ PyDoc_STRVAR(Integrator_integrate_doc,
" :class:`UnaryFunction0DUnsigned` type.\n"
" :rtype: int or float");
-static PyObject * Integrator_integrate(PyObject *self, PyObject *args, PyObject *kwds)
+static PyObject * Integrator_integrate(PyObject * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"func", "it", "it_end", "integration_type", NULL};
PyObject *obj1, *obj4 = 0;
diff --git a/source/blender/freestyle/intern/python/BPy_Operators.cpp b/source/blender/freestyle/intern/python/BPy_Operators.cpp
index 57ec15f4150..1b2b18c2c99 100644
--- a/source/blender/freestyle/intern/python/BPy_Operators.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Operators.cpp
@@ -34,6 +34,8 @@
#include "BPy_StrokeShader.h"
#include "BPy_Convert.h"
+#include <sstream>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -76,7 +78,7 @@ PyDoc_STRVAR(Operators_select_doc,
" :arg pred: The predicate expressing this condition.\n"
" :type pred: :class:`UnaryPredicate1D`");
-static PyObject *Operators_select(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_select(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"pred", NULL};
PyObject *obj = 0;
@@ -135,7 +137,7 @@ PyDoc_STRVAR(Operators_chain_doc,
" stopping condition.\n"
" :type pred: :class:`UnaryPredicate1D`");
-static PyObject *Operators_chain(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_chain(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"it", "pred", "modifier", NULL};
PyObject *obj1 = 0, *obj2 = 0, *obj3 = 0;
@@ -224,7 +226,7 @@ PyDoc_STRVAR(Operators_bidirectional_chain_doc,
" contains the chaining rule.\n"
" :type it: :class:`ChainingIterator`");
-static PyObject *Operators_bidirectional_chain(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_bidirectional_chain(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"it", "pred", NULL};
PyObject *obj1 = 0, *obj2 = 0;
@@ -304,7 +306,7 @@ PyDoc_STRVAR(Operators_sequential_split_doc,
" resolution.)\n"
" :type sampling: float");
-static PyObject *Operators_sequential_split(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_sequential_split(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist_1[] = {"starting_pred", "stopping_pred", "sampling", NULL};
static const char *kwlist_2[] = {"pred", "sampling", NULL};
@@ -411,7 +413,7 @@ PyDoc_STRVAR(Operators_recursive_split_doc,
" resolution.)\n"
" :type sampling: float");
-static PyObject *Operators_recursive_split(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_recursive_split(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist_1[] = {"func", "pred_1d", "sampling", NULL};
static const char *kwlist_2[] = {"func", "pred_0d", "pred_1d", "sampling", NULL};
@@ -486,7 +488,7 @@ PyDoc_STRVAR(Operators_sort_doc,
" :arg pred: The binary predicate used for the comparison.\n"
" :type pred: :class:`BinaryPredicate1D`");
-static PyObject *Operators_sort(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_sort(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"pred", NULL};
PyObject *obj = 0;
@@ -517,7 +519,7 @@ PyDoc_STRVAR(Operators_create_doc,
" :arg shaders: The list of shaders used to shade the strokes.\n"
" :type shaders: list of :class:`StrokeShader` objects");
-static PyObject *Operators_create(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_create(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"pred", "shaders", NULL};
PyObject *obj1 = 0, *obj2 = 0;
@@ -539,7 +541,15 @@ static PyObject *Operators_create(BPy_Operators *self, PyObject *args, PyObject
PyErr_SetString(PyExc_TypeError, "Operators.create(): 2nd argument must be a list of StrokeShader objects");
return NULL;
}
- shaders.push_back(((BPy_StrokeShader *)py_ss)->ss);
+ StrokeShader *shader = ((BPy_StrokeShader *)py_ss)->ss;
+ if (!shader) {
+ stringstream ss;
+ ss << "Operators.create(): item " << (i + 1)
+ << " of the shaders list is invalid likely due to missing call of StrokeShader.__init__()";
+ PyErr_SetString(PyExc_TypeError, ss.str().c_str());
+ return NULL;
+ }
+ shaders.push_back(shader);
}
if (Operators::create(*(((BPy_UnaryPredicate1D *)obj1)->up1D), shaders) < 0) {
if (!PyErr_Occurred())
@@ -558,7 +568,7 @@ PyDoc_STRVAR(Operators_reset_doc,
" :arg delete_strokes: Delete the strokes that are currently stored.\n"
" :type delete_strokes: bool\n");
-static PyObject *Operators_reset(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_reset(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"delete_strokes", NULL};
PyObject *obj1 = 0;
@@ -583,7 +593,7 @@ PyDoc_STRVAR(Operators_get_viewedge_from_index_doc,
" :return: The ViewEdge object.\n"
" :rtype: :class:`ViewEdge`");
-static PyObject *Operators_get_viewedge_from_index(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_get_viewedge_from_index(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"i", NULL};
unsigned int i;
@@ -607,7 +617,7 @@ PyDoc_STRVAR(Operators_get_chain_from_index_doc,
" :return: The Chain object.\n"
" :rtype: :class:`Chain`");
-static PyObject *Operators_get_chain_from_index(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_get_chain_from_index(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"i", NULL};
unsigned int i;
@@ -631,7 +641,7 @@ PyDoc_STRVAR(Operators_get_stroke_from_index_doc,
" :return: The Stroke object.\n"
" :rtype: :class:`Stroke`");
-static PyObject *Operators_get_stroke_from_index(BPy_Operators *self, PyObject *args, PyObject *kwds)
+static PyObject *Operators_get_stroke_from_index(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"i", NULL};
unsigned int i;
@@ -653,7 +663,7 @@ PyDoc_STRVAR(Operators_get_view_edges_size_doc,
" :return: The number of ViewEdges.\n"
" :rtype: int");
-static PyObject *Operators_get_view_edges_size(BPy_Operators *self)
+static PyObject *Operators_get_view_edges_size(BPy_Operators * /*self*/)
{
return PyLong_FromLong(Operators::getViewEdgesSize());
}
@@ -666,7 +676,7 @@ PyDoc_STRVAR(Operators_get_chains_size_doc,
" :return: The number of Chains.\n"
" :rtype: int");
-static PyObject *Operators_get_chains_size(BPy_Operators *self)
+static PyObject *Operators_get_chains_size(BPy_Operators * /*self*/)
{
return PyLong_FromLong(Operators::getChainsSize());
}
@@ -679,7 +689,7 @@ PyDoc_STRVAR(Operators_get_strokes_size_doc,
" :return: The number of Strokes.\n"
" :rtype: int");
-static PyObject *Operators_get_strokes_size(BPy_Operators *self)
+static PyObject *Operators_get_strokes_size(BPy_Operators * /*self*/)
{
return PyLong_FromLong(Operators::getStrokesSize());
}
diff --git a/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp b/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp
index be20febba2b..0941efe9df5 100644
--- a/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp
+++ b/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp
@@ -93,7 +93,7 @@ static void UnaryFunction0D___dealloc__(BPy_UnaryFunction0D *self)
Py_TYPE(self)->tp_free((PyObject *)self);
}
-static PyObject *UnaryFunction0D___repr__(BPy_UnaryFunction0D *self)
+static PyObject *UnaryFunction0D___repr__(BPy_UnaryFunction0D * /*self*/)
{
return PyUnicode_FromString("UnaryFunction0D");
}
diff --git a/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp b/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp
index b88d609e48d..1b82c7777c7 100644
--- a/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp
+++ b/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp
@@ -87,7 +87,7 @@ static void UnaryFunction1D___dealloc__(BPy_UnaryFunction1D *self)
Py_TYPE(self)->tp_free((PyObject *)self);
}
-static PyObject *UnaryFunction1D___repr__(BPy_UnaryFunction1D *self)
+static PyObject *UnaryFunction1D___repr__(BPy_UnaryFunction1D * /*self*/)
{
return PyUnicode_FromString("UnaryFunction1D");
}
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp
index 1ef29792d56..9f0660baa9b 100644
--- a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp
@@ -188,7 +188,10 @@ static PyObject *CurvePoint_fedge_get(BPy_CurvePoint *self, void *UNUSED(closure
{
SVertex *A = self->cp->A();
Interface0D *B = (Interface0D *)self->cp->B();
- return Any_BPy_Interface1D_from_Interface1D(*(A->getFEdge(*B)));
+ // B can be NULL under certain circumstances
+ if (B)
+ return Any_BPy_Interface1D_from_Interface1D(*(A->getFEdge(*B)));
+ Py_RETURN_NONE;
}
PyDoc_STRVAR(CurvePoint_t2d_doc,
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp
index 5e2130ac8e7..f8d0b34d6a9 100644
--- a/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp
@@ -49,7 +49,7 @@ PyDoc_STRVAR(ViewVertex_doc,
"Thus, this class can be specialized into two classes, the\n"
":class:`TVertex` class and the :class:`NonTVertex` class.");
-static int ViewVertex_init(BPy_ViewVertex *self, PyObject *args, PyObject *kwds)
+static int ViewVertex_init(BPy_ViewVertex * /*self*/, PyObject * /*args*/, PyObject * /*kwds*/)
{
PyErr_SetString(PyExc_TypeError, "cannot instantiate abstract class");
return -1;
@@ -82,7 +82,7 @@ PyDoc_STRVAR(ViewVertex_edges_end_doc,
" :return: An orientedViewEdgeIterator pointing after the last ViewEdge.\n"
" :rtype: :class:`orientedViewEdgeIterator`");
-static PyObject *ViewVertex_edges_end(BPy_ViewVertex *self)
+static PyObject *ViewVertex_edges_end(BPy_ViewVertex * /*self*/)
{
#if 0
ViewVertexInternal::orientedViewEdgeIterator ove_it(self->vv->edgesEnd());
diff --git a/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp
index ae4fe0764b6..ba773d4f4cf 100644
--- a/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp
@@ -166,7 +166,7 @@ static int StrokeVertex_mathutils_check(BaseMathObject *bmo)
return 0;
}
-static int StrokeVertex_mathutils_get(BaseMathObject *bmo, int subtype)
+static int StrokeVertex_mathutils_get(BaseMathObject *bmo, int /*subtype*/)
{
BPy_StrokeVertex *self = (BPy_StrokeVertex *)bmo->cb_user;
bmo->data[0] = (float)self->sv->x();
@@ -174,7 +174,7 @@ static int StrokeVertex_mathutils_get(BaseMathObject *bmo, int subtype)
return 0;
}
-static int StrokeVertex_mathutils_set(BaseMathObject *bmo, int subtype)
+static int StrokeVertex_mathutils_set(BaseMathObject *bmo, int /*subtype*/)
{
BPy_StrokeVertex *self = (BPy_StrokeVertex *)bmo->cb_user;
self->sv->setX((real)bmo->data[0]);
@@ -182,7 +182,7 @@ static int StrokeVertex_mathutils_set(BaseMathObject *bmo, int subtype)
return 0;
}
-static int StrokeVertex_mathutils_get_index(BaseMathObject *bmo, int subtype, int index)
+static int StrokeVertex_mathutils_get_index(BaseMathObject *bmo, int /*subtype*/, int index)
{
BPy_StrokeVertex *self = (BPy_StrokeVertex *)bmo->cb_user;
switch (index) {
@@ -194,7 +194,7 @@ static int StrokeVertex_mathutils_get_index(BaseMathObject *bmo, int subtype, in
return 0;
}
-static int StrokeVertex_mathutils_set_index(BaseMathObject *bmo, int subtype, int index)
+static int StrokeVertex_mathutils_set_index(BaseMathObject *bmo, int /*subtype*/, int index)
{
BPy_StrokeVertex *self = (BPy_StrokeVertex *)bmo->cb_user;
switch (index) {
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp
index 7592508902b..4c9e0630d40 100644
--- a/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp
@@ -100,7 +100,7 @@ static int FEdge_init(BPy_FEdge *self, PyObject *args, PyObject *kwds)
/*----------------------FEdge sequence protocol ----------------------------*/
-static Py_ssize_t FEdge_sq_length(BPy_FEdge *self)
+static Py_ssize_t FEdge_sq_length(BPy_FEdge * /*self*/)
{
return 2;
}
diff --git a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp
index a2079c7d685..cf893ad9481 100644
--- a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp
@@ -99,7 +99,7 @@ static int FEdgeSmooth_mathutils_check(BaseMathObject *bmo)
return 0;
}
-static int FEdgeSmooth_mathutils_get(BaseMathObject *bmo, int subtype)
+static int FEdgeSmooth_mathutils_get(BaseMathObject *bmo, int /*subtype*/)
{
BPy_FEdgeSmooth *self = (BPy_FEdgeSmooth *)bmo->cb_user;
Vec3r p(self->fes->normal());
@@ -109,7 +109,7 @@ static int FEdgeSmooth_mathutils_get(BaseMathObject *bmo, int subtype)
return 0;
}
-static int FEdgeSmooth_mathutils_set(BaseMathObject *bmo, int subtype)
+static int FEdgeSmooth_mathutils_set(BaseMathObject *bmo, int /*subtype*/)
{
BPy_FEdgeSmooth *self = (BPy_FEdgeSmooth *)bmo->cb_user;
Vec3r p(bmo->data[0], bmo->data[1], bmo->data[2]);
@@ -117,7 +117,7 @@ static int FEdgeSmooth_mathutils_set(BaseMathObject *bmo, int subtype)
return 0;
}
-static int FEdgeSmooth_mathutils_get_index(BaseMathObject *bmo, int subtype, int index)
+static int FEdgeSmooth_mathutils_get_index(BaseMathObject *bmo, int /*subtype*/, int index)
{
BPy_FEdgeSmooth *self = (BPy_FEdgeSmooth *)bmo->cb_user;
Vec3r p(self->fes->normal());
@@ -125,7 +125,7 @@ static int FEdgeSmooth_mathutils_get_index(BaseMathObject *bmo, int subtype, int
return 0;
}
-static int FEdgeSmooth_mathutils_set_index(BaseMathObject *bmo, int subtype, int index)
+static int FEdgeSmooth_mathutils_set_index(BaseMathObject *bmo, int /*subtype*/, int index)
{
BPy_FEdgeSmooth *self = (BPy_FEdgeSmooth *)bmo->cb_user;
Vec3r p(self->fes->normal());
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.h
index 46294c07b66..c4fead6a4e4 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.h
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.h
@@ -31,7 +31,6 @@
extern "C" {
#endif
-struct MTex;
///////////////////////////////////////////////////////////////////////////////////////////
diff --git a/source/blender/freestyle/intern/stroke/Predicates1D.h b/source/blender/freestyle/intern/stroke/Predicates1D.h
index 46efeae9f12..05fc043822f 100644
--- a/source/blender/freestyle/intern/stroke/Predicates1D.h
+++ b/source/blender/freestyle/intern/stroke/Predicates1D.h
@@ -471,7 +471,7 @@ public:
}
/*! The () operator. */
- int operator()(Interface1D& i1, Interface1D& i2)
+ int operator()(Interface1D& /*i1*/, Interface1D& /*i2*/)
{
result = true;
return 0;
@@ -490,7 +490,7 @@ public:
}
/*! The () operator. */
- int operator()(Interface1D& i1, Interface1D& i2)
+ int operator()(Interface1D& /*i1*/, Interface1D& /*i2*/)
{
result = false;
return 0;
diff --git a/source/blender/freestyle/intern/stroke/Stroke.cpp b/source/blender/freestyle/intern/stroke/Stroke.cpp
index 244b20f6b89..b4a3646edef 100644
--- a/source/blender/freestyle/intern/stroke/Stroke.cpp
+++ b/source/blender/freestyle/intern/stroke/Stroke.cpp
@@ -752,12 +752,12 @@ Interface0DIterator Stroke::verticesEnd()
return ret;
}
-Interface0DIterator Stroke::pointsBegin(float t)
+Interface0DIterator Stroke::pointsBegin(float /*t*/)
{
return verticesBegin(); // FIXME
}
-Interface0DIterator Stroke::pointsEnd(float t)
+Interface0DIterator Stroke::pointsEnd(float /*t*/)
{
return verticesEnd();
}
diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h
index 60193590944..ddb79b2df0b 100644
--- a/source/blender/freestyle/intern/system/PythonInterpreter.h
+++ b/source/blender/freestyle/intern/system/PythonInterpreter.h
@@ -51,6 +51,8 @@ extern "C" {
#include "BKE_text.h"
#include "BPY_extern.h"
+
+#include "bpy_util.h"
}
namespace Freestyle {
@@ -105,6 +107,26 @@ public:
return 0;
}
+ int interpretString(const string& str, const string& name)
+ {
+ ReportList *reports = CTX_wm_reports(_context);
+
+ BKE_reports_clear(reports);
+
+ if (BPY_string_exec(_context, str.c_str()) != 0) {
+ BPy_errors_to_report(reports);
+ cerr << "\nError executing Python script from PythonInterpreter::interpretString" << endl;
+ cerr << "Name: " << name << endl;
+ cerr << "Errors: " << endl;
+ BKE_reports_print(reports, RPT_ERROR);
+ return 1;
+ }
+
+ BKE_reports_clear(reports);
+
+ return 0;
+ }
+
int interpretText(struct Text *text, const string& name)
{
ReportList *reports = CTX_wm_reports(_context);
diff --git a/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp b/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp
index 8bc7c0952a8..3243c4d1fb7 100644
--- a/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp
+++ b/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp
@@ -100,22 +100,22 @@ ArbitraryGridDensityProviderFactory::ArbitraryGridDensityProviderFactory(unsigne
ArbitraryGridDensityProviderFactory::~ArbitraryGridDensityProviderFactory() {}
-auto_ptr<GridDensityProvider> ArbitraryGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source,
- const real proscenium[4])
+AutoPtr<GridDensityProvider> ArbitraryGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source,
+ const real proscenium[4])
{
- return auto_ptr<GridDensityProvider>(new ArbitraryGridDensityProvider(source, proscenium, numCells));
+ return AutoPtr<GridDensityProvider>(new ArbitraryGridDensityProvider(source, proscenium, numCells));
}
-auto_ptr<GridDensityProvider>
+AutoPtr<GridDensityProvider>
ArbitraryGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
const GridHelpers::Transform& transform)
{
- return auto_ptr<GridDensityProvider>(new ArbitraryGridDensityProvider(source, bbox, transform, numCells));
+ return AutoPtr<GridDensityProvider>(new ArbitraryGridDensityProvider(source, bbox, transform, numCells));
}
-auto_ptr<GridDensityProvider> ArbitraryGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source)
+AutoPtr<GridDensityProvider> ArbitraryGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source)
{
- return auto_ptr<GridDensityProvider>(new ArbitraryGridDensityProvider(source, numCells));
+ return AutoPtr<GridDensityProvider>(new ArbitraryGridDensityProvider(source, numCells));
}
} /* namespace Freestyle */
diff --git a/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.h b/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.h
index 652cb9b34b0..c7939d34da4 100644
--- a/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.h
+++ b/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.h
@@ -58,10 +58,10 @@ public:
ArbitraryGridDensityProviderFactory(unsigned numCells);
~ArbitraryGridDensityProviderFactory();
- auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const real proscenium[4]);
- auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
- const GridHelpers::Transform& transform);
- auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source);
+ AutoPtr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const real proscenium[4]);
+ AutoPtr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform);
+ AutoPtr<GridDensityProvider> newGridDensityProvider(OccluderSource& source);
protected:
unsigned numCells;
diff --git a/source/blender/freestyle/intern/view_map/AutoPtrHelper.h b/source/blender/freestyle/intern/view_map/AutoPtrHelper.h
new file mode 100644
index 00000000000..17a43c184c7
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/AutoPtrHelper.h
@@ -0,0 +1,60 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_AUTOPTR_HELPER_H__
+#define __FREESTYLE_AUTOPTR_HELPER_H__
+
+/** \file blender/freestyle/intern/view_map/AutoPtrHelper.h
+ * \ingroup freestyle
+ * \brief Utility header for auto_ptr/unique_ptr selection
+ * \author Sergey Sharybin
+ * \date 2015-02-09
+ */
+
+#include <memory>
+
+namespace Freestyle {
+
+#if __cplusplus > 199711L
+template<typename T>
+class AutoPtr : public std::unique_ptr<T> {
+public:
+ AutoPtr() : std::unique_ptr<T>() {}
+ AutoPtr(T *ptr) : std::unique_ptr<T>(ptr) {}
+
+ /* TODO(sergey): Is there more clear way to do this? */
+ template<typename X>
+ AutoPtr(AutoPtr<X>& other) : std::unique_ptr<T>(other.get()) {
+ other.release();
+ }
+};
+#else
+template<typename T>
+class AutoPtr : public std::auto_ptr<T> {
+public:
+ AutoPtr() : std::auto_ptr<T>() {}
+ AutoPtr(T *ptr) : std::auto_ptr<T>(ptr) {}
+ AutoPtr(std::auto_ptr_ref<T> ref) : std::auto_ptr<T>(ref) {}
+};
+#endif
+
+} /* namespace Freestyle */
+
+#endif // __FREESTYLE_AUTOPTR_HELPER_H__
diff --git a/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp b/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp
index 952b9752a3e..b5e133ec441 100644
--- a/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp
+++ b/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp
@@ -121,22 +121,22 @@ AverageAreaGridDensityProviderFactory::AverageAreaGridDensityProviderFactory(rea
AverageAreaGridDensityProviderFactory::~AverageAreaGridDensityProviderFactory() {}
-auto_ptr<GridDensityProvider>
+AutoPtr<GridDensityProvider>
AverageAreaGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source, const real proscenium[4])
{
- return auto_ptr<GridDensityProvider>(new AverageAreaGridDensityProvider(source, proscenium, sizeFactor));
+ return AutoPtr<GridDensityProvider>(new AverageAreaGridDensityProvider(source, proscenium, sizeFactor));
}
-auto_ptr<GridDensityProvider>
+AutoPtr<GridDensityProvider>
AverageAreaGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
const GridHelpers::Transform& transform)
{
- return auto_ptr<GridDensityProvider>(new AverageAreaGridDensityProvider(source, bbox, transform, sizeFactor));
+ return AutoPtr<GridDensityProvider>(new AverageAreaGridDensityProvider(source, bbox, transform, sizeFactor));
}
-auto_ptr<GridDensityProvider> AverageAreaGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source)
+AutoPtr<GridDensityProvider> AverageAreaGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source)
{
- return auto_ptr<GridDensityProvider>(new AverageAreaGridDensityProvider(source, sizeFactor));
+ return AutoPtr<GridDensityProvider>(new AverageAreaGridDensityProvider(source, sizeFactor));
}
} /* namespace Freestyle */
diff --git a/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.h b/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.h
index d63557f5cda..2c58cc32da9 100644
--- a/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.h
+++ b/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.h
@@ -55,10 +55,10 @@ public:
AverageAreaGridDensityProviderFactory(real sizeFactor);
~AverageAreaGridDensityProviderFactory();
- auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const real proscenium[4]);
- auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
- const GridHelpers::Transform& transform);
- auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source);
+ AutoPtr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const real proscenium[4]);
+ AutoPtr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform);
+ AutoPtr<GridDensityProvider> newGridDensityProvider(OccluderSource& source);
protected:
real sizeFactor;
diff --git a/source/blender/freestyle/intern/view_map/BoxGrid.cpp b/source/blender/freestyle/intern/view_map/BoxGrid.cpp
index f770bf6843f..ae22a26ec9b 100644
--- a/source/blender/freestyle/intern/view_map/BoxGrid.cpp
+++ b/source/blender/freestyle/intern/view_map/BoxGrid.cpp
@@ -71,18 +71,18 @@ void BoxGrid::Cell::indexPolygons()
// Iterator
//////////////////
-BoxGrid::Iterator::Iterator (BoxGrid& grid, Vec3r& center, real epsilon)
+BoxGrid::Iterator::Iterator (BoxGrid& grid, Vec3r& center, real /*epsilon*/)
: _target(grid.transform(center)), _foundOccludee(false)
{
// Find target cell
_cell = grid.findCell(_target);
- #if BOX_GRID_LOGGING
+#if BOX_GRID_LOGGING
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "Searching for occluders of edge centered at " << _target << " in cell [" <<
1_cell->boundary[0] << ", " << _cell->boundary[1] << ", " << _cell->boundary[2] <<
", " << _cell->boundary[3] << "] (" << _cell->faces.size() << " occluders)" << endl;
}
- #endif
+#endif
// Set iterator
_current = _cell->faces.begin();
@@ -122,7 +122,7 @@ BoxGrid::BoxGrid(OccluderSource& source, GridDensityProvider& density, ViewMap *
BoxGrid::~BoxGrid() {}
-void BoxGrid::assignCells (OccluderSource& source, GridDensityProvider& density, ViewMap *viewMap)
+void BoxGrid::assignCells (OccluderSource& /*source*/, GridDensityProvider& density, ViewMap *viewMap)
{
_cellSize = density.cellSize();
_cellsX = density.cellsX();
diff --git a/source/blender/freestyle/intern/view_map/BoxGrid.h b/source/blender/freestyle/intern/view_map/BoxGrid.h
index 0ef4ce37b11..b8e751d041d 100644
--- a/source/blender/freestyle/intern/view_map/BoxGrid.h
+++ b/source/blender/freestyle/intern/view_map/BoxGrid.h
@@ -303,11 +303,11 @@ inline void BoxGrid::Iterator::reportDepth(Vec3r origin, Vec3r u, real t)
// The reported depth is the length of a ray in camera space
// We need to convert it into a Z-value in grid space
real depth = -(origin + (u * t))[2];
- #if BOX_GRID_LOGGING
+#if BOX_GRID_LOGGING
if (G.debug & G_DEBUG_FREESTYLE) {
std::cout << "\t\tReporting depth of occluder/ee: " << depth;
}
- #endif
+#endif
if (depth > _target[2]) {
#if BOX_GRID_LOGGING
if (G.debug & G_DEBUG_FREESTYLE) {
diff --git a/source/blender/freestyle/intern/view_map/GridDensityProvider.h b/source/blender/freestyle/intern/view_map/GridDensityProvider.h
index 272d64dd6de..b49e74d6402 100644
--- a/source/blender/freestyle/intern/view_map/GridDensityProvider.h
+++ b/source/blender/freestyle/intern/view_map/GridDensityProvider.h
@@ -32,6 +32,7 @@
#include <algorithm>
#include <memory>
+#include "AutoPtrHelper.h"
#include "OccluderSource.h"
#include "../geometry/BBox.h"
@@ -148,12 +149,12 @@ class GridDensityProviderFactory
public:
GridDensityProviderFactory() {}
- virtual auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const real proscenium[4]) = 0;
+ virtual AutoPtr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const real proscenium[4]) = 0;
- virtual auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
- const GridHelpers::Transform& transform) = 0;
+ virtual AutoPtr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform) = 0;
- virtual auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source) = 0;
+ virtual AutoPtr<GridDensityProvider> newGridDensityProvider(OccluderSource& source) = 0;
virtual ~GridDensityProviderFactory () {}
diff --git a/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp b/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp
index 00f5cc90cc4..18edc82b096 100644
--- a/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp
+++ b/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp
@@ -36,45 +36,45 @@ HeuristicGridDensityProviderFactory::HeuristicGridDensityProviderFactory(real si
HeuristicGridDensityProviderFactory::~HeuristicGridDensityProviderFactory() {}
-auto_ptr<GridDensityProvider>
+AutoPtr<GridDensityProvider>
HeuristicGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source, const real proscenium[4])
{
- auto_ptr<AverageAreaGridDensityProvider> avg(new AverageAreaGridDensityProvider(source, proscenium, sizeFactor));
- auto_ptr<Pow23GridDensityProvider> p23(new Pow23GridDensityProvider(source, proscenium, numFaces));
+ AutoPtr<AverageAreaGridDensityProvider> avg(new AverageAreaGridDensityProvider(source, proscenium, sizeFactor));
+ AutoPtr<Pow23GridDensityProvider> p23(new Pow23GridDensityProvider(source, proscenium, numFaces));
if (avg->cellSize() > p23->cellSize()) {
- return (auto_ptr<GridDensityProvider>) p23;
+ return (AutoPtr<GridDensityProvider>) p23;
}
else {
- return (auto_ptr<GridDensityProvider>) avg;
+ return (AutoPtr<GridDensityProvider>) avg;
}
}
-auto_ptr<GridDensityProvider>
+AutoPtr<GridDensityProvider>
HeuristicGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
const GridHelpers::Transform& transform)
{
- auto_ptr<AverageAreaGridDensityProvider> avg(new AverageAreaGridDensityProvider(source, bbox,
- transform, sizeFactor));
- auto_ptr<Pow23GridDensityProvider> p23(new Pow23GridDensityProvider(source, bbox, transform, numFaces));
+ AutoPtr<AverageAreaGridDensityProvider> avg(new AverageAreaGridDensityProvider(source, bbox,
+ transform, sizeFactor));
+ AutoPtr<Pow23GridDensityProvider> p23(new Pow23GridDensityProvider(source, bbox, transform, numFaces));
if (avg->cellSize() > p23->cellSize()) {
- return (auto_ptr<GridDensityProvider>) p23;
+ return (AutoPtr<GridDensityProvider>) p23;
}
else {
- return (auto_ptr<GridDensityProvider>) avg;
+ return (AutoPtr<GridDensityProvider>) avg;
}
}
-auto_ptr<GridDensityProvider> HeuristicGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source)
+AutoPtr<GridDensityProvider> HeuristicGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source)
{
real proscenium[4];
GridDensityProvider::calculateOptimalProscenium(source, proscenium);
- auto_ptr<AverageAreaGridDensityProvider> avg(new AverageAreaGridDensityProvider(source, proscenium, sizeFactor));
- auto_ptr<Pow23GridDensityProvider> p23(new Pow23GridDensityProvider(source, proscenium, numFaces));
+ AutoPtr<AverageAreaGridDensityProvider> avg(new AverageAreaGridDensityProvider(source, proscenium, sizeFactor));
+ AutoPtr<Pow23GridDensityProvider> p23(new Pow23GridDensityProvider(source, proscenium, numFaces));
if (avg->cellSize() > p23->cellSize()) {
- return (auto_ptr<GridDensityProvider>) p23;
+ return (AutoPtr<GridDensityProvider>) p23;
}
else {
- return (auto_ptr<GridDensityProvider>) avg;
+ return (AutoPtr<GridDensityProvider>) avg;
}
}
diff --git a/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.h b/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.h
index 65f2af6df2f..9414e4931f5 100644
--- a/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.h
+++ b/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.h
@@ -42,10 +42,10 @@ public:
HeuristicGridDensityProviderFactory(real sizeFactor, unsigned numFaces);
~HeuristicGridDensityProviderFactory();
- auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const real proscenium[4]);
- auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
- const GridHelpers::Transform& transform);
- auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source);
+ AutoPtr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const real proscenium[4]);
+ AutoPtr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform);
+ AutoPtr<GridDensityProvider> newGridDensityProvider(OccluderSource& source);
protected:
real sizeFactor;
diff --git a/source/blender/freestyle/intern/view_map/Interface1D.cpp b/source/blender/freestyle/intern/view_map/Interface1D.cpp
index 985310e52b5..f4abad11479 100644
--- a/source/blender/freestyle/intern/view_map/Interface1D.cpp
+++ b/source/blender/freestyle/intern/view_map/Interface1D.cpp
@@ -42,13 +42,13 @@ Interface0DIterator Interface1D::verticesEnd()
return Interface0DIterator();
}
-Interface0DIterator Interface1D::pointsBegin(float t)
+Interface0DIterator Interface1D::pointsBegin(float /*t*/)
{
PyErr_SetString(PyExc_TypeError, "method pointsBegin() not properly overridden");
return Interface0DIterator();
}
-Interface0DIterator Interface1D::pointsEnd(float t)
+Interface0DIterator Interface1D::pointsEnd(float /*t*/)
{
PyErr_SetString(PyExc_TypeError, "method pointsEnd() not properly overridden");
return Interface0DIterator();
diff --git a/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp b/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp
index e3bb9b87ecc..8dff079e0cf 100644
--- a/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp
+++ b/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp
@@ -99,22 +99,22 @@ Pow23GridDensityProviderFactory::Pow23GridDensityProviderFactory(unsigned numFac
Pow23GridDensityProviderFactory::~Pow23GridDensityProviderFactory () {}
-auto_ptr<GridDensityProvider>
+AutoPtr<GridDensityProvider>
Pow23GridDensityProviderFactory::newGridDensityProvider(OccluderSource& source, const real proscenium[4])
{
- return auto_ptr<GridDensityProvider>(new Pow23GridDensityProvider(source, proscenium, numFaces));
+ return AutoPtr<GridDensityProvider>(new Pow23GridDensityProvider(source, proscenium, numFaces));
}
-auto_ptr<GridDensityProvider>
+AutoPtr<GridDensityProvider>
Pow23GridDensityProviderFactory::newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
const GridHelpers::Transform& transform)
{
- return auto_ptr<GridDensityProvider>(new Pow23GridDensityProvider(source, bbox, transform, numFaces));
+ return AutoPtr<GridDensityProvider>(new Pow23GridDensityProvider(source, bbox, transform, numFaces));
}
-auto_ptr<GridDensityProvider> Pow23GridDensityProviderFactory::newGridDensityProvider(OccluderSource& source)
+AutoPtr<GridDensityProvider> Pow23GridDensityProviderFactory::newGridDensityProvider(OccluderSource& source)
{
- return auto_ptr<GridDensityProvider>(new Pow23GridDensityProvider(source, numFaces));
+ return AutoPtr<GridDensityProvider>(new Pow23GridDensityProvider(source, numFaces));
}
} /* namespace Freestyle */
diff --git a/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.h b/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.h
index 7f646790ab6..5dfa9cdfc87 100644
--- a/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.h
+++ b/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.h
@@ -58,10 +58,10 @@ public:
Pow23GridDensityProviderFactory(unsigned numFaces);
~Pow23GridDensityProviderFactory();
- auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const real proscenium[4]);
- auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
- const GridHelpers::Transform& transform);
- auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source);
+ AutoPtr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const real proscenium[4]);
+ AutoPtr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform);
+ AutoPtr<GridDensityProvider> newGridDensityProvider(OccluderSource& source);
protected:
unsigned numFaces;
diff --git a/source/blender/freestyle/intern/view_map/Silhouette.h b/source/blender/freestyle/intern/view_map/Silhouette.h
index 94b00157ccd..a80fea0342f 100644
--- a/source/blender/freestyle/intern/view_map/Silhouette.h
+++ b/source/blender/freestyle/intern/view_map/Silhouette.h
@@ -1122,12 +1122,12 @@ Interface0DIterator FEdge::verticesEnd()
return ret;
}
-Interface0DIterator FEdge::pointsBegin(float t)
+Interface0DIterator FEdge::pointsBegin(float /*t*/)
{
return verticesBegin();
}
-Interface0DIterator FEdge::pointsEnd(float t)
+Interface0DIterator FEdge::pointsEnd(float /*t*/)
{
return verticesEnd();
}
diff --git a/source/blender/freestyle/intern/view_map/SphericalGrid.cpp b/source/blender/freestyle/intern/view_map/SphericalGrid.cpp
index 60ad7daea0a..10c88190cb3 100644
--- a/source/blender/freestyle/intern/view_map/SphericalGrid.cpp
+++ b/source/blender/freestyle/intern/view_map/SphericalGrid.cpp
@@ -72,18 +72,18 @@ void SphericalGrid::Cell::indexPolygons()
// Iterator
//////////////////
-SphericalGrid::Iterator::Iterator(SphericalGrid& grid, Vec3r& center, real epsilon)
+SphericalGrid::Iterator::Iterator(SphericalGrid& grid, Vec3r& center, real /*epsilon*/)
: _target(SphericalGrid::Transform::sphericalProjection(center)), _foundOccludee(false)
{
// Find target cell
_cell = grid.findCell(_target);
- #if SPHERICAL_GRID_LOGGING
+#if SPHERICAL_GRID_LOGGING
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "Searching for occluders of edge centered at " << _target << " in cell [" <<
_cell->boundary[0] << ", " << _cell->boundary[1] << ", " << _cell->boundary[2] <<
", " << _cell->boundary[3] << "] (" << _cell->faces.size() << " occluders)" << endl;
}
- #endif
+#endif
// Set iterator
_current = _cell->faces.begin();
@@ -120,7 +120,7 @@ SphericalGrid::SphericalGrid(OccluderSource& source, GridDensityProvider& densit
SphericalGrid::~SphericalGrid() {}
-void SphericalGrid::assignCells(OccluderSource& source, GridDensityProvider& density, ViewMap *viewMap)
+void SphericalGrid::assignCells(OccluderSource& /*source*/, GridDensityProvider& density, ViewMap *viewMap)
{
_cellSize = density.cellSize();
_cellsX = density.cellsX();
diff --git a/source/blender/freestyle/intern/view_map/ViewMap.cpp b/source/blender/freestyle/intern/view_map/ViewMap.cpp
index 6bb0082e379..52769413e79 100644
--- a/source/blender/freestyle/intern/view_map/ViewMap.cpp
+++ b/source/blender/freestyle/intern/view_map/ViewMap.cpp
@@ -701,12 +701,12 @@ Interface0DIterator ViewEdge::verticesEnd()
return ret;
}
-Interface0DIterator ViewEdge::pointsBegin(float t)
+Interface0DIterator ViewEdge::pointsBegin(float /*t*/)
{
return verticesBegin();
}
-Interface0DIterator ViewEdge::pointsEnd(float t)
+Interface0DIterator ViewEdge::pointsEnd(float /*t*/)
{
return verticesEnd();
}
diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
index a0a1282219c..932c23698dc 100644
--- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
+++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
@@ -56,7 +56,7 @@ static const Global &_global = G;
using namespace std;
template <typename G, typename I>
-static void findOccludee(FEdge *fe, G& grid, I& occluders, real epsilon, WFace **oaWFace,
+static void findOccludee(FEdge *fe, G& /*grid*/, I& occluders, real epsilon, WFace **oaWFace,
Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector<WVertex*>& faceVertices)
{
WFace *face = NULL;
@@ -169,7 +169,7 @@ static void findOccludee(FEdge *fe, G& grid, I& occluders, real epsilon, WFace *
}
template <typename G, typename I>
-static void findOccludee(FEdge *fe, G& grid, real epsilon, ViewEdge *ve, WFace **oaFace)
+static void findOccludee(FEdge *fe, G& grid, real epsilon, ViewEdge * /*ve*/, WFace **oaFace)
{
Vec3r A;
Vec3r edge;
@@ -205,7 +205,7 @@ static void findOccludee(FEdge *fe, G& grid, real epsilon, ViewEdge *ve, WFace *
// computeVisibility takes a pointer to foundOccluders, instead of using a reference,
// so that computeVeryFastVisibility can skip the AddOccluders step with minimal overhead.
template <typename G, typename I>
-static int computeVisibility(ViewMap *viewMap, FEdge *fe, G& grid, real epsilon, ViewEdge *ve, WFace **oaWFace,
+static int computeVisibility(ViewMap *viewMap, FEdge *fe, G& grid, real epsilon, ViewEdge * /*ve*/, WFace **oaWFace,
set<ViewShape*> *foundOccluders)
{
int qi = 0;
@@ -1300,8 +1300,8 @@ void ViewMapBuilder::computeCusps(ViewMap *ioViewMap)
void ViewMapBuilder::ComputeCumulativeVisibility(ViewMap *ioViewMap, WingedEdge& we, const BBox<Vec3r>& bbox,
real epsilon, bool cull, GridDensityProviderFactory& factory)
{
- auto_ptr<GridHelpers::Transform> transform;
- auto_ptr<OccluderSource> source;
+ AutoPtr<GridHelpers::Transform> transform;
+ AutoPtr<OccluderSource> source;
if (_orthographicProjection) {
transform.reset(new BoxGrid::Transform);
@@ -1317,7 +1317,7 @@ void ViewMapBuilder::ComputeCumulativeVisibility(ViewMap *ioViewMap, WingedEdge&
source.reset(new OccluderSource(*transform, we));
}
- auto_ptr<GridDensityProvider> density(factory.newGridDensityProvider(*source, bbox, *transform));
+ AutoPtr<GridDensityProvider> density(factory.newGridDensityProvider(*source, bbox, *transform));
if (_orthographicProjection) {
BoxGrid grid(*source, *density, ioViewMap, _viewpoint, _EnableQI);
@@ -1332,8 +1332,8 @@ void ViewMapBuilder::ComputeCumulativeVisibility(ViewMap *ioViewMap, WingedEdge&
void ViewMapBuilder::ComputeDetailedVisibility(ViewMap *ioViewMap, WingedEdge& we, const BBox<Vec3r>& bbox,
real epsilon, bool cull, GridDensityProviderFactory& factory)
{
- auto_ptr<GridHelpers::Transform> transform;
- auto_ptr<OccluderSource> source;
+ AutoPtr<GridHelpers::Transform> transform;
+ AutoPtr<OccluderSource> source;
if (_orthographicProjection) {
transform.reset(new BoxGrid::Transform);
@@ -1349,7 +1349,7 @@ void ViewMapBuilder::ComputeDetailedVisibility(ViewMap *ioViewMap, WingedEdge& w
source.reset(new OccluderSource(*transform, we));
}
- auto_ptr<GridDensityProvider> density(factory.newGridDensityProvider(*source, bbox, *transform));
+ AutoPtr<GridDensityProvider> density(factory.newGridDensityProvider(*source, bbox, *transform));
if (_orthographicProjection) {
BoxGrid grid(*source, *density, ioViewMap, _viewpoint, _EnableQI);
diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.h b/source/blender/freestyle/intern/view_map/ViewMapBuilder.h
index 08b2fde8f31..36497bf8d22 100644
--- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.h
+++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.h
@@ -145,7 +145,7 @@ public:
* The viewport. 4 real array: origin.x, origin.y, width, length
*/
inline void setTransform(const real iModelViewMatrix[4][4], const real iProjectionMatrix[4][4],
- const int iViewport[4], real iFocalLength, real iAspect, real iFovy)
+ const int iViewport[4], real iFocalLength, real /*iAspect*/, real /*iFovy*/)
{
_orthographicProjection = (iProjectionMatrix[3][3] != 0.0);
SilhouetteGeomEngine::setTransform(iModelViewMatrix, iProjectionMatrix, iViewport, iFocalLength);
diff --git a/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp b/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp
index c9f2f3badab..df990a3468f 100644
--- a/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp
+++ b/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp
@@ -221,7 +221,7 @@ void WingedEdgeBuilder::buildWVertices(WShape& shape, const real *vertices, unsi
}
}
-void WingedEdgeBuilder::buildTriangleStrip(const real *vertices, const real *normals, vector<FrsMaterial>& iMaterials,
+void WingedEdgeBuilder::buildTriangleStrip(const real * /*vertices*/, const real *normals, vector<FrsMaterial>& /*iMaterials*/,
const real *texCoords, const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
const unsigned *vindices, const unsigned *nindices, const unsigned *mindices,
const unsigned *tindices, const unsigned nvertices)
@@ -296,15 +296,15 @@ void WingedEdgeBuilder::buildTriangleStrip(const real *vertices, const real *nor
}
}
-void WingedEdgeBuilder::buildTriangleFan(const real *vertices, const real *normals, vector<FrsMaterial>& iMaterials,
- const real *texCoords, const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
- const unsigned *vindices, const unsigned *nindices, const unsigned *mindices,
- const unsigned *tindices, const unsigned nvertices)
+void WingedEdgeBuilder::buildTriangleFan(const real * /*vertices*/, const real * /*normals*/, vector<FrsMaterial>& /*iMaterials*/,
+ const real * /*texCoords*/, const IndexedFaceSet::FaceEdgeMark * /*iFaceEdgeMarks*/,
+ const unsigned * /*vindices*/, const unsigned * /*nindices*/, const unsigned * /*mindices*/,
+ const unsigned * /*tindices*/, const unsigned /*nvertices*/)
{
// Nothing to be done
}
-void WingedEdgeBuilder::buildTriangles(const real *vertices, const real *normals, vector<FrsMaterial>& iMaterials,
+void WingedEdgeBuilder::buildTriangles(const real * /*vertices*/, const real *normals, vector<FrsMaterial>& /*iMaterials*/,
const real *texCoords, const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
const unsigned *vindices, const unsigned *nindices, const unsigned *mindices,
const unsigned *tindices, const unsigned nvertices)
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index b5d9028a8ae..23a2b77d1e7 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -57,10 +57,16 @@ set(SRC
intern/gpu_compositing.c
intern/gpu_debug.c
+ shaders/gpu_program_smoke_frag.glsl
+ shaders/gpu_program_smoke_color_frag.glsl
+
shaders/gpu_shader_fx_lib.glsl
shaders/gpu_shader_fx_ssao_frag.glsl
shaders/gpu_shader_fx_dof_frag.glsl
shaders/gpu_shader_fx_dof_vert.glsl
+ shaders/gpu_shader_fx_dof_hq_frag.glsl
+ shaders/gpu_shader_fx_dof_hq_vert.glsl
+ shaders/gpu_shader_fx_dof_hq_geo.glsl
shaders/gpu_shader_fx_vert.glsl
shaders/gpu_shader_material.glsl
shaders/gpu_shader_sep_gaussian_blur_frag.glsl
@@ -86,6 +92,8 @@ set(SRC
intern/gpu_private.h
)
+data_to_c_simple(shaders/gpu_program_smoke_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_program_smoke_color_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_material.glsl SRC)
data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_vert.glsl SRC)
@@ -99,6 +107,9 @@ data_to_c_simple(shaders/gpu_shader_fx_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_fx_ssao_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_fx_dof_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_fx_dof_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_fx_dof_hq_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_fx_dof_hq_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_fx_dof_hq_geo.glsl SRC)
data_to_c_simple(shaders/gpu_shader_fx_depth_resolve.glsl SRC)
data_to_c_simple(shaders/gpu_shader_fx_lib.glsl SRC)
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 69e1dddee8c..cda7bffe93f 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -42,10 +42,8 @@
struct BMesh;
struct CCGElem;
struct CCGKey;
-struct CustomData;
struct DMFlagMat;
struct DerivedMesh;
-struct GHash;
struct GSet;
struct GPUVertPointLink;
struct PBVH;
@@ -54,10 +52,10 @@ typedef void (*GPUBufferCopyFunc)(DerivedMesh *dm, float *varray, int *index,
int *mat_orig_to_new, void *user_data);
typedef struct GPUBuffer {
- int size; /* in bytes */
- void *pointer; /* used with vertex arrays */
- unsigned int id; /* used with vertex buffer objects */
- bool use_vbo; /* true for VBOs, false for vertex arrays */
+ int size; /* in bytes */
+ void *pointer; /* used with vertex arrays */
+ unsigned int id; /* used with vertex buffer objects */
+ bool use_vbo; /* true for VBOs, false for vertex arrays */
} GPUBuffer;
typedef struct GPUBufferMaterial {
diff --git a/source/blender/gpu/GPU_compositing.h b/source/blender/gpu/GPU_compositing.h
index 93f1bc64922..04e89da00a7 100644
--- a/source/blender/gpu/GPU_compositing.h
+++ b/source/blender/gpu/GPU_compositing.h
@@ -42,17 +42,15 @@ struct GPUDOFSettings;
struct GPUSSAOSettings;
struct GPUOffScreen;
struct GPUFXSettings;
-struct RegionView3D;
struct rcti;
struct Scene;
-struct View3D;
enum eGPUFXFlags;
/**** Public API *****/
typedef enum GPUFXShaderEffect {
/* Screen space ambient occlusion shader */
- GPU_SHADER_FX_SSAO = 1,
+ GPU_SHADER_FX_SSAO = 1,
/* depth of field passes. Yep, quite a complex effect */
GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE = 2,
@@ -61,11 +59,16 @@ typedef enum GPUFXShaderEffect {
GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR = 5,
GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE = 6,
- GPU_SHADER_FX_DEPTH_RESOLVE = 7,
+ /* high quality */
+ GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE = 7,
+ GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO = 8,
+ GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE = 9,
+
+ GPU_SHADER_FX_DEPTH_RESOLVE = 10,
} GPUFXShaderEffect;
/* keep in synch with enum above! */
-#define MAX_FX_SHADERS 8
+#define MAX_FX_SHADERS 11
/* generate a new FX compositor */
GPUFX *GPU_fx_compositor_create(void);
diff --git a/source/blender/gpu/GPU_debug.h b/source/blender/gpu/GPU_debug.h
index 02c5df013af..f89df2b54aa 100644
--- a/source/blender/gpu/GPU_debug.h
+++ b/source/blender/gpu/GPU_debug.h
@@ -63,7 +63,7 @@ void gpu_assert_no_gl_errors(const char *file, int line, const char *str);
#ifdef WITH_GPU_DEBUG
/* inserts a debug marker message for the debug context messaging system */
-void gpu_string_marker (size_t size, const char *str);
+void gpu_string_marker(size_t size, const char *str);
# define GPU_STRING_MARKER(size, str) gpu_string_marker((size), (str))
#else /* WITH_GPU_DEBUG */
@@ -74,5 +74,4 @@ void gpu_string_marker (size_t size, const char *str);
}
#endif
-
-#endif /* __GPU_DEBUG_H__ */ \ No newline at end of file
+#endif /* __GPU_DEBUG_H__ */
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
index 57aa7f202b0..845ae9d2b30 100644
--- a/source/blender/gpu/GPU_draw.h
+++ b/source/blender/gpu/GPU_draw.h
@@ -36,6 +36,7 @@
extern "C" {
#endif
+struct ImBuf;
struct Image;
struct ImageUser;
struct MTFace;
@@ -84,6 +85,7 @@ int GPU_get_material_alpha_blend(void);
int GPU_set_tpage(struct MTFace *tface, int mipmap, int transp);
void GPU_clear_tpage(bool force);
+
/* Lights
* - returns how many lights were enabled
* - this affects fixed functions materials and texface, not glsl */
@@ -102,11 +104,11 @@ void GPU_render_text(struct MTFace *tface, int mode,
/* Mipmap settings
* - these will free textures on changes */
-void GPU_set_mipmap(int mipmap);
-int GPU_get_mipmap(void);
-void GPU_set_linear_mipmap(int linear);
-int GPU_get_linear_mipmap(void);
-void GPU_paint_set_mipmap(int mipmap);
+void GPU_set_mipmap(bool mipmap);
+bool GPU_get_mipmap(void);
+void GPU_set_linear_mipmap(bool linear);
+bool GPU_get_linear_mipmap(void);
+void GPU_paint_set_mipmap(bool mipmap);
/* Anisotropic filtering settings
* - these will free textures on changes */
@@ -119,7 +121,7 @@ void GPU_set_gpu_mipmapping(int gpu_mipmap);
/* Image updates and free
* - these deal with images bound as opengl textures */
-void GPU_paint_update_image(struct Image *ima, int x, int y, int w, int h);
+void GPU_paint_update_image(struct Image *ima, ImageUser *iuser, int x, int y, int w, int h);
void GPU_update_images_framechange(void);
int GPU_update_image_time(struct Image *ima, double time);
int GPU_verify_image(struct Image *ima, struct ImageUser *iuser, int tftile, bool compare, bool mipmap, bool is_data);
diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h
index 228bea14e00..f3927ba960b 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_extensions.h
@@ -52,46 +52,56 @@ typedef struct GPUOffScreen GPUOffScreen;
struct GPUShader;
typedef struct GPUShader GPUShader;
+struct GPUProgram;
+typedef struct GPUProgram GPUProgram;
+
/* GPU extensions support */
void GPU_extensions_disable(void);
-int GPU_glsl_support(void);
-int GPU_non_power_of_two_support(void);
-int GPU_vertex_buffer_support(void);
-int GPU_display_list_support(void);
+bool GPU_glsl_support(void);
+bool GPU_non_power_of_two_support(void);
+bool GPU_vertex_buffer_support(void);
+bool GPU_display_list_support(void);
+bool GPU_bicubic_bump_support(void);
+bool GPU_geometry_shader_support(void);
+bool GPU_instanced_drawing_support(void);
+
+int GPU_max_texture_size(void);
int GPU_color_depth(void);
-void GPU_code_generate_glsl_lib(void);
-int GPU_bicubic_bump_support(void);
-int GPU_max_texture_size (void);
+void GPU_get_dfdy_factors(float fac[2]);
+bool GPU_mem_stats_supported(void);
+void GPU_mem_stats_get(int *totalmem, int *freemem);
+
+void GPU_code_generate_glsl_lib(void);
/* GPU Types */
typedef enum GPUDeviceType {
- GPU_DEVICE_NVIDIA = (1<<0),
- GPU_DEVICE_ATI = (1<<1),
- GPU_DEVICE_INTEL = (1<<2),
- GPU_DEVICE_SOFTWARE = (1<<3),
- GPU_DEVICE_UNKNOWN = (1<<4),
- GPU_DEVICE_ANY = (0xff)
+ GPU_DEVICE_NVIDIA = (1<<0),
+ GPU_DEVICE_ATI = (1<<1),
+ GPU_DEVICE_INTEL = (1<<2),
+ GPU_DEVICE_SOFTWARE = (1<<3),
+ GPU_DEVICE_UNKNOWN = (1<<4),
+ GPU_DEVICE_ANY = (0xff)
} GPUDeviceType;
typedef enum GPUOSType {
- GPU_OS_WIN = (1<<8),
- GPU_OS_MAC = (1<<9),
- GPU_OS_UNIX = (1<<10),
- GPU_OS_ANY = (0xff00)
+ GPU_OS_WIN = (1<<8),
+ GPU_OS_MAC = (1<<9),
+ GPU_OS_UNIX = (1<<10),
+ GPU_OS_ANY = (0xff00)
} GPUOSType;
typedef enum GPUDriverType {
- GPU_DRIVER_OFFICIAL = (1<<16),
+ GPU_DRIVER_OFFICIAL = (1<<16),
GPU_DRIVER_OPENSOURCE = (1<<17),
- GPU_DRIVER_SOFTWARE = (1<<18),
- GPU_DRIVER_ANY = (0xff0000)
+ GPU_DRIVER_SOFTWARE = (1<<18),
+ GPU_DRIVER_ANY = (0xff0000)
} GPUDriverType;
-int GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver);
+bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver);
/* GPU Texture
* - always returns unsigned char RGBA textures
@@ -113,13 +123,13 @@ typedef enum GPUHDRType {
GPU_HDR_FULL_FLOAT = (1 << 1),
} GPUHDRType;
-GPUTexture *GPU_texture_create_1D(int w, float *pixels, char err_out[256]);
-GPUTexture *GPU_texture_create_2D(int w, int h, float *pixels, GPUHDRType hdr, char err_out[256]);
-GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, float *fpixels);
+GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, GPUHDRType hdr, char err_out[256]);
+GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels);
GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]);
GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]);
-GPUTexture *GPU_texture_create_2D_procedural(int w, int h, float *pixels, char err_out[256]);
-GPUTexture *GPU_texture_create_1D_procedural(int w, float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]);
+GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]);
GPUTexture *GPU_texture_from_blender(struct Image *ima,
struct ImageUser *iuser, bool is_data, double time, int mipmap);
GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap);
@@ -134,14 +144,14 @@ void GPU_texture_ref(GPUTexture *tex);
void GPU_texture_bind(GPUTexture *tex, int number);
void GPU_texture_unbind(GPUTexture *tex);
-void GPU_depth_texture_mode(GPUTexture *tex, bool compare, bool use_filter);
+void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter);
GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex);
-int GPU_texture_target(GPUTexture *tex);
-int GPU_texture_opengl_width(GPUTexture *tex);
-int GPU_texture_opengl_height(GPUTexture *tex);
-int GPU_texture_opengl_bindcode(GPUTexture *tex);
+int GPU_texture_target(const GPUTexture *tex);
+int GPU_texture_opengl_width(const GPUTexture *tex);
+int GPU_texture_opengl_height(const GPUTexture *tex);
+int GPU_texture_opengl_bindcode(const GPUTexture *tex);
/* GPU Framebuffer
* - this is a wrapper for an OpenGL framebuffer object (FBO). in practice
@@ -174,14 +184,26 @@ void GPU_offscreen_free(GPUOffScreen *ofs);
void GPU_offscreen_bind(GPUOffScreen *ofs, bool save);
void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore);
void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels);
-int GPU_offscreen_width(GPUOffScreen *ofs);
-int GPU_offscreen_height(GPUOffScreen *ofs);
+int GPU_offscreen_width(const GPUOffScreen *ofs);
+int GPU_offscreen_height(const GPUOffScreen *ofs);
+
+/* Builtin/Non-generated shaders */
+typedef enum GPUProgramType {
+ GPU_PROGRAM_TYPE_FRAGMENT = 0
+} GPUProgramType;
+
+
+GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code);
+void GPU_program_free(GPUProgram *program);
+void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w);
+void GPU_program_bind(GPUProgram *);
+void GPU_program_unbind(GPUProgram *);
/* GPU Shader
* - only for fragment shaders now
* - must call texture bind before setting a texture as uniform! */
-GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *libcode, const char *defines);
+GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines, int input, int output, int number);
void GPU_shader_free(GPUShader *shader);
void GPU_shader_bind(GPUShader *shader);
@@ -190,25 +212,35 @@ void GPU_shader_unbind(void);
int GPU_shader_get_uniform(GPUShader *shader, const char *name);
void GPU_shader_uniform_vector(GPUShader *shader, int location, int length,
int arraysize, const float *value);
+void GPU_shader_uniform_vector_int(GPUShader *shader, int location, int length,
+ int arraysize, const int *value);
+
void GPU_shader_uniform_texture(GPUShader *shader, int location, GPUTexture *tex);
void GPU_shader_uniform_int(GPUShader *shader, int location, int value);
+void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number);
int GPU_shader_get_attribute(GPUShader *shader, const char *name);
/* Builtin/Non-generated shaders */
typedef enum GPUBuiltinShader {
- GPU_SHADER_VSM_STORE = (1<<0),
- GPU_SHADER_SEP_GAUSSIAN_BLUR = (1<<1),
+ GPU_SHADER_VSM_STORE = 0,
+ GPU_SHADER_SEP_GAUSSIAN_BLUR = 1,
} GPUBuiltinShader;
+typedef enum GPUBuiltinProgram {
+ GPU_PROGRAM_SMOKE = 0,
+ GPU_PROGRAM_SMOKE_COLORED = 1,
+} GPUBuiltinProgram;
+
GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader);
+GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program);
GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp);
void GPU_shader_free_builtin_shaders(void);
/* Vertex attributes for shaders */
-#define GPU_MAX_ATTRIB 32
+#define GPU_MAX_ATTRIB 32
typedef struct GPUVertexAttribs {
struct {
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 64ce936e64a..ee6e02547e7 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -45,10 +45,7 @@ struct Image;
struct ImageUser;
struct Material;
struct Object;
-struct Lamp;
struct Image;
-struct bNode;
-struct LinkNode;
struct Scene;
struct SceneRenderLayer;
struct GPUVertexAttribs;
@@ -92,7 +89,7 @@ typedef enum GPUBuiltin {
GPU_VIEW_NORMAL = (1 << 5),
GPU_OBCOLOR = (1 << 6),
GPU_AUTO_BUMPSCALE = (1 << 7),
- GPU_CAMERA_TEXCO_FACTORS = (1 << 8),
+ GPU_CAMERA_TEXCO_FACTORS = (1 << 8),
} GPUBuiltin;
typedef enum GPUOpenGLBuiltin {
@@ -124,31 +121,62 @@ typedef struct GPUNodeStack {
short sockettype;
} GPUNodeStack;
+
+#define GPU_DYNAMIC_GROUP_FROM_TYPE(f) ((f) & 0xFFFF0000)
+
+#define GPU_DYNAMIC_GROUP_MISC 0x00010000
+#define GPU_DYNAMIC_GROUP_LAMP 0x00020000
+#define GPU_DYNAMIC_GROUP_OBJECT 0x00030000
+#define GPU_DYNAMIC_GROUP_SAMPLER 0x00040000
+#define GPU_DYNAMIC_GROUP_MIST 0x00050000
+#define GPU_DYNAMIC_GROUP_WORLD 0x00060000
+#define GPU_DYNAMIC_GROUP_MAT 0x00070000
+
typedef enum GPUDynamicType {
- GPU_DYNAMIC_NONE = 0,
- GPU_DYNAMIC_OBJECT_VIEWMAT = 1,
- GPU_DYNAMIC_OBJECT_MAT = 2,
- GPU_DYNAMIC_OBJECT_VIEWIMAT = 3,
- GPU_DYNAMIC_OBJECT_IMAT = 4,
- GPU_DYNAMIC_OBJECT_COLOR = 5,
- GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE = 15,
-
- GPU_DYNAMIC_LAMP_FIRST = 6,
- GPU_DYNAMIC_LAMP_DYNVEC = 6,
- GPU_DYNAMIC_LAMP_DYNCO = 7,
- GPU_DYNAMIC_LAMP_DYNIMAT = 8,
- GPU_DYNAMIC_LAMP_DYNPERSMAT = 9,
- GPU_DYNAMIC_LAMP_DYNENERGY = 10,
- GPU_DYNAMIC_LAMP_DYNCOL = 11,
- GPU_DYNAMIC_LAMP_LAST = 11,
- GPU_DYNAMIC_SAMPLER_2DBUFFER = 12,
- GPU_DYNAMIC_SAMPLER_2DIMAGE = 13,
- GPU_DYNAMIC_SAMPLER_2DSHADOW = 14,
- GPU_DYNAMIC_LAMP_DISTANCE = 16,
- GPU_DYNAMIC_LAMP_ATT1 = 17,
- GPU_DYNAMIC_LAMP_ATT2 = 18,
- GPU_DYNAMIC_LAMP_SPOTSIZE = 19,
- GPU_DYNAMIC_LAMP_SPOTBLEND = 20,
+
+ GPU_DYNAMIC_NONE = 0,
+
+ GPU_DYNAMIC_OBJECT_VIEWMAT = 1 | GPU_DYNAMIC_GROUP_OBJECT,
+ GPU_DYNAMIC_OBJECT_MAT = 2 | GPU_DYNAMIC_GROUP_OBJECT,
+ GPU_DYNAMIC_OBJECT_VIEWIMAT = 3 | GPU_DYNAMIC_GROUP_OBJECT,
+ GPU_DYNAMIC_OBJECT_IMAT = 4 | GPU_DYNAMIC_GROUP_OBJECT,
+ GPU_DYNAMIC_OBJECT_COLOR = 5 | GPU_DYNAMIC_GROUP_OBJECT,
+ GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE = 6 | GPU_DYNAMIC_GROUP_OBJECT,
+
+ GPU_DYNAMIC_LAMP_DYNVEC = 1 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_DYNCO = 2 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_DYNIMAT = 3 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_DYNPERSMAT = 4 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_DYNENERGY = 5 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_DYNCOL = 6 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_DISTANCE = 7 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_ATT1 = 8 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_ATT2 = 9 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_SPOTSIZE = 10 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_SPOTBLEND = 11 | GPU_DYNAMIC_GROUP_LAMP,
+
+ GPU_DYNAMIC_SAMPLER_2DBUFFER = 1 | GPU_DYNAMIC_GROUP_SAMPLER,
+ GPU_DYNAMIC_SAMPLER_2DIMAGE = 2 | GPU_DYNAMIC_GROUP_SAMPLER,
+ GPU_DYNAMIC_SAMPLER_2DSHADOW = 3 | GPU_DYNAMIC_GROUP_SAMPLER,
+
+ GPU_DYNAMIC_MIST_ENABLE = 1 | GPU_DYNAMIC_GROUP_MIST,
+ GPU_DYNAMIC_MIST_START = 2 | GPU_DYNAMIC_GROUP_MIST,
+ GPU_DYNAMIC_MIST_DISTANCE = 3 | GPU_DYNAMIC_GROUP_MIST,
+ GPU_DYNAMIC_MIST_INTENSITY = 4 | GPU_DYNAMIC_GROUP_MIST,
+ GPU_DYNAMIC_MIST_TYPE = 5 | GPU_DYNAMIC_GROUP_MIST,
+ GPU_DYNAMIC_MIST_COLOR = 6 | GPU_DYNAMIC_GROUP_MIST,
+
+ GPU_DYNAMIC_HORIZON_COLOR = 1 | GPU_DYNAMIC_GROUP_WORLD,
+ GPU_DYNAMIC_AMBIENT_COLOR = 2 | GPU_DYNAMIC_GROUP_WORLD,
+
+ GPU_DYNAMIC_MAT_DIFFRGB = 1 | GPU_DYNAMIC_GROUP_MAT,
+ GPU_DYNAMIC_MAT_REF = 2 | GPU_DYNAMIC_GROUP_MAT,
+ GPU_DYNAMIC_MAT_SPECRGB = 3 | GPU_DYNAMIC_GROUP_MAT,
+ GPU_DYNAMIC_MAT_SPEC = 4 | GPU_DYNAMIC_GROUP_MAT,
+ GPU_DYNAMIC_MAT_HARD = 5 | GPU_DYNAMIC_GROUP_MAT,
+ GPU_DYNAMIC_MAT_EMIT = 6 | GPU_DYNAMIC_GROUP_MAT,
+ GPU_DYNAMIC_MAT_AMB = 7 | GPU_DYNAMIC_GROUP_MAT,
+ GPU_DYNAMIC_MAT_ALPHA = 8 | GPU_DYNAMIC_GROUP_MAT
} GPUDynamicType;
GPUNodeLink *GPU_attribute(CustomDataType type, const char *name);
@@ -181,7 +209,7 @@ bool GPU_lamp_override_visible(GPULamp *lamp, struct SceneRenderLayer *srl, stru
void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, float viewmat[4][4], float viewinv[4][4], float cameraborder[4], bool scenelock);
void GPU_material_bind_uniforms(GPUMaterial *material, float obmat[4][4], float obcol[4], float autobumpscale);
void GPU_material_unbind(GPUMaterial *material);
-int GPU_material_bound(GPUMaterial *material);
+bool GPU_material_bound(GPUMaterial *material);
struct Scene *GPU_material_scene(GPUMaterial *material);
GPUMatType GPU_Material_get_type(GPUMaterial *material);
@@ -213,7 +241,7 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr);
typedef enum GPUDataType {
GPU_DATA_NONE = 0,
- GPU_DATA_1I = 1, // 1 integer
+ GPU_DATA_1I = 1, /* 1 integer */
GPU_DATA_1F = 2,
GPU_DATA_2F = 3,
GPU_DATA_3F = 4,
@@ -226,23 +254,23 @@ typedef enum GPUDataType {
/* this structure gives information of each uniform found in the shader */
typedef struct GPUInputUniform {
struct GPUInputUniform *next, *prev;
- char varname[32]; /* name of uniform in shader */
- GPUDynamicType type; /* type of uniform, data format and calculation derive from it */
- GPUDataType datatype; /* type of uniform data */
- struct Object *lamp; /* when type=GPU_DYNAMIC_LAMP_... or GPU_DYNAMIC_SAMPLER_2DSHADOW */
- struct Image *image; /* when type=GPU_DYNAMIC_SAMPLER_2DIMAGE */
- int texnumber; /* when type=GPU_DYNAMIC_SAMPLER, texture number: 0.. */
- unsigned char *texpixels; /* for internally generated texture, pixel data in RGBA format */
- int texsize; /* size in pixel of the texture in texpixels buffer: for 2D textures, this is S and T size (square texture) */
+ char varname[32]; /* name of uniform in shader */
+ GPUDynamicType type; /* type of uniform, data format and calculation derive from it */
+ GPUDataType datatype; /* type of uniform data */
+ struct Object *lamp; /* when type=GPU_DYNAMIC_LAMP_... or GPU_DYNAMIC_SAMPLER_2DSHADOW */
+ struct Image *image; /* when type=GPU_DYNAMIC_SAMPLER_2DIMAGE */
+ int texnumber; /* when type=GPU_DYNAMIC_SAMPLER, texture number: 0.. */
+ unsigned char *texpixels; /* for internally generated texture, pixel data in RGBA format */
+ int texsize; /* size in pixel of the texture in texpixels buffer: for 2D textures, this is S and T size (square texture) */
} GPUInputUniform;
typedef struct GPUInputAttribute {
struct GPUInputAttribute *next, *prev;
- char varname[32]; /* name of attribute in shader */
- int type; /* from CustomData.type, data type derives from it */
- GPUDataType datatype; /* type of attribute data */
- const char *name; /* layer name */
- int number; /* generic attribute number */
+ char varname[32]; /* name of attribute in shader */
+ int type; /* from CustomData.type, data type derives from it */
+ GPUDataType datatype; /* type of attribute data */
+ const char *name; /* layer name */
+ int number; /* generic attribute number */
} GPUInputAttribute;
typedef struct GPUShaderExport {
@@ -273,6 +301,12 @@ void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend);
int GPU_lamp_shadow_layer(GPULamp *lamp);
GPUNodeLink *GPU_lamp_get_data(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **col, GPUNodeLink **lv, GPUNodeLink **dist, GPUNodeLink **shadow, GPUNodeLink **energy);
+/* World */
+void GPU_mist_update_enable(short enable);
+void GPU_mist_update_values(int type, float start, float dist, float inten, float color[3]);
+void GPU_horizon_update_color(float color[3]);
+void GPU_ambient_update_color(float color[3]);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h
index 1a274e0ad9d..09137fc998b 100644
--- a/source/blender/gpu/GPU_select.h
+++ b/source/blender/gpu/GPU_select.h
@@ -27,8 +27,8 @@
* \ingroup gpu
*/
-#ifndef __GPU_SELECT__
-#define __GPU_SELECT__
+#ifndef __GPU_SELECT_H__
+#define __GPU_SELECT_H__
#include "DNA_vec_types.h" /* rcft */
#include "BLI_sys_types.h"
diff --git a/source/blender/gpu/GPU_simple_shader.h b/source/blender/gpu/GPU_simple_shader.h
index c8fb1f09b04..239296209b4 100644
--- a/source/blender/gpu/GPU_simple_shader.h
+++ b/source/blender/gpu/GPU_simple_shader.h
@@ -42,11 +42,11 @@ extern "C" {
typedef enum GPUSimpleShaderOption {
GPU_SHADER_OVERRIDE_DIFFUSE = (1<<0), /* replace diffuse with glcolor */
- GPU_SHADER_LIGHTING = (1<<1), /* use lighting */
- GPU_SHADER_TWO_SIDED = (1<<2), /* flip normals towards viewer */
- GPU_SHADER_TEXTURE_2D = (1<<3), /* use 2D texture to replace diffuse color */
+ GPU_SHADER_LIGHTING = (1<<1), /* use lighting */
+ GPU_SHADER_TWO_SIDED = (1<<2), /* flip normals towards viewer */
+ GPU_SHADER_TEXTURE_2D = (1<<3), /* use 2D texture to replace diffuse color */
- GPU_SHADER_SOLID_LIGHTING = (1<<4), /* use faster lighting (set automatically) */
+ GPU_SHADER_SOLID_LIGHTING = (1<<4), /* use faster lighting (set automatically) */
GPU_SHADER_OPTIONS_NUM = 5,
GPU_SHADER_OPTION_COMBINATIONS = (1<<GPU_SHADER_OPTIONS_NUM)
} GPUSimpleShaderOption;
diff --git a/source/blender/gpu/SConscript b/source/blender/gpu/SConscript
index f52b39dba3b..ff5fb42c021 100644
--- a/source/blender/gpu/SConscript
+++ b/source/blender/gpu/SConscript
@@ -63,9 +63,14 @@ if env['WITH_BF_DDS']:
# generated data files
import os
sources.extend((
+ os.path.join(env['DATA_SOURCES'], "gpu_program_smoke_frag.glsl.c"),
+ os.path.join(env['DATA_SOURCES'], "gpu_program_smoke_color_frag.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_simple_frag.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_simple_vert.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_ssao_frag.glsl.c"),
+ os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_hq_frag.glsl.c"),
+ os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_hq_vert.glsl.c"),
+ os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_hq_geo.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_frag.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_vert.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_depth_resolve.glsl.c"),
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 030554c9531..8554f2c08e0 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -411,8 +411,9 @@ void GPU_buffer_free(GPUBuffer *buffer)
BLI_mutex_unlock(&buffer_mutex);
}
-/* currently unused */
-// #define USE_GPU_POINT_LINK
+#if 0 /* currently unused */
+# define USE_GPU_POINT_LINK
+#endif
typedef struct GPUVertPointLink {
#ifdef USE_GPU_POINT_LINK
@@ -480,7 +481,7 @@ static void gpu_drawobject_init_vert_points(GPUDrawObject *gdo, MFace *f, int to
int i, *mat_orig_to_new;
mat_orig_to_new = MEM_callocN(sizeof(*mat_orig_to_new) * totmat,
- "GPUDrawObject.mat_orig_to_new");
+ "GPUDrawObject.mat_orig_to_new");
/* allocate the array and space for links */
gdo->vert_points = MEM_mallocN(sizeof(GPUVertPointLink) * gdo->totvert,
"GPUDrawObject.vert_points");
@@ -1471,6 +1472,7 @@ void GPU_buffer_unbind(void)
else
break;
}
+ attribData[0].index = -1;
/* not guaranteed we used VBOs but in that case it's just a no-op */
if (GLEW_ARB_vertex_buffer_object)
@@ -1604,6 +1606,7 @@ struct GPU_PBVH_Buffers {
bool use_matcaps;
float diffuse_color[4];
};
+
typedef enum {
VBO_ENABLED,
VBO_DISABLED
@@ -1683,8 +1686,8 @@ static void gpu_color_from_mask_quad_set(const CCGKey *key,
}
void GPU_update_mesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, MVert *mvert,
- int *vert_indices, int totvert, const float *vmask,
- int (*face_vert_indices)[4], bool show_diffuse_color)
+ int *vert_indices, int totvert, const float *vmask,
+ int (*face_vert_indices)[4], bool show_diffuse_color)
{
VertexBufferFormat *vert_data;
int i, j, k;
@@ -1821,9 +1824,9 @@ void GPU_update_mesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, MVert *mvert,
}
GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(int (*face_vert_indices)[4],
- MFace *mface, MVert *mvert,
- int *face_indices,
- int totface)
+ MFace *mface, MVert *mvert,
+ int *face_indices,
+ int totface)
{
GPU_PBVH_Buffers *buffers;
unsigned short *tri_data;
@@ -1913,8 +1916,8 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(int (*face_vert_indices)[4],
}
void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids,
- const DMFlagMat *grid_flag_mats, int *grid_indices,
- int totgrid, const CCGKey *key, bool show_diffuse_color)
+ const DMFlagMat *grid_flag_mats, int *grid_indices,
+ int totgrid, const CCGKey *key, bool show_diffuse_color)
{
VertexBufferFormat *vert_data;
int i, j, k, x, y;
@@ -2027,51 +2030,51 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids,
/* Build the element array buffer of grid indices using either
* unsigned shorts or unsigned ints. */
#define FILL_QUAD_BUFFER(type_, tot_quad_, buffer_) \
- { \
- type_ *tri_data; \
- int offset = 0; \
- int i, j, k; \
- \
- glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, \
- sizeof(type_) * (tot_quad_) * 6, NULL, \
- GL_STATIC_DRAW_ARB); \
- \
- /* Fill the buffer */ \
- tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, \
- GL_WRITE_ONLY_ARB); \
- if (tri_data) { \
- for (i = 0; i < totgrid; ++i) { \
- BLI_bitmap *gh = NULL; \
- if (grid_hidden) \
- gh = grid_hidden[(grid_indices)[i]]; \
- \
- for (j = 0; j < gridsize - 1; ++j) { \
- for (k = 0; k < gridsize - 1; ++k) { \
- /* Skip hidden grid face */ \
- if (gh && \
- paint_is_grid_face_hidden(gh, \
- gridsize, k, j)) \
- continue; \
- \
- *(tri_data++) = offset + j * gridsize + k + 1; \
- *(tri_data++) = offset + j * gridsize + k; \
- *(tri_data++) = offset + (j + 1) * gridsize + k; \
- \
- *(tri_data++) = offset + (j + 1) * gridsize + k + 1; \
- *(tri_data++) = offset + j * gridsize + k + 1; \
- *(tri_data++) = offset + (j + 1) * gridsize + k; \
- } \
- } \
- \
- offset += gridsize * gridsize; \
- } \
- glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); \
- } \
- else { \
- glDeleteBuffersARB(1, &(buffer_)); \
- (buffer_) = 0; \
- } \
- } (void)0
+ { \
+ type_ *tri_data; \
+ int offset = 0; \
+ int i, j, k; \
+ \
+ glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, \
+ sizeof(type_) * (tot_quad_) * 6, NULL, \
+ GL_STATIC_DRAW_ARB); \
+ \
+ /* Fill the buffer */ \
+ tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, \
+ GL_WRITE_ONLY_ARB); \
+ if (tri_data) { \
+ for (i = 0; i < totgrid; ++i) { \
+ BLI_bitmap *gh = NULL; \
+ if (grid_hidden) \
+ gh = grid_hidden[(grid_indices)[i]]; \
+ \
+ for (j = 0; j < gridsize - 1; ++j) { \
+ for (k = 0; k < gridsize - 1; ++k) { \
+ /* Skip hidden grid face */ \
+ if (gh && \
+ paint_is_grid_face_hidden(gh, \
+ gridsize, k, j)) \
+ continue; \
+ \
+ *(tri_data++) = offset + j * gridsize + k + 1; \
+ *(tri_data++) = offset + j * gridsize + k; \
+ *(tri_data++) = offset + (j + 1) * gridsize + k; \
+ \
+ *(tri_data++) = offset + (j + 1) * gridsize + k + 1; \
+ *(tri_data++) = offset + j * gridsize + k + 1; \
+ *(tri_data++) = offset + (j + 1) * gridsize + k; \
+ } \
+ } \
+ \
+ offset += gridsize * gridsize; \
+ } \
+ glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); \
+ } \
+ else { \
+ glDeleteBuffersARB(1, &(buffer_)); \
+ (buffer_) = 0; \
+ } \
+ } (void)0
/* end FILL_QUAD_BUFFER */
static GLuint gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned *totquad)
@@ -2127,7 +2130,7 @@ static GLuint gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned *to
}
GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
- BLI_bitmap **grid_hidden, int gridsize)
+ BLI_bitmap **grid_hidden, int gridsize)
{
GPU_PBVH_Buffers *buffers;
int totquad;
@@ -2209,7 +2212,6 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset),
diffuse_color,
vd->color);
-
/* Assign index for use in the triangle index buffer */
/* note: caller must set: bm->elem_index_dirty |= BM_VERT; */
@@ -2259,11 +2261,11 @@ static int gpu_bmesh_face_visible_count(GSet *bm_faces)
/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
* shading, an element index buffer. */
void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
- BMesh *bm,
- GSet *bm_faces,
- GSet *bm_unique_verts,
- GSet *bm_other_verts,
- bool show_diffuse_color)
+ BMesh *bm,
+ GSet *bm_faces,
+ GSet *bm_unique_verts,
+ GSet *bm_other_verts,
+ bool show_diffuse_color)
{
VertexBufferFormat *vert_data;
void *tri_data;
@@ -2310,8 +2312,8 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
/* Initialize vertex buffer */
glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
glBufferDataARB(GL_ARRAY_BUFFER_ARB,
- sizeof(VertexBufferFormat) * totvert,
- NULL, GL_STATIC_DRAW_ARB);
+ sizeof(VertexBufferFormat) * totvert,
+ NULL, GL_STATIC_DRAW_ARB);
/* Fill vertex buffer */
vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
@@ -2352,7 +2354,9 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
float fmask = 0;
int i;
- // BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void**)v, 3);
+#if 0
+ BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void**)v, 3);
+#endif
BM_face_as_array_vert_tri(f, v);
/* Average mask value */
@@ -2772,7 +2776,7 @@ bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces,
GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color);
}
else if (buffers->use_bmesh) {
- /* due to dynamc nature of dyntopo, only get first material */
+ /* due to dynamic nature of dyntopo, only get first material */
if (BLI_gset_size(bm_faces) > 0) {
GSetIterator gs_iter;
BMFace *f;
@@ -2823,7 +2827,7 @@ static void gpu_pbvh_buffer_free_intern(GLuint id)
if (pool->maxpbvhsize == pool->totpbvhbufids) {
pool->maxpbvhsize += MAX_FREE_GPU_BUFF_IDS;
pool->pbvhbufids = MEM_reallocN(pool->pbvhbufids,
- sizeof(*pool->pbvhbufids) * pool->maxpbvhsize);
+ sizeof(*pool->pbvhbufids) * pool->maxpbvhsize);
}
/* insert the buffer into the beginning of the pool */
@@ -2848,33 +2852,33 @@ void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers)
void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf)
{
const float quads[4][4][3] = {
- {
- {min[0], min[1], min[2]},
- {max[0], min[1], min[2]},
- {max[0], min[1], max[2]},
- {min[0], min[1], max[2]}
- },
-
- {
- {min[0], min[1], min[2]},
- {min[0], max[1], min[2]},
- {min[0], max[1], max[2]},
- {min[0], min[1], max[2]}
- },
-
- {
- {max[0], max[1], min[2]},
- {max[0], min[1], min[2]},
- {max[0], min[1], max[2]},
- {max[0], max[1], max[2]}
- },
-
- {
- {max[0], max[1], min[2]},
- {min[0], max[1], min[2]},
- {min[0], max[1], max[2]},
- {max[0], max[1], max[2]}
- },
+ {
+ {min[0], min[1], min[2]},
+ {max[0], min[1], min[2]},
+ {max[0], min[1], max[2]},
+ {min[0], min[1], max[2]}
+ },
+
+ {
+ {min[0], min[1], min[2]},
+ {min[0], max[1], min[2]},
+ {min[0], max[1], max[2]},
+ {min[0], min[1], max[2]}
+ },
+
+ {
+ {max[0], max[1], min[2]},
+ {max[0], min[1], min[2]},
+ {max[0], min[1], max[2]},
+ {max[0], max[1], max[2]}
+ },
+
+ {
+ {max[0], max[1], min[2]},
+ {min[0], max[1], min[2]},
+ {min[0], max[1], max[2]},
+ {max[0], max[1], max[2]}
+ },
};
if (leaf)
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 47d2ac2d2e5..8f07df5d3d1 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -46,7 +46,7 @@
#include "GPU_material.h"
#include "GPU_extensions.h"
-#include "BLI_sys_types.h" // for intptr_t support
+#include "BLI_sys_types.h" /* for intptr_t support */
#include "gpu_codegen.h"
@@ -90,9 +90,11 @@ static const char *GPU_DATATYPE_STR[17] = {"", "float", "vec2", "vec3", "vec4",
/* GLSL code parsing for finding function definitions.
* These are stored in a hash for lookup when creating a material. */
-static GHash *FUNCTION_HASH= NULL;
-/* static char *FUNCTION_PROTOTYPES= NULL;
- * static GPUShader *FUNCTION_LIB= NULL;*/
+static GHash *FUNCTION_HASH = NULL;
+#if 0
+static char *FUNCTION_PROTOTYPES = NULL;
+static GPUShader *FUNCTION_LIB = NULL;
+#endif
static int gpu_str_prefix(const char *str, const char *prefix)
{
@@ -117,7 +119,7 @@ static char *gpu_str_skip_token(char *str, char *token, int max)
break;
else {
if (token && len < max-1) {
- *token= *str;
+ *token = *str;
token++;
len++;
}
@@ -126,7 +128,7 @@ static char *gpu_str_skip_token(char *str, char *token, int max)
}
if (token)
- *token= '\0';
+ *token = '\0';
/* skip the next special characters:
* note the missing ')' */
@@ -165,10 +167,10 @@ static void gpu_parse_functions_string(GHash *hash, char *code)
code = gpu_str_skip_token(code, NULL, 0);
/* test for type */
- type= GPU_NONE;
- for (i=1; i<=16; i++) {
+ type = GPU_NONE;
+ for (i = 1; i <= 16; i++) {
if (GPU_DATATYPE_STR[i] && gpu_str_prefix(code, GPU_DATATYPE_STR[i])) {
- type= i;
+ type = i;
break;
}
}
@@ -220,7 +222,7 @@ static char *gpu_generate_function_prototyps(GHash *hash)
function = BLI_ghashIterator_getValue(ghi);
BLI_dynstr_appendf(ds, "void %s(", name);
- for (a=0; a<function->totparam; a++) {
+ for (a = 0; a < function->totparam; a++) {
if (function->paramqual[a] == FUNCTION_QUAL_OUT)
BLI_dynstr_append(ds, "out ");
else if (function->paramqual[a] == FUNCTION_QUAL_INOUT)
@@ -232,9 +234,10 @@ static char *gpu_generate_function_prototyps(GHash *hash)
BLI_dynstr_append(ds, "sampler2DShadow");
else
BLI_dynstr_append(ds, GPU_DATATYPE_STR[function->paramtype[a]]);
-
- //BLI_dynstr_appendf(ds, " param%d", a);
-
+# if 0
+ BLI_dynstr_appendf(ds, " param%d", a);
+# endif
+
if (a != function->totparam-1)
BLI_dynstr_append(ds, ", ");
}
@@ -267,7 +270,7 @@ void gpu_codegen_init(void)
void gpu_codegen_exit(void)
{
- extern Material defmaterial; // render module abuse...
+ extern Material defmaterial; /* render module abuse... */
if (defmaterial.gpumaterial.first)
GPU_material_free(&defmaterial.gpumaterial);
@@ -284,14 +287,16 @@ void gpu_codegen_exit(void)
glsl_material_library = NULL;
}
- /*if (FUNCTION_PROTOTYPES) {
+#if 0
+ if (FUNCTION_PROTOTYPES) {
MEM_freeN(FUNCTION_PROTOTYPES);
FUNCTION_PROTOTYPES = NULL;
- }*/
- /*if (FUNCTION_LIB) {
+ }
+ if (FUNCTION_LIB) {
GPU_shader_free(FUNCTION_LIB);
FUNCTION_LIB = NULL;
- }*/
+ }
+#endif
}
/* GLSL code generation */
@@ -306,18 +311,16 @@ static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *t
BLI_dynstr_append(ds, name);
}
else if (to == GPU_FLOAT) {
- if (from == GPU_VEC4)
- BLI_dynstr_appendf(ds, "dot(%s.rgb, vec3(0.35, 0.45, 0.2))", name);
- else if (from == GPU_VEC3)
- BLI_dynstr_appendf(ds, "dot(%s, vec3(0.33))", name);
+ if (from == GPU_VEC4 || from == GPU_VEC3)
+ BLI_dynstr_appendf(ds, "(%s.r + %s.g + %s.b) / 3.0", name, name, name);
else if (from == GPU_VEC2)
BLI_dynstr_appendf(ds, "%s.r", name);
}
else if (to == GPU_VEC2) {
if (from == GPU_VEC4)
- BLI_dynstr_appendf(ds, "vec2(dot(%s.rgb, vec3(0.35, 0.45, 0.2)), %s.a)", name, name);
+ BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, %s.a)", name, name, name, name);
else if (from == GPU_VEC3)
- BLI_dynstr_appendf(ds, "vec2(dot(%s.rgb, vec3(0.33)), 1.0)", name);
+ BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, 1.0)", name, name, name);
else if (from == GPU_FLOAT)
BLI_dynstr_appendf(ds, "vec2(%s, 1.0)", name);
}
@@ -345,9 +348,9 @@ static void codegen_print_datatype(DynStr *ds, const GPUType type, float *data)
BLI_dynstr_appendf(ds, "%s(", GPU_DATATYPE_STR[type]);
- for (i=0; i<type; i++) {
+ for (i = 0; i < type; i++) {
BLI_dynstr_appendf(ds, "%f", data[i]);
- if (i == type-1)
+ if (i == type - 1)
BLI_dynstr_append(ds, ")");
else
BLI_dynstr_append(ds, ", ");
@@ -412,11 +415,11 @@ static void codegen_set_unique_ids(ListBase *nodes)
GPUOutput *output;
int id = 1, texid = 0;
- bindhash= BLI_ghash_ptr_new("codegen_set_unique_ids1 gh");
- definehash= BLI_ghash_ptr_new("codegen_set_unique_ids2 gh");
+ bindhash = BLI_ghash_ptr_new("codegen_set_unique_ids1 gh");
+ definehash = BLI_ghash_ptr_new("codegen_set_unique_ids2 gh");
- for (node=nodes->first; node; node=node->next) {
- for (input=node->inputs.first; input; input=input->next) {
+ for (node = nodes->first; node; node = node->next) {
+ for (input = node->inputs.first; input; input = input->next) {
/* set id for unique names of uniform variables */
input->id = id++;
input->bindtex = false;
@@ -463,7 +466,7 @@ static void codegen_set_unique_ids(ListBase *nodes)
}
}
- for (output=node->outputs.first; output; output=output->next)
+ for (output = node->outputs.first; output; output = output->next)
/* set id for unique names of tmp variables storing output */
output->id = id++;
}
@@ -480,8 +483,8 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes)
int builtins = 0;
/* print uniforms */
- for (node=nodes->first; node; node=node->next) {
- for (input=node->inputs.first; input; input=input->next) {
+ for (node = nodes->first; node; node = node->next) {
+ for (input = node->inputs.first; input; input = input->next) {
if ((input->source == GPU_SOURCE_TEX) || (input->source == GPU_SOURCE_TEX_PIXEL)) {
/* create exactly one sampler for each texture */
if (codegen_input_has_texture(input) && input->bindtex)
@@ -537,9 +540,9 @@ static void codegen_declare_tmps(DynStr *ds, ListBase *nodes)
GPUInput *input;
GPUOutput *output;
- for (node=nodes->first; node; node=node->next) {
+ for (node = nodes->first; node; node = node->next) {
/* load pixels from textures */
- for (input=node->inputs.first; input; input=input->next) {
+ for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_TEX_PIXEL) {
if (codegen_input_has_texture(input) && input->definetex) {
BLI_dynstr_appendf(ds, "\tvec4 tex%d = texture2D(", input->texid);
@@ -550,7 +553,7 @@ static void codegen_declare_tmps(DynStr *ds, ListBase *nodes)
}
/* declare temporary variables for node output storage */
- for (output=node->outputs.first; output; output=output->next)
+ for (output = node->outputs.first; output; output = output->next)
BLI_dynstr_appendf(ds, "\t%s tmp%d;\n",
GPU_DATATYPE_STR[output->type], output->id);
}
@@ -564,10 +567,10 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final
GPUInput *input;
GPUOutput *output;
- for (node=nodes->first; node; node=node->next) {
+ for (node = nodes->first; node; node = node->next) {
BLI_dynstr_appendf(ds, "\t%s(", node->name);
- for (input=node->inputs.first; input; input=input->next) {
+ for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_TEX) {
BLI_dynstr_appendf(ds, "samp%d", input->texid);
if (input->link)
@@ -602,7 +605,7 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final
BLI_dynstr_append(ds, ", ");
}
- for (output=node->outputs.first; output; output=output->next) {
+ for (output = node->outputs.first; output; output = output->next) {
BLI_dynstr_appendf(ds, "tmp%d", output->id);
if (output->next)
BLI_dynstr_append(ds, ", ");
@@ -622,13 +625,17 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output)
char *code;
int builtins;
- /*BLI_dynstr_append(ds, FUNCTION_PROTOTYPES);*/
+#if 0
+ BLI_dynstr_append(ds, FUNCTION_PROTOTYPES);
+#endif
codegen_set_unique_ids(nodes);
builtins = codegen_print_uniforms_functions(ds, nodes);
- //if (G.debug & G_DEBUG)
- // BLI_dynstr_appendf(ds, "/* %s */\n", name);
+#if 0
+ if (G.debug & G_DEBUG)
+ BLI_dynstr_appendf(ds, "/* %s */\n", name);
+#endif
BLI_dynstr_append(ds, "void main(void)\n");
BLI_dynstr_append(ds, "{\n");
@@ -645,7 +652,9 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output)
code = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
- //if (G.debug & G_DEBUG) printf("%s\n", code);
+#if 0
+ if (G.debug & G_DEBUG) printf("%s\n", code);
+#endif
return code;
}
@@ -658,8 +667,8 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
char *code;
char *vertcode;
- for (node=nodes->first; node; node=node->next) {
- for (input=node->inputs.first; input; input=input->next) {
+ for (node = nodes->first; node; node = node->next) {
+ for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
BLI_dynstr_appendf(ds, "attribute %s att%d;\n",
GPU_DATATYPE_STR[input->type], input->attribid);
@@ -685,8 +694,8 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
BLI_dynstr_append(ds, vertcode);
- for (node=nodes->first; node; node=node->next)
- for (input=node->inputs.first; input; input=input->next)
+ for (node = nodes->first; node; node = node->next)
+ for (input = node->inputs.first; input; input = input->next)
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
if (input->attribtype == CD_TANGENT) { /* silly exception */
BLI_dynstr_appendf(ds, "\tvar%d.xyz = normalize(gl_NormalMatrix * att%d.xyz);\n", input->attribid, input->attribid);
@@ -714,16 +723,13 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
BLI_dynstr_free(ds);
- //if (G.debug & G_DEBUG) printf("%s\n", code);
+#if 0
+ if (G.debug & G_DEBUG) printf("%s\n", code);
+#endif
return code;
}
-int GPU_bicubic_bump_support(void)
-{
- return GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0;
-}
-
void GPU_code_generate_glsl_lib(void)
{
DynStr *ds;
@@ -765,9 +771,9 @@ static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
GPU_shader_bind(shader);
- for (node=nodes->first; node; node=node->next) {
+ for (node = nodes->first; node; node = node->next) {
z = 0;
- for (input=node->inputs.first; input; input=next, z++) {
+ for (input = node->inputs.first; input; input = next, z++) {
next = input->next;
/* attributes don't need to be bound, they already have
@@ -820,7 +826,7 @@ void GPU_pass_bind(GPUPass *pass, double time, int mipmap)
GPU_shader_bind(shader);
/* now bind the textures */
- for (input=inputs->first; input; input=input->next) {
+ for (input = inputs->first; input; input = input->next) {
if (input->ima)
input->tex = GPU_texture_from_blender(input->ima, input->iuser, input->image_isdata, time, mipmap);
else if (input->prv)
@@ -844,10 +850,19 @@ void GPU_pass_update_uniforms(GPUPass *pass)
return;
/* pass dynamic inputs to opengl, others were removed */
- for (input=inputs->first; input; input=input->next)
- if (!(input->ima || input->tex || input->prv))
- GPU_shader_uniform_vector(shader, input->shaderloc, input->type, 1,
- input->dynamicvec);
+ for (input = inputs->first; input; input = input->next) {
+ if (!(input->ima || input->tex || input->prv)) {
+ if (input->dynamictype == GPU_DYNAMIC_MAT_HARD) {
+ // The hardness is actually a short pointer, so we convert it here
+ float val = (float)(*(short*)input->dynamicvec);
+ GPU_shader_uniform_vector(shader, input->shaderloc, 1, 1, &val);
+ }
+ else {
+ GPU_shader_uniform_vector(shader, input->shaderloc, input->type, 1,
+ input->dynamicvec);
+ }
+ }
+ }
}
void GPU_pass_unbind(GPUPass *pass)
@@ -859,7 +874,7 @@ void GPU_pass_unbind(GPUPass *pass)
if (!shader)
return;
- for (input=inputs->first; input; input=input->next) {
+ for (input = inputs->first; input; input = input->next) {
if (input->tex && input->bindtex)
GPU_texture_unbind(input->tex);
@@ -901,7 +916,7 @@ static GPUNode *GPU_node_begin(const char *name)
{
GPUNode *node = MEM_callocN(sizeof(GPUNode), "GPUNode");
- node->name= name;
+ node->name = name;
return node;
}
@@ -915,8 +930,11 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
if (link->output) {
outnode = link->output->node;
name = outnode->name;
+ input = outnode->inputs.first;
- if (STREQ(name, "set_value") || STREQ(name, "set_rgb")) {
+ if ((STREQ(name, "set_value") || STREQ(name, "set_rgb")) &&
+ (input->type == type))
+ {
input = MEM_dupallocN(outnode->inputs.first);
input->type = type;
if (input->link)
@@ -970,7 +988,9 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
input->source = GPU_SOURCE_TEX;
input->textype = type;
- //input->tex = GPU_texture_create_2D(link->texturesize, link->texturesize, link->ptr2, NULL);
+#if 0
+ input->tex = GPU_texture_create_2D(link->texturesize, link->texturesize, link->ptr2, NULL);
+#endif
input->tex = GPU_texture_create_2D(link->texturesize, 1, link->ptr1, GPU_HDR_NONE, NULL);
input->textarget = GL_TEXTURE_2D;
@@ -1009,9 +1029,9 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
memcpy(input->vec, link->ptr1, type*sizeof(float));
if (link->dynamic) {
- input->dynamicvec= link->ptr1;
- input->dynamictype= link->dynamictype;
- input->dynamicdata= link->ptr2;
+ input->dynamicvec = link->ptr1;
+ input->dynamictype = link->dynamictype;
+ input->dynamicdata = link->ptr2;
}
MEM_freeN(link);
}
@@ -1045,7 +1065,7 @@ static void gpu_node_output(GPUNode *node, const GPUType type, GPUNodeLink **lin
output->link->type = type;
output->link->output = output;
- /* note: the caller owns the reference to the linkfer, GPUOutput
+ /* note: the caller owns the reference to the link, GPUOutput
* merely points to it, and if the node is destroyed it will
* set that pointer to NULL */
}
@@ -1057,7 +1077,7 @@ static void gpu_inputs_free(ListBase *inputs)
{
GPUInput *input;
- for (input=inputs->first; input; input=input->next) {
+ for (input = inputs->first; input; input = input->next) {
if (input->link)
gpu_node_link_free(input->link);
else if (input->tex && !input->dynamictex)
@@ -1073,7 +1093,7 @@ static void gpu_node_free(GPUNode *node)
gpu_inputs_free(&node->inputs);
- for (output=node->outputs.first; output; output=output->next)
+ for (output = node->outputs.first; output; output = output->next)
if (output->link) {
output->link->output = NULL;
gpu_node_link_free(output->link);
@@ -1105,10 +1125,10 @@ static void gpu_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *a
memset(attribs, 0, sizeof(*attribs));
- for (node=nodes->first; node; node=node->next) {
- for (input=node->inputs.first; input; input=input->next) {
+ for (node = nodes->first; node; node = node->next) {
+ for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_ATTRIB) {
- for (a=0; a<attribs->totlayer; a++) {
+ for (a = 0; a < attribs->totlayer; a++) {
if (attribs->layer[a].type == input->attribtype &&
STREQ(attribs->layer[a].name, input->attribname))
{
@@ -1140,10 +1160,10 @@ static void gpu_nodes_get_builtin_flag(ListBase *nodes, int *builtin)
GPUNode *node;
GPUInput *input;
- *builtin= 0;
+ *builtin = 0;
- for (node=nodes->first; node; node=node->next)
- for (input=node->inputs.first; input; input=input->next)
+ for (node = nodes->first; node; node = node->next)
+ for (input = node->inputs.first; input; input = input->next)
if (input->source == GPU_SOURCE_BUILTIN)
*builtin |= input->builtin;
}
@@ -1154,8 +1174,8 @@ GPUNodeLink *GPU_attribute(const CustomDataType type, const char *name)
{
GPUNodeLink *link = GPU_node_link_create();
- link->attribtype= type;
- link->attribname= name;
+ link->attribtype = type;
+ link->attribname = name;
return link;
}
@@ -1164,8 +1184,8 @@ GPUNodeLink *GPU_uniform(float *num)
{
GPUNodeLink *link = GPU_node_link_create();
- link->ptr1= num;
- link->ptr2= NULL;
+ link->ptr1 = num;
+ link->ptr2 = NULL;
return link;
}
@@ -1174,9 +1194,9 @@ GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *d
{
GPUNodeLink *link = GPU_node_link_create();
- link->ptr1= num;
- link->ptr2= data;
- link->dynamic= true;
+ link->ptr1 = num;
+ link->ptr2 = data;
+ link->dynamic = true;
link->dynamictype = dynamictype;
@@ -1199,8 +1219,8 @@ GPUNodeLink *GPU_image_preview(PreviewImage *prv)
{
GPUNodeLink *link = GPU_node_link_create();
- link->image= GPU_NODE_LINK_IMAGE_PREVIEW;
- link->ptr1= prv;
+ link->image = GPU_NODE_LINK_IMAGE_PREVIEW;
+ link->ptr1 = prv;
return link;
}
@@ -1212,7 +1232,7 @@ GPUNodeLink *GPU_texture(int size, float *pixels)
link->texture = true;
link->texturesize = size;
- link->ptr1= pixels;
+ link->ptr1 = pixels;
return link;
}
@@ -1264,13 +1284,13 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
node = GPU_node_begin(name);
va_start(params, name);
- for (i=0; i<function->totparam; i++) {
+ for (i = 0; i<function->totparam; i++) {
if (function->paramqual[i] != FUNCTION_QUAL_IN) {
- linkptr= va_arg(params, GPUNodeLink**);
+ linkptr = va_arg(params, GPUNodeLink**);
gpu_node_output(node, function->paramtype[i], linkptr);
}
else {
- link= va_arg(params, GPUNodeLink*);
+ link = va_arg(params, GPUNodeLink*);
gpu_node_input_link(node, link, function->paramtype[i]);
}
}
@@ -1314,10 +1334,10 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
}
va_start(params, out);
- for (i=0; i<function->totparam; i++) {
+ for (i = 0; i<function->totparam; i++) {
if (function->paramqual[i] != FUNCTION_QUAL_IN) {
if (totout == 0) {
- linkptr= va_arg(params, GPUNodeLink**);
+ linkptr = va_arg(params, GPUNodeLink**);
gpu_node_output(node, function->paramtype[i], linkptr);
}
else
@@ -1325,7 +1345,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
}
else {
if (totin == 0) {
- link= va_arg(params, GPUNodeLink*);
+ link = va_arg(params, GPUNodeLink*);
if (link->socket)
gpu_node_input_socket(node, link->socket);
else
@@ -1378,7 +1398,7 @@ static void gpu_nodes_tag(GPUNodeLink *link)
return;
node->tag = true;
- for (input=node->inputs.first; input; input=input->next)
+ for (input = node->inputs.first; input; input = input->next)
if (input->link)
gpu_nodes_tag(input->link);
}
@@ -1387,12 +1407,12 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
{
GPUNode *node, *next;
- for (node=nodes->first; node; node=node->next)
+ for (node = nodes->first; node; node = node->next)
node->tag = false;
gpu_nodes_tag(outlink);
- for (node=nodes->first; node; node=next) {
+ for (node = nodes->first; node; node = next) {
next = node->next;
if (!node->tag) {
@@ -1410,10 +1430,12 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink,
GPUPass *pass;
char *vertexcode, *fragmentcode;
- /*if (!FUNCTION_LIB) {
+#if 0
+ if (!FUNCTION_LIB) {
GPU_nodes_free(nodes);
return NULL;
- }*/
+ }
+#endif
/* prune unused nodes */
gpu_nodes_prune(nodes, outlink);
@@ -1424,7 +1446,7 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink,
/* generate code and compile with opengl */
fragmentcode = code_generate_fragment(nodes, outlink->output);
vertexcode = code_generate_vertex(nodes, type);
- shader = GPU_shader_create(vertexcode, fragmentcode, glsl_material_library, NULL);
+ shader = GPU_shader_create(vertexcode, fragmentcode, NULL, glsl_material_library, NULL, 0, 0, 0);
/* failed? */
if (!shader) {
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index a6da5e018fd..c6ed2e3f837 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -43,7 +43,6 @@ struct GPUShader;
struct GPUOutput;
struct GPUNode;
struct GPUVertexAttribs;
-struct GPUFrameBuffer;
struct PreviewImage;
/* Pass Generation
@@ -113,9 +112,9 @@ typedef struct GPUOutput {
struct GPUOutput *next, *prev;
GPUNode *node;
- GPUType type; /* data type = length of vector/matrix */
- GPUNodeLink *link; /* output link */
- int id; /* unique id as created by code generator */
+ GPUType type; /* data type = length of vector/matrix */
+ GPUNodeLink *link; /* output link */
+ int id; /* unique id as created by code generator */
} GPUOutput;
typedef struct GPUInput {
@@ -123,35 +122,35 @@ typedef struct GPUInput {
GPUNode *node;
- GPUType type; /* datatype */
- GPUDataSource source; /* data source */
-
- int id; /* unique id as created by code generator */
- int texid; /* number for multitexture, starting from zero */
- int attribid; /* id for vertex attributes */
- bool bindtex; /* input is responsible for binding the texture? */
- bool definetex; /* input is responsible for defining the pixel? */
- int textarget; /* GL texture target, e.g. GL_TEXTURE_2D */
- GPUType textype; /* datatype */
-
- struct Image *ima; /* image */
- struct ImageUser *iuser;/* image user */
- struct PreviewImage *prv; /* preview images & icons */
- bool image_isdata; /* image does not contain color data */
- float *dynamicvec; /* vector data in case it is dynamic */
- GPUDynamicType dynamictype; /* origin of the dynamic uniform */
- void *dynamicdata; /* data source of the dynamic uniform */
- struct GPUTexture *tex; /* input texture, only set at runtime */
- int shaderloc; /* id from opengl */
- char shadername[32]; /* name in shader */
-
- float vec[16]; /* vector data */
+ GPUType type; /* datatype */
+ GPUDataSource source; /* data source */
+
+ int id; /* unique id as created by code generator */
+ int texid; /* number for multitexture, starting from zero */
+ int attribid; /* id for vertex attributes */
+ bool bindtex; /* input is responsible for binding the texture? */
+ bool definetex; /* input is responsible for defining the pixel? */
+ int textarget; /* GL texture target, e.g. GL_TEXTURE_2D */
+ GPUType textype; /* datatype */
+
+ struct Image *ima; /* image */
+ struct ImageUser *iuser; /* image user */
+ struct PreviewImage *prv; /* preview images & icons */
+ bool image_isdata; /* image does not contain color data */
+ float *dynamicvec; /* vector data in case it is dynamic */
+ GPUDynamicType dynamictype; /* origin of the dynamic uniform */
+ void *dynamicdata; /* data source of the dynamic uniform */
+ struct GPUTexture *tex; /* input texture, only set at runtime */
+ int shaderloc; /* id from opengl */
+ char shadername[32]; /* name in shader */
+
+ float vec[16]; /* vector data */
GPUNodeLink *link;
- bool dynamictex; /* dynamic? */
- CustomDataType attribtype; /* attribute type */
- char attribname[MAX_CUSTOMDATA_LAYER_NAME]; /* attribute name */
- int attribfirst; /* this is the first one that is bound */
- GPUBuiltin builtin; /* builtin uniform */
+ bool dynamictex; /* dynamic? */
+ CustomDataType attribtype; /* attribute type */
+ char attribname[MAX_CUSTOMDATA_LAYER_NAME]; /* attribute name */
+ int attribfirst; /* this is the first one that is bound */
+ GPUBuiltin builtin; /* builtin uniform */
GPUOpenGLBuiltin oglbuiltin; /* opengl built in varying */
} GPUInput;
@@ -170,8 +169,8 @@ struct GPUPass {
typedef struct GPUPass GPUPass;
GPUPass *GPU_generate_pass(ListBase *nodes, struct GPUNodeLink *outlink,
- struct GPUVertexAttribs *attribs, int *builtin,
- const GPUMatType type, const char *name);
+ struct GPUVertexAttribs *attribs, int *builtin,
+ const GPUMatType type, const char *name);
struct GPUShader *GPU_pass_shader(GPUPass *pass);
diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c
index 6ed6a4537e9..d19be0a8b7e 100644
--- a/source/blender/gpu/intern/gpu_compositing.c
+++ b/source/blender/gpu/intern/gpu_compositing.c
@@ -50,7 +50,7 @@
#include "GPU_extensions.h"
#include "GPU_compositing.h"
-#include "GL/glew.h"
+#include "GPU_glew.h"
#include "MEM_guardedalloc.h"
@@ -62,11 +62,20 @@ struct GPUFX {
* depth/color framebuffer. Could be extended later though */
GPUFrameBuffer *gbuffer;
+ /* dimensions of the gbuffer */
+ int gbuffer_dim[2];
+
/* texture bound to the first color attachment of the gbuffer */
GPUTexture *color_buffer;
/* second texture used for ping-pong compositing */
GPUTexture *color_buffer_sec;
+ /* texture bound to the depth attachment of the gbuffer */
+ GPUTexture *depth_buffer;
+ GPUTexture *depth_buffer_xray;
+
+ /* texture used for jittering for various effects */
+ GPUTexture *jitter_buffer;
/* all those buffers below have to coexist. Fortunately they are all quarter sized (1/16th of memory) of original framebuffer */
int dof_downsampled_w;
@@ -80,26 +89,20 @@ struct GPUFX {
GPUTexture *dof_near_coc_final_buffer;
/* half size blur buffer */
- GPUTexture *dof_half_downsampled;
- /* high quality dof texture downsamplers. 6 levels means 64 pixels wide */
- GPUTexture *dof_nearfar_coc[6];
+ GPUTexture *dof_half_downsampled_near;
+ GPUTexture *dof_half_downsampled_far;
+ /* high quality dof texture downsamplers. 6 levels means 64 pixels wide - should be enough */
+ GPUTexture *dof_nearfar_coc;
GPUTexture *dof_near_blur;
GPUTexture *dof_far_blur;
- GPUTexture *dof_concentric_samples_tex;
-
- /* texture bound to the depth attachment of the gbuffer */
- GPUTexture *depth_buffer;
- GPUTexture *depth_buffer_xray;
- /* texture used for jittering for various effects */
- GPUTexture *jitter_buffer;
+ /* for high quality we use again a spiral texture with radius adapted */
+ bool dof_high_quality;
/* texture used for ssao */
- int ssao_sample_count;
- GPUTexture *ssao_concentric_samples_tex;
+ int ssao_sample_count_cache;
+ GPUTexture *ssao_spiral_samples_tex;
- /* dimensions of the gbuffer */
- int gbuffer_dim[2];
GPUFXSettings settings;
@@ -111,6 +114,8 @@ struct GPUFX {
/* we have a stencil, restore the previous state */
bool restore_stencil;
+
+ unsigned int vbuffer;
};
#if 0
@@ -174,6 +179,14 @@ GPUFX *GPU_fx_compositor_create(void)
{
GPUFX *fx = MEM_callocN(sizeof(GPUFX), "GPUFX compositor");
+ if (GLEW_ARB_vertex_buffer_object) {
+ glGenBuffersARB(1, &fx->vbuffer);
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, fx->vbuffer);
+ glBufferDataARB(GL_ARRAY_BUFFER_ARB, 16 * sizeof(float), NULL, GL_STATIC_DRAW);
+ glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, 8 * sizeof(float), fullscreencos);
+ glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 8 * sizeof(float), 8 * sizeof(float), fullscreenuvs);
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ }
return fx;
}
@@ -192,16 +205,17 @@ static void cleanup_fx_dof_buffers(GPUFX *fx)
fx->dof_near_coc_final_buffer = NULL;
}
- if (fx->dof_half_downsampled) {
- GPU_texture_free(fx->dof_half_downsampled);
- fx->dof_half_downsampled = NULL;
+ if (fx->dof_half_downsampled_near) {
+ GPU_texture_free(fx->dof_half_downsampled_near);
+ fx->dof_half_downsampled_near = NULL;
}
- if (fx->dof_nearfar_coc[0]) {
- int i;
- for (i = 0; i < 6; i++) {
- GPU_texture_free(fx->dof_nearfar_coc[i]);
- fx->dof_nearfar_coc[i] = NULL;
- }
+ if (fx->dof_half_downsampled_far) {
+ GPU_texture_free(fx->dof_half_downsampled_far);
+ fx->dof_half_downsampled_far = NULL;
+ }
+ if (fx->dof_nearfar_coc) {
+ GPU_texture_free(fx->dof_nearfar_coc);
+ fx->dof_nearfar_coc = NULL;
}
if (fx->dof_near_blur) {
GPU_texture_free(fx->dof_near_blur);
@@ -211,10 +225,6 @@ static void cleanup_fx_dof_buffers(GPUFX *fx)
GPU_texture_free(fx->dof_far_blur);
fx->dof_far_blur = NULL;
}
- if (fx->dof_concentric_samples_tex) {
- GPU_texture_free(fx->dof_concentric_samples_tex);
- fx->dof_concentric_samples_tex = NULL;
- }
}
static void cleanup_fx_gl_data(GPUFX *fx, bool do_fbo)
@@ -245,9 +255,9 @@ static void cleanup_fx_gl_data(GPUFX *fx, bool do_fbo)
cleanup_fx_dof_buffers(fx);
- if (fx->ssao_concentric_samples_tex) {
- GPU_texture_free(fx->ssao_concentric_samples_tex);
- fx->ssao_concentric_samples_tex = NULL;
+ if (fx->ssao_spiral_samples_tex) {
+ GPU_texture_free(fx->ssao_spiral_samples_tex);
+ fx->ssao_spiral_samples_tex = NULL;
}
if (fx->jitter_buffer && do_fbo) {
@@ -265,6 +275,8 @@ static void cleanup_fx_gl_data(GPUFX *fx, bool do_fbo)
void GPU_fx_compositor_destroy(GPUFX *fx)
{
cleanup_fx_gl_data(fx, true);
+ if (GLEW_ARB_vertex_buffer_object)
+ glDeleteBuffersARB(1, &fx->vbuffer);
MEM_freeN(fx);
}
@@ -279,7 +291,7 @@ static GPUTexture * create_jitter_texture(void)
normalize_v2(jitter[i]);
}
- return GPU_texture_create_2D_procedural(64, 64, &jitter[0][0], NULL);
+ return GPU_texture_create_2D_procedural(64, 64, &jitter[0][0], true, NULL);
}
bool GPU_fx_compositor_initialize_passes(
@@ -355,54 +367,113 @@ bool GPU_fx_compositor_initialize_passes(
}
if (fx_flag & GPU_FX_FLAG_SSAO) {
- if (fx_settings->ssao->samples != fx->ssao_sample_count || !fx->ssao_concentric_samples_tex) {
+ if (fx_settings->ssao->samples != fx->ssao_sample_count_cache || !fx->ssao_spiral_samples_tex) {
if (fx_settings->ssao->samples < 1)
fx_settings->ssao->samples = 1;
- fx->ssao_sample_count = fx_settings->ssao->samples;
+ fx->ssao_sample_count_cache = fx_settings->ssao->samples;
- if (fx->ssao_concentric_samples_tex) {
- GPU_texture_free(fx->ssao_concentric_samples_tex);
+ if (fx->ssao_spiral_samples_tex) {
+ GPU_texture_free(fx->ssao_spiral_samples_tex);
}
- fx->ssao_concentric_samples_tex = create_spiral_sample_texture(fx_settings->ssao->samples);
+ fx->ssao_spiral_samples_tex = create_spiral_sample_texture(fx_settings->ssao->samples);
}
}
else {
- if (fx->ssao_concentric_samples_tex) {
- GPU_texture_free(fx->ssao_concentric_samples_tex);
- fx->ssao_concentric_samples_tex = NULL;
+ if (fx->ssao_spiral_samples_tex) {
+ GPU_texture_free(fx->ssao_spiral_samples_tex);
+ fx->ssao_spiral_samples_tex = NULL;
}
}
/* create textures for dof effect */
if (fx_flag & GPU_FX_FLAG_DOF) {
- if (!fx->dof_near_coc_buffer || !fx->dof_near_coc_blurred_buffer || !fx->dof_near_coc_final_buffer) {
+ bool dof_high_quality = (fx_settings->dof->high_quality != 0) &&
+ GPU_geometry_shader_support() && GPU_instanced_drawing_support();
+
+ /* cleanup buffers if quality setting has changed (no need to keep more buffers around than necessary ) */
+ if (dof_high_quality != fx->dof_high_quality)
+ cleanup_fx_dof_buffers(fx);
+
+ if (dof_high_quality) {
+ fx->dof_downsampled_w = w / 2;
+ fx->dof_downsampled_h = h / 2;
+
+ if (!fx->dof_half_downsampled_near || !fx->dof_nearfar_coc || !fx->dof_near_blur ||
+ !fx->dof_far_blur || !fx->dof_half_downsampled_far) {
+
+ if (!(fx->dof_half_downsampled_near = GPU_texture_create_2D(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
+ {
+ printf("%.256s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+ if (!(fx->dof_half_downsampled_far = GPU_texture_create_2D(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
+ {
+ printf("%.256s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+ if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_procedural(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, false, err_out)))
+ {
+ printf("%.256s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+
+
+ if (!(fx->dof_near_blur = GPU_texture_create_2D(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out)))
+ {
+ printf("%.256s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+
+ if (!(fx->dof_far_blur = GPU_texture_create_2D(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out)))
+ {
+ printf("%.256s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+ }
+ }
+ else {
fx->dof_downsampled_w = w / 4;
fx->dof_downsampled_h = h / 4;
- if (!(fx->dof_near_coc_buffer = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
- {
- printf("%.256s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return false;
- }
- if (!(fx->dof_near_coc_blurred_buffer = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
- {
- printf("%.256s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return false;
- }
- if (!(fx->dof_near_coc_final_buffer = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
- {
- printf("%.256s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return false;
+ if (!fx->dof_near_coc_buffer || !fx->dof_near_coc_blurred_buffer || !fx->dof_near_coc_final_buffer) {
+
+ if (!(fx->dof_near_coc_buffer = GPU_texture_create_2D(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
+ {
+ printf("%.256s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+ if (!(fx->dof_near_coc_blurred_buffer = GPU_texture_create_2D(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
+ {
+ printf("%.256s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
+ if (!(fx->dof_near_coc_final_buffer = GPU_texture_create_2D(
+ fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
+ {
+ printf("%.256s\n", err_out);
+ cleanup_fx_gl_data(fx, true);
+ return false;
+ }
}
}
+
+ fx->dof_high_quality = dof_high_quality;
}
else {
/* cleanup unnecessary buffers */
@@ -411,7 +482,7 @@ bool GPU_fx_compositor_initialize_passes(
/* we need to pass data between shader stages, allocate an extra color buffer */
if (num_passes > 1) {
- if(!fx->color_buffer_sec) {
+ if (!fx->color_buffer_sec) {
if (!(fx->color_buffer_sec = GPU_texture_create_2D(w, h, NULL, GPU_HDR_NONE, err_out))) {
printf(".256%s\n", err_out);
cleanup_fx_gl_data(fx, true);
@@ -430,13 +501,13 @@ bool GPU_fx_compositor_initialize_passes(
/* bind the buffers */
/* first depth buffer, because system assumes read/write buffers */
- if(!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, err_out))
+ if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, err_out))
printf("%.256s\n", err_out);
- if(!GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0, err_out))
+ if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0, err_out))
printf("%.256s\n", err_out);
- if(!GPU_framebuffer_check_valid(fx->gbuffer, err_out))
+ if (!GPU_framebuffer_check_valid(fx->gbuffer, err_out))
printf("%.256s\n", err_out);
GPU_texture_bind_as_framebuffer(fx->color_buffer);
@@ -506,7 +577,7 @@ void GPU_fx_compositor_setup_XRay_pass(GPUFX *fx, bool do_xray)
GPU_framebuffer_texture_detach(fx->depth_buffer);
/* first depth buffer, because system assumes read/write buffers */
- if(!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer_xray, 0, err_out))
+ if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer_xray, 0, err_out))
printf("%.256s\n", err_out);
}
@@ -528,8 +599,9 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx)
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
/* set up quad buffer */
- glVertexPointer(2, GL_FLOAT, 0, fullscreencos);
- glTexCoordPointer(2, GL_FLOAT, 0, fullscreenuvs);
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, fx->vbuffer);
+ glVertexPointer(2, GL_FLOAT, 0, NULL);
+ glTexCoordPointer(2, GL_FLOAT, 0, ((GLubyte *)NULL + 8 * sizeof(float)));
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -543,14 +615,14 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx)
GPU_shader_bind(depth_resolve_shader);
GPU_texture_bind(fx->depth_buffer_xray, 0);
- GPU_depth_texture_mode(fx->depth_buffer_xray, false, true);
+ GPU_texture_filter_mode(fx->depth_buffer_xray, false, true);
GPU_shader_uniform_texture(depth_resolve_shader, depth_uniform, fx->depth_buffer_xray);
/* draw */
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
/* disable bindings */
- GPU_depth_texture_mode(fx->depth_buffer_xray, true, false);
+ GPU_texture_filter_mode(fx->depth_buffer_xray, true, false);
GPU_texture_unbind(fx->depth_buffer_xray);
GPU_shader_unbind();
@@ -558,6 +630,7 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx)
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -571,6 +644,7 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
int numslots = 0;
float invproj[4][4];
int i;
+ float dfdyfac[2];
/* number of passes left. when there are no more passes, the result is passed to the frambuffer */
int passes_left = fx->num_passes;
/* view vectors for the corners of the view frustum. Can be used to recreate the world space position easily */
@@ -583,6 +657,7 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
if (fx->effects == 0)
return false;
+ GPU_get_dfdy_factors(dfdyfac);
/* first, unbind the render-to-texture framebuffer */
GPU_framebuffer_texture_detach(fx->color_buffer);
GPU_framebuffer_texture_detach(fx->depth_buffer);
@@ -594,8 +669,9 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
target = fx->color_buffer_sec;
/* set up quad buffer */
- glVertexPointer(2, GL_FLOAT, 0, fullscreencos);
- glTexCoordPointer(2, GL_FLOAT, 0, fullscreenuvs);
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, fx->vbuffer);
+ glVertexPointer(2, GL_FLOAT, 0, NULL);
+ glTexCoordPointer(2, GL_FLOAT, 0, ((GLubyte *)NULL + 8 * sizeof(float)));
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -640,12 +716,14 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
int ssao_uniform, ssao_color_uniform, viewvecs_uniform, ssao_sample_params_uniform;
int ssao_jitter_uniform, ssao_concentric_tex;
float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, fx_ssao->attenuation, 0.0f};
- float sample_params[4];
+ float sample_params[3];
- sample_params[0] = fx->ssao_sample_count;
+ sample_params[0] = fx->ssao_sample_count_cache;
/* multiplier so we tile the random texture on screen */
- sample_params[2] = fx->gbuffer_dim[0] / 64.0;
- sample_params[3] = fx->gbuffer_dim[1] / 64.0;
+ sample_params[1] = fx->gbuffer_dim[0] / 64.0;
+ sample_params[2] = fx->gbuffer_dim[1] / 64.0;
+
+ ssao_params[3] = (passes_left == 1 && !ofs) ? dfdyfac[0] : dfdyfac[1];
ssao_uniform = GPU_shader_get_uniform(ssao_shader, "ssao_params");
ssao_color_uniform = GPU_shader_get_uniform(ssao_shader, "ssao_color");
@@ -661,20 +739,20 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
GPU_shader_uniform_vector(ssao_shader, ssao_uniform, 4, 1, ssao_params);
GPU_shader_uniform_vector(ssao_shader, ssao_color_uniform, 4, 1, fx_ssao->color);
GPU_shader_uniform_vector(ssao_shader, viewvecs_uniform, 4, 3, viewvecs[0]);
- GPU_shader_uniform_vector(ssao_shader, ssao_sample_params_uniform, 4, 1, sample_params);
+ GPU_shader_uniform_vector(ssao_shader, ssao_sample_params_uniform, 3, 1, sample_params);
GPU_texture_bind(src, numslots++);
GPU_shader_uniform_texture(ssao_shader, color_uniform, src);
GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_depth_texture_mode(fx->depth_buffer, false, true);
+ GPU_texture_filter_mode(fx->depth_buffer, false, true);
GPU_shader_uniform_texture(ssao_shader, depth_uniform, fx->depth_buffer);
GPU_texture_bind(fx->jitter_buffer, numslots++);
GPU_shader_uniform_texture(ssao_shader, ssao_jitter_uniform, fx->jitter_buffer);
- GPU_texture_bind(fx->ssao_concentric_samples_tex, numslots++);
- GPU_shader_uniform_texture(ssao_shader, ssao_concentric_tex, fx->ssao_concentric_samples_tex);
+ GPU_texture_bind(fx->ssao_spiral_samples_tex, numslots++);
+ GPU_shader_uniform_texture(ssao_shader, ssao_concentric_tex, fx->ssao_spiral_samples_tex);
/* draw */
gpu_fx_bind_render_target(&passes_left, fx, ofs, target);
@@ -683,10 +761,10 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
/* disable bindings */
GPU_texture_unbind(src);
- GPU_depth_texture_mode(fx->depth_buffer, true, false);
+ GPU_texture_filter_mode(fx->depth_buffer, true, false);
GPU_texture_unbind(fx->depth_buffer);
GPU_texture_unbind(fx->jitter_buffer);
- GPU_texture_unbind(fx->ssao_concentric_samples_tex);
+ GPU_texture_unbind(fx->ssao_spiral_samples_tex);
/* may not be attached, in that case this just returns */
if (target) {
@@ -708,7 +786,6 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
/* second pass, dof */
if (fx->effects & GPU_FX_FLAG_DOF) {
const GPUDOFSettings *fx_dof = fx->settings.dof;
- GPUShader *dof_shader_pass1, *dof_shader_pass2, *dof_shader_pass3, *dof_shader_pass4, *dof_shader_pass5;
float dof_params[4];
float scale = scene->unit.system ? scene->unit.scale_length : 1.0f;
/* this is factor that converts to the scene scale. focal length and sensor are expressed in mm
@@ -721,248 +798,467 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
dof_params[0] = aperture * fabsf(scale_camera * fx_dof->focal_length / ((fx_dof->focus_distance / scale) - scale_camera * fx_dof->focal_length));
dof_params[1] = fx_dof->focus_distance / scale;
dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor);
- dof_params[3] = 0.0f;
-
- /* DOF effect has many passes but most of them are performed on a texture whose dimensions are 4 times less than the original
- * (16 times lower than original screen resolution). Technique used is not very exact but should be fast enough and is based
- * on "Practical Post-Process Depth of Field" see http://http.developer.nvidia.com/GPUGems3/gpugems3_ch28.html */
- dof_shader_pass1 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE, is_persp);
- dof_shader_pass2 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO, is_persp);
- dof_shader_pass3 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE, is_persp);
- dof_shader_pass4 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR, is_persp);
- dof_shader_pass5 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE, is_persp);
-
- /* error occured, restore framebuffers and return */
- if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3 && dof_shader_pass4 && dof_shader_pass5)) {
- GPU_framebuffer_texture_unbind(fx->gbuffer, NULL);
- GPU_framebuffer_restore();
- return false;
- }
+ dof_params[3] = fx_dof->num_blades;
- /* pass first, first level of blur in low res buffer */
- {
- int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform;
- int viewvecs_uniform;
+ if (fx->dof_high_quality) {
+ GPUShader *dof_shader_pass1, *dof_shader_pass2, *dof_shader_pass3;
- float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]};
+ /* custom shaders close to the effect described in CryEngine 3 Graphics Gems */
+ dof_shader_pass1 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE, is_persp);
+ dof_shader_pass2 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO, is_persp);
+ dof_shader_pass3 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE, is_persp);
- dof_uniform = GPU_shader_get_uniform(dof_shader_pass1, "dof_params");
- invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim");
- color_uniform = GPU_shader_get_uniform(dof_shader_pass1, "colorbuffer");
- depth_uniform = GPU_shader_get_uniform(dof_shader_pass1, "depthbuffer");
- viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass1, "viewvecs");
+ /* error occured, restore framebuffers and return */
+ if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3)) {
+ GPU_framebuffer_texture_unbind(fx->gbuffer, NULL);
+ GPU_framebuffer_restore();
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- GPU_shader_bind(dof_shader_pass1);
+ GPU_shader_unbind();
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ return false;
+ }
- GPU_shader_uniform_vector(dof_shader_pass1, dof_uniform, 4, 1, dof_params);
- GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass1, viewvecs_uniform, 4, 3, viewvecs[0]);
+ /* pass first, downsample the color buffer to near/far targets and calculate coc texture */
+ {
+ int depth_uniform, dof_uniform;
+ int viewvecs_uniform;
+ int invrendertargetdim_uniform, color_uniform;
+
+ float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h};
+
+ invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim");
+ color_uniform = GPU_shader_get_uniform(dof_shader_pass1, "colorbuffer");
+ dof_uniform = GPU_shader_get_uniform(dof_shader_pass1, "dof_params");
+ invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim");
+ depth_uniform = GPU_shader_get_uniform(dof_shader_pass1, "depthbuffer");
+ viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass1, "viewvecs");
+
+ GPU_shader_bind(dof_shader_pass1);
+
+ GPU_shader_uniform_vector(dof_shader_pass1, dof_uniform, 4, 1, dof_params);
+ GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass1, viewvecs_uniform, 4, 3, viewvecs[0]);
+
+ GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+
+ GPU_texture_bind(fx->depth_buffer, numslots++);
+ GPU_texture_filter_mode(fx->depth_buffer, false, false);
+ GPU_shader_uniform_texture(dof_shader_pass1, depth_uniform, fx->depth_buffer);
+
+ GPU_texture_bind(src, numslots++);
+ /* disable filtering for the texture so custom downsample can do the right thing */
+ GPU_texture_filter_mode(src, false, false);
+ GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, src);
+
+ /* target is the downsampled coc buffer */
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_near, 0, NULL);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_far, 1, NULL);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_nearfar_coc, 2, NULL);
+ /* binding takes care of setting the viewport to the downsampled size */
+ GPU_framebuffer_slots_bind(fx->gbuffer, 0);
+
+ GPU_framebuffer_check_valid(fx->gbuffer, NULL);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ /* disable bindings */
+ GPU_texture_filter_mode(src, false, true);
+ GPU_texture_unbind(src);
+ GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_unbind(fx->depth_buffer);
+
+ GPU_framebuffer_texture_detach(fx->dof_half_downsampled_near);
+ GPU_framebuffer_texture_detach(fx->dof_half_downsampled_far);
+ GPU_framebuffer_texture_detach(fx->dof_nearfar_coc);
+ GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_half_downsampled_near);
+
+ numslots = 0;
+ }
- GPU_texture_bind(src, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass1, color_uniform, src);
+ /* second pass, shoot quads for every pixel in the downsampled buffers, scaling according
+ * to circle of confusion */
+ {
+ int rendertargetdim_uniform, coc_uniform, color_uniform, select_uniform, dof_uniform;
+ int rendertargetdim[2] = {fx->dof_downsampled_w, fx->dof_downsampled_h};
+ float selection[2] = {0.0f, 1.0f};
- GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_depth_texture_mode(fx->depth_buffer, false, true);
- GPU_shader_uniform_texture(dof_shader_pass1, depth_uniform, fx->depth_buffer);
+ rendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass2, "rendertargetdim");
- /* target is the downsampled coc buffer */
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL);
- /* binding takes care of setting the viewport to the downsampled size */
- GPU_texture_bind_as_framebuffer(fx->dof_near_coc_buffer);
+ color_uniform = GPU_shader_get_uniform(dof_shader_pass2, "colorbuffer");
+ coc_uniform = GPU_shader_get_uniform(dof_shader_pass2, "cocbuffer");
+ select_uniform = GPU_shader_get_uniform(dof_shader_pass2, "layerselection");
+ dof_uniform = GPU_shader_get_uniform(dof_shader_pass2, "dof_params");
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- /* disable bindings */
- GPU_texture_unbind(src);
- GPU_depth_texture_mode(fx->depth_buffer, true, false);
- GPU_texture_unbind(fx->depth_buffer);
+ GPU_shader_bind(dof_shader_pass2);
- GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer);
- numslots = 0;
+ GPU_shader_uniform_vector(dof_shader_pass2, dof_uniform, 4, 1, dof_params);
+ GPU_shader_uniform_vector_int(dof_shader_pass2, rendertargetdim_uniform, 2, 1, rendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass2, select_uniform, 2, 1, selection);
+
+ GPU_texture_bind(fx->dof_nearfar_coc, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass2, coc_uniform, fx->dof_nearfar_coc);
+
+ GPU_texture_bind(fx->dof_half_downsampled_far, numslots++);
+ GPU_texture_bind(fx->dof_half_downsampled_near, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_half_downsampled_far);
+ GPU_texture_filter_mode(fx->dof_half_downsampled_far, false, false);
+
+ /* target is the downsampled coc buffer */
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0, NULL);
+ GPU_texture_bind_as_framebuffer(fx->dof_far_blur);
+
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE);
+ /* have to clear the buffer unfortunately */
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */
+ glDrawArraysInstancedARB(GL_POINTS, 0, 1, fx->dof_downsampled_w * fx->dof_downsampled_h);
+
+ GPU_texture_unbind(fx->dof_half_downsampled_far);
+ GPU_framebuffer_texture_detach(fx->dof_far_blur);
+
+ GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_half_downsampled_near);
+ GPU_texture_filter_mode(fx->dof_half_downsampled_near, false, false);
+
+ selection[0] = 1.0f;
+ selection[1] = 0.0f;
+
+ GPU_shader_uniform_vector(dof_shader_pass2, select_uniform, 2, 1, selection);
+
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0, NULL);
+ /* have to clear the buffer unfortunately */
+ glClear(GL_COLOR_BUFFER_BIT);
+ /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */
+ glDrawArraysInstancedARB(GL_POINTS, 0, 1, fx->dof_downsampled_w * fx->dof_downsampled_h);
+
+ /* disable bindings */
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_BLEND);
+
+ GPU_framebuffer_texture_detach(fx->dof_near_blur);
+
+ GPU_texture_unbind(fx->dof_half_downsampled_near);
+ GPU_texture_unbind(fx->dof_nearfar_coc);
+
+ GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_far_blur);
+ }
+
+ /* third pass, accumulate the near/far blur fields */
+ {
+ int invrendertargetdim_uniform, near_uniform, color_uniform;
+ int dof_uniform, far_uniform, viewvecs_uniform, depth_uniform;
+
+ float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h};
+
+ dof_uniform = GPU_shader_get_uniform(dof_shader_pass3, "dof_params");
+ invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass3, "invrendertargetdim");
+ color_uniform = GPU_shader_get_uniform(dof_shader_pass3, "colorbuffer");
+ far_uniform = GPU_shader_get_uniform(dof_shader_pass3, "farbuffer");
+ near_uniform = GPU_shader_get_uniform(dof_shader_pass3, "nearbuffer");
+ viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass3, "viewvecs");
+ depth_uniform = GPU_shader_get_uniform(dof_shader_pass3, "depthbuffer");
+
+ GPU_shader_bind(dof_shader_pass3);
+
+ GPU_shader_uniform_vector(dof_shader_pass3, dof_uniform, 4, 1, dof_params);
+
+ GPU_shader_uniform_vector(dof_shader_pass3, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass3, viewvecs_uniform, 4, 3, viewvecs[0]);
+
+ GPU_texture_bind(fx->dof_near_blur, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass3, near_uniform, fx->dof_near_blur);
+ GPU_texture_filter_mode(fx->dof_near_blur, false, true);
+
+ GPU_texture_bind(fx->dof_far_blur, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass3, far_uniform, fx->dof_far_blur);
+ GPU_texture_filter_mode(fx->dof_far_blur, false, true);
+
+ GPU_texture_bind(fx->depth_buffer, numslots++);
+ GPU_texture_filter_mode(fx->depth_buffer, false, false);
+ GPU_shader_uniform_texture(dof_shader_pass3, depth_uniform, fx->depth_buffer);
+
+ GPU_texture_bind(src, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass3, color_uniform, src);
+
+ /* if this is the last pass, prepare for rendering on the frambuffer */
+ gpu_fx_bind_render_target(&passes_left, fx, ofs, target);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ /* disable bindings */
+ GPU_texture_unbind(fx->dof_near_blur);
+ GPU_texture_unbind(fx->dof_far_blur);
+ GPU_texture_unbind(src);
+ GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_unbind(fx->depth_buffer);
+
+ /* may not be attached, in that case this just returns */
+ if (target) {
+ GPU_framebuffer_texture_detach(target);
+ if (ofs) {
+ GPU_offscreen_bind(ofs, false);
+ }
+ else {
+ GPU_framebuffer_restore();
+ }
+ }
+
+ numslots = 0;
+ }
}
+ else {
+ GPUShader *dof_shader_pass1, *dof_shader_pass2, *dof_shader_pass3, *dof_shader_pass4, *dof_shader_pass5;
+
+ /* DOF effect has many passes but most of them are performed on a texture whose dimensions are 4 times less than the original
+ * (16 times lower than original screen resolution). Technique used is not very exact but should be fast enough and is based
+ * on "Practical Post-Process Depth of Field" see http://http.developer.nvidia.com/GPUGems3/gpugems3_ch28.html */
+ dof_shader_pass1 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE, is_persp);
+ dof_shader_pass2 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO, is_persp);
+ dof_shader_pass3 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE, is_persp);
+ dof_shader_pass4 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR, is_persp);
+ dof_shader_pass5 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE, is_persp);
+
+ /* error occured, restore framebuffers and return */
+ if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3 && dof_shader_pass4 && dof_shader_pass5)) {
+ GPU_framebuffer_texture_unbind(fx->gbuffer, NULL);
+ GPU_framebuffer_restore();
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ GPU_shader_unbind();
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ return false;
+ }
- /* second pass, gaussian blur the downsampled image */
- {
- int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform;
- int viewvecs_uniform;
- float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer),
- 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)};
- float tmp = invrendertargetdim[0];
- invrendertargetdim[0] = 0.0f;
+ /* pass first, first level of blur in low res buffer */
+ {
+ int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform;
+ int viewvecs_uniform;
- dof_params[2] = GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer) / (scale_camera * fx_dof->sensor);
+ float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]};
- dof_uniform = GPU_shader_get_uniform(dof_shader_pass2, "dof_params");
- invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass2, "invrendertargetdim");
- color_uniform = GPU_shader_get_uniform(dof_shader_pass2, "colorbuffer");
- depth_uniform = GPU_shader_get_uniform(dof_shader_pass2, "depthbuffer");
- viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass2, "viewvecs");
+ dof_uniform = GPU_shader_get_uniform(dof_shader_pass1, "dof_params");
+ invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim");
+ color_uniform = GPU_shader_get_uniform(dof_shader_pass1, "colorbuffer");
+ depth_uniform = GPU_shader_get_uniform(dof_shader_pass1, "depthbuffer");
+ viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass1, "viewvecs");
- /* Blurring vertically */
- GPU_shader_bind(dof_shader_pass2);
+ GPU_shader_bind(dof_shader_pass1);
- GPU_shader_uniform_vector(dof_shader_pass2, dof_uniform, 4, 1, dof_params);
- GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass2, viewvecs_uniform, 4, 3, viewvecs[0]);
+ GPU_shader_uniform_vector(dof_shader_pass1, dof_uniform, 4, 1, dof_params);
+ GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass1, viewvecs_uniform, 4, 3, viewvecs[0]);
- GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_depth_texture_mode(fx->depth_buffer, false, true);
- GPU_shader_uniform_texture(dof_shader_pass2, depth_uniform, fx->depth_buffer);
+ GPU_texture_bind(src, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass1, color_uniform, src);
- GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_buffer);
+ GPU_texture_bind(fx->depth_buffer, numslots++);
+ GPU_texture_filter_mode(fx->depth_buffer, false, true);
+ GPU_shader_uniform_texture(dof_shader_pass1, depth_uniform, fx->depth_buffer);
- /* use final buffer as a temp here */
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL);
+ /* target is the downsampled coc buffer */
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL);
+ /* binding takes care of setting the viewport to the downsampled size */
+ GPU_texture_bind_as_framebuffer(fx->dof_near_coc_buffer);
- /* Drawing quad */
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ /* disable bindings */
+ GPU_texture_unbind(src);
+ GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_unbind(fx->depth_buffer);
- /* *unbind/detach */
- GPU_texture_unbind(fx->dof_near_coc_buffer);
- GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer);
+ GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer);
+ numslots = 0;
+ }
- /* Blurring horizontally */
- invrendertargetdim[0] = tmp;
- invrendertargetdim[1] = 0.0f;
- GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ /* second pass, gaussian blur the downsampled image */
+ {
+ int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform;
+ int viewvecs_uniform;
+ float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer),
+ 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)};
+ float tmp = invrendertargetdim[0];
+ invrendertargetdim[0] = 0.0f;
- GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_final_buffer);
+ dof_params[2] = GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer) / (scale_camera * fx_dof->sensor);
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0, NULL);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ dof_uniform = GPU_shader_get_uniform(dof_shader_pass2, "dof_params");
+ invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass2, "invrendertargetdim");
+ color_uniform = GPU_shader_get_uniform(dof_shader_pass2, "colorbuffer");
+ depth_uniform = GPU_shader_get_uniform(dof_shader_pass2, "depthbuffer");
+ viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass2, "viewvecs");
- /* *unbind/detach */
- GPU_depth_texture_mode(fx->depth_buffer, true, false);
- GPU_texture_unbind(fx->depth_buffer);
+ /* Blurring vertically */
+ GPU_shader_bind(dof_shader_pass2);
- GPU_texture_unbind(fx->dof_near_coc_final_buffer);
- GPU_framebuffer_texture_detach(fx->dof_near_coc_blurred_buffer);
+ GPU_shader_uniform_vector(dof_shader_pass2, dof_uniform, 4, 1, dof_params);
+ GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass2, viewvecs_uniform, 4, 3, viewvecs[0]);
- dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor);
+ GPU_texture_bind(fx->depth_buffer, numslots++);
+ GPU_texture_filter_mode(fx->depth_buffer, false, true);
+ GPU_shader_uniform_texture(dof_shader_pass2, depth_uniform, fx->depth_buffer);
- numslots = 0;
- }
+ GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_buffer);
- /* third pass, calculate near coc */
- {
- int near_coc_downsampled, near_coc_blurred;
+ /* use final buffer as a temp here */
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL);
- near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass3, "colorbuffer");
- near_coc_blurred = GPU_shader_get_uniform(dof_shader_pass3, "blurredcolorbuffer");
+ /* Drawing quad */
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- GPU_shader_bind(dof_shader_pass3);
+ /* *unbind/detach */
+ GPU_texture_unbind(fx->dof_near_coc_buffer);
+ GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer);
- GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass3, near_coc_downsampled, fx->dof_near_coc_buffer);
+ /* Blurring horizontally */
+ invrendertargetdim[0] = tmp;
+ invrendertargetdim[1] = 0.0f;
+ GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass3, near_coc_blurred, fx->dof_near_coc_blurred_buffer);
+ GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_final_buffer);
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0, NULL);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- /* disable bindings */
- GPU_texture_unbind(fx->dof_near_coc_buffer);
- GPU_texture_unbind(fx->dof_near_coc_blurred_buffer);
+ /* *unbind/detach */
+ GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_unbind(fx->depth_buffer);
- /* unbinding here restores the size to the original */
- GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer);
+ GPU_texture_unbind(fx->dof_near_coc_final_buffer);
+ GPU_framebuffer_texture_detach(fx->dof_near_coc_blurred_buffer);
- numslots = 0;
- }
+ dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor);
- /* fourth pass blur final coc once to eliminate discontinuities */
- {
- int near_coc_downsampled;
- int invrendertargetdim_uniform;
- float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer),
- 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)};
+ numslots = 0;
+ }
- near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass4, "colorbuffer");
- invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass4, "invrendertargetdim");
+ /* third pass, calculate near coc */
+ {
+ int near_coc_downsampled, near_coc_blurred;
- GPU_shader_bind(dof_shader_pass4);
+ near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass3, "colorbuffer");
+ near_coc_blurred = GPU_shader_get_uniform(dof_shader_pass3, "blurredcolorbuffer");
- GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass4, near_coc_downsampled, fx->dof_near_coc_final_buffer);
- GPU_shader_uniform_vector(dof_shader_pass4, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_bind(dof_shader_pass3);
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL);
+ GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass3, near_coc_downsampled, fx->dof_near_coc_buffer);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- /* disable bindings */
- GPU_texture_unbind(fx->dof_near_coc_final_buffer);
+ GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass3, near_coc_blurred, fx->dof_near_coc_blurred_buffer);
- /* unbinding here restores the size to the original */
- GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_near_coc_buffer);
- GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL);
- numslots = 0;
- }
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ /* disable bindings */
+ GPU_texture_unbind(fx->dof_near_coc_buffer);
+ GPU_texture_unbind(fx->dof_near_coc_blurred_buffer);
- /* final pass, merge blurred layers according to final calculated coc */
- {
- int medium_blurred_uniform, high_blurred_uniform, original_uniform, depth_uniform, dof_uniform;
- int invrendertargetdim_uniform, viewvecs_uniform;
- float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]};
+ /* unbinding here restores the size to the original */
+ GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer);
- medium_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "mblurredcolorbuffer");
- high_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "blurredcolorbuffer");
- dof_uniform = GPU_shader_get_uniform(dof_shader_pass5, "dof_params");
- invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass5, "invrendertargetdim");
- original_uniform = GPU_shader_get_uniform(dof_shader_pass5, "colorbuffer");
- depth_uniform = GPU_shader_get_uniform(dof_shader_pass5, "depthbuffer");
- viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass5, "viewvecs");
+ numslots = 0;
+ }
- GPU_shader_bind(dof_shader_pass5);
+ /* fourth pass blur final coc once to eliminate discontinuities */
+ {
+ int near_coc_downsampled;
+ int invrendertargetdim_uniform;
+ float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer),
+ 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)};
- GPU_shader_uniform_vector(dof_shader_pass5, dof_uniform, 4, 1, dof_params);
- GPU_shader_uniform_vector(dof_shader_pass5, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass5, viewvecs_uniform, 4, 3, viewvecs[0]);
+ near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass4, "colorbuffer");
+ invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass4, "invrendertargetdim");
- GPU_texture_bind(src, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass5, original_uniform, src);
+ GPU_shader_bind(dof_shader_pass4);
- GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass5, high_blurred_uniform, fx->dof_near_coc_blurred_buffer);
+ GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass4, near_coc_downsampled, fx->dof_near_coc_final_buffer);
+ GPU_shader_uniform_vector(dof_shader_pass4, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass5, medium_blurred_uniform, fx->dof_near_coc_buffer);
+ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL);
- GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_depth_texture_mode(fx->depth_buffer, false, true);
- GPU_shader_uniform_texture(dof_shader_pass5, depth_uniform, fx->depth_buffer);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ /* disable bindings */
+ GPU_texture_unbind(fx->dof_near_coc_final_buffer);
- /* if this is the last pass, prepare for rendering on the frambuffer */
- gpu_fx_bind_render_target(&passes_left, fx, ofs, target);
+ /* unbinding here restores the size to the original */
+ GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_near_coc_buffer);
+ GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- /* disable bindings */
- GPU_texture_unbind(fx->dof_near_coc_buffer);
- GPU_texture_unbind(fx->dof_near_coc_blurred_buffer);
- GPU_texture_unbind(src);
- GPU_depth_texture_mode(fx->depth_buffer, true, false);
- GPU_texture_unbind(fx->depth_buffer);
+ numslots = 0;
+ }
- /* may not be attached, in that case this just returns */
- if (target) {
- GPU_framebuffer_texture_detach(target);
- if (ofs) {
- GPU_offscreen_bind(ofs, false);
- }
- else {
- GPU_framebuffer_restore();
+ /* final pass, merge blurred layers according to final calculated coc */
+ {
+ int medium_blurred_uniform, high_blurred_uniform, original_uniform, depth_uniform, dof_uniform;
+ int invrendertargetdim_uniform, viewvecs_uniform;
+ float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]};
+
+ medium_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "mblurredcolorbuffer");
+ high_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "blurredcolorbuffer");
+ dof_uniform = GPU_shader_get_uniform(dof_shader_pass5, "dof_params");
+ invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass5, "invrendertargetdim");
+ original_uniform = GPU_shader_get_uniform(dof_shader_pass5, "colorbuffer");
+ depth_uniform = GPU_shader_get_uniform(dof_shader_pass5, "depthbuffer");
+ viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass5, "viewvecs");
+
+ GPU_shader_bind(dof_shader_pass5);
+
+ GPU_shader_uniform_vector(dof_shader_pass5, dof_uniform, 4, 1, dof_params);
+ GPU_shader_uniform_vector(dof_shader_pass5, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass5, viewvecs_uniform, 4, 3, viewvecs[0]);
+
+ GPU_texture_bind(src, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass5, original_uniform, src);
+
+ GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass5, high_blurred_uniform, fx->dof_near_coc_blurred_buffer);
+
+ GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
+ GPU_shader_uniform_texture(dof_shader_pass5, medium_blurred_uniform, fx->dof_near_coc_buffer);
+
+ GPU_texture_bind(fx->depth_buffer, numslots++);
+ GPU_texture_filter_mode(fx->depth_buffer, false, true);
+ GPU_shader_uniform_texture(dof_shader_pass5, depth_uniform, fx->depth_buffer);
+
+ /* if this is the last pass, prepare for rendering on the frambuffer */
+ gpu_fx_bind_render_target(&passes_left, fx, ofs, target);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ /* disable bindings */
+ GPU_texture_unbind(fx->dof_near_coc_buffer);
+ GPU_texture_unbind(fx->dof_near_coc_blurred_buffer);
+ GPU_texture_unbind(src);
+ GPU_texture_filter_mode(fx->depth_buffer, true, false);
+ GPU_texture_unbind(fx->depth_buffer);
+
+ /* may not be attached, in that case this just returns */
+ if (target) {
+ GPU_framebuffer_texture_detach(target);
+ if (ofs) {
+ GPU_offscreen_bind(ofs, false);
+ }
+ else {
+ GPU_framebuffer_restore();
+ }
}
- }
- SWAP(GPUTexture *, target, src);
- numslots = 0;
+ SWAP(GPUTexture *, target, src);
+ numslots = 0;
+ }
}
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
GPU_shader_unbind();
@@ -975,6 +1271,7 @@ void GPU_fx_compositor_init_dof_settings(GPUDOFSettings *fx_dof)
fx_dof->focal_length = 1.0f;
fx_dof->focus_distance = 1.0f;
fx_dof->sensor = 1.0f;
+ fx_dof->num_blades = 6;
}
void GPU_fx_compositor_init_ssao_settings(GPUSSAOSettings *fx_ssao)
diff --git a/source/blender/gpu/intern/gpu_debug.c b/source/blender/gpu/intern/gpu_debug.c
index 21257a9c734..7bcc51aef31 100644
--- a/source/blender/gpu/intern/gpu_debug.c
+++ b/source/blender/gpu/intern/gpu_debug.c
@@ -25,7 +25,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file source/blender/gpu/GPU_debug.h
+/** \file source/blender/gpu/intern/gpu_debug.c
* \ingroup gpu
*/
@@ -45,7 +45,7 @@
static const char* gpu_gl_error_symbol(GLenum err)
{
- switch(err) {
+ switch (err) {
CASE_CODE_RETURN_STR(GL_NO_ERROR)
CASE_CODE_RETURN_STR(GL_INVALID_ENUM)
CASE_CODE_RETURN_STR(GL_INVALID_VALUE)
@@ -109,7 +109,7 @@ static bool gpu_report_gl_errors(const char *file, int line, const char *str)
const char* gpuErrorString(GLenum err)
{
- switch(err) {
+ switch (err) {
case GL_NO_ERROR:
return "No Error";
@@ -356,6 +356,7 @@ void gpu_assert_no_gl_errors(const char* file, int line, const char* str)
GLboolean gl_ok = gpu_report_gl_errors(file, line, str);
BLI_assert(gl_ok);
+ (void) gl_ok;
}
}
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 3ed7253d309..a24067fc381 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -88,7 +88,7 @@ extern Material defmaterial; /* from material.c */
static void gpu_mcol(unsigned int ucol)
{
/* mcol order is swapped */
- const char *cp= (char *)&ucol;
+ const char *cp = (char *)&ucol;
glColor3ub(cp[3], cp[2], cp[1]);
}
@@ -96,7 +96,7 @@ void GPU_render_text(MTFace *tface, int mode,
const char *textstr, int textlen, unsigned int *col,
float *v1, float *v2, float *v3, float *v4, int glattrib)
{
- if ((mode & GEMAT_TEXT) && (textlen>0) && tface->tpage) {
+ if ((mode & GEMAT_TEXT) && (textlen > 0) && tface->tpage) {
Image* ima = (Image *)tface->tpage;
ImBuf *first_ibuf;
const size_t textlen_st = textlen;
@@ -105,7 +105,7 @@ void GPU_render_text(MTFace *tface, int mode,
float advance_tab;
/* multiline */
- float line_start= 0.0f, line_height;
+ float line_start = 0.0f, line_height;
if (v4)
line_height = max_ffff(v1[1], v2[1], v3[1], v4[2]) - min_ffff(v1[1], v2[1], v3[1], v4[2]);
@@ -117,7 +117,7 @@ void GPU_render_text(MTFace *tface, int mode,
/* color has been set */
if (tface->mode & TF_OBCOL)
- col= NULL;
+ col = NULL;
else if (!col)
glColor3f(1.0f, 1.0f, 1.0f);
@@ -128,23 +128,23 @@ void GPU_render_text(MTFace *tface, int mode,
matrixGlyph(first_ibuf, ' ', &centerx, &centery,
&sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
- advance_tab= advance * 4; /* tab width could also be an option */
+ advance_tab = advance * 4; /* tab width could also be an option */
for (index = 0; index < textlen_st; ) {
unsigned int character;
float uv[4][2];
- // lets calculate offset stuff
+ /* lets calculate offset stuff */
character = BLI_str_utf8_as_unicode_and_size_safe(textstr + index, &index);
- if (character=='\n') {
- glTranslatef(line_start, -line_height, 0.0);
+ if (character == '\n') {
+ glTranslatef(line_start, -line_height, 0.0f);
line_start = 0.0f;
continue;
}
- else if (character=='\t') {
- glTranslatef(advance_tab, 0.0, 0.0);
+ else if (character == '\t') {
+ glTranslatef(advance_tab, 0.0f, 0.0f);
line_start -= advance_tab; /* so we can go back to the start of the line */
continue;
@@ -154,8 +154,8 @@ void GPU_render_text(MTFace *tface, int mode,
character = '?';
}
- // space starts at offset 1
- // character = character - ' ' + 1;
+ /* space starts at offset 1 */
+ /* character = character - ' ' + 1; */
matrixGlyph(first_ibuf, character, & centerx, &centery,
&sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
@@ -193,7 +193,7 @@ void GPU_render_text(MTFace *tface, int mode,
}
glEnd();
- glTranslatef(advance, 0.0, 0.0);
+ glTranslatef(advance, 0.0f, 0.0f);
line_start -= advance; /* so we can go back to the start of the line */
}
glPopMatrix();
@@ -239,14 +239,18 @@ static struct GPUTextureState {
int curtileYRep, tileYRep;
Image *ima, *curima;
- int domipmap, linearmipmap;
- int texpaint; /* store this so that new images created while texture painting won't be set to mipmapped */
+ /* also controls min/mag filtering */
+ bool domipmap;
+ /* only use when 'domipmap' is set */
+ bool linearmipmap;
+ /* store this so that new images created while texture painting won't be set to mipmapped */
+ bool texpaint;
int alphablend;
float anisotropic;
int gpu_mipmap;
MTFace *lasttface;
-} GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.f, 0, NULL};
+} GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.0f, 0, NULL};
/* Mipmap settings */
@@ -281,49 +285,53 @@ static void gpu_generate_mipmap(GLenum target)
glDisable(target);
}
-void GPU_set_mipmap(int mipmap)
+void GPU_set_mipmap(bool mipmap)
{
- if (GTS.domipmap != (mipmap != 0)) {
+ if (GTS.domipmap != mipmap) {
GPU_free_images();
- GTS.domipmap = mipmap != 0;
+ GTS.domipmap = mipmap;
}
}
-void GPU_set_linear_mipmap(int linear)
+void GPU_set_linear_mipmap(bool linear)
{
- if (GTS.linearmipmap != (linear != 0)) {
- GPU_free_images();
- GTS.linearmipmap = linear != 0;
+ if (GTS.linearmipmap != linear) {
+ GTS.linearmipmap = linear;
}
}
-int GPU_get_mipmap(void)
+bool GPU_get_mipmap(void)
{
return GTS.domipmap && !GTS.texpaint;
}
-int GPU_get_linear_mipmap(void)
+bool GPU_get_linear_mipmap(void)
{
return GTS.linearmipmap;
}
-static GLenum gpu_get_mipmap_filter(int mag)
+static GLenum gpu_get_mipmap_filter(bool mag)
{
/* linearmipmap is off by default *when mipmapping is off,
* use unfiltered display */
if (mag) {
- if (GTS.linearmipmap || GTS.domipmap)
+ if (GTS.domipmap)
return GL_LINEAR;
else
return GL_NEAREST;
}
else {
- if (GTS.linearmipmap)
- return GL_LINEAR_MIPMAP_LINEAR;
- else if (GTS.domipmap)
- return GL_LINEAR_MIPMAP_NEAREST;
- else
+ if (GTS.domipmap) {
+ if (GTS.linearmipmap) {
+ return GL_LINEAR_MIPMAP_LINEAR;
+ }
+ else {
+ return GL_LINEAR_MIPMAP_NEAREST;
+ }
+ }
+ else {
return GL_NEAREST;
+ }
}
}
@@ -353,41 +361,41 @@ static void gpu_make_repbind(Image *ima)
ImBuf *ibuf;
ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- if (ibuf==NULL)
+ if (ibuf == NULL)
return;
if (ima->repbind) {
glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
MEM_freeN(ima->repbind);
- ima->repbind= NULL;
+ ima->repbind = NULL;
ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
}
- ima->totbind= ima->xrep*ima->yrep;
+ ima->totbind = ima->xrep*ima->yrep;
if (ima->totbind>1)
- ima->repbind= MEM_callocN(sizeof(int)*ima->totbind, "repbind");
+ ima->repbind = MEM_callocN(sizeof(int) * ima->totbind, "repbind");
BKE_image_release_ibuf(ima, ibuf, NULL);
}
void GPU_clear_tpage(bool force)
{
- if (GTS.lasttface==NULL && !force)
+ if (GTS.lasttface == NULL && !force)
return;
- GTS.lasttface= NULL;
- GTS.curtile= 0;
- GTS.curima= NULL;
- if (GTS.curtilemode!=0) {
+ GTS.lasttface = NULL;
+ GTS.curtile = 0;
+ GTS.curima = NULL;
+ if (GTS.curtilemode != 0) {
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
}
- GTS.curtilemode= 0;
- GTS.curtileXRep=0;
- GTS.curtileYRep=0;
- GTS.alphablend= -1;
+ GTS.curtilemode = 0;
+ GTS.curtileXRep = 0;
+ GTS.curtileYRep = 0;
+ GTS.alphablend = -1;
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
@@ -403,7 +411,7 @@ static void gpu_set_alpha_blend(GPUBlendMode alphablend)
glDisable(GL_ALPHA_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
- else if (alphablend==GPU_BLEND_ADD) {
+ else if (alphablend == GPU_BLEND_ADD) {
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glDisable(GL_ALPHA_TEST);
@@ -429,7 +437,7 @@ static void gpu_set_alpha_blend(GPUBlendMode alphablend)
glAlphaFunc(GL_GREATER, U.glalphaclip);
}
}
- else if (alphablend==GPU_BLEND_CLIP) {
+ else if (alphablend == GPU_BLEND_CLIP) {
glDisable(GL_BLEND);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.5f);
@@ -443,7 +451,7 @@ static void gpu_verify_alpha_blend(int alphablend)
return;
gpu_set_alpha_blend(alphablend);
- GTS.alphablend= alphablend;
+ GTS.alphablend = alphablend;
}
static void gpu_verify_reflection(Image *ima)
@@ -467,9 +475,9 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
{
ImBuf *ibuf = NULL;
unsigned int *bind = NULL;
- int rectw, recth, tpx=0, tpy=0, y;
- unsigned int *tilerect= NULL, *rect= NULL;
- float *ftilerect= NULL, *frect = NULL;
+ int rectw, recth, tpx = 0, tpy = 0, y;
+ unsigned int *tilerect = NULL, *rect = NULL;
+ float *ftilerect = NULL, *frect = NULL;
float *srgb_frect = NULL;
short texwindx, texwindy, texwinsx, texwinsy;
/* flag to determine whether high resolution format is used */
@@ -477,15 +485,15 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
/* initialize tile mode and number of repeats */
GTS.ima = ima;
- GTS.tilemode= (ima && (ima->tpageflag & (IMA_TILES|IMA_TWINANIM)));
+ GTS.tilemode = (ima && (ima->tpageflag & (IMA_TILES|IMA_TWINANIM)));
GTS.tileXRep = 0;
GTS.tileYRep = 0;
/* setting current tile according to frame */
if (ima && (ima->tpageflag & IMA_TWINANIM))
- GTS.tile= ima->lastframe;
+ GTS.tile = ima->lastframe;
else
- GTS.tile= tftile;
+ GTS.tile = tftile;
GTS.tile = MAX2(0, GTS.tile);
@@ -503,26 +511,26 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
}
/* if tiling mode or repeat changed, change texture matrix to fit */
- if (GTS.tilemode!=GTS.curtilemode || GTS.curtileXRep!=GTS.tileXRep ||
+ if (GTS.tilemode != GTS.curtilemode || GTS.curtileXRep != GTS.tileXRep ||
GTS.curtileYRep != GTS.tileYRep)
{
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
if (ima && (ima->tpageflag & IMA_TILES))
- glScalef(ima->xrep, ima->yrep, 1.0);
+ glScalef(ima->xrep, ima->yrep, 1.0f);
glMatrixMode(GL_MODELVIEW);
}
/* check if we have a valid image */
- if (ima==NULL || ima->ok==0)
+ if (ima == NULL || ima->ok == 0)
return 0;
/* check if we have a valid image buffer */
- ibuf= BKE_image_acquire_ibuf(ima, iuser, NULL);
+ ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
- if (ibuf==NULL)
+ if (ibuf == NULL)
return 0;
if (ibuf->rect_float) {
@@ -552,59 +560,58 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
if (GTS.tilemode) {
/* tiled mode */
- if (ima->repbind==NULL) gpu_make_repbind(ima);
- if (GTS.tile>=ima->totbind) GTS.tile= 0;
+ if (ima->repbind == NULL) gpu_make_repbind(ima);
+ if (GTS.tile >= ima->totbind) GTS.tile = 0;
/* this happens when you change repeat buttons */
- if (ima->repbind) bind= &ima->repbind[GTS.tile];
- else bind= &ima->bindcode;
+ if (ima->repbind) bind = &ima->repbind[GTS.tile];
+ else bind = &ima->bindcode;
- if (*bind==0) {
-
- texwindx= ibuf->x/ima->xrep;
- texwindy= ibuf->y/ima->yrep;
+ if (*bind == 0) {
+ texwindx = ibuf->x / ima->xrep;
+ texwindy = ibuf->y / ima->yrep;
- if (GTS.tile>=ima->xrep*ima->yrep)
- GTS.tile= ima->xrep*ima->yrep-1;
+ if (GTS.tile >= ima->xrep * ima->yrep)
+ GTS.tile = ima->xrep * ima->yrep - 1;
- texwinsy= GTS.tile / ima->xrep;
- texwinsx= GTS.tile - texwinsy*ima->xrep;
+ texwinsy = GTS.tile / ima->xrep;
+ texwinsx = GTS.tile - texwinsy * ima->xrep;
- texwinsx*= texwindx;
- texwinsy*= texwindy;
+ texwinsx *= texwindx;
+ texwinsy *= texwindy;
- tpx= texwindx;
- tpy= texwindy;
+ tpx = texwindx;
+ tpy = texwindy;
if (use_high_bit_depth) {
if (do_color_management) {
- srgb_frect = MEM_mallocN(ibuf->x*ibuf->y*sizeof(float)*4, "floar_buf_col_cor");
+ srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(float) * 4, "floar_buf_col_cor");
IMB_buffer_float_from_float(srgb_frect, ibuf->rect_float,
ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, true,
ibuf->x, ibuf->y, ibuf->x, ibuf->x);
IMB_buffer_float_unpremultiply(srgb_frect, ibuf->x, ibuf->y);
/* clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images */
IMB_buffer_float_clamp(srgb_frect, ibuf->x, ibuf->y);
- frect= srgb_frect + texwinsy*ibuf->x + texwinsx;
+ frect = srgb_frect + texwinsy*ibuf->x + texwinsx;
}
else
- frect= ibuf->rect_float + texwinsy*ibuf->x + texwinsx;
+ frect = ibuf->rect_float + texwinsy*ibuf->x + texwinsx;
}
else
- rect= ibuf->rect + texwinsy*ibuf->x + texwinsx;
+ rect = ibuf->rect + texwinsy*ibuf->x + texwinsx;
}
}
else {
/* regular image mode */
bind= &ima->bindcode;
- if (*bind==0) {
- tpx= ibuf->x;
- tpy= ibuf->y;
- rect= ibuf->rect;
+ if (*bind == 0) {
+ tpx = ibuf->x;
+ tpy = ibuf->y;
+ rect = ibuf->rect;
if (use_high_bit_depth) {
if (do_color_management) {
- frect = srgb_frect = MEM_mallocN(ibuf->x*ibuf->y*sizeof(*srgb_frect)*4, "floar_buf_col_cor");
+ frect = srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(*srgb_frect) * 4, "floar_buf_col_cor");
IMB_buffer_float_from_float(srgb_frect, ibuf->rect_float,
ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, true,
ibuf->x, ibuf->y, ibuf->x, ibuf->x);
@@ -613,7 +620,7 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
IMB_buffer_float_clamp(srgb_frect, ibuf->x, ibuf->y);
}
else
- frect= ibuf->rect_float;
+ frect = ibuf->rect_float;
}
}
}
@@ -633,30 +640,30 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
if (use_high_bit_depth) {
float *frectrow, *ftilerectrow;
- ftilerect= MEM_mallocN(rectw*recth*sizeof(*ftilerect), "tilerect");
+ ftilerect = MEM_mallocN(rectw*recth*sizeof(*ftilerect), "tilerect");
- for (y=0; y<recth; y++) {
- frectrow= &frect[y*ibuf->x];
- ftilerectrow= &ftilerect[y*rectw];
+ for (y = 0; y < recth; y++) {
+ frectrow = &frect[y * ibuf->x];
+ ftilerectrow = &ftilerect[y * rectw];
- memcpy(ftilerectrow, frectrow, tpx*sizeof(*frectrow));
+ memcpy(ftilerectrow, frectrow, tpx * sizeof(*frectrow));
}
- frect= ftilerect;
+ frect = ftilerect;
}
else {
unsigned int *rectrow, *tilerectrow;
- tilerect= MEM_mallocN(rectw*recth*sizeof(*tilerect), "tilerect");
+ tilerect = MEM_mallocN(rectw*recth*sizeof(*tilerect), "tilerect");
- for (y=0; y<recth; y++) {
- rectrow= &rect[y*ibuf->x];
- tilerectrow= &tilerect[y*rectw];
+ for (y = 0; y < recth; y++) {
+ rectrow = &rect[y * ibuf->x];
+ tilerectrow = &tilerect[y * rectw];
- memcpy(tilerectrow, rectrow, tpx*sizeof(*rectrow));
+ memcpy(tilerectrow, rectrow, tpx * sizeof(*rectrow));
}
- rect= tilerect;
+ rect = tilerect;
}
}
@@ -723,43 +730,56 @@ void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int
glGenTextures(1, (GLuint *)bind);
glBindTexture(GL_TEXTURE_2D, *bind);
- if (!(GPU_get_mipmap() && mipmap)) {
- if (use_high_bit_depth) {
- if (GLEW_ARB_texture_float)
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
- else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
- }
+ if (use_high_bit_depth) {
+ if (GLEW_ARB_texture_float)
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
}
- else {
- if (GTS.gpu_mipmap) {
- if (use_high_bit_depth) {
- if (GLEW_ARB_texture_float)
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
- else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
- }
- else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
+
+ if (GPU_get_mipmap() && mipmap) {
+ if (GTS.gpu_mipmap) {
gpu_generate_mipmap(GL_TEXTURE_2D);
}
else {
- if (use_high_bit_depth)
- gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA16, rectw, recth, GL_RGBA, GL_FLOAT, frect);
- else
- gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ int i;
+
+ if (!ibuf) {
+ if (use_high_bit_depth) {
+ ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy);
+ }
+ else {
+ ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy);
+ }
+ }
+
+ IMB_makemipmap(ibuf, true);
+
+ for (i = 1; i < ibuf->miptot; i++) {
+ ImBuf *mip = ibuf->mipmap[i - 1];
+ if (use_high_bit_depth) {
+ if (GLEW_ARB_texture_float)
+ glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16F, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float);
+ else
+ glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float);
+ }
+ else {
+ glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect);
+ }
+ }
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
if (ima)
ima->tpageflag |= IMA_MIPMAP_COMPLETE;
}
+ else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
if (GLEW_EXT_texture_filter_anisotropic)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic());
@@ -812,7 +832,7 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic());
blocksize = (ibuf->dds_data.fourcc == FOURCC_DXT1) ? 8 : 16;
- for (i=0; i<ibuf->dds_data.nummipmaps && (width||height); ++i) {
+ for (i = 0; i < ibuf->dds_data.nummipmaps && (width||height); ++i) {
if (width == 0)
width = 1;
if (height == 0)
@@ -829,7 +849,7 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf)
}
/* set number of mipmap levels we have, needed in case they don't go down to 1x1 */
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i-1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i - 1);
return true;
#else
@@ -875,21 +895,21 @@ int GPU_set_tpage(MTFace *tface, int mipmap, int alphablend)
Image *ima;
/* check if we need to clear the state */
- if (tface==NULL) {
+ if (tface == NULL) {
GPU_clear_tpage(false);
return 0;
}
- ima= tface->tpage;
- GTS.lasttface= tface;
+ ima = tface->tpage;
+ GTS.lasttface = tface;
gpu_verify_alpha_blend(alphablend);
gpu_verify_reflection(ima);
if (GPU_verify_image(ima, NULL, tface->tile, 1, mipmap, false)) {
- GTS.curtile= GTS.tile;
- GTS.curima= GTS.ima;
- GTS.curtilemode= GTS.tilemode;
+ GTS.curtile = GTS.tile;
+ GTS.curima = GTS.ima;
+ GTS.curtilemode = GTS.tilemode;
GTS.curtileXRep = GTS.tileXRep;
GTS.curtileYRep = GTS.tileYRep;
@@ -898,9 +918,9 @@ int GPU_set_tpage(MTFace *tface, int mipmap, int alphablend)
else {
glDisable(GL_TEXTURE_2D);
- GTS.curtile= 0;
- GTS.curima= NULL;
- GTS.curtilemode= 0;
+ GTS.curtile = 0;
+ GTS.curima = NULL;
+ GTS.curtilemode = 0;
GTS.curtileXRep = 0;
GTS.curtileYRep = 0;
@@ -919,9 +939,9 @@ int GPU_set_tpage(MTFace *tface, int mipmap, int alphablend)
* temporary disabling/enabling mipmapping on all images for quick texture
* updates with glTexSubImage2D. images that didn't change don't have to be
* re-uploaded to OpenGL */
-void GPU_paint_set_mipmap(int mipmap)
+void GPU_paint_set_mipmap(bool mipmap)
{
- Image* ima;
+ Image *ima;
if (!GTS.domipmap)
return;
@@ -929,7 +949,7 @@ void GPU_paint_set_mipmap(int mipmap)
GTS.texpaint = !mipmap;
if (mipmap) {
- for (ima=G.main->image.first; ima; ima=ima->id.next) {
+ for (ima = G.main->image.first; ima; ima = ima->id.next) {
if (ima->bindcode) {
if (ima->tpageflag & IMA_MIPMAP_COMPLETE) {
glBindTexture(GL_TEXTURE_2D, ima->bindcode);
@@ -945,7 +965,7 @@ void GPU_paint_set_mipmap(int mipmap)
}
else {
- for (ima=G.main->image.first; ima; ima=ima->id.next) {
+ for (ima = G.main->image.first; ima; ima = ima->id.next) {
if (ima->bindcode) {
glBindTexture(GL_TEXTURE_2D, ima->bindcode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -1028,11 +1048,11 @@ static bool GPU_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x,
return false;
}
-void GPU_paint_update_image(Image *ima, int x, int y, int w, int h)
+void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
{
ImBuf *ibuf;
- ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
if (ima->repbind || (GPU_get_mipmap() && !GTS.gpu_mipmap) || !ima->bindcode || !ibuf ||
(w == 0) || (h == 0))
@@ -1058,8 +1078,7 @@ void GPU_paint_update_image(Image *ima, int x, int y, int w, int h)
}
glBindTexture(GL_TEXTURE_2D, ima->bindcode);
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
- GL_FLOAT, buffer);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, buffer);
MEM_freeN(buffer);
@@ -1114,16 +1133,16 @@ void GPU_update_images_framechange(void)
{
Image *ima;
- for (ima=G.main->image.first; ima; ima=ima->id.next) {
+ for (ima = G.main->image.first; ima; ima = ima->id.next) {
if (ima->tpageflag & IMA_TWINANIM) {
- if (ima->twend >= ima->xrep*ima->yrep)
- ima->twend= ima->xrep*ima->yrep-1;
+ if (ima->twend >= ima->xrep * ima->yrep)
+ ima->twend = ima->xrep * ima->yrep - 1;
/* check: is bindcode not in the array? free. (to do) */
ima->lastframe++;
if (ima->lastframe > ima->twend)
- ima->lastframe= ima->twsta;
+ ima->lastframe = ima->twsta;
}
}
}
@@ -1131,33 +1150,33 @@ void GPU_update_images_framechange(void)
int GPU_update_image_time(Image *ima, double time)
{
int inc = 0;
- float diff;
+ float diff;
int newframe;
if (!ima)
return 0;
- if (ima->lastupdate<0)
+ if (ima->lastupdate < 0)
ima->lastupdate = 0;
if (ima->lastupdate > (float)time)
- ima->lastupdate=(float)time;
+ ima->lastupdate = (float)time;
if (ima->tpageflag & IMA_TWINANIM) {
- if (ima->twend >= ima->xrep*ima->yrep) ima->twend= ima->xrep*ima->yrep-1;
+ if (ima->twend >= ima->xrep * ima->yrep) ima->twend = ima->xrep * ima->yrep - 1;
/* check: is the bindcode not in the array? Then free. (still to do) */
diff = (float)((float)time - ima->lastupdate);
- inc = (int)(diff*(float)ima->animspeed);
+ inc = (int)(diff * (float)ima->animspeed);
- ima->lastupdate+=((float)inc/(float)ima->animspeed);
+ ima->lastupdate += ((float)inc / (float)ima->animspeed);
- newframe = ima->lastframe+inc;
+ newframe = ima->lastframe + inc;
if (newframe > (int)ima->twend) {
- if (ima->twend-ima->twsta != 0)
- newframe = (int)ima->twsta-1 + (newframe-ima->twend)%(ima->twend-ima->twsta);
+ if (ima->twend - ima->twsta != 0)
+ newframe = (int)ima->twsta - 1 + (newframe - ima->twend) % (ima->twend - ima->twsta);
else
newframe = ima->twsta;
}
@@ -1194,7 +1213,7 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres)
if (!sds->tex && !highres) {
/* rgba texture for color + density */
if (smoke_has_colors(sds->fluid)) {
- float *data = MEM_callocN(sizeof(float)*sds->total_cells*4, "smokeColorTexture");
+ float *data = MEM_callocN(sizeof(float) * sds->total_cells * 4, "smokeColorTexture");
smoke_get_rgba(sds->fluid, data, 0);
sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 4, data);
MEM_freeN(data);
@@ -1208,7 +1227,7 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres)
else if (!sds->tex && highres) {
/* rgba texture for color + density */
if (smoke_turbulence_has_colors(sds->wt)) {
- float *data = MEM_callocN(sizeof(float)*smoke_turbulence_get_cells(sds->wt)*4, "smokeColorTexture");
+ float *data = MEM_callocN(sizeof(float) * smoke_turbulence_get_cells(sds->wt) * 4, "smokeColorTexture");
smoke_turbulence_get_rgba(sds->wt, data, 0);
sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 4, data);
MEM_freeN(data);
@@ -1224,9 +1243,9 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres)
}
#else // WITH_SMOKE
(void)highres;
- smd->domain->tex= NULL;
- smd->domain->tex_flame= NULL;
- smd->domain->tex_shadow= NULL;
+ smd->domain->tex = NULL;
+ smd->domain->tex_flame = NULL;
+ smd->domain->tex_shadow = NULL;
#endif // WITH_SMOKE
}
@@ -1250,7 +1269,7 @@ void GPU_free_unused_buffers(void)
BLI_lock_thread(LOCK_OPENGL);
/* images */
- for (node=image_free_queue; node; node=node->next) {
+ for (node = image_free_queue; node; node = node->next) {
ima = node->link;
/* check in case it was freed in the meantime */
@@ -1277,13 +1296,13 @@ void GPU_free_image(Image *ima)
/* free regular image binding */
if (ima->bindcode) {
glDeleteTextures(1, (GLuint *)&ima->bindcode);
- ima->bindcode= 0;
+ ima->bindcode = 0;
}
/* free glsl image binding */
if (ima->gputexture) {
GPU_texture_free(ima->gputexture);
- ima->gputexture= NULL;
+ ima->gputexture = NULL;
}
/* free repeated image binding */
@@ -1291,7 +1310,7 @@ void GPU_free_image(Image *ima)
glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
MEM_freeN(ima->repbind);
- ima->repbind= NULL;
+ ima->repbind = NULL;
}
ima->tpageflag &= ~(IMA_MIPMAP_COMPLETE|IMA_GLBIND_IS_DATA);
@@ -1299,20 +1318,20 @@ void GPU_free_image(Image *ima)
void GPU_free_images(void)
{
- Image* ima;
+ Image *ima;
if (G.main)
- for (ima=G.main->image.first; ima; ima=ima->id.next)
+ for (ima = G.main->image.first; ima; ima = ima->id.next)
GPU_free_image(ima);
}
/* same as above but only free animated images */
void GPU_free_images_anim(void)
{
- Image* ima;
+ Image *ima;
if (G.main)
- for (ima=G.main->image.first; ima; ima=ima->id.next)
+ for (ima = G.main->image.first; ima; ima = ima->id.next)
if (BKE_image_is_animated(ima))
GPU_free_image(ima);
}
@@ -1358,7 +1377,7 @@ void GPU_free_images_old(void)
/* OpenGL Materials */
-#define FIXEDMAT 8
+#define FIXEDMAT 8
/* OpenGL state caching for materials */
@@ -1401,21 +1420,21 @@ static void gpu_material_to_fixed(GPUMaterialFixed *smat, const Material *bmat,
{
if (bmat->mode & MA_SHLESS) {
copy_v3_v3(smat->diff, &bmat->r);
- smat->diff[3]= 1.0;
+ smat->diff[3] = 1.0;
if (gamma)
linearrgb_to_srgb_v3_v3(smat->diff, smat->diff);
zero_v4(smat->spec);
- smat->hard= 0;
+ smat->hard = 0;
}
else if (new_shading_nodes) {
copy_v3_v3(smat->diff, &bmat->r);
- smat->diff[3]= 1.0;
+ smat->diff[3] = 1.0;
copy_v3_v3(smat->spec, &bmat->specr);
smat->spec[3] = 1.0;
- smat->hard= CLAMPIS(bmat->har, 0, 128);
+ smat->hard = CLAMPIS(bmat->har, 0, 128);
if (dimdown) {
mul_v3_fl(smat->diff, 0.8f);
@@ -1429,13 +1448,13 @@ static void gpu_material_to_fixed(GPUMaterialFixed *smat, const Material *bmat,
}
else {
mul_v3_v3fl(smat->diff, &bmat->r, bmat->ref + bmat->emit);
- smat->diff[3]= 1.0; /* caller may set this to bmat->alpha */
+ smat->diff[3] = 1.0; /* caller may set this to bmat->alpha */
if (bmat->shade_flag & MA_OBCOLOR)
mul_v3_v3(smat->diff, ob->col);
mul_v3_v3fl(smat->spec, &bmat->specr, bmat->spec);
- smat->spec[3]= 1.0; /* always 1 */
+ smat->spec[3] = 1.0; /* always 1 */
smat->hard= CLAMPIS(bmat->har, 0, 128);
if (gamma) {
@@ -1487,10 +1506,10 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
GMS.gob = ob;
GMS.gscene = scene;
GMS.totmat = use_matcap ? 1 : ob->totcol + 1; /* materials start from 1, default material is 0 */
- GMS.glay= (v3d->localvd)? v3d->localvd->lay: v3d->lay; /* keep lamps visible in local view */
+ GMS.glay = (v3d->localvd)? v3d->localvd->lay: v3d->lay; /* keep lamps visible in local view */
GMS.gscenelock = (v3d->scenelock != 0);
- GMS.gviewmat= rv3d->viewmat;
- GMS.gviewinv= rv3d->viewinv;
+ GMS.gviewmat = rv3d->viewmat;
+ GMS.gviewinv = rv3d->viewinv;
GMS.gviewcamtexcofac = rv3d->viewcamtexcofac;
/* alpha pass setup. there's various cases to handle here:
@@ -1504,14 +1523,14 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
*do_alpha_after = false;
if (GMS.totmat > FIXEDMAT) {
- GMS.matbuf= MEM_callocN(sizeof(GPUMaterialFixed)*GMS.totmat, "GMS.matbuf");
- GMS.gmatbuf= MEM_callocN(sizeof(*GMS.gmatbuf)*GMS.totmat, "GMS.matbuf");
- GMS.alphablend= MEM_callocN(sizeof(*GMS.alphablend)*GMS.totmat, "GMS.matbuf");
+ GMS.matbuf = MEM_callocN(sizeof(GPUMaterialFixed) * GMS.totmat, "GMS.matbuf");
+ GMS.gmatbuf = MEM_callocN(sizeof(*GMS.gmatbuf) * GMS.totmat, "GMS.matbuf");
+ GMS.alphablend = MEM_callocN(sizeof(*GMS.alphablend) * GMS.totmat, "GMS.matbuf");
}
else {
- GMS.matbuf= GMS.matbuf_fixed;
- GMS.gmatbuf= GMS.gmatbuf_fixed;
- GMS.alphablend= GMS.alphablend_fixed;
+ GMS.matbuf = GMS.matbuf_fixed;
+ GMS.gmatbuf = GMS.gmatbuf_fixed;
+ GMS.alphablend = GMS.alphablend_fixed;
}
/* viewport material, setup in space_view3d, defaults to matcap using ma->preview now */
@@ -1522,38 +1541,38 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
/* do material 1 too, for displists! */
memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed));
- GMS.alphablend[0]= GPU_BLEND_SOLID;
+ GMS.alphablend[0] = GPU_BLEND_SOLID;
}
else {
/* no materials assigned? */
- if (ob->totcol==0) {
+ if (ob->totcol == 0) {
gpu_material_to_fixed(&GMS.matbuf[0], &defmaterial, 0, ob, new_shading_nodes, true);
/* do material 1 too, for displists! */
memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed));
if (glsl) {
- GMS.gmatbuf[0]= &defmaterial;
+ GMS.gmatbuf[0] = &defmaterial;
GPU_material_from_blender(GMS.gscene, &defmaterial);
}
- GMS.alphablend[0]= GPU_BLEND_SOLID;
+ GMS.alphablend[0] = GPU_BLEND_SOLID;
}
/* setup materials */
- for (a=1; a<=ob->totcol; a++) {
+ for (a = 1; a <= ob->totcol; a++) {
/* find a suitable material */
- ma= give_current_material(ob, a);
- if (!glsl && !new_shading_nodes) ma= gpu_active_node_material(ma);
- if (ma==NULL) ma= &defmaterial;
+ ma = give_current_material(ob, a);
+ if (!glsl && !new_shading_nodes) ma = gpu_active_node_material(ma);
+ if (ma == NULL) ma = &defmaterial;
/* create glsl material if requested */
- gpumat = (glsl)? GPU_material_from_blender(GMS.gscene, ma): NULL;
+ gpumat = glsl? GPU_material_from_blender(GMS.gscene, ma): NULL;
if (gpumat) {
/* do glsl only if creating it succeed, else fallback */
- GMS.gmatbuf[a]= ma;
+ GMS.gmatbuf[a] = ma;
alphablend = GPU_material_alpha_blend(gpumat, ob->col);
}
else {
@@ -1561,11 +1580,11 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
gpu_material_to_fixed(&GMS.matbuf[a], ma, gamma, ob, new_shading_nodes, false);
if (GMS.use_alpha_pass && ((ma->mode & MA_TRANSP) || (new_shading_nodes && ma->alpha != 1.0f))) {
- GMS.matbuf[a].diff[3]= ma->alpha;
+ GMS.matbuf[a].diff[3] = ma->alpha;
alphablend = (ma->alpha == 1.0f)? GPU_BLEND_SOLID: GPU_BLEND_ALPHA;
}
else {
- GMS.matbuf[a].diff[3]= 1.0f;
+ GMS.matbuf[a].diff[3] = 1.0f;
alphablend = GPU_BLEND_SOLID;
}
}
@@ -1576,10 +1595,10 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ADD, GPU_BLEND_ALPHA_SORT))
*do_alpha_after = true;
- GMS.alphablend[a]= alphablend;
+ GMS.alphablend[a] = alphablend;
}
}
-
+
/* let's start with a clean state */
GPU_disable_material();
}
@@ -1597,10 +1616,10 @@ int GPU_enable_material(int nr, void *attribs)
memset(&GMS, 0, sizeof(GMS));
mul_v3_v3fl(diff, &defmaterial.r, defmaterial.ref + defmaterial.emit);
- diff[3]= 1.0;
+ diff[3] = 1.0;
mul_v3_v3fl(spec, &defmaterial.specr, defmaterial.spec);
- spec[3]= 1.0;
+ spec[3] = 1.0;
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diff);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
@@ -1610,21 +1629,21 @@ int GPU_enable_material(int nr, void *attribs)
}
/* prevent index to use un-initialized array items */
- if (nr>=GMS.totmat)
- nr= 0;
+ if (nr >= GMS.totmat)
+ nr = 0;
if (gattribs)
memset(gattribs, 0, sizeof(*gattribs));
/* keep current material */
- if (nr==GMS.lastmatnr)
+ if (nr == GMS.lastmatnr)
return GMS.lastretval;
/* unbind glsl material */
if (GMS.gboundmat) {
if (GMS.is_alpha_pass) glDepthMask(0);
GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat));
- GMS.gboundmat= NULL;
+ GMS.gboundmat = NULL;
}
/* draw materials with alpha in alpha pass */
@@ -1654,7 +1673,7 @@ int GPU_enable_material(int nr, void *attribs)
auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f;
GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gob->col, auto_bump_scale);
- GMS.gboundmat= mat;
+ GMS.gboundmat = mat;
/* for glsl use alpha blend mode, unless it's set to solid and
* we are already drawing in an alpha pass */
@@ -1671,7 +1690,7 @@ int GPU_enable_material(int nr, void *attribs)
}
if (GMS.use_matcaps)
- glColor3f(1.0, 1.0, 1.0f);
+ glColor3f(1.0f, 1.0f, 1.0f);
}
else {
/* or do fixed function opengl material */
@@ -1703,8 +1722,8 @@ int GPU_get_material_alpha_blend(void)
void GPU_disable_material(void)
{
- GMS.lastmatnr= -1;
- GMS.lastretval= 1;
+ GMS.lastmatnr = -1;
+ GMS.lastretval = 1;
if (GMS.gboundmat) {
if (GMS.backface_culling)
@@ -1712,7 +1731,7 @@ void GPU_disable_material(void)
if (GMS.is_alpha_pass) glDepthMask(0);
GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat));
- GMS.gboundmat= NULL;
+ GMS.gboundmat = NULL;
}
GPU_set_material_alpha_blend(GPU_BLEND_SOLID);
@@ -1749,9 +1768,9 @@ void GPU_end_object_materials(void)
MEM_freeN(GMS.alphablend);
}
- GMS.matbuf= NULL;
- GMS.gmatbuf= NULL;
- GMS.alphablend= NULL;
+ GMS.matbuf = NULL;
+ GMS.gmatbuf = NULL;
+ GMS.alphablend = NULL;
/* resetting the texture matrix after the scaling needed for tiled textures */
if (GTS.tilemode) {
@@ -1769,57 +1788,57 @@ int GPU_default_lights(void)
int a, count = 0;
/* initialize */
- if (U.light[0].flag==0 && U.light[1].flag==0 && U.light[2].flag==0) {
- U.light[0].flag= 1;
- U.light[0].vec[0]= -0.3; U.light[0].vec[1]= 0.3; U.light[0].vec[2]= 0.9;
- U.light[0].col[0]= 0.8; U.light[0].col[1]= 0.8; U.light[0].col[2]= 0.8;
- U.light[0].spec[0]= 0.5; U.light[0].spec[1]= 0.5; U.light[0].spec[2]= 0.5;
- U.light[0].spec[3]= 1.0;
+ if (U.light[0].flag == 0 && U.light[1].flag == 0 && U.light[2].flag == 0) {
+ U.light[0].flag = 1;
+ U.light[0].vec[0] = -0.3; U.light[0].vec[1] = 0.3; U.light[0].vec[2] = 0.9;
+ U.light[0].col[0] = 0.8; U.light[0].col[1] = 0.8; U.light[0].col[2] = 0.8;
+ U.light[0].spec[0] = 0.5; U.light[0].spec[1] = 0.5; U.light[0].spec[2] = 0.5;
+ U.light[0].spec[3] = 1.0;
- U.light[1].flag= 0;
- U.light[1].vec[0]= 0.5; U.light[1].vec[1]= 0.5; U.light[1].vec[2]= 0.1;
- U.light[1].col[0]= 0.4; U.light[1].col[1]= 0.4; U.light[1].col[2]= 0.8;
- U.light[1].spec[0]= 0.3; U.light[1].spec[1]= 0.3; U.light[1].spec[2]= 0.5;
- U.light[1].spec[3]= 1.0;
+ U.light[1].flag = 0;
+ U.light[1].vec[0] = 0.5; U.light[1].vec[1] = 0.5; U.light[1].vec[2] = 0.1;
+ U.light[1].col[0] = 0.4; U.light[1].col[1] = 0.4; U.light[1].col[2] = 0.8;
+ U.light[1].spec[0] = 0.3; U.light[1].spec[1] = 0.3; U.light[1].spec[2] = 0.5;
+ U.light[1].spec[3] = 1.0;
- U.light[2].flag= 0;
- U.light[2].vec[0]= 0.3; U.light[2].vec[1]= -0.3; U.light[2].vec[2]= -0.2;
- U.light[2].col[0]= 0.8; U.light[2].col[1]= 0.5; U.light[2].col[2]= 0.4;
- U.light[2].spec[0]= 0.5; U.light[2].spec[1]= 0.4; U.light[2].spec[2]= 0.3;
- U.light[2].spec[3]= 1.0;
+ U.light[2].flag = 0;
+ U.light[2].vec[0] = 0.3; U.light[2].vec[1] = -0.3; U.light[2].vec[2] = -0.2;
+ U.light[2].col[0] = 0.8; U.light[2].col[1] = 0.5; U.light[2].col[2] = 0.4;
+ U.light[2].spec[0] = 0.5; U.light[2].spec[1] = 0.4; U.light[2].spec[2] = 0.3;
+ U.light[2].spec[3] = 1.0;
}
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
- for (a=0; a<8; a++) {
- if (a<3) {
+ for (a = 0; a < 8; a++) {
+ if (a < 3) {
if (U.light[a].flag) {
- glEnable(GL_LIGHT0+a);
+ glEnable(GL_LIGHT0 + a);
normalize_v3_v3(position, U.light[a].vec);
- position[3]= 0.0f;
+ position[3] = 0.0f;
- glLightfv(GL_LIGHT0+a, GL_POSITION, position);
- glLightfv(GL_LIGHT0+a, GL_DIFFUSE, U.light[a].col);
- glLightfv(GL_LIGHT0+a, GL_SPECULAR, U.light[a].spec);
+ glLightfv(GL_LIGHT0 + a, GL_POSITION, position);
+ glLightfv(GL_LIGHT0 + a, GL_DIFFUSE, U.light[a].col);
+ glLightfv(GL_LIGHT0 + a, GL_SPECULAR, U.light[a].spec);
count++;
}
else {
- glDisable(GL_LIGHT0+a);
+ glDisable(GL_LIGHT0 + a);
- glLightfv(GL_LIGHT0+a, GL_POSITION, zero);
- glLightfv(GL_LIGHT0+a, GL_DIFFUSE, zero);
- glLightfv(GL_LIGHT0+a, GL_SPECULAR, zero);
+ glLightfv(GL_LIGHT0 + a, GL_POSITION, zero);
+ glLightfv(GL_LIGHT0 + a, GL_DIFFUSE, zero);
+ glLightfv(GL_LIGHT0 + a, GL_SPECULAR, zero);
}
- // clear stuff from other opengl lamp usage
- glLightf(GL_LIGHT0+a, GL_SPOT_CUTOFF, 180.0);
- glLightf(GL_LIGHT0+a, GL_CONSTANT_ATTENUATION, 1.0);
- glLightf(GL_LIGHT0+a, GL_LINEAR_ATTENUATION, 0.0);
+ /* clear stuff from other opengl lamp usage */
+ glLightf(GL_LIGHT0 + a, GL_SPOT_CUTOFF, 180.0);
+ glLightf(GL_LIGHT0 + a, GL_CONSTANT_ATTENUATION, 1.0);
+ glLightf(GL_LIGHT0 + a, GL_LINEAR_ATTENUATION, 0.0);
}
else
- glDisable(GL_LIGHT0+a);
+ glDisable(GL_LIGHT0 + a);
}
glDisable(GL_LIGHTING);
@@ -1837,68 +1856,68 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][
float position[4], direction[4], energy[4];
/* disable all lights */
- for (count=0; count<8; count++)
- glDisable(GL_LIGHT0+count);
+ for (count = 0; count < 8; count++)
+ glDisable(GL_LIGHT0 + count);
- /* view direction for specular is not compute correct by default in
+ /* view direction for specular is not computed correct by default in
* opengl, so we set the settings ourselfs */
- glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (ortho)? GL_FALSE: GL_TRUE);
+ glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, ortho ? GL_FALSE : GL_TRUE);
- count= 0;
-
- for (base=scene->base.first; base; base=base->next) {
- if (base->object->type!=OB_LAMP)
+ count = 0;
+
+ for (base = scene->base.first; base; base = base->next) {
+ if (base->object->type != OB_LAMP)
continue;
if (!(base->lay & lay) || !(base->lay & ob->lay))
continue;
- la= base->object->data;
+ la = base->object->data;
/* setup lamp transform */
glPushMatrix();
glLoadMatrixf((float *)viewmat);
- if (la->type==LA_SUN) {
+ if (la->type == LA_SUN) {
/* sun lamp */
copy_v3_v3(direction, base->object->obmat[2]);
- direction[3]= 0.0;
+ direction[3] = 0.0;
glLightfv(GL_LIGHT0+count, GL_POSITION, direction);
}
else {
/* other lamps with attenuation */
copy_v3_v3(position, base->object->obmat[3]);
- position[3]= 1.0f;
+ position[3] = 1.0f;
glLightfv(GL_LIGHT0+count, GL_POSITION, position);
glLightf(GL_LIGHT0+count, GL_CONSTANT_ATTENUATION, 1.0);
- glLightf(GL_LIGHT0+count, GL_LINEAR_ATTENUATION, la->att1/la->dist);
- glLightf(GL_LIGHT0+count, GL_QUADRATIC_ATTENUATION, la->att2/(la->dist*la->dist));
+ glLightf(GL_LIGHT0+count, GL_LINEAR_ATTENUATION, la->att1 / la->dist);
+ glLightf(GL_LIGHT0+count, GL_QUADRATIC_ATTENUATION, la->att2 / (la->dist * la->dist));
- if (la->type==LA_SPOT) {
+ if (la->type == LA_SPOT) {
/* spot lamp */
negate_v3_v3(direction, base->object->obmat[2]);
- glLightfv(GL_LIGHT0+count, GL_SPOT_DIRECTION, direction);
- glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, RAD2DEGF(la->spotsize * 0.5f));
- glLightf(GL_LIGHT0+count, GL_SPOT_EXPONENT, 128.0f*la->spotblend);
+ glLightfv(GL_LIGHT0 + count, GL_SPOT_DIRECTION, direction);
+ glLightf(GL_LIGHT0 + count, GL_SPOT_CUTOFF, RAD2DEGF(la->spotsize * 0.5f));
+ glLightf(GL_LIGHT0 + count, GL_SPOT_EXPONENT, 128.0f * la->spotblend);
}
else
- glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, 180.0);
+ glLightf(GL_LIGHT0 + count, GL_SPOT_CUTOFF, 180.0);
}
/* setup energy */
mul_v3_v3fl(energy, &la->r, la->energy);
- energy[3]= 1.0;
+ energy[3] = 1.0;
- glLightfv(GL_LIGHT0+count, GL_DIFFUSE, energy);
- glLightfv(GL_LIGHT0+count, GL_SPECULAR, energy);
- glEnable(GL_LIGHT0+count);
+ glLightfv(GL_LIGHT0 + count, GL_DIFFUSE, energy);
+ glLightfv(GL_LIGHT0 + count, GL_SPECULAR, energy);
+ glEnable(GL_LIGHT0 + count);
glPopMatrix();
count++;
- if (count==8)
+ if (count == 8)
break;
}
@@ -1944,8 +1963,8 @@ void GPU_state_init(void)
float mat_ambient[] = { 0.0, 0.0, 0.0, 0.0 };
float mat_specular[] = { 0.5, 0.5, 0.5, 1.0 };
int a, x, y;
- GLubyte pat[32*32];
- const GLubyte *patc= pat;
+ GLubyte pat[32 * 32];
+ const GLubyte *patc = pat;
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_specular);
@@ -1990,14 +2009,14 @@ void GPU_state_init(void)
glPixelTransferi(GL_DEPTH_SCALE, 1);
glDepthRange(0.0, 1.0);
- a= 0;
- for (x=0; x<32; x++) {
- for (y=0; y<4; y++) {
- if ( (x) & 1) pat[a++]= 0x88;
- else pat[a++]= 0x22;
+ a = 0;
+ for (x = 0; x < 32; x++) {
+ for (y = 0; y < 4; y++) {
+ if (x & 1) pat[a++] = 0x88;
+ else pat[a++] = 0x22;
}
}
-
+
glPolygonStipple(patc);
glMatrixMode(GL_TEXTURE);
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index f9bdaad832a..44a3654109f 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -40,6 +40,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_base.h"
+#include "BLI_math_vector.h"
#include "BKE_global.h"
@@ -61,6 +62,7 @@
#endif
#define MAX_DEFINE_LENGTH 72
+#define MAX_EXT_DEFINE_LENGTH 280
/* Extensions support */
@@ -75,6 +77,8 @@
*/
/* Non-generated shaders */
+extern char datatoc_gpu_program_smoke_frag_glsl[];
+extern char datatoc_gpu_program_smoke_color_frag_glsl[];
extern char datatoc_gpu_shader_vsm_store_vert_glsl[];
extern char datatoc_gpu_shader_vsm_store_frag_glsl[];
extern char datatoc_gpu_shader_sep_gaussian_blur_vert_glsl[];
@@ -83,12 +87,17 @@ extern char datatoc_gpu_shader_fx_vert_glsl[];
extern char datatoc_gpu_shader_fx_ssao_frag_glsl[];
extern char datatoc_gpu_shader_fx_dof_frag_glsl[];
extern char datatoc_gpu_shader_fx_dof_vert_glsl[];
+extern char datatoc_gpu_shader_fx_dof_hq_frag_glsl[];
+extern char datatoc_gpu_shader_fx_dof_hq_vert_glsl[];
+extern char datatoc_gpu_shader_fx_dof_hq_geo_glsl[];
extern char datatoc_gpu_shader_fx_depth_resolve_glsl[];
extern char datatoc_gpu_shader_fx_lib_glsl[];
typedef struct GPUShaders {
GPUShader *vsm_store;
GPUShader *sep_gaussian_blur;
+ GPUProgram *smoke;
+ GPUProgram *smoke_colored;
/* cache for shader fx. Those can exist in combinations so store them here */
GPUShader *fx_shaders[MAX_FX_SHADERS * 2];
} GPUShaders;
@@ -109,6 +118,9 @@ static struct GPUGlobal {
GPUTexture *invalid_tex_1D; /* texture used in place of invalid textures (not loaded correctly, missing) */
GPUTexture *invalid_tex_2D;
GPUTexture *invalid_tex_3D;
+ 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 */
} GG = {1, 0};
/* Number of maximum output slots. We support 4 outputs for now (usually we wouldn't need more to preserve fill rate) */
@@ -123,7 +135,7 @@ struct GPUFrameBuffer {
/* GPU Types */
-int GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
+bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
{
return (GG.device & device) && (GG.os & os) && (GG.driver & driver);
}
@@ -140,10 +152,15 @@ int GPU_max_texture_size(void)
return GG.maxtexsize;
}
+void GPU_get_dfdy_factors(float fac[2])
+{
+ copy_v2_v2(fac, GG.dfdyfactors);
+}
+
void gpu_extensions_init(void)
{
GLint r, g, b;
- const char *vendor, *renderer;
+ const char *vendor, *renderer, *version;
/* glewIsSupported("GL_VERSION_2_0") */
@@ -160,10 +177,11 @@ void gpu_extensions_init(void)
glGetIntegerv(GL_RED_BITS, &r);
glGetIntegerv(GL_GREEN_BITS, &g);
glGetIntegerv(GL_BLUE_BITS, &b);
- GG.colordepth = r+g+b; /* assumes same depth for RGB */
+ GG.colordepth = r + g + b; /* assumes same depth for RGB */
vendor = (const char *)glGetString(GL_VENDOR);
renderer = (const char *)glGetString(GL_RENDERER);
+ version = (const char *)glGetString(GL_VERSION);
if (strstr(vendor, "ATI")) {
GG.device = GPU_DEVICE_ATI;
@@ -240,6 +258,27 @@ void gpu_extensions_init(void)
#endif
+ /* df/dy calculation factors, those are dependent on driver */
+ if ((strstr(vendor, "ATI") && strstr(version, "3.3.10750"))) {
+ GG.dfdyfactors[0] = 1.0;
+ GG.dfdyfactors[1] = -1.0;
+ }
+ else if (GG.device == GPU_DEVICE_INTEL && GG.os == GPU_OS_WIN &&
+ (strstr(version, "4.0.0 - Build 10.18.10.3308") ||
+ strstr(version, "4.0.0 - Build 9.18.10.3186") ||
+ strstr(version, "4.0.0 - Build 9.18.10.3165") ||
+ strstr(version, "3.1.0 - Build 9.17.10.3347") ||
+ strstr(version, "3.1.0 - Build 9.17.10.4101")))
+ {
+ GG.dfdyfactors[0] = -1.0;
+ GG.dfdyfactors[1] = 1.0;
+ }
+ else {
+ GG.dfdyfactors[0] = 1.0;
+ GG.dfdyfactors[1] = 1.0;
+ }
+
+
GPU_invalid_tex_init();
GPU_simple_shaders_init();
}
@@ -250,29 +289,44 @@ void gpu_extensions_exit(void)
GPU_invalid_tex_free();
}
-int GPU_glsl_support(void)
+bool GPU_glsl_support(void)
{
return !GG.extdisabled && GG.glslsupport;
}
-int GPU_non_power_of_two_support(void)
+bool GPU_non_power_of_two_support(void)
{
if (GG.npotdisabled)
- return 0;
+ return false;
return GLEW_ARB_texture_non_power_of_two;
}
-int GPU_vertex_buffer_support(void)
+bool GPU_vertex_buffer_support(void)
{
return GLEW_ARB_vertex_buffer_object || GLEW_VERSION_1_5;
}
-int GPU_display_list_support(void)
+bool GPU_display_list_support(void)
{
return !GG.dlistsdisabled;
}
+bool GPU_bicubic_bump_support(void)
+{
+ return GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0;
+}
+
+bool GPU_geometry_shader_support(void)
+{
+ return GLEW_EXT_geometry_shader4 || GLEW_VERSION_3_2;
+}
+
+bool GPU_instanced_drawing_support(void)
+{
+ return GLEW_ARB_draw_instanced;
+}
+
int GPU_color_depth(void)
{
return GG.colordepth;
@@ -280,34 +334,34 @@ int GPU_color_depth(void)
static void GPU_print_framebuffer_error(GLenum status, char err_out[256])
{
- const char *err= "unknown";
+ const char *err = "unknown";
switch (status) {
case GL_FRAMEBUFFER_COMPLETE_EXT:
break;
case GL_INVALID_OPERATION:
- err= "Invalid operation";
+ err = "Invalid operation";
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
- err= "Incomplete attachment";
+ err = "Incomplete attachment";
break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
- err= "Unsupported framebuffer format";
+ err = "Unsupported framebuffer format";
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
- err= "Missing attachment";
+ err = "Missing attachment";
break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
- err= "Attached images must have same dimensions";
+ err = "Attached images must have same dimensions";
break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
- err= "Attached images must have same format";
+ err = "Attached images must have same format";
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
- err= "Missing draw buffer";
+ err = "Missing draw buffer";
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
- err= "Missing read buffer";
+ err = "Missing read buffer";
break;
}
@@ -324,29 +378,28 @@ static void GPU_print_framebuffer_error(GLenum status, char err_out[256])
/* GPUTexture */
struct GPUTexture {
- int w, h; /* width/height */
- int number; /* number for multitexture binding */
- int refcount; /* reference count */
- GLenum target; /* GL_TEXTURE_* */
- GLuint bindcode; /* opengl identifier for texture */
- int fromblender; /* we got the texture from Blender */
-
- GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */
- int fb_attachment; /* slot the texture is attached to */
- int depth; /* is a depth texture? */
+ int w, h; /* width/height */
+ int number; /* number for multitexture binding */
+ int refcount; /* reference count */
+ GLenum target; /* GL_TEXTURE_* */
+ GLuint bindcode; /* opengl identifier for texture */
+ int fromblender; /* we got the texture from Blender */
+
+ GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */
+ int fb_attachment; /* slot the texture is attached to */
+ int depth; /* is a depth texture? if 3D how deep? */
};
-static unsigned char *GPU_texture_convert_pixels(int length, float *fpixels)
+static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels)
{
unsigned char *pixels, *p;
- const float *fp;
- int a, len;
+ const float *fp = fpixels;
+ const int len = 4 * length;
+ int a;
- len = 4*length;
- fp = fpixels;
- p = pixels = MEM_callocN(sizeof(unsigned char)*len, "GPUTexturePixels");
+ p = pixels = MEM_callocN(sizeof(unsigned char) * len, "GPUTexturePixels");
- for (a=0; a<len; a++, p++, fp++)
+ for (a = 0; a < len; a++, p++, fp++)
*p = FTOCHAR((*fp));
return pixels;
@@ -354,7 +407,7 @@ static unsigned char *GPU_texture_convert_pixels(int length, float *fpixels)
static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h)
{
- void *pixels = MEM_callocN(sizeof(char)*4*w*h, "GPUTextureEmptyPixels");
+ void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels");
if (target == GL_TEXTURE_1D)
glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels);
@@ -365,7 +418,7 @@ static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, i
}
static GPUTexture *GPU_texture_create_nD(
- int w, int h, int n, float *fpixels, int depth, GPUHDRType hdr_type, int components,
+ int w, int h, int n, const float *fpixels, int depth, GPUHDRType hdr_type, int components,
char err_out[256])
{
GPUTexture *tex;
@@ -507,12 +560,13 @@ static GPUTexture *GPU_texture_create_nD(
}
-GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, float *fpixels)
+GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels)
{
GPUTexture *tex;
GLenum type, format, internalformat;
void *pixels = NULL;
- float vfBorderColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ int r_width;
+ bool rescale = false;
if (!GLEW_VERSION_1_2)
return NULL;
@@ -555,35 +609,90 @@ GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, float *
internalformat = GL_INTENSITY;
}
- //if (fpixels)
- // pixels = GPU_texture_convert_pixels(w*h*depth, fpixels);
+ /* 3D textures are quite heavy, test if it's possible to create them first */
+ glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
+ glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
+
+ while (r_width == 0) {
+ rescale = true;
+ tex->w /= 2;
+ tex->h /= 2;
+ tex->depth /= 2;
+ glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
+ glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
+ }
- glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
+ /* really unlikely to happen but keep this just in case */
+ tex->w = max_ii(tex->w, 1);
+ tex->h = max_ii(tex->h, 1);
+ tex->depth = max_ii(tex->depth, 1);
+
+#if 0
+ if (fpixels)
+ pixels = GPU_texture_convert_pixels(w*h*depth, fpixels);
+#endif
GPU_ASSERT_NO_GL_ERRORS("3D glTexImage3D");
- if (fpixels) {
- if (!GPU_non_power_of_two_support() && (w != tex->w || h != tex->h || depth != tex->depth)) {
- /* clear first to avoid unitialized pixels */
- float *zero= MEM_callocN(sizeof(float)*tex->w*tex->h*tex->depth, "zero");
- glTexSubImage3D(tex->target, 0, 0, 0, 0, tex->w, tex->h, tex->depth, format, type, zero);
- MEM_freeN(zero);
+ /* hardcore stuff, 3D texture rescaling - warning, this is gonna hurt your performance a lot, but we need it
+ * for gooseberry */
+ if (rescale && fpixels) {
+ unsigned int i, j, k;
+ unsigned int xf = w / tex->w, yf = h / tex->h, zf = depth / tex->depth;
+ float *tex3d = MEM_mallocN(channels * sizeof(float)*tex->w*tex->h*tex->depth, "tex3d");
+
+ GPU_print_error_debug("You need to scale a 3D texture, feel the pain!");
+
+ for (k = 0; k < tex->depth; k++) {
+ for (j = 0; j < tex->h; j++) {
+ for (i = 0; i < tex->w; i++) {
+ /* obviously doing nearest filtering here, it's going to be slow in any case, let's not make it worse */
+ float xb = i * xf;
+ float yb = j * yf;
+ float zb = k * zf;
+ unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j;
+ unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb);
+
+ if (channels == 4) {
+ tex3d[offset * 4] = fpixels[offset_orig * 4];
+ tex3d[offset * 4 + 1] = fpixels[offset_orig * 4 + 1];
+ tex3d[offset * 4 + 2] = fpixels[offset_orig * 4 + 2];
+ tex3d[offset * 4 + 3] = fpixels[offset_orig * 4 + 3];
+ }
+ else
+ tex3d[offset] = fpixels[offset_orig];
+ }
+ }
}
- glTexSubImage3D(tex->target, 0, 0, 0, 0, w, h, depth, format, type, fpixels);
- GPU_ASSERT_NO_GL_ERRORS("3D glTexSubImage3D");
+ glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, tex3d);
+
+ MEM_freeN(tex3d);
+ }
+ else {
+ if (fpixels) {
+ if (!GPU_non_power_of_two_support() && (w != tex->w || h != tex->h || depth != tex->depth)) {
+ /* clear first to avoid unitialized pixels */
+ float *zero= MEM_callocN(sizeof(float)*tex->w*tex->h*tex->depth, "zero");
+ glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
+ glTexSubImage3D(tex->target, 0, 0, 0, 0, tex->w, tex->h, tex->depth, GL_INTENSITY, GL_FLOAT, zero);
+ glTexSubImage3D(tex->target, 0, 0, 0, 0, w, h, depth, format, type, fpixels);
+ MEM_freeN(zero);
+ }
+ else {
+ glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, fpixels);
+ }
+
+ GPU_ASSERT_NO_GL_ERRORS("3D glTexSubImage3D");
+ }
}
- glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, vfBorderColor);
- GPU_ASSERT_NO_GL_ERRORS("3D GL_TEXTURE_BORDER_COLOR");
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- GPU_ASSERT_NO_GL_ERRORS("3D GL_LINEAR");
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
- GPU_ASSERT_NO_GL_ERRORS("3D GL_CLAMP_TO_BORDER");
if (pixels)
MEM_freeN(pixels);
@@ -684,7 +793,7 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
}
-GPUTexture *GPU_texture_create_1D(int w, float *fpixels, char err_out[256])
+GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256])
{
GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, err_out);
@@ -694,7 +803,7 @@ GPUTexture *GPU_texture_create_1D(int w, float *fpixels, char err_out[256])
return tex;
}
-GPUTexture *GPU_texture_create_2D(int w, int h, float *fpixels, GPUHDRType hdr, char err_out[256])
+GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType hdr, char err_out[256])
{
GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, err_out);
@@ -732,14 +841,16 @@ GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256])
return tex;
}
-GPUTexture *GPU_texture_create_2D_procedural(int w, int h, float *pixels, char err_out[256])
+GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256])
{
GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, err_out);
if (tex) {
/* Now we tweak some of the settings */
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ if (repeat) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ }
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -749,7 +860,7 @@ GPUTexture *GPU_texture_create_2D_procedural(int w, int h, float *pixels, char e
return tex;
}
-GPUTexture *GPU_texture_create_1D_procedural(int w, float *pixels, char err_out[256])
+GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256])
{
GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, err_out);
@@ -767,7 +878,7 @@ GPUTexture *GPU_texture_create_1D_procedural(int w, float *pixels, char err_out[
void GPU_invalid_tex_init(void)
{
- float color[4] = {1.0f, 0.0f, 1.0f, 1.0};
+ const float color[4] = {1.0f, 0.0f, 1.0f, 1.0f};
GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL);
GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, GPU_HDR_NONE, NULL);
GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, 4, color);
@@ -859,7 +970,7 @@ void GPU_texture_unbind(GPUTexture *tex)
GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind");
}
-void GPU_depth_texture_mode(GPUTexture *tex, bool compare, bool use_filter)
+void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter)
{
GLenum arbnumber;
@@ -868,11 +979,6 @@ void GPU_depth_texture_mode(GPUTexture *tex, bool compare, bool use_filter)
return;
}
- if (!tex->depth) {
- fprintf(stderr, "Not a depth texture.");
- return;
- }
-
if (tex->number == -1)
return;
@@ -880,10 +986,13 @@ void GPU_depth_texture_mode(GPUTexture *tex, bool compare, bool use_filter)
arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
if (tex->number != 0) glActiveTextureARB(arbnumber);
- if (compare)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
- else
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+
+ if (tex->depth) {
+ if (compare)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
+ else
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+ }
if (use_filter) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -920,22 +1029,22 @@ void GPU_texture_ref(GPUTexture *tex)
tex->refcount++;
}
-int GPU_texture_target(GPUTexture *tex)
+int GPU_texture_target(const GPUTexture *tex)
{
return tex->target;
}
-int GPU_texture_opengl_width(GPUTexture *tex)
+int GPU_texture_opengl_width(const GPUTexture *tex)
{
return tex->w;
}
-int GPU_texture_opengl_height(GPUTexture *tex)
+int GPU_texture_opengl_height(const GPUTexture *tex)
{
return tex->h;
}
-int GPU_texture_opengl_bindcode(GPUTexture *tex)
+int GPU_texture_opengl_bindcode(const GPUTexture *tex)
{
return tex->bindcode;
}
@@ -954,7 +1063,7 @@ GPUFrameBuffer *GPU_framebuffer_create(void)
if (!GLEW_EXT_framebuffer_object)
return NULL;
- fb= MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
+ fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
glGenFramebuffersEXT(1, &fb->object);
if (!fb->object) {
@@ -1047,8 +1156,7 @@ void GPU_framebuffer_texture_detach(GPUTexture *tex)
attachment = GL_COLOR_ATTACHMENT0_EXT + tex->fb_attachment;
}
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
- tex->target, 0, 0);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, tex->target, 0, 0);
tex->fb = NULL;
tex->fb_attachment = -1;
@@ -1098,7 +1206,7 @@ void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot)
return;
}
- for (i = 0 ; i < 4; i++) {
+ for (i = 0; i < 4; i++) {
if (fb->colortex[i]) {
attachments[numslots] = GL_COLOR_ATTACHMENT0_EXT + i;
numslots++;
@@ -1288,7 +1396,7 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256])
{
GPUOffScreen *ofs;
- ofs= MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen");
+ ofs = MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen");
ofs->fb = GPU_framebuffer_create();
if (!ofs->fb) {
@@ -1345,7 +1453,7 @@ void GPU_offscreen_bind(GPUOffScreen *ofs, bool save)
{
glDisable(GL_SCISSOR_TEST);
if (save)
- GPU_framebuffer_slots_bind(ofs->fb, 0);
+ GPU_texture_bind_as_framebuffer(ofs->color);
else {
GPU_framebuffer_bind_no_save(ofs->fb, 0);
}
@@ -1364,12 +1472,12 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
glReadPixels(0, 0, ofs->color->w, ofs->color->h, GL_RGBA, type, pixels);
}
-int GPU_offscreen_width(GPUOffScreen *ofs)
+int GPU_offscreen_width(const GPUOffScreen *ofs)
{
return ofs->color->w;
}
-int GPU_offscreen_height(GPUOffScreen *ofs)
+int GPU_offscreen_height(const GPUOffScreen *ofs)
{
return ofs->color->h;
}
@@ -1377,23 +1485,30 @@ int GPU_offscreen_height(GPUOffScreen *ofs)
/* GPUShader */
struct GPUShader {
- GLhandleARB object; /* handle for full shader */
- GLhandleARB vertex; /* handle for vertex shader */
- GLhandleARB fragment; /* handle for fragment shader */
- GLhandleARB lib; /* handle for libment shader */
- int totattrib; /* total number of attributes */
- int uniforms; /* required uniforms */
+ GLhandleARB object; /* handle for full shader */
+ GLhandleARB vertex; /* handle for vertex shader */
+ GLhandleARB fragment; /* handle for fragment shader */
+ GLhandleARB geometry; /* handle for geometry shader */
+ GLhandleARB lib; /* handle for libment shader */
+ int totattrib; /* total number of attributes */
+ int uniforms; /* required uniforms */
+};
+
+struct GPUProgram {
+ GPUProgramType type;
+ GLuint prog;
};
-static void shader_print_errors(const char *task, char *log, const char **code, int totcode)
+
+static void shader_print_errors(const char *task, const char *log, const char **code, int totcode)
{
int i;
+ int line = 1;
fprintf(stderr, "GPUShader: %s error:\n", task);
for (i = 0; i < totcode; i++) {
const char *c, *pos, *end = code[i] + strlen(code[i]);
- int line = 1;
if ((G.debug & G_DEBUG)) {
fprintf(stderr, "===== shader string %d ====\n", i + 1);
@@ -1401,8 +1516,8 @@ static void shader_print_errors(const char *task, char *log, const char **code,
c = code[i];
while ((c < end) && (pos = strchr(c, '\n'))) {
fprintf(stderr, "%2d ", line);
- fwrite(c, (pos+1)-c, 1, stderr);
- c = pos+1;
+ fwrite(c, (pos + 1) - c, 1, stderr);
+ c = pos + 1;
line++;
}
@@ -1426,13 +1541,19 @@ static const char *gpu_shader_version(void)
}
-static const char *gpu_shader_standard_extensions(void)
+static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH])
{
- /* need this extensions for high quality bump mapping */
+ /* need this extension for high quality bump mapping */
if (GPU_bicubic_bump_support())
- return "#extension GL_ARB_texture_query_lod: enable\n";
+ strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n");
- return "";
+ if (GPU_geometry_shader_support())
+ strcat(defines, "#extension GL_EXT_geometry_shader4: enable\n");
+
+ if (GPU_instanced_drawing_support()) {
+ strcat(defines, "#extension GL_EXT_gpu_shader4: enable\n");
+ strcat(defines, "#extension GL_ARB_draw_instanced: enable\n");
+ }
}
static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
@@ -1453,15 +1574,80 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
return;
}
-GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *libcode, const char *defines)
+void GPU_program_bind(GPUProgram *program)
+{
+ glEnable(program->type);
+ glBindProgramARB(program->type, program->prog);
+}
+
+void GPU_program_unbind(GPUProgram *program)
+{
+ glDisable(program->type);
+ glBindProgramARB(program->type, 0);
+}
+
+
+GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code)
+{
+ GPUProgram *program;
+ GLint error_pos, is_native;
+
+ if (!(GLEW_ARB_fragment_program && type == GPU_PROGRAM_TYPE_FRAGMENT))
+ return NULL;
+
+ program = MEM_callocN(sizeof(GPUProgram), "GPUProgram");
+
+ switch (type) {
+ case GPU_PROGRAM_TYPE_FRAGMENT:
+ program->type = GL_FRAGMENT_PROGRAM_ARB;
+ break;
+ }
+
+ /* create the object and set its code string */
+ glGenProgramsARB(1, &program->prog);
+ glBindProgramARB(program->type, program->prog);
+
+ glProgramStringARB(program->type, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(code), code);
+
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos);
+ glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &is_native);
+ if ((error_pos == -1) && (is_native == 1)) {
+ return program;
+ }
+ else {
+ /* glGetError is set before that, clear it */
+ while (glGetError() != GL_NO_ERROR)
+ ;
+ shader_print_errors("compile", (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB), &code, 1);
+ MEM_freeN(program);
+ }
+
+ return NULL;
+}
+
+void GPU_program_free(GPUProgram *program)
+{
+ glDeleteProgramsARB(1, &program->prog);
+ MEM_freeN(program);
+}
+
+void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w)
+{
+ glProgramLocalParameter4fARB(program->type, location, x, y, z, w);
+}
+
+
+
+GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines, int input, int output, int number)
{
GLint status;
GLcharARB log[5000];
GLsizei length = 0;
GPUShader *shader;
char standard_defines[MAX_DEFINE_LENGTH] = "";
+ char standard_extensions[MAX_EXT_DEFINE_LENGTH] = "";
- if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
+ if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader || (geocode && !GPU_geometry_shader_support()))
return NULL;
shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
@@ -1470,11 +1656,15 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
shader->vertex = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
if (fragcode)
shader->fragment = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
+ if (geocode)
+ shader->geometry = glCreateShaderObjectARB(GL_GEOMETRY_SHADER_EXT);
+
shader->object = glCreateProgramObjectARB();
if (!shader->object ||
(vertexcode && !shader->vertex) ||
- (fragcode && !shader->fragment))
+ (fragcode && !shader->fragment) ||
+ (geocode && !shader->geometry))
{
fprintf(stderr, "GPUShader, object creation failed.\n");
GPU_shader_free(shader);
@@ -1482,6 +1672,7 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
}
gpu_shader_standard_defines(standard_defines);
+ gpu_shader_standard_extensions(standard_extensions);
if (vertexcode) {
const char *source[5];
@@ -1489,11 +1680,11 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
int num_source = 0;
source[num_source++] = gpu_shader_version();
- source[num_source++] = gpu_shader_standard_extensions();
+ source[num_source++] = standard_extensions;
source[num_source++] = standard_defines;
if (defines) source[num_source++] = defines;
- if (vertexcode) source[num_source++] = vertexcode;
+ source[num_source++] = vertexcode;
glAttachObjectARB(shader->object, shader->vertex);
glShaderSourceARB(shader->vertex, num_source, source, NULL);
@@ -1515,12 +1706,12 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
int num_source = 0;
source[num_source++] = gpu_shader_version();
- source[num_source++] = gpu_shader_standard_extensions();
+ source[num_source++] = standard_extensions;
source[num_source++] = standard_defines;
if (defines) source[num_source++] = defines;
if (libcode) source[num_source++] = libcode;
- if (fragcode) source[num_source++] = fragcode;
+ source[num_source++] = fragcode;
glAttachObjectARB(shader->object, shader->fragment);
glShaderSourceARB(shader->fragment, num_source, source, NULL);
@@ -1537,6 +1728,35 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
}
}
+ if (geocode) {
+ const char *source[6];
+ int num_source = 0;
+
+ source[num_source++] = gpu_shader_version();
+ source[num_source++] = standard_extensions;
+ source[num_source++] = standard_defines;
+
+ if (defines) source[num_source++] = defines;
+ source[num_source++] = geocode;
+
+ glAttachObjectARB(shader->object, shader->geometry);
+ glShaderSourceARB(shader->geometry, num_source, source, NULL);
+
+ glCompileShaderARB(shader->geometry);
+ glGetObjectParameterivARB(shader->geometry, GL_OBJECT_COMPILE_STATUS_ARB, &status);
+
+ if (!status) {
+ glGetInfoLogARB(shader->geometry, sizeof(log), &length, log);
+ shader_print_errors("compile", log, source, num_source);
+
+ GPU_shader_free(shader);
+ return NULL;
+ }
+
+ GPU_shader_geometry_stage_primitive_io(shader, input, output, number);
+ }
+
+
#if 0
if (lib && lib->lib)
glAttachObjectARB(shader->object, lib->lib);
@@ -1549,6 +1769,7 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
if (fragcode) shader_print_errors("linking", log, &fragcode, 1);
else if (vertexcode) shader_print_errors("linking", log, &vertexcode, 1);
else if (libcode) shader_print_errors("linking", log, &libcode, 1);
+ else if (geocode) shader_print_errors("linking", log, &geocode, 1);
GPU_shader_free(shader);
return NULL;
@@ -1644,6 +1865,21 @@ void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int leng
GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector");
}
+void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int length, int arraysize, const int *value)
+{
+ if (location == -1)
+ return;
+
+ GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector");
+
+ if (length == 1) glUniform1ivARB(location, arraysize, value);
+ else if (length == 2) glUniform2ivARB(location, arraysize, value);
+ else if (length == 3) glUniform3ivARB(location, arraysize, value);
+ else if (length == 4) glUniform4ivARB(location, arraysize, value);
+
+ GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector");
+}
+
void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value)
{
if (location == -1)
@@ -1652,6 +1888,13 @@ void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value)
GPU_CHECK_ERRORS_AROUND(glUniform1iARB(location, value));
}
+void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number)
+{
+ glProgramParameteriEXT(shader->object, GL_GEOMETRY_INPUT_TYPE_EXT, input);
+ glProgramParameteriEXT(shader->object, GL_GEOMETRY_OUTPUT_TYPE_EXT, output);
+ glProgramParameteriEXT(shader->object, GL_GEOMETRY_VERTICES_OUT_EXT, number);
+}
+
void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex)
{
GLenum arbnumber;
@@ -1699,12 +1942,12 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
switch (shader) {
case GPU_SHADER_VSM_STORE:
if (!GG.shaders.vsm_store)
- GG.shaders.vsm_store = GPU_shader_create(datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, NULL, NULL);
+ GG.shaders.vsm_store = GPU_shader_create(datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, NULL, NULL, NULL, 0, 0, 0);
retval = GG.shaders.vsm_store;
break;
case GPU_SHADER_SEP_GAUSSIAN_BLUR:
if (!GG.shaders.sep_gaussian_blur)
- GG.shaders.sep_gaussian_blur = GPU_shader_create(datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, datatoc_gpu_shader_sep_gaussian_blur_frag_glsl, NULL, NULL);
+ GG.shaders.sep_gaussian_blur = GPU_shader_create(datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, datatoc_gpu_shader_sep_gaussian_blur_frag_glsl, NULL, NULL, NULL, 0, 0, 0);
retval = GG.shaders.sep_gaussian_blur;
break;
}
@@ -1715,6 +1958,29 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
return retval;
}
+GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program)
+{
+ GPUProgram *retval = NULL;
+
+ switch (program) {
+ case GPU_PROGRAM_SMOKE:
+ if (!GG.shaders.smoke)
+ GG.shaders.smoke = GPU_program_shader_create(GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_frag_glsl);
+ retval = GG.shaders.smoke;
+ break;
+ case GPU_PROGRAM_SMOKE_COLORED:
+ if (!GG.shaders.smoke_colored)
+ GG.shaders.smoke_colored = GPU_program_shader_create(GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_color_frag_glsl);
+ retval = GG.shaders.smoke_colored;
+ break;
+ }
+
+ if (retval == NULL)
+ printf("Unable to create a GPUProgram for builtin program: %d\n", program);
+
+ return retval;
+}
+
#define MAX_DEFINES 100
GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp)
@@ -1733,38 +1999,57 @@ GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp)
}
if (!GG.shaders.fx_shaders[offset]) {
- switch(effects) {
+ GPUShader *shader;
+
+ switch (effects) {
case GPU_SHADER_FX_SSAO:
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_ssao_frag_glsl, datatoc_gpu_shader_fx_lib_glsl, defines);
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_ssao_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
break;
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE:
strcat(defines, "#define FIRST_PASS\n");
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, datatoc_gpu_shader_fx_lib_glsl, defines);
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
break;
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO:
strcat(defines, "#define SECOND_PASS\n");
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, datatoc_gpu_shader_fx_lib_glsl, defines);
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
break;
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE:
strcat(defines, "#define THIRD_PASS\n");
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, datatoc_gpu_shader_fx_lib_glsl, defines);
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
break;
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR:
strcat(defines, "#define FOURTH_PASS\n");
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, datatoc_gpu_shader_fx_lib_glsl, defines);
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
break;
case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE:
strcat(defines, "#define FIFTH_PASS\n");
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, datatoc_gpu_shader_fx_lib_glsl, defines);
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
+ break;
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE:
+ strcat(defines, "#define FIRST_PASS\n");
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
+ break;
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO:
+ strcat(defines, "#define SECOND_PASS\n");
+ shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, datatoc_gpu_shader_fx_dof_hq_geo_glsl, datatoc_gpu_shader_fx_lib_glsl,
+ defines, GL_POINTS, GL_TRIANGLE_STRIP, 4);
+ GG.shaders.fx_shaders[offset] = shader;
+ break;
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE:
+ strcat(defines, "#define THIRD_PASS\n");
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
break;
case GPU_SHADER_FX_DEPTH_RESOLVE:
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, defines);
+ GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines, 0, 0, 0);
}
}
@@ -1777,24 +2062,63 @@ void GPU_shader_free_builtin_shaders(void)
int i;
if (GG.shaders.vsm_store) {
- MEM_freeN(GG.shaders.vsm_store);
+ GPU_shader_free(GG.shaders.vsm_store);
GG.shaders.vsm_store = NULL;
}
if (GG.shaders.sep_gaussian_blur) {
- MEM_freeN(GG.shaders.sep_gaussian_blur);
+ GPU_shader_free(GG.shaders.sep_gaussian_blur);
GG.shaders.sep_gaussian_blur = NULL;
}
+ if (GG.shaders.smoke) {
+ GPU_program_free(GG.shaders.smoke);
+ GG.shaders.smoke = NULL;
+ }
+
+ if (GG.shaders.smoke_colored) {
+ GPU_program_free(GG.shaders.smoke_colored);
+ GG.shaders.smoke_colored = NULL;
+ }
+
for (i = 0; i < 2 * MAX_FX_SHADERS; i++) {
if (GG.shaders.fx_shaders[i]) {
- MEM_freeN(GG.shaders.fx_shaders[i]);
+ GPU_shader_free(GG.shaders.fx_shaders[i]);
GG.shaders.fx_shaders[i] = NULL;
}
}
}
-#if 0
+bool GPU_mem_stats_supported(void)
+{
+ return (GLEW_NVX_gpu_memory_info || (GLEW_ATI_meminfo)) && (G.debug & G_DEBUG_GPU_MEM);
+}
+
+
+void GPU_mem_stats_get(int *totalmem, int *freemem)
+{
+ if (GLEW_NVX_gpu_memory_info) {
+ /* returned value in Kb */
+ glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, totalmem);
+
+ glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, freemem);
+ }
+ else if (GLEW_ATI_meminfo) {
+ int stats[4];
+
+ glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, stats);
+ *freemem = stats[0];
+ *totalmem = 0;
+ }
+ else {
+ *totalmem = 0;
+ *freemem = 0;
+ }
+}
+
+
+#if 0 /* unused */
+
/* GPUPixelBuffer */
typedef struct GPUPixelBuffer {
@@ -1820,7 +2144,7 @@ GPUPixelBuffer *gpu_pixelbuffer_create(int x, int y, int halffloat, int numbuffe
return NULL;
pb = MEM_callocN(sizeof(GPUPixelBuffer), "GPUPBO");
- pb->datasize = x*y*4*((halffloat)? 16: 8);
+ pb->datasize = x * y * 4 * (halffloat ? 16 : 8);
pb->numbuffers = numbuffers;
pb->halffloat = halffloat;
@@ -1848,10 +2172,13 @@ void GPU_pixelbuffer_texture(GPUTexture *tex, GPUPixelBuffer *pb)
GL_STREAM_DRAW_ARB);
pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
- /*memcpy(pixels, _oImage.data(), pb->datasize);*/
+
+# if 0
+ memcpy(pixels, _oImage.data(), pb->datasize);
+# endif
if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
- fprintf(stderr, "Could not unmap opengl PBO\n");
+ fprintf(stderr, "Could not unmap OpenGL PBO\n");
break;
}
}
@@ -1869,7 +2196,7 @@ static int pixelbuffer_map_into_gpu(GLuint bindcode)
/* do stuff in pixels */
if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
- fprintf(stderr, "Could not unmap opengl PBO\n");
+ fprintf(stderr, "Could not unmap OpenGL PBO\n");
return 0;
}
@@ -1882,8 +2209,7 @@ static void pixelbuffer_copy_to_texture(GPUTexture *tex, GPUPixelBuffer *pb, GLu
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
- glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, tex->w, tex->h,
- GL_RGBA, type, NULL);
+ glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, tex->w, tex->h, GL_RGBA, type, NULL);
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
@@ -1898,12 +2224,12 @@ void GPU_pixelbuffer_async_to_gpu(GPUTexture *tex, GPUPixelBuffer *pb)
pixelbuffer_map_into_gpu(pb->bindcode[0]);
}
else {
- pb->current = (pb->current+1)%pb->numbuffers;
- newbuffer = (pb->current+1)%pb->numbuffers;
+ pb->current = (pb->current + 1) % pb->numbuffers;
+ newbuffer = (pb->current + 1) % pb->numbuffers;
pixelbuffer_map_into_gpu(pb->bindcode[newbuffer]);
pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[pb->current]);
}
}
-#endif
+#endif /* unused */
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index f8499ca2d34..bd17fb0b1aa 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -76,6 +76,16 @@ typedef enum DynMatProperty {
DYN_LAMP_PERSMAT = 8,
} DynMatProperty;
+static struct GPUWorld {
+ float mistenabled;
+ float mistype;
+ float miststart;
+ float mistdistance;
+ float mistintensity;
+ float mistcol[4];
+ float horicol[3];
+ float ambcol[4];
+} GPUWorld;
struct GPUMaterial {
Scene *scene;
@@ -92,7 +102,6 @@ struct GPUMaterial {
/* for binding the material */
GPUPass *pass;
GPUVertexAttribs attribs;
- int bound;
int builtins;
int alpha, obcolalpha;
int dynproperty;
@@ -104,6 +113,7 @@ struct GPUMaterial {
int cameratexcofacloc;
ListBase lamps;
+ bool bound;
};
struct GPULamp {
@@ -157,7 +167,7 @@ static GPUMaterial *GPU_material_construct_begin(Material *ma)
{
GPUMaterial *material = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");
- material->ma= ma;
+ material->ma = ma;
return material;
}
@@ -170,14 +180,14 @@ static void gpu_material_set_attrib_id(GPUMaterial *material)
char name[32];
int a, b;
- attribs= &material->attribs;
- pass= material->pass;
+ attribs = &material->attribs;
+ pass = material->pass;
if (!pass) {
attribs->totlayer = 0;
return;
}
- shader= GPU_pass_shader(pass);
+ shader = GPU_pass_shader(pass);
if (!shader) {
attribs->totlayer = 0;
return;
@@ -187,7 +197,7 @@ static void gpu_material_set_attrib_id(GPUMaterial *material)
* in case the attrib does not get a valid index back, it was probably
* removed by the glsl compiler by dead code elimination */
- for (a=0, b=0; a<attribs->totlayer; a++) {
+ for (a = 0, b = 0; a < attribs->totlayer; a++) {
BLI_snprintf(name, sizeof(name), "att%d", attribs->layer[a].attribid);
attribs->layer[a].glindex = GPU_shader_get_attribute(shader, name);
@@ -242,19 +252,19 @@ void GPU_material_free(ListBase *gpumaterial)
LinkData *link;
LinkData *nlink, *mlink, *next;
- for (link=gpumaterial->first; link; link=link->next) {
+ for (link = gpumaterial->first; link; link = link->next) {
GPUMaterial *material = link->data;
if (material->pass)
GPU_pass_free(material->pass);
- for (nlink=material->lamps.first; nlink; nlink=nlink->next) {
+ for (nlink = material->lamps.first; nlink; nlink = nlink->next) {
GPULamp *lamp = nlink->data;
if (material->ma) {
Material *ma = material->ma;
- for (mlink=lamp->materials.first; mlink; mlink=next) {
+ for (mlink = lamp->materials.first; mlink; mlink = next) {
next = mlink->next;
if (mlink->data == ma)
BLI_freelinkN(&lamp->materials, mlink);
@@ -293,8 +303,8 @@ void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double tim
/* handle layer lamps */
if (material->type == GPU_MATERIAL_TYPE_MESH) {
- for (nlink=material->lamps.first; nlink; nlink=nlink->next) {
- lamp= nlink->data;
+ for (nlink = material->lamps.first; nlink; nlink = nlink->next) {
+ lamp = nlink->data;
if (!lamp->hide && (lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay))
&& GPU_lamp_override_visible(lamp, srl, material->ma)) {
@@ -303,7 +313,7 @@ void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double tim
}
else {
lamp->dynenergy = 0.0f;
- lamp->dyncol[0]= lamp->dyncol[1]= lamp->dyncol[2] = 0.0f;
+ lamp->dyncol[0] = lamp->dyncol[1] = lamp->dyncol[2] = 0.0f;
}
if (material->dynproperty & DYN_LAMP_VEC) {
@@ -390,7 +400,7 @@ void GPU_material_unbind(GPUMaterial *material)
}
}
-int GPU_material_bound(GPUMaterial *material)
+bool GPU_material_bound(GPUMaterial *material)
{
return material->bound;
}
@@ -414,12 +424,12 @@ void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *att
void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link)
{
if (!material->outlink)
- material->outlink= link;
+ material->outlink = link;
}
void GPU_material_enable_alpha(GPUMaterial *material)
{
- material->alpha= 1;
+ material->alpha = 1;
}
GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4])
@@ -442,7 +452,7 @@ bool GPU_material_do_color_management(GPUMaterial *mat)
if (!BKE_scene_check_color_management_enabled(mat->scene))
return false;
- return !((mat->scene->gm.flag & GAME_GLSL_NO_COLOR_MANAGEMENT));
+ return true;
}
bool GPU_material_use_new_shading_nodes(GPUMaterial *mat)
@@ -455,7 +465,7 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode
GPUNodeLink *visifac, *inpr;
/* from get_lamp_visibility */
- if (lamp->type==LA_SUN || lamp->type==LA_HEMI) {
+ if (lamp->type == LA_SUN || lamp->type == LA_HEMI) {
mat->dynproperty |= DYN_LAMP_VEC;
GPU_link(mat, "lamp_visibility_sun_hemi", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), lv, dist, &visifac);
return visifac;
@@ -464,7 +474,7 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode
mat->dynproperty |= DYN_LAMP_CO;
GPU_link(mat, "lamp_visibility_other", GPU_builtin(GPU_VIEW_POSITION), GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob), lv, dist, &visifac);
- if (lamp->type==LA_AREA)
+ if (lamp->type == LA_AREA)
return visifac;
switch (lamp->falloff_type) {
@@ -480,15 +490,16 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode
GPU_link(mat, "lamp_falloff_sliders", GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), GPU_dynamic_uniform(&lamp->att1, GPU_DYNAMIC_LAMP_ATT1, lamp->ob), GPU_dynamic_uniform(&lamp->att2, GPU_DYNAMIC_LAMP_ATT2, lamp->ob), *dist, &visifac);
break;
case LA_FALLOFF_CURVE:
- {
- float *array;
- int size;
+ {
+ float *array;
+ int size;
+
+ curvemapping_initialize(lamp->curfalloff);
+ curvemapping_table_RGBA(lamp->curfalloff, &array, &size);
+ GPU_link(mat, "lamp_falloff_curve", GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), GPU_texture(size, array), *dist, &visifac);
- curvemapping_initialize(lamp->curfalloff);
- curvemapping_table_RGBA(lamp->curfalloff, &array, &size);
- GPU_link(mat, "lamp_falloff_curve", GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), GPU_texture(size, array), *dist, &visifac);
- }
break;
+ }
}
if (lamp->mode & LA_SPHERE)
@@ -516,34 +527,34 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode
#if 0
static void area_lamp_vectors(LampRen *lar)
{
- float xsize= 0.5*lar->area_size, ysize= 0.5*lar->area_sizey, multifac;
+ float xsize = 0.5f * lar->area_size, ysize = 0.5f * lar->area_sizey, multifac;
/* make it smaller, so area light can be multisampled */
- multifac= 1.0f/sqrt((float)lar->ray_totsamp);
+ multifac = 1.0f / sqrtf((float)lar->ray_totsamp);
xsize *= multifac;
ysize *= multifac;
/* corner vectors */
- lar->area[0][0]= lar->co[0] - xsize*lar->mat[0][0] - ysize*lar->mat[1][0];
- lar->area[0][1]= lar->co[1] - xsize*lar->mat[0][1] - ysize*lar->mat[1][1];
- lar->area[0][2]= lar->co[2] - xsize*lar->mat[0][2] - ysize*lar->mat[1][2];
+ lar->area[0][0] = lar->co[0] - xsize * lar->mat[0][0] - ysize * lar->mat[1][0];
+ lar->area[0][1] = lar->co[1] - xsize * lar->mat[0][1] - ysize * lar->mat[1][1];
+ lar->area[0][2] = lar->co[2] - xsize * lar->mat[0][2] - ysize * lar->mat[1][2];
/* corner vectors */
- lar->area[1][0]= lar->co[0] - xsize*lar->mat[0][0] + ysize*lar->mat[1][0];
- lar->area[1][1]= lar->co[1] - xsize*lar->mat[0][1] + ysize*lar->mat[1][1];
- lar->area[1][2]= lar->co[2] - xsize*lar->mat[0][2] + ysize*lar->mat[1][2];
+ lar->area[1][0] = lar->co[0] - xsize * lar->mat[0][0] + ysize * lar->mat[1][0];
+ lar->area[1][1] = lar->co[1] - xsize * lar->mat[0][1] + ysize * lar->mat[1][1];
+ lar->area[1][2] = lar->co[2] - xsize * lar->mat[0][2] + ysize * lar->mat[1][2];
/* corner vectors */
- lar->area[2][0]= lar->co[0] + xsize*lar->mat[0][0] + ysize*lar->mat[1][0];
- lar->area[2][1]= lar->co[1] + xsize*lar->mat[0][1] + ysize*lar->mat[1][1];
- lar->area[2][2]= lar->co[2] + xsize*lar->mat[0][2] + ysize*lar->mat[1][2];
+ lar->area[2][0] = lar->co[0] + xsize * lar->mat[0][0] + ysize * lar->mat[1][0];
+ lar->area[2][1] = lar->co[1] + xsize * lar->mat[0][1] + ysize * lar->mat[1][1];
+ lar->area[2][2] = lar->co[2] + xsize * lar->mat[0][2] + ysize * lar->mat[1][2];
/* corner vectors */
- lar->area[3][0]= lar->co[0] + xsize*lar->mat[0][0] - ysize*lar->mat[1][0];
- lar->area[3][1]= lar->co[1] + xsize*lar->mat[0][1] - ysize*lar->mat[1][1];
- lar->area[3][2]= lar->co[2] + xsize*lar->mat[0][2] - ysize*lar->mat[1][2];
+ lar->area[3][0] = lar->co[0] + xsize * lar->mat[0][0] - ysize * lar->mat[1][0];
+ lar->area[3][1] = lar->co[1] + xsize * lar->mat[0][1] - ysize * lar->mat[1][1];
+ lar->area[3][2] = lar->co[2] + xsize * lar->mat[0][2] - ysize * lar->mat[1][2];
/* only for correction button size, matrix size works on energy */
- lar->areasize= lar->dist*lar->dist/(4.0*xsize*ysize);
+ lar->areasize = lar->dist * lar->dist / (4.0f * xsize * ysize);
}
#endif
@@ -577,8 +588,8 @@ static void do_colorband_blend(GPUMaterial *mat, ColorBand *coba, GPUNodeLink *f
static void ramp_diffuse_result(GPUShadeInput *shi, GPUNodeLink **diff)
{
- Material *ma= shi->mat;
- GPUMaterial *mat= shi->gpumat;
+ Material *ma = shi->mat;
+ GPUMaterial *mat = shi->gpumat;
GPUNodeLink *fac;
if (!(mat->scene->gm.flag & GAME_GLSL_NO_RAMPS)) {
@@ -607,18 +618,18 @@ static void add_to_diffuse(GPUMaterial *mat, Material *ma, GPUShadeInput *shi, G
else {
/* input */
switch (ma->rampin_col) {
- case MA_RAMP_IN_ENERGY:
- GPU_link(mat, "ramp_rgbtobw", rgb, &fac);
- break;
- case MA_RAMP_IN_SHADER:
- fac= is;
- break;
- case MA_RAMP_IN_NOR:
- GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac);
- break;
- default:
- GPU_link(mat, "set_value_zero", &fac);
- break;
+ case MA_RAMP_IN_ENERGY:
+ GPU_link(mat, "ramp_rgbtobw", rgb, &fac);
+ break;
+ case MA_RAMP_IN_SHADER:
+ fac= is;
+ break;
+ case MA_RAMP_IN_NOR:
+ GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac);
+ break;
+ default:
+ GPU_link(mat, "set_value_zero", &fac);
+ break;
}
/* colorband + blend */
@@ -634,12 +645,12 @@ static void add_to_diffuse(GPUMaterial *mat, Material *ma, GPUShadeInput *shi, G
static void ramp_spec_result(GPUShadeInput *shi, GPUNodeLink **spec)
{
- Material *ma= shi->mat;
- GPUMaterial *mat= shi->gpumat;
+ Material *ma = shi->mat;
+ GPUMaterial *mat = shi->gpumat;
GPUNodeLink *fac;
if (!(mat->scene->gm.flag & GAME_GLSL_NO_RAMPS) &&
- ma->ramp_spec && ma->rampin_spec==MA_RAMP_IN_RESULT)
+ ma->ramp_spec && ma->rampin_spec == MA_RAMP_IN_RESULT)
{
GPU_link(mat, "ramp_rgbtobw", *spec, &fac);
@@ -650,29 +661,29 @@ static void ramp_spec_result(GPUShadeInput *shi, GPUNodeLink **spec)
static void do_specular_ramp(GPUShadeInput *shi, GPUNodeLink *is, GPUNodeLink *t, GPUNodeLink **spec)
{
- Material *ma= shi->mat;
- GPUMaterial *mat= shi->gpumat;
+ Material *ma = shi->mat;
+ GPUMaterial *mat = shi->gpumat;
GPUNodeLink *fac, *tmp;
*spec = shi->specrgb;
/* MA_RAMP_IN_RESULT is exception */
- if (ma->ramp_spec && (ma->rampin_spec!=MA_RAMP_IN_RESULT)) {
+ if (ma->ramp_spec && (ma->rampin_spec != MA_RAMP_IN_RESULT)) {
/* input */
switch (ma->rampin_spec) {
- case MA_RAMP_IN_ENERGY:
- fac = t;
- break;
- case MA_RAMP_IN_SHADER:
- fac = is;
- break;
- case MA_RAMP_IN_NOR:
- GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac);
- break;
- default:
- GPU_link(mat, "set_value_zero", &fac);
- break;
+ case MA_RAMP_IN_ENERGY:
+ fac = t;
+ break;
+ case MA_RAMP_IN_SHADER:
+ fac = is;
+ break;
+ case MA_RAMP_IN_NOR:
+ GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac);
+ break;
+ default:
+ GPU_link(mat, "set_value_zero", &fac);
+ break;
}
/* colorband + blend */
@@ -694,10 +705,10 @@ static void shade_light_textures(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **
int i;
float one = 1.f;
- for (i=0; i<MAX_MTEX; ++i) {
+ for (i = 0; i < MAX_MTEX; ++i) {
mtex = lamp->la->mtex[i];
- if (mtex && mtex->tex->type & TEX_IMAGE && mtex->tex->ima) {
+ if (mtex && mtex->tex->type & TEX_IMAGE && mtex->tex->ima) {
mat->dynproperty |= DYN_LAMP_PERSMAT;
GPU_link(mat, "shade_light_texture",
@@ -705,29 +716,31 @@ static void shade_light_textures(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **
GPU_image(mtex->tex->ima, &mtex->tex->iuser, false),
GPU_dynamic_uniform((float*)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
&tex_rgb);
- texture_rgb_blend(mat, tex_rgb, *rgb, GPU_uniform(&one), GPU_uniform(&mtex->colfac), mtex->blendtype, rgb);
+ texture_rgb_blend(mat, tex_rgb, *rgb, GPU_uniform(&one), GPU_uniform(&mtex->colfac), mtex->blendtype, rgb);
}
}
}
static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *lamp)
{
- Material *ma= shi->mat;
- GPUMaterial *mat= shi->gpumat;
+ Material *ma = shi->mat;
+ GPUMaterial *mat = shi->gpumat;
GPUNodeLink *lv, *dist, *visifac, *is, *inp, *i, *vn, *view;
- GPUNodeLink *outcol, *specfac, *t, *shadfac= NULL, *lcol;
+ GPUNodeLink *outcol, *specfac, *t, *shadfac = NULL, *lcol;
float one = 1.0f;
if ((lamp->mode & LA_ONLYSHADOW) && !(ma->mode & MA_SHADOW))
return;
- vn= shi->vn;
- view= shi->view;
+ vn = shi->vn;
+ view = shi->view;
- visifac= lamp_get_visibility(mat, lamp, &lv, &dist);
+ visifac = lamp_get_visibility(mat, lamp, &lv, &dist);
- /*if (ma->mode & MA_TANGENT_V)
- GPU_link(mat, "shade_tangent_v", lv, GPU_attribute(CD_TANGENT, ""), &vn);*/
+#if 0
+ if (ma->mode & MA_TANGENT_V)
+ GPU_link(mat, "shade_tangent_v", lv, GPU_attribute(CD_TANGENT, ""), &vn);
+#endif
GPU_link(mat, "shade_inp", vn, lv, &inp);
@@ -739,23 +752,23 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
}
else {
if (lamp->type == LA_AREA) {
- float area[4][4]= {{0.0f}}, areasize= 0.0f;
+ float area[4][4] = {{0.0f}}, areasize = 0.0f;
mat->dynproperty |= DYN_LAMP_VEC|DYN_LAMP_CO;
GPU_link(mat, "shade_inp_area", GPU_builtin(GPU_VIEW_POSITION), GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob), GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), vn, GPU_uniform((float*)area),
GPU_uniform(&areasize), GPU_uniform(&lamp->k), &inp);
}
- is= inp; /* Lambert */
+ is = inp; /* Lambert */
if (!(mat->scene->gm.flag & GAME_GLSL_NO_SHADERS)) {
- if (ma->diff_shader==MA_DIFF_ORENNAYAR)
+ if (ma->diff_shader == MA_DIFF_ORENNAYAR)
GPU_link(mat, "shade_diffuse_oren_nayer", inp, vn, lv, view, GPU_uniform(&ma->roughness), &is);
- else if (ma->diff_shader==MA_DIFF_TOON)
+ else if (ma->diff_shader == MA_DIFF_TOON)
GPU_link(mat, "shade_diffuse_toon", vn, lv, view, GPU_uniform(&ma->param[0]), GPU_uniform(&ma->param[1]), &is);
- else if (ma->diff_shader==MA_DIFF_MINNAERT)
+ else if (ma->diff_shader == MA_DIFF_MINNAERT)
GPU_link(mat, "shade_diffuse_minnaert", inp, vn, view, GPU_uniform(&ma->darkness), &is);
- else if (ma->diff_shader==MA_DIFF_FRESNEL)
+ else if (ma->diff_shader == MA_DIFF_FRESNEL)
GPU_link(mat, "shade_diffuse_fresnel", vn, lv, view, GPU_uniform(&ma->param[0]), GPU_uniform(&ma->param[1]), &is);
}
}
@@ -777,7 +790,7 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
#endif
/* this replaces if (i > 0.0) conditional until that is supported */
- // done in shade_visifac now, GPU_link(mat, "mtex_value_clamp_positive", i, &i);
+ /* done in shade_visifac now, GPU_link(mat, "mtex_value_clamp_positive", i, &i); */
if ((ma->mode & MA_SHADOW) && GPU_lamp_has_shadow_buffer(lamp)) {
if (!(mat->scene->gm.flag & GAME_GLSL_NO_SHADOWS)) {
@@ -850,18 +863,18 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
GPU_link(mat, "shade_add_clamped", shr->spec, outcol, &shr->spec);
}
else {
- if (ma->spec_shader==MA_SPEC_PHONG)
+ if (ma->spec_shader == MA_SPEC_PHONG)
GPU_link(mat, "shade_phong_spec", vn, lv, view, shi->har, &specfac);
- else if (ma->spec_shader==MA_SPEC_COOKTORR)
+ else if (ma->spec_shader == MA_SPEC_COOKTORR)
GPU_link(mat, "shade_cooktorr_spec", vn, lv, view, shi->har, &specfac);
- else if (ma->spec_shader==MA_SPEC_BLINN)
+ else if (ma->spec_shader == MA_SPEC_BLINN)
GPU_link(mat, "shade_blinn_spec", vn, lv, view, GPU_uniform(&ma->refrac), shi->har, &specfac);
- else if (ma->spec_shader==MA_SPEC_WARDISO)
+ else if (ma->spec_shader == MA_SPEC_WARDISO)
GPU_link(mat, "shade_wardiso_spec", vn, lv, view, GPU_uniform(&ma->rms), &specfac);
else
GPU_link(mat, "shade_toon_spec", vn, lv, view, GPU_uniform(&ma->param[2]), GPU_uniform(&ma->param[3]), &specfac);
- if (lamp->type==LA_AREA)
+ if (lamp->type == LA_AREA)
GPU_link(mat, "shade_spec_area_inp", specfac, inp, &specfac);
GPU_link(mat, "shade_spec_t", shadfac, shi->spec, visifac, specfac, &t);
@@ -891,9 +904,9 @@ static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr)
GPULamp *lamp;
for (SETLOOPER(shi->gpumat->scene, sce_iter, base)) {
- ob= base->object;
+ ob = base->object;
- if (ob->type==OB_LAMP) {
+ if (ob->type == OB_LAMP) {
lamp = GPU_lamp_from_blender(shi->gpumat->scene, ob, NULL);
if (lamp)
shade_one_light(shi, shr, lamp);
@@ -903,10 +916,10 @@ static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr)
DupliObject *dob;
ListBase *lb = object_duplilist(G.main->eval_ctx, shi->gpumat->scene, ob);
- for (dob=lb->first; dob; dob=dob->next) {
+ for (dob = lb->first; dob; dob = dob->next) {
Object *ob_iter = dob->ob;
- if (ob_iter->type==OB_LAMP) {
+ if (ob_iter->type == OB_LAMP) {
float omat[4][4];
copy_m4_m4(omat, ob_iter->obmat);
copy_m4_m4(ob_iter->obmat, dob->mat);
@@ -1023,8 +1036,8 @@ static void texture_value_blend(GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink
static void do_material_tex(GPUShadeInput *shi)
{
- Material *ma= shi->mat;
- GPUMaterial *mat= shi->gpumat;
+ Material *ma = shi->mat;
+ GPUMaterial *mat = shi->gpumat;
MTex *mtex;
Tex *tex;
GPUNodeLink *texco, *tin, *trgb, *tnor, *tcol, *stencil, *tnorfac;
@@ -1035,9 +1048,9 @@ static void do_material_tex(GPUShadeInput *shi)
float one = 1.0f, norfac, ofs[3];
int tex_nr, rgbnor, talpha;
bool init_done = false;
- int iBumpSpacePrev = 0; /* Not necessary, quiting gcc warning. */
+ int iBumpSpacePrev = 0; /* Not necessary, quieting gcc warning. */
GPUNodeLink *vNorg, *vNacc, *fPrevMagnitude;
- int iFirstTimeNMap=1;
+ int iFirstTimeNMap = 1;
int found_deriv_map = 0;
GPU_link(mat, "set_value", GPU_uniform(&one), &stencil);
@@ -1047,44 +1060,46 @@ static void do_material_tex(GPUShadeInput *shi)
GPU_link(mat, "texco_object", GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
GPU_builtin(GPU_VIEW_POSITION), &texco_object);
- //GPU_link(mat, "texco_tangent", GPU_attribute(CD_TANGENT, ""), &texco_tangent);
+#if 0
+ GPU_link(mat, "texco_tangent", GPU_attribute(CD_TANGENT, ""), &texco_tangent);
+#endif
GPU_link(mat, "texco_global", GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
GPU_builtin(GPU_VIEW_POSITION), &texco_global);
orn= texco_norm;
/* go over texture slots */
- for (tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
+ for (tex_nr = 0; tex_nr < MAX_MTEX; tex_nr++) {
/* separate tex switching */
- if (ma->septex & (1<<tex_nr)) continue;
+ if (ma->septex & (1 << tex_nr)) continue;
if (ma->mtex[tex_nr]) {
- mtex= ma->mtex[tex_nr];
+ mtex = ma->mtex[tex_nr];
- tex= mtex->tex;
+ tex = mtex->tex;
if (tex == NULL) continue;
/* which coords */
- if (mtex->texco==TEXCO_ORCO)
- texco= texco_orco;
- else if (mtex->texco==TEXCO_OBJECT)
- texco= texco_object;
- else if (mtex->texco==TEXCO_NORM)
- texco= orn;
- else if (mtex->texco==TEXCO_TANGENT)
- texco= texco_object;
- else if (mtex->texco==TEXCO_GLOB)
- texco= texco_global;
- else if (mtex->texco==TEXCO_REFL) {
+ if (mtex->texco == TEXCO_ORCO)
+ texco = texco_orco;
+ else if (mtex->texco == TEXCO_OBJECT)
+ texco = texco_object;
+ else if (mtex->texco == TEXCO_NORM)
+ texco = orn;
+ else if (mtex->texco == TEXCO_TANGENT)
+ texco = texco_object;
+ else if (mtex->texco == TEXCO_GLOB)
+ texco = texco_global;
+ else if (mtex->texco == TEXCO_REFL) {
GPU_link(mat, "texco_refl", shi->vn, shi->view, &shi->ref);
- texco= shi->ref;
+ texco = shi->ref;
}
- else if (mtex->texco==TEXCO_UV) {
+ else if (mtex->texco == TEXCO_UV) {
if (1) { //!(texco_uv && strcmp(mtex->uvname, lastuvname) == 0)) {
GPU_link(mat, "texco_uv", GPU_attribute(CD_MTFACE, mtex->uvname), &texco_uv);
/*lastuvname = mtex->uvname;*/ /*UNUSED*/
}
- texco= texco_uv;
+ texco = texco_uv;
}
else
continue;
@@ -1096,8 +1111,8 @@ static void do_material_tex(GPUShadeInput *shi)
if (mtex->size[0] != 1.0f || mtex->size[1] != 1.0f || mtex->size[2] != 1.0f)
GPU_link(mat, "mtex_mapping_size", texco, GPU_uniform(mtex->size), &texco);
- ofs[0] = mtex->ofs[0] + 0.5f - 0.5f*mtex->size[0];
- ofs[1] = mtex->ofs[1] + 0.5f - 0.5f*mtex->size[1];
+ ofs[0] = mtex->ofs[0] + 0.5f - 0.5f * mtex->size[0];
+ ofs[1] = mtex->ofs[1] + 0.5f - 0.5f * mtex->size[1];
ofs[2] = 0.0f;
if (ofs[0] != 0.0f || ofs[1] != 0.0f || ofs[2] != 0.0f)
GPU_link(mat, "mtex_mapping_ofs", texco, GPU_uniform(ofs), &texco);
@@ -1106,7 +1121,7 @@ static void do_material_tex(GPUShadeInput *shi)
if (tex && tex->type == TEX_IMAGE && tex->ima) {
GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, false), &tin, &trgb);
- rgbnor= TEX_RGB;
+ rgbnor = TEX_RGB;
talpha = ((tex->imaflag & TEX_USEALPHA) && tex->ima && (tex->ima->flag & IMA_IGNORE_ALPHA) == 0);
}
@@ -1151,7 +1166,7 @@ static void do_material_tex(GPUShadeInput *shi)
GPU_link(mat, "set_value_one", &tin);
}
- if (tex->type==TEX_IMAGE)
+ if (tex->type == TEX_IMAGE)
if (GPU_material_do_color_management(mat))
GPU_link(mat, "srgb_to_linearrgb", tcol, &tcol);
@@ -1175,7 +1190,7 @@ static void do_material_tex(GPUShadeInput *shi)
}
if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && (mtex->mapto & MAP_NORM)) {
- if (tex->type==TEX_IMAGE) {
+ if (tex->type == TEX_IMAGE) {
found_deriv_map = tex->imaflag & TEX_DERIVATIVEMAP;
if (tex->imaflag & TEX_NORMALMAP) {
@@ -1225,44 +1240,43 @@ static void do_material_tex(GPUShadeInput *shi)
}
}
- else if ( (mtex->texflag & (MTEX_3TAP_BUMP|MTEX_5TAP_BUMP|MTEX_BICUBIC_BUMP)) || found_deriv_map) {
+ else if ((mtex->texflag & (MTEX_3TAP_BUMP | MTEX_5TAP_BUMP | MTEX_BICUBIC_BUMP)) || found_deriv_map) {
/* ntap bumpmap image */
int iBumpSpace;
float ima_x, ima_y;
float hScale;
- float imag_tspace_dimension_x = 1024.0f; // only used for texture space variant
+ float imag_tspace_dimension_x = 1024.0f; /* only used for texture space variant */
float aspect = 1.0f;
- GPUNodeLink *surf_pos = GPU_builtin(GPU_VIEW_POSITION);
GPUNodeLink *vR1, *vR2;
GPUNodeLink *dBs, *dBt, *fDet;
- hScale = 0.1; // compatibility adjustment factor for all bumpspace types
- if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE )
- hScale = 13.0f; // factor for scaling texspace bumps
+ hScale = 0.1; /* compatibility adjustment factor for all bumpspace types */
+ if (mtex->texflag & MTEX_BUMP_TEXTURESPACE)
+ hScale = 13.0f; /* factor for scaling texspace bumps */
else if (found_deriv_map!=0)
hScale = 1.0f;
- // resolve texture resolution
- if ( (mtex->texflag & MTEX_BUMP_TEXTURESPACE) || found_deriv_map ) {
- ImBuf *ibuf= BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL);
- ima_x= 512.0f; ima_y= 512.f; // prevent calling textureSize, glsl 1.3 only
+ /* resolve texture resolution */
+ if ((mtex->texflag & MTEX_BUMP_TEXTURESPACE) || found_deriv_map) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL);
+ ima_x = 512.0f; ima_y = 512.f; /* prevent calling textureSize, glsl 1.3 only */
if (ibuf) {
- ima_x= ibuf->x;
- ima_y= ibuf->y;
- aspect = ((float) ima_y) / ima_x;
+ ima_x = ibuf->x;
+ ima_y = ibuf->y;
+ aspect = (float)ima_y / ima_x;
}
BKE_image_release_ibuf(tex->ima, ibuf, NULL);
}
- // The negate on norfac is done because the
- // normal in the renderer points inward which corresponds
- // to inverting the bump map. Should this ever change
- // this negate must be removed.
+ /* The negate on norfac is done because the
+ * normal in the renderer points inward which corresponds
+ * to inverting the bump map. Should this ever change
+ * this negate must be removed. */
norfac = -hScale * mtex->norfac;
if (found_deriv_map) {
- float fVirtDim = sqrtf(fabsf(ima_x*mtex->size[0]*ima_y*mtex->size[1]));
+ float fVirtDim = sqrtf(fabsf(ima_x * mtex->size[0] * ima_y * mtex->size[1]));
norfac /= MAX2(fVirtDim, FLT_EPSILON);
}
@@ -1274,25 +1288,26 @@ static void do_material_tex(GPUShadeInput *shi)
if (GPU_link_changed(stencil))
GPU_link(mat, "math_multiply", tnorfac, stencil, &tnorfac);
- if ( !init_done ) {
- // copy shi->vn to vNorg and vNacc, set magnitude to 1
+ if (!init_done) {
+ /* copy shi->vn to vNorg and vNacc, set magnitude to 1 */
GPU_link(mat, "mtex_bump_normals_init", shi->vn, &vNorg, &vNacc, &fPrevMagnitude);
iBumpSpacePrev = 0;
init_done = true;
}
// find current bump space
- if ( mtex->texflag & MTEX_BUMP_OBJECTSPACE )
+ if (mtex->texflag & MTEX_BUMP_OBJECTSPACE)
iBumpSpace = 1;
- else if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE )
+ else if (mtex->texflag & MTEX_BUMP_TEXTURESPACE)
iBumpSpace = 2;
else
- iBumpSpace = 4; // ViewSpace
+ iBumpSpace = 4; /* ViewSpace */
- // re-initialize if bump space changed
- if ( iBumpSpacePrev != iBumpSpace ) {
-
- if ( mtex->texflag & MTEX_BUMP_OBJECTSPACE )
+ /* re-initialize if bump space changed */
+ if (iBumpSpacePrev != iBumpSpace) {
+ GPUNodeLink *surf_pos = GPU_builtin(GPU_VIEW_POSITION);
+
+ if (mtex->texflag & MTEX_BUMP_OBJECTSPACE)
GPU_link(mat, "mtex_bump_init_objspace",
surf_pos, vNorg,
GPU_builtin(GPU_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_OBJECT_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
@@ -1300,7 +1315,7 @@ static void do_material_tex(GPUShadeInput *shi)
&fPrevMagnitude, &vNacc,
&vR1, &vR2, &fDet);
- else if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE )
+ else if (mtex->texflag & MTEX_BUMP_TEXTURESPACE)
GPU_link(mat, "mtex_bump_init_texturespace",
surf_pos, vNorg,
fPrevMagnitude, vNacc,
@@ -1321,17 +1336,17 @@ static void do_material_tex(GPUShadeInput *shi)
if (found_deriv_map) {
GPU_link(mat, "mtex_bump_deriv",
texco, GPU_image(tex->ima, &tex->iuser, true), GPU_uniform(&ima_x), GPU_uniform(&ima_y), tnorfac,
- &dBs, &dBt );
+ &dBs, &dBt);
}
- else if ( mtex->texflag & MTEX_3TAP_BUMP)
+ else if (mtex->texflag & MTEX_3TAP_BUMP)
GPU_link(mat, "mtex_bump_tap3",
texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac,
- &dBs, &dBt );
- else if ( mtex->texflag & MTEX_5TAP_BUMP)
+ &dBs, &dBt);
+ else if (mtex->texflag & MTEX_5TAP_BUMP)
GPU_link(mat, "mtex_bump_tap5",
texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac,
- &dBs, &dBt );
- else if ( mtex->texflag & MTEX_BICUBIC_BUMP ) {
+ &dBs, &dBt);
+ else if (mtex->texflag & MTEX_BICUBIC_BUMP) {
if (GPU_bicubic_bump_support()) {
GPU_link(mat, "mtex_bump_bicubic",
texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac,
@@ -1345,18 +1360,18 @@ static void do_material_tex(GPUShadeInput *shi)
}
- if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE ) {
- float imag_tspace_dimension_y = aspect*imag_tspace_dimension_x;
+ if (mtex->texflag & MTEX_BUMP_TEXTURESPACE) {
+ float imag_tspace_dimension_y = aspect * imag_tspace_dimension_x;
GPU_link(mat, "mtex_bump_apply_texspace",
fDet, dBs, dBt, vR1, vR2,
GPU_image(tex->ima, &tex->iuser, true), texco,
GPU_uniform(&imag_tspace_dimension_x), GPU_uniform(&imag_tspace_dimension_y), vNacc,
- &vNacc, &shi->vn );
+ &vNacc, &shi->vn);
}
else
GPU_link(mat, "mtex_bump_apply",
fDet, dBs, dBt, vR1, vR2, vNacc,
- &vNacc, &shi->vn );
+ &vNacc, &shi->vn);
}
}
@@ -1434,7 +1449,6 @@ static void do_material_tex(GPUShadeInput *shi)
void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi)
{
- float hard = ma->har;
float one = 1.0f;
memset(shi, 0, sizeof(*shi));
@@ -1442,20 +1456,20 @@ void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi)
shi->gpumat = mat;
shi->mat = ma;
- GPU_link(mat, "set_rgb", GPU_uniform(&ma->r), &shi->rgb);
- GPU_link(mat, "set_rgb", GPU_uniform(&ma->specr), &shi->specrgb);
+ GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->r, GPU_DYNAMIC_MAT_DIFFRGB, NULL), &shi->rgb);
+ GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->specr, GPU_DYNAMIC_MAT_SPECRGB, NULL), &shi->specrgb);
GPU_link(mat, "shade_norm", GPU_builtin(GPU_VIEW_NORMAL), &shi->vn);
if (mat->alpha)
- GPU_link(mat, "set_value", GPU_uniform(&ma->alpha), &shi->alpha);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->alpha, GPU_DYNAMIC_MAT_ALPHA, NULL), &shi->alpha);
else
GPU_link(mat, "set_value", GPU_uniform(&one), &shi->alpha);
- GPU_link(mat, "set_value", GPU_uniform(&ma->ref), &shi->refl);
- GPU_link(mat, "set_value", GPU_uniform(&ma->spec), &shi->spec);
- GPU_link(mat, "set_value", GPU_uniform(&ma->emit), &shi->emit);
- GPU_link(mat, "set_value", GPU_uniform(&hard), &shi->har);
- GPU_link(mat, "set_value", GPU_uniform(&ma->amb), &shi->amb);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->ref, GPU_DYNAMIC_MAT_REF, NULL), &shi->refl);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->spec, GPU_DYNAMIC_MAT_SPEC, NULL), &shi->spec);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->emit, GPU_DYNAMIC_MAT_EMIT, NULL), &shi->emit);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform((float*)&ma->har, GPU_DYNAMIC_MAT_HARD, NULL), &shi->har);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->amb, GPU_DYNAMIC_MAT_AMB, NULL), &shi->amb);
GPU_link(mat, "set_value", GPU_uniform(&ma->spectra), &shi->spectra);
GPU_link(mat, "shade_view", GPU_builtin(GPU_VIEW_POSITION), &shi->view);
GPU_link(mat, "vcol_attribute", GPU_attribute(CD_MCOL, ""), &shi->vcol);
@@ -1464,13 +1478,39 @@ void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi)
GPU_link(mat, "texco_refl", shi->vn, shi->view, &shi->ref);
}
+void GPU_mist_update_enable(short enable)
+{
+ GPUWorld.mistenabled = (float)enable;
+}
+
+void GPU_mist_update_values(int type, float start, float dist, float inten, float color[3])
+{
+ GPUWorld.mistype = (float)type;
+ GPUWorld.miststart = start;
+ GPUWorld.mistdistance = dist;
+ GPUWorld.mistintensity = inten;
+ copy_v3_v3(GPUWorld.mistcol, color);
+ GPUWorld.mistcol[3] = 1.0f;
+}
+
+void GPU_horizon_update_color(float color[3])
+{
+ copy_v3_v3(GPUWorld.horicol, color);
+}
+
+void GPU_ambient_update_color(float color[3])
+{
+ copy_v3_v3(GPUWorld.ambcol, color);
+ GPUWorld.ambcol[3] = 1.0f;
+}
+
void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
{
- GPUMaterial *mat= shi->gpumat;
+ GPUMaterial *mat = shi->gpumat;
GPUNodeLink *emit, *ulinfac, *ulogfac, *mistfac;
- Material *ma= shi->mat;
- World *world= mat->scene->world;
- float linfac, logfac, misttype;
+ Material *ma = shi->mat;
+ World *world = mat->scene->world;
+ float linfac, logfac;
memset(shr, 0, sizeof(*shr));
@@ -1487,7 +1527,7 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
}
else {
if (GPU_link_changed(shi->emit) || ma->emit != 0.0f) {
- if ((ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL) {
+ if ((ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP)) == MA_VERTEXCOL) {
GPU_link(mat, "shade_add", shi->emit, shi->vcol, &emit);
GPU_link(mat, "shade_mul", emit, shi->rgb, &shr->diff);
}
@@ -1507,9 +1547,9 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
if (world) {
/* exposure correction */
- if (world->exp!=0.0f || world->range!=1.0f) {
- linfac= 1.0f + powf((2.0f*world->exp + 0.5f), -10);
- logfac= logf((linfac-1.0f)/linfac)/world->range;
+ if (world->exp != 0.0f || world->range != 1.0f) {
+ linfac = 1.0f + powf((2.0f * world->exp + 0.5f), -10);
+ logfac = logf((linfac - 1.0f) / linfac) / world->range;
GPU_link(mat, "set_value", GPU_uniform(&linfac), &ulinfac);
GPU_link(mat, "set_value", GPU_uniform(&logfac), &ulogfac);
@@ -1521,10 +1561,10 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
}
/* ambient color */
- if (world->ambr!=0.0f || world->ambg!=0.0f || world->ambb!=0.0f) {
- if (GPU_link_changed(shi->amb) || ma->amb != 0.0f)
- GPU_link(mat, "shade_maddf", shr->combined, GPU_uniform(&ma->amb),
- GPU_uniform(&world->ambr), &shr->combined);
+ if (GPU_link_changed(shi->amb) || ma->amb != 0.0f) {
+ GPU_link(mat, "shade_maddf", shr->combined, GPU_uniform(&ma->amb),
+ GPU_dynamic_uniform(GPUWorld.ambcol, GPU_DYNAMIC_AMBIENT_COLOR, NULL),
+ &shr->combined);
}
}
@@ -1546,21 +1586,22 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
if (ma->shade_flag & MA_OBCOLOR)
GPU_link(mat, "shade_obcolor", shr->combined, GPU_builtin(GPU_OBCOLOR), &shr->combined);
- if (world && (world->mode & WO_MIST) && !(ma->mode & MA_NOMIST)) {
- misttype = world->mistype;
-
+ if (!(ma->mode & MA_NOMIST)) {
GPU_link(mat, "shade_mist_factor", GPU_builtin(GPU_VIEW_POSITION),
- GPU_uniform(&world->miststa), GPU_uniform(&world->mistdist),
- GPU_uniform(&misttype), GPU_uniform(&world->misi), &mistfac);
+ GPU_dynamic_uniform(&GPUWorld.mistenabled, GPU_DYNAMIC_MIST_ENABLE, NULL),
+ GPU_dynamic_uniform(&GPUWorld.miststart, GPU_DYNAMIC_MIST_START, NULL),
+ GPU_dynamic_uniform(&GPUWorld.mistdistance, GPU_DYNAMIC_MIST_DISTANCE, NULL),
+ GPU_dynamic_uniform(&GPUWorld.mistype, GPU_DYNAMIC_MIST_TYPE, NULL),
+ GPU_dynamic_uniform(&GPUWorld.mistintensity, GPU_DYNAMIC_MIST_INTENSITY, NULL), &mistfac);
GPU_link(mat, "mix_blend", mistfac, shr->combined,
- GPU_uniform(&world->horr), &shr->combined);
+ GPU_dynamic_uniform(GPUWorld.mistcol, GPU_DYNAMIC_MIST_COLOR, NULL), &shr->combined);
}
if (!mat->alpha) {
if (world && (GPU_link_changed(shr->alpha) || ma->alpha != 1.0f))
- GPU_link(mat, "shade_world_mix", GPU_uniform(&world->horr),
- shr->combined, &shr->combined);
+ GPU_link(mat, "shade_world_mix", GPU_dynamic_uniform(GPUWorld.horicol, GPU_DYNAMIC_HORIZON_COLOR, NULL),
+ shr->combined, &shr->combined);
GPU_link(mat, "shade_alpha_opaque", shr->combined, &shr->combined);
}
@@ -1612,7 +1653,7 @@ GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma)
GPUNodeLink *outlink;
LinkData *link;
- for (link=ma->gpumaterial.first; link; link=link->next)
+ for (link = ma->gpumaterial.first; link; link = link->next)
if (((GPUMaterial*)link->data)->scene == scene)
return link->data;
@@ -1648,7 +1689,7 @@ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo)
LinkData *link;
GPUMaterial *mat;
- for (link=wo->gpumaterial.first; link; link=link->next)
+ for (link = wo->gpumaterial.first; link; link = link->next)
if (((GPUMaterial*)link->data)->scene == scene)
return link->data;
@@ -1688,7 +1729,7 @@ GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma)
GPUNodeLink *outlink;
LinkData *link;
- for (link=ma->gpumaterial.first; link; link=link->next)
+ for (link = ma->gpumaterial.first; link; link = link->next)
if (((GPUMaterial*)link->data)->scene == scene)
return link->data;
@@ -1745,15 +1786,15 @@ void GPU_materials_free(void)
World *wo;
extern Material defmaterial;
- for (ma=G.main->mat.first; ma; ma=ma->id.next)
+ for (ma = G.main->mat.first; ma; ma = ma->id.next)
GPU_material_free(&ma->gpumaterial);
- for (wo=G.main->world.first; wo; wo=wo->id.next)
+ for (wo = G.main->world.first; wo; wo = wo->id.next)
GPU_material_free(&wo->gpumaterial);
GPU_material_free(&defmaterial.gpumaterial);
- for (ob=G.main->object.first; ob; ob=ob->id.next)
+ for (ob = G.main->object.first; ob; ob = ob->id.next)
GPU_lamp_free(ob);
}
@@ -1795,11 +1836,11 @@ void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4])
void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy)
{
lamp->energy = energy;
- if (lamp->mode & LA_NEG) lamp->energy= -lamp->energy;
+ if (lamp->mode & LA_NEG) lamp->energy = -lamp->energy;
- lamp->col[0]= r;
- lamp->col[1]= g;
- lamp->col[2]= b;
+ lamp->col[0] = r;
+ lamp->col[1] = g;
+ lamp->col[2] = b;
}
void GPU_lamp_update_distance(GPULamp *lamp, float distance, float att1, float att2)
@@ -1829,11 +1870,11 @@ static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *l
lamp->type = la->type;
lamp->energy = la->energy;
- if (lamp->mode & LA_NEG) lamp->energy= -lamp->energy;
+ if (lamp->mode & LA_NEG) lamp->energy = -lamp->energy;
- lamp->col[0]= la->r;
- lamp->col[1]= la->g;
- lamp->col[2]= la->b;
+ lamp->col[0] = la->r;
+ lamp->col[1] = la->g;
+ lamp->col[2] = la->b;
GPU_lamp_update(lamp, ob->lay, (ob->restrictflag & OB_RESTRICT_RENDER), ob->obmat);
@@ -1842,20 +1883,20 @@ static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *l
if (lamp->spotsi > DEG2RADF(170.0f))
lamp->spotsi = DEG2RADF(170.0f);
lamp->spotsi = cosf(lamp->spotsi * 0.5f);
- lamp->spotbl= (1.0f - lamp->spotsi)*la->spotblend;
- lamp->k= la->k;
+ lamp->spotbl = (1.0f - lamp->spotsi) * la->spotblend;
+ lamp->k = la->k;
- lamp->dist= la->dist;
- lamp->falloff_type= la->falloff_type;
- lamp->att1= la->att1;
- lamp->att2= la->att2;
- lamp->curfalloff= la->curfalloff;
+ lamp->dist = la->dist;
+ lamp->falloff_type = la->falloff_type;
+ lamp->att1 = la->att1;
+ lamp->att2 = la->att2;
+ lamp->curfalloff = la->curfalloff;
/* initshadowbuf */
- lamp->bias = 0.02f*la->bias;
+ lamp->bias = 0.02f * la->bias;
lamp->size = la->bufsize;
- lamp->d= la->clipsta;
- lamp->clipend= la->clipend;
+ lamp->d = la->clipsta;
+ lamp->clipend = la->clipend;
/* arbitrary correction for the fact we do no soft transition */
lamp->bias *= 0.25f;
@@ -1868,23 +1909,23 @@ static void gpu_lamp_shadow_free(GPULamp *lamp)
{
if (lamp->tex) {
GPU_texture_free(lamp->tex);
- lamp->tex= NULL;
+ lamp->tex = NULL;
}
if (lamp->depthtex) {
GPU_texture_free(lamp->depthtex);
- lamp->depthtex= NULL;
+ lamp->depthtex = NULL;
}
if (lamp->fb) {
GPU_framebuffer_free(lamp->fb);
- lamp->fb= NULL;
+ lamp->fb = NULL;
}
if (lamp->blurtex) {
GPU_texture_free(lamp->blurtex);
- lamp->blurtex= NULL;
+ lamp->blurtex = NULL;
}
if (lamp->blurfb) {
GPU_framebuffer_free(lamp->blurfb);
- lamp->blurfb= NULL;
+ lamp->blurfb = NULL;
}
}
@@ -1894,7 +1935,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par)
GPULamp *lamp;
LinkData *link;
- for (link=ob->gpulamp.first; link; link=link->next) {
+ for (link = ob->gpulamp.first; link; link = link->next) {
lamp = (GPULamp*)link->data;
if (lamp->par == par && lamp->scene == scene)
@@ -1910,7 +1951,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par)
la = ob->data;
gpu_lamp_from_blender(scene, ob, par, la, lamp);
- if ((la->type==LA_SPOT && (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY))) || (la->type==LA_SUN && (la->mode & LA_SHAD_RAY))) {
+ if ((la->type == LA_SPOT && (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY))) || (la->type == LA_SUN && (la->mode & LA_SHAD_RAY))) {
/* opengl */
lamp->fb = GPU_framebuffer_create();
if (!lamp->fb) {
@@ -1955,7 +1996,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par)
return lamp;
}
- lamp->blurtex = GPU_texture_create_vsm_shadow_map(lamp->size*0.5, NULL);
+ lamp->blurtex = GPU_texture_create_vsm_shadow_map(lamp->size * 0.5, NULL);
if (!lamp->blurtex) {
gpu_lamp_shadow_free(lamp);
return lamp;
@@ -2016,7 +2057,7 @@ void GPU_lamp_free(Object *ob)
LinkData *nlink;
Material *ma;
- for (link=ob->gpulamp.first; link; link=link->next) {
+ for (link = ob->gpulamp.first; link; link = link->next) {
lamp = link->data;
while (lamp->materials.first) {
@@ -2264,7 +2305,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
break;
}
- if (uniform->type >= GPU_DYNAMIC_LAMP_FIRST && uniform->type <= GPU_DYNAMIC_LAMP_LAST)
+ if (GPU_DYNAMIC_GROUP_FROM_TYPE(uniform->type) == GPU_DYNAMIC_GROUP_LAMP)
uniform->lamp = input->dynamicdata;
}
@@ -2275,7 +2316,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
}
/* process builtin uniform */
- for (i=0; builtins[i].gputype; i++) {
+ for (i = 0; builtins[i].gputype; i++) {
if (mat->builtins & builtins[i].gputype) {
uniform = MEM_callocN(sizeof(GPUInputUniform), "GPUInputUniform");
uniform->type = builtins[i].dynamictype;
@@ -2289,14 +2330,14 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
/* TBD: remove the function that are not used in the main function */
liblen = (pass->libcode) ? strlen(pass->libcode) : 0;
fraglen = strlen(pass->fragmentcode);
- shader->fragment = (char *)MEM_mallocN(liblen+fraglen+1, "GPUFragShader");
+ shader->fragment = (char *)MEM_mallocN(liblen + fraglen + 1, "GPUFragShader");
if (pass->libcode)
memcpy(shader->fragment, pass->libcode, liblen);
memcpy(&shader->fragment[liblen], pass->fragmentcode, fraglen);
- shader->fragment[liblen+fraglen] = 0;
+ shader->fragment[liblen + fraglen] = 0;
// export the attribute
- for (i=0; i<mat->attribs.totlayer; i++) {
+ for (i = 0; i < mat->attribs.totlayer; i++) {
attribute = MEM_callocN(sizeof(GPUInputAttribute), "GPUInputAttribute");
attribute->type = mat->attribs.layer[i].type;
attribute->number = mat->attribs.layer[i].glindex;
@@ -2325,7 +2366,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
MEM_freeN(attribute);
}
- // export the vertex shader
+ /* export the vertex shader */
shader->vertex = BLI_strdup(pass->vertexcode);
}
@@ -2339,7 +2380,7 @@ void GPU_free_shader_export(GPUShaderExport *shader)
if (shader == NULL)
return;
- for (uniform = shader->uniforms.first; uniform; uniform=uniform->next)
+ for (uniform = shader->uniforms.first; uniform; uniform = uniform->next)
if (uniform->texpixels)
MEM_freeN(uniform->texpixels);
diff --git a/source/blender/gpu/intern/gpu_private.h b/source/blender/gpu/intern/gpu_private.h
index 11bc2bd3119..188a2d16abc 100644
--- a/source/blender/gpu/intern/gpu_private.h
+++ b/source/blender/gpu/intern/gpu_private.h
@@ -18,7 +18,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file gpu_extensions_private.h
+/** \file gpu_private.h
* \ingroup gpu
*/
diff --git a/source/blender/gpu/intern/gpu_simple_shader.c b/source/blender/gpu/intern/gpu_simple_shader.c
index 3fa5975ef15..b439a37f3c3 100644
--- a/source/blender/gpu/intern/gpu_simple_shader.c
+++ b/source/blender/gpu/intern/gpu_simple_shader.c
@@ -151,7 +151,8 @@ static GPUShader *gpu_simple_shader(int options)
shader = GPU_shader_create(
datatoc_gpu_shader_simple_vert_glsl,
datatoc_gpu_shader_simple_frag_glsl,
- NULL, defines);
+ NULL,
+ NULL, defines, 0, 0, 0);
if (shader) {
/* set texture map to first texture unit */
diff --git a/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl b/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl
new file mode 100644
index 00000000000..a94c823f408
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl
@@ -0,0 +1,32 @@
+!!ARBfp1.0
+PARAM dx = program.local[0];
+PARAM darkness = program.local[1];
+PARAM render = program.local[2];
+PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041};
+TEMP temp, shadow, flame, spec, value;
+TEX temp, fragment.texcoord[0], texture[0], 3D;
+TEX shadow, fragment.texcoord[0], texture[1], 3D;
+TEX flame, fragment.texcoord[0], texture[2], 3D;
+TEX spec, flame.r, texture[3], 1D;
+# unpremultiply volume texture
+RCP value.r, temp.a;
+MUL temp.r, temp.r, value.r;
+MUL temp.g, temp.g, value.r;
+MUL temp.b, temp.b, value.r;
+# calculate shading factor from density
+MUL value.r, temp.a, darkness.a;
+MUL value.r, value.r, dx.r;
+MUL value.r, value.r, f.r;
+EX2 value.r, -value.r;
+# alpha
+SUB temp.a, 1.0, value.r;
+# shade colors
+MUL temp.r, temp.r, shadow.r;
+MUL temp.g, temp.g, shadow.r;
+MUL temp.b, temp.b, shadow.r;
+MUL temp.r, temp.r, value.r;
+MUL temp.g, temp.g, value.r;
+MUL temp.b, temp.b, value.r;
+# for now this just replace smoke shading if rendering fire
+CMP result.color, render.r, temp, spec;
+END
diff --git a/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl b/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl
new file mode 100644
index 00000000000..04b171d24bd
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl
@@ -0,0 +1,27 @@
+!!ARBfp1.0
+PARAM dx = program.local[0];
+PARAM darkness = program.local[1];
+PARAM render = program.local[2];
+PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};
+TEMP temp, shadow, flame, spec, value;
+TEX temp, fragment.texcoord[0], texture[0], 3D;
+TEX shadow, fragment.texcoord[0], texture[1], 3D;
+TEX flame, fragment.texcoord[0], texture[2], 3D;
+TEX spec, flame.r, texture[3], 1D;
+# calculate shading factor from density
+MUL value.r, temp.a, darkness.a;
+MUL value.r, value.r, dx.r;
+MUL value.r, value.r, f.r;
+EX2 temp, -value.r;
+# alpha
+SUB temp.a, 1.0, temp.r;
+# shade colors
+MUL temp.r, temp.r, shadow.r;
+MUL temp.g, temp.g, shadow.r;
+MUL temp.b, temp.b, shadow.r;
+MUL temp.r, temp.r, darkness.r;
+MUL temp.g, temp.g, darkness.g;
+MUL temp.b, temp.b, darkness.b;
+# for now this just replace smoke shading if rendering fire
+CMP result.color, render.r, temp, spec;
+END
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
new file mode 100644
index 00000000000..e315d2fb97a
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
@@ -0,0 +1,166 @@
+/* amount of offset to move one pixel left-right.
+ * In second pass some dimensions are zero to control verical/horizontal convolution */
+uniform vec2 invrendertargetdim;
+
+uniform ivec2 rendertargetdim;
+
+/* color buffer */
+uniform sampler2D colorbuffer;
+uniform sampler2D farbuffer;
+uniform sampler2D nearbuffer;
+
+/* depth buffer */
+uniform sampler2D depthbuffer;
+
+uniform sampler2D cocbuffer;
+
+/* this includes focal distance in x and aperture size in y */
+uniform vec4 dof_params;
+
+/* viewvectors for reconstruction of world space */
+uniform vec4 viewvecs[3];
+
+/* initial uv coordinate */
+varying vec2 uvcoord;
+
+/* coordinate used for calculating radius et al set in geometry shader */
+varying vec2 particlecoord;
+varying vec4 color;
+
+/* downsampling coordinates */
+varying vec2 downsample1;
+varying vec2 downsample2;
+varying vec2 downsample3;
+varying vec2 downsample4;
+
+#define M_PI 3.1415926535897932384626433832795
+
+/* calculate 4 samples at once */
+vec4 calculate_coc(in vec4 zdepth)
+{
+ vec4 coc = dof_params.x * (vec4(dof_params.y) / zdepth - vec4(1.0));
+
+ /* multiply by 1.0 / sensor size to get the normalized size */
+ return coc * dof_params.z;
+}
+
+#define THRESHOLD 0.0
+
+/* downsample the color buffer to half resolution */
+void downsample_pass()
+{
+ vec4 depth;
+ vec4 zdepth;
+ vec4 coc;
+ float far_coc, near_coc;
+
+ /* custom downsampling. We need to be careful to sample nearest here to avoid leaks */
+ vec4 color1 = texture2D(colorbuffer, downsample1);
+ vec4 color2 = texture2D(colorbuffer, downsample2);
+ vec4 color3 = texture2D(colorbuffer, downsample3);
+ vec4 color4 = texture2D(colorbuffer, downsample4);
+
+ depth.r = texture2D(depthbuffer, downsample1).r;
+ depth.g = texture2D(depthbuffer, downsample2).r;
+ depth.b = texture2D(depthbuffer, downsample3).r;
+ depth.a = texture2D(depthbuffer, downsample4).r;
+
+ zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth);
+ coc = calculate_coc(zdepth);
+ vec4 coc_far = -coc;
+
+ /* now we need to write the near-far fields premultiplied by the coc */
+ vec4 near_weights = vec4((coc.x >= THRESHOLD) ? 1.0 : 0.0, (coc.y >= THRESHOLD) ? 1.0 : 0.0,
+ (coc.z >= THRESHOLD) ? 1.0 : 0.0, (coc.w >= THRESHOLD) ? 1.0 : 0.0);
+ vec4 far_weights = vec4((coc_far.x >= THRESHOLD) ? 1.0 : 0.0, (coc_far.y >= THRESHOLD) ? 1.0 : 0.0,
+ (coc_far.z >= THRESHOLD) ? 1.0 : 0.0, (coc_far.w >= THRESHOLD) ? 1.0 : 0.0);
+
+ near_coc = max(max(max(coc.x, coc.y), max(coc.z, coc.w)), 0.0);
+ far_coc = max(max(max(coc_far.x, coc_far.y), max(coc_far.z, coc_far.w)), 0.0);
+
+ float norm_near = dot(near_weights, vec4(1.0));
+ float norm_far = dot(far_weights, vec4(1.0));
+
+ /* now write output to weighted buffers. */
+ gl_FragData[0] = color1 * near_weights.x + color2 * near_weights.y + color3 * near_weights.z +
+ color4 * near_weights.w;
+ gl_FragData[1] = color1 * far_weights.x + color2 * far_weights.y + color3 * far_weights.z +
+ color4 * far_weights.w;
+
+ if (norm_near > 0.0)
+ gl_FragData[0] /= norm_near;
+ if (norm_far > 0.0)
+ gl_FragData[1] /= norm_far;
+ gl_FragData[2] = vec4(near_coc, far_coc, 0.0, 1.0);
+}
+
+/* accumulate color in the near/far blur buffers */
+void accumulate_pass(void) {
+ float theta = atan(particlecoord.y, particlecoord.x);
+ float r;
+
+ if (dof_params.w == 0.0)
+ r = 1.0;
+ else
+ r = cos(M_PI / dof_params.w) / (cos(theta - (2.0 * M_PI / dof_params.w) * floor((dof_params.w * theta + M_PI) / (2.0 * M_PI))));
+
+ if (dot(particlecoord, particlecoord) > r * r)
+ discard;
+
+ gl_FragData[0] = color;
+}
+#define MERGE_THRESHOLD 4.0
+
+/* combine the passes, */
+void final_pass(void) {
+ vec4 finalcolor;
+ float totalweight;
+ float depth = texture2D(depthbuffer, uvcoord).r;
+
+ vec4 zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), vec4(depth));
+ float coc_near = calculate_coc(zdepth).r;
+ float coc_far = max(-coc_near, 0.0);
+ coc_near = max(coc_near, 0.0);
+
+ vec4 farcolor = texture2D(farbuffer, uvcoord);
+ float farweight = farcolor.a;
+ if (farweight > 0.0)
+ farcolor /= farweight;
+ vec4 nearcolor = texture2D(nearbuffer, uvcoord);
+
+ vec4 srccolor = texture2D(colorbuffer, uvcoord);
+
+ vec4 coc = texture2D(cocbuffer, uvcoord);
+
+ float mixfac = smoothstep(1.0, MERGE_THRESHOLD, coc_far);
+ finalcolor = mix(srccolor, farcolor, mixfac);
+
+ farweight = mix(1.0, farweight, mixfac);
+
+ float nearweight = nearcolor.a;
+ if (nearweight > 0.0) {
+ nearcolor /= nearweight;
+ }
+
+ if (coc_near > 1.0) {
+ nearweight = 1.0;
+ finalcolor = nearcolor;
+ }
+ else {
+ totalweight = nearweight + farweight;
+ finalcolor = mix(finalcolor, nearcolor, nearweight / totalweight);
+ }
+
+ gl_FragData[0] = finalcolor;
+}
+
+void main()
+{
+#ifdef FIRST_PASS
+ downsample_pass();
+#elif defined(SECOND_PASS)
+ accumulate_pass();
+#elif defined(THIRD_PASS)
+ final_pass();
+#endif
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl
new file mode 100644
index 00000000000..7918122a681
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl
@@ -0,0 +1,50 @@
+uniform ivec2 rendertargetdim;
+uniform sampler2D colorbuffer;
+
+uniform vec2 layerselection;
+
+uniform sampler2D cocbuffer;
+
+/* initial uv coordinate */
+varying in vec2 uvcoord[1];
+varying out vec2 particlecoord;
+varying out vec4 color;
+
+
+#define M_PI 3.1415926535897932384626433832795
+
+void main(void)
+{
+ vec4 coc = texture2DLod(cocbuffer, uvcoord[0], 0.0);
+
+ float offset_val = dot(coc.rg, layerselection);
+ if (offset_val < 1.0)
+ return;
+
+ vec4 colortex = texture2DLod(colorbuffer, uvcoord[0], 0.0);
+
+ /* find the area the pixel will cover and divide the color by it */
+ float alpha = 1.0 / (offset_val * offset_val * M_PI);
+ colortex *= alpha;
+ colortex.a = alpha;
+
+ vec2 offset_far = vec2(offset_val * 0.5) / vec2(rendertargetdim.x, rendertargetdim.y);
+
+ gl_Position = gl_PositionIn[0] + vec4(-offset_far.x, -offset_far.y, 0.0, 0.0);
+ color = colortex;
+ particlecoord = vec2(-1.0, -1.0);
+ EmitVertex();
+ gl_Position = gl_PositionIn[0] + vec4(-offset_far.x, offset_far.y, 0.0, 0.0);
+ particlecoord = vec2(-1.0, 1.0);
+ color = colortex;
+ EmitVertex();
+ gl_Position = gl_PositionIn[0] + vec4(offset_far.x, -offset_far.y, 0.0, 0.0);
+ particlecoord = vec2(1.0, -1.0);
+ color = colortex;
+ EmitVertex();
+ gl_Position = gl_PositionIn[0] + vec4(offset_far.x, offset_far.y, 0.0, 0.0);
+ particlecoord = vec2(1.0, 1.0);
+ color = colortex;
+ EmitVertex();
+ EndPrimitive();
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl
new file mode 100644
index 00000000000..09a0c75facc
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl
@@ -0,0 +1,58 @@
+uniform vec2 invrendertargetdim;
+uniform ivec2 rendertargetdim;
+/* initial uv coordinate */
+varying vec2 uvcoord;
+
+/* coordinate used for calculating radius et al set in geometry shader */
+varying vec2 particlecoord;
+
+/* downsampling coordinates */
+varying vec2 downsample1;
+varying vec2 downsample2;
+varying vec2 downsample3;
+varying vec2 downsample4;
+
+void vert_dof_downsample()
+{
+ /* gather pixels from neighbors. half dimensions means we offset half a pixel to
+ * get this right though it's possible we may lose a pixel at some point */
+ downsample1 = gl_MultiTexCoord0.xy + vec2(-0.5, -0.5) * invrendertargetdim;
+ downsample2 = gl_MultiTexCoord0.xy + vec2(-0.5, 0.5) * invrendertargetdim;
+ downsample3 = gl_MultiTexCoord0.xy + vec2(0.5, 0.5) * invrendertargetdim;
+ downsample4 = gl_MultiTexCoord0.xy + vec2(0.5, -0.5) * invrendertargetdim;
+
+ gl_Position = gl_Vertex;
+}
+
+/* geometry shading pass, calculate a texture coordinate based on the indexed id */
+void vert_dof_coc_scatter_pass()
+{
+ vec2 pixel = vec2(rendertargetdim.x, rendertargetdim.y);
+ /* some math to get the target pixel */
+ int row = gl_InstanceID / rendertargetdim.x;
+ int column = gl_InstanceID % rendertargetdim.x;
+ uvcoord = (vec2(column, row) + vec2(0.5)) / pixel;
+
+ vec2 pos = uvcoord * 2.0 - vec2(1.0);
+ gl_Position = vec4(pos.x, pos.y, 0.0, 1.0);
+
+// uvcoord = vec2(0.5, 0.5);
+// gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
+}
+
+void vert_dof_final()
+{
+ uvcoord = gl_MultiTexCoord0.xy;
+ gl_Position = gl_Vertex;
+}
+
+void main()
+{
+#if defined(FIRST_PASS)
+ vert_dof_downsample();
+#elif defined(SECOND_PASS)
+ vert_dof_coc_scatter_pass();
+#else
+ vert_dof_final();
+#endif
+} \ No newline at end of file
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl b/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl
index 6c4bf3bb7a0..1dc49b52be1 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl
@@ -1,11 +1,3 @@
-vec3 calculate_view_space_normal(in vec3 viewposition)
-{
- vec3 normal = cross(normalize(dFdx(viewposition)),
- normalize(dFdy(viewposition)));
- normalize(normal);
- return normal;
-}
-
/* simple depth reconstruction, see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer
* we change the factors from the article to fit the OpennGL model. */
#ifdef PERSP_MATRIX
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
index 5e2512b6a46..494a74dcdf8 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
@@ -15,7 +15,7 @@ varying vec4 uvcoordsvar;
/* ssao_params.x : pixel scale for the ssao radious */
/* ssao_params.y : factor for the ssao darkening */
uniform vec4 ssao_params;
-uniform vec4 ssao_sample_params;
+uniform vec3 ssao_sample_params;
uniform vec4 ssao_color;
/* store the view space vectors for the corners of the view frustum here.
@@ -23,10 +23,18 @@ uniform vec4 ssao_color;
* see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
uniform vec4 viewvecs[3];
+vec3 calculate_view_space_normal(in vec3 viewposition)
+{
+ vec3 normal = cross(normalize(dFdx(viewposition)),
+ ssao_params.w * normalize(dFdy(viewposition)));
+ normalize(normal);
+ return normal;
+}
+
float calculate_ssao_factor(float depth)
{
/* take the normalized ray direction here */
- vec2 rotX = texture2D(jitter_tex, uvcoordsvar.xy * ssao_sample_params.zw).rg;
+ vec2 rotX = texture2D(jitter_tex, uvcoordsvar.xy * ssao_sample_params.yz).rg;
vec2 rotY = vec2(-rotX.y, rotX.x);
/* occlusion is zero in full depth */
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 945b7ef303f..8edffe787eb 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -698,22 +698,7 @@ void mix_linear(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
fac = clamp(fac, 0.0, 1.0);
- outcol = col1;
-
- if(col2.r > 0.5)
- outcol.r= col1.r + fac*(2.0*(col2.r - 0.5));
- else
- outcol.r= col1.r + fac*(2.0*(col2.r) - 1.0);
-
- if(col2.g > 0.5)
- outcol.g= col1.g + fac*(2.0*(col2.g - 0.5));
- else
- outcol.g= col1.g + fac*(2.0*(col2.g) - 1.0);
-
- if(col2.b > 0.5)
- outcol.b= col1.b + fac*(2.0*(col2.b - 0.5));
- else
- outcol.b= col1.b + fac*(2.0*(col2.b) - 1.0);
+ outcol = col1 + fac*(2.0*(col2 - vec4(0.5)));
}
void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha)
@@ -2114,18 +2099,23 @@ void shade_exposure_correct(vec3 col, float linfac, float logfac, out vec3 outco
outcol = linfac*(1.0 - exp(col*logfac));
}
-void shade_mist_factor(vec3 co, float miststa, float mistdist, float misttype, float misi, out float outfac)
+void shade_mist_factor(vec3 co, float enable, float miststa, float mistdist, float misttype, float misi, out float outfac)
{
- float fac, zcor;
+ if(enable == 1.0) {
+ float fac, zcor;
- zcor = (gl_ProjectionMatrix[3][3] == 0.0)? length(co): -co[2];
-
- fac = clamp((zcor-miststa)/mistdist, 0.0, 1.0);
- if(misttype == 0.0) fac *= fac;
- else if(misttype == 1.0);
- else fac = sqrt(fac);
+ zcor = (gl_ProjectionMatrix[3][3] == 0.0)? length(co): -co[2];
+
+ fac = clamp((zcor - miststa) / mistdist, 0.0, 1.0);
+ if(misttype == 0.0) fac *= fac;
+ else if(misttype == 1.0);
+ else fac = sqrt(fac);
- outfac = 1.0 - (1.0-fac)*(1.0-misi);
+ outfac = 1.0 - (1.0 - fac) * (1.0 - misi);
+ }
+ else {
+ outfac = 0.0;
+ }
}
void shade_world_mix(vec3 hor, vec4 col, out vec4 outcol)
diff --git a/source/blender/ikplugin/BIK_api.h b/source/blender/ikplugin/BIK_api.h
index 95b1dafd129..177be074897 100644
--- a/source/blender/ikplugin/BIK_api.h
+++ b/source/blender/ikplugin/BIK_api.h
@@ -41,7 +41,6 @@ extern "C" {
struct Object;
struct bPoseChannel;
struct bPose;
-struct bArmature;
struct Scene;
struct bConstraint;
diff --git a/source/blender/ikplugin/CMakeLists.txt b/source/blender/ikplugin/CMakeLists.txt
index 0a0e0e664b4..8991e113410 100644
--- a/source/blender/ikplugin/CMakeLists.txt
+++ b/source/blender/ikplugin/CMakeLists.txt
@@ -23,6 +23,8 @@
#
# ***** END GPL LICENSE BLOCK *****
+remove_extra_strict_flags()
+
set(INC
.
../blenkernel
@@ -59,7 +61,7 @@ if(WITH_IK_ITASC)
../../../intern/itasc
)
list(APPEND INC_SYS
- ../../../extern/Eigen3
+ ${EIGEN3_INCLUDE_DIRS}
)
list(APPEND SRC
intern/itasc_plugin.cpp
diff --git a/source/blender/ikplugin/intern/ikplugin_api.h b/source/blender/ikplugin/intern/ikplugin_api.h
index 53d9da8e614..cd32bf26242 100644
--- a/source/blender/ikplugin/intern/ikplugin_api.h
+++ b/source/blender/ikplugin/intern/ikplugin_api.h
@@ -40,7 +40,6 @@ extern "C" {
struct Object;
struct bPoseChannel;
-struct bArmature;
struct Scene;
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index afff97a8409..d4814a4e3a2 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -89,8 +89,7 @@ struct IK_Target;
typedef void (*ErrorCallback)(const iTaSC::ConstraintValues *values, unsigned int nvalues, IK_Target *iktarget);
// one structure for each target in the scene
-struct IK_Target
-{
+struct IK_Target {
struct Scene *blscene;
iTaSC::MovingFrame* target;
iTaSC::ConstraintSet* constraint;
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt
index e8977913948..bdd8230a6ff 100644
--- a/source/blender/imbuf/CMakeLists.txt
+++ b/source/blender/imbuf/CMakeLists.txt
@@ -62,9 +62,11 @@ set(SRC
intern/rectop.c
intern/rotate.c
intern/scaling.c
+ intern/stereoimbuf.c
intern/targa.c
intern/thumbs.c
intern/thumbs_blend.c
+ intern/thumbs_font.c
intern/util.c
intern/writeimage.c
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 262e87bedf5..59df8334099 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -47,10 +47,6 @@ struct ColormanageProcessor;
struct EnumPropertyItem;
struct ImBuf;
struct Main;
-struct rcti;
-struct PartialBufferUpdateContext;
-struct wmWindow;
-struct Scene;
struct ImageFormatData;
struct ColorSpace;
@@ -71,6 +67,9 @@ void IMB_colormanagement_assign_rect_colorspace(struct ImBuf *ibuf, const char *
const char *IMB_colormanagement_get_float_colorspace(struct ImBuf *ibuf);
const char *IMB_colormanagement_get_rect_colorspace(struct ImBuf *ibuf);
+float IMB_colormanagement_get_luminance(const float rgb[3]);
+unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3]);
+
/* ** Color space transformation functions ** */
void IMB_colormanagement_transform(float *buffer, int width, int height, int channels,
const char *from_colorspace, const char *to_colorspace, bool predivide);
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 447a14b95c3..2a976092fd3 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -38,21 +38,21 @@
* \page IMB Imbuf module external interface
*
*
- * \section about About the IMB module
+ * \section imb_about About the IMB module
*
* External interface of the IMage Buffer module. This module offers
* import/export of several graphical file formats. It offers the
* ImBuf type as a common structure to refer to different graphical
* file formats, and to enable a uniform way of handling them.
*
- * \section issues Known issues with IMB
+ * \section imb_issues Known issues with IMB
*
* - imbuf is written in C.
* - Endianness issues are dealt with internally.
* - File I/O must be done externally. The module uses FILE*'s to
* direct input/output.
*
- * \section dependencies Dependencies
+ * \section imb_dependencies Dependencies
*
* IMB needs:
* - \ref DNA module
@@ -89,6 +89,13 @@ struct ColorManagedDisplay;
struct GSet;
/**
*
+ * \attention defined in DNA_scene_types.h
+ */
+struct ImageFormatData;
+struct Stereo3dFormat;
+
+/**
+ *
* \attention Defined in allocimbuf.c
*/
void IMB_init(void);
@@ -240,6 +247,7 @@ typedef enum IMB_Proxy_Size {
/* defaults to BL_proxy within the directory of the animation */
void IMB_anim_set_index_dir(struct anim *anim, const char *dir);
+void IMB_anim_get_fname(struct anim *anim, char *file, int size);
int IMB_anim_index_get_frame_index(struct anim *anim, IMB_Timecode_Type tc,
int position);
@@ -271,17 +279,17 @@ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc);
* and frs_sec and frs_sec_base untouched if none available!)
*/
bool IMB_anim_get_fps(struct anim *anim,
- short *frs_sec, float *frs_sec_base);
+ short *frs_sec, float *frs_sec_base, bool no_av_base);
/**
*
* \attention Defined in anim_movie.c
*/
struct anim *IMB_open_anim(const char *name, int ib_flags, int streamindex, char colorspace[IM_MAX_SPACE]);
+void IMB_suffix_anim(struct anim *anim, const char *suffix);
void IMB_close_anim(struct anim *anim);
void IMB_close_anim_proxies(struct anim *anim);
-
/**
*
* \attention Defined in anim_movie.c
@@ -376,6 +384,7 @@ void IMB_scaleImBuf_threaded(struct ImBuf *ibuf, unsigned int newx, unsigned int
* \attention Defined in writeimage.c
*/
short IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags);
+struct ImBuf *IMB_prepare_write_ImBuf(const bool isfloat, struct ImBuf *ibuf);
/**
*
@@ -398,6 +407,12 @@ int imb_get_anim_type(const char *name);
/**
*
+ * \attention Defined in util.c
+ */
+bool IMB_isfloat(struct ImBuf *ibuf);
+
+/**
+ *
* \attention Defined in divers.c
*/
void IMB_de_interlace(struct ImBuf *ibuf);
@@ -452,6 +467,7 @@ void bilinear_interpolation(struct ImBuf *in, struct ImBuf *out, float u, float
void bicubic_interpolation_color(struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v);
void nearest_interpolation_color(struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v);
+void nearest_interpolation_color_wrap(struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v);
void bilinear_interpolation_color(struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v);
void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char col[4], float col_float[4], float u, float v);
@@ -532,8 +548,21 @@ void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height,
const float col[4], struct ColorManagedDisplay *display,
int x1, int y1, int x2, int y2);
-/* defined in metadata.c */
+/**
+ *
+ * \attention Defined in metadata.c
+ */
+/** read the field from the image info into the field
+ * \param img - the ImBuf that contains the image data
+ * \param key - the key of the field
+ * \param value - the data in the field, first one found with key is returned,
+ * memory has to be allocated by user.
+ * \param len - length of value buffer allocated by user.
+ * \return - 1 (true) if ImageInfo present and value for the key found, 0 (false) otherwise
+ */
+bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *value, const size_t len);
bool IMB_metadata_change_field(struct ImBuf *img, const char *key, const char *field);
+void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb);
/* exported for image tools in blender, to quickly allocate 32 bits rect */
bool imb_addrectImBuf(struct ImBuf *ibuf);
@@ -556,5 +585,27 @@ void IMB_processor_apply_threaded(int buffer_lines, int handle_size, void *init_
void IMB_ffmpeg_init(void);
const char *IMB_ffmpeg_last_error(void);
-#endif
+/**
+ *
+ * \attention defined in stereoimbuf.c
+ */
+void IMB_stereo3d_write_dimensions(
+ const char mode, const bool is_squeezed, const size_t width, const size_t height,
+ size_t *r_width, size_t *r_height);
+void IMB_stereo3d_read_dimensions(
+ const char mode, const bool is_squeezed, const size_t width, const size_t height,
+ size_t *r_width, size_t *r_height);
+int *IMB_stereo3d_from_rect(
+ struct ImageFormatData *im_format, const size_t x, const size_t y, const size_t channels,
+ int *rect_left, int *rect_right);
+float *IMB_stereo3d_from_rectf(
+ struct ImageFormatData *im_format, const size_t x, const size_t y, const size_t channels,
+ float *rectf_left, float *rectf_right);
+struct ImBuf *IMB_stereo3d_ImBuf(
+ struct ImageFormatData *im_format,
+ struct ImBuf *ibuf_left, struct ImBuf *ibuf_right);
+void IMB_ImBufFromStereo3d(
+ struct Stereo3dFormat *s3d, struct ImBuf *ibuf_stereo,
+ struct ImBuf **r_ibuf_left, struct ImBuf **r_ibuf_right);
+#endif
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 867c4a826fe..862c587f75b 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -110,7 +110,7 @@ typedef struct ImBuf {
int index; /* reference index for ImBuf lists */
int userflags; /* used to set imbuf to dirty and other stuff */
struct IDProperty *metadata; /* image metadata */
- void *userdata; /* temporary storage, only used by baking at the moment */
+ void *userdata; /* temporary storage */
/* file information */
int ftype; /* file type we are going to save as */
@@ -172,6 +172,8 @@ typedef struct ImBuf {
#define IB_alphamode_premul (1 << 12) /* indicates whether image on disk have premul alpha */
#define IB_alphamode_detect (1 << 13) /* if this flag is set, alpha mode would be guessed from file */
#define IB_ignore_alpha (1 << 14) /* ignore alpha on load and substitude it with 1.0f */
+#define IB_thumbnail (1 << 15)
+#define IB_multiview (1 << 16)
/*
* The bit flag is stored in the ImBuf.ftype variable.
@@ -202,7 +204,7 @@ typedef struct ImBuf {
#define OPENEXR (1 << 22)
#define OPENEXR_HALF (1 << 8 )
-#define OPENEXR_COMPRESS (7)
+#define OPENEXR_COMPRESS (15)
#ifdef WITH_CINEON
#define CINEON (1 << 21)
diff --git a/source/blender/imbuf/IMB_thumbs.h b/source/blender/imbuf/IMB_thumbs.h
index 9fc075e4e8b..f2f75973bcd 100644
--- a/source/blender/imbuf/IMB_thumbs.h
+++ b/source/blender/imbuf/IMB_thumbs.h
@@ -54,13 +54,19 @@ typedef enum ThumbSize {
typedef enum ThumbSource {
THB_SOURCE_IMAGE,
THB_SOURCE_MOVIE,
- THB_SOURCE_BLEND
+ THB_SOURCE_BLEND,
+ THB_SOURCE_FONT,
} ThumbSource;
/* don't generate thumbs for images bigger then this (100mb) */
#define THUMB_SIZE_MAX (100 * 1024 * 1024)
-// IB_metadata
+#define PREVIEW_RENDER_DEFAULT_HEIGHT 128
+
+/* Note this can also be used as versionning system,
+ * to force refreshing all thumbnails if e.g. we change some thumb generating code or so.
+ * Only used by fonts so far. */
+#define THUMB_DEFAULT_HASH "00000000000000000000000000000000"
/* create thumbnail for file and returns new imbuf for thumbnail */
ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, ImBuf *ibuf);
@@ -78,8 +84,12 @@ ImBuf *IMB_thumb_manage(const char *path, ThumbSize size, ThumbSource source);
void IMB_thumb_makedirs(void);
/* special function for loading a thumbnail embedded into a blend file */
-ImBuf *IMB_loadblend_thumb(const char *path);
-void IMB_overlayblend_thumb(unsigned int *thumb, int width, int height, float aspect);
+ImBuf *IMB_thumb_load_blend(const char *path);
+void IMB_thumb_overlay_blend(unsigned int *thumb, int width, int height, float aspect);
+
+/* special function for previewing fonts */
+ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned int y);
+bool IMB_thumb_load_font_get_hash(char *r_hash);
#ifdef __cplusplus
}
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index ed349e8f7eb..1fc43e22f68 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -194,6 +194,7 @@ struct anim {
struct anim_index *curr_idx[IMB_TC_MAX_SLOT];
char colorspace[64];
+ char suffix[64]; /* MAX_NAME - multiview */
};
#endif
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index 9327c15c415..332878b6067 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -40,7 +40,7 @@ typedef struct ImFileType {
int (*is_a)(unsigned char *buf);
int (*is_a_filepath)(const char *name);
- int (*ftype)(struct ImFileType *type, struct ImBuf *ibuf);
+ int (*ftype)(const struct ImFileType *type, struct ImBuf *ibuf);
struct ImBuf *(*load)(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]);
struct ImBuf *(*load_filepath)(const char *name, int flags, char colorspace[IM_MAX_SPACE]);
int (*save)(struct ImBuf *ibuf, const char *name, int flags);
@@ -51,8 +51,8 @@ typedef struct ImFileType {
int default_save_role;
} ImFileType;
-extern ImFileType IMB_FILE_TYPES[];
-extern ImFileType *IMB_FILE_TYPES_LAST;
+extern const ImFileType IMB_FILE_TYPES[];
+extern const ImFileType *IMB_FILE_TYPES_LAST;
void imb_filetypes_init(void);
void imb_filetypes_exit(void);
@@ -88,7 +88,7 @@ int imb_savejp2(struct ImBuf *ibuf, const char *name, int flags);
/* jpeg */
int imb_is_a_jpeg(unsigned char *mem);
int imb_savejpeg(struct ImBuf *ibuf, const char *name, int flags);
-struct ImBuf *imb_load_jpeg (unsigned char *buffer, size_t size, int flags, char colorspace[IM_MAX_SPACE]);
+struct ImBuf *imb_load_jpeg(unsigned char *buffer, size_t size, int flags, char colorspace[IM_MAX_SPACE]);
/* bmp */
int imb_is_a_bmp(unsigned char *buf);
diff --git a/source/blender/imbuf/intern/IMB_metadata.h b/source/blender/imbuf/intern/IMB_metadata.h
index 5d4a0028ee1..bc0b2c70ecb 100644
--- a/source/blender/imbuf/intern/IMB_metadata.h
+++ b/source/blender/imbuf/intern/IMB_metadata.h
@@ -47,16 +47,6 @@ struct ImBuf;
/* free blender ImMetaData struct */
void IMB_metadata_free(struct ImBuf *img);
-/** read the field from the image info into the field
- * \param img - the ImBuf that contains the image data
- * \param key - the key of the field
- * \param value - the data in the field, first one found with key is returned,
- * memory has to be allocated by user.
- * \param len - length of value buffer allocated by user.
- * \return - 1 (true) if ImageInfo present and value for the key found, 0 (false) otherwise
- */
-bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *value, const size_t len);
-
/** set user data in the ImMetaData struct, which has to be allocated with IMB_metadata_create
* before calling this function.
* \param img - the ImBuf that contains the image data
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index b28d19e3e15..79f869968d3 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -210,6 +210,8 @@ ImBuf *IMB_makeSingleUser(ImBuf *ibuf)
rval = IMB_dupImBuf(ibuf);
+ IMB_metadata_copy(rval, ibuf);
+
IMB_freeImBuf(ibuf);
return rval;
@@ -465,10 +467,10 @@ ImBuf *IMB_dupImBuf(ImBuf *ibuf1)
if (ibuf2 == NULL) return NULL;
if (flags & IB_rect)
- memcpy(ibuf2->rect, ibuf1->rect, x * y * sizeof(int));
+ memcpy(ibuf2->rect, ibuf1->rect, ((size_t)x) * y * sizeof(int));
if (flags & IB_rectfloat)
- memcpy(ibuf2->rect_float, ibuf1->rect_float, ibuf1->channels * x * y * sizeof(float));
+ memcpy(ibuf2->rect_float, ibuf1->rect_float, ((size_t)ibuf1->channels) * x * y * sizeof(float));
if (ibuf1->encodedbuffer) {
ibuf2->encodedbuffersize = ibuf1->encodedbuffersize;
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index ffdecb793aa..aee83c39b29 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -288,6 +288,11 @@ struct anim *IMB_open_anim(const char *name, int ib_flags, int streamindex, char
return(anim);
}
+void IMB_suffix_anim(struct anim *anim, const char *suffix)
+{
+ BLI_strncpy(anim->suffix, suffix, sizeof(anim->suffix));
+}
+
#ifdef WITH_AVI
static int startavi(struct anim *anim)
{
@@ -1422,11 +1427,17 @@ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc)
}
bool IMB_anim_get_fps(struct anim *anim,
- short *frs_sec, float *frs_sec_base)
+ short *frs_sec, float *frs_sec_base, bool no_av_base)
{
if (anim->frs_sec) {
*frs_sec = anim->frs_sec;
*frs_sec_base = anim->frs_sec_base;
+#ifdef WITH_FFMPEG
+ if (no_av_base)
+ *frs_sec_base /= AV_TIME_BASE;
+#else
+ (void)no_av_base;
+#endif
return true;
}
return false;
diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c
index f8cf1164e4f..298e2da965f 100644
--- a/source/blender/imbuf/intern/bmp.c
+++ b/source/blender/imbuf/intern/bmp.c
@@ -105,7 +105,7 @@ static int checkbmp(unsigned char *mem)
if (u >= sizeof(BMPINFOHEADER)) {
if (bmi.biCompression == 0) {
u = LITTLE_SHORT(bmi.biBitCount);
- if (u >= 8) {
+ if (u > 0 && u <= 32) {
ret_val = 1;
}
}
@@ -136,10 +136,15 @@ struct ImBuf *imb_bmp_decode(unsigned char *mem, size_t size, int flags, char co
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
+ bmp = mem + LITTLE_LONG(*(int *)(mem + 10));
+
if (CHECK_HEADER_FIELD_BMP(mem)) {
/* skip fileheader */
mem += BMP_FILEHEADER_SIZE;
}
+ else {
+ return NULL;
+ }
/* for systems where an int needs to be 4 bytes aligned */
memcpy(&bmi, mem, sizeof(bmi));
@@ -173,28 +178,43 @@ struct ImBuf *imb_bmp_decode(unsigned char *mem, size_t size, int flags, char co
}
else {
ibuf = IMB_allocImBuf(x, y, ibuf_depth, IB_rect);
- bmp = mem + skip;
rect = (unsigned char *) ibuf->rect;
- if (depth == 8) {
- const int x_pad = (4 - (x % 4)) % 4;
- const char (*palette)[4] = (void *)bmp;
- bmp += bmi.biClrUsed * 4;
+ if (depth <= 8) {
+ const int rowsize = (depth * x + 31) / 32 * 4;
+ const char (*palette)[4] = (void *)(mem + skip);
+ const int startmask = ((1 << depth) - 1) << 8;
for (i = y; i > 0; i--) {
+ int index;
+ int bitoffs = 8;
+ int bitmask = startmask;
+ int nbytes = 0;
+ const char *pcol;
if (top_to_bottom) {
rect = (unsigned char *) &ibuf->rect[(i - 1) * x];
}
for (j = x; j > 0; j--) {
- const char *pcol = palette[bmp[0]];
- rect[0] = pcol[0];
+ bitoffs -= depth;
+ bitmask >>= depth;
+ index = (bmp[0] & bitmask) >> bitoffs;
+ pcol = palette[index];
+ /* intentionally BGR -> RGB */
+ rect[0] = pcol[2];
rect[1] = pcol[1];
- rect[2] = pcol[2];
+ rect[2] = pcol[0];
rect[3] = 255;
- rect += 4; bmp += 1;
+ rect += 4;
+ if (bitoffs == 0) {
+ /* Advance to the next byte */
+ bitoffs = 8;
+ bitmask = startmask;
+ nbytes += 1;
+ bmp += 1;
+ }
}
- /* rows are padded to multiples of 4 */
- bmp += x_pad;
+ /* Advance to the next row */
+ bmp += (rowsize - nbytes);
}
}
else if (depth == 16) {
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.h b/source/blender/imbuf/intern/cineon/logImageCore.h
index 6b1435817d2..389e88a24de 100644
--- a/source/blender/imbuf/intern/cineon/logImageCore.h
+++ b/source/blender/imbuf/intern/cineon/logImageCore.h
@@ -52,8 +52,7 @@ enum format {
format_Cineon
};
-typedef struct LogImageElement
-{
+typedef struct LogImageElement {
int depth;
int bitsPerSample;
int dataOffset;
@@ -67,8 +66,7 @@ typedef struct LogImageElement
float maxValue; /* = 2^bitsPerSample - 1 (used internally, doesn't come from the file header) */
} LogImageElement;
-typedef struct LogImageFile
-{
+typedef struct LogImageFile {
/* specified in header */
int width;
int height;
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 95e166b2f8b..a61204ea850 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -90,6 +90,11 @@ static int global_tot_display = 0;
static int global_tot_view = 0;
static int global_tot_looks = 0;
+/* Set to ITU-BT.709 / sRGB primaries weight. Brute force stupid, but only
+ * option with no colormanagement in place.
+ */
+static float luma_coefficients[3] = { 0.2126f, 0.7152f, 0.0722f };
+
/* lock used by pre-cached processors getters, so processor wouldn't
* be created several times
* LOCK_COLORMANAGE can not be used since this mutex could be needed to
@@ -545,6 +550,9 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
colormanage_look_add(name, process_space, false);
}
+
+ /* Load luminance coefficients. */
+ OCIO_configGetDefaultLumaCoefs(config, luma_coefficients);
}
static void colormanage_free_config(void)
@@ -1222,6 +1230,34 @@ const char *IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf)
return ibuf->rect_colorspace->name;
}
+/* Convert a float RGB triplet to the correct luminance weighted average.
+ *
+ * Grayscale, or Luma is a distillation of RGB data values down to a weighted average
+ * based on the luminance positions of the red, green, and blue primaries.
+ * Given that the internal reference space may be arbitrarily set, any
+ * effort to glean the luminance coefficients must be aware of the reference
+ * space primaries.
+ *
+ * See http://wiki.blender.org/index.php/User:Nazg-gul/ColorManagement#Luminance
+ */
+
+float IMB_colormanagement_get_luminance(const float rgb[3])
+{
+ return dot_v3v3(luma_coefficients, rgb);
+}
+
+/* Byte equivalent of IMB_colormanagement_get_luminance(). */
+unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char rgb[3])
+{
+ float rgbf[3];
+ float val;
+
+ rgb_uchar_to_float(rgbf, rgb);
+ val = dot_v3v3(luma_coefficients, rgbf);
+
+ return FTOCHAR(val);
+}
+
/*********************** Threaded display buffer transform routines *************************/
typedef struct DisplayBufferThread {
@@ -1270,8 +1306,8 @@ static void display_buffer_init_handle(void *handle_v, int start_line, int tot_l
float dither = ibuf->dither;
bool is_data = (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) != 0;
- int offset = channels * start_line * ibuf->x;
- int display_buffer_byte_offset = DISPLAY_BUFFER_CHANNELS * start_line * ibuf->x;
+ size_t offset = ((size_t)channels) * start_line * ibuf->x;
+ size_t display_buffer_byte_offset = ((size_t)DISPLAY_BUFFER_CHANNELS) * start_line * ibuf->x;
memset(handle, 0, sizeof(DisplayBufferThread));
@@ -1308,7 +1344,7 @@ static void display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle,
int channels = handle->channels;
int width = handle->width;
- int buffer_size = channels * width * height;
+ size_t buffer_size = ((size_t)channels) * width * height;
bool is_data = handle->is_data;
bool is_data_display = handle->cm_processor->is_data_result;
@@ -1321,11 +1357,12 @@ static void display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle,
float *fp;
unsigned char *cp;
- int i;
+ const size_t i_last = ((size_t)width) * height;
+ size_t i;
/* first convert byte buffer to float, keep in image space */
for (i = 0, fp = linear_buffer, cp = byte_buffer;
- i < width * height;
+ i != i_last;
i++, fp += channels, cp += channels)
{
if (channels == 3) {
@@ -1404,7 +1441,7 @@ static void *do_display_buffer_apply_thread(void *handle_v)
}
else {
bool is_straight_alpha, predivide;
- float *linear_buffer = MEM_mallocN(channels * width * height * sizeof(float),
+ float *linear_buffer = MEM_mallocN(((size_t)channels) * width * height * sizeof(float),
"color conversion linear buffer");
display_buffer_apply_get_linear_buffer(handle, height, linear_buffer, &is_straight_alpha);
@@ -1431,14 +1468,15 @@ static void *do_display_buffer_apply_thread(void *handle_v)
}
if (display_buffer) {
- memcpy(display_buffer, linear_buffer, width * height * channels * sizeof(float));
+ memcpy(display_buffer, linear_buffer, ((size_t)width) * height * channels * sizeof(float));
if (is_straight_alpha && channels == 4) {
- int i;
+ const size_t i_last = ((size_t)width) * height;
+ size_t i;
float *fp;
for (i = 0, fp = display_buffer;
- i < width * height;
+ i != i_last;
i++, fp += channels)
{
straight_to_premul_v4(fp);
@@ -1566,7 +1604,7 @@ static void processor_transform_init_handle(void *handle_v, int start_line, int
int width = init_data->width;
bool predivide = init_data->predivide;
- int offset = channels * start_line * width;
+ size_t offset = ((size_t)channels) * start_line * width;
memset(handle, 0, sizeof(ProcessorTransformThread));
@@ -1751,8 +1789,10 @@ void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, in
if (processor) {
OCIO_PackedImageDesc *img;
- img = OCIO_createOCIO_PackedImageDesc(buffer, width, height, channels, sizeof(float),
- channels * sizeof(float), channels * sizeof(float) * width);
+ img = OCIO_createOCIO_PackedImageDesc(
+ buffer, width, height, channels, sizeof(float),
+ (size_t)channels * sizeof(float),
+ (size_t)channels * sizeof(float) * width);
if (predivide)
OCIO_processorApply_predivide(processor, img);
@@ -1912,7 +1952,7 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, boo
if (do_colormanagement) {
bool make_byte = false;
- ImFileType *type;
+ const ImFileType *type;
/* for proper check whether byte buffer is required by a format or not
* should be pretty safe since this image buffer is supposed to be used for
@@ -1954,7 +1994,7 @@ void IMB_colormanagement_buffer_make_display_space(float *buffer, unsigned char
const ColorManagedDisplaySettings *display_settings)
{
ColormanageProcessor *cm_processor;
- size_t float_buffer_size = width * height * channels * sizeof(float);
+ size_t float_buffer_size = ((size_t)width) * height * channels * sizeof(float);
float *display_buffer_float = MEM_mallocN(float_buffer_size, "byte_buffer_make_display_space");
memcpy(display_buffer_float, buffer, float_buffer_size);
@@ -1979,7 +2019,7 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSet
const ColorManagedDisplaySettings *display_settings, void **cache_handle)
{
unsigned char *display_buffer;
- int buffer_size;
+ size_t buffer_size;
ColormanageCacheViewSettings cache_view_settings;
ColormanageCacheDisplaySettings cache_display_settings;
ColorManagedViewSettings default_view_settings;
@@ -2047,7 +2087,7 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSet
return display_buffer;
}
- buffer_size = DISPLAY_BUFFER_CHANNELS * ibuf->x * ibuf->y * sizeof(char);
+ buffer_size = DISPLAY_BUFFER_CHANNELS * ((size_t)ibuf->x) * ibuf->y * sizeof(char);
display_buffer = MEM_callocN(buffer_size, "imbuf display buffer");
colormanage_display_buffer_process(ibuf, display_buffer, applied_view_settings, display_settings);
@@ -2077,8 +2117,8 @@ void IMB_display_buffer_transform_apply(unsigned char *display_buffer, float *li
float *buffer;
ColormanageProcessor *cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
- buffer = MEM_callocN(channels * width * height * sizeof(float), "display transform temp buffer");
- memcpy(buffer, linear_buffer, channels * width * height * sizeof(float));
+ buffer = MEM_mallocN((size_t)channels * width * height * sizeof(float), "display transform temp buffer");
+ memcpy(buffer, linear_buffer, (size_t)channels * width * height * sizeof(float));
IMB_colormanagement_processor_apply(cm_processor, buffer, width, height, channels, predivide);
@@ -2421,7 +2461,7 @@ const char *IMB_colormanagement_colorspace_get_indexed_name(int index)
void IMB_colormanagment_colorspace_from_ibuf_ftype(ColorManagedColorspaceSettings *colorspace_settings, ImBuf *ibuf)
{
- ImFileType *type;
+ const ImFileType *type;
for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
if (type->save && type->ftype(type, ibuf)) {
@@ -2622,14 +2662,14 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
if (!cm_processor)
channels = 4;
- display_buffer_float = MEM_callocN(channels * width * height * sizeof(float), "display buffer for dither");
+ display_buffer_float = MEM_callocN((size_t)channels * width * height * sizeof(float), "display buffer for dither");
}
if (cm_processor) {
for (y = ymin; y < ymax; y++) {
for (x = xmin; x < xmax; x++) {
- int display_index = (y * display_stride + x) * 4;
- int linear_index = ((y - linear_offset_y) * linear_stride + (x - linear_offset_x)) * channels;
+ size_t display_index = ((size_t)y * display_stride + x) * 4;
+ size_t linear_index = ((size_t)(y - linear_offset_y) * linear_stride + (x - linear_offset_x)) * channels;
float pixel[4];
if (linear_buffer) {
@@ -2658,7 +2698,7 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
}
if (display_buffer_float) {
- int index = ((y - ymin) * width + (x - xmin)) * channels;
+ size_t index = ((size_t)(y - ymin) * width + (x - xmin)) * channels;
if (channels == 4) {
copy_v4_v4(display_buffer_float + index, pixel);
@@ -2701,8 +2741,8 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
int i;
for (i = ymin; i < ymax; i++) {
- int byte_offset = (linear_stride * i + xmin) * 4;
- int display_offset = (display_stride * i + xmin) * 4;
+ size_t byte_offset = ((size_t)linear_stride * i + xmin) * 4;
+ size_t display_offset = ((size_t)display_stride * i + xmin) * 4;
memcpy(display_buffer + display_offset, byte_buffer + byte_offset, 4 * sizeof(char) * width);
}
@@ -2710,7 +2750,7 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
}
if (display_buffer_float) {
- int display_index = (ymin * display_stride + xmin) * channels;
+ size_t display_index = ((size_t)ymin * display_stride + xmin) * channels;
IMB_buffer_byte_from_float(display_buffer + display_index, display_buffer_float, channels, dither,
IB_PROFILE_SRGB, IB_PROFILE_SRGB, true, width, height, display_stride, width);
@@ -2797,8 +2837,8 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer,
if (copy_display_to_byte_buffer && (unsigned char *) ibuf->rect != display_buffer) {
int y;
for (y = ymin; y < ymax; y++) {
- int index = y * buffer_width * 4;
- memcpy((unsigned char *)ibuf->rect + index, display_buffer + index, (xmax - xmin) * 4);
+ size_t index = (size_t)y * buffer_width * 4;
+ memcpy((unsigned char *)ibuf->rect + index, display_buffer + index, (size_t)(xmax - xmin) * 4);
}
}
}
@@ -2923,7 +2963,7 @@ void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, flo
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
- float *pixel = buffer + channels * (y * width + x);
+ float *pixel = buffer + channels * (((size_t)y) * width + x);
curve_mapping_apply_pixel(cm_processor->curve_mapping, pixel, channels);
}
@@ -2934,8 +2974,10 @@ void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, flo
OCIO_PackedImageDesc *img;
/* apply OCIO processor */
- img = OCIO_createOCIO_PackedImageDesc(buffer, width, height, channels, sizeof(float),
- channels * sizeof(float), channels * sizeof(float) * width);
+ img = OCIO_createOCIO_PackedImageDesc(
+ buffer, width, height, channels, sizeof(float),
+ (size_t)channels * sizeof(float),
+ (size_t)channels * sizeof(float) * width);
if (predivide)
OCIO_processorApply_predivide(cm_processor->processor, img);
diff --git a/source/blender/imbuf/intern/dds/BlockDXT.h b/source/blender/imbuf/intern/dds/BlockDXT.h
index 7e5a1e504b8..6aae9c9817c 100644
--- a/source/blender/imbuf/intern/dds/BlockDXT.h
+++ b/source/blender/imbuf/intern/dds/BlockDXT.h
@@ -64,8 +64,7 @@
#include <Stream.h>
/// DXT1 block.
-struct BlockDXT1
-{
+struct BlockDXT1 {
Color16 col0;
Color16 col1;
union {
@@ -98,8 +97,7 @@ inline bool BlockDXT1::isFourColorMode() const
/// DXT3 alpha block with explicit alpha.
-struct AlphaBlockDXT3
-{
+struct AlphaBlockDXT3 {
union {
struct {
uint alpha0 : 4;
@@ -130,8 +128,7 @@ struct AlphaBlockDXT3
/// DXT3 block.
-struct BlockDXT3
-{
+struct BlockDXT3 {
AlphaBlockDXT3 alpha;
BlockDXT1 color;
@@ -144,8 +141,7 @@ struct BlockDXT3
/// DXT5 alpha block.
-struct AlphaBlockDXT5
-{
+struct AlphaBlockDXT5 {
// uint64 unions do not compile on all platforms
#if 0
union {
@@ -208,8 +204,7 @@ struct AlphaBlockDXT5
/// DXT5 block.
-struct BlockDXT5
-{
+struct BlockDXT5 {
AlphaBlockDXT5 alpha;
BlockDXT1 color;
@@ -221,8 +216,7 @@ struct BlockDXT5
};
/// ATI1 block.
-struct BlockATI1
-{
+struct BlockATI1 {
AlphaBlockDXT5 alpha;
void decodeBlock(ColorBlock * block) const;
@@ -232,8 +226,7 @@ struct BlockATI1
};
/// ATI2 block.
-struct BlockATI2
-{
+struct BlockATI2 {
AlphaBlockDXT5 x;
AlphaBlockDXT5 y;
@@ -244,8 +237,7 @@ struct BlockATI2
};
/// CTX1 block.
-struct BlockCTX1
-{
+struct BlockCTX1 {
uint8 col0[2];
uint8 col1[2];
union {
diff --git a/source/blender/imbuf/intern/dds/ColorBlock.h b/source/blender/imbuf/intern/dds/ColorBlock.h
index 730a19d84fd..8d5031aa603 100644
--- a/source/blender/imbuf/intern/dds/ColorBlock.h
+++ b/source/blender/imbuf/intern/dds/ColorBlock.h
@@ -41,8 +41,7 @@
#include <Image.h>
/// Uncompressed 4x4 color block.
-struct ColorBlock
-{
+struct ColorBlock {
ColorBlock();
ColorBlock(const uint * linearImage);
ColorBlock(const ColorBlock & block);
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
index 028026527dc..6bf82776afe 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
@@ -60,6 +60,7 @@
#include <PixelFormat.h>
#include <stdio.h> // printf
+#include <stdlib.h> // malloc
#include <math.h> // sqrt
#include <sys/types.h>
@@ -496,8 +497,7 @@ void mem_read(Stream & mem, DDSHeader & header)
namespace
{
-struct FormatDescriptor
-{
+struct FormatDescriptor {
uint format;
uint bitcount;
uint rmask;
@@ -1148,7 +1148,7 @@ void* DirectDrawSurface::readData(uint &rsize)
uint size = stream.size - header_size;
rsize = size;
- unsigned char *data = new unsigned char[size];
+ unsigned char *data = (unsigned char *)malloc(sizeof(*data) * size);
stream.seek(header_size);
mem_read(stream, data, size);
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.h b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
index 3d308ba1ff1..44c27a98c1d 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.h
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
@@ -63,8 +63,7 @@
#include <ColorBlock.h>
#include <Image.h>
-struct DDSPixelFormat
-{
+struct DDSPixelFormat {
uint size;
uint flags;
uint fourcc;
@@ -75,8 +74,7 @@ struct DDSPixelFormat
uint amask;
};
-struct DDSCaps
-{
+struct DDSCaps {
uint caps1;
uint caps2;
uint caps3;
@@ -84,8 +82,7 @@ struct DDSCaps
};
/// DDS file header for DX10.
-struct DDSHeader10
-{
+struct DDSHeader10 {
uint dxgiFormat;
uint resourceDimension;
uint miscFlag;
@@ -94,8 +91,7 @@ struct DDSHeader10
};
/// DDS file header.
-struct DDSHeader
-{
+struct DDSHeader {
uint fourcc;
uint size;
uint flags;
diff --git a/source/blender/imbuf/intern/dds/Stream.h b/source/blender/imbuf/intern/dds/Stream.h
index a1ac49b58da..6557fb4f063 100644
--- a/source/blender/imbuf/intern/dds/Stream.h
+++ b/source/blender/imbuf/intern/dds/Stream.h
@@ -30,8 +30,7 @@
#ifndef __STREAM_H__
#define __STREAM_H__
-struct Stream
-{
+struct Stream {
unsigned char *mem; // location in memory
unsigned int size; // size
unsigned int pos; // current position
diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp
index a6d53ffac96..45d9fa2ac59 100644
--- a/source/blender/imbuf/intern/dds/dds_api.cpp
+++ b/source/blender/imbuf/intern/dds/dds_api.cpp
@@ -47,7 +47,7 @@ extern "C" {
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
-int imb_save_dds(struct ImBuf *ibuf, const char *name, int flags)
+int imb_save_dds(struct ImBuf *ibuf, const char *name, int /*flags*/)
{
return(0); /* todo: finish this function */
diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c
index 65abf22ff2c..455b78bce4d 100644
--- a/source/blender/imbuf/intern/divers.c
+++ b/source/blender/imbuf/intern/divers.c
@@ -184,16 +184,16 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
if (channels_from == 1) {
/* single channel input */
- const float *from = rect_from + stride_from * y;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from++, to += 4)
to[0] = to[1] = to[2] = to[3] = FTOCHAR(from[0]);
}
else if (channels_from == 3) {
/* RGB input */
- const float *from = rect_from + stride_from * y * 3;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 3;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
/* no color space conversion */
@@ -221,8 +221,8 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
}
else if (channels_from == 4) {
/* RGBA input */
- const float *from = rect_from + stride_from * y * 4;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 4;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
float straight[4];
@@ -334,8 +334,8 @@ void IMB_buffer_byte_from_float_mask(uchar *rect_to, const float *rect_from,
if (channels_from == 1) {
/* single channel input */
- const float *from = rect_from + stride_from * y;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from++, to += 4)
if (*mask++ == FILTER_MASK_USED)
@@ -343,8 +343,8 @@ void IMB_buffer_byte_from_float_mask(uchar *rect_to, const float *rect_from,
}
else if (channels_from == 3) {
/* RGB input */
- const float *from = rect_from + stride_from * y * 3;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 3;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from += 3, to += 4) {
if (*mask++ == FILTER_MASK_USED) {
@@ -355,8 +355,8 @@ void IMB_buffer_byte_from_float_mask(uchar *rect_to, const float *rect_from,
}
else if (channels_from == 4) {
/* RGBA input */
- const float *from = rect_from + stride_from * y * 4;
- uchar *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 4;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
float straight[4];
@@ -408,7 +408,7 @@ void IMB_buffer_float_from_byte(float *rect_to, const uchar *rect_from,
/* RGBA input */
for (y = 0; y < height; y++) {
const uchar *from = rect_from + stride_from * y * 4;
- float *to = rect_to + stride_to * y * 4;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
/* no color space conversion */
@@ -460,8 +460,8 @@ void IMB_buffer_float_from_float(float *rect_to, const float *rect_from,
if (channels_from == 1) {
/* single channel input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from++, to += 4)
to[0] = to[1] = to[2] = to[3] = from[0];
@@ -470,8 +470,8 @@ void IMB_buffer_float_from_float(float *rect_to, const float *rect_from,
else if (channels_from == 3) {
/* RGB input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y * 3;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 3;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
/* no color space conversion */
@@ -499,12 +499,12 @@ void IMB_buffer_float_from_float(float *rect_to, const float *rect_from,
else if (channels_from == 4) {
/* RGBA input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y * 4;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 4;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
/* same profile, copy */
- memcpy(to, from, sizeof(float) * 4 * width);
+ memcpy(to, from, sizeof(float) * ((size_t)4) * width);
}
else if (profile_to == IB_PROFILE_LINEAR_RGB) {
/* convert to sRGB to linear */
@@ -541,8 +541,8 @@ void IMB_buffer_float_from_float_mask(float *rect_to, const float *rect_from, in
if (channels_from == 1) {
/* single channel input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from++, to += 4)
if (*mask++ == FILTER_MASK_USED)
@@ -552,8 +552,8 @@ void IMB_buffer_float_from_float_mask(float *rect_to, const float *rect_from, in
else if (channels_from == 3) {
/* RGB input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y * 3;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 3;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from += 3, to += 4) {
if (*mask++ == FILTER_MASK_USED) {
@@ -566,8 +566,8 @@ void IMB_buffer_float_from_float_mask(float *rect_to, const float *rect_from, in
else if (channels_from == 4) {
/* RGBA input */
for (y = 0; y < height; y++) {
- const float *from = rect_from + stride_from * y * 4;
- float *to = rect_to + stride_to * y * 4;
+ const float *from = rect_from + ((size_t)stride_from) * y * 4;
+ float *to = rect_to + ((size_t)stride_to) * y * 4;
for (x = 0; x < width; x++, from += 4, to += 4)
if (*mask++ == FILTER_MASK_USED)
@@ -590,8 +590,8 @@ void IMB_buffer_byte_from_byte(uchar *rect_to, const uchar *rect_from,
/* always RGBA input */
for (y = 0; y < height; y++) {
- const uchar *from = rect_from + stride_from * y * 4;
- uchar *to = rect_to + stride_to * y * 4;
+ const uchar *from = rect_from + ((size_t)stride_from) * y * 4;
+ uchar *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
/* same profile, copy */
@@ -690,8 +690,8 @@ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w
imb_addrectImBuf(ibuf);
/* do conversion */
- rect_float = ibuf->rect_float + (x + y * ibuf->x) * ibuf->channels;
- rect_byte = (uchar *)ibuf->rect + (x + y * ibuf->x) * 4;
+ rect_float = ibuf->rect_float + (x + ((size_t)y) * ibuf->x) * ibuf->channels;
+ rect_byte = (uchar *)ibuf->rect + (x + ((size_t)y) * ibuf->x) * 4;
if (is_data) {
/* exception for non-color data, just copy float */
@@ -734,9 +734,9 @@ void IMB_float_from_rect(ImBuf *ibuf)
*/
rect_float = ibuf->rect_float;
if (rect_float == NULL) {
- int size;
+ size_t size;
- size = ibuf->x * ibuf->y;
+ size = ((size_t)ibuf->x) * ibuf->y;
size = size * 4 * sizeof(float);
ibuf->channels = 4;
@@ -771,22 +771,22 @@ void IMB_color_to_bw(ImBuf *ibuf)
{
float *rct_fl = ibuf->rect_float;
uchar *rct = (uchar *)ibuf->rect;
- int i;
+ size_t i;
if (rct_fl) {
- for (i = ibuf->x * ibuf->y; i > 0; i--, rct_fl += 4)
- rct_fl[0] = rct_fl[1] = rct_fl[2] = rgb_to_grayscale(rct_fl);
+ for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4)
+ rct_fl[0] = rct_fl[1] = rct_fl[2] = IMB_colormanagement_get_luminance(rct_fl);
}
if (rct) {
- for (i = ibuf->x * ibuf->y; i > 0; i--, rct += 4)
- rct[0] = rct[1] = rct[2] = rgb_to_grayscale_byte(rct);
+ for (i = ((size_t)ibuf->x * ibuf->y); i > 0; i--, rct += 4)
+ rct[0] = rct[1] = rct[2] = IMB_colormanagement_get_luminance_byte(rct);
}
}
void IMB_buffer_float_clamp(float *buf, int width, int height)
{
- int i, total = width * height * 4;
+ size_t i, total = ((size_t)width) * height * 4;
for (i = 0; i < total; i++) {
buf[i] = min_ff(1.0, buf[i]);
}
@@ -794,7 +794,7 @@ void IMB_buffer_float_clamp(float *buf, int width, int height)
void IMB_buffer_float_unpremultiply(float *buf, int width, int height)
{
- int total = width * height;
+ size_t total = ((size_t)width) * height;
float *fp = buf;
while (total--) {
premul_to_straight_v4(fp);
@@ -804,7 +804,7 @@ void IMB_buffer_float_unpremultiply(float *buf, int width, int height)
void IMB_buffer_float_premultiply(float *buf, int width, int height)
{
- int total = width * height;
+ size_t total = ((size_t)width) * height;
float *fp = buf;
while (total--) {
straight_to_premul_v4(fp);
@@ -816,14 +816,14 @@ void IMB_buffer_float_premultiply(float *buf, int width, int height)
void IMB_saturation(ImBuf *ibuf, float sat)
{
- int i;
+ size_t i;
unsigned char *rct = (unsigned char *)ibuf->rect;
float *rct_fl = ibuf->rect_float;
float hsv[3];
if (rct) {
float rgb[3];
- for (i = ibuf->x * ibuf->y; i > 0; i--, rct += 4) {
+ for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct += 4) {
rgb_uchar_to_float(rgb, rct);
rgb_to_hsv_v(rgb, hsv);
hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rgb, rgb + 1, rgb + 2);
@@ -832,7 +832,7 @@ void IMB_saturation(ImBuf *ibuf, float sat)
}
if (rct_fl) {
- for (i = ibuf->x * ibuf->y; i > 0; i--, rct_fl += 4) {
+ for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4) {
rgb_to_hsv_v(rct_fl, hsv);
hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rct_fl, rct_fl + 1, rct_fl + 2);
}
diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c
index c6e358dd3d2..e58cda07ecf 100644
--- a/source/blender/imbuf/intern/filetype.c
+++ b/source/blender/imbuf/intern/filetype.c
@@ -51,17 +51,17 @@
#include "quicktime_import.h"
#endif
-static int imb_ftype_default(ImFileType *type, ImBuf *ibuf)
+static int imb_ftype_default(const ImFileType *type, ImBuf *ibuf)
{
return (ibuf->ftype & type->filetype);
}
-static int imb_ftype_iris(ImFileType *type, ImBuf *ibuf)
+static int imb_ftype_iris(const ImFileType *type, ImBuf *ibuf)
{
(void)type;
return (ibuf->ftype == IMAGIC);
}
-ImFileType IMB_FILE_TYPES[] = {
+const ImFileType IMB_FILE_TYPES[] = {
{NULL, NULL, imb_is_a_jpeg, NULL, imb_ftype_default, imb_load_jpeg, NULL, imb_savejpeg, NULL, 0, JPG, COLOR_ROLE_DEFAULT_BYTE},
{NULL, NULL, imb_is_a_png, NULL, imb_ftype_default, imb_loadpng, NULL, imb_savepng, NULL, 0, PNG, COLOR_ROLE_DEFAULT_BYTE},
{NULL, NULL, imb_is_a_bmp, NULL, imb_ftype_default, imb_bmp_decode, NULL, imb_savebmp, NULL, 0, BMP, COLOR_ROLE_DEFAULT_BYTE},
@@ -92,11 +92,11 @@ ImFileType IMB_FILE_TYPES[] = {
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0}
};
-ImFileType *IMB_FILE_TYPES_LAST = &IMB_FILE_TYPES[sizeof(IMB_FILE_TYPES) / sizeof(ImFileType) - 1];
+const ImFileType *IMB_FILE_TYPES_LAST = &IMB_FILE_TYPES[sizeof(IMB_FILE_TYPES) / sizeof(ImFileType) - 1];
void imb_filetypes_init(void)
{
- ImFileType *type;
+ const ImFileType *type;
for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++)
if (type->init)
@@ -109,7 +109,7 @@ void imb_filetypes_init(void)
void imb_filetypes_exit(void)
{
- ImFileType *type;
+ const ImFileType *type;
for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++)
if (type->exit)
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index 352e230068b..7adb2c7cc1d 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -526,7 +526,7 @@ void IMB_makemipmap(ImBuf *ibuf, int use_filter)
hbuf = ibuf->mipmap[curmap];
hbuf->miplevel = curmap + 1;
- if (hbuf->x <= 2 && hbuf->y <= 2)
+ if (hbuf->x < 2 && hbuf->y < 2)
break;
curmap++;
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index 8234b01992b..d44f0dc86f4 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -51,7 +51,7 @@
/* Only this one is used liberally here, and in imbuf */
void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
{
- int size;
+ size_t size;
unsigned char rt, *cp = (unsigned char *)ibuf->rect;
float rtf, *cpf = ibuf->rect_float;
@@ -86,7 +86,7 @@ void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
static void pixel_from_buffer(struct ImBuf *ibuf, unsigned char **outI, float **outF, int x, int y)
{
- int offset = ibuf->x * y * 4 + 4 * x;
+ size_t offset = ((size_t)ibuf->x) * y * 4 + 4 * x;
if (ibuf->rect)
*outI = (unsigned char *)ibuf->rect + offset;
@@ -172,10 +172,10 @@ void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char outI[4],
if (outF) {
/* sample including outside of edges of image */
- row1 = in->rect_float + in->x * y1 * 4 + 4 * x1;
- row2 = in->rect_float + in->x * y2 * 4 + 4 * x1;
- row3 = in->rect_float + in->x * y1 * 4 + 4 * x2;
- row4 = in->rect_float + in->x * y2 * 4 + 4 * x2;
+ row1 = in->rect_float + ((size_t)in->x) * y1 * 4 + 4 * x1;
+ row2 = in->rect_float + ((size_t)in->x) * y2 * 4 + 4 * x1;
+ row3 = in->rect_float + ((size_t)in->x) * y1 * 4 + 4 * x2;
+ row4 = in->rect_float + ((size_t)in->x) * y2 * 4 + 4 * x2;
outF[0] = ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0];
outF[1] = ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1];
@@ -190,10 +190,10 @@ void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char outI[4],
}
if (outI) {
/* sample including outside of edges of image */
- row1I = (unsigned char *)in->rect + in->x * y1 * 4 + 4 * x1;
- row2I = (unsigned char *)in->rect + in->x * y2 * 4 + 4 * x1;
- row3I = (unsigned char *)in->rect + in->x * y1 * 4 + 4 * x2;
- row4I = (unsigned char *)in->rect + in->x * y2 * 4 + 4 * x2;
+ row1I = (unsigned char *)in->rect + ((size_t)in->x) * y1 * 4 + 4 * x1;
+ row2I = (unsigned char *)in->rect + ((size_t)in->x) * y2 * 4 + 4 * x1;
+ row3I = (unsigned char *)in->rect + ((size_t)in->x) * y1 * 4 + 4 * x2;
+ row4I = (unsigned char *)in->rect + ((size_t)in->x) * y2 * 4 + 4 * x2;
/* need to add 0.5 to avoid rounding down (causes darken with the smear brush)
* tested with white images and this should not wrap back to zero */
@@ -256,14 +256,14 @@ void nearest_interpolation_color(struct ImBuf *in, unsigned char outI[4], float
}
}
else {
- dataI = (unsigned char *)in->rect + in->x * y1 * 4 + 4 * x1;
+ dataI = (unsigned char *)in->rect + ((size_t)in->x) * y1 * 4 + 4 * x1;
if (outI) {
outI[0] = dataI[0];
outI[1] = dataI[1];
outI[2] = dataI[2];
outI[3] = dataI[3];
}
- dataF = in->rect_float + in->x * y1 * 4 + 4 * x1;
+ dataF = in->rect_float + ((size_t)in->x) * y1 * 4 + 4 * x1;
if (outF) {
outF[0] = dataF[0];
outF[1] = dataF[1];
@@ -273,6 +273,41 @@ void nearest_interpolation_color(struct ImBuf *in, unsigned char outI[4], float
}
}
+
+void nearest_interpolation_color_wrap(struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+{
+ const float *dataF;
+ unsigned char *dataI;
+ int y, x;
+
+ /* ImBuf in must have a valid rect or rect_float, assume this is already checked */
+
+ x = (int) floor(u);
+ y = (int) floor(v);
+
+ x = x % in->x;
+ y = y % in->y;
+
+ /* wrap interpolation pixels - main difference from nearest_interpolation_color */
+ if (x < 0) x += in->x;
+ if (y < 0) y += in->y;
+
+ dataI = (unsigned char *)in->rect + ((size_t)in->x) * y * 4 + 4 * x;
+ if (outI) {
+ outI[0] = dataI[0];
+ outI[1] = dataI[1];
+ outI[2] = dataI[2];
+ outI[3] = dataI[3];
+ }
+ dataF = in->rect_float + ((size_t)in->x) * y * 4 + 4 * x;
+ if (outF) {
+ outF[0] = dataF[0];
+ outF[1] = dataF[1];
+ outF[2] = dataF[2];
+ outF[3] = dataF[3];
+ }
+}
+
void nearest_interpolation(ImBuf *in, ImBuf *out, float x, float y, int xout, int yout)
{
unsigned char *outI = NULL;
@@ -343,7 +378,7 @@ void IMB_processor_apply_threaded(int buffer_lines, int handle_size, void *init_
void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[3])
{
- int a = x * y;
+ size_t a = ((size_t)x) * y;
float *fp = rect_float;
while (a--) {
@@ -366,7 +401,7 @@ void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[
void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, float backcol[3])
{
- int a = x * y;
+ size_t a = ((size_t)x) * y;
unsigned char *cp = rect;
while (a--) {
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index d0281744830..0509dea89d5 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -374,6 +374,13 @@ static void get_index_dir(struct anim *anim, char *index_dir, size_t index_dir_l
}
}
+void IMB_anim_get_fname(struct anim *anim, char *file, int size)
+{
+ char fname[FILE_MAXFILE];
+ BLI_split_dirfile(anim->name, file, fname, size, sizeof(fname));
+ BLI_strncpy(file, fname, size);
+}
+
static void get_proxy_filename(struct anim *anim, IMB_Proxy_Size preview_size,
char *fname, bool temp)
{
@@ -381,8 +388,8 @@ static void get_proxy_filename(struct anim *anim, IMB_Proxy_Size preview_size,
int i = IMB_proxy_size_to_array_index(preview_size);
char proxy_name[256];
- char proxy_temp_name[256];
char stream_suffix[20];
+ const char *name = (temp) ? "proxy_%d%s_part.avi" : "proxy_%d%s.avi";
stream_suffix[0] = 0;
@@ -390,15 +397,12 @@ static void get_proxy_filename(struct anim *anim, IMB_Proxy_Size preview_size,
BLI_snprintf(stream_suffix, sizeof(stream_suffix), "_st%d", anim->streamindex);
}
- BLI_snprintf(proxy_name, sizeof(proxy_name), "proxy_%d%s.avi",
- (int) (proxy_fac[i] * 100), stream_suffix);
- BLI_snprintf(proxy_temp_name, sizeof(proxy_temp_name), "proxy_%d%s_part.avi",
- (int) (proxy_fac[i] * 100), stream_suffix);
+ BLI_snprintf(proxy_name, sizeof(proxy_name), name,
+ (int) (proxy_fac[i] * 100), stream_suffix, anim->suffix);
get_index_dir(anim, index_dir, sizeof(index_dir));
- BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir,
- temp ? proxy_temp_name : proxy_name);
+ BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir, proxy_name);
}
static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc,
@@ -407,10 +411,10 @@ static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc,
char index_dir[FILE_MAXDIR];
int i = IMB_timecode_to_array_index(tc);
const char *index_names[] = {
- "record_run%s.blen_tc",
- "free_run%s.blen_tc",
- "interp_free_run%s.blen_tc",
- "record_run_no_gaps%s.blen_tc"
+ "record_run%s%s.blen_tc",
+ "free_run%s%s.blen_tc",
+ "interp_free_run%s%s.blen_tc",
+ "record_run_no_gaps%s%s.blen_tc"
};
char stream_suffix[20];
@@ -422,7 +426,7 @@ static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc,
BLI_snprintf(stream_suffix, 20, "_st%d", anim->streamindex);
}
- BLI_snprintf(index_name, 256, index_names[i], stream_suffix);
+ BLI_snprintf(index_name, 256, index_names[i], stream_suffix, anim->suffix);
get_index_dir(anim, index_dir, sizeof(index_dir));
@@ -1002,7 +1006,7 @@ static AviMovie *alloc_proxy_output_avi(
* but sane defaults help anyways...*/
float frs_sec_base = 1.0;
- IMB_anim_get_fps(anim, &frs_sec, &frs_sec_base);
+ IMB_anim_get_fps(anim, &frs_sec, &frs_sec_base, false);
x = width;
y = height;
diff --git a/source/blender/imbuf/intern/metadata.c b/source/blender/imbuf/intern/metadata.c
index 8cb5070dd62..134bbe88f15 100644
--- a/source/blender/imbuf/intern/metadata.c
+++ b/source/blender/imbuf/intern/metadata.c
@@ -79,6 +79,13 @@ bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *field, con
return retval;
}
+void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb)
+{
+ if (simb->metadata) {
+ dimb->metadata = IDP_CopyProperty(simb->metadata);
+ }
+}
+
bool IMB_metadata_add_field(struct ImBuf *img, const char *key, const char *value)
{
IDProperty *prop;
diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c
index 29bb35986e8..4b49076dcd6 100644
--- a/source/blender/imbuf/intern/moviecache.c
+++ b/source/blender/imbuf/intern/moviecache.c
@@ -147,8 +147,8 @@ static void check_unused_keys(MovieCache *cache)
BLI_ghashIterator_init(&gh_iter, cache->hash);
while (!BLI_ghashIterator_done(&gh_iter)) {
- MovieCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
- MovieCacheItem *item = BLI_ghashIterator_getValue(&gh_iter);
+ const MovieCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
+ const MovieCacheItem *item = BLI_ghashIterator_getValue(&gh_iter);
bool remove;
BLI_ghashIterator_step(&gh_iter);
diff --git a/source/blender/imbuf/intern/oiio/CMakeLists.txt b/source/blender/imbuf/intern/oiio/CMakeLists.txt
index 5fb8f11602e..c873fa3f32d 100644
--- a/source/blender/imbuf/intern/oiio/CMakeLists.txt
+++ b/source/blender/imbuf/intern/oiio/CMakeLists.txt
@@ -47,6 +47,7 @@ set(SRC
if(WITH_OPENIMAGEIO)
list(APPEND INC_SYS
${OPENIMAGEIO_INCLUDE_DIRS}
+ ${BOOST_INCLUDE_DIR}
)
add_definitions(-DWITH_OPENIMAGEIO)
endif()
diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
index 6e3f97a4902..7728183d3b6 100644
--- a/source/blender/imbuf/intern/oiio/openimageio_api.cpp
+++ b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
@@ -182,7 +182,7 @@ int imb_is_a_photoshop(const char *filename)
return BLI_testextensie_array(filename, photoshop_extension);
}
-int imb_save_photoshop(struct ImBuf *ibuf, const char *name, int flags)
+int imb_save_photoshop(struct ImBuf *ibuf, const char * /*name*/, int flags)
{
if (flags & IB_mem) {
std::cerr << __func__ << ": Photoshop PSD-save: Create PSD in memory"
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 5de243845a4..e805d3dc25c 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -38,6 +38,8 @@
#include <errno.h>
#include <algorithm>
+#include "DNA_scene_types.h" /* For OpenEXR compression constants */
+
#include <openexr_api.h>
#if defined (WIN32) && !defined(FREE_WINDOWS)
@@ -61,6 +63,7 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
#include "BLI_threads.h"
#include "BKE_idprop.h"
+#include "BKE_image.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -90,9 +93,32 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
#include <ImfStringAttribute.h>
#include <ImfStandardAttributes.h>
+/* multiview/multipart */
+#include <ImfMultiView.h>
+#include <ImfMultiPartInputFile.h>
+#include <ImfInputPart.h>
+#include <ImfOutputPart.h>
+#include <ImfMultiPartOutputFile.h>
+#include <ImfTiledOutputPart.h>
+#include <ImfPartType.h>
+#include <ImfPartHelper.h>
+
using namespace Imf;
using namespace Imath;
+extern "C"
+{
+/* prototype */
+static struct ExrPass *imb_exr_get_pass(ListBase *lb, char *passname);
+static bool exr_has_multiview(MultiPartInputFile& file);
+static bool exr_has_multipart_file(MultiPartInputFile& file);
+static bool exr_has_alpha(MultiPartInputFile& file);
+static bool exr_has_zbuffer(MultiPartInputFile& file);
+static void exr_printf(const char *__restrict format, ...);
+static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
+ bool *r_singlelayer, bool *r_multilayer, bool *r_multiview);
+}
+
/* Memory Input Stream */
class Mem_IStream : public Imf::IStream
@@ -284,21 +310,38 @@ int imb_is_a_openexr(unsigned char *mem)
static void openexr_header_compression(Header *header, int compression)
{
switch (compression) {
- case 0:
+ case R_IMF_EXR_CODEC_NONE:
header->compression() = NO_COMPRESSION;
break;
- case 1:
+ case R_IMF_EXR_CODEC_PXR24:
header->compression() = PXR24_COMPRESSION;
break;
- case 2:
+ case R_IMF_EXR_CODEC_ZIP:
header->compression() = ZIP_COMPRESSION;
break;
- case 3:
+ case R_IMF_EXR_CODEC_PIZ:
header->compression() = PIZ_COMPRESSION;
break;
- case 4:
+ case R_IMF_EXR_CODEC_RLE:
header->compression() = RLE_COMPRESSION;
break;
+ case R_IMF_EXR_CODEC_ZIPS:
+ header->compression() = ZIPS_COMPRESSION;
+ break;
+ case R_IMF_EXR_CODEC_B44:
+ header->compression() = B44_COMPRESSION;
+ break;
+ case R_IMF_EXR_CODEC_B44A:
+ header->compression() = B44A_COMPRESSION;
+ break;
+#if OPENEXR_VERSION_MAJOR >= 2 && OPENEXR_VERSION_MINOR >= 2
+ case R_IMF_EXR_CODEC_DWAA:
+ header->compression() = DWAA_COMPRESSION;
+ break;
+ case R_IMF_EXR_CODEC_DWAB:
+ header->compression() = DWAB_COMPRESSION;
+ break;
+#endif
default:
header->compression() = ZIP_COMPRESSION;
break;
@@ -321,13 +364,28 @@ static void openexr_header_metadata(Header *header, struct ImBuf *ibuf)
addXDensity(*header, ibuf->ppm[0] / 39.3700787); /* 1 meter = 39.3700787 inches */
}
-static int imb_save_openexr_half(struct ImBuf *ibuf, const char *name, int flags)
+static void openexr_header_metadata_callback(void *data, const char *propname, const char *prop)
+{
+ Header *header = (Header *)data;
+ header->insert(propname, StringAttribute(prop));
+}
+
+
+static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, size_t view_id),
+ ImBuf * (*getbuffer)(void *base, const size_t view_id))
{
const int channels = ibuf->channels;
- const int is_alpha = (channels >= 4) && (ibuf->planes == 32);
- const int is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
+ const bool is_alpha = (channels >= 4) && (ibuf->planes == 32);
+ const bool is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
const int width = ibuf->x;
const int height = ibuf->y;
+ const bool is_multiview = (flags & IB_multiview) && ibuf->userdata;
+
+ BLI_assert((!is_multiview) || (getview && getbuffer));
+
+ std::vector <string> views;
+ size_t view_id;
try
{
@@ -336,13 +394,22 @@ static int imb_save_openexr_half(struct ImBuf *ibuf, const char *name, int flags
openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
openexr_header_metadata(&header, ibuf);
- header.channels().insert("R", Channel(HALF));
- header.channels().insert("G", Channel(HALF));
- header.channels().insert("B", Channel(HALF));
- if (is_alpha)
- header.channels().insert("A", Channel(HALF));
- if (is_zbuf) // z we do as float always
- header.channels().insert("Z", Channel(Imf::FLOAT));
+ /* create views when possible */
+ for (view_id = 0; view_id < totviews; view_id ++)
+ views.push_back(is_multiview ? getview(ibuf->userdata, view_id) : "");
+
+ if (is_multiview)
+ addMultiView(header, views);
+
+ for (view_id = 0; view_id < totviews; view_id ++) {
+ header.channels().insert(insertViewName("R", views, view_id), Channel(HALF));
+ header.channels().insert(insertViewName("G", views, view_id), Channel(HALF));
+ header.channels().insert(insertViewName("B", views, view_id), Channel(HALF));
+ if (is_alpha)
+ header.channels().insert(insertViewName("A", views, view_id), Channel(HALF));
+ if (is_zbuf) // z we do as float always
+ header.channels().insert(insertViewName("Z", views, view_id), Channel(Imf::FLOAT));
+ }
FrameBuffer frameBuffer;
@@ -351,75 +418,91 @@ static int imb_save_openexr_half(struct ImBuf *ibuf, const char *name, int flags
OutputFile file(file_stream, header);
/* we store first everything in half array */
- RGBAZ *pixels = new RGBAZ[height * width];
- RGBAZ *to = pixels;
+ RGBAZ *pixels = new RGBAZ[height * width * totviews];
int xstride = sizeof(RGBAZ);
int ystride = xstride * width;
- /* indicate used buffers */
- frameBuffer.insert("R", Slice(HALF, (char *) &pixels[0].r, xstride, ystride));
- frameBuffer.insert("G", Slice(HALF, (char *) &pixels[0].g, xstride, ystride));
- frameBuffer.insert("B", Slice(HALF, (char *) &pixels[0].b, xstride, ystride));
- if (is_alpha)
- frameBuffer.insert("A", Slice(HALF, (char *) &pixels[0].a, xstride, ystride));
- if (is_zbuf)
- frameBuffer.insert("Z", Slice(Imf::FLOAT, (char *)(ibuf->zbuf_float + (height - 1) * width),
- sizeof(float), sizeof(float) * -width));
- if (ibuf->rect_float) {
- float *from;
-
- for (int i = ibuf->y - 1; i >= 0; i--) {
- from = ibuf->rect_float + channels * i * width;
-
- for (int j = ibuf->x; j > 0; j--) {
- to->r = from[0];
- to->g = (channels >= 2) ? from[1] : from[0];
- to->b = (channels >= 3) ? from[2] : from[0];
- to->a = (channels >= 4) ? from[3] : 1.0f;
- to++; from += channels;
+ for (view_id = 0; view_id < totviews; view_id ++) {
+ ImBuf *view_ibuf = is_multiview ? getbuffer(ibuf->userdata, view_id) : ibuf;
+ const size_t offset = view_id * width * height;
+ RGBAZ *to = pixels + offset;
+
+ /* indicate used buffers */
+ frameBuffer.insert(insertViewName("R", views, view_id), Slice(HALF, (char *) &pixels[offset].r, xstride, ystride));
+ frameBuffer.insert(insertViewName("G", views, view_id), Slice(HALF, (char *) &pixels[offset].g, xstride, ystride));
+ frameBuffer.insert(insertViewName("B", views, view_id), Slice(HALF, (char *) &pixels[offset].b, xstride, ystride));
+ if (is_alpha)
+ frameBuffer.insert(insertViewName("A", views, view_id), Slice(HALF, (char *) &pixels[offset].a, xstride, ystride));
+ if (is_zbuf)
+ frameBuffer.insert(insertViewName("Z", views, view_id), Slice(Imf::FLOAT, (char *)(view_ibuf->zbuf_float + (height - 1) * width),
+ sizeof(float), sizeof(float) * -width));
+ if (view_ibuf->rect_float) {
+ float *from;
+
+ for (int i = view_ibuf->y - 1; i >= 0; i--) {
+ from = view_ibuf->rect_float + channels * i * width;
+
+ for (int j = view_ibuf->x; j > 0; j--) {
+ to->r = from[0];
+ to->g = (channels >= 2) ? from[1] : from[0];
+ to->b = (channels >= 3) ? from[2] : from[0];
+ to->a = (channels >= 4) ? from[3] : 1.0f;
+ to++; from += channels;
+ }
}
}
- }
- else {
- unsigned char *from;
-
- for (int i = ibuf->y - 1; i >= 0; i--) {
- from = (unsigned char *)ibuf->rect + 4 * i * width;
-
- for (int j = ibuf->x; j > 0; j--) {
- to->r = srgb_to_linearrgb((float)from[0] / 255.0f);
- to->g = srgb_to_linearrgb((float)from[1] / 255.0f);
- to->b = srgb_to_linearrgb((float)from[2] / 255.0f);
- to->a = channels >= 4 ? (float)from[3] / 255.0f : 1.0f;
- to++; from += 4;
+ else {
+ unsigned char *from;
+
+ for (int i = view_ibuf->y - 1; i >= 0; i--) {
+ from = (unsigned char *)view_ibuf->rect + 4 * i * width;
+
+ for (int j = view_ibuf->x; j > 0; j--) {
+ to->r = srgb_to_linearrgb((float)from[0] / 255.0f);
+ to->g = srgb_to_linearrgb((float)from[1] / 255.0f);
+ to->b = srgb_to_linearrgb((float)from[2] / 255.0f);
+ to->a = channels >= 4 ? (float)from[3] / 255.0f : 1.0f;
+ to++; from += 4;
+ }
}
}
+
+ if (is_multiview)
+ IMB_freeImBuf(view_ibuf);
}
-// printf("OpenEXR-save: Writing OpenEXR file of height %d.\n", height);
+ exr_printf("OpenEXR-save: Writing OpenEXR file of height %d.\n", height);
file.setFrameBuffer(frameBuffer);
file.writePixels(height);
delete[] pixels;
}
- catch (const std::exception &exc)
+ catch (const std::exception& exc)
{
printf("OpenEXR-save: ERROR: %s\n", exc.what());
- return (0);
+ return false;
}
- return (1);
+ return true;
}
-static int imb_save_openexr_float(struct ImBuf *ibuf, const char *name, int flags)
+static bool imb_save_openexr_float(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, const size_t view_id),
+ ImBuf * (*getbuffer)(void *base, const size_t view_id))
{
const int channels = ibuf->channels;
- const int is_alpha = (channels >= 4) && (ibuf->planes == 32);
- const int is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
+ const bool is_alpha = (channels >= 4) && (ibuf->planes == 32);
+ const bool is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
const int width = ibuf->x;
const int height = ibuf->y;
+ const bool is_multiview = (flags & IB_multiview) && ibuf->userdata;
+
+ BLI_assert((!is_multiview) || (getview && getbuffer));
+
+ std::vector <string> views;
+ size_t view_id;
try
{
@@ -428,13 +511,22 @@ static int imb_save_openexr_float(struct ImBuf *ibuf, const char *name, int flag
openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
openexr_header_metadata(&header, ibuf);
- header.channels().insert("R", Channel(Imf::FLOAT));
- header.channels().insert("G", Channel(Imf::FLOAT));
- header.channels().insert("B", Channel(Imf::FLOAT));
- if (is_alpha)
- header.channels().insert("A", Channel(Imf::FLOAT));
- if (is_zbuf)
- header.channels().insert("Z", Channel(Imf::FLOAT));
+ /* create views when possible */
+ for (view_id = 0; view_id < totviews; view_id ++)
+ views.push_back(is_multiview ? getview(ibuf->userdata, view_id) : "");
+
+ if (is_multiview)
+ addMultiView(header, views);
+
+ for (view_id = 0; view_id < totviews; view_id ++) {
+ header.channels().insert(insertViewName("R", views, view_id), Channel(Imf::FLOAT));
+ header.channels().insert(insertViewName("G", views, view_id), Channel(Imf::FLOAT));
+ header.channels().insert(insertViewName("B", views, view_id), Channel(Imf::FLOAT));
+ if (is_alpha)
+ header.channels().insert(insertViewName("A", views, view_id), Channel(Imf::FLOAT));
+ if (is_zbuf)
+ header.channels().insert(insertViewName("Z", views, view_id), Channel(Imf::FLOAT));
+ }
FrameBuffer frameBuffer;
@@ -444,37 +536,41 @@ static int imb_save_openexr_float(struct ImBuf *ibuf, const char *name, int flag
int xstride = sizeof(float) * channels;
int ystride = -xstride * width;
- float *rect[4] = {NULL, NULL, NULL, NULL};
- /* last scanline, stride negative */
- rect[0] = ibuf->rect_float + channels * (height - 1) * width;
- rect[1] = (channels >= 2) ? rect[0] + 1 : rect[0];
- rect[2] = (channels >= 3) ? rect[0] + 2 : rect[0];
- rect[3] = (channels >= 4) ? rect[0] + 3 : rect[0]; /* red as alpha, is this needed since alpha isn't written? */
-
- frameBuffer.insert("R", Slice(Imf::FLOAT, (char *)rect[0], xstride, ystride));
- frameBuffer.insert("G", Slice(Imf::FLOAT, (char *)rect[1], xstride, ystride));
- frameBuffer.insert("B", Slice(Imf::FLOAT, (char *)rect[2], xstride, ystride));
- if (is_alpha)
- frameBuffer.insert("A", Slice(Imf::FLOAT, (char *)rect[3], xstride, ystride));
- if (is_zbuf)
- frameBuffer.insert("Z", Slice(Imf::FLOAT, (char *) (ibuf->zbuf_float + (height - 1) * width),
- sizeof(float), sizeof(float) * -width));
+ for (view_id = 0; view_id < totviews; view_id ++) {
+ float *rect[4] = {NULL, NULL, NULL, NULL};
+ ImBuf *view_ibuf = is_multiview ? getbuffer(ibuf->userdata, view_id) : ibuf;
+
+ /* last scanline, stride negative */
+ rect[0] = view_ibuf->rect_float + channels * (height - 1) * width;
+ rect[1] = (channels >= 2) ? rect[0] + 1 : rect[0];
+ rect[2] = (channels >= 3) ? rect[0] + 2 : rect[0];
+ rect[3] = (channels >= 4) ? rect[0] + 3 : rect[0]; /* red as alpha, is this needed since alpha isn't written? */
+
+ frameBuffer.insert(insertViewName("R", views, view_id), Slice(Imf::FLOAT, (char *)rect[0], xstride, ystride));
+ frameBuffer.insert(insertViewName("G", views, view_id), Slice(Imf::FLOAT, (char *)rect[1], xstride, ystride));
+ frameBuffer.insert(insertViewName("B", views, view_id), Slice(Imf::FLOAT, (char *)rect[2], xstride, ystride));
+ if (is_alpha)
+ frameBuffer.insert(insertViewName("A", views, view_id), Slice(Imf::FLOAT, (char *)rect[3], xstride, ystride));
+ if (is_zbuf)
+ frameBuffer.insert(insertViewName("Z", views, view_id), Slice(Imf::FLOAT, (char *) (view_ibuf->zbuf_float + (height - 1) * width),
+ sizeof(float), sizeof(float) * -width));
+
+ if (is_multiview)
+ IMB_freeImBuf(view_ibuf);
+ }
file.setFrameBuffer(frameBuffer);
file.writePixels(height);
}
- catch (const std::exception &exc)
+ catch (const std::exception& exc)
{
printf("OpenEXR-save: ERROR: %s\n", exc.what());
-
- return (0);
+ return false;
}
- return (1);
- // printf("OpenEXR-save: Done.\n");
+ return true;
}
-
int imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags)
{
if (flags & IB_mem) {
@@ -485,16 +581,48 @@ int imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags)
}
if (ibuf->ftype & OPENEXR_HALF)
- return imb_save_openexr_half(ibuf, name, flags);
+ return (int) imb_save_openexr_half(ibuf, name, flags, 1, NULL, NULL);
+ else {
+ /* when no float rect, we save as half (16 bits is sufficient) */
+ if (ibuf->rect_float == NULL)
+ return (int) imb_save_openexr_half(ibuf, name, flags, 1, NULL, NULL);
+ else
+ return (int) imb_save_openexr_float(ibuf, name, flags, 1, NULL, NULL);
+ }
+}
+
+static bool imb_save_openexr_multiview(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, const size_t view_id),
+ ImBuf * (*getbuffer)(void *base, const size_t view_id))
+{
+ if (flags & IB_mem) {
+ printf("OpenEXR-save: Create multiview EXR in memory CURRENTLY NOT SUPPORTED !\n");
+ imb_addencodedbufferImBuf(ibuf);
+ ibuf->encodedsize = 0;
+ return false;
+ }
+
+ if (ibuf->ftype & OPENEXR_HALF)
+ return imb_save_openexr_half(ibuf, name, flags, totviews, getview, getbuffer);
else {
/* when no float rect, we save as half (16 bits is sufficient) */
if (ibuf->rect_float == NULL)
- return imb_save_openexr_half(ibuf, name, flags);
+ return imb_save_openexr_half(ibuf, name, flags, totviews, getview, getbuffer);
else
- return imb_save_openexr_float(ibuf, name, flags);
+ return imb_save_openexr_float(ibuf, name, flags, totviews, getview, getbuffer);
}
}
+/* Save single-layer multiview OpenEXR
+ * If we have more multiview formats in the future, the function below could be incorporated
+ * in our ImBuf write functions, meanwhile this is an OpenEXR special case only */
+bool IMB_exr_multiview_save(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, size_t view_id),
+ ImBuf * (*getbuffer)(void *base, const size_t view_id))
+{
+ return imb_save_openexr_multiview(ibuf, name, flags, totviews, getview, getbuffer);
+}
+
/* ********************* Nicer API, MultiLayer and with Tile file support ************************************ */
/* naming rules:
@@ -508,18 +636,22 @@ static ListBase exrhandles = {NULL, NULL};
typedef struct ExrHandle {
struct ExrHandle *next, *prev;
+ char name[FILE_MAX];
- IFileStream *ifile_stream;
- InputFile *ifile;
+ IStream *ifile_stream;
+ MultiPartInputFile *ifile;
OFileStream *ofile_stream;
- TiledOutputFile *tofile;
+ MultiPartOutputFile *mpofile;
OutputFile *ofile;
int tilex, tiley;
int width, height;
int mipmap;
+ StringVector *multiView; /* it needs to be a pointer due to Windows release builds of EXR2.0 segfault when opening EXR bug */
+ int parts;
+
ListBase channels; /* flattened out, ExrChannel */
ListBase layers; /* hierarchical, pointing in end to ExrChannel */
} ExrHandle;
@@ -528,10 +660,12 @@ typedef struct ExrHandle {
typedef struct ExrChannel {
struct ExrChannel *next, *prev;
- char name[EXR_TOT_MAXNAME + 1]; /* full name of layer+pass */
+ char name[EXR_TOT_MAXNAME + 1]; /* full name with everything */
+ struct MultiViewChannelName *m; /* struct to store all multipart channel info */
int xstride, ystride; /* step to next pixel, to next scanline */
float *rect; /* first pointer to write in */
char chan_id; /* quick lookup of channel char */
+ int view_id; /* quick lookup of channel view */
} ExrChannel;
@@ -543,6 +677,10 @@ typedef struct ExrPass {
float *rect;
struct ExrChannel *chan[EXR_PASS_MAXCHAN];
char chan_id[EXR_PASS_MAXCHAN];
+
+ char internal_name[EXR_PASS_MAXNAME]; /* name with no view */
+ char view[EXR_VIEW_MAXNAME];
+ int view_id;
} ExrPass;
typedef struct ExrLayer {
@@ -556,40 +694,142 @@ typedef struct ExrLayer {
void *IMB_exr_get_handle(void)
{
ExrHandle *data = (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle");
+ data->multiView = new StringVector();
+
BLI_addtail(&exrhandles, data);
return data;
}
+void *IMB_exr_get_handle_name(const char *name)
+{
+ ExrHandle *data = (ExrHandle *) BLI_rfindstring(&exrhandles, name, offsetof(ExrHandle, name));
+
+ if (data == NULL) {
+ data = (ExrHandle *)IMB_exr_get_handle();
+ BLI_strncpy(data->name, name, strlen(name) + 1);
+ }
+ return data;
+}
+
+/* multiview functions */
+} // extern "C"
+
+extern "C"
+{
+
+void IMB_exr_add_view(void *handle, const char *name)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ data->multiView->push_back(name);
+}
+
+static int imb_exr_get_multiView_id(StringVector& views, const std::string& name)
+{
+ int count = 0;
+ for (StringVector::const_iterator i = views.begin(); count < views.size(); ++i) {
+ if (name == *i)
+ return count;
+ else
+ count ++;
+ }
+
+ /* no views or wrong name */
+ return -1;
+}
+
+static void imb_exr_get_views(MultiPartInputFile& file, StringVector& views)
+{
+ if (exr_has_multipart_file(file) == false) {
+ if (exr_has_multiview(file)) {
+ StringVector sv = multiView(file.header(0));
+ for (StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i)
+ views.push_back(*i);
+ }
+ }
+
+ else {
+ for (int p = 0; p < file.parts(); p++) {
+ std::string view = "";
+ if (file.header(p).hasView())
+ view = file.header(p).view();
+
+ if (imb_exr_get_multiView_id(views, view) == -1)
+ views.push_back(view);
+ }
+ }
+}
+
+/* Multilayer Blender files have the view name in all the passes (even the default view one) */
+static const char *imb_exr_insert_view_name(const char *passname, const char *viewname)
+{
+ if (viewname == NULL || viewname[0] == '\0')
+ return passname;
+
+ static char retstr[EXR_PASS_MAXNAME];
+ const char *end = passname + strlen(passname);
+ const char *token;
+
+ int len = IMB_exr_split_token(passname, end, &token);
+
+ if (len == 0)
+ BLI_snprintf(retstr, sizeof(retstr), "%s.%s", passname, viewname);
+ else
+ BLI_snprintf(retstr, sizeof(retstr), "%.*s%s.%s",
+ (int)(end - passname) - len, passname, viewname, token);
+
+ return retstr;
+}
+
/* adds flattened ExrChannels */
/* xstride, ystride and rect can be done in set_channel too, for tile writing */
-void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
+/* passname does not include view */
+void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, const char *viewname, int xstride, int ystride, float *rect)
{
ExrHandle *data = (ExrHandle *)handle;
ExrChannel *echan;
- echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr tile channel");
+ echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr channel");
+ echan->m = new MultiViewChannelName ();
- if (layname) {
- char lay[EXR_LAY_MAXNAME + 1], pass[EXR_PASS_MAXNAME + 1];
- BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
- BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
+ if (layname && layname[0] != '\0') {
+ echan->m->name = layname;
+ echan->m->name.append(".");
+ echan->m->name.append(passname);
+ }
+ else {
+ echan->m->name.assign(passname);
+ }
+
+ echan->m->internal_name = echan->m->name;
+
+ echan->m->view.assign(viewname ? viewname : "");
- BLI_snprintf(echan->name, sizeof(echan->name), "%s.%s", lay, pass);
+ /* quick look up */
+ echan->view_id = std::max(0, imb_exr_get_multiView_id(*data->multiView, echan->m->view));
+
+ /* name has to be unique, thus it's a combination of layer, pass, view, and channel */
+ if (layname && layname[0] != '\0') {
+ std::string raw_name = imb_exr_insert_view_name(echan->m->name.c_str(), echan->m->view.c_str());
+ BLI_strncpy(echan->name, raw_name.c_str(), sizeof(echan->name));
+ }
+ else if (data->multiView->size() > 1) {
+ std::string raw_name = insertViewName(echan->m->name, *data->multiView, echan->view_id);
+ BLI_strncpy(echan->name, raw_name.c_str(), sizeof(echan->name));
}
else {
- BLI_strncpy(echan->name, passname, EXR_TOT_MAXNAME - 1);
+ BLI_strncpy(echan->name, echan->m->name.c_str(), sizeof(echan->name));
}
echan->xstride = xstride;
echan->ystride = ystride;
echan->rect = rect;
- // printf("added channel %s\n", echan->name);
+ exr_printf("added channel %s\n", echan->name);
BLI_addtail(&data->channels, echan);
}
-/* only used for writing temp. render results (not image files) */
-int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress)
+/* used for output files (from RenderResult) (single and multilayer, single and multiview) */
+int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress, const StampData *stamp)
{
ExrHandle *data = (ExrHandle *)handle;
Header header(width, height);
@@ -598,14 +838,22 @@ int IMB_exr_begin_write(void *handle, const char *filename, int width, int heigh
data->width = width;
data->height = height;
+ bool is_singlelayer, is_multilayer, is_multiview;
+
for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next)
header.channels().insert(echan->name, Channel(Imf::FLOAT));
openexr_header_compression(&header, compress);
- // openexr_header_metadata(&header, ibuf); // no imbuf. cant write
+ BKE_stamp_info_callback(&header, stamp, openexr_header_metadata_callback);
/* header.lineOrder() = DECREASING_Y; this crashes in windows for file read! */
- header.insert("BlenderMultiChannel", StringAttribute("Blender V2.55.1 and newer"));
+ imb_exr_type_by_channels(header.channels(), *data->multiView, &is_singlelayer, &is_multilayer, &is_multiview);
+
+ if (is_multilayer)
+ header.insert("BlenderMultiChannel", StringAttribute("Blender V2.55.1 and newer"));
+
+ if (is_multiview)
+ addMultiView(header, *data->multiView);
/* avoid crash/abort when we don't have permission to write here */
/* manually create ofstream, so we can handle utf-8 filepaths on windows */
@@ -613,7 +861,7 @@ int IMB_exr_begin_write(void *handle, const char *filename, int width, int heigh
data->ofile_stream = new OFileStream(filename);
data->ofile = new OutputFile(*(data->ofile_stream), header);
}
- catch (const std::exception &exc) {
+ catch (const std::exception& exc) {
std::cerr << "IMB_exr_begin_write: ERROR: " << exc.what() << std::endl;
delete data->ofile;
@@ -626,10 +874,13 @@ int IMB_exr_begin_write(void *handle, const char *filename, int width, int heigh
return (data->ofile != NULL);
}
+/* only used for writing temp. render results (not image files)
+ * (FSA and Save Buffers) */
void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley)
{
ExrHandle *data = (ExrHandle *)handle;
Header header(width, height);
+ std::vector<Header> headers;
ExrChannel *echan;
data->tilex = tilex;
@@ -638,26 +889,47 @@ void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int
data->height = height;
data->mipmap = mipmap;
- for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next)
- header.channels().insert(echan->name, Channel(Imf::FLOAT));
-
header.setTileDescription(TileDescription(tilex, tiley, (mipmap) ? MIPMAP_LEVELS : ONE_LEVEL));
- header.lineOrder() = RANDOM_Y;
header.compression() = RLE_COMPRESSION;
+ header.setType(TILEDIMAGE);
header.insert("BlenderMultiChannel", StringAttribute("Blender V2.43"));
+ int numparts = data->multiView->size();
+
+ /* copy header from all parts of input to our header array
+ * those temporary files have one part per view */
+ for (int i = 0; i < numparts; i++) {
+ headers.push_back (header);
+ headers[headers.size() - 1].setView((*(data->multiView))[i]);
+ headers[headers.size() - 1].setName((*(data->multiView))[i]);
+ }
+
+ exr_printf("\nIMB_exrtile_begin_write\n");
+ exr_printf("%s %-6s %-22s \"%s\"\n", "p", "view", "name", "internal_name");
+ exr_printf("---------------------------------------------------------------\n");
+
+ /* assign channels */
+ for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+
+ echan->m->internal_name = echan->m->name;
+ echan->m->part_number = echan->view_id;
+
+ headers[echan->view_id].channels().insert(echan->m->internal_name, Channel(Imf::FLOAT));
+ exr_printf("%d %-6s %-22s \"%s\"\n", echan->m->part_number, echan->m->view.c_str(), echan->m->name.c_str(), echan->m->internal_name.c_str());
+ }
+
/* avoid crash/abort when we don't have permission to write here */
/* manually create ofstream, so we can handle utf-8 filepaths on windows */
try {
data->ofile_stream = new OFileStream(filename);
- data->tofile = new TiledOutputFile(*(data->ofile_stream), header);
+ data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), &headers[0], headers.size());
}
catch (const std::exception &) {
- delete data->tofile;
+ delete data->mpofile;
delete data->ofile_stream;
- data->tofile = NULL;
+ data->mpofile = NULL;
data->ofile_stream = NULL;
}
}
@@ -666,12 +938,13 @@ void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int
int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *height)
{
ExrHandle *data = (ExrHandle *)handle;
+ ExrChannel *echan;
if (BLI_exists(filename) && BLI_file_size(filename) > 32) { /* 32 is arbitrary, but zero length files crashes exr */
/* avoid crash/abort when we don't have permission to write here */
try {
data->ifile_stream = new IFileStream(filename);
- data->ifile = new InputFile(*(data->ifile_stream));
+ data->ifile = new MultiPartInputFile(*(data->ifile_stream));
}
catch (const std::exception &) {
delete data->ifile;
@@ -682,14 +955,24 @@ int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *heig
}
if (data->ifile) {
- Box2i dw = data->ifile->header().dataWindow();
+ Box2i dw = data->ifile->header(0).dataWindow();
data->width = *width = dw.max.x - dw.min.x + 1;
data->height = *height = dw.max.y - dw.min.y + 1;
- const ChannelList &channels = data->ifile->header().channels();
+ imb_exr_get_views(*data->ifile, *data->multiView);
- for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
- IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
+ std::vector<MultiViewChannelName> channels;
+ GetChannelsInMultiPartFile(*data->ifile, channels);
+
+ for (size_t i = 0; i < channels.size(); i++) {
+ IMB_exr_add_channel(data, NULL, channels[i].name.c_str(), channels[i].view.c_str(), 0, 0, NULL);
+
+ echan = (ExrChannel *)data->channels.last;
+ echan->m->name = channels[i].name;
+ echan->m->view = channels[i].view;
+ echan->m->part_number = channels[i].part_number;
+ echan->m->internal_name = channels[i].internal_name;
+ }
return 1;
}
@@ -698,6 +981,7 @@ int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *heig
}
/* still clumsy name handling, layers/channels can be ordered as list in list later */
+/* passname here is the raw channel name without the layer */
void IMB_exr_set_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
{
ExrHandle *data = (ExrHandle *)handle;
@@ -722,37 +1006,53 @@ void IMB_exr_set_channel(void *handle, const char *layname, const char *passname
echan->rect = rect;
}
else
- printf("IMB_exrtile_set_channel error %s\n", name);
-}
-
-void IMB_exrtile_clear_channels(void *handle)
-{
- ExrHandle *data = (ExrHandle *)handle;
- BLI_freelistN(&data->channels);
+ printf("IMB_exr_set_channel error %s\n", name);
}
-void IMB_exrtile_write_channels(void *handle, int partx, int party, int level)
+float *IMB_exr_channel_rect(void *handle, const char *layname, const char *passname, const char *viewname)
{
ExrHandle *data = (ExrHandle *)handle;
- FrameBuffer frameBuffer;
ExrChannel *echan;
+ char name[EXR_TOT_MAXNAME + 1];
- for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
- float *rect = echan->rect - echan->xstride * partx - echan->ystride * party;
+ if (layname) {
+ char lay[EXR_LAY_MAXNAME + 1], pass[EXR_PASS_MAXNAME + 1];
+ BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
+ BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
- frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)rect,
- echan->xstride * sizeof(float), echan->ystride * sizeof(float)));
+ BLI_snprintf(name, sizeof(name), "%s.%s", lay, pass);
}
+ else
+ BLI_strncpy(name, passname, EXR_TOT_MAXNAME - 1);
- data->tofile->setFrameBuffer(frameBuffer);
-
- try {
- // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
- data->tofile->writeTile(partx / data->tilex, party / data->tiley, level);
+ /* name has to be unique, thus it's a combination of layer, pass, view, and channel */
+ if (layname && layname[0] != '\0') {
+ std::string raw_name = imb_exr_insert_view_name(name, viewname);
+ BLI_strncpy(name, raw_name.c_str(), sizeof(name));
}
- catch (const std::exception &exc) {
- std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl;
+ else if (data->multiView->size() > 1) {
+ size_t view_id = std::max(0, imb_exr_get_multiView_id(*data->multiView, viewname));
+ std::string raw_name = insertViewName(name, *data->multiView, view_id);
+ BLI_strncpy(name, raw_name.c_str(), sizeof(name));
}
+
+ echan = (ExrChannel *)BLI_findstring(&data->channels, name, offsetof(ExrChannel, name));
+
+ if (echan)
+ return echan->rect;
+
+ return NULL;
+}
+
+void IMB_exr_clear_channels(void *handle)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ ExrChannel *chan;
+
+ for (chan = (ExrChannel *)data->channels.first; chan; chan = chan->next)
+ delete chan->m;
+
+ BLI_freelistN(&data->channels);
}
void IMB_exr_write_channels(void *handle)
@@ -774,7 +1074,7 @@ void IMB_exr_write_channels(void *handle)
try {
data->ofile->writePixels(data->height);
}
- catch (const std::exception &exc) {
+ catch (const std::exception& exc) {
std::cerr << "OpenEXR-writePixels: ERROR: " << exc.what() << std::endl;
}
}
@@ -783,49 +1083,177 @@ void IMB_exr_write_channels(void *handle)
}
}
-void IMB_exr_read_channels(void *handle)
+/* temporary function, used for FSA and Save Buffers */
+/* called once per tile * view */
+void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname)
{
ExrHandle *data = (ExrHandle *)handle;
FrameBuffer frameBuffer;
ExrChannel *echan;
+ std::string view(viewname);
+ const size_t view_id = imb_exr_get_multiView_id(*data->multiView, view);
+
+ exr_printf("\nIMB_exrtile_write_channels(view: %s)\n", viewname);
+ exr_printf("%s %-6s %-22s \"%s\"\n", "p", "view", "name", "internal_name");
+ exr_printf("---------------------------------------------------------------------\n");
+
+ for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+
+ /* eventually we can make the parts' channels to include
+ only the current view TODO */
+ if (strcmp(viewname, echan->m->view.c_str()) != 0)
+ continue;
+
+ exr_printf("%d %-6s %-22s \"%s\"\n",
+ echan->m->part_number,
+ echan->m->view.c_str(),
+ echan->m->name.c_str(),
+ echan->m->internal_name.c_str()
+ );
+
+ float *rect = echan->rect - echan->xstride * partx - echan->ystride * party;
+ frameBuffer.insert(echan->m->internal_name,
+ Slice(Imf::FLOAT,
+ (char *)rect,
+ echan->xstride * sizeof(float),
+ echan->ystride * sizeof(float)
+ )
+ );
+ }
+
+ TiledOutputPart out (*data->mpofile, view_id);
+ out.setFrameBuffer(frameBuffer);
+
+ try {
+ // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
+ out.writeTile(partx / data->tilex, party / data->tiley, level);
+ }
+ catch (const std::exception& exc) {
+ std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl;
+ }
+}
+
+/* called only when handle has all views */
+void IMB_exrmultiview_write_channels(void *handle, const char *viewname)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ const size_t view_id = viewname ? imb_exr_get_multiView_id(*data->multiView, viewname) : -1;
+ int numparts = (view_id == -1 ? data->parts : view_id + 1);
+ std::vector <FrameBuffer> frameBuffers(numparts);
+ std::vector <OutputPart> outputParts;
+ ExrChannel *echan;
+ int i, part;
+
+ if (data->channels.first == NULL)
+ return;
+
+ exr_printf("\nIMB_exrmultiview_write_channels()\n");
+
+ for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+ if (view_id != -1 && echan->view_id != view_id)
+ continue;
+
+ part = (view_id == -1 ? echan->m->part_number : echan->view_id);
+
+ /* last scanline, stride negative */
+ float *rect = echan->rect + echan->xstride * (data->height - 1) * data->width;
+ frameBuffers[part].insert(echan->m->internal_name,
+ Slice(Imf::FLOAT,
+ (char *)rect,
+ echan->xstride * sizeof(float),
+ -echan->ystride * sizeof(float))
+ );
+ }
+
+ for (i = 0; i < numparts; i++) {
+ OutputPart out(*data->mpofile, i);
+ out.setFrameBuffer(frameBuffers[i]);
+ outputParts.push_back(out);
+ }
+
+ try {
+ for (i = 0; i < numparts; i++) {
+ if (view_id != -1 && i != view_id)
+ continue;
+
+ outputParts[i].writePixels(data->height);
+ }
+ }
+ catch (const std::exception& exc) {
+ std::cerr << "OpenEXR-write Multi Part: ERROR: " << exc.what() << std::endl;
+ }
+}
+
+void IMB_exr_read_channels(void *handle)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ ExrChannel *echan;
+ int numparts = data->ifile->parts();
+ std::vector<FrameBuffer> frameBuffers(numparts);
+ std::vector<InputPart> inputParts;
/* check if exr was saved with previous versions of blender which flipped images */
- const StringAttribute *ta = data->ifile->header().findTypedAttribute <StringAttribute> ("BlenderMultiChannel");
+ const StringAttribute *ta = data->ifile->header(0).findTypedAttribute <StringAttribute> ("BlenderMultiChannel");
short flip = (ta && STREQLEN(ta->value().c_str(), "Blender V2.43", 13)); /* 'previous multilayer attribute, flipped */
+ exr_printf("\nIMB_exr_read_channels\n%s %-6s %-22s \"%s\"\n---------------------------------------------------------------------\n", "p", "view", "name", "internal_name");
+
for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
+ exr_printf("%d %-6s %-22s \"%s\"\n", echan->m->part_number, echan->m->view.c_str(), echan->m->name.c_str(), echan->m->internal_name.c_str());
if (echan->rect) {
if (flip)
- frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)echan->rect,
+ frameBuffers[echan->m->part_number].insert(echan->m->internal_name, Slice(Imf::FLOAT, (char *)echan->rect,
echan->xstride * sizeof(float), echan->ystride * sizeof(float)));
else
- frameBuffer.insert(echan->name, Slice(Imf::FLOAT, (char *)(echan->rect + echan->xstride * (data->height - 1) * data->width),
+ frameBuffers[echan->m->part_number].insert(echan->m->internal_name, Slice(Imf::FLOAT, (char *)(echan->rect + echan->xstride * (data->height - 1) * data->width),
echan->xstride * sizeof(float), -echan->ystride * sizeof(float)));
}
else
- printf("warning, channel with no rect set %s\n", echan->name);
+ printf("warning, channel with no rect set %s\n", echan->m->internal_name.c_str());
}
- data->ifile->setFrameBuffer(frameBuffer);
+ for (int i = 0; i < numparts; i++) {
+ InputPart in (*data->ifile, i);
+ in.setFrameBuffer(frameBuffers[i]);
+ inputParts.push_back(in);
+ }
try {
- data->ifile->readPixels(0, data->height - 1);
+ for (int i = 0; i < numparts; i++) {
+ Header header = inputParts[i].header();
+ exr_printf("readPixels:readPixels[%d]: min.y: %d, max.y: %d\n", i, header.dataWindow().min.y, header.dataWindow().max.y);
+ inputParts[i].readPixels(header.dataWindow().min.y, header.dataWindow().max.y);
+ inputParts[i].readPixels(0, data->height - 1);
+ }
}
- catch (const std::exception &exc) {
+ catch (const std::exception& exc) {
std::cerr << "OpenEXR-readPixels: ERROR: " << exc.what() << std::endl;
}
}
void IMB_exr_multilayer_convert(void *handle, void *base,
+ void * (*addview)(void *base, const char *str),
void * (*addlayer)(void *base, const char *str),
void (*addpass)(void *base, void *lay, const char *str,
- float *rect, int totchan, const char *chan_id))
+ float *rect, int totchan, const char *chan_id,
+ const char *view))
{
ExrHandle *data = (ExrHandle *)handle;
ExrLayer *lay;
ExrPass *pass;
+ /* RenderResult needs at least one RenderView */
+ if (data->multiView->size() == 0) {
+ addview(base, "");
+ }
+ else {
+ /* add views to RenderResult */
+ for (StringVector::const_iterator i = data->multiView->begin(); i != data->multiView->end(); ++i) {
+ addview(base, (*i).c_str());
+ }
+ }
+
if (BLI_listbase_is_empty(&data->layers)) {
printf("cannot convert multilayer, no layers in handle\n");
return;
@@ -835,32 +1263,99 @@ void IMB_exr_multilayer_convert(void *handle, void *base,
void *laybase = addlayer(base, lay->name);
if (laybase) {
for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
- addpass(base, laybase, pass->name, pass->rect, pass->totchan, pass->chan_id);
+ addpass(base, laybase, pass->internal_name, pass->rect, pass->totchan, pass->chan_id, pass->view);
pass->rect = NULL;
}
}
}
}
+void IMB_exr_multiview_convert(void *handle, void *base,
+ void (*addview)(void *base, const char *str),
+ void (*addbuffer)(void *base, const char *str, ImBuf *ibuf, const int frame),
+ const int frame)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ MultiPartInputFile *file = data->ifile;
+ ExrLayer *lay;
+ ExrPass *pass;
+ ImBuf *ibuf = NULL;
+ const bool is_alpha = exr_has_alpha(*file);
+ Box2i dw = file->header(0).dataWindow();
+ const size_t width = dw.max.x - dw.min.x + 1;
+ const size_t height = dw.max.y - dw.min.y + 1;
+ const bool is_depth = exr_has_zbuffer(*file);
+
+ /* add views to RenderResult */
+ for (StringVector::const_iterator i = data->multiView->begin(); i != data->multiView->end(); ++i) {
+ addview(base, (*i).c_str());
+ }
+
+ if (BLI_listbase_is_empty(&data->layers)) {
+ printf("cannot convert multiviews, no views in handle\n");
+ return;
+ }
+
+ /* there is one float/pass per layer (layer here is a view) */
+ BLI_assert(BLI_listbase_count_ex(&data->layers, 2) == 1);
+ lay = (ExrLayer *)data->layers.first;
+ for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
+ if (STREQ(pass->chan_id, "RGB") || STREQ(pass->chan_id, "RGBA")) {
+ ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, IB_rectfloat);
+
+ if (!ibuf) {
+ printf("error creating multiview buffer\n");
+ return;
+ }
+
+ IMB_buffer_float_from_float(
+ ibuf->rect_float, pass->rect, pass->totchan,
+ IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false,
+ ibuf->x, ibuf->y, ibuf->x, ibuf->x);
+
+ if (hasXDensity(file->header(0))) {
+ ibuf->ppm[0] = xDensity(file->header(0)) * 39.3700787f;
+ ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header(0).pixelAspectRatio();
+ }
+
+ if (is_depth) {
+ ExrPass *zpass;
+ for (zpass = (ExrPass *)lay->passes.first; zpass; zpass = zpass->next) {
+ if (STREQ(zpass->chan_id, "Z") && STREQ(zpass->view, pass->view)) {
+ addzbuffloatImBuf(ibuf);
+ memcpy(ibuf->zbuf_float, zpass->rect, sizeof(float) * ibuf->x * ibuf->y);
+ }
+ }
+ }
+
+ addbuffer(base, pass->view, ibuf, frame);
+ }
+ }
+}
void IMB_exr_close(void *handle)
{
ExrHandle *data = (ExrHandle *)handle;
ExrLayer *lay;
ExrPass *pass;
+ ExrChannel *chan;
delete data->ifile;
delete data->ifile_stream;
delete data->ofile;
- delete data->tofile;
+ delete data->mpofile;
delete data->ofile_stream;
+ delete data->multiView;
data->ifile = NULL;
data->ifile_stream = NULL;
data->ofile = NULL;
- data->tofile = NULL;
+ data->mpofile = NULL;
data->ofile_stream = NULL;
+ for (chan = (ExrChannel *)data->channels.first; chan; chan = chan->next) {
+ delete chan->m;
+ }
BLI_freelistN(&data->channels);
for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
@@ -878,7 +1373,7 @@ void IMB_exr_close(void *handle)
/* ********* */
/* get a substring from the end of the name, separated by '.' */
-static int imb_exr_split_token(const char *str, const char *end, const char **token)
+int IMB_exr_split_token(const char *str, const char *end, const char **token)
{
ptrdiff_t maxlen = end - str;
int len = 0;
@@ -892,7 +1387,7 @@ static int imb_exr_split_token(const char *str, const char *end, const char **to
static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *passname)
{
- const char *name = echan->name;
+ const char *name = echan->m->name.c_str();
const char *end = name + strlen(name);
const char *token;
char tokenbuf[EXR_TOT_MAXNAME];
@@ -914,7 +1409,7 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
}
/* last token is single character channel identifier */
- len = imb_exr_split_token(name, end, &token);
+ len = IMB_exr_split_token(name, end, &token);
if (len == 0) {
printf("multilayer read: bad channel name: %s\n", name);
return 0;
@@ -952,7 +1447,7 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
end -= len + 1; /* +1 to skip '.' separator */
/* second token is pass name */
- len = imb_exr_split_token(name, end, &token);
+ len = IMB_exr_split_token(name, end, &token);
if (len == 0) {
printf("multilayer read: bad channel name: %s\n", name);
return 0;
@@ -1001,7 +1496,7 @@ static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname)
}
/* creates channels, makes a hierarchy and assigns memory to channels */
-static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
+static ExrHandle *imb_exr_begin_read_mem(IStream &file_stream, MultiPartInputFile &file, int width, int height)
{
ExrLayer *lay;
ExrPass *pass;
@@ -1010,30 +1505,59 @@ static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
int a;
char layname[EXR_TOT_MAXNAME], passname[EXR_TOT_MAXNAME];
- data->ifile = file;
+ data->ifile_stream = &file_stream;
+ data->ifile = &file;
+
data->width = width;
data->height = height;
- const ChannelList &channels = data->ifile->header().channels();
+ std::vector<MultiViewChannelName> channels;
+ GetChannelsInMultiPartFile(*data->ifile, channels);
+
+ data->multiView = new StringVector();
+ imb_exr_get_views(*data->ifile, *data->multiView);
- for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
- IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
+ for (size_t i = 0; i < channels.size(); i++) {
+ IMB_exr_add_channel(data, NULL, channels[i].name.c_str(), channels[i].view.c_str(), 0, 0, NULL);
+
+ echan = (ExrChannel *)data->channels.last;
+ echan->m->name = channels[i].name;
+ echan->m->view = channels[i].view;
+ echan->m->part_number = channels[i].part_number;
+ echan->m->internal_name = channels[i].internal_name;
+ }
/* now try to sort out how to assign memory to the channels */
/* first build hierarchical layer list */
for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
- if (imb_exr_split_channel_name(echan, layname, passname) ) {
+ if (imb_exr_split_channel_name(echan, layname, passname)) {
+
+ const char *view = echan->m->view.c_str();
+ char internal_name[EXR_PASS_MAXNAME];
+
+ BLI_strncpy(internal_name, passname, EXR_PASS_MAXNAME);
+
+ if (view[0] != '\0') {
+ char tmp_pass[EXR_PASS_MAXNAME];
+ BLI_snprintf(tmp_pass, sizeof(tmp_pass), "%s.%s", passname, view);
+ BLI_strncpy(passname, tmp_pass, sizeof(passname));
+ }
+
ExrLayer *lay = imb_exr_get_layer(&data->layers, layname);
ExrPass *pass = imb_exr_get_pass(&lay->passes, passname);
pass->chan[pass->totchan] = echan;
pass->totchan++;
+ pass->view_id = echan->view_id;
+ BLI_strncpy(pass->view, view, sizeof(pass->view));
+ BLI_strncpy(pass->internal_name, internal_name, EXR_PASS_MAXNAME);
+
if (pass->totchan >= EXR_PASS_MAXCHAN)
break;
}
}
if (echan) {
- printf("error, too many channels in one pass: %s\n", echan->name);
+ printf("error, too many channels in one pass: %s\n", echan->m->name.c_str());
IMB_exr_close(data);
return NULL;
}
@@ -1103,20 +1627,52 @@ static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
/* ********************************************************* */
/* debug only */
-static void exr_print_filecontents(InputFile *file)
+static void exr_printf(const char *fmt, ...)
{
- const ChannelList &channels = file->header().channels();
+#if 0
+ char output[1024];
+ va_list args;
+ va_start(args, fmt);
+ std::vsprintf(output, fmt, args);
+ va_end(args);
+ printf("%s", output);
+#else
+ (void)fmt;
+#endif
+}
- for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
- const Channel &channel = i.channel();
- printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
+static void exr_print_filecontents(MultiPartInputFile& file)
+{
+ int numparts = file.parts();
+ if (numparts == 1 && hasMultiView(file.header(0))) {
+ const StringVector views = multiView(file.header(0));
+ printf("OpenEXR-load: MultiView file\n");
+ printf("OpenEXR-load: Default view: %s\n", defaultViewName(views).c_str());
+ for (StringVector::const_iterator i = views.begin(); i != views.end(); ++i) {
+ printf("OpenEXR-load: Found view %s\n", (*i).c_str());
+ }
+ }
+ else if (numparts > 1) {
+ printf("OpenEXR-load: MultiPart file\n");
+ for (int i = 0; i < numparts; i++) {
+ if (file.header(i).hasView())
+ printf("OpenEXR-load: Part %d: view = \"%s\"\n", i, file.header(i).view().c_str());
+ }
+ }
+
+ for (int j = 0; j < numparts; j++) {
+ const ChannelList& channels = file.header(j).channels();
+ for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
+ const Channel& channel = i.channel();
+ printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
+ }
}
}
/* for non-multilayer, map R G B A channel names to something that's in this file */
-static const char *exr_rgba_channelname(InputFile *file, const char *chan)
+static const char *exr_rgba_channelname(MultiPartInputFile& file, const char *chan)
{
- const ChannelList &channels = file->header().channels();
+ const ChannelList& channels = file.header(0).channels();
for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
/* const Channel &channel = i.channel(); */ /* Not used yet */
@@ -1131,48 +1687,48 @@ static const char *exr_rgba_channelname(InputFile *file, const char *chan)
return chan;
}
-static bool exr_has_rgb(InputFile *file)
+static bool exr_has_rgb(MultiPartInputFile& file)
{
- return file->header().channels().findChannel("R") != NULL &&
- file->header().channels().findChannel("G") != NULL &&
- file->header().channels().findChannel("B") != NULL;
+ return file.header(0).channels().findChannel("R") != NULL &&
+ file.header(0).channels().findChannel("G") != NULL &&
+ file.header(0).channels().findChannel("B") != NULL;
}
-static bool exr_has_luma(InputFile *file)
+static bool exr_has_luma(MultiPartInputFile& file)
{
/* Y channel is the luma and should always present fir luma space images,
* optionally it could be also channels for chromas called BY and RY.
*/
- return file->header().channels().findChannel("Y") != NULL;
+ return file.header(0).channels().findChannel("Y") != NULL;
}
-static bool exr_has_chroma(InputFile *file)
+static bool exr_has_chroma(MultiPartInputFile& file)
{
- return file->header().channels().findChannel("BY") != NULL &&
- file->header().channels().findChannel("RY") != NULL;
+ return file.header(0).channels().findChannel("BY") != NULL &&
+ file.header(0).channels().findChannel("RY") != NULL;
}
-static int exr_has_zbuffer(InputFile *file)
+static bool exr_has_zbuffer(MultiPartInputFile& file)
{
- return !(file->header().channels().findChannel("Z") == NULL);
+ return !(file.header(0).channels().findChannel("Z") == NULL);
}
-static int exr_has_alpha(InputFile *file)
+static bool exr_has_alpha(MultiPartInputFile& file)
{
- return !(file->header().channels().findChannel("A") == NULL);
+ return !(file.header(0).channels().findChannel("A") == NULL);
}
-static bool exr_is_multilayer(InputFile *file)
+static bool imb_exr_is_multilayer_file(MultiPartInputFile& file)
{
- const StringAttribute *comments = file->header().findTypedAttribute<StringAttribute>("BlenderMultiChannel");
- const ChannelList &channels = file->header().channels();
+ const StringAttribute *comments = file.header(0).findTypedAttribute<StringAttribute>("BlenderMultiChannel");
+ const ChannelList& channels = file.header(0).channels();
std::set <std::string> layerNames;
/* will not include empty layer names */
channels.layers(layerNames);
if (comments || layerNames.size() > 1)
- return 1;
+ return true;
if (layerNames.size()) {
/* if layerNames is not empty, it means at least one layer is non-empty,
@@ -1187,17 +1743,123 @@ static bool exr_is_multilayer(InputFile *file)
size_t pos = layerName.rfind ('.');
if (pos == std::string::npos)
- return 1;
+ return true;
}
}
- return 0;
+ return false;
+}
+
+static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
+ bool *r_singlelayer, bool *r_multilayer, bool *r_multiview)
+{
+ std::set <std::string> layerNames;
+
+ *r_singlelayer = true;
+ *r_multilayer = *r_multiview = false;
+
+ /* will not include empty layer names */
+ channels.layers(layerNames);
+
+ if (views.size() && views[0] != "")
+ *r_multiview = true;
+
+ if (layerNames.size()) {
+ /* if layerNames is not empty, it means at least one layer is non-empty,
+ * but it also could be layers without names in the file and such case
+ * shall be considered a multilayer exr
+ *
+ * that's what we do here: test whether there're empty layer names together
+ * with non-empty ones in the file
+ */
+ for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); i++)
+ for (std::set<string>::iterator i = layerNames.begin(); i != layerNames.end(); i++)
+ /* see if any layername differs from a viewname */
+ if (imb_exr_get_multiView_id(views, *i) == -1) {
+ std::string layerName = *i;
+ size_t pos = layerName.rfind ('.');
+
+ if (pos != std::string::npos) {
+ *r_multilayer = true;
+ *r_singlelayer = false;
+ return;
+ }
+ }
+ }
+ else {
+ *r_singlelayer = true;
+ *r_multilayer = false;
+ *r_multiview = false;
+ }
+
+ BLI_assert(r_singlelayer != r_multilayer);
+}
+
+bool IMB_exr_has_singlelayer_multiview(void *handle)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ MultiPartInputFile *file = data->ifile;
+ std::set <std::string> layerNames;
+ const ChannelList& channels = file->header(0).channels();
+ const StringAttribute *comments;
+
+ if (exr_has_multiview(*file) == false)
+ return false;
+
+ comments = file->header(0).findTypedAttribute<StringAttribute>("BlenderMultiChannel");
+
+ if (comments)
+ return false;
+
+ /* will not include empty layer names */
+ channels.layers(layerNames);
+
+ /* returns false if any layer differs from views list */
+ if (layerNames.size())
+ for (std::set<string>::iterator i = layerNames.begin(); i != layerNames.end(); i++)
+ if (imb_exr_get_multiView_id(*data->multiView, *i) == -1)
+ return false;
+
+ return true;
+}
+
+bool IMB_exr_has_multilayer(void *handle)
+{
+ ExrHandle *data = (ExrHandle *)handle;
+ return imb_exr_is_multilayer_file(*data->ifile);
+}
+
+static bool exr_has_multiview(MultiPartInputFile& file)
+{
+ return hasMultiView(file.header(0));
+}
+
+static bool exr_has_multipart_file(MultiPartInputFile& file)
+{
+ return file.parts() > 1;
+}
+
+/* it returns true if the file is multilayer or multiview */
+static bool imb_exr_is_multi(MultiPartInputFile& file)
+{
+ /* multipart files are treated as multilayer in blender - even if they are single layer openexr with multiview */
+ if (exr_has_multipart_file(file))
+ return true;
+
+ if (exr_has_multiview(file))
+ return true;
+
+ if (imb_exr_is_multilayer_file(file))
+ return true;
+
+ return false;
}
struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
struct ImBuf *ibuf = NULL;
- InputFile *file = NULL;
+ Mem_IStream *membuf = NULL;
+ MultiPartInputFile *file = NULL;
if (imb_is_a_openexr(mem) == 0) return(NULL);
@@ -1205,11 +1867,12 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
try
{
- Mem_IStream *membuf = new Mem_IStream(mem, size);
bool is_multi;
- file = new InputFile(*membuf);
- Box2i dw = file->header().dataWindow();
+ membuf = new Mem_IStream(mem, size);
+ file = new MultiPartInputFile(*membuf);
+
+ Box2i dw = file->header(0).dataWindow();
const int width = dw.max.x - dw.min.x + 1;
const int height = dw.max.y - dw.min.y + 1;
@@ -1217,38 +1880,54 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
// dw.min.x, dw.min.y, dw.max.x, dw.max.y);
if (0) // debug
- exr_print_filecontents(file);
+ exr_print_filecontents(*file);
- is_multi = exr_is_multilayer(file);
+ is_multi = imb_exr_is_multi(*file);
/* do not make an ibuf when */
if (is_multi && !(flags & IB_test) && !(flags & IB_multilayer)) {
printf("Error: can't process EXR multilayer file\n");
}
else {
- const int is_alpha = exr_has_alpha(file);
+ const int is_alpha = exr_has_alpha(*file);
ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, 0);
- if (hasXDensity(file->header())) {
- ibuf->ppm[0] = xDensity(file->header()) * 39.3700787f;
- ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header().pixelAspectRatio();
+ if (hasXDensity(file->header(0))) {
+ ibuf->ppm[0] = xDensity(file->header(0)) * 39.3700787f;
+ ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header(0).pixelAspectRatio();
}
ibuf->ftype = OPENEXR;
if (!(flags & IB_test)) {
- if (is_multi) { /* only enters with IB_multilayer flag set */
+
+ if (flags & IB_metadata) {
+ const Header & header = file->header(0);
+ Header::ConstIterator iter;
+
+ for (iter = header.begin(); iter != header.end(); iter++) {
+ const StringAttribute *attrib = file->header(0).findTypedAttribute <StringAttribute> (iter.name());
+
+ /* not all attributes are string attributes so we might get some NULLs here */
+ if (attrib) {
+ IMB_metadata_add_field(ibuf, iter.name(), attrib->value().c_str());
+ ibuf->flags |= IB_metadata;
+ }
+ }
+ }
+
+ if (is_multi && ((flags & IB_thumbnail) == 0)) { /* only enters with IB_multilayer flag set */
/* constructs channels for reading, allocates memory in channels */
- ExrHandle *handle = imb_exr_begin_read_mem(file, width, height);
+ ExrHandle *handle = imb_exr_begin_read_mem(*membuf, *file, width, height);
if (handle) {
IMB_exr_read_channels(handle);
ibuf->userdata = handle; /* potential danger, the caller has to check for this! */
}
}
else {
- const bool has_rgb = exr_has_rgb(file);
- const bool has_luma = exr_has_luma(file);
+ const bool has_rgb = exr_has_rgb(*file);
+ const bool has_luma = exr_has_luma(*file);
FrameBuffer frameBuffer;
float *first;
int xstride = sizeof(float) * 4;
@@ -1262,27 +1941,27 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
first += 4 * (height - 1) * width;
if (has_rgb) {
- frameBuffer.insert(exr_rgba_channelname(file, "R"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "R"),
Slice(Imf::FLOAT, (char *) first, xstride, ystride));
- frameBuffer.insert(exr_rgba_channelname(file, "G"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "G"),
Slice(Imf::FLOAT, (char *) (first + 1), xstride, ystride));
- frameBuffer.insert(exr_rgba_channelname(file, "B"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "B"),
Slice(Imf::FLOAT, (char *) (first + 2), xstride, ystride));
}
else if (has_luma) {
- frameBuffer.insert(exr_rgba_channelname(file, "Y"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "Y"),
Slice(Imf::FLOAT, (char *) first, xstride, ystride));
- frameBuffer.insert(exr_rgba_channelname(file, "BY"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "BY"),
Slice(Imf::FLOAT, (char *) (first + 1), xstride, ystride, 1, 1, 0.5f));
- frameBuffer.insert(exr_rgba_channelname(file, "RY"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "RY"),
Slice(Imf::FLOAT, (char *) (first + 2), xstride, ystride, 1, 1, 0.5f));
}
/* 1.0 is fill value, this still needs to be assigned even when (is_alpha == 0) */
- frameBuffer.insert(exr_rgba_channelname(file, "A"),
+ frameBuffer.insert(exr_rgba_channelname(*file, "A"),
Slice(Imf::FLOAT, (char *) (first + 3), xstride, ystride, 1, 1, 1.0f));
- if (exr_has_zbuffer(file)) {
+ if (exr_has_zbuffer(*file)) {
float *firstz;
addzbuffloatImBuf(ibuf);
@@ -1291,8 +1970,9 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
frameBuffer.insert("Z", Slice(Imf::FLOAT, (char *)firstz, sizeof(float), -width * sizeof(float)));
}
- file->setFrameBuffer(frameBuffer);
- file->readPixels(dw.min.y, dw.max.y);
+ InputPart in (*file, 0);
+ in.setFrameBuffer(frameBuffer);
+ in.readPixels(dw.min.y, dw.max.y);
// XXX, ImBuf has no nice way to deal with this.
// ideally IM_rect would be used when the caller wants a rect BUT
@@ -1306,7 +1986,7 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
if (!has_rgb && has_luma) {
size_t a;
- if (exr_has_chroma(file)) {
+ if (exr_has_chroma(*file)) {
for (a = 0; a < (size_t) ibuf->x * ibuf->y; ++a) {
float *color = ibuf->rect_float + a * 4;
ycc_to_rgb(color[0] * 255.0f, color[1] * 255.0f, color[2] * 255.0f,
@@ -1323,6 +2003,7 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
}
/* file is no longer needed */
+ delete membuf;
delete file;
}
}
@@ -1332,11 +2013,12 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
}
return(ibuf);
}
- catch (const std::exception &exc)
+ catch (const std::exception& exc)
{
std::cerr << exc.what() << std::endl;
if (ibuf) IMB_freeImBuf(ibuf);
delete file;
+ delete membuf;
return (0);
}
diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h
index 376d2401b1c..77fa420322e 100644
--- a/source/blender/imbuf/intern/openexr/openexr_multi.h
+++ b/source/blender/imbuf/intern/openexr/openexr_multi.h
@@ -39,34 +39,61 @@
/* This api also supports max 8 channels per pass now. easy to fix! */
#define EXR_LAY_MAXNAME 64
#define EXR_PASS_MAXNAME 64
+#define EXR_VIEW_MAXNAME 64
#define EXR_TOT_MAXNAME 64
-#define EXR_PASS_MAXCHAN 8
+#define EXR_PASS_MAXCHAN 24
#ifdef __cplusplus
extern "C" {
#endif
+struct StampData;
+
void *IMB_exr_get_handle(void);
-void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect);
+void *IMB_exr_get_handle_name(const char *name);
+void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, const char *view, int xstride, int ystride, float *rect);
int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *height);
-int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress);
+int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress, const struct StampData *stamp);
void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley);
void IMB_exr_set_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect);
+float *IMB_exr_channel_rect(void *handle, const char *layname, const char *passname, const char *view);
void IMB_exr_read_channels(void *handle);
void IMB_exr_write_channels(void *handle);
-void IMB_exrtile_write_channels(void *handle, int partx, int party, int level);
-void IMB_exrtile_clear_channels(void *handle);
+void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname);
+void IMB_exrmultiview_write_channels(void *handle, const char *viewname);
+void IMB_exr_clear_channels(void *handle);
+
+void IMB_exr_multilayer_convert(
+ void *handle, void *base,
+ void * (*addview)(void *base, const char *str),
+ void * (*addlayer)(void *base, const char *str),
+ void (*addpass)(void *base, void *lay, const char *str, float *rect, int totchan,
+ const char *chan_id, const char *view));
+
+void IMB_exr_multiview_convert(
+ void *handle, void *base,
+ void (*addview)(void *base, const char *str),
+ void (*addbuffer)(void *base, const char *str, struct ImBuf *ibuf, const int frame),
+ const int frame);
-void IMB_exr_multilayer_convert(void *handle, void *base,
- void * (*addlayer)(void *base, const char *str),
- void (*addpass)(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id));
+bool IMB_exr_multiview_save(
+ struct ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
+ const char * (*getview)(void *base, size_t view_id),
+ struct ImBuf * (*getbuffer)(void *base, const size_t view_id));
void IMB_exr_close(void *handle);
+void IMB_exr_add_view(void *handle, const char *name);
+
+int IMB_exr_split_token(const char *str, const char *end, const char **token);
+
+bool IMB_exr_has_multilayer(void *handle);
+bool IMB_exr_has_singlelayer_multiview(void *handle);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/source/blender/imbuf/intern/openexr/openexr_stub.cpp b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
index 21fa878c08a..1a2ae7a97e1 100644
--- a/source/blender/imbuf/intern/openexr/openexr_stub.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
@@ -32,26 +32,52 @@
#include "openexr_api.h"
#include "openexr_multi.h"
-
void *IMB_exr_get_handle (void) {return NULL;}
-void IMB_exr_add_channel (void *handle, const char *layname, const char *channame, int xstride, int ystride, float *rect) { (void)handle; (void)layname; (void)channame; (void)xstride; (void)ystride; (void)rect; }
+void *IMB_exr_get_handle_name (const char * /*name*/) { return NULL;}
+void IMB_exr_add_channel (void * /*handle*/, const char * /*layname*/, const char * /*passname*/, const char * /*view*/,
+ int /*xstride*/, int /*ystride*/, float * /*rect*/) { }
+
+int IMB_exr_begin_read (void * /*handle*/, const char * /*filename*/, int * /*width*/, int * /*height*/) { return 0;}
+int IMB_exr_begin_write (void * /*handle*/, const char * /*filename*/, int /*width*/, int /*height*/, int /*compress*/, const struct StampData * /*stamp*/) { return 0;}
+void IMB_exrtile_begin_write (void * /*handle*/, const char * /*filename*/, int /*mipmap*/, int /*width*/, int /*height*/, int /*tilex*/, int /*tiley*/) { }
-int IMB_exr_begin_read (void *handle, const char *filename, int *width, int *height) { (void)handle; (void)filename; (void)width; (void)height; return 0;}
-int IMB_exr_begin_write (void *handle, const char *filename, int width, int height, int compress) { (void)handle; (void)filename; (void)width; (void)height; (void)compress; return 0;}
-void IMB_exrtile_begin_write (void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley) { (void)handle; (void)filename; (void)mipmap; (void)width; (void)height; (void)tilex; (void)tiley; }
+void IMB_exr_set_channel (void * /*handle*/, const char * /*layname*/, const char * /*passname*/, int /*xstride*/, int /*ystride*/, float * /*rect*/) { }
+float *IMB_exr_channel_rect (void * /*handle*/, const char * /*layname*/, const char * /*passname*/, const char * /*view*/) { return NULL; }
-void IMB_exr_set_channel (void *handle, const char *layname, const char *channame, int xstride, int ystride, float *rect) { (void)handle; (void)layname; (void)channame; (void)xstride; (void)ystride; (void)rect; }
+void IMB_exr_read_channels (void * /*handle*/) { }
+void IMB_exr_write_channels (void * /*handle*/) { }
+void IMB_exrtile_write_channels (void * /*handle*/, int /*partx*/, int /*party*/, int /*level*/, const char * /*viewname*/) { }
+void IMB_exrmultiview_write_channels(void * /*handle*/, const char * /*viewname*/) { }
+void IMB_exr_clear_channels (void * /*handle*/) { }
+
+void IMB_exr_multilayer_convert(
+ void * /*handle*/, void * /*base*/,
+ void * (* /*addview*/)(void *base, const char *str),
+ void * (* /*addlayer*/)(void *base, const char *str),
+ void (* /*addpass*/)(void *base, void *lay, const char *str, float *rect, int totchan,
+ const char *chan_id, const char *view))
+{
+}
-void IMB_exr_read_channels (void *handle) { (void)handle; }
-void IMB_exr_write_channels (void *handle) { (void)handle; }
-void IMB_exrtile_write_channels (void *handle, int partx, int party, int level) { (void)handle; (void)partx; (void)party; (void)level; }
-void IMB_exrtile_clear_channels (void *handle) { (void)handle; }
+void IMB_exr_multiview_convert(
+ void * /*handle*/, void * /*base*/,
+ void (* /*addview*/)(void *base, const char *str),
+ void (* /*addbuffer*/)(void *base, const char *str, struct ImBuf *ibuf, const int frame),
+ const int /*frame*/)
+{
+}
-void IMB_exr_multilayer_convert (void *handle, void *base,
- void * (*addlayer)(void *base, const char *str),
- void (*addpass)(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id))
+bool IMB_exr_multiview_save(
+ struct ImBuf * /*ibuf*/, const char * /*name*/, const int /*flags*/, const size_t /*totviews*/,
+ const char * (* /*getview*/)(void *base, size_t view_id),
+ struct ImBuf * (* /*getbuffer*/)(void *base, const size_t view_id))
{
- (void)handle; (void)base; (void)addlayer; (void)addpass;
+ return false;
}
-void IMB_exr_close (void *handle) { (void)handle; }
+void IMB_exr_close (void * /*handle*/) { }
+
+void IMB_exr_add_view(void * /*handle*/, const char * /*name*/) { }
+int IMB_exr_split_token(const char * /*str*/, const char * /*end*/, const char ** /*token*/) { return 1; }
+bool IMB_exr_has_multilayer(void * /*handle*/) { return false; }
+bool IMB_exr_has_singlelayer_multiview(void * /*handle*/) { return false; }
diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c
index 683bdabcd6c..1b6b413838d 100644
--- a/source/blender/imbuf/intern/png.c
+++ b/source/blender/imbuf/intern/png.c
@@ -138,6 +138,7 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
int channels_in_float = ibuf->channels ? ibuf->channels : 4;
float (*chanel_colormanage_cb)(float);
+ size_t num_bytes;
/* use the jpeg quality setting for compression */
int compression;
@@ -184,11 +185,11 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
}
/* copy image data */
-
+ num_bytes = ((size_t)ibuf->x) * ibuf->y * bytesperpixel;
if (is_16bit)
- pixels16 = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned short), "png 16bit pixels");
+ pixels16 = MEM_mallocN(num_bytes * sizeof(unsigned short), "png 16bit pixels");
else
- pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "png 8bit pixels");
+ pixels = MEM_mallocN(num_bytes * sizeof(unsigned char), "png 8bit pixels");
if (pixels == NULL && pixels16 == NULL) {
png_destroy_write_struct(&png_ptr, &info_ptr);
@@ -312,7 +313,7 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
rgb[0] = chanel_colormanage_cb(from_straight[0]);
rgb[1] = chanel_colormanage_cb(from_straight[1]);
rgb[2] = chanel_colormanage_cb(from_straight[2]);
- to16[0] = ftoshort(rgb_to_bw(rgb));
+ to16[0] = ftoshort(IMB_colormanagement_get_luminance(rgb));
to16++; from_float += 4;
}
}
@@ -321,7 +322,7 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
rgb[0] = chanel_colormanage_cb(from_float[0]);
rgb[1] = chanel_colormanage_cb(from_float[1]);
rgb[2] = chanel_colormanage_cb(from_float[2]);
- to16[0] = ftoshort(rgb_to_bw(rgb));
+ to16[0] = ftoshort(IMB_colormanagement_get_luminance(rgb));
to16++; from_float += 3;
}
}
@@ -454,13 +455,13 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
if (is_16bit) {
for (i = 0; i < ibuf->y; i++) {
row_pointers[ibuf->y - 1 - i] = (png_bytep)
- ((unsigned short *)pixels16 + (i * ibuf->x) * bytesperpixel);
+ ((unsigned short *)pixels16 + (((size_t)i) * ibuf->x) * bytesperpixel);
}
}
else {
for (i = 0; i < ibuf->y; i++) {
row_pointers[ibuf->y - 1 - i] = (png_bytep)
- ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
+ ((unsigned char *)pixels + (((size_t)i) * ibuf->x) * bytesperpixel * sizeof(unsigned char));
}
}
@@ -682,7 +683,7 @@ ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags, char colorspace[I
else {
imb_addrectImBuf(ibuf);
- pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
+ pixels = MEM_mallocN(((size_t)ibuf->x) * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
if (pixels == NULL) {
printf("Cannot allocate pixels array\n");
longjmp(png_jmpbuf(png_ptr), 1);
@@ -698,7 +699,7 @@ ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags, char colorspace[I
/* set the individual row-pointers to point at the correct offsets */
for (i = 0; i < ibuf->y; i++) {
row_pointers[ibuf->y - 1 - i] = (png_bytep)
- ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
+ ((unsigned char *)pixels + (((size_t)i) * ibuf->x) * bytesperpixel * sizeof(unsigned char));
}
png_read_image(png_ptr, row_pointers);
diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c
index bb09c57d1e5..3cf123fbc28 100644
--- a/source/blender/imbuf/intern/readimage.c
+++ b/source/blender/imbuf/intern/readimage.c
@@ -103,7 +103,7 @@ static void imb_handle_alpha(ImBuf *ibuf, int flags, char colorspace[IM_MAX_SPAC
ImBuf *IMB_ibImageFromMemory(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE], const char *descr)
{
ImBuf *ibuf;
- ImFileType *type;
+ const ImFileType *type;
char effective_colorspace[IM_MAX_SPACE] = "";
if (mem == NULL) {
@@ -133,7 +133,7 @@ ImBuf *IMB_ibImageFromMemory(unsigned char *mem, size_t size, int flags, char co
static ImBuf *IMB_ibImageFromFile(const char *filepath, int flags, char colorspace[IM_MAX_SPACE], const char *descr)
{
ImBuf *ibuf;
- ImFileType *type;
+ const ImFileType *type;
char effective_colorspace[IM_MAX_SPACE] = "";
if (colorspace)
@@ -257,7 +257,7 @@ ImBuf *IMB_testiffname(const char *filepath, int flags)
static void imb_loadtilefile(ImBuf *ibuf, int file, int tx, int ty, unsigned int *rect)
{
- ImFileType *type;
+ const ImFileType *type;
unsigned char *mem;
size_t size;
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index 4001b681ad9..c7b347cb20c 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -322,30 +322,30 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask,
do_float = (sbuf && sbuf->rect_float && dbuf->rect_float && obuf->rect_float);
if (do_char) {
- drect = dbuf->rect + desty * dbuf->x + destx;
- orect = obuf->rect + origy * obuf->x + origx;
+ drect = dbuf->rect + ((size_t)desty) * dbuf->x + destx;
+ orect = obuf->rect + ((size_t)origy) * obuf->x + origx;
}
if (do_float) {
- drectf = dbuf->rect_float + (desty * dbuf->x + destx) * 4;
- orectf = obuf->rect_float + (origy * obuf->x + origx) * 4;
+ drectf = dbuf->rect_float + (((size_t)desty) * dbuf->x + destx) * 4;
+ orectf = obuf->rect_float + (((size_t)origy) * obuf->x + origx) * 4;
}
if (dmaskrect)
- dmaskrect += origy * obuf->x + origx;
+ dmaskrect += ((size_t)origy) * obuf->x + origx;
destskip = dbuf->x;
origskip = obuf->x;
if (sbuf) {
- if (do_char) srect = sbuf->rect + srcy * sbuf->x + srcx;
- if (do_float) srectf = sbuf->rect_float + (srcy * sbuf->x + srcx) * 4;
+ if (do_char) srect = sbuf->rect + ((size_t)srcy) * sbuf->x + srcx;
+ if (do_float) srectf = sbuf->rect_float + (((size_t)srcy) * sbuf->x + srcx) * 4;
srcskip = sbuf->x;
if (cmaskrect)
- cmaskrect += srcy * sbuf->x + srcx;
+ cmaskrect += ((size_t)srcy) * sbuf->x + srcx;
if (texmaskrect)
- texmaskrect += srcy * sbuf->x + srcx;
+ texmaskrect += ((size_t)srcy) * sbuf->x + srcx;
}
else {
srect = drect;
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
new file mode 100644
index 00000000000..f1608f56c0b
--- /dev/null
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -0,0 +1,1292 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if 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 by Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/imbuf/intern/stereoimbuf.c
+ * \ingroup imbuf
+ */
+
+#include <stddef.h>
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "IMB_allocimbuf.h"
+#include "IMB_filetype.h"
+#include "IMB_metadata.h"
+#include "IMB_colormanagement_intern.h"
+
+#include "imbuf.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#include "BLI_math.h"
+
+#include "DNA_userdef_types.h"
+#include "DNA_scene_types.h"
+
+/* prototypes */
+struct Stereo3DData;
+static void imb_stereo3d_write_doit(struct Stereo3DData *s3d_data, struct Stereo3dFormat *s3d);
+static void imb_stereo3d_read_doit(struct Stereo3DData *s3d_data, struct Stereo3dFormat *s3d);
+
+typedef struct Stereo3DData {
+ struct { float *left, *right, *stereo; } rectf;
+ struct { uchar *left, *right, *stereo; } rect;
+ size_t x, y, channels;
+ bool is_float;
+} Stereo3DData;
+
+static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyphType mode)
+{
+ int x, y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ int anaglyph_encoding[3][3] = {
+ {0, 1, 1},
+ {1, 0, 1},
+ {0, 0, 1},
+ };
+
+ int r, g, b;
+
+ r = anaglyph_encoding[mode][0];
+ g = anaglyph_encoding[mode][1];
+ b = anaglyph_encoding[mode][2];
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ float *rect_to = s3d->rectf.stereo;
+
+ if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 3;
+ float *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ to[0] = from[r][0];
+ to[1] = from[g][1];
+ to[2] = from[b][2];
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 4;
+ float *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ to[0] = from[r][0];
+ to[1] = from[g][1];
+ to[2] = from[b][2];
+ to[3] = MAX2(from[0][2], from[0][2]);
+ }
+ }
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.left;
+ uchar *rect_right = s3d->rect.right;
+ uchar *rect_to = s3d->rect.stereo;
+
+ if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 3;
+ uchar *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ to[0] = from[r][0];
+ to[1] = from[g][1];
+ to[2] = from[b][2];
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 4;
+ uchar *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ to[0] = from[r][0];
+ to[1] = from[g][1];
+ to[2] = from[b][2];
+ to[3] = MAX2(from[0][2], from[0][2]);
+ }
+ }
+ }
+ }
+}
+
+static void imb_stereo3d_write_interlace(Stereo3DData *s3d, enum eStereo3dInterlaceType mode, const bool swap)
+{
+ int x, y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ if (s3d->is_float) {
+ const float *rect_left = s3d->rectf.left;
+ const float *rect_right = s3d->rectf.right;
+ float *rect_to = s3d->rectf.stereo;
+
+ switch (mode) {
+ case S3D_INTERLACE_ROW:
+ {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * channels;
+ const float *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+ memcpy(to, from[i], sizeof(float) * channels * stride_from);
+ i = !i;
+ }
+ break;
+ }
+ case S3D_INTERLACE_COLUMN:
+ {
+ if (channels == 1) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y;
+ const float *from[2] = {
+ rect_left + stride_from * y,
+ rect_right + stride_from * y,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 1, from[1] += 1, to += 1) {
+ to[0] = from[i][0];
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 3;
+ const float *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ copy_v3_v3(to, from[i]);
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * channels;
+ const float *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ copy_v4_v4(to, from[i]);
+ i = !i;
+ }
+ }
+ }
+ break;
+ }
+ case S3D_INTERLACE_CHECKERBOARD:
+ {
+ if (channels == 1) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y;
+ const float *from[2] = {
+ rect_left + stride_from * y,
+ rect_right + stride_from * y,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 1, from[1] += 1, to += 1) {
+ to[0] = from[j][0];
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 3) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 3;
+ const float *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ copy_v3_v3(to, from[j]);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 4) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * 4;
+ const float *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ copy_v4_v4(to, from[j]);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+ else {
+ const uchar *rect_left = s3d->rect.left;
+ const uchar *rect_right = s3d->rect.right;
+ uchar *rect_to = s3d->rect.stereo;
+
+ switch (mode) {
+ case S3D_INTERLACE_ROW:
+ {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * channels;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+ memcpy(to, from[i], sizeof(uchar) * channels * stride_from);
+ i = !i;
+ }
+ break;
+ }
+ case S3D_INTERLACE_COLUMN:
+ {
+ if (channels == 1) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y;
+ const uchar *from[2] = {
+ rect_left + stride_from * y,
+ rect_right + stride_from * y,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 1, from[1] += 1, to += 1) {
+ to[0] = from[i][0];
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 3;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ copy_v3_v3_char((char *)to, (char *)from[i]);
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 4;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ copy_v4_v4_char((char *)to, (char *)from[i]);
+ i = !i;
+ }
+ }
+ }
+ break;
+ }
+ case S3D_INTERLACE_CHECKERBOARD:
+ {
+ if (channels == 1) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y;
+ const uchar *from[2] = {
+ rect_left + stride_from * y,
+ rect_right + stride_from * y,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 1, from[1] += 1, to += 1) {
+ to[0] = from[j][0];
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 3) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 3;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * 3,
+ rect_right + stride_from * y * 3,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
+ copy_v3_v3_char((char *)to, (char *)from[j]);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 4) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * 4;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * 4,
+ rect_right + stride_from * y * 4,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
+ copy_v4_v4_char((char *)to, (char *)from[j]);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+}
+
+/* stereo3d output (s3d->rectf.stereo) is always unsqueezed */
+static void imb_stereo3d_write_sidebyside(Stereo3DData *s3d, const bool crosseyed)
+{
+ int y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width * 2;
+
+ const int l = (int) crosseyed;
+ const int r = !l;
+
+ if (s3d->is_float) {
+ const float *rect_left = s3d->rectf.left;
+ const float *rect_right = s3d->rectf.right;
+ float *rect_to = s3d->rectf.stereo;
+
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * channels;
+ const float *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ memcpy(to, from[l], sizeof(float) * channels * stride_from);
+ memcpy(to + channels * stride_from, from[r], sizeof(float) * channels * stride_from);
+ }
+ }
+ else {
+ const uchar *rect_left = s3d->rect.left;
+ const uchar *rect_right = s3d->rect.right;
+ uchar *rect_to = s3d->rect.stereo;
+
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * channels;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ memcpy(to, from[l], sizeof(uchar) * channels * stride_from);
+ memcpy(to + channels * stride_from, from[r], sizeof(uchar) * channels * stride_from);
+ }
+ }
+}
+
+/* stereo3d output (s3d->rectf.stereo) is always unsqueezed */
+static void imb_stereo3d_write_topbottom(Stereo3DData *s3d)
+{
+ int y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ if (s3d->is_float) {
+ const float *rect_left = s3d->rectf.left;
+ const float *rect_right = s3d->rectf.right;
+ float *rect_to = s3d->rectf.stereo;
+
+ for (y = 0; y < height; y++) {
+ float *to = rect_to + stride_to * y * channels;
+ const float *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ memcpy(to, from[1], sizeof(float) * channels * stride_from);
+ memcpy(to + channels * height * stride_from, from[0], sizeof(float) * channels * stride_from);
+ }
+ }
+ else {
+ const uchar *rect_left = s3d->rect.left;
+ const uchar *rect_right = s3d->rect.right;
+ uchar *rect_to = s3d->rect.stereo;
+
+ for (y = 0; y < height; y++) {
+ uchar *to = rect_to + stride_to * y * channels;
+ const uchar *from[2] = {
+ rect_left + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
+ };
+
+ memcpy(to, from[1], sizeof(uchar) * channels * stride_from);
+ memcpy(to + channels * height * stride_from, from[0], sizeof(uchar) * channels * stride_from);
+ }
+ }
+}
+
+/**************************** dimension utils ****************************************/
+
+void IMB_stereo3d_write_dimensions(
+ const char mode, const bool is_squeezed, const size_t width, const size_t height,
+ size_t *r_width, size_t *r_height)
+{
+ switch (mode) {
+ case S3D_DISPLAY_SIDEBYSIDE:
+ {
+ *r_width = is_squeezed ? width : width * 2;
+ *r_height = height;
+ break;
+ }
+ case S3D_DISPLAY_TOPBOTTOM:
+ {
+ *r_width = width;
+ *r_height = is_squeezed ? height : height * 2;
+ break;
+ }
+ case S3D_DISPLAY_ANAGLYPH:
+ case S3D_DISPLAY_INTERLACE:
+ default:
+ {
+ *r_width = width;
+ *r_height = height;
+ break;
+ }
+ }
+}
+
+void IMB_stereo3d_read_dimensions(
+ const char mode, const bool is_squeezed, const size_t width, const size_t height,
+ size_t *r_width, size_t *r_height)
+{
+ switch (mode) {
+ case S3D_DISPLAY_SIDEBYSIDE:
+ {
+ *r_width = is_squeezed ? width / 2 : width;
+ *r_height = height;
+ break;
+ }
+ case S3D_DISPLAY_TOPBOTTOM:
+ {
+ *r_width = width;
+ *r_height = is_squeezed ? height / 2 : height;
+ break;
+ }
+ case S3D_DISPLAY_ANAGLYPH:
+ case S3D_DISPLAY_INTERLACE:
+ default:
+ {
+ *r_width = width;
+ *r_height = height;
+ break;
+ }
+ }
+}
+
+/**************************** un/squeeze frame ****************************************/
+
+static void imb_stereo3d_squeeze_ImBuf(ImBuf *ibuf, Stereo3dFormat *s3d, const size_t x, const size_t y)
+{
+ if (ELEM(s3d->display_mode, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM) == false)
+ return;
+
+ if ((s3d->flag & S3D_SQUEEZED_FRAME) == 0)
+ return;
+
+ IMB_scaleImBuf_threaded(ibuf, x, y);
+}
+
+static void imb_stereo3d_unsqueeze_ImBuf(ImBuf *ibuf, Stereo3dFormat *s3d, const size_t x, const size_t y)
+{
+ if (ELEM(s3d->display_mode, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM) == false)
+ return;
+
+ if ((s3d->flag & S3D_SQUEEZED_FRAME) == 0)
+ return;
+
+ IMB_scaleImBuf_threaded(ibuf, x, y);
+}
+
+static void imb_stereo3d_squeeze_rectf(float *rectf, Stereo3dFormat *s3d, const size_t x, const size_t y, const size_t channels)
+{
+ ImBuf *ibuf;
+ size_t width, height;
+
+ if (ELEM(s3d->display_mode, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM) == false)
+ return;
+
+ if ((s3d->flag & S3D_SQUEEZED_FRAME) == 0)
+ return;
+
+ /* creates temporary imbuf to store the rectf */
+ IMB_stereo3d_write_dimensions(s3d->display_mode, false, x, y, &width, &height);
+ ibuf = IMB_allocImBuf(width, height, channels, IB_rectfloat);
+
+ IMB_buffer_float_from_float(
+ ibuf->rect_float, rectf, channels,
+ IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false,
+ width, height, width, width);
+
+ IMB_scaleImBuf_threaded(ibuf, x, y);
+ memcpy(rectf, ibuf->rect_float, x * y * sizeof(float[4]));
+ IMB_freeImBuf(ibuf);
+}
+
+static void imb_stereo3d_squeeze_rect(int *rect, Stereo3dFormat *s3d, const size_t x, const size_t y, const size_t channels)
+{
+ ImBuf *ibuf;
+ size_t width, height;
+
+ if (ELEM(s3d->display_mode, S3D_DISPLAY_SIDEBYSIDE, S3D_DISPLAY_TOPBOTTOM) == false)
+ return;
+
+ if ((s3d->flag & S3D_SQUEEZED_FRAME) == 0)
+ return;
+
+ /* creates temporary imbuf to store the rectf */
+ IMB_stereo3d_write_dimensions(s3d->display_mode, false, x, y, &width, &height);
+ ibuf = IMB_allocImBuf(width, height, channels, IB_rect);
+
+ IMB_buffer_byte_from_byte(
+ (unsigned char *)ibuf->rect, (unsigned char *)rect,
+ IB_PROFILE_SRGB, IB_PROFILE_SRGB, false,
+ width, height, width, width);
+
+ IMB_scaleImBuf_threaded(ibuf, x, y);
+ memcpy(rect, ibuf->rect, x * y * sizeof(unsigned int));
+ IMB_freeImBuf(ibuf);
+}
+
+
+/*************************** preparing to call the write functions **************************/
+
+static void imb_stereo3d_data_initialize(
+ Stereo3DData *s3d_data, const bool is_float,
+ const size_t x, const size_t y, const size_t channels,
+ int *rect_left, int *rect_right, int *rect_stereo,
+ float *rectf_left, float *rectf_right, float *rectf_stereo)
+{
+ s3d_data->is_float = is_float;
+ s3d_data->x = x;
+ s3d_data->y = y;
+ s3d_data->channels = channels;
+ s3d_data->rect.left = (uchar *)rect_left;
+ s3d_data->rect.right = (uchar *)rect_right;
+ s3d_data->rect.stereo = (uchar *)rect_stereo;
+ s3d_data->rectf.left = rectf_left;
+ s3d_data->rectf.right = rectf_right;
+ s3d_data->rectf.stereo = rectf_stereo;
+}
+
+int *IMB_stereo3d_from_rect(
+ ImageFormatData *im_format, const size_t x, const size_t y, const size_t channels,
+ int *rect_left, int *rect_right)
+{
+ int *r_rect;
+ Stereo3DData s3d_data = {{NULL}};
+ size_t width, height;
+ const bool is_float = im_format->depth > 8;
+
+ IMB_stereo3d_write_dimensions(im_format->stereo3d_format.display_mode, false, x, y, &width, &height);
+ r_rect = MEM_mallocN(channels * sizeof(int) * width * height, __func__);
+
+ imb_stereo3d_data_initialize(&s3d_data, is_float, x, y, channels, rect_left, rect_right, r_rect, NULL, NULL, NULL);
+ imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
+ imb_stereo3d_squeeze_rect(r_rect, &im_format->stereo3d_format, x, y, channels);
+
+ return r_rect;
+}
+
+float *IMB_stereo3d_from_rectf(
+ ImageFormatData *im_format, const size_t x, const size_t y, const size_t channels,
+ float *rectf_left, float *rectf_right)
+{
+ float *r_rectf;
+ Stereo3DData s3d_data = {{NULL}};
+ size_t width, height;
+ const bool is_float = im_format->depth > 8;
+
+ IMB_stereo3d_write_dimensions(im_format->stereo3d_format.display_mode, false, x, y, &width, &height);
+ r_rectf = MEM_mallocN(channels * sizeof(float) * width * height, __func__);
+
+ imb_stereo3d_data_initialize(&s3d_data, is_float, x, y, channels, NULL, NULL, NULL, rectf_left, rectf_right, r_rectf);
+ imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
+ imb_stereo3d_squeeze_rectf(r_rectf, &im_format->stereo3d_format, x, y, channels);
+
+ return r_rectf;
+}
+
+/* left/right are always float */
+ImBuf *IMB_stereo3d_ImBuf(ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right)
+{
+ ImBuf *ibuf_stereo = NULL;
+ Stereo3DData s3d_data = {{NULL}};
+ size_t width, height;
+ const bool is_float = im_format->depth > 8;
+
+ IMB_stereo3d_write_dimensions(im_format->stereo3d_format.display_mode, false, ibuf_left->x, ibuf_left->y, &width, &height);
+ ibuf_stereo = IMB_allocImBuf(width, height, ibuf_left->planes, (is_float ? IB_rectfloat : IB_rect));
+
+ /* copy flags for IB_fields and other settings */
+ ibuf_stereo->flags = ibuf_left->flags;
+
+ imb_stereo3d_data_initialize(
+ &s3d_data, is_float, ibuf_left->x, ibuf_left->y, 4,
+ (int *)ibuf_left->rect, (int *)ibuf_right->rect, (int *)ibuf_stereo->rect,
+ ibuf_left->rect_float, ibuf_right->rect_float, ibuf_stereo->rect_float);
+
+ imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
+ imb_stereo3d_squeeze_ImBuf(ibuf_stereo, &im_format->stereo3d_format, ibuf_left->x, ibuf_left->y);
+
+ return ibuf_stereo;
+}
+
+static void imb_stereo3d_write_doit(Stereo3DData *s3d_data, Stereo3dFormat *s3d)
+{
+ switch (s3d->display_mode) {
+ case S3D_DISPLAY_ANAGLYPH:
+ imb_stereo3d_write_anaglyph(s3d_data, s3d->anaglyph_type);
+ break;
+ case S3D_DISPLAY_INTERLACE:
+ imb_stereo3d_write_interlace(s3d_data, s3d->interlace_type, (s3d->flag & S3D_INTERLACE_SWAP) != 0);
+ break;
+ case S3D_DISPLAY_SIDEBYSIDE:
+ imb_stereo3d_write_sidebyside(s3d_data, (s3d->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0);
+ break;
+ case S3D_DISPLAY_TOPBOTTOM:
+ imb_stereo3d_write_topbottom(s3d_data);
+ break;
+ default:
+ break;
+ }
+}
+
+/******************************** reading stereo imbufs **********************/
+
+static void imb_stereo3d_read_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyphType mode)
+{
+ int x, y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ int anaglyph_encoding[3][3] = {
+ {0, 1, 1},
+ {1, 0, 1},
+ {0, 0, 1},
+ };
+
+ int r, g, b;
+
+ r = anaglyph_encoding[mode][0];
+ g = anaglyph_encoding[mode][1];
+ b = anaglyph_encoding[mode][2];
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ float *rect_from = s3d->rectf.stereo;
+
+ if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ float *from = rect_from + stride_from * y * 3;
+ float *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ to[r][0] = from[0];
+ to[g][1] = from[1];
+ to[b][2] = from[2];
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ float *from = rect_from + stride_from * y * 4;
+ float *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ to[r][0] = from[0];
+ to[g][1] = from[1];
+ to[b][2] = from[2];
+ to[0][3] = to[1][3] = from[3];
+ }
+ }
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.left;
+ uchar *rect_right = s3d->rect.right;
+ uchar *rect_from = s3d->rect.stereo;
+
+ if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ uchar *from = rect_from + stride_from * y * 3;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ to[r][0] = from[0];
+ to[g][1] = from[1];
+ to[b][2] = from[2];
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ uchar *from = rect_from + stride_from * y * 4;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ to[r][0] = from[0];
+ to[g][1] = from[1];
+ to[b][2] = from[2];
+ to[0][3] = to[1][3] = from[3];
+ }
+ }
+ }
+ }
+}
+
+static void imb_stereo3d_read_interlace(Stereo3DData *s3d, enum eStereo3dInterlaceType mode, const bool swap)
+{
+ int x, y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ const float *rect_from = s3d->rectf.stereo;
+
+ switch (mode) {
+ case S3D_INTERLACE_ROW:
+ {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * channels;
+ float *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+ memcpy(to[i], from, sizeof(float) * channels * stride_to);
+ i = !i;
+ }
+ break;
+ }
+ case S3D_INTERLACE_COLUMN:
+ {
+ if (channels == 1) {
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y;
+ float *to[2] = {
+ rect_left + stride_to * y,
+ rect_right + stride_to * y,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 1, to[0] += 1, to[1] += 1) {
+ to[i][0] = from[0];
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * 3;
+ float *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ copy_v3_v3(to[i], from);
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * channels;
+ float *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ copy_v4_v4(to[i], from);
+ i = !i;
+ }
+ }
+ }
+ break;
+ }
+ case S3D_INTERLACE_CHECKERBOARD:
+ {
+ if (channels == 1) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y;
+ float *to[2] = {
+ rect_left + stride_to * y,
+ rect_right + stride_to * y,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 1, to[0] += 1, to[1] += 1) {
+ to[j][0] = from[0];
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 3) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * 3;
+ float *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ copy_v3_v3(to[j], from);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 4) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * 4;
+ float *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ copy_v4_v4(to[j], from);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.right;
+ uchar *rect_right = s3d->rect.left;
+ const uchar *rect_from = s3d->rect.stereo;
+
+ switch (mode) {
+ case S3D_INTERLACE_ROW:
+ {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * channels;
+ uchar *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+ memcpy(to[i], from, sizeof(uchar) * channels * stride_to);
+ i = !i;
+ }
+ break;
+ }
+ case S3D_INTERLACE_COLUMN:
+ {
+ if (channels == 1) {
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y;
+ uchar *to[2] = {
+ rect_left + stride_to * y,
+ rect_right + stride_to * y,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 1, to[0] += 1, to[1] += 1) {
+ to[i][0] = from[0];
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 3) {
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * 3;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ copy_v3_v3_char((char *)to[i], (char *)from);
+ i = !i;
+ }
+ }
+ }
+ else if (channels == 4) {
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * 4;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+ char i = (char) swap;
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ copy_v4_v4_char((char *)to[i], (char *)from);
+ i = !i;
+ }
+ }
+ }
+ break;
+ }
+ case S3D_INTERLACE_CHECKERBOARD:
+ {
+ if (channels == 1) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y;
+ uchar *to[2] = {
+ rect_left + stride_to * y,
+ rect_right + stride_to * y,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 1, to[0] += 1, to[1] += 1) {
+ to[j][0] = from[0];
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 3) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * 3;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 3,
+ rect_right + stride_to * y * 3,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
+ copy_v3_v3_char((char *)to[j], (char *)from);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ else if (channels == 4) {
+ char i = (char) swap;
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * 4;
+ uchar *to[2] = {
+ rect_left + stride_to * y * 4,
+ rect_right + stride_to * y * 4,
+ };
+ char j = i;
+ for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
+ copy_v4_v4_char((char *)to[j], (char *)from);
+ j = !j;
+ }
+ i = !i;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+}
+
+/* stereo input (s3d->rectf.stereo) is always unsqueezed */
+static void imb_stereo3d_read_sidebyside(Stereo3DData *s3d, const bool crosseyed)
+{
+ int y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width * 2;
+ const int stride_to = width;
+
+ const int l = (int) crosseyed;
+ const int r = !l;
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ const float *rect_from = s3d->rectf.stereo;
+
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * channels;
+ float *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ memcpy(to[l], from, sizeof(float) * channels * stride_to);
+ memcpy(to[r], from + channels * stride_to, sizeof(float) * channels * stride_to);
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.left;
+ uchar *rect_right = s3d->rect.right;
+ const uchar *rect_from = s3d->rect.stereo;
+
+ /* always RGBA input/output */
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * channels;
+ uchar *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ memcpy(to[l], from, sizeof(uchar) * channels * stride_to);
+ memcpy(to[r], from + channels * stride_to, sizeof(uchar) * channels * stride_to);
+ }
+ }
+}
+
+/* stereo input (s3d->rectf.stereo) is always unsqueezed */
+static void imb_stereo3d_read_topbottom(Stereo3DData *s3d)
+{
+ int y;
+ size_t width = s3d->x;
+ size_t height = s3d->y;
+ const size_t channels = s3d->channels;
+
+ const int stride_from = width;
+ const int stride_to = width;
+
+ if (s3d->is_float) {
+ float *rect_left = s3d->rectf.left;
+ float *rect_right = s3d->rectf.right;
+ const float *rect_from = s3d->rectf.stereo;
+
+ for (y = 0; y < height; y++) {
+ const float *from = rect_from + stride_from * y * channels;
+ float *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ memcpy(to[1], from, sizeof(float) * channels * stride_to);
+ memcpy(to[0], from + channels * height * stride_to, sizeof(float) * channels * stride_to);
+ }
+ }
+ else {
+ uchar *rect_left = s3d->rect.left;
+ uchar *rect_right = s3d->rect.right;
+ const uchar *rect_from = s3d->rect.stereo;
+
+ for (y = 0; y < height; y++) {
+ const uchar *from = rect_from + stride_from * y * channels;
+ uchar *to[2] = {
+ rect_left + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
+ };
+
+ memcpy(to[1], from, sizeof(uchar) * channels * stride_to);
+ memcpy(to[0], from + channels * height * stride_to, sizeof(uchar) * channels * stride_to);
+ }
+ }
+}
+
+
+/*************************** preparing to call the read functions **************************/
+
+/* reading a stereo encoded ibuf (*left) and generating two ibufs from it (*left and *right) */
+void IMB_ImBufFromStereo3d(
+ Stereo3dFormat *s3d, ImBuf *ibuf_stereo3d,
+ ImBuf **r_ibuf_left, ImBuf **r_ibuf_right)
+{
+ Stereo3DData s3d_data = {{NULL}};
+ ImBuf *ibuf_left, *ibuf_right;
+ size_t width, height;
+ const bool is_float = (ibuf_stereo3d->rect_float != NULL);
+
+ IMB_stereo3d_read_dimensions(
+ s3d->display_mode, ((s3d->flag & S3D_SQUEEZED_FRAME) == 0), ibuf_stereo3d->x, ibuf_stereo3d->y,
+ &width, &height);
+
+ ibuf_left = IMB_allocImBuf(width, height, ibuf_stereo3d->planes, (is_float ? IB_rectfloat : IB_rect));
+ ibuf_right = IMB_allocImBuf(width, height, ibuf_stereo3d->planes, (is_float ? IB_rectfloat : IB_rect));
+
+ /* copy flags for IB_fields and other settings */
+ ibuf_left->flags = ibuf_stereo3d->flags;
+ ibuf_right->flags = ibuf_stereo3d->flags;
+
+ /* we always work with unsqueezed formats */
+ IMB_stereo3d_write_dimensions(
+ s3d->display_mode, ((s3d->flag & S3D_SQUEEZED_FRAME) == 0), ibuf_stereo3d->x, ibuf_stereo3d->y,
+ &width, &height);
+ imb_stereo3d_unsqueeze_ImBuf(ibuf_stereo3d, s3d, width, height);
+
+ imb_stereo3d_data_initialize(
+ &s3d_data, is_float, ibuf_left->x, ibuf_left->y, 4,
+ (int *)ibuf_left->rect, (int *)ibuf_right->rect, (int *)ibuf_stereo3d->rect,
+ ibuf_left->rect_float, ibuf_right->rect_float, ibuf_stereo3d->rect_float);
+
+ imb_stereo3d_read_doit(&s3d_data, s3d);
+
+ if (ibuf_stereo3d->flags & (IB_zbuf | IB_zbuffloat)) {
+ if (is_float) {
+ addzbuffloatImBuf(ibuf_left);
+ addzbuffloatImBuf(ibuf_right);
+ }
+ else {
+ addzbufImBuf(ibuf_left);
+ addzbufImBuf(ibuf_right);
+ }
+
+ imb_stereo3d_data_initialize(
+ &s3d_data, is_float, ibuf_left->x, ibuf_left->y, 1,
+ (int *)ibuf_left->zbuf, (int *)ibuf_right->zbuf, (int *)ibuf_stereo3d->zbuf,
+ ibuf_left->zbuf_float, ibuf_right->zbuf_float, ibuf_stereo3d->zbuf_float);
+
+ imb_stereo3d_read_doit(&s3d_data, s3d);
+ }
+
+ IMB_freeImBuf(ibuf_stereo3d);
+
+ *r_ibuf_left = ibuf_left;
+ *r_ibuf_right = ibuf_right;
+}
+
+static void imb_stereo3d_read_doit(Stereo3DData *s3d_data, Stereo3dFormat *s3d)
+{
+ switch (s3d->display_mode) {
+ case S3D_DISPLAY_ANAGLYPH:
+ imb_stereo3d_read_anaglyph(s3d_data, s3d->anaglyph_type);
+ break;
+ case S3D_DISPLAY_INTERLACE:
+ imb_stereo3d_read_interlace(s3d_data, s3d->interlace_type, (s3d->flag & S3D_INTERLACE_SWAP) != 0);
+ break;
+ case S3D_DISPLAY_SIDEBYSIDE:
+ imb_stereo3d_read_sidebyside(s3d_data, (s3d->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0);
+ break;
+ case S3D_DISPLAY_TOPBOTTOM:
+ imb_stereo3d_read_topbottom(s3d_data);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/source/blender/imbuf/intern/targa.c b/source/blender/imbuf/intern/targa.c
index 70b71ec4182..40dcdc9d24a 100644
--- a/source/blender/imbuf/intern/targa.c
+++ b/source/blender/imbuf/intern/targa.c
@@ -568,7 +568,7 @@ ImBuf *imb_loadtarga(unsigned char *mem, size_t mem_size, int flags, char colors
else ibuf = IMB_allocImBuf(tga.xsize, tga.ysize, (tga.pixsize + 0x7) & ~0x7, IB_rect);
if (ibuf == NULL) return NULL;
- ibuf->ftype = TGA;
+ ibuf->ftype = (tga.imgtyp < 4) ? RAWTGA : TGA;
mem = mem + 18 + tga.numid;
cp[0] = 0xff;
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index 118f0405303..7a949b7ffea 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -200,6 +200,17 @@ static void escape_uri_string(const char *string, char *escaped_string, int esca
/** ----- end of adapted code from glib --- */
+static bool thumbhash_from_path(const char *UNUSED(path), ThumbSource source, char *r_hash)
+{
+ switch (source) {
+ case THB_SOURCE_FONT:
+ return IMB_thumb_load_font_get_hash(r_hash);
+ default:
+ r_hash[0] = '\0';
+ return false;
+ }
+}
+
static int uri_from_filename(const char *path, char *uri)
{
char orig_uri[URI_MAX];
@@ -239,47 +250,68 @@ static int uri_from_filename(const char *path, char *uri)
return 1;
}
-static void thumbname_from_uri(const char *uri, char *thumb, const int thumb_len)
+static bool thumbpathname_from_uri(
+ const char *uri, char *r_path, const int path_len, char *r_name, int name_len, ThumbSize size)
{
- char hexdigest[33];
- unsigned char digest[16];
+ char name_buff[40];
+
+ if (r_path && !r_name) {
+ r_name = name_buff;
+ name_len = sizeof(name_buff);
+ }
- BLI_hash_md5_buffer(uri, strlen(uri), digest);
- hexdigest[0] = '\0';
- BLI_snprintf(thumb, thumb_len, "%s.png", BLI_hash_md5_to_hexdigest(digest, hexdigest));
+ if (r_name) {
+ char hexdigest[33];
+ unsigned char digest[16];
+ BLI_hash_md5_buffer(uri, strlen(uri), digest);
+ hexdigest[0] = '\0';
+ BLI_snprintf(r_name, name_len, "%s.png", BLI_hash_md5_to_hexdigest(digest, hexdigest));
+// printf("%s: '%s' --> '%s'\n", __func__, uri, r_name);
+ }
- // printf("%s: '%s' --> '%s'\n", __func__, uri, thumb);
+ if (r_path) {
+ char tmppath[FILE_MAX];
+
+ if (get_thumb_dir(tmppath, size)) {
+ BLI_snprintf(r_path, path_len, "%s%s", tmppath, r_name);
+// printf("%s: '%s' --> '%s'\n", __func__, uri, r_path);
+ return true;
+ }
+ }
+ return false;
+}
+
+static void thumbname_from_uri(const char *uri, char *thumb, const int thumb_len)
+{
+ thumbpathname_from_uri(uri, NULL, 0, thumb, thumb_len, THB_FAIL);
}
-static int thumbpath_from_uri(const char *uri, char *path, const int path_len, ThumbSize size)
+static bool thumbpath_from_uri(const char *uri, char *path, const int path_len, ThumbSize size)
{
- char tmppath[FILE_MAX];
- int rv = 0;
-
- if (get_thumb_dir(tmppath, size)) {
- char thumb[40];
- thumbname_from_uri(uri, thumb, sizeof(thumb));
- BLI_snprintf(path, path_len, "%s%s", tmppath, thumb);
- rv = 1;
- }
- return rv;
+ return thumbpathname_from_uri(uri, path, path_len, NULL, 0, size);
}
void IMB_thumb_makedirs(void)
{
char tpath[FILE_MAX];
+#if 0 /* UNUSED */
if (get_thumb_dir(tpath, THB_NORMAL)) {
BLI_dir_create_recursive(tpath);
}
+#endif
+ if (get_thumb_dir(tpath, THB_LARGE)) {
+ BLI_dir_create_recursive(tpath);
+ }
if (get_thumb_dir(tpath, THB_FAIL)) {
BLI_dir_create_recursive(tpath);
}
}
/* create thumbnail for file and returns new imbuf for thumbnail */
-ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, ImBuf *img)
+static ImBuf *thumb_create_ex(
+ const char *file_path, const char *uri, const char *thumb, const bool use_hash, const char *hash,
+ ThumbSize size, ThumbSource source, ImBuf *img)
{
- char uri[URI_MAX] = "";
char desc[URI_MAX + 22];
char tpath[FILE_MAX];
char tdir[FILE_MAX];
@@ -287,7 +319,6 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
char mtime[40] = "0"; /* in case we can't stat the file */
char cwidth[40] = "0"; /* in case images have no data */
char cheight[40] = "0";
- char thumb[40];
short tsize = 128;
short ex, ey;
float scaledx, scaledy;
@@ -295,10 +326,10 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
switch (size) {
case THB_NORMAL:
- tsize = 128;
+ tsize = PREVIEW_RENDER_DEFAULT_HEIGHT;
break;
case THB_LARGE:
- tsize = 256;
+ tsize = PREVIEW_RENDER_DEFAULT_HEIGHT * 2;
break;
case THB_FAIL:
tsize = 1;
@@ -309,20 +340,18 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
/* exception, skip images over 100mb */
if (source == THB_SOURCE_IMAGE) {
- const size_t file_size = BLI_file_size(path);
+ const size_t file_size = BLI_file_size(file_path);
if (file_size != -1 && file_size > THUMB_SIZE_MAX) {
- // printf("file too big: %d, skipping %s\n", (int)size, path);
+ // printf("file too big: %d, skipping %s\n", (int)size, file_path);
return NULL;
}
}
- uri_from_filename(path, uri);
- thumbname_from_uri(uri, thumb, sizeof(thumb));
if (get_thumb_dir(tdir, size)) {
BLI_snprintf(tpath, FILE_MAX, "%s%s", tdir, thumb);
- thumb[8] = '\0'; /* shorten for tempname, not needed anymore */
+// thumb[8] = '\0'; /* shorten for tempname, not needed anymore */
BLI_snprintf(temp, FILE_MAX, "%sblender_%d_%s.png", tdir, abs(getpid()), thumb);
- if (BLI_path_ncmp(path, tdir, sizeof(tdir)) == 0) {
+ if (BLI_path_ncmp(file_path, tdir, sizeof(tdir)) == 0) {
return NULL;
}
if (size == THB_FAIL) {
@@ -330,20 +359,26 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
if (!img) return NULL;
}
else {
- if (THB_SOURCE_IMAGE == source || THB_SOURCE_BLEND == source) {
-
+ if (ELEM(source, THB_SOURCE_IMAGE, THB_SOURCE_BLEND, THB_SOURCE_FONT)) {
/* only load if we didnt give an image */
if (img == NULL) {
- if (THB_SOURCE_BLEND == source) {
- img = IMB_loadblend_thumb(path);
- }
- else {
- img = IMB_loadiffname(path, IB_rect | IB_metadata, NULL);
+ switch (source) {
+ case THB_SOURCE_IMAGE:
+ img = IMB_loadiffname(file_path, IB_rect | IB_metadata, NULL);
+ break;
+ case THB_SOURCE_BLEND:
+ img = IMB_thumb_load_blend(file_path);
+ break;
+ case THB_SOURCE_FONT:
+ img = IMB_thumb_load_font(file_path, tsize, tsize);
+ break;
+ default:
+ BLI_assert(0); /* This should never happen */
}
}
if (img != NULL) {
- if (BLI_stat(path, &info) != -1) {
+ if (BLI_stat(file_path, &info) != -1) {
BLI_snprintf(mtime, sizeof(mtime), "%ld", (long int)info.st_mtime);
}
BLI_snprintf(cwidth, sizeof(cwidth), "%d", img->x);
@@ -352,11 +387,11 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
}
else if (THB_SOURCE_MOVIE == source) {
struct anim *anim = NULL;
- anim = IMB_open_anim(path, IB_rect | IB_metadata, 0, NULL);
+ anim = IMB_open_anim(file_path, IB_rect | IB_metadata, 0, NULL);
if (anim != NULL) {
img = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
if (img == NULL) {
- printf("not an anim; %s\n", path);
+ printf("not an anim; %s\n", file_path);
}
else {
IMB_freeImBuf(img);
@@ -364,7 +399,7 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
}
IMB_free_anim(anim);
}
- if (BLI_stat(path, &info) != -1) {
+ if (BLI_stat(file_path, &info) != -1) {
BLI_snprintf(mtime, sizeof(mtime), "%ld", (long int)info.st_mtime);
}
}
@@ -380,7 +415,7 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
}
ex = (short)scaledx;
ey = (short)scaledy;
-
+
/* save some time by only scaling byte buf */
if (img->rect_float) {
if (img->rect == NULL) {
@@ -397,7 +432,10 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
IMB_metadata_change_field(img, "Software", "Blender");
IMB_metadata_change_field(img, "Thumb::URI", uri);
IMB_metadata_change_field(img, "Thumb::MTime", mtime);
- if (THB_SOURCE_IMAGE == source) {
+ if (use_hash) {
+ IMB_metadata_change_field(img, "X-Blender::Hash", hash);
+ }
+ if (ELEM(source, THB_SOURCE_IMAGE, THB_SOURCE_BLEND, THB_SOURCE_FONT)) {
IMB_metadata_change_field(img, "Thumb::Image::Width", cwidth);
IMB_metadata_change_field(img, "Thumb::Image::Height", cheight);
}
@@ -412,12 +450,40 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
BLI_rename(temp, tpath);
}
+ }
+ return img;
+}
- return img;
+static ImBuf *thumb_create_or_fail(
+ const char *file_path, const char *uri, const char *thumb, const bool use_hash, const char *hash,
+ ThumbSize size, ThumbSource source)
+{
+ ImBuf *img = thumb_create_ex(file_path, uri, thumb, use_hash, hash, size, source, NULL);
+
+ if (!img) {
+ /* thumb creation failed, write fail thumb */
+ img = thumb_create_ex(file_path, uri, thumb, use_hash, hash, THB_FAIL, source, NULL);
+ if (img) {
+ /* we don't need failed thumb anymore */
+ IMB_freeImBuf(img);
+ img = NULL;
+ }
}
+
return img;
}
+ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, ImBuf *img)
+{
+ char uri[URI_MAX] = "";
+ char thumb_name[40];
+
+ uri_from_filename(path, uri);
+ thumbname_from_uri(uri, thumb_name, sizeof(thumb_name));
+
+ return thumb_create_ex(path, uri, thumb_name, false, THUMB_DEFAULT_HASH, size, source, img);
+}
+
/* read thumbnail for file and returns new imbuf for thumbnail */
ImBuf *IMB_thumb_read(const char *path, ThumbSize size)
{
@@ -456,25 +522,30 @@ void IMB_thumb_delete(const char *path, ThumbSize size)
/* create the thumb if necessary and manage failed and old thumbs */
-ImBuf *IMB_thumb_manage(const char *path, ThumbSize size, ThumbSource source)
+ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source)
{
- char thumb[FILE_MAX];
+ char thumb_path[FILE_MAX];
+ char thumb_name[40];
char uri[URI_MAX];
+ const char *file_path;
+ const char *path;
BLI_stat_t st;
ImBuf *img = NULL;
-
- if (BLI_stat(path, &st) == -1) {
+
+ path = file_path = org_path;
+
+ if (BLI_stat(file_path, &st) == -1) {
return NULL;
}
if (!uri_from_filename(path, uri)) {
return NULL;
}
- if (thumbpath_from_uri(uri, thumb, sizeof(thumb), THB_FAIL)) {
+ if (thumbpath_from_uri(uri, thumb_path, sizeof(thumb_path), THB_FAIL)) {
/* failure thumb exists, don't try recreating */
- if (BLI_exists(thumb)) {
+ if (BLI_exists(thumb_path)) {
/* clear out of date fail case */
- if (BLI_file_older(thumb, path)) {
- BLI_delete(thumb, false, false);
+ if (BLI_file_older(thumb_path, file_path)) {
+ BLI_delete(thumb_path, false, false);
}
else {
return NULL;
@@ -482,52 +553,53 @@ ImBuf *IMB_thumb_manage(const char *path, ThumbSize size, ThumbSource source)
}
}
- if (thumbpath_from_uri(uri, thumb, sizeof(thumb), size)) {
- if (BLI_path_ncmp(path, thumb, sizeof(thumb)) == 0) {
+ if (thumbpathname_from_uri(uri, thumb_path, sizeof(thumb_path), thumb_name, sizeof(thumb_name), size)) {
+ if (BLI_path_ncmp(path, thumb_path, sizeof(thumb_path)) == 0) {
img = IMB_loadiffname(path, IB_rect, NULL);
}
else {
- img = IMB_loadiffname(thumb, IB_rect | IB_metadata, NULL);
+ img = IMB_loadiffname(thumb_path, IB_rect | IB_metadata, NULL);
if (img) {
+ bool regenerate = false;
+
char mtime[40];
- if (!IMB_metadata_get_field(img, "Thumb::MTime", mtime, 40)) {
- /* illegal thumb, forget it! */
- IMB_freeImBuf(img);
- img = NULL;
+ char thumb_hash[33];
+ char thumb_hash_curr[33];
+
+ const bool use_hash = thumbhash_from_path(file_path, source, thumb_hash);
+
+ if (IMB_metadata_get_field(img, "Thumb::MTime", mtime, sizeof(mtime))) {
+ regenerate = (st.st_mtime != atol(mtime));
}
else {
- time_t t = atol(mtime);
- if (st.st_mtime != t) {
- /* recreate all thumbs */
- IMB_freeImBuf(img);
- img = NULL;
- IMB_thumb_delete(path, THB_NORMAL);
- IMB_thumb_delete(path, THB_LARGE);
- IMB_thumb_delete(path, THB_FAIL);
- img = IMB_thumb_create(path, size, source, NULL);
- if (!img) {
- /* thumb creation failed, write fail thumb */
- img = IMB_thumb_create(path, THB_FAIL, source, NULL);
- if (img) {
- /* we don't need failed thumb anymore */
- IMB_freeImBuf(img);
- img = NULL;
- }
- }
+ /* illegal thumb, regenerate it! */
+ regenerate = true;
+ }
+
+ if (use_hash && !regenerate) {
+ if (IMB_metadata_get_field(img, "X-Blender::Hash", thumb_hash_curr, sizeof(thumb_hash_curr))) {
+ regenerate = !STREQ(thumb_hash, thumb_hash_curr);
+ }
+ else {
+ regenerate = true;
}
}
+
+ if (regenerate) {
+ /* recreate all thumbs */
+ IMB_freeImBuf(img);
+ img = NULL;
+ IMB_thumb_delete(path, THB_NORMAL);
+ IMB_thumb_delete(path, THB_LARGE);
+ IMB_thumb_delete(path, THB_FAIL);
+ img = thumb_create_or_fail(file_path, uri, thumb_name, use_hash, thumb_hash, size, source);
+ }
}
else {
- img = IMB_thumb_create(path, size, source, NULL);
- if (!img) {
- /* thumb creation failed, write fail thumb */
- img = IMB_thumb_create(path, THB_FAIL, source, NULL);
- if (img) {
- /* we don't need failed thumb anymore */
- IMB_freeImBuf(img);
- img = NULL;
- }
- }
+ char thumb_hash[33];
+ const bool use_hash = thumbhash_from_path(file_path, source, thumb_hash);
+
+ img = thumb_create_or_fail(file_path, uri, thumb_name, use_hash, thumb_hash, size, source);
}
}
}
diff --git a/source/blender/imbuf/intern/thumbs_blend.c b/source/blender/imbuf/intern/thumbs_blend.c
index aee465c49cc..d7b9089c437 100644
--- a/source/blender/imbuf/intern/thumbs_blend.c
+++ b/source/blender/imbuf/intern/thumbs_blend.c
@@ -121,7 +121,7 @@ static ImBuf *loadblend_thumb(gzFile gzfile)
return NULL;
}
-ImBuf *IMB_loadblend_thumb(const char *path)
+ImBuf *IMB_thumb_load_blend(const char *path)
{
gzFile gzfile;
/* not necessarily a gzip */
@@ -143,7 +143,7 @@ ImBuf *IMB_loadblend_thumb(const char *path)
/* add a fake passepartout overlay to a byte buffer, use for blend file thumbnails */
#define MARGIN 2
-void IMB_overlayblend_thumb(unsigned int *thumb, int width, int height, float aspect)
+void IMB_thumb_overlay_blend(unsigned int *thumb, int width, int height, float aspect)
{
unsigned char *px = (unsigned char *)thumb;
int margin_l = MARGIN;
diff --git a/source/blender/imbuf/intern/thumbs_font.c b/source/blender/imbuf/intern/thumbs_font.c
new file mode 100644
index 00000000000..4b024f3c51b
--- /dev/null
+++ b/source/blender/imbuf/intern/thumbs_font.c
@@ -0,0 +1,100 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Thomas Beck.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/imbuf/intern/thumbs_font.c
+ * \ingroup imbuf
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_fileops.h"
+#include "BLI_hash_md5.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_thumbs.h"
+
+
+/* XXX, bad level call */
+#include "../../blenfont/BLF_api.h"
+#include "../../blenfont/BLF_translation.h" /* 'N_' macro and BLF_lang_get()... */
+
+static const char *thumb_str[] = {
+ N_("AaBbCc"),
+
+ N_("The quick"),
+ N_("brown fox"),
+ N_("jumps over"),
+ N_("the lazy dog"),
+};
+
+struct ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned int y)
+{
+ const int font_size = y / 4;
+
+ struct ImBuf *ibuf;
+ float font_color[4];
+
+ /* create a white image (theme color is used for drawing) */
+ font_color[0] = font_color[1] = font_color[2] = 1.0f;
+
+ /* fill with zero alpha */
+ font_color[3] = 0.0f;
+
+ ibuf = IMB_allocImBuf(x, y, 32, IB_rect | IB_metadata);
+ IMB_rectfill(ibuf, font_color);
+
+ /* draw with full alpha */
+ font_color[3] = 1.0f;
+
+ BLF_thumb_preview(
+ filename, thumb_str, ARRAY_SIZE(thumb_str),
+ font_color, font_size,
+ (unsigned char *)ibuf->rect, ibuf->x, ibuf->y, ibuf->channels);
+
+ return ibuf;
+}
+
+bool IMB_thumb_load_font_get_hash(char *r_hash)
+{
+ char buf[1024];
+ char *str = buf;
+ size_t len = 0;
+
+ int draw_str_lines = ARRAY_SIZE(thumb_str);
+ int i;
+
+ unsigned char digest[16];
+
+ len += BLI_strncpy_rlen(str + len, THUMB_DEFAULT_HASH, sizeof(buf) - len);
+
+ for (i = 0; (i < draw_str_lines) && (len < sizeof(buf)); i++) {
+ len += BLI_strncpy_rlen(str + len, BLF_translate_do(BLF_I18NCONTEXT_DEFAULT, thumb_str[i]), sizeof(buf) - len);
+ }
+
+ BLI_hash_md5_buffer(str, len, digest);
+ r_hash[0] = '\0';
+ BLI_hash_md5_to_hexdigest(digest, r_hash);
+
+ return true;
+}
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index 4d58642e9c4..62097635296 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -454,7 +454,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
if (bitspersample == 32) {
if (chan == 3 && spp == 3) /* fill alpha if only RGB TIFF */
- fill_vn_fl(fbuf, ibuf->x, 1.0f);
+ copy_vn_fl(fbuf, ibuf->x, 1.0f);
else if (chan >= spp) /* for grayscale, duplicate first channel into G and B */
success |= TIFFReadScanline(image, fbuf, row, 0);
else
@@ -464,7 +464,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
}
else if (bitspersample == 16) {
if (chan == 3 && spp == 3) /* fill alpha if only RGB TIFF */
- fill_vn_ushort(sbuf, ibuf->x, 65535);
+ copy_vn_ushort(sbuf, ibuf->x, 65535);
else if (chan >= spp) /* for grayscale, duplicate first channel into G and B */
success |= TIFFReadScanline(image, fbuf, row, 0);
else
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index 32100aa2288..77962d43470 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -186,7 +186,7 @@ int IMB_ispic_type(const char *name)
#define HEADER_SIZE 64
unsigned char buf[HEADER_SIZE];
- ImFileType *type;
+ const ImFileType *type;
BLI_stat_t st;
int fp;
@@ -439,3 +439,15 @@ bool IMB_isanim(const char *filename)
return (type && type != ANIM_SEQUENCE);
}
+
+bool IMB_isfloat(ImBuf *ibuf)
+{
+ const ImFileType *type;
+
+ for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
+ if (type->ftype(type, ibuf)) {
+ return (type->flag & IM_FTYPE_FLOAT) != 0;
+ }
+ }
+ return false;
+}
diff --git a/source/blender/imbuf/intern/writeimage.c b/source/blender/imbuf/intern/writeimage.c
index 087330d10d2..2f688803804 100644
--- a/source/blender/imbuf/intern/writeimage.c
+++ b/source/blender/imbuf/intern/writeimage.c
@@ -41,26 +41,14 @@
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
-static ImBuf *prepare_write_imbuf(ImFileType *type, ImBuf *ibuf)
+static ImBuf *prepare_write_imbuf(const ImFileType *type, ImBuf *ibuf)
{
- ImBuf *write_ibuf = ibuf;
-
- if (type->flag & IM_FTYPE_FLOAT) {
- /* pass */
- }
- else {
- if (ibuf->rect == NULL && ibuf->rect_float) {
- ibuf->rect_colorspace = colormanage_colorspace_get_roled(COLOR_ROLE_DEFAULT_BYTE);
- IMB_rect_from_float(ibuf);
- }
- }
-
- return write_ibuf;
+ return IMB_prepare_write_ImBuf((type->flag & IM_FTYPE_FLOAT), ibuf);
}
short IMB_saveiff(struct ImBuf *ibuf, const char *name, int flags)
{
- ImFileType *type;
+ const ImFileType *type;
if (ibuf == NULL) return (false);
ibuf->flags = flags;
@@ -86,3 +74,19 @@ short IMB_saveiff(struct ImBuf *ibuf, const char *name, int flags)
return false;
}
+ImBuf *IMB_prepare_write_ImBuf(const bool isfloat, ImBuf *ibuf)
+{
+ ImBuf *write_ibuf = ibuf;
+
+ if (isfloat) {
+ /* pass */
+ }
+ else {
+ if (ibuf->rect == NULL && ibuf->rect_float) {
+ ibuf->rect_colorspace = colormanage_colorspace_get_roled(COLOR_ROLE_DEFAULT_BYTE);
+ IMB_rect_from_float(ibuf);
+ }
+ }
+
+ return write_ibuf;
+}
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index b51b53cc801..f9128363dee 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -155,20 +155,36 @@ typedef struct Library {
enum eIconSizes {
ICON_SIZE_ICON = 0,
- ICON_SIZE_PREVIEW = 1
+ ICON_SIZE_PREVIEW = 1,
+
+ NUM_ICON_SIZES
+};
+
+/* for PreviewImage->flag */
+enum ePreviewImage_Flag {
+ PRV_CHANGED = (1 << 0),
+ PRV_USER_EDITED = (1 << 1), /* if user-edited, do not auto-update this anymore! */
};
-#define NUM_ICON_SIZES (ICON_SIZE_PREVIEW + 1)
typedef struct PreviewImage {
/* All values of 2 are really NUM_ICON_SIZES */
unsigned int w[2];
unsigned int h[2];
- short changed[2];
+ short flag[2];
short changed_timestamp[2];
unsigned int *rect[2];
+
+ /* Runtime-only data. */
struct GPUTexture *gputexture[2];
+ int icon_id; /* Used by previews outside of ID context. */
+
+ char pad[3];
+ char use_deferred; /* for now a mere bool, if we add more deferred loading methods we can switch to bitflag. */
} PreviewImage;
+#define PRV_DEFERRED_DATA(prv) \
+ (CHECK_TYPE_INLINE(prv, PreviewImage *), BLI_assert((prv)->use_deferred), (void *)((prv) + 1))
+
/**
* Defines for working with IDs.
*
@@ -222,6 +238,7 @@ typedef struct PreviewImage {
#define ID_LS MAKE_ID2('L', 'S') /* FreestyleLineStyle */
#define ID_PAL MAKE_ID2('P', 'L') /* Palette */
#define ID_PC MAKE_ID2('P', 'C') /* PaintCurve */
+#define ID_CL MAKE_ID2('C', 'L') /* CacheLibrary */
/* NOTE! Fake IDs, needed for g.sipo->blocktype or outliner */
#define ID_SEQ MAKE_ID2('S', 'Q')
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index 47c84d99a16..5e076136f9b 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -378,7 +378,9 @@ typedef enum ePose_Flags {
/* set by BKE_pose_rebuild to give a chance to the IK solver to rebuild IK tree */
POSE_WAS_REBUILT = (1 << 5),
/* set by game_copy_pose to indicate that this pose is used in the game engine */
- POSE_GAME_ENGINE = (1 << 6)
+ POSE_GAME_ENGINE = (1 << 6),
+ /* pose constraint flags needs to be updated */
+ POSE_CONSTRAINTS_NEED_UPDATE_FLAGS = (1 << 7),
} ePose_Flags;
/* IK Solvers ------------------------------------ */
@@ -472,6 +474,9 @@ typedef enum eActionGroup_Flag {
AGRP_NOTVISIBLE = (1 << 5),
/* for UI (Graph Editor), sub-channels are shown */
AGRP_EXPANDED_G = (1 << 6),
+
+ /* sub channel modifiers off */
+ AGRP_MODIFIERS_OFF = (1 << 7),
AGRP_TEMP = (1 << 30),
AGRP_MOVED = (1 << 31)
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 9e6b71fcbac..590179e0a0f 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -459,7 +459,7 @@ typedef struct FCurve {
int color_mode; /* coloring method to use (eFCurve_Coloring) */
float color[3]; /* the last-color this curve took */
- float prev_norm_factor, pad;
+ float prev_norm_factor, prev_offset;
} FCurve;
@@ -479,7 +479,7 @@ typedef enum eFCurve_Flags {
/* fcurve uses 'auto-handles', which stay horizontal... */
// DEPRECATED
FCURVE_AUTO_HANDLES = (1<<5),
-
+ FCURVE_MOD_OFF = (1<<6),
/* skip evaluation, as RNA-path cannot be resolved (similar to muting, but cannot be set by user) */
FCURVE_DISABLED = (1<<10),
/* curve can only have whole-number values (integer types) */
@@ -853,6 +853,8 @@ typedef struct AnimData {
/* nla-tracks */
ListBase nla_tracks;
+ /* active NLA-track (only set/used during tweaking, so no need to worry about dangling pointers) */
+ NlaTrack *act_track;
/* active NLA-strip (only set/used during tweaking, so no need to worry about dangling pointers) */
NlaStrip *actstrip;
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 89c8316002b..a799e851887 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -102,7 +102,10 @@ 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 */
-
+ char hair_tool; /* active hair tool */
+ char pad2[3];
+ int pad3;
+
float autosmooth_factor;
float crease_pinch_factor;
@@ -137,34 +140,29 @@ typedef struct Brush {
float mask_stencil_dimension[2];
} Brush;
-typedef struct PaletteColor
-{
+typedef struct PaletteColor {
struct PaletteColor *next, *prev;
/* two values, one to store rgb, other to store values for sculpt/weight */
float rgb[3];
float value;
} PaletteColor;
-typedef struct Palette
-{
+typedef struct Palette {
ID id;
/* pointer to individual colours */
ListBase colors;
- ListBase deleted;
int active_color;
int pad;
} Palette;
-typedef struct PaintCurvePoint
-{
+typedef struct PaintCurvePoint {
BezTriple bez; /* bezier handle */
float pressure; /* pressure on that point */
} PaintCurvePoint;
-typedef struct PaintCurve
-{
+typedef struct PaintCurve {
ID id;
PaintCurvePoint *points; /* points of curve */
int tot_points;
@@ -260,6 +258,36 @@ typedef enum BrushSculptTool {
SCULPT_TOOL_MASK = 19
} BrushSculptTool;
+/** When #BRUSH_ACCUMULATE is used */
+#define SCULPT_TOOL_HAS_ACCUMULATE(t) ELEM(t, \
+ SCULPT_TOOL_DRAW, \
+ SCULPT_TOOL_CREASE, \
+ SCULPT_TOOL_BLOB, \
+ SCULPT_TOOL_LAYER, \
+ SCULPT_TOOL_INFLATE, \
+ SCULPT_TOOL_CLAY, \
+ SCULPT_TOOL_CLAY_STRIPS, \
+ SCULPT_TOOL_ROTATE, \
+ SCULPT_TOOL_FLATTEN \
+ )
+
+#define SCULPT_TOOL_HAS_NORMAL_WEIGHT(t) ELEM(t, \
+ SCULPT_TOOL_GRAB, \
+ SCULPT_TOOL_SNAKE_HOOK \
+ )
+
+#define SCULPT_TOOL_HAS_DYNTOPO(t) (ELEM(t, \
+ /* These brushes, as currently coded, cannot support dynamic topology */ \
+ SCULPT_TOOL_GRAB, \
+ SCULPT_TOOL_ROTATE, \
+ SCULPT_TOOL_THUMB, \
+ SCULPT_TOOL_LAYER, \
+ \
+ /* These brushes could handle dynamic topology, but user feedback indicates it's better not to */ \
+ SCULPT_TOOL_SMOOTH, \
+ SCULPT_TOOL_MASK \
+ ) == 0)
+
/* ImagePaintSettings.tool */
typedef enum BrushImagePaintTool {
PAINT_TOOL_DRAW = 0,
@@ -270,6 +298,16 @@ typedef enum BrushImagePaintTool {
PAINT_TOOL_MASK = 5
} BrushImagePaintTool;
+typedef enum BrushHairTool {
+ HAIR_TOOL_COMB = 1,
+ HAIR_TOOL_CUT = 2,
+ HAIR_TOOL_LENGTH = 3,
+ HAIR_TOOL_PUFF = 4,
+ HAIR_TOOL_ADD = 5,
+ HAIR_TOOL_SMOOTH = 6,
+ HAIR_TOOL_WEIGHT = 7,
+} BrushHairTool;
+
/* direction that the brush displaces along */
enum {
SCULPT_DISP_DIR_AREA = 0,
@@ -300,7 +338,7 @@ typedef enum BlurKernelType {
KERNEL_BOX
} BlurKernelType;
-#define MAX_BRUSH_PIXEL_RADIUS 200
+#define MAX_BRUSH_PIXEL_RADIUS 500
#endif
diff --git a/source/blender/makesdna/DNA_cache_library_types.h b/source/blender/makesdna/DNA_cache_library_types.h
new file mode 100644
index 00000000000..0def355e7d5
--- /dev/null
+++ b/source/blender/makesdna/DNA_cache_library_types.h
@@ -0,0 +1,294 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 by Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file DNA_cache_library_types.h
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_CACHE_LIBRARY_TYPES_H__
+#define __DNA_CACHE_LIBRARY_TYPES_H__
+
+#include "DNA_defs.h"
+#include "DNA_ID.h"
+#include "DNA_listBase.h"
+
+#define MAX_CACHE_GROUP_LEVEL 8
+
+typedef enum eCacheLibrary_SourceMode {
+ CACHE_LIBRARY_SOURCE_SCENE = 0, /* use generated scene data as input */
+ CACHE_LIBRARY_SOURCE_CACHE = 1, /* use cached data as input*/
+} eCacheLibrary_SourceMode;
+
+typedef enum eCacheLibrary_DisplayMode {
+ CACHE_LIBRARY_DISPLAY_SOURCE = 0, /* display source data */
+ CACHE_LIBRARY_DISPLAY_RESULT = 1, /* display result data */
+ CACHE_LIBRARY_DISPLAY_MODIFIERS = 2, /* display input with modifiers */
+} eCacheLibrary_DisplayMode;
+
+typedef enum eCacheDataType {
+ CACHE_TYPE_OBJECT = (1 << 0),
+ CACHE_TYPE_DERIVED_MESH = (1 << 1),
+ CACHE_TYPE_HAIR = (1 << 2),
+ CACHE_TYPE_HAIR_PATHS = (1 << 3),
+ CACHE_TYPE_PARTICLES = (1 << 4),
+
+ CACHE_TYPE_ALL = CACHE_TYPE_OBJECT | CACHE_TYPE_DERIVED_MESH | CACHE_TYPE_HAIR | CACHE_TYPE_HAIR_PATHS | CACHE_TYPE_PARTICLES,
+} eCacheDataType;
+
+typedef enum eCacheReadSampleResult {
+ CACHE_READ_SAMPLE_INVALID = 0, /* no valid result can be retrieved */
+ CACHE_READ_SAMPLE_EARLY = 1, /* request time before first sample */
+ CACHE_READ_SAMPLE_LATE = 2, /* request time after last sample */
+ CACHE_READ_SAMPLE_EXACT = 3, /* found sample for requested frame */
+ CACHE_READ_SAMPLE_INTERPOLATED = 4, /* no exact sample, but found enclosing samples for interpolation */
+} eCacheReadSampleResult;
+
+typedef enum eCacheLibrary_Flag {
+ CACHE_LIBRARY_BAKING = (1 << 0), /* perform modifier evaluation when evaluating */
+} eCacheLibrary_Flag;
+
+typedef enum eCacheLibrary_DisplayFlag {
+ CACHE_LIBRARY_DISPLAY_MOTION = (1 << 0), /* display motion state result from simulation, if available */
+ CACHE_LIBRARY_DISPLAY_CHILDREN = (1 << 1), /* display child strands, if available */
+} eCacheLibrary_DisplayFlag;
+
+typedef struct CacheLibrary {
+ ID id;
+
+ int flag;
+ short eval_mode DNA_DEPRECATED;
+ short source_mode;
+ short display_mode;
+ short pad;
+ int display_flag;
+ int render_flag DNA_DEPRECATED;
+ int data_types;
+ struct Group *filter_group;
+ char description[256];
+
+ char input_filepath[1024]; /* 1024 = FILE_MAX */
+ char output_filepath[1024]; /* 1024 = FILE_MAX */
+
+ ListBase modifiers;
+
+ struct CacheArchiveInfo *archive_info;
+} CacheLibrary;
+
+/* ========================================================================= */
+
+/* These are runtime structs, included in DNA only for easier RNA parsing */
+
+typedef struct CacheArchiveInfoNode {
+ struct CacheArchiveInfoNode *next, *prev;
+
+ short type;
+ short flag;
+ int pad;
+ char name[256];
+
+ ListBase child_nodes;
+
+ int64_t bytes_size; /* overall size of data stored in this node and children */
+
+ char datatype_name[64];
+ short datatype_extent;
+ short pad2;
+
+ int num_samples;
+
+ /* array properties */
+ int array_size;
+ int pad3;
+} CacheArchiveInfoNode;
+
+typedef enum eCacheArchiveInfoNode_Flag {
+ eCacheArchiveInfoNode_Flag_Expand,
+} eCacheArchiveInfoNode_Flag;
+
+typedef enum eCacheArchiveInfoNode_Type {
+ eCacheArchiveInfoNode_Type_Object,
+ eCacheArchiveInfoNode_Type_ScalarProperty,
+ eCacheArchiveInfoNode_Type_ArrayProperty,
+ eCacheArchiveInfoNode_Type_CompoundProperty,
+} eCacheArchiveInfoNode_Type;
+
+typedef struct CacheArchiveInfo {
+ char filepath[1024]; /* FILE_MAX */
+
+ char app_name[64]; /* MAX_NAME */
+ char date_written[64]; /* MAX_NAME */
+ char description[256];
+
+ struct CacheArchiveInfoNode *root_node;
+} CacheArchiveInfo;
+
+/* ========================================================================= */
+
+/* XXX here be dragons ...
+ * stuff below is a production hack,
+ * should not be considered a permanent solution ...
+ */
+typedef struct CacheModifier {
+ struct CacheModifier *next, *prev;
+
+ short type, pad;
+ int flag;
+ char name[64]; /* MAX_NAME */
+} CacheModifier;
+
+typedef enum eCacheModifier_Type {
+ eCacheModifierType_None = 0,
+
+ eCacheModifierType_HairSimulation = 1,
+ eCacheModifierType_ForceField = 2,
+ eCacheModifierType_ShrinkWrap = 3,
+ eCacheModifierType_StrandsKey = 4,
+ eCacheModifierType_Haircut = 5,
+
+ NUM_CACHE_MODIFIER_TYPES
+} eCacheModifier_Type;
+
+typedef struct HairSimParams {
+ int flag;
+ float timescale;
+ int substeps;
+ int pad;
+
+ struct EffectorWeights *effector_weights;
+
+ float mass;
+ float drag;
+ float goal_stiffness, goal_damping;
+ struct CurveMapping *goal_stiffness_mapping;
+ float stretch_stiffness, stretch_damping;
+ float bend_stiffness, bend_damping;
+ struct CurveMapping *bend_stiffness_mapping;
+} HairSimParams;
+
+typedef enum eHairSimParams_Flag {
+ eHairSimParams_Flag_UseGoalStiffnessCurve = (1 << 0),
+ eHairSimParams_Flag_UseBendStiffnessCurve = (1 << 1),
+ eHairSimParams_Flag_UseGoalDeflect = (1 << 2),
+} eHairSimParams_Flag;
+
+typedef struct HairSimCacheModifier {
+ CacheModifier modifier;
+
+ struct Object *object;
+ int hair_system;
+ int pad;
+
+ HairSimParams sim_params;
+} HairSimCacheModifier;
+
+/* cached mesh data for calculating velocities */
+typedef struct ForceFieldVertexCache {
+ float frame_prev;
+ int totvert;
+ float (*co_prev)[3];
+ float (*vel)[3];
+} ForceFieldVertexCache;
+
+typedef struct ForceFieldCacheModifier {
+ CacheModifier modifier;
+
+ struct Object *object;
+
+ struct ForceFieldVertexCache *vertex_cache;
+
+ int type;
+ int flag;
+ float strength;
+ float min_distance, max_distance;
+ float falloff;
+} ForceFieldCacheModifier;
+
+typedef enum eForceFieldCacheModifier_Type {
+ eForceFieldCacheModifier_Type_Deflect = 0,
+ eForceFieldCacheModifier_Type_Drag = 1,
+} eForceFieldCacheModifier_Type;
+
+typedef enum eForceFieldCacheModifier_Flag {
+ eForceFieldCacheModifier_Flag_DoubleSided = (1 << 0),
+} eForceFieldCacheModifier_Flag;
+
+typedef struct ShrinkWrapCacheModifier {
+ CacheModifier modifier;
+
+ struct Object *object;
+ int hair_system;
+ int flag;
+
+ struct Object *target;
+} ShrinkWrapCacheModifier;
+
+typedef enum eShrinkWrapCacheModifier_Flag {
+ eShrinkWrapCacheModifier_Flag_InternalTarget = (1 << 0),
+} eShrinkWrapCacheModifier_Flag;
+
+typedef struct StrandsKeyCacheModifier {
+ CacheModifier modifier;
+
+ struct Object *object;
+ int hair_system;
+ int flag;
+
+ struct Key *key;
+ int shapenr;
+ int pad;
+
+ struct BMEditStrands *edit; /* edit data (runtime) */
+} StrandsKeyCacheModifier;
+
+typedef enum eStrandsKeyCacheModifier_Flag {
+ eStrandsKeyCacheModifier_Flag_ShapeLock = (1 << 0),
+ eStrandsKeyCacheModifier_Flag_UseMotionState = (1 << 1),
+} eStrandsKeyCacheModifier_Flag;
+
+typedef struct HaircutCacheModifier {
+ CacheModifier modifier;
+
+ struct Object *object;
+ int hair_system;
+ int flag;
+
+ short cut_mode;
+ short pad[3];
+
+ struct Object *target;
+} HaircutCacheModifier;
+
+typedef enum eHaircutCacheModifier_Flag {
+ eHaircutCacheModifier_Flag_InternalTarget = (1 << 0),
+} eHaircutCacheModifier_Flag;
+
+typedef enum eHaircutCacheModifier_CutMode {
+ eHaircutCacheModifier_CutMode_Enter = (1 << 0),
+ eHaircutCacheModifier_CutMode_Exit = (1 << 1),
+} eHaircutCacheModifier_CutMode;
+
+#endif
diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h
index c67a356a708..6a9942aea66 100644
--- a/source/blender/makesdna/DNA_camera_types.h
+++ b/source/blender/makesdna/DNA_camera_types.h
@@ -44,6 +44,16 @@ struct Object;
struct AnimData;
struct Ipo;
+/* ------------------------------------------- */
+/* Stereo Settings */
+typedef struct CameraStereoSettings {
+ float interocular_distance;
+ float convergence_distance;
+ short convergence_mode;
+ short pivot;
+ short pad, pad2;
+} CameraStereoSettings;
+
typedef struct Camera {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
@@ -69,6 +79,9 @@ typedef struct Camera {
char sensor_fit;
char pad[7];
+
+ /* Stereo settings */
+ struct CameraStereoSettings stereo;
} Camera;
/* **************** CAMERA ********************* */
@@ -123,6 +136,20 @@ enum {
#define DEFAULT_SENSOR_WIDTH 32.0f
#define DEFAULT_SENSOR_HEIGHT 18.0f
+/* stereo->convergence_mode */
+enum {
+ CAM_S3D_OFFAXIS = 0,
+ CAM_S3D_PARALLEL = 1,
+ CAM_S3D_TOE = 2,
+};
+
+/* stereo->pivot */
+enum {
+ CAM_S3D_PIVOT_LEFT = 0,
+ CAM_S3D_PIVOT_RIGHT = 1,
+ CAM_S3D_PIVOT_CENTER = 2,
+};
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h
index e3731129632..c9a5e056e4a 100644
--- a/source/blender/makesdna/DNA_color_types.h
+++ b/source/blender/makesdna/DNA_color_types.h
@@ -133,7 +133,6 @@ typedef struct Histogram {
float co[2][2];
} Histogram;
-struct ImBuf;
typedef struct Scopes {
int ok;
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 288743d5e2f..40c028c3aa1 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -46,7 +46,6 @@ struct Key;
struct Material;
struct VFont;
struct AnimData;
-struct SelBox;
struct EditFont;
struct GHash;
@@ -158,6 +157,7 @@ typedef struct Nurb {
short tilt_interp; /* KEY_LINEAR, KEY_CARDINAL, KEY_BSPLINE */
short radius_interp;
+ /* only used for dynamically generated Nurbs created from OB_FONT's */
int charidx;
} Nurb;
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index aa954036e23..47cae0f4134 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -63,9 +63,10 @@ typedef struct CustomDataExternal {
* layers, each with a data type (e.g. MTFace, MDeformVert, etc.). */
typedef struct CustomData {
CustomDataLayer *layers; /* CustomDataLayers, ordered by type */
- int typemap[43]; /* runtime only! - maps types to indices of first layer of that type,
+ int typemap[44]; /* runtime only! - maps types to indices of first layer of that type,
* MUST be >= CD_NUMTYPES, but we cant use a define here.
* Correct size is ensured in CustomData_update_typemap assert() */
+ int pad;
int totlayer, maxlayer; /* number of layers, size of layers array */
int totsize; /* in editmode, total size of all data layers */
struct BLI_mempool *pool; /* (BMesh Only): Memory pool for allocation of blocks */
@@ -121,7 +122,9 @@ typedef enum CustomDataType {
CD_TESSLOOPNORMAL = 40,
CD_CUSTOMLOOPNORMAL = 41,
CD_FACEMAP = 42, /* exclusive face group, each face can only be part of one */
- CD_NUMTYPES = 43
+ CD_MSURFACE_SAMPLE = 43,
+
+ CD_NUMTYPES = 44
} CustomDataType;
/* Bits for CustomDataMask */
@@ -170,6 +173,7 @@ typedef enum CustomDataType {
#define CD_MASK_TESSLOOPNORMAL (1LL << CD_TESSLOOPNORMAL)
#define CD_MASK_CUSTOMLOOPNORMAL (1LL << CD_CUSTOMLOOPNORMAL)
#define CD_MASK_FACEMAP (1LL << CD_FACEMAP)
+#define CD_MASK_MSURFACE_SAMPLE (1LL << CD_MSURFACE_SAMPLE)
/* CustomData.flag */
enum {
diff --git a/source/blender/makesdna/DNA_documentation.h b/source/blender/makesdna/DNA_documentation.h
index 0dd7f37f8b4..0a0d46d70ff 100644
--- a/source/blender/makesdna/DNA_documentation.h
+++ b/source/blender/makesdna/DNA_documentation.h
@@ -48,6 +48,24 @@
* be badly defined. The reason for this is that it is called with
* different types of arguments. It takes a char* at this moment...
*
+ * - Ignoring structs:
+ *
+ * Sometimes we need to define structs in DNA which aren't written
+ * to disk, and can be excluded from blend file DNA string.
+ * in this case, add two '#' chars directly before the struct. eg.
+ *
+ * \code{.c}
+ * #
+ * #
+ * typedef struct MyStruct {
+ * int value;
+ * } MyStruct;
+ * \endcode
+ *
+ * Ignored structs can only be referred to from non-ignored structs
+ * when referred to as a pointer (where they're usually allocated
+ * and cleared in ``readfile.c``).
+ *
* - %Path to the header files
*
* Also because of historical reasons, there is a path prefix to the
diff --git a/source/blender/makesdna/DNA_dynamicpaint_types.h b/source/blender/makesdna/DNA_dynamicpaint_types.h
index dece93af122..17553e98817 100644
--- a/source/blender/makesdna/DNA_dynamicpaint_types.h
+++ b/source/blender/makesdna/DNA_dynamicpaint_types.h
@@ -29,7 +29,6 @@
#define __DNA_DYNAMICPAINT_TYPES_H__
#include "DNA_listBase.h"
-struct CurveMapping;
struct PaintSurfaceData;
/* surface format */
diff --git a/source/blender/makesdna/DNA_gpu_types.h b/source/blender/makesdna/DNA_gpu_types.h
index b6009b3f899..967cb7284dc 100644
--- a/source/blender/makesdna/DNA_gpu_types.h
+++ b/source/blender/makesdna/DNA_gpu_types.h
@@ -38,6 +38,8 @@ typedef struct GPUDOFSettings {
float fstop;
float focal_length;
float sensor;
+ int num_blades;
+ int high_quality;
} GPUDOFSettings;
/* properties for SSAO effect */
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index dca1c8330b0..0e2a41a0aeb 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -39,12 +39,10 @@
struct PackedFile;
struct Scene;
struct anim;
-struct ImBuf;
struct MovieCache;
struct RenderResult;
struct GPUTexture;
-
/* ImageUser is in Texture, in Nodes, Background Image, Image Window, .... */
/* should be used in conjunction with an ID * to Image. */
typedef struct ImageUser {
@@ -54,16 +52,32 @@ typedef struct ImageUser {
int frames; /* total amount of frames to use */
int offset, sfra; /* offset within movie, start frame in global time */
char fie_ima, cycl; /* fields/image in movie, cyclic flag */
- char ok, pad;
+ char ok;
- short multi_index, layer, pass; /* listbase indices, for menu browsing or retrieve buffer */
+ char multiview_eye; /* multiview current eye - for internal use of drawing routines */
+ int passtype;
+ short multi_index, view, layer; /* listbase indices, for menu browsing or retrieve buffer */
short flag;
-
- int pad2;
-
} ImageUser;
+typedef struct ImageAnim {
+ struct ImageAnim *next, *prev;
+ struct anim *anim;
+} ImageAnim;
+
+typedef struct ImageView {
+ struct ImageView *next, *prev;
+ char name[64]; /* MAX_NAME */
+ char filepath[1024]; /* 1024 = FILE_MAX */
+} ImageView;
+
+typedef struct ImagePackedFile {
+ struct ImagePackedFile *next, *prev;
+ struct PackedFile *packedfile;
+ char filepath[1024]; /* 1024 = FILE_MAX */
+} ImagePackedFile;
+
typedef struct RenderSlot {
char name[64]; /* 64 = MAX_NAME */
} RenderSlot;
@@ -73,6 +87,7 @@ typedef struct RenderSlot {
#define IMA_ANIM_REFRESHED 2
/* #define IMA_DO_PREMUL 4 */
#define IMA_NEED_FRAME_RECALC 8
+#define IMA_SHOW_STEREO 16
typedef struct Image {
ID id;
@@ -83,13 +98,13 @@ typedef struct Image {
struct GPUTexture *gputexture; /* not written in file */
/* sources from: */
- struct anim *anim;
+ ListBase anims;
struct RenderResult *rr;
struct RenderResult *renders[8]; /* IMA_MAX_RENDER_SLOT */
short render_slot, last_render_slot;
-
- short ok, flag;
+
+ int flag;
short source, type;
int lastframe;
@@ -100,14 +115,16 @@ typedef struct Image {
unsigned int bindcode; /* only for current image... */
unsigned int *repbind; /* for repeat of parts of images */
- struct PackedFile *packedfile;
+ struct PackedFile *packedfile DNA_DEPRECATED; /* deprecated */
+ struct ListBase packedfiles;
struct PreviewImage *preview;
/* game engine tile animation */
float lastupdate;
int lastused;
short animspeed;
- short pad2;
+
+ short ok;
/* for generated images */
int gen_x, gen_y;
@@ -122,7 +139,14 @@ typedef struct Image {
ColorManagedColorspaceSettings colorspace_settings;
char alpha_mode;
- char pad[7];
+ char pad[5];
+
+ /* Multiview */
+ char eye; /* for viewer node stereoscopy */
+ char views_format;
+ ListBase views;
+ struct Stereo3dFormat *stereo3d_format;
+
RenderSlot render_slots[8]; /* 8 = IMA_MAX_RENDER_SLOT */
} Image;
@@ -144,6 +168,9 @@ enum {
IMA_VIEW_AS_RENDER = (1 << 11),
IMA_IGNORE_ALPHA = (1 << 12),
IMA_DEINTERLACE = (1 << 13),
+ IMA_USE_VIEWS = (1 << 14),
+ IMA_IS_STEREO = (1 << 15),
+ IMA_IS_MULTIVIEW = (1 << 16), /* similar to stereo, but a more general case */
};
#if (DNA_DEPRECATED_GCC_POISON == 1)
diff --git a/source/blender/makesdna/DNA_key_types.h b/source/blender/makesdna/DNA_key_types.h
index 4cd2a41435c..5ab67d286b6 100644
--- a/source/blender/makesdna/DNA_key_types.h
+++ b/source/blender/makesdna/DNA_key_types.h
@@ -69,19 +69,21 @@ typedef struct KeyBlock {
float slidermax;
} KeyBlock;
-typedef struct KeyFrom {
- int type;
- int index; /* index of owner in the id */
-} KeyFrom;
-
typedef enum eKeyOwnerType {
/* 0 used as 'undefined', for versioning */
KEY_OWNER_MESH = 1,
KEY_OWNER_CURVE = 2,
KEY_OWNER_LATTICE = 3,
KEY_OWNER_PARTICLES = 4,
+ KEY_OWNER_CACHELIB = 5,
} eKeyOwnerType;
+/* DEPRECATED */
+typedef struct KeyFrom {
+ int type DNA_DEPRECATED;
+ int index DNA_DEPRECATED; /* index of owner in the id */
+} KeyFrom;
+
typedef struct Key {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
@@ -102,7 +104,9 @@ typedef struct Key {
struct Ipo *ipo DNA_DEPRECATED; /* old animation system, deprecated for 2.5 */
ID *from;
- KeyFrom from_extra; /* supplementary info about the 'from' datablock */
+ KeyFrom from_extra DNA_DEPRECATED;
+ int fromtype; /* supplementary type of the Key owner */
+ int fromindex; /* index of owner in the id */
int totkey; /* (totkey == BLI_listbase_count(&key->block)) */
short flag;
diff --git a/source/blender/makesdna/DNA_lamp_types.h b/source/blender/makesdna/DNA_lamp_types.h
index a920182d5a3..ce8e86cb512 100644
--- a/source/blender/makesdna/DNA_lamp_types.h
+++ b/source/blender/makesdna/DNA_lamp_types.h
@@ -151,6 +151,7 @@ typedef struct Lamp {
#define LA_LAYER_SHADOW (1 << 15)
#define LA_SHAD_TEX (1 << 16)
#define LA_SHOW_CONE (1 << 17)
+#define LA_SHOW_SHADOW_BOX (1 << 18)
/* layer_shadow */
#define LA_LAYER_SHADOW_BOTH 0
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 8067fa5db2d..3799de011d4 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -37,7 +37,6 @@
#include "DNA_customdata_types.h"
struct AnimData;
-struct DerivedMesh;
struct Ipo;
struct Key;
struct MCol;
@@ -47,13 +46,11 @@ struct MLoop;
struct MLoopCol;
struct MLoopUV;
struct MPoly;
-struct MSticky;
struct MTexPoly;
struct MVert;
struct Material;
struct Mesh;
struct Multires;
-struct OcInfo;
typedef struct Mesh {
ID id;
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index 3304980f964..e3eb04a5578 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -35,7 +35,6 @@
#include "DNA_customdata_types.h"
#include "DNA_listBase.h"
-struct Bone;
struct Image;
/*tessellation face, see MLoop/MPoly for the real face data*/
@@ -216,7 +215,6 @@ typedef struct MultiresEdge {
unsigned int mid;
} MultiresEdge;
-struct MultiresMapNode;
typedef struct MultiresLevel {
struct MultiresLevel *next, *prev;
@@ -300,6 +298,13 @@ enum {
FREESTYLE_FACE_MARK = 1,
};
+typedef struct MSurfaceSample {
+ unsigned int orig_verts[3];
+ float orig_weights[3];
+ int orig_poly;
+ unsigned int orig_loops[3];
+} MSurfaceSample;
+
/* mvert->flag */
enum {
/* SELECT = (1 << 0), */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 414d1d7212e..bf2d5e5fa6c 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -84,6 +84,7 @@ typedef enum ModifierType {
eModifierType_Wireframe = 48,
eModifierType_DataTransfer = 49,
eModifierType_NormalEdit = 50,
+ eModifierType_CorrectiveSmooth = 51,
NUM_MODIFIER_TYPES
} ModifierType;
@@ -430,10 +431,11 @@ typedef struct DecimateModifierData {
float angle; /* (mode == MOD_DECIM_MODE_DISSOLVE) */
char defgrp_name[64]; /* MAX_VGROUP_NAME */
+ float defgrp_factor;
short flag, mode;
/* runtime only */
- int face_count, pad2;
+ int face_count;
} DecimateModifierData;
enum {
@@ -733,6 +735,7 @@ typedef struct ParticleInstanceModifierData {
struct Object *ob;
short psys, flag, axis, space;
float position, random_position;
+ float rotation, random_rotation;
float particle_amount, particle_offset;
char index_layer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
char value_layer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
@@ -1296,6 +1299,48 @@ enum {
MOD_LAPLACIANSMOOTH_NORMALIZED = (1 << 5),
};
+
+typedef struct CorrectiveSmoothModifierData {
+ ModifierData modifier;
+
+ /* positions set during 'bind' operator
+ * use for MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND */
+ float (*bind_coords)[3];
+
+ /* note: -1 is used to bind */
+ unsigned int bind_coords_num;
+
+ float lambda;
+ short repeat, flag;
+ char smooth_type, rest_source;
+ char pad[2];
+
+ char defgrp_name[64]; /* MAX_VGROUP_NAME */
+
+ /* runtime-only cache (delta's between),
+ * delta's between the original positions and the smoothed positions */
+ float (*delta_cache)[3];
+ unsigned int delta_cache_num;
+ char pad2[4];
+} CorrectiveSmoothModifierData;
+
+enum {
+ MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE = 0,
+ MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT = 1,
+};
+
+enum {
+ MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO = 0,
+ MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND = 1,
+};
+
+/* Corrective Smooth modifier flags */
+enum {
+ MOD_CORRECTIVESMOOTH_INVERT_VGROUP = (1 << 0),
+ MOD_CORRECTIVESMOOTH_ONLY_SMOOTH = (1 << 1),
+ MOD_CORRECTIVESMOOTH_PIN_BOUNDARY = (1 << 2),
+};
+
typedef struct UVWarpModifierData {
ModifierData modifier;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index f08b3ea9590..37bc65999a9 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -40,7 +40,6 @@
struct ID;
struct ListBase;
-struct SpaceNode;
struct bNodeLink;
struct bNodeType;
struct bNodeTreeExec;
@@ -264,12 +263,12 @@ typedef struct bNode {
*/
#define NODE_UPDATE 0xFFFF /* generic update flag (includes all others) */
#define NODE_UPDATE_ID 1 /* associated id data block has changed */
+#define NODE_UPDATE_OPERATOR 2 /* node update triggered from update operator */
/* Unique hash key for identifying node instances
* Defined as a struct because DNA does not support other typedefs.
*/
-typedef struct bNodeInstanceKey
-{
+typedef struct bNodeInstanceKey {
unsigned int value;
} bNodeInstanceKey;
@@ -383,7 +382,7 @@ typedef struct bNodeTree {
/* callbacks */
void (*progress)(void *, float progress);
- void (*stats_draw)(void *, char *str);
+ void (*stats_draw)(void *, const char *str);
int (*test_break)(void *);
void (*update_draw)(void *);
void *tbh, *prh, *sdh, *udh;
@@ -789,6 +788,17 @@ typedef struct NodeShaderVectTransform {
int pad;
} NodeShaderVectTransform;
+typedef struct NodeShaderTexPointDensity {
+ short point_source, pad;
+ int particle_system;
+ float radius;
+ int resolution;
+ short space;
+ short interpolation;
+ short color_source;
+ short pad2;
+} NodeShaderTexPointDensity;
+
/* TEX_output */
typedef struct TexNodeOutput {
char name[64];
@@ -1091,4 +1101,24 @@ enum {
#define CMP_NODE_PLANETRACKDEFORM_MBLUR_SAMPLES_MAX 64
+/* Point Density shader node */
+
+enum {
+ SHD_POINTDENSITY_SOURCE_PSYS = 0,
+ SHD_POINTDENSITY_SOURCE_OBJECT = 1,
+};
+
+enum {
+ SHD_POINTDENSITY_SPACE_OBJECT = 0,
+ SHD_POINTDENSITY_SPACE_WORLD = 1,
+};
+
+enum {
+ SHD_POINTDENSITY_COLOR_CONSTANT = 0,
+ SHD_POINTDENSITY_COLOR_PARTAGE = 1,
+ SHD_POINTDENSITY_COLOR_PARTSPEED = 2,
+ SHD_POINTDENSITY_COLOR_PARTVEL = 3,
+ SHD_POINTDENSITY_COLOR_PARTTEX = 4,
+};
+
#endif
diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h
index fac8443308e..52ea42eb535 100644
--- a/source/blender/makesdna/DNA_object_force.h
+++ b/source/blender/makesdna/DNA_object_force.h
@@ -297,7 +297,7 @@ typedef struct SoftBody {
char namedVG_Softgoal[64]; /* MAX_VGROUP_NAME */
/* starting to fix old bug .. nastiness that VG are indexes
* rather find them by name tag to find it -> jow20090613 */
-
+
short fuzzyness; /* */
/* springs */
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 955674fd79e..10e59618aa0 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -48,7 +48,6 @@ struct Ipo;
struct BoundBox;
struct Path;
struct Material;
-struct bConstraintChannel;
struct PartDeflect;
struct SoftBody;
struct FluidsimSettings;
@@ -117,7 +116,8 @@ typedef struct LodLevel {
struct LodLevel *next, *prev;
struct Object *source;
int flags;
- float distance;
+ float distance, pad;
+ int obhysteresis;
} LodLevel;
typedef struct Object {
@@ -189,7 +189,8 @@ typedef struct Object {
short flag; /* copy of Base */
short colbits DNA_DEPRECATED; /* deprecated, use 'matbits' */
- short transflag, protectflag; /* transformation settings and transform locks */
+ int transflag; /* transformation settings */
+ short protectflag, pad; /* transform locks */
short trackflag, upflag;
short nlaflag; /* used for DopeSheet filtering settings (expanded/collapsed) */
short ipoflag; // xxx deprecated... old animation system
@@ -200,8 +201,6 @@ typedef struct Object {
/* dupli-frame settings */
int dupon, dupoff, dupsta, dupend;
- int pad;
-
/* during realtime */
/* note that inertia is only called inertia for historical reasons
@@ -253,7 +252,11 @@ typedef struct Object {
short index; /* custom index, for renderpasses */
unsigned short actdef; /* current deformation group, note: index starts at 1 */
unsigned short actfmap; /* current face map, note: index starts at 1 */
- unsigned short pad2[3];
+ unsigned short pad2[2];
+
+ /* did last modifier stack generation need mapping support? */
+ short lastNeedMapping;
+
float col[4]; /* object color */
int gameflag;
@@ -274,6 +277,8 @@ typedef struct Object {
struct PartDeflect *pd; /* particle deflector/attractor/collision data */
struct SoftBody *soft; /* if exists, saved in file */
struct Group *dup_group; /* object duplicator for group */
+ struct DupliCache *dup_cache; /* cached dupli overrides */
+ struct CacheLibrary *cache_library; /* cache library to use */
char body_type; /* for now used to temporarily holds the type of collision object */
char shapeflag; /* flag for pinning */
@@ -339,8 +344,43 @@ typedef struct DupliObject {
/* particle this dupli was generated from */
struct ParticleSystem *particle_system;
+
+ struct DupliObjectData *data;
} DupliObject;
+typedef struct DupliObjectDataStrands {
+ struct DupliObjectDataStrands *next, *prev;
+
+ char name[64]; /* MAX_NAME */
+ struct Strands *strands;
+ struct StrandsChildren *strands_children;
+} DupliObjectDataStrands;
+
+/* data that can be shared by multiple DupliObject instances */
+typedef struct DupliObjectData {
+ /* XXX eventually it should be possible to construct dupli instances
+ * entirely without Objects in the DNA, but current drawing code and
+ * others make this too difficult
+ */
+ struct Object *ob;
+ struct BoundBox bb;
+ struct DerivedMesh *dm;
+ ListBase strands;
+} DupliObjectData;
+
+typedef struct DupliCache {
+ short flag;
+ short result;
+ float cfra; /* frame for which the cache was constructed */
+
+ struct GHash *ghash;
+ ListBase duplilist;
+} DupliCache;
+
+typedef enum eDupliCache_Flag {
+ DUPCACHE_FLAG_DIRTY = (1 << 0), /* cache requires update */
+} eDupliCache_Flag;
+
/* **************** OBJECT ********************* */
/* used many places... should be specialized */
@@ -408,7 +448,7 @@ enum {
OB_DUPLIVERTS = 1 << 4,
OB_DUPLIROT = 1 << 5,
OB_DUPLINOSPEED = 1 << 6,
-/* OB_POWERTRACK = 1 << 7,*/ /*UNUSED*/
+ OB_DUPLICALCDERIVED = 1 << 7, /* runtime, calculate derivedmesh for dupli before it's used */
OB_DUPLIGROUP = 1 << 8,
OB_DUPLIFACES = 1 << 9,
OB_DUPLIFACES_SCALE = 1 << 10,
@@ -417,6 +457,8 @@ enum {
OB_NO_CONSTRAINTS = 1 << 13, /* runtime constraints disable */
OB_NO_PSYS_UPDATE = 1 << 14, /* hack to work around particle issue */
+ OB_IS_DUPLI_CACHE = 1 << 31, /* temporary flag: object data overridden from cache */
+
OB_DUPLI = OB_DUPLIFRAMES | OB_DUPLIVERTS | OB_DUPLIGROUP | OB_DUPLIFACES | OB_DUPLIPARTS,
};
@@ -496,6 +538,7 @@ enum {
enum {
OB_LOD_USE_MESH = 1 << 0,
OB_LOD_USE_MAT = 1 << 1,
+ OB_LOD_USE_HYST = 1 << 2,
};
@@ -541,7 +584,7 @@ enum {
#define OB_MAX_STATES 30
/* collision masks */
-#define OB_MAX_COL_MASKS 8
+#define OB_MAX_COL_MASKS 16
/* ob->gameflag */
enum {
@@ -684,10 +727,12 @@ typedef enum ObjectMode {
OB_MODE_TEXTURE_PAINT = 1 << 4,
OB_MODE_PARTICLE_EDIT = 1 << 5,
OB_MODE_POSE = 1 << 6,
+ OB_MODE_HAIR_EDIT = 1 << 7,
} ObjectMode;
/* any mode where the brush system is used */
#define OB_MODE_ALL_PAINT (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)
+#define OB_MODE_ALL_BRUSH (OB_MODE_ALL_PAINT | OB_MODE_HAIR_EDIT)
#define MAX_DUPLI_RECUR 8
diff --git a/source/blender/makesdna/DNA_packedFile_types.h b/source/blender/makesdna/DNA_packedFile_types.h
index ef0a0f642d6..56140c84cb1 100644
--- a/source/blender/makesdna/DNA_packedFile_types.h
+++ b/source/blender/makesdna/DNA_packedFile_types.h
@@ -40,8 +40,7 @@ typedef struct PackedFile {
void *data;
} PackedFile;
-enum PF_FileStatus
-{
+enum PF_FileStatus {
PF_EQUAL = 0,
PF_DIFFERS = 1,
PF_NOFILE = 2,
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index 9d1f7e46765..07e944c360a 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -282,6 +282,7 @@ typedef struct ParticleSystem {
struct PTCacheEdit *edit; /* particle editmode (runtime) */
void (*free_edit)(struct PTCacheEdit *edit); /* free callback */
+ struct BMEditStrands *hairedit; /* hair edit data (runtime) */
struct ParticleCacheKey **pathcache; /* path cache (runtime) */
struct ParticleCacheKey **childcache; /* child cache (runtime) */
@@ -452,9 +453,9 @@ typedef enum eParticleDrawColorMode {
PART_DRAW_COL_VEL = 2,
PART_DRAW_COL_ACC = 3,
PART_DRAW_COL_PARENT = 4,
+ PART_DRAW_COL_TEX = 5,
} eParticleDrawColorMode;
-
/* part->simplify_flag */
#define PART_SIMPLIFY_ENABLE 1
#define PART_SIMPLIFY_VIEWPORT 2
@@ -625,6 +626,8 @@ typedef enum eParticleTextureInfluence {
PAMAP_LENGTH = (1<<4),
PAMAP_CHILD = (PAMAP_CLUMP | PAMAP_KINK_FREQ | PAMAP_KINK_AMP | PAMAP_ROUGH | PAMAP_LENGTH),
PAMAP_SHAPEKEY = (1<<13), /* shapekey blend multiplier */
+ /* color */
+ PAMAP_COLOR = (1<<14),
} eParticleTextureInfluence;
#endif
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index ff924edb152..1872ced9b24 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -47,6 +47,7 @@ extern "C" {
#include "DNA_ID.h"
#include "DNA_freestyle_types.h"
#include "DNA_gpu_types.h"
+#include "DNA_userdef_types.h"
struct CurveMapping;
struct Object;
@@ -249,6 +250,73 @@ typedef enum ScenePassType {
/* note, srl->passflag is treestore element 'nr' in outliner, short still... */
+/* View - MultiView */
+typedef struct SceneRenderView {
+ struct SceneRenderView *next, *prev;
+
+ char name[64]; /* MAX_NAME */
+ char suffix[64]; /* MAX_NAME */
+
+ int viewflag;
+ int pad[2];
+ char pad2[4];
+
+} SceneRenderView;
+
+/* srv->viewflag */
+#define SCE_VIEW_DISABLE (1<<0)
+
+/* scene.render.views_format */
+enum {
+ SCE_VIEWS_FORMAT_STEREO_3D = 0,
+ SCE_VIEWS_FORMAT_MULTIVIEW = 1,
+};
+
+/* ImageFormatData.views_output */
+enum {
+ R_IMF_VIEWS_INDIVIDUAL = 0,
+ R_IMF_VIEWS_STEREO_3D = 1,
+ R_IMF_VIEWS_MULTIVIEW = 2,
+};
+
+typedef struct Stereo3dFormat {
+ short flag;
+ char display_mode; /* encoding mode */
+ char anaglyph_type; /* anaglyph scheme for the user display */
+ char interlace_type; /* interlace type for the user display */
+ char pad[3];
+} Stereo3dFormat;
+
+/* Stereo3dFormat.display_mode */
+typedef enum eStereoDisplayMode {
+ S3D_DISPLAY_ANAGLYPH = 0,
+ S3D_DISPLAY_INTERLACE = 1,
+ S3D_DISPLAY_PAGEFLIP = 2,
+ S3D_DISPLAY_SIDEBYSIDE = 3,
+ S3D_DISPLAY_TOPBOTTOM = 4,
+} eStereoDisplayMode;
+
+/* Stereo3dFormat.flag */
+typedef enum eStereo3dFlag {
+ S3D_INTERLACE_SWAP = (1 << 0),
+ S3D_SIDEBYSIDE_CROSSEYED = (1 << 1),
+ S3D_SQUEEZED_FRAME = (1 << 2),
+} eStereo3dFlag;
+
+/* Stereo3dFormat.anaglyph_type */
+typedef enum eStereo3dAnaglyphType {
+ S3D_ANAGLYPH_REDCYAN = 0,
+ S3D_ANAGLYPH_GREENMAGENTA = 1,
+ S3D_ANAGLYPH_YELLOWBLUE = 2,
+} eStereo3dAnaglyphType;
+
+/* Stereo3dFormat.interlace_type */
+typedef enum eStereo3dInterlaceType {
+ S3D_INTERLACE_ROW = 0,
+ S3D_INTERLACE_COLUMN = 1,
+ S3D_INTERLACE_CHECKERBOARD = 2,
+} eStereo3dInterlaceType;
+
/* *************************************************************** */
/* Generic image format settings,
@@ -286,7 +354,11 @@ typedef struct ImageFormatData {
char jp2_flag;
char jp2_codec;
- char pad[6];
+ char pad[5];
+
+ /* Multiview */
+ char views_format;
+ Stereo3dFormat stereo3d_format;
/* color management */
ColorManagedViewSettings view_settings;
@@ -350,6 +422,12 @@ typedef struct ImageFormatData {
#define R_IMF_EXR_CODEC_ZIP 2
#define R_IMF_EXR_CODEC_PIZ 3
#define R_IMF_EXR_CODEC_RLE 4
+#define R_IMF_EXR_CODEC_ZIPS 5
+#define R_IMF_EXR_CODEC_B44 6
+#define R_IMF_EXR_CODEC_B44A 7
+#define R_IMF_EXR_CODEC_DWAA 8
+#define R_IMF_EXR_CODEC_DWAB 9
+#define R_IMF_EXR_CODEC_MAX 10
/* ImageFormatData.jp2_flag */
#define R_IMF_JP2_FLAG_YCC (1<<0) /* when disabled use RGB */ /* was R_JPEG2K_YCC */
@@ -579,8 +657,10 @@ typedef struct RenderData {
/* render simplify */
int simplify_flag;
short simplify_subsurf;
- short simplify_shadowsamples;
+ short simplify_subsurf_render;
+ short simplify_shadowsamples, pad9;
float simplify_particles;
+ float simplify_particles_render;
float simplify_aosss;
/* cineon */
@@ -610,6 +690,12 @@ typedef struct RenderData {
int preview_start_resolution;
int pad;
+
+ /* MultiView */
+ ListBase views;
+ short actview;
+ short views_format;
+ short pad8[2];
} RenderData;
/* *************************************************************** */
@@ -712,7 +798,12 @@ typedef struct GameData {
short obstacleSimulation;
short raster_storage;
float levelHeight;
- float deactivationtime, lineardeactthreshold, angulardeactthreshold, pad2;
+ float deactivationtime, lineardeactthreshold, angulardeactthreshold;
+
+ /* Scene LoD */
+ short lodflag, pad2;
+ int scehysteresis, pad5;
+
} GameData;
#define STEREO_NOSTEREO 1
@@ -785,6 +876,9 @@ enum {
#pragma GCC poison GAME_MAT_TEXFACE
#endif
+/* GameData.lodflag */
+#define SCE_LOD_USE_HYST (1 << 0)
+
/* UV Paint */
#define UV_SCULPT_LOCK_BORDERS 1
#define UV_SCULPT_ALL_ISLANDS 2
@@ -796,6 +890,19 @@ enum {
#define UV_SCULPT_TOOL_RELAX_LAPLACIAN 1
#define UV_SCULPT_TOOL_RELAX_HC 2
+/* Stereo Flags */
+#define STEREO_RIGHT_NAME "right"
+#define STEREO_LEFT_NAME "left"
+#define STEREO_RIGHT_SUFFIX "_R"
+#define STEREO_LEFT_SUFFIX "_L"
+
+typedef enum StereoViews {
+ STEREO_LEFT_ID = 0,
+ STEREO_RIGHT_ID = 1,
+ STEREO_3D_ID = 2,
+ STEREO_MONO_ID = 3,
+} StereoViews;
+
/* Markers */
typedef struct TimeMarker {
@@ -889,6 +996,32 @@ typedef struct ParticleEditSettings {
} ParticleEditSettings;
/* ------------------------------------------- */
+/* Hair Edit */
+
+/* HairEditSettings->select_mode */
+typedef enum HairEditSelectMode {
+ HAIR_SELECT_STRAND = 0,
+ HAIR_SELECT_VERTEX = 1,
+ HAIR_SELECT_TIP = 2,
+} HairEditSelectMode;
+
+/* HairEditSettings->flag */
+typedef enum HairEditFlag {
+ HAIR_EDIT_SHOW_DEBUG = (1 << 16),
+} HairEditFlag;
+
+typedef struct HairEditSettings {
+ int flag;
+ int select_mode;
+
+ struct Brush *brush;
+ struct Object *shape_object;
+
+ /* WM Paint cursor */
+ void *paint_cursor;
+} HairEditSettings;
+
+/* ------------------------------------------- */
/* Sculpt */
/* Sculpt */
@@ -914,6 +1047,8 @@ typedef struct Sculpt {
/* scale for constant detail size */
float constant_detail;
+ float detail_percent;
+ float pad;
struct Object *gravity_object;
void *pad2;
@@ -1112,7 +1247,10 @@ typedef struct ToolSettings {
/* Particle Editing */
struct ParticleEditSettings particle;
-
+
+ /* Hair Editing */
+ struct HairEditSettings hair_edit;
+
/* Transform Proportional Area of Effect */
float proportional_size;
@@ -1166,7 +1304,11 @@ typedef struct ToolSettings {
short snap_flag, snap_target;
short proportional, prop_mode;
char proportional_objects; /* proportional edit, object mode */
- char proportional_mask; /* proportional edit, object mode */
+ char proportional_mask; /* proportional edit, mask editing */
+ char proportional_action; /* proportional edit, action editor */
+ char proportional_fcurve; /* proportional edit, graph editor */
+ char lock_markers; /* lock marker editing */
+ char pad4[5];
char auto_normalize; /*auto normalizing mode in wpaint*/
char multipaint; /* paint multiple bones in wpaint */
@@ -1283,13 +1425,15 @@ typedef struct Scene {
ListBase transform_spaces;
void *sound_scene;
- void *sound_scene_handle;
+ void *playback_handle;
void *sound_scrub_handle;
void *speaker_handles;
void *fps_info; /* (runtime) info/cache used for presenting playback framerate info to the user */
/* none of the dependency graph vars is mean to be saved */
+ struct Depsgraph *depsgraph;
+ void *pad1;
struct DagForest *theDag;
short dagflags;
short recalc; /* recalc = counterpart of ob->recalc */
@@ -1428,6 +1572,7 @@ typedef struct Scene {
#define R_TEXNODE_PREVIEW 0x40000
#define R_VIEWPORT_PREVIEW 0x80000
#define R_EXR_CACHE_FILE 0x100000
+#define R_MULTIVIEW 0x200000
/* r->stamp */
#define R_STAMP_TIME 0x0001
@@ -1741,7 +1886,8 @@ typedef enum SculptFlags {
SCULPT_DYNTOPO_COLLAPSE = (1 << 11),
/* If set, dynamic-topology detail size will be constant in object space */
- SCULPT_DYNTOPO_DETAIL_CONSTANT = (1 << 13)
+ SCULPT_DYNTOPO_DETAIL_CONSTANT = (1 << 13),
+ SCULPT_DYNTOPO_DETAIL_BRUSH = (1 << 14),
} SculptFlags;
typedef enum ImagePaintMode {
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 81f497d97a4..5a707ef7c3b 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -41,7 +41,6 @@ struct SpaceLink;
struct ARegion;
struct ARegionType;
struct PanelType;
-struct HeaderType;
struct Scene;
struct uiLayout;
struct wmTimer;
@@ -70,7 +69,8 @@ typedef struct bScreen {
char do_draw_drag; /* notifier for dragging draw. */
char swap; /* indicator to survive swap-exchange systems */
char skip_handling; /* set to delay screen handling after switching back from maximized area */
- char pad[7];
+ char scrubbing; /* set while scrubbing to skip some updates done while animating */
+ char pad[6];
short mainwin; /* screensize subwindow, for screenedges and global menus */
short subwinactive; /* active subwindow */
@@ -284,6 +284,8 @@ enum {
AREA_FLAG_TEMP_TYPE = (1 << 6),
/* for temporary fullscreens (file browser, image editor render) that are opened above user set fullscreens */
AREA_FLAG_STACKED_FULLSCREEN = (1 << 7),
+ /* update action zones (even if the mouse is not intersecting them) */
+ AREA_FLAG_ACTIONZONES_UPDATE = (1 << 8),
};
#define EDGEWIDTH 1
@@ -375,6 +377,8 @@ enum {
RGN_TYPE_TOOL_PROPS = 6,
RGN_TYPE_PREVIEW = 7
};
+/* use for function args */
+#define RGN_TYPE_ANY -1
/* region alignment */
#define RGN_ALIGN_NONE 0
diff --git a/source/blender/makesdna/DNA_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h
index 8d59a13768b..d886dcf2807 100644
--- a/source/blender/makesdna/DNA_sensor_types.h
+++ b/source/blender/makesdna/DNA_sensor_types.h
@@ -164,7 +164,7 @@ typedef struct bSensor {
struct bSensor *next, *prev;
/* pulse and freq are the bool toggle and frame count for pulse mode */
short type, otype, flag, pulse;
- short freq, totlinks, pad1, pad2;
+ short freq, totlinks, pad1, pad2; /* freq makes reference to skipped ticks between 2 active pulses */
char name[64]; /* MAX_NAME */
void *data;
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index ce9fdbaba64..d45467373d6 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -53,6 +53,11 @@ struct MovieClip;
/* strlens; 256= FILE_MAXFILE, 768= FILE_MAXDIR */
+typedef struct StripAnim {
+ struct StripAnim *next, *prev;
+ struct anim *anim;
+} StripAnim;
+
typedef struct StripElem {
char name[256];
int orig_width, orig_height;
@@ -95,7 +100,8 @@ typedef struct StripProxy {
short build_tc_flags; // time code flags (see below) of all tc indices
// to build
short build_flags;
- char pad[6];
+ char storage;
+ char pad[5];
} StripProxy;
typedef struct Strip {
@@ -155,15 +161,14 @@ typedef struct Sequence {
struct Object *scene_camera; /* override scene camera */
struct MovieClip *clip; /* for MOVIECLIP strips */
struct Mask *mask; /* for MASK strips */
-
- struct anim *anim; /* for MOVIE strips */
+ ListBase anims; /* for MOVIE strips */
float effect_fader;
float speed_fader;
/* pointers for effects: */
struct Sequence *seq1, *seq2, *seq3;
-
+
ListBase seqbase; /* list of strips for metastrips */
struct bSound *sound; /* the linked "bSound" object */
@@ -186,8 +191,14 @@ typedef struct Sequence {
int sfra; /* starting frame according to the timeline of the scene. */
char alpha_mode;
- char pad[3];
-
+ char pad[2];
+
+ /* Multiview */
+ char views_format;
+ struct Stereo3dFormat *stereo3d_format;
+
+ struct IDProperty *prop;
+
/* modifiers */
ListBase modifiers;
} Sequence;
@@ -215,9 +226,10 @@ typedef struct Editing {
char act_imagedir[1024]; /* 1024 = FILE_MAX */
char act_sounddir[1024]; /* 1024 = FILE_MAX */
+ char proxy_dir[1024]; /* 1024 = FILE_MAX */
int over_ofs, over_cfra;
- int over_flag, pad;
+ int over_flag, proxy_storage;
rctf over_border;
} Editing;
@@ -332,6 +344,10 @@ typedef struct SequencerScopes {
#define SEQ_STRIP_OFSBOTTOM 0.2f
#define SEQ_STRIP_OFSTOP 0.8f
+/* Editor->proxy_storage */
+/* store proxies in project directory */
+#define SEQ_EDIT_PROXY_DIR_STORAGE 1
+
/* SpeedControlVars->flags */
#define SEQ_SPEED_INTEGRATE 1
/* #define SEQ_SPEED_BLEND 2 */ /* DEPRECATED */
@@ -360,9 +376,9 @@ enum {
SEQ_USE_TRANSFORM = (1 << 16),
SEQ_USE_CROP = (1 << 17),
/* SEQ_USE_COLOR_BALANCE = (1 << 18), */ /* DEPRECATED */
- SEQ_USE_PROXY_CUSTOM_DIR = (1 << 19),
+ /* SEQ_USE_PROXY_CUSTOM_DIR = (1 << 19), */ /* DEPRECATED */
- SEQ_USE_PROXY_CUSTOM_FILE = (1 << 21),
+ /* SEQ_USE_PROXY_CUSTOM_FILE = (1 << 21), */ /* DEPRECATED */
SEQ_USE_EFFECT_DEFAULT_FADE = (1 << 22),
SEQ_USE_LINEAR_MODIFIERS = (1 << 23),
@@ -374,12 +390,19 @@ enum {
/* don't include Grease Pencil in OpenGL previews of Scene strips */
SEQ_SCENE_NO_GPENCIL = (1 << 28),
+ SEQ_USE_VIEWS = (1 << 29),
/* access scene strips directly (like a metastrip) */
- SEQ_SCENE_STRIPS = (1 << 29),
+ SEQ_SCENE_STRIPS = (1 << 30),
SEQ_INVALID_EFFECT = (1 << 31),
};
+/* StripProxy->storage */
+enum {
+ SEQ_STORAGE_PROXY_CUSTOM_FILE = (1 << 1), /* store proxy in custom directory */
+ SEQ_STORAGE_PROXY_CUSTOM_DIR = (1 << 2), /* store proxy in custom file */
+};
+
#if (DNA_DEPRECATED_GCC_POISON == 1)
#pragma GCC poison SEQ_MAKE_PREMUL
#endif
diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h
index 25c98b4f07e..54b734f8de6 100644
--- a/source/blender/makesdna/DNA_smoke_types.h
+++ b/source/blender/makesdna/DNA_smoke_types.h
@@ -137,6 +137,8 @@ typedef struct SmokeDomainSettings {
/* Smoke uses only one cache from now on (index [0]), but keeping the array for now for reading old files. */
struct PointCache *point_cache[2]; /* definition is in DNA_object_force.h */
struct ListBase ptcaches[2];
+ int point_cache_offset;
+ int pad;
struct EffectorWeights *effector_weights;
int border_collisions; /* How domain border collisions are handled */
float time_scale;
@@ -149,6 +151,10 @@ typedef struct SmokeDomainSettings {
float burning_rate, flame_smoke, flame_vorticity;
float flame_ignition, flame_max_temp;
float flame_smoke_color[3];
+
+ /* display */
+ float display_thickness;
+ int pad2;
} SmokeDomainSettings;
@@ -173,6 +179,7 @@ typedef struct SmokeDomainSettings {
#define MOD_SMOKE_FLOW_INITVELOCITY (1<<2) /* passes particles speed to the smoke */
#define MOD_SMOKE_FLOW_TEXTUREEMIT (1<<3) /* use texture to control emission speed */
#define MOD_SMOKE_FLOW_USE_PART_SIZE (1<<4) /* use specific size for particles instead of closest cell */
+#define MOD_SMOKE_FLOW_USE_PART_TEXCOLOR (1<<5) /* passes particles texture color to the smoke */
typedef struct SmokeFlowSettings {
struct SmokeModifierData *smd; /* for fast RNA access */
diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h
index cb132c1b550..811d78d67c2 100644
--- a/source/blender/makesdna/DNA_sound_types.h
+++ b/source/blender/makesdna/DNA_sound_types.h
@@ -41,7 +41,6 @@
struct Ipo;
struct PackedFile;
-struct SpaceLink;
typedef struct bSound {
ID id;
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index dcb7591a181..c7071d7566c 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -51,28 +51,21 @@
struct ID;
struct Text;
struct Script;
-struct bSound;
-struct ImBuf;
struct Image;
struct Scopes;
struct Histogram;
struct SpaceIpo;
-struct BlendHandle;
struct bNodeTree;
-struct uiBlock;
struct FileList;
struct bGPdata;
struct bDopeSheet;
struct FileSelectParams;
struct FileLayout;
-struct bScreen;
-struct Scene;
struct wmOperator;
struct wmTimer;
struct MovieClip;
struct MovieClipScopes;
struct Mask;
-struct GHash;
struct BLI_mempool;
@@ -298,10 +291,13 @@ typedef enum eSpaceOutliner_Mode {
/* SpaceOops->storeflag */
typedef enum eSpaceOutliner_StoreFlag {
- /* rebuild tree */
+ /* cleanup tree */
SO_TREESTORE_CLEANUP = (1 << 0),
/* if set, it allows redraws. gets set for some allqueue events */
SO_TREESTORE_REDRAW = (1 << 1),
+ /* rebuild the tree, similar to cleanup,
+ * but defer a call to BKE_outliner_treehash_rebuild_from_treestore instead */
+ SO_TREESTORE_REBUILD = (1 << 2),
} eSpaceOutliner_StoreFlag;
/* outliner search flags (SpaceOops->search_flags) */
@@ -328,6 +324,11 @@ typedef struct SpaceIpo {
ListBase ghostCurves; /* sampled snapshots of F-Curves used as in-session guides */
+ struct Object *backdrop_camera; /* the view from this camera is used to draw the backdrop */
+ float backdrop_offset[2]; /* offset of the backdrop */
+ float backdrop_zoom; /* zoom factor of the backdrop */
+ float backdrop_opacity; /* opacity of the backdrop */
+
short mode; /* mode for the Graph editor (eGraphEdit_Mode) */
short autosnap; /* time-transform autosnapping settings for Graph editor (eAnimEdit_AutoSnap in DNA_action_types.h) */
int flag; /* settings for Graph editor (eGraphEdit_Flag) */
@@ -372,6 +373,7 @@ typedef enum eGraphEdit_Flag {
/* normalize curves on display */
SIPO_NORMALIZE = (1 << 14),
SIPO_NORMALIZE_FREEZE = (1 << 15),
+ SIPO_DRAW_BACKDROP = (1 << 16),
} eGraphEdit_Flag;
/* SpaceIpo->mode (Graph Editor Mode) */
@@ -509,6 +511,9 @@ typedef struct SpaceSeq {
struct bGPdata *gpd; /* grease-pencil data */
struct SequencerScopes scopes; /* different scoped displayed in space */
+
+ char multiview_eye; /* multiview current eye - for internal use */
+ char pad2[7];
} SpaceSeq;
@@ -540,6 +545,8 @@ typedef enum eSpaceSeq_Flag {
SEQ_ALL_WAVEFORMS = (1 << 7), /* draw all waveforms */
SEQ_NO_WAVEFORMS = (1 << 8), /* draw no waveforms */
SEQ_SHOW_SAFE_CENTER = (1 << 9),
+ SEQ_SHOW_METADATA = (1 << 10),
+ SEQ_NO_INFO = (1 << 11), /* do not draw names on strips */
} eSpaceSeq_Flag;
/* sseq->view */
@@ -560,8 +567,7 @@ typedef enum eSpaceSeq_Proxy_RenderSize {
SEQ_PROXY_RENDER_SIZE_FULL = 100
} eSpaceSeq_Proxy_RenderSize;
-typedef struct MaskSpaceInfo
-{
+typedef struct MaskSpaceInfo {
/* **** mask editing **** */
struct Mask *mask;
/* draw options */
@@ -597,6 +603,8 @@ typedef struct FileSelectParams {
int active_file;
int sel_first;
int sel_last;
+ unsigned short thumbnail_size;
+ short pad;
/* short */
short type; /* XXXXX for now store type here, should be moved to the operator */
@@ -695,17 +703,19 @@ typedef enum eFileSel_Action {
/* sfile->params->flag and simasel->flag */
typedef enum eFileSel_Params_Flag {
- FILE_SHOWSHORT = (1 << 0),
- FILE_RELPATH = (1 << 1), /* was FILE_STRINGCODE */
- FILE_LINK = (1 << 2),
- FILE_HIDE_DOT = (1 << 3),
- FILE_AUTOSELECT = (1 << 4),
- FILE_ACTIVELAY = (1 << 5),
-/* FILE_ATCURSOR = (1 << 6), */ /* deprecated */
- FILE_DIRSEL_ONLY = (1 << 7),
- FILE_FILTER = (1 << 8),
- FILE_BOOKMARKS = (1 << 9),
- FILE_GROUP_INSTANCE = (1 << 10),
+ FILE_SHOWSHORT = (1 << 0),
+ FILE_RELPATH = (1 << 1), /* was FILE_STRINGCODE */
+ FILE_LINK = (1 << 2),
+ FILE_HIDE_DOT = (1 << 3),
+ FILE_AUTOSELECT = (1 << 4),
+ FILE_ACTIVELAY = (1 << 5),
+/* FILE_ATCURSOR = (1 << 6), */ /* deprecated */
+ FILE_DIRSEL_ONLY = (1 << 7),
+ FILE_FILTER = (1 << 8),
+ FILE_BOOKMARKS = (1 << 9),
+ FILE_GROUP_INSTANCE = (1 << 10),
+ FILE_COLLAPSE_IMAGES = (1 << 11),
+ FILE_COLLAPSE_IMAGES_TMP = (1 << 12),
} eFileSel_Params_Flag;
@@ -719,7 +729,7 @@ typedef enum eFileSel_File_Types {
FILE_TYPE_FTFONT = (1 << 7),
FILE_TYPE_SOUND = (1 << 8),
FILE_TYPE_TEXT = (1 << 9),
- FILE_TYPE_MOVIE_ICON = (1 << 10), /* movie file that preview can't load */
+ /* 1 << 10 was FILE_TYPE_MOVIE_ICON, got rid of this so free slot for future type... */
FILE_TYPE_FOLDER = (1 << 11), /* represents folders for filtering */
FILE_TYPE_BTX = (1 << 12),
FILE_TYPE_COLLADA = (1 << 13),
@@ -733,6 +743,8 @@ typedef enum eDirEntry_SelectFlag {
FILE_SEL_HIGHLIGHTED = (1 << 2),
FILE_SEL_SELECTED = (1 << 3),
FILE_SEL_EDITING = (1 << 4),
+ FILE_SEL_COLLAPSED = (1 << 5),
+ FILE_SEL_PLAYING = (1 << 6),
} eDirEntry_SelectFlag;
/* Image/UV Editor ======================================== */
@@ -841,6 +853,7 @@ typedef enum eSpaceImage_Flag {
SI_COLOR_CORRECTION = (1 << 24),
SI_NO_DRAW_TEXPAINT = (1 << 25),
+ SI_DRAW_METADATA = (1 << 26)
} eSpaceImage_Flag;
/* Text Editor ============================================ */
diff --git a/source/blender/makesdna/DNA_strands_types.h b/source/blender/makesdna/DNA_strands_types.h
new file mode 100644
index 00000000000..c5d58e3439a
--- /dev/null
+++ b/source/blender/makesdna/DNA_strands_types.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file DNA_strands_types.h
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_STRANDS_TYPES_H__
+#define __DNA_STRANDS_TYPES_H__
+
+#include "DNA_defs.h"
+
+#include "DNA_meshdata_types.h"
+
+typedef struct StrandsVertex {
+ float co[3];
+ float base[3]; /* base shape, defining deformation for children */
+ float time;
+ float weight;
+
+ /* utility data */
+ float nor[3]; /* normals (edge directions) */
+} StrandsVertex;
+
+typedef struct StrandsMotionState {
+ float co[3];
+ float vel[3];
+
+ /* utility data */
+ float nor[3]; /* normals (edge directions) */
+} StrandsMotionState;
+
+typedef struct StrandsCurve {
+ int numverts;
+ float root_matrix[3][3];
+
+ MSurfaceSample msurf;
+} StrandsCurve;
+
+typedef struct Strands {
+ StrandsCurve *curves;
+ StrandsVertex *verts;
+ int totcurves, totverts;
+
+ /* optional */
+ StrandsMotionState *state;
+} Strands;
+
+
+typedef struct StrandsChildCurve {
+ int numverts;
+ float root_matrix[4][4];
+ int parents[4];
+ float parent_weights[4];
+ float cutoff; /* shortens the curve if 0 <= cutoff < numverts */
+} StrandsChildCurve;
+
+typedef struct StrandsChildCurveUV {
+ float uv[2];
+} StrandsChildCurveUV;
+
+typedef struct StrandsChildCurveVCol {
+ float vcol[3];
+} StrandsChildCurveVCol;
+
+typedef struct StrandsChildVertex {
+ float co[3];
+ float base[3]; /* undeformed shape */
+ float time;
+
+ /* utility data */
+ float nor[3]; /* normals (edge directions) */
+} StrandsChildVertex;
+
+typedef struct StrandsChildren {
+ StrandsChildCurve *curves;
+ StrandsChildCurveUV *curve_uvs;
+ StrandsChildCurveVCol *curve_vcols;
+ StrandsChildVertex *verts;
+ int totcurves, totverts;
+ int numuv, numvcol; /* number of uv/vcol per curve */
+} StrandsChildren;
+
+#endif /* __DNA_STRANDS_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index b6023a3bf91..a1b736124a2 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -85,7 +85,7 @@ typedef struct MTex {
/* particles */
float timefac, lengthfac, clumpfac, dampfac;
float kinkfac, kinkampfac, roughfac, padensfac, gravityfac;
- float lifefac, sizefac, ivelfac, fieldfac;
+ float lifefac, sizefac, ivelfac, fieldfac, pacolfac, pad2;
float shapefac;
char shapekey[64]; /* MAX_NAME */
@@ -597,9 +597,11 @@ enum {
#define TEX_PD_COLOR_PARTAGE 1
#define TEX_PD_COLOR_PARTSPEED 2
#define TEX_PD_COLOR_PARTVEL 3
+#define TEX_PD_COLOR_PARTTEX 4
#define POINT_DATA_VEL 1
#define POINT_DATA_LIFE 2
+#define POINT_DATA_COLOR 3
/******************** Voxel Data *****************************/
/* flag */
diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h
index c471cb26892..9888b735b8b 100644
--- a/source/blender/makesdna/DNA_tracking_types.h
+++ b/source/blender/makesdna/DNA_tracking_types.h
@@ -43,11 +43,9 @@
/* match-moving data */
struct bGPdata;
-struct ImBuf;
struct Image;
struct MovieReconstructedCamera;
struct MovieTrackingCamera;
-struct MovieTrackingBundle;
struct MovieTrackingMarker;
struct MovieTrackingTrack;
struct MovieTracking;
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index afa1f03a8ca..af0c3bfbf0e 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -338,6 +338,9 @@ typedef struct ThemeSpace {
char paint_curve_pivot[4];
char paint_curve_handle[4];
+
+ char metadatabg[4];
+ char metadatatext[4];
} ThemeSpace;
@@ -500,7 +503,10 @@ typedef struct UserDef {
char ipo_new; /* interpolation mode for newly added F-Curves */
char keyhandles_new; /* handle types for newly added keyframes */
char gpu_select_method;
- char pad1;
+ char view_frame_type;
+
+ int view_frame_keyframes; /* number of keyframes to zoom around current frame */
+ float view_frame_seconds; /* seconds to zoom around current frame */
short scrcastfps; /* frame rate for screencast to be played back */
short scrcastwait; /* milliseconds between screencast snapshots */
@@ -683,6 +689,13 @@ typedef enum eAutokey_Mode {
AUTOKEY_MODE_EDITKEYS = 5
} eAutokey_Mode;
+/* Zoom to frame mode */
+typedef enum eZoomFrame_Mode {
+ ZOOM_FRAME_MODE_KEEP_RANGE = 0,
+ ZOOM_FRAME_MODE_SECONDS = 1,
+ ZOOM_FRAME_MODE_KEYFRAMES = 2
+} eZoomFrame_Mode;
+
/* Auto-Keying flag
* U.autokey_flag (not strictly used when autokeying only - is also used when keyframing these days)
* note: AUTOKEY_FLAG_* is used with a macro, search for lines like IS_AUTOKEY_FLAG(INSERTAVAIL)
diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h
index a7921be44d5..6f2e347c84d 100644
--- a/source/blender/makesdna/DNA_view2d_types.h
+++ b/source/blender/makesdna/DNA_view2d_types.h
@@ -43,7 +43,7 @@ typedef struct View2D {
rcti mask; /* mask - region (in screenspace) within which 'cur' can be viewed */
float min[2], max[2]; /* min/max sizes of 'cur' rect (only when keepzoom not set) */
- float minzoom, maxzoom; /* self explanatory. allowable zoom factor range (only when keepzoom set) */
+ float minzoom, maxzoom; /* allowable zoom factor range (only when (keepzoom & V2D_LIMITZOOM)) is set */
short scroll; /* scroll - scrollbars to display (bitflag) */
short scroll_ui; /* scroll_ui - temp settings used for UI drawing of scrollers */
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index d4d1bcda2b3..6841393ab98 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -35,9 +35,7 @@
struct ViewDepths;
struct Object;
struct Image;
-struct Tex;
struct SpaceLink;
-struct Base;
struct BoundBox;
struct MovieClip;
struct MovieClipUser;
@@ -220,8 +218,10 @@ typedef struct View3D {
/* drawflags, denoting state */
char zbuf, transp, xray;
+ char multiview_eye; /* multiview current eye - for internal use */
+
/* built-in shader effects (eGPUFXFlags) */
- char pad3[5];
+ char pad3[4];
/* note, 'fx_settings.dof' is currently _not_ allocated,
* instead set (temporarily) from camera */
@@ -232,9 +232,22 @@ typedef struct View3D {
/* XXX deprecated? */
struct bGPdata *gpd DNA_DEPRECATED; /* Grease-Pencil Data (annotation layers) */
+
+ /* multiview - stereo 3d */
+ short stereo3d_flag;
+ char stereo3d_camera;
+ char pad4;
+ float stereo3d_convergence_factor;
+ float stereo3d_volume_alpha;
+ float stereo3d_convergence_alpha;
} View3D;
+/* View3D->stereo_flag (short) */
+#define V3D_S3D_DISPCAMERAS (1 << 0)
+#define V3D_S3D_DISPPLANE (1 << 1)
+#define V3D_S3D_DISPVOLUME (1 << 2)
+
/* View3D->flag (short) */
/*#define V3D_DISPIMAGE 1*/ /*UNUSED*/
#define V3D_DISPBGPICS 2
@@ -379,6 +392,9 @@ enum {
#define RV3D_CAMZOOM_MIN -30
#define RV3D_CAMZOOM_MAX 600
-#endif
+/* #BKE_screen_view3d_zoom_to_fac() values above */
+#define RV3D_CAMZOOM_MIN_FACTOR 0.1657359312880714853f
+#define RV3D_CAMZOOM_MAX_FACTOR 44.9852813742385702928f
+#endif
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 7f5f3ccddca..9c089ce0021 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -33,6 +33,7 @@
#include "DNA_listBase.h"
#include "DNA_vec_types.h"
+#include "DNA_userdef_types.h"
#include "DNA_ID.h"
@@ -49,16 +50,14 @@ struct wmKeyConfig;
/* forwards */
struct bContext;
-struct wmLocal;
struct bScreen;
-struct uiBlock;
struct wmSubWindow;
struct wmTimer;
-struct StructRNA;
struct PointerRNA;
struct ReportList;
struct Report;
struct uiLayout;
+struct Stereo3dFormat;
#define OP_MAX_TYPENAME 64
#define KMAP_MAX_NAME 64
@@ -210,7 +209,7 @@ typedef struct wmWindow {
struct wmIMEData *ime_data;
int drawmethod, drawfail; /* internal for wm_draw.c only */
- void *drawdata; /* internal for wm_draw.c only */
+ ListBase drawdata; /* internal for wm_draw.c only */
ListBase queue; /* all events (ghost level events were handled) */
ListBase handlers; /* window+screen handlers, handled last */
@@ -218,6 +217,8 @@ typedef struct wmWindow {
ListBase subwindows; /* opengl stuff for sub windows, see notes in wm_subwindow.c */
ListBase gesture; /* gesture stuff */
+
+ struct Stereo3dFormat *stereo3d_format; /* properties for stereoscopic displays */
} wmWindow;
#ifdef ime_data
@@ -390,10 +391,16 @@ enum {
/* wmOperator flag */
enum {
- OP_GRAB_POINTER = (1 << 0),
/* low level flag so exec() operators can tell if they were invoked, use with care.
* typically this shouldn't make any difference, but it rare cases its needed (see smooth-view) */
- OP_IS_INVOKE = (1 << 1),
+ OP_IS_INVOKE = (1 << 0),
+
+ /* When the cursor is grabbed */
+ OP_IS_MODAL_GRAB_CURSOR = (1 << 1),
+
+ /* allow modal operators to have the region under the cursor for their context
+ * (the regiontype is maintained to prevent errors) */
+ OP_IS_MODAL_CURSOR_REGION = (1 << 2),
};
#endif /* __DNA_WINDOWMANAGER_TYPES_H__ */
diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
index 317141b14e3..be097c0e51e 100644
--- a/source/blender/makesdna/intern/CMakeLists.txt
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -74,7 +74,7 @@ set(INC_SYS
set(SRC
dna_genfile.c
- dna.c
+ ${CMAKE_CURRENT_BINARY_DIR}/dna.c
${SRC_DNA_INC}
)
@@ -97,6 +97,7 @@ set(SRC
../../blenlib/intern/BLI_mempool.c
../../blenlib/intern/listbase.c
../../blenlib/intern/BLI_ghash.c
+ ../../blenlib/intern/hash_mm2a.c
)
blender_add_lib(bf_dna_blenlib "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 4615a1ce9e4..389e22b2a0c 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -525,7 +525,7 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap)
for (nr = 0; nr < sdna->nr_structs; nr++) {
sp = sdna->structs[nr];
- BLI_ghash_insert(sdna->structs_map, (void *)sdna->types[sp[0]], (void *)(nr + 1));
+ BLI_ghash_insert(sdna->structs_map, sdna->types[sp[0]], SET_INT_IN_POINTER(nr + 1));
}
#endif
}
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 8e89d325a87..6333db331fb 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -137,6 +137,8 @@ static const char *includefiles[] = {
"DNA_rigidbody_types.h",
"DNA_freestyle_types.h",
"DNA_linestyle_types.h",
+ "DNA_cache_library_types.h",
+ "DNA_strands_types.h",
/* empty string to indicate end of includefiles */
""
@@ -540,6 +542,11 @@ static void *read_file_data(char *filename, int *r_len)
*r_len = ftell(fp);
fseek(fp, 0L, SEEK_SET);
+ if (*r_len == -1) {
+ fclose(fp);
+ return NULL;
+ }
+
data = MEM_mallocN(*r_len, "read_file_data");
if (!data) {
*r_len = -1;
@@ -1289,4 +1296,6 @@ int main(int argc, char **argv)
#include "DNA_rigidbody_types.h"
#include "DNA_freestyle_types.h"
#include "DNA_linestyle_types.h"
+#include "DNA_cache_library_types.h"
+#include "DNA_strands_types.h"
/* end of list */
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 18238ab3215..ae09f5f2699 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -95,6 +95,11 @@ extern StructRNA RNA_Brush;
extern StructRNA RNA_BrushTextureSlot;
extern StructRNA RNA_BuildModifier;
extern StructRNA RNA_MeshCacheModifier;
+extern StructRNA RNA_CacheArchiveInfo;
+extern StructRNA RNA_CacheArchiveInfoNode;
+extern StructRNA RNA_CacheItem;
+extern StructRNA RNA_CacheLibrary;
+extern StructRNA RNA_CacheLibraryModifier;
extern StructRNA RNA_Camera;
extern StructRNA RNA_CastModifier;
extern StructRNA RNA_ChildOfConstraint;
@@ -172,6 +177,7 @@ extern StructRNA RNA_CompositorNodeSepYCCA;
extern StructRNA RNA_CompositorNodeSepYUVA;
extern StructRNA RNA_CompositorNodeSetAlpha;
extern StructRNA RNA_CompositorNodeSplitViewer;
+extern StructRNA RNA_CompositorNodeSwitchView;
extern StructRNA RNA_CompositorNodeTexture;
extern StructRNA RNA_CompositorNodeTime;
extern StructRNA RNA_CompositorNodeTonemap;
@@ -202,6 +208,7 @@ extern StructRNA RNA_DampedTrackConstraint;
extern StructRNA RNA_DataTransferModifier;
extern StructRNA RNA_DecimateModifier;
extern StructRNA RNA_DelaySensor;
+extern StructRNA RNA_CorrectiveSmoothModifier;
extern StructRNA RNA_DisplaceModifier;
extern StructRNA RNA_DisplaySafeAreas;
extern StructRNA RNA_DistortedNoiseTexture;
@@ -279,6 +286,7 @@ extern StructRNA RNA_IKParam;
extern StructRNA RNA_Image;
extern StructRNA RNA_ImageFormatSettings;
extern StructRNA RNA_ImagePaint;
+extern StructRNA RNA_ImagePreview;
extern StructRNA RNA_ImageSequence;
extern StructRNA RNA_ImageTexture;
extern StructRNA RNA_ImageUser;
@@ -566,6 +574,7 @@ extern StructRNA RNA_SpeedControlSequence;
extern StructRNA RNA_Spline;
extern StructRNA RNA_SplineIKConstraint;
extern StructRNA RNA_SpotLamp;
+extern StructRNA RNA_Stereo3dDisplay;
extern StructRNA RNA_StretchToConstraint;
extern StructRNA RNA_StringProperty;
extern StructRNA RNA_Struct;
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index 4d836601ac4..ea94056217c 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -56,6 +56,7 @@ extern EnumPropertyItem mesh_delimit_mode_items[];
extern EnumPropertyItem space_type_items[];
extern EnumPropertyItem region_type_items[];
extern EnumPropertyItem modifier_type_items[];
+extern EnumPropertyItem cache_modifier_type_items[];
extern EnumPropertyItem constraint_type_items[];
extern EnumPropertyItem boidrule_type_items[];
extern EnumPropertyItem sequence_modifier_type_items[];
@@ -72,6 +73,13 @@ extern EnumPropertyItem normal_space_items[];
extern EnumPropertyItem normal_swizzle_items[];
extern EnumPropertyItem bake_save_mode_items[];
+extern EnumPropertyItem views_format_items[];
+extern EnumPropertyItem views_format_multilayer_items[];
+extern EnumPropertyItem views_format_multiview_items[];
+extern EnumPropertyItem stereo3d_display_items[];
+extern EnumPropertyItem stereo3d_anaglyph_type_items[];
+extern EnumPropertyItem stereo3d_interlace_type_items[];
+
extern EnumPropertyItem exr_codec_items[];
extern EnumPropertyItem color_sets_items[];
@@ -102,6 +110,7 @@ extern EnumPropertyItem operator_return_items[];
extern EnumPropertyItem brush_sculpt_tool_items[];
extern EnumPropertyItem brush_vertex_tool_items[];
extern EnumPropertyItem brush_image_tool_items[];
+extern EnumPropertyItem brush_hair_tool_items[];
extern EnumPropertyItem symmetrize_direction_items[];
@@ -174,6 +183,9 @@ extern EnumPropertyItem prop_dynamicpaint_type_items[];
extern EnumPropertyItem clip_editor_mode_items[];
+extern EnumPropertyItem cache_library_data_type_items[];
+extern EnumPropertyItem cache_library_read_result_items[];
+
extern EnumPropertyItem icon_items[];
extern EnumPropertyItem uilist_layout_type_items[];
@@ -213,5 +225,7 @@ EnumPropertyItem *RNA_movieclip_itemf(struct bContext *C, struct PointerRNA *ptr
EnumPropertyItem *RNA_movieclip_local_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
EnumPropertyItem *RNA_mask_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
EnumPropertyItem *RNA_mask_local_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
+EnumPropertyItem *RNA_cachelibrary_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
+EnumPropertyItem *RNA_cachelibrary_local_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
#endif /* __RNA_ENUM_TYPES_H__ */
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index a9c0f591858..0c99769a390 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -37,10 +37,8 @@ extern "C" {
struct ParameterList;
struct FunctionRNA;
struct PropertyRNA;
-struct EnumPropertyRNA;
struct StructRNA;
struct BlenderRNA;
-struct IDProperty;
struct bContext;
struct Main;
struct ReportList;
diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript
index e366c9bbe2b..f8eb2e1807c 100644
--- a/source/blender/makesrna/SConscript
+++ b/source/blender/makesrna/SConscript
@@ -47,6 +47,7 @@ incs = [
'../blenkernel',
'../blenlib',
'../bmesh',
+ '../depsgraph',
'../editors/include',
'../gpu',
'../ikplugin',
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index ec82fcafe76..cd3f63f317c 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -38,6 +38,7 @@ set(DEFSRC
rna_armature.c
rna_boid.c
rna_brush.c
+ rna_cache_library.c
rna_camera.c
rna_cloth.c
rna_color.c
@@ -45,6 +46,7 @@ set(DEFSRC
rna_context.c
rna_controller.c
rna_curve.c
+ rna_depsgraph.c
rna_dynamicpaint.c
rna_fcurve.c
rna_fluidsim.c
@@ -59,6 +61,7 @@ set(DEFSRC
rna_mask.c
rna_material.c
rna_mesh.c
+ rna_mesh_sample.c
rna_meta.c
rna_modifier.c
rna_movieclip.c
@@ -67,6 +70,7 @@ set(DEFSRC
rna_object.c
rna_object_force.c
rna_packedfile.c
+ rna_palette.c
rna_particle.c
rna_pose.c
rna_property.c
@@ -82,6 +86,7 @@ set(DEFSRC
rna_sound.c
rna_space.c
rna_speaker.c
+ rna_strands.c
rna_test.c
rna_text.c
rna_texture.c
@@ -124,6 +129,9 @@ set(APISRC
)
string(REGEX REPLACE "rna_([a-zA-Z0-9_-]*).c" "${CMAKE_CURRENT_BINARY_DIR}/rna_\\1_gen.c" GENSRC "${DEFSRC}")
+list(APPEND GENSRC
+ "${CMAKE_CURRENT_BINARY_DIR}/rna_prototypes_gen.h"
+)
set_source_files_properties(${GENSRC} PROPERTIES GENERATED TRUE)
# --------------------------
@@ -303,6 +311,7 @@ blender_include_dirs(
../../blenlib
../../bmesh
../../blenfont
+ ../../depsgraph
../../gpu
../../imbuf
../../ikplugin
diff --git a/source/blender/makesrna/intern/SConscript b/source/blender/makesrna/intern/SConscript
index 3d190fc6a13..afa4ab3a67d 100644
--- a/source/blender/makesrna/intern/SConscript
+++ b/source/blender/makesrna/intern/SConscript
@@ -66,6 +66,7 @@ incs = [
'../../blenkernel',
'../../blenlib',
'../../bmesh',
+ '../../depsgraph',
'../../editors/include',
'../../gpu',
'../../ikplugin',
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 14c39862467..0c2082c9597 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -936,7 +936,7 @@ static char *rna_def_property_set_func(FILE *f, StructRNA *srna, PropertyRNA *pr
if (dp->dnaarraylength == 1) {
if (prop->type == PROP_BOOLEAN && dp->booleanbit) {
- fprintf(f, " if (%svalues[i]) data->%s |= (%d<<i);\n",
+ fprintf(f, " if (%svalues[i]) data->%s |= (%du << i);\n",
(dp->booleannegative) ? "!" : "", dp->dnaname, dp->booleanbit);
fprintf(f, " else data->%s &= ~(%du << i);\n", dp->dnaname, dp->booleanbit);
}
@@ -2027,7 +2027,8 @@ static void rna_def_struct_function_call_impl_cpp(FILE *f, StructRNA *srna, Func
if ((func->flag & FUNC_NO_SELF) == 0) {
WRITE_COMMA;
- if (dsrna->dnaname) fprintf(f, "(::%s *) this->ptr.data", dsrna->dnaname);
+ if (dsrna->dnafromprop) fprintf(f, "(::%s *) this->ptr.data", dsrna->dnafromname);
+ else if (dsrna->dnaname) fprintf(f, "(::%s *) this->ptr.data", dsrna->dnaname);
else fprintf(f, "(::%s *) this->ptr.data", srna->identifier);
}
else if (func->flag & FUNC_USE_SELF_TYPE) {
@@ -2222,7 +2223,8 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
}
if ((func->flag & FUNC_NO_SELF) == 0) {
- if (dsrna->dnaname) fprintf(f, "\tstruct %s *_self;\n", dsrna->dnaname);
+ if (dsrna->dnafromprop) fprintf(f, "\tstruct %s *_self;\n", dsrna->dnafromname);
+ else if (dsrna->dnaname) fprintf(f, "\tstruct %s *_self;\n", dsrna->dnaname);
else fprintf(f, "\tstruct %s *_self;\n", srna->identifier);
}
else if (func->flag & FUNC_USE_SELF_TYPE) {
@@ -2274,7 +2276,8 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
}
if ((func->flag & FUNC_NO_SELF) == 0) {
- if (dsrna->dnaname) fprintf(f, "\t_self = (struct %s *)_ptr->data;\n", dsrna->dnaname);
+ if (dsrna->dnafromprop) fprintf(f, "\t_self = (struct %s *)_ptr->data;\n", dsrna->dnafromname);
+ else if (dsrna->dnaname) fprintf(f, "\t_self = (struct %s *)_ptr->data;\n", dsrna->dnaname);
else fprintf(f, "\t_self = (struct %s *)_ptr->data;\n", srna->identifier);
}
else if (func->flag & FUNC_USE_SELF_TYPE) {
@@ -2675,7 +2678,8 @@ static void rna_generate_static_parameter_prototypes(FILE *f, StructRNA *srna, F
if ((func->flag & FUNC_NO_SELF) == 0) {
if (!first) fprintf(f, ", ");
- if (dsrna->dnaname) fprintf(f, "struct %s *_self", dsrna->dnaname);
+ if (dsrna->dnafromprop) fprintf(f, "struct %s *_self", dsrna->dnafromname);
+ else if (dsrna->dnaname) fprintf(f, "struct %s *_self", dsrna->dnaname);
else fprintf(f, "struct %s *_self", srna->identifier);
first = 0;
}
@@ -3283,12 +3287,14 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_boid.c", NULL, RNA_def_boid},
{"rna_brush.c", NULL, RNA_def_brush},
{"rna_camera.c", "rna_camera_api.c", RNA_def_camera},
+ {"rna_cache_library.c", NULL, RNA_def_cache_library},
{"rna_cloth.c", NULL, RNA_def_cloth},
{"rna_color.c", NULL, RNA_def_color},
{"rna_constraint.c", NULL, RNA_def_constraint},
{"rna_context.c", NULL, RNA_def_context},
{"rna_controller.c", "rna_controller_api.c", RNA_def_controller},
{"rna_curve.c", "rna_curve_api.c", RNA_def_curve},
+ {"rna_depsgraph.c", NULL, RNA_def_depsgraph},
{"rna_dynamicpaint.c", NULL, RNA_def_dynamic_paint},
{"rna_fcurve.c", "rna_fcurve_api.c", RNA_def_fcurve},
{"rna_fluidsim.c", NULL, RNA_def_fluidsim},
@@ -3302,6 +3308,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_main.c", "rna_main_api.c", RNA_def_main},
{"rna_material.c", "rna_material_api.c", RNA_def_material},
{"rna_mesh.c", "rna_mesh_api.c", RNA_def_mesh},
+ {"rna_mesh_sample.c", NULL, RNA_def_mesh_sample},
{"rna_meta.c", "rna_meta_api.c", RNA_def_meta},
{"rna_modifier.c", NULL, RNA_def_modifier},
{"rna_nla.c", NULL, RNA_def_nla},
@@ -3309,6 +3316,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_object.c", "rna_object_api.c", RNA_def_object},
{"rna_object_force.c", NULL, RNA_def_object_force},
{"rna_packedfile.c", NULL, RNA_def_packedfile},
+ {"rna_palette.c", NULL, RNA_def_palette},
{"rna_particle.c", NULL, RNA_def_particle},
{"rna_pose.c", "rna_pose_api.c", RNA_def_pose},
{"rna_property.c", NULL, RNA_def_gameproperty},
@@ -3322,6 +3330,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_smoke.c", NULL, RNA_def_smoke},
{"rna_space.c", "rna_space_api.c", RNA_def_space},
{"rna_speaker.c", NULL, RNA_def_speaker},
+ {"rna_strands.c", NULL, RNA_def_strands},
{"rna_test.c", NULL, RNA_def_test},
{"rna_text.c", "rna_text_api.c", RNA_def_text},
{"rna_timeline.c", NULL, RNA_def_timeline_marker},
@@ -3372,7 +3381,9 @@ static void rna_generate(BlenderRNA *brna, FILE *f, const char *filename, const
fprintf(f, "#include \"RNA_types.h\"\n");
fprintf(f, "#include \"rna_internal.h\"\n\n");
- rna_generate_prototypes(brna, f);
+
+ /* include the generated prototypes header */
+ fprintf(f, "#include \"rna_prototypes_gen.h\"\n\n");
fprintf(f, "#include \"%s\"\n", filename);
if (api_filename)
@@ -3760,7 +3771,7 @@ static const char *cpp_classes = ""
"\n"
"class DefaultCollectionFunctions {\n"
"public:\n"
-" DefaultCollectionFunctions(const PointerRNA &p) {}\n"
+" DefaultCollectionFunctions(const PointerRNA & /*p*/) {}\n"
"};\n"
"\n"
"\n";
@@ -3967,6 +3978,26 @@ static int rna_preprocess(const char *outfile)
status = (DefRNA.error != 0);
+ /* create rna prototype header file */
+ strcpy(deffile, outfile);
+ strcat(deffile, "rna_prototypes_gen.h");
+ if (status) {
+ make_bad_file(deffile, __LINE__);
+ }
+ file = fopen(deffile, "w");
+ if (!file) {
+ fprintf(stderr, "Unable to open file: %s\n", deffile);
+ status = 1;
+ }
+ else {
+ fprintf(file,
+ "/* Automatically generated function declarations for the Data API.\n"
+ " * Do not edit manually, changes will be overwritten. */\n\n");
+ rna_generate_prototypes(brna, file);
+ fclose(file);
+ status = (DefRNA.error != 0);
+ }
+
/* create rna_gen_*.c files */
for (i = 0; PROCESS_ITEMS[i].filename; i++) {
strcpy(deffile, outfile);
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 009e3799c49..d29450aa320 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -34,6 +34,8 @@
#include "BLI_utildefines.h"
+#include "BKE_icons.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -50,6 +52,7 @@ EnumPropertyItem id_type_items[] = {
{ID_AR, "ARMATURE", ICON_ARMATURE_DATA, "Armature", ""},
{ID_BR, "BRUSH", ICON_BRUSH_DATA, "Brush", ""},
{ID_CA, "CAMERA", ICON_CAMERA_DATA, "Camera", ""},
+ {ID_CL, "CACHELIBRARY", ICON_PHYSICS, "Cache Library", ""},
{ID_CU, "CURVE", ICON_CURVE_DATA, "Curve", ""},
{ID_VF, "FONT", ICON_FONT_DATA, "Font", ""},
{ID_GD, "GREASEPENCIL", ICON_GREASEPENCIL, "Grease Pencil", ""},
@@ -130,6 +133,7 @@ short RNA_type_to_ID_code(StructRNA *type)
if (RNA_struct_is_a(type, &RNA_Action)) return ID_AC;
if (RNA_struct_is_a(type, &RNA_Armature)) return ID_AR;
if (RNA_struct_is_a(type, &RNA_Brush)) return ID_BR;
+ if (RNA_struct_is_a(type, &RNA_CacheLibrary)) return ID_CL;
if (RNA_struct_is_a(type, &RNA_Camera)) return ID_CA;
if (RNA_struct_is_a(type, &RNA_Curve)) return ID_CU;
if (RNA_struct_is_a(type, &RNA_GreasePencil)) return ID_GD;
@@ -170,6 +174,7 @@ StructRNA *ID_code_to_RNA_type(short idcode)
case ID_AR: return &RNA_Armature;
case ID_BR: return &RNA_Brush;
case ID_CA: return &RNA_Camera;
+ case ID_CL: return &RNA_CacheLibrary;
case ID_CU: return &RNA_Curve;
case ID_GD: return &RNA_GreasePencil;
case ID_GR: return &RNA_Group;
@@ -406,6 +411,183 @@ static void rna_Library_filepath_set(PointerRNA *ptr, const char *value)
BKE_library_filepath_set(lib, value);
}
+/* ***** ImagePreview ***** */
+
+static void rna_ImagePreview_is_custom_set(PointerRNA *ptr, int value, enum eIconSizes size)
+{
+ ID *id = ptr->id.data;
+ PreviewImage *prv_img = (PreviewImage *)ptr->data;
+
+ if (id != NULL) {
+ BLI_assert(prv_img == BKE_previewimg_id_ensure(id));
+ }
+
+ if ((value && (prv_img->flag[size] & PRV_USER_EDITED)) || (!value && !(prv_img->flag[size] & PRV_USER_EDITED))) {
+ return;
+ }
+
+ if (value)
+ prv_img->flag[size] |= PRV_USER_EDITED;
+ else
+ prv_img->flag[size] &= ~PRV_USER_EDITED;
+
+ prv_img->flag[size] |= PRV_CHANGED;
+
+ BKE_previewimg_clear_single(prv_img, size);
+}
+
+static void rna_ImagePreview_size_get(PointerRNA *ptr, int *values, enum eIconSizes size)
+{
+ ID *id = (ID *)ptr->id.data;
+ PreviewImage *prv_img = (PreviewImage *)ptr->data;
+
+ if (id != NULL) {
+ BLI_assert(prv_img == BKE_previewimg_id_ensure(id));
+ }
+
+ BKE_previewimg_ensure(prv_img, size);
+
+ values[0] = prv_img->w[size];
+ values[1] = prv_img->h[size];
+}
+
+static void rna_ImagePreview_size_set(PointerRNA *ptr, const int *values, enum eIconSizes size)
+{
+ ID *id = (ID *)ptr->id.data;
+ PreviewImage *prv_img = (PreviewImage *)ptr->data;
+
+ if (id != NULL) {
+ BLI_assert(prv_img == BKE_previewimg_id_ensure(id));
+ }
+
+ BKE_previewimg_ensure(prv_img, size);
+
+ if (values[0] && values[1]) {
+ prv_img->rect[size] = MEM_callocN(values[0] * values[1] * sizeof(unsigned int), "prv_rect");
+ }
+
+ prv_img->w[size] = values[0];
+ prv_img->h[size] = values[1];
+
+ prv_img->flag[size] |= (PRV_CHANGED | PRV_USER_EDITED);
+}
+
+static int rna_ImagePreview_pixels_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION], enum eIconSizes size)
+{
+ ID *id = ptr->id.data;
+ PreviewImage *prv_img = (PreviewImage *)ptr->data;
+
+ if (id != NULL) {
+ BLI_assert(prv_img == BKE_previewimg_id_ensure(id));
+ }
+
+ BKE_previewimg_ensure(prv_img, size);
+
+ length[0] = prv_img->w[size] * prv_img->h[size];
+
+ return length[0];
+}
+
+static void rna_ImagePreview_pixels_get(PointerRNA *ptr, int *values, enum eIconSizes size)
+{
+ ID *id = ptr->id.data;
+ PreviewImage *prv_img = (PreviewImage *)ptr->data;
+
+ if (id != NULL) {
+ BLI_assert(prv_img == BKE_previewimg_id_ensure(id));
+ }
+
+ BKE_previewimg_ensure(prv_img, size);
+
+ memcpy(values, prv_img->rect[size], prv_img->w[size] * prv_img->h[size] * sizeof(unsigned int));
+}
+
+static void rna_ImagePreview_pixels_set(PointerRNA *ptr, const int *values, enum eIconSizes size)
+{
+ ID *id = ptr->id.data;
+ PreviewImage *prv_img = (PreviewImage *)ptr->data;
+
+ if (id != NULL) {
+ BLI_assert(prv_img == BKE_previewimg_id_ensure(id));
+ }
+
+ memcpy(prv_img->rect[size], values, prv_img->w[size] * prv_img->h[size] * sizeof(unsigned int));
+ prv_img->flag[size] |= PRV_USER_EDITED;
+}
+
+static void rna_ImagePreview_is_image_custom_set(PointerRNA *ptr, int value)
+{
+ rna_ImagePreview_is_custom_set(ptr, value, ICON_SIZE_PREVIEW);
+}
+
+static void rna_ImagePreview_image_size_get(PointerRNA *ptr, int *values)
+{
+ rna_ImagePreview_size_get(ptr, values, ICON_SIZE_PREVIEW);
+}
+
+static void rna_ImagePreview_image_size_set(PointerRNA *ptr, const int *values)
+{
+ rna_ImagePreview_size_set(ptr, values, ICON_SIZE_PREVIEW);
+}
+
+static int rna_ImagePreview_image_pixels_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+{
+ return rna_ImagePreview_pixels_get_length(ptr, length, ICON_SIZE_PREVIEW);
+}
+
+static void rna_ImagePreview_image_pixels_get(PointerRNA *ptr, int *values)
+{
+ rna_ImagePreview_pixels_get(ptr, values, ICON_SIZE_PREVIEW);
+}
+
+static void rna_ImagePreview_image_pixels_set(PointerRNA *ptr, const int *values)
+{
+ rna_ImagePreview_pixels_set(ptr, values, ICON_SIZE_PREVIEW);
+}
+
+static void rna_ImagePreview_is_icon_custom_set(PointerRNA *ptr, int value)
+{
+ rna_ImagePreview_is_custom_set(ptr, value, ICON_SIZE_ICON);
+}
+
+static void rna_ImagePreview_icon_size_get(PointerRNA *ptr, int *values)
+{
+ rna_ImagePreview_size_get(ptr, values, ICON_SIZE_ICON);
+}
+
+static void rna_ImagePreview_icon_size_set(PointerRNA *ptr, const int *values)
+{
+ rna_ImagePreview_size_set(ptr, values, ICON_SIZE_ICON);
+}
+
+static int rna_ImagePreview_icon_pixels_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+{
+ return rna_ImagePreview_pixels_get_length(ptr, length, ICON_SIZE_ICON);
+}
+
+static void rna_ImagePreview_icon_pixels_get(PointerRNA *ptr, int *values)
+{
+ rna_ImagePreview_pixels_get(ptr, values, ICON_SIZE_ICON);
+}
+
+static void rna_ImagePreview_icon_pixels_set(PointerRNA *ptr, const int *values)
+{
+ rna_ImagePreview_pixels_set(ptr, values, ICON_SIZE_ICON);
+}
+
+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));
+}
+static void rna_ImagePreview_icon_reload(PreviewImage *prv)
+{
+ /* will lazy load on next use, but only in case icon is not user-modified! */
+ if (!(prv->flag[ICON_SIZE_ICON] & PRV_USER_EDITED) && !(prv->flag[ICON_SIZE_PREVIEW] & PRV_USER_EDITED)) {
+ BKE_previewimg_clear(prv);
+ }
+}
+
#else
static void rna_def_ID_properties(BlenderRNA *brna)
@@ -524,6 +706,62 @@ static void rna_def_ID_materials(BlenderRNA *brna)
RNA_def_boolean(func, "update_data", 0, "", "Update data by re-adjusting the material slots assigned");
}
+static void rna_def_image_preview(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ImagePreview", NULL);
+ RNA_def_struct_sdna(srna, "PreviewImage");
+ RNA_def_struct_ui_text(srna, "Image Preview", "Preview image and icon");
+
+ prop = RNA_def_property(srna, "is_image_custom", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag[ICON_SIZE_PREVIEW]", PRV_USER_EDITED);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_ImagePreview_is_image_custom_set");
+ RNA_def_property_ui_text(prop, "Custom Image", "True if this preview image has been modified by py script,"
+ "and is no more auto-generated by Blender");
+
+ prop = RNA_def_int_vector(srna, "image_size", 2, NULL, 0, 0, "Image Size",
+ "Width and height in pixels", 0, 0);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+ RNA_def_property_int_funcs(prop, "rna_ImagePreview_image_size_get", "rna_ImagePreview_image_size_set", NULL);
+
+ prop = RNA_def_property(srna, "image_pixels", PROP_INT, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_multi_array(prop, 1, NULL);
+ RNA_def_property_ui_text(prop, "Image Pixels", "Image pixels, as bytes (always RGBA 32bits)");
+ RNA_def_property_dynamic_array_funcs(prop, "rna_ImagePreview_image_pixels_get_length");
+ RNA_def_property_int_funcs(prop, "rna_ImagePreview_image_pixels_get", "rna_ImagePreview_image_pixels_set", NULL);
+
+
+ prop = RNA_def_property(srna, "is_icon_custom", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag[ICON_SIZE_ICON]", PRV_USER_EDITED);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_ImagePreview_is_icon_custom_set");
+ RNA_def_property_ui_text(prop, "Custom Icon", "True if this preview icon has been modified by py script,"
+ "and is no more auto-generated by Blender");
+
+ prop = RNA_def_int_vector(srna, "icon_size", 2, NULL, 0, 0, "Icon Size",
+ "Width and height in pixels", 0, 0);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+ RNA_def_property_int_funcs(prop, "rna_ImagePreview_icon_size_get", "rna_ImagePreview_icon_size_set", NULL);
+
+ prop = RNA_def_property(srna, "icon_pixels", PROP_INT, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_multi_array(prop, 1, NULL);
+ RNA_def_property_ui_text(prop, "Icon Pixels", "Icon pixels, as bytes (always RGBA 32bits)");
+ RNA_def_property_dynamic_array_funcs(prop, "rna_ImagePreview_icon_pixels_get_length");
+ RNA_def_property_int_funcs(prop, "rna_ImagePreview_icon_pixels_get", "rna_ImagePreview_icon_pixels_set", NULL);
+
+ prop = RNA_def_int(srna, "icon_id", 0, INT_MIN, INT_MAX, "Icon ID",
+ "Unique integer identifying this preview as an icon (zero means invalid)", INT_MIN, INT_MAX);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_int_funcs(prop, "rna_ImagePreview_icon_id_get", NULL, NULL);
+
+ func = RNA_def_function(srna, "reload", "rna_ImagePreview_icon_reload");
+ RNA_def_function_ui_description(func, "Reload the preview from its source path");
+}
+
static void rna_def_ID(BlenderRNA *brna)
{
StructRNA *srna;
@@ -566,7 +804,9 @@ static void rna_def_ID(BlenderRNA *brna)
prop = RNA_def_property(srna, "tag", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LIB_DOIT);
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
- RNA_def_property_ui_text(prop, "Tag", "Tools can use this to tag data (initial state is undefined)");
+ RNA_def_property_ui_text(prop, "Tag",
+ "Tools can use this to tag data for their own purposes "
+ "(initial state is undefined)");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LIB_ID_RECALC);
@@ -598,17 +838,19 @@ static void rna_def_ID(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Clear the user count of a datablock so its not saved, "
"on reload the data will be removed");
- func = RNA_def_function(srna, "animation_data_create", "BKE_id_add_animdata");
+ func = RNA_def_function(srna, "animation_data_create", "BKE_animdata_add_id");
RNA_def_function_ui_description(func, "Create animation data to this ID, note that not all ID types support this");
parm = RNA_def_pointer(func, "anim_data", "AnimData", "", "New animation data or NULL");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "animation_data_clear", "BKE_free_animdata");
+ func = RNA_def_function(srna, "animation_data_clear", "BKE_animdata_free");
RNA_def_function_ui_description(func, "Clear animation on this this ID");
func = RNA_def_function(srna, "update_tag", "rna_ID_update_tag");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_function_ui_description(func, "Tag the ID to update its display data");
+ RNA_def_function_ui_description(func,
+ "Tag the ID to update its display data, "
+ "e.g. when calling :class:`bpy.types.Scene.update`");
RNA_def_enum_flag(func, "refresh", update_flag_items, 0, "", "Type of updates to perform");
}
@@ -647,6 +889,7 @@ void RNA_def_ID(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Any Type", "RNA type used for pointers to any possible data");
rna_def_ID(brna);
+ rna_def_image_preview(brna);
rna_def_ID_properties(brna);
rna_def_ID_materials(brna);
rna_def_library(brna);
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index c3499d0b139..ef798820321 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -1622,7 +1622,7 @@ bool RNA_property_animateable(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop)
{
int len = 1, index;
- bool driven;
+ bool driven, special;
if (!prop)
return false;
@@ -1631,7 +1631,7 @@ bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop)
len = RNA_property_array_length(ptr, prop);
for (index = 0; index < len; index++) {
- if (rna_get_fcurve(ptr, prop, index, NULL, NULL, &driven))
+ if (rna_get_fcurve(ptr, prop, index, NULL, NULL, &driven, &special))
return true;
}
@@ -5462,14 +5462,20 @@ char *RNA_property_as_string(bContext *C, PointerRNA *ptr, PropertyRNA *prop, in
BLI_dynstr_append(dynstr, bool_as_py_string(RNA_property_boolean_get_index(ptr, prop, index)));
}
else {
+ int fixedbuf[RNA_MAX_ARRAY_LENGTH];
+ int *buf = ARRAY_SIZE(fixedbuf) >= len ? fixedbuf : MEM_mallocN(sizeof(*buf) * len, __func__);
+
+ RNA_property_boolean_get_array(ptr, prop, buf);
BLI_dynstr_append(dynstr, "(");
for (i = 0; i < len; i++) {
- BLI_dynstr_appendf(dynstr, i ? ", %s" : "%s",
- bool_as_py_string(RNA_property_boolean_get_index(ptr, prop, i)));
+ BLI_dynstr_appendf(dynstr, i ? ", %s" : "%s", bool_as_py_string(buf[i]));
}
if (len == 1)
BLI_dynstr_append(dynstr, ","); /* otherwise python wont see it as a tuple */
BLI_dynstr_append(dynstr, ")");
+ if (buf != fixedbuf) {
+ MEM_freeN(buf);
+ }
}
}
break;
@@ -5482,13 +5488,20 @@ char *RNA_property_as_string(bContext *C, PointerRNA *ptr, PropertyRNA *prop, in
BLI_dynstr_appendf(dynstr, "%d", RNA_property_int_get_index(ptr, prop, index));
}
else {
+ int fixedbuf[RNA_MAX_ARRAY_LENGTH];
+ int *buf = ARRAY_SIZE(fixedbuf) >= len ? fixedbuf : MEM_mallocN(sizeof(*buf) * len, __func__);
+
+ RNA_property_int_get_array(ptr, prop, buf);
BLI_dynstr_append(dynstr, "(");
for (i = 0; i < len; i++) {
- BLI_dynstr_appendf(dynstr, i ? ", %d" : "%d", RNA_property_int_get_index(ptr, prop, i));
+ BLI_dynstr_appendf(dynstr, i ? ", %d" : "%d", buf[i]);
}
if (len == 1)
BLI_dynstr_append(dynstr, ","); /* otherwise python wont see it as a tuple */
BLI_dynstr_append(dynstr, ")");
+ if (buf != fixedbuf) {
+ MEM_freeN(buf);
+ }
}
}
break;
@@ -5501,13 +5514,20 @@ char *RNA_property_as_string(bContext *C, PointerRNA *ptr, PropertyRNA *prop, in
BLI_dynstr_appendf(dynstr, "%g", RNA_property_float_get_index(ptr, prop, index));
}
else {
+ float fixedbuf[RNA_MAX_ARRAY_LENGTH];
+ float *buf = ARRAY_SIZE(fixedbuf) >= len ? fixedbuf : MEM_mallocN(sizeof(*buf) * len, __func__);
+
+ RNA_property_float_get_array(ptr, prop, buf);
BLI_dynstr_append(dynstr, "(");
for (i = 0; i < len; i++) {
- BLI_dynstr_appendf(dynstr, i ? ", %g" : "%g", RNA_property_float_get_index(ptr, prop, i));
+ BLI_dynstr_appendf(dynstr, i ? ", %g" : "%g", buf[i]);
}
if (len == 1)
BLI_dynstr_append(dynstr, ","); /* otherwise python wont see it as a tuple */
BLI_dynstr_append(dynstr, ")");
+ if (buf != fixedbuf) {
+ MEM_freeN(buf);
+ }
}
}
break;
@@ -6497,6 +6517,12 @@ bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop,
/* In case of IDProperty, we have to find the *real* idprop of ptr,
* since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
prop = (PropertyRNA *)rna_idproperty_find(ptr, ((IDProperty *)fromprop)->name);
+
+ /* its possible the custom-prop doesn't exist on this datablock */
+ if (prop == NULL) {
+ return false;
+ }
+
/* Even though currently we now prop will always be the 'fromprop', this might not be the case in the future. */
if (prop == fromprop) {
fromprop = (PropertyRNA *)rna_idproperty_find(fromptr, ((IDProperty *)prop)->name);
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 3fed505b9d6..29e699a57b2 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -329,6 +329,21 @@ static void rna_def_dopesheet(BlenderRNA *brna)
prop = RNA_def_property(srna, "filter_fcurve_name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "searchstr");
RNA_def_property_ui_text(prop, "F-Curve Name Filter", "F-Curve live filtering string");
+ RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ /* NLA Name Search Settings (Shared with FCurve setting, but with different labels) */
+ prop = RNA_def_property(srna, "use_filter_text", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_BY_FCU_NAME);
+ RNA_def_property_ui_text(prop, "Only Matching Channels",
+ "Only include channels with names containing search text");
+ RNA_def_property_ui_icon(prop, ICON_VIEWZOOM, 0);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "filter_text", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "searchstr");
+ RNA_def_property_ui_text(prop, "Name Filter", "Live filtering string");
+ RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
/* NLA Specific Settings */
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index df1e6dd55dd..ac30c615438 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -112,6 +112,7 @@ static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value)
adt = BKE_animdata_from_id(ownerId);
if (adt) {
adt->recalc |= ADT_RECALC_ANIM;
+ DAG_id_tag_update(ownerId, OB_RECALC_TIME);
}
}
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 421d7b28dda..93e5ceaa229 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -247,8 +247,8 @@ static void rna_bone_layer_set(int *layer, const int *values)
return;
for (i = 0; i < 32; i++) {
- if (values[i]) *layer |= (1 << i);
- else *layer &= ~(1 << i);
+ if (values[i]) *layer |= (1u << i);
+ else *layer &= ~(1u << i);
}
}
@@ -272,8 +272,8 @@ static void rna_Armature_layer_set(PointerRNA *ptr, const int *values)
return;
for (i = 0; i < 32; i++) {
- if (values[i]) arm->layer |= (1 << i);
- else arm->layer &= ~(1 << i);
+ if (values[i]) arm->layer |= (1u << i);
+ else arm->layer &= ~(1u << i);
}
}
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 81ba3a9066f..f6e60471a58 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -107,6 +107,17 @@ EnumPropertyItem brush_image_tool_items[] = {
{0, NULL, 0, NULL, NULL}
};
+EnumPropertyItem brush_hair_tool_items[] = {
+ {HAIR_TOOL_COMB, "COMB", ICON_BRUSH_HAIR_COMB, "Comb", "Align hairs to the stroke direction"},
+ {HAIR_TOOL_CUT, "CUT", ICON_BRUSH_HAIR_CUT, "Cut", "Shorten and/or remove hairs"},
+ {HAIR_TOOL_LENGTH, "LENGTH", ICON_BRUSH_HAIR_LENGTH, "Length", "Increase hair length"},
+ {HAIR_TOOL_PUFF, "PUFF", ICON_BRUSH_HAIR_PUFF, "Puff", "Increase spacing between hairs"},
+ {HAIR_TOOL_ADD, "ADD", ICON_BRUSH_HAIR_ADD, "Add", "Add more hairs on the object"},
+ {HAIR_TOOL_SMOOTH, "SMOOTH", ICON_BRUSH_HAIR_SMOOTH, "Smooth", "Align hairs in the same direction"},
+ {HAIR_TOOL_WEIGHT, "WEIGHT", ICON_BRUSH_HAIR_WEIGHT, "Weight", "Set hair vertex weights"},
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifdef RNA_RUNTIME
#include "MEM_guardedalloc.h"
@@ -125,9 +136,7 @@ EnumPropertyItem brush_image_tool_items[] = {
static int rna_SculptToolCapabilities_has_accumulate_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- return ELEM(br->sculpt_tool,
- SCULPT_TOOL_BLOB, SCULPT_TOOL_CLAY, SCULPT_TOOL_CREASE,
- SCULPT_TOOL_DRAW, SCULPT_TOOL_INFLATE, SCULPT_TOOL_LAYER);
+ return SCULPT_TOOL_HAS_ACCUMULATE(br->sculpt_tool);
}
static int rna_SculptToolCapabilities_has_auto_smooth_get(PointerRNA *ptr)
@@ -155,7 +164,7 @@ static int rna_SculptToolCapabilities_has_jitter_get(PointerRNA *ptr)
static int rna_SculptToolCapabilities_has_normal_weight_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- return ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK);
+ return SCULPT_TOOL_HAS_NORMAL_WEIGHT(br->sculpt_tool);
}
static int rna_BrushCapabilities_has_overlay_get(PointerRNA *ptr)
@@ -344,8 +353,8 @@ static void rna_Brush_reset_icon(Brush *br, const char *UNUSED(type))
return;
if (id->icon_id >= BIFICONID_LAST) {
- BKE_icon_delete(id);
- BKE_previewimg_free_id(id);
+ BKE_icon_id_delete(id);
+ BKE_previewimg_id_free(id);
}
id->icon_id = 0;
@@ -399,6 +408,13 @@ static void rna_Brush_imagepaint_tool_update(Main *bmain, Scene *scene, PointerR
rna_Brush_update(bmain, scene, ptr);
}
+static void rna_Brush_hair_tool_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Brush *br = (Brush *)ptr->data;
+ rna_Brush_reset_icon(br, "hair");
+ rna_Brush_update(bmain, scene, ptr);
+}
+
static void rna_Brush_stroke_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, scene);
@@ -417,8 +433,8 @@ static void rna_Brush_icon_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
br->id.icon_id = 0;
if (br->flag & BRUSH_CUSTOM_ICON) {
- BKE_previewimg_get(&br->id);
- BKE_icon_changed(BKE_icon_getid(&br->id));
+ BKE_previewimg_id_ensure(&br->id);
+ BKE_icon_changed(BKE_icon_id_ensure(&br->id));
}
WM_main_add_notifier(NC_BRUSH | NA_EDITED, br);
@@ -881,6 +897,12 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Image Paint Tool", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, "rna_Brush_imagepaint_tool_update");
+ prop = RNA_def_property(srna, "hair_tool", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "hair_tool");
+ RNA_def_property_enum_items(prop, brush_hair_tool_items);
+ RNA_def_property_ui_text(prop, "Hair Tool", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_hair_tool_update");
+
prop = RNA_def_property(srna, "direction", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, prop_direction_items);
@@ -1323,6 +1345,10 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "ob_mode", OB_MODE_TEXTURE_PAINT);
RNA_def_property_ui_text(prop, "Use Texture", "Use this brush in texture paint mode");
+ prop = RNA_def_property(srna, "use_hair_edit", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "ob_mode", OB_MODE_HAIR_EDIT);
+ RNA_def_property_ui_text(prop, "Use Hair", "Use this brush in hair edit mode");
+
/* texture */
prop = RNA_def_property(srna, "texture_slot", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "BrushTextureSlot");
diff --git a/source/blender/makesrna/intern/rna_cache_library.c b/source/blender/makesrna/intern/rna_cache_library.c
new file mode 100644
index 00000000000..4c8b8835491
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_cache_library.c
@@ -0,0 +1,1049 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Foundation (2015).
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_cache_library.c
+ * \ingroup RNA
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include "DNA_cache_library_types.h"
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#include "WM_types.h"
+
+EnumPropertyItem cache_library_data_type_items[] = {
+ {CACHE_TYPE_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Object base properties"},
+ {CACHE_TYPE_DERIVED_MESH, "DERIVED_MESH", ICON_OUTLINER_OB_MESH, "Derived Mesh", "Mesh result from modifiers"},
+ {CACHE_TYPE_HAIR, "HAIR", ICON_PARTICLE_POINT, "Hair", "Hair parent strands"},
+ {CACHE_TYPE_HAIR_PATHS, "HAIR_PATHS", ICON_PARTICLE_PATH, "Hair Paths", "Full hair paths"},
+ {CACHE_TYPE_PARTICLES, "PARTICLES", ICON_PARTICLES, "Particles", "Emitter particles"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+EnumPropertyItem cache_library_read_result_items[] = {
+ {CACHE_READ_SAMPLE_INVALID, "INVALID", ICON_ERROR, "Invalid", "No valid sample found"},
+ {CACHE_READ_SAMPLE_EXACT, "EXACT", ICON_SPACE3, "Exact", "Found sample for requested frame"},
+ {CACHE_READ_SAMPLE_INTERPOLATED, "INTERPOLATED", ICON_TRIA_DOWN_BAR, "Interpolated", "Enclosing samples found for interpolation"},
+ {CACHE_READ_SAMPLE_EARLY, "EARLY", ICON_TRIA_RIGHT_BAR, "Early", "Requested frame before the first sample"},
+ {CACHE_READ_SAMPLE_LATE, "LATE", ICON_TRIA_LEFT_BAR, "Late", "Requested frame after the last sample"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+EnumPropertyItem cache_modifier_type_items[] = {
+ {eCacheModifierType_HairSimulation, "HAIR_SIMULATION", ICON_HAIR, "Hair Simulation", ""},
+ {eCacheModifierType_ForceField, "FORCE_FIELD", ICON_FORCE_FORCE, "Force Field", ""},
+ {eCacheModifierType_ShrinkWrap, "SHRINK_WRAP", ICON_MOD_SHRINKWRAP, "Shrink Wrap", ""},
+ {eCacheModifierType_StrandsKey, "STRANDS_KEY", ICON_SHAPEKEY_DATA, "Strands Key", "Shape key for strands"},
+ {eCacheModifierType_Haircut, "HAIRCUT", ICON_HAIR, "Hair Cut", "Cut strands where they intersect with an object"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+#ifdef RNA_RUNTIME
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+
+#include "BKE_animsys.h"
+#include "BKE_cache_library.h"
+#include "BKE_depsgraph.h"
+#include "BKE_main.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+
+/* ========================================================================= */
+
+static void rna_CacheLibrary_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ CacheLibrary *cachelib = ptr->data;
+ DAG_id_tag_update(&cachelib->id, OB_RECALC_DATA);
+ WM_main_add_notifier(NC_WINDOW, NULL);
+}
+
+static void rna_CacheArchiveInfo_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+{
+// CacheLibrary *cachelib = ptr->id.data;
+// WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+}
+
+/* ========================================================================= */
+
+static void rna_CacheModifier_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+{
+}
+
+#if 0 /* unused */
+static void rna_CacheModifier_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ rna_CacheModifier_update(bmain, scene, ptr);
+ DAG_relations_tag_update(bmain);
+}
+#endif
+
+
+static StructRNA *rna_CacheModifier_refine(struct PointerRNA *ptr)
+{
+ CacheModifier *md = (CacheModifier *)ptr->data;
+
+ switch ((eCacheModifier_Type)md->type) {
+ case eCacheModifierType_HairSimulation:
+ return &RNA_HairSimulationCacheModifier;
+ case eCacheModifierType_ForceField:
+ return &RNA_ForceFieldCacheModifier;
+ case eCacheModifierType_ShrinkWrap:
+ return &RNA_ShrinkWrapCacheModifier;
+ case eCacheModifierType_StrandsKey:
+ return &RNA_StrandsKeyCacheModifier;
+ case eCacheModifierType_Haircut:
+ return &RNA_HaircutCacheModifier;
+
+ /* Default */
+ case eCacheModifierType_None:
+ case NUM_CACHE_MODIFIER_TYPES:
+ return &RNA_CacheLibraryModifier;
+ }
+
+ return &RNA_CacheLibraryModifier;
+}
+
+static void rna_CacheLibraryModifier_name_set(PointerRNA *ptr, const char *value)
+{
+ CacheModifier *md = ptr->data;
+ char oldname[sizeof(md->name)];
+
+ /* make a copy of the old name first */
+ BLI_strncpy(oldname, md->name, sizeof(md->name));
+
+ /* copy the new name into the name slot */
+ BLI_strncpy_utf8(md->name, value, sizeof(md->name));
+
+ /* make sure the name is truly unique */
+ if (ptr->id.data) {
+ CacheLibrary *cachelib = ptr->id.data;
+ BKE_cache_modifier_unique_name(&cachelib->modifiers, md);
+ }
+
+ /* fix all the animation data which may link to this */
+ BKE_animdata_fix_paths_rename_all(NULL, "modifiers", oldname, md->name);
+}
+
+static char *rna_CacheLibraryModifier_path(PointerRNA *ptr)
+{
+ CacheModifier *md = ptr->data;
+ char name_esc[sizeof(md->name) * 2];
+
+ BLI_strescape(name_esc, md->name, sizeof(name_esc));
+ return BLI_sprintfN("modifiers[\"%s\"]", name_esc);
+}
+
+static CacheModifier *rna_CacheLibrary_modifier_new(CacheLibrary *cachelib, bContext *UNUSED(C), ReportList *UNUSED(reports),
+ const char *name, int type)
+{
+ return BKE_cache_modifier_add(cachelib, name, type);
+}
+
+static void rna_CacheLibrary_modifier_remove(CacheLibrary *cachelib, bContext *UNUSED(C), ReportList *UNUSED(reports), PointerRNA *md_ptr)
+{
+ CacheModifier *md = md_ptr->data;
+
+ BKE_cache_modifier_remove(cachelib, md);
+
+ RNA_POINTER_INVALIDATE(md_ptr);
+}
+
+static void rna_CacheLibrary_modifier_clear(CacheLibrary *cachelib, bContext *UNUSED(C))
+{
+ BKE_cache_modifier_clear(cachelib);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int rna_CacheLibraryModifier_mesh_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
+{
+ /*HairSimCacheModifier *hsmd = ptr->data;*/
+ Object *ob = value.data;
+
+ return ob->type == OB_MESH && ob->data != NULL;
+}
+
+static int rna_CacheLibraryModifier_hair_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
+{
+ /*HairSimCacheModifier *hsmd = ptr->data;*/
+ Object *ob = value.data;
+ ParticleSystem *psys;
+ bool has_hair_system = false;
+
+ for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ if (psys->part && psys->part->type == PART_HAIR) {
+ has_hair_system = true;
+ break;
+ }
+ }
+ return has_hair_system;
+}
+
+static PointerRNA rna_HairSimulationCacheModifier_hair_system_get(PointerRNA *ptr)
+{
+ HairSimCacheModifier *hsmd = ptr->data;
+ ParticleSystem *psys = hsmd->object ? BLI_findlink(&hsmd->object->particlesystem, hsmd->hair_system) : NULL;
+ PointerRNA value;
+
+ RNA_pointer_create(ptr->id.data, &RNA_ParticleSystem, psys, &value);
+ return value;
+}
+
+static void rna_HairSimulationCacheModifier_hair_system_set(PointerRNA *ptr, PointerRNA value)
+{
+ HairSimCacheModifier *hsmd = ptr->data;
+ ParticleSystem *psys = value.data;
+ hsmd->hair_system = hsmd->object ? BLI_findindex(&hsmd->object->particlesystem, psys) : -1;
+}
+
+static int rna_HairSimulationCacheModifier_hair_system_poll(PointerRNA *ptr, PointerRNA value)
+{
+ HairSimCacheModifier *hsmd = ptr->data;
+ ParticleSystem *psys = value.data;
+
+ if (!hsmd->object)
+ return false;
+ if (BLI_findindex(&hsmd->object->particlesystem, psys) == -1)
+ return false;
+ if (!psys->part || psys->part->type != PART_HAIR)
+ return false;
+ return true;
+}
+
+static PointerRNA rna_ShrinkWrapCacheModifier_hair_system_get(PointerRNA *ptr)
+{
+ ShrinkWrapCacheModifier *smd = ptr->data;
+ ParticleSystem *psys = smd->object ? BLI_findlink(&smd->object->particlesystem, smd->hair_system) : NULL;
+ PointerRNA value;
+
+ RNA_pointer_create(ptr->id.data, &RNA_ParticleSystem, psys, &value);
+ return value;
+}
+
+static void rna_ShrinkWrapCacheModifier_hair_system_set(PointerRNA *ptr, PointerRNA value)
+{
+ ShrinkWrapCacheModifier *smd = ptr->data;
+ ParticleSystem *psys = value.data;
+ smd->hair_system = smd->object ? BLI_findindex(&smd->object->particlesystem, psys) : -1;
+}
+
+static int rna_ShrinkWrapCacheModifier_hair_system_poll(PointerRNA *ptr, PointerRNA value)
+{
+ ShrinkWrapCacheModifier *smd = ptr->data;
+ ParticleSystem *psys = value.data;
+
+ if (!smd->object)
+ return false;
+ if (BLI_findindex(&smd->object->particlesystem, psys) == -1)
+ return false;
+ if (!psys->part || psys->part->type != PART_HAIR)
+ return false;
+ return true;
+}
+
+static PointerRNA rna_StrandsKeyCacheModifier_hair_system_get(PointerRNA *ptr)
+{
+ StrandsKeyCacheModifier *skmd = ptr->data;
+ ParticleSystem *psys = skmd->object ? BLI_findlink(&skmd->object->particlesystem, skmd->hair_system) : NULL;
+ PointerRNA value;
+
+ RNA_pointer_create(ptr->id.data, &RNA_ParticleSystem, psys, &value);
+ return value;
+}
+
+static void rna_StrandsKeyCacheModifier_hair_system_set(PointerRNA *ptr, PointerRNA value)
+{
+ StrandsKeyCacheModifier *skmd = ptr->data;
+ ParticleSystem *psys = value.data;
+ skmd->hair_system = skmd->object ? BLI_findindex(&skmd->object->particlesystem, psys) : -1;
+}
+
+static int rna_StrandsKeyCacheModifier_hair_system_poll(PointerRNA *ptr, PointerRNA value)
+{
+ StrandsKeyCacheModifier *skmd = ptr->data;
+ ParticleSystem *psys = value.data;
+
+ if (!skmd->object)
+ return false;
+ if (BLI_findindex(&skmd->object->particlesystem, psys) == -1)
+ return false;
+ if (!psys->part || psys->part->type != PART_HAIR)
+ return false;
+ return true;
+}
+
+static void rna_StrandsKeyCacheModifier_active_shape_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+#if 0 // TODO
+ StrandsKeyCacheModifier *skmd = ptr->data;
+
+ if (scene->obedit == ob) {
+ /* exit/enter editmode to get new shape */
+ switch (ob->type) {
+ case OB_MESH:
+ EDBM_mesh_load(ob);
+ EDBM_mesh_make(scene->toolsettings, ob);
+ EDBM_mesh_normals_update(((Mesh *)ob->data)->edit_btmesh);
+ BKE_editmesh_tessface_calc(((Mesh *)ob->data)->edit_btmesh);
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ load_editNurb(ob);
+ make_editNurb(ob);
+ break;
+ case OB_LATTICE:
+ load_editLatt(ob);
+ make_editLatt(ob);
+ break;
+ }
+ }
+#endif
+
+ rna_CacheModifier_update(bmain, scene, ptr);
+}
+
+static void rna_StrandsKeyCacheModifier_active_shape_key_index_range(PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ StrandsKeyCacheModifier *skmd = ptr->data;
+ Key *key = skmd->key;
+
+ *min = 0;
+ if (key) {
+ *max = BLI_listbase_count(&key->block) - 1;
+ if (*max < 0) *max = 0;
+ }
+ else {
+ *max = 0;
+ }
+}
+
+static int rna_StrandsKeyCacheModifier_active_shape_key_index_get(PointerRNA *ptr)
+{
+ StrandsKeyCacheModifier *skmd = ptr->data;
+
+ return max_ii(skmd->shapenr - 1, 0);
+}
+
+static void rna_StrandsKeyCacheModifier_active_shape_key_index_set(PointerRNA *ptr, int value)
+{
+ StrandsKeyCacheModifier *skmd = ptr->data;
+
+ skmd->shapenr = value + 1;
+}
+
+static PointerRNA rna_StrandsKeyCacheModifier_active_shape_key_get(PointerRNA *ptr)
+{
+ StrandsKeyCacheModifier *skmd = ptr->data;
+ Key *key = skmd->key;
+ KeyBlock *kb;
+ PointerRNA keyptr;
+
+ if (key == NULL)
+ return PointerRNA_NULL;
+
+ kb = BLI_findlink(&key->block, skmd->shapenr - 1);
+ RNA_pointer_create((ID *)key, &RNA_ShapeKey, kb, &keyptr);
+ return keyptr;
+}
+
+static PointerRNA rna_HaircutCacheModifier_hair_system_get(PointerRNA *ptr)
+{
+ HaircutCacheModifier *hmd = ptr->data;
+ ParticleSystem *psys = hmd->object ? BLI_findlink(&hmd->object->particlesystem, hmd->hair_system) : NULL;
+ PointerRNA value;
+
+ RNA_pointer_create(ptr->id.data, &RNA_ParticleSystem, psys, &value);
+ return value;
+}
+
+static void rna_HaircutCacheModifier_hair_system_set(PointerRNA *ptr, PointerRNA value)
+{
+ HaircutCacheModifier *hmd = ptr->data;
+ ParticleSystem *psys = value.data;
+ hmd->hair_system = hmd->object ? BLI_findindex(&hmd->object->particlesystem, psys) : -1;
+}
+
+static int rna_HaircutCacheModifier_hair_system_poll(PointerRNA *ptr, PointerRNA value)
+{
+ HaircutCacheModifier *hmd = ptr->data;
+ ParticleSystem *psys = value.data;
+
+ if (!hmd->object)
+ return false;
+ if (BLI_findindex(&hmd->object->particlesystem, psys) == -1)
+ return false;
+ if (!psys->part || psys->part->type != PART_HAIR)
+ return false;
+ return true;
+}
+
+static void rna_CacheArchiveInfoNode_bytes_size_get(PointerRNA *ptr, char *value)
+{
+ CacheArchiveInfoNode *node = ptr->data;
+ BLI_snprintf(value, MAX_NAME, "%lld", (long long int)node->bytes_size);
+}
+
+static int rna_CacheArchiveInfoNode_bytes_size_length(PointerRNA *ptr)
+{
+ char buf[MAX_NAME];
+ /* theoretically could do a dummy BLI_snprintf here, but BLI does not allow NULL buffer ... */
+ CacheArchiveInfoNode *node = ptr->data;
+ return BLI_snprintf(buf, sizeof(buf), "%lld", (long long int)node->bytes_size);
+}
+
+#else
+
+static void rna_def_hair_sim_params(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "HairSimulationParameters", NULL);
+ RNA_def_struct_sdna(srna, "HairSimParams");
+ RNA_def_struct_ui_text(srna, "Hair Simulation Parameters", "Simulation parameters for hair simulation");
+ RNA_def_struct_ui_icon(srna, ICON_HAIR);
+
+ prop = RNA_def_property(srna, "timescale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 0.1f, 3);
+ RNA_def_property_ui_text(prop, "Time Scale", "Simulation time scale relative to scene time");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "substeps", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 1, 80);
+ RNA_def_property_ui_text(prop, "Substeps", "Simulation steps per frame");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "EffectorWeights");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Effector Weights", "");
+
+ prop = RNA_def_property(srna, "mass", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0f, 10.0f);
+ RNA_def_property_ui_text(prop, "Mass", "Mass of hair vertices");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "drag", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 0.1f, 3);
+ RNA_def_property_ui_text(prop, "Drag", "Drag simulating friction with surrounding air");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "goal_stiffness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 0.1f, 3);
+ RNA_def_property_float_default(prop, 0.0f);
+ RNA_def_property_ui_text(prop, "Goal Strength", "Goal spring, pulling vertices toward their rest position");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "goal_damping", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1f, 3);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Goal Damping", "Damping factor of goal springs");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "use_goal_stiffness_curve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", eHairSimParams_Flag_UseGoalStiffnessCurve);
+ RNA_def_property_ui_text(prop, "Use Goal Stiffness Curve", "Use a curve to define goal stiffness along the strand");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "goal_stiffness_curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "goal_stiffness_mapping");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Goal Stiffness Curve", "Stiffness of goal springs along the strand curves");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "use_goal_deflect", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", eHairSimParams_Flag_UseGoalDeflect);
+ RNA_def_property_ui_text(prop, "Use Goal Deflect", "Disable goal springs inside deflectors, to avoid unstable deformations");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "use_bend_stiffness_curve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", eHairSimParams_Flag_UseBendStiffnessCurve);
+ RNA_def_property_ui_text(prop, "Use Bend Stiffness Curve", "Use a curve to define bend resistance along the strand");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "bend_stiffness_curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "bend_stiffness_mapping");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Bend Stiffness Curve", "Resistance to bending along the strand curves");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "stretch_stiffness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 10000.0f, 0.1f, 3);
+ RNA_def_property_float_default(prop, 10000.0f);
+ RNA_def_property_ui_text(prop, "Stretch Stiffness", "Resistance to stretching");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "stretch_damping", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1f, 3);
+ RNA_def_property_float_default(prop, 0.1f);
+ RNA_def_property_ui_text(prop, "Stretch Damping", "Damping factor of stretch springs");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "bend_stiffness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 0.1f, 3);
+ RNA_def_property_float_default(prop, 100.0f);
+ RNA_def_property_ui_text(prop, "Bend Stiffness", "Resistance to bending of the rest shape");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "bend_damping", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1f, 3);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Bend Damping", "Damping factor of bending springs");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+}
+
+static void rna_def_cache_modifier_hair_simulation(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ rna_def_hair_sim_params(brna);
+
+ srna = RNA_def_struct(brna, "HairSimulationCacheModifier", "CacheLibraryModifier");
+ RNA_def_struct_sdna(srna, "HairSimCacheModifier");
+ RNA_def_struct_ui_text(srna, "Hair Simulation Cache Modifier", "Apply hair dynamics simulation to the cache");
+ RNA_def_struct_ui_icon(srna, ICON_HAIR);
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "object");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_CacheLibraryModifier_hair_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Object", "Object whose cache to simulate");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "hair_system_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "hair_system");
+ RNA_def_property_ui_text(prop, "Hair System Index", "Hair system cache to simulate");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "hair_system", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_funcs(prop, "rna_HairSimulationCacheModifier_hair_system_get", "rna_HairSimulationCacheModifier_hair_system_set", NULL, "rna_HairSimulationCacheModifier_hair_system_poll");
+ RNA_def_property_struct_type(prop, "ParticleSystem");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Hair System", "Hair system cache to simulate");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "parameters", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "sim_params");
+ RNA_def_property_struct_type(prop, "HairSimulationParameters");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Simulation Parameters", "Parameters of the simulation");
+}
+
+static void rna_def_cache_modifier_force_field(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem force_type_items[] = {
+ {eForceFieldCacheModifier_Type_Deflect, "DEFLECT", ICON_FORCE_FORCE, "Deflect", "Push away from the surface"},
+ {eForceFieldCacheModifier_Type_Drag, "DRAG", ICON_FORCE_DRAG, "Drag", "Adjust velocity to the surface"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "ForceFieldCacheModifier", "CacheLibraryModifier");
+ RNA_def_struct_sdna(srna, "ForceFieldCacheModifier");
+ RNA_def_struct_ui_text(srna, "Force Field Cache Modifier", "Use an object as a force field");
+ RNA_def_struct_ui_icon(srna, ICON_FORCE_FORCE);
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "object");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_CacheLibraryModifier_mesh_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Object", "Object whose cache to simulate");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "force_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, force_type_items);
+ RNA_def_property_ui_text(prop, "Force Type", "Type of force field");
+
+ prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -10000.0f, 10000.0f, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Strength", "");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Falloff", "");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "min_distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -100.0f, 100.0f, 0.1, 4);
+ RNA_def_property_ui_text(prop, "Minimum Distance", "");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "max_distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -100.0f, 100.0f, 0.1, 4);
+ RNA_def_property_ui_text(prop, "Maximum Distance", "");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "use_double_sided", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", eForceFieldCacheModifier_Flag_DoubleSided);
+ RNA_def_property_ui_text(prop, "Use Double Sided", "");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+}
+
+static void rna_def_cache_modifier_shrink_wrap(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShrinkWrapCacheModifier", "CacheLibraryModifier");
+ RNA_def_struct_sdna(srna, "ShrinkWrapCacheModifier");
+ RNA_def_struct_ui_text(srna, "Shrink Wrap Cache Modifier", "");
+ RNA_def_struct_ui_icon(srna, ICON_HAIR);
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "object");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_CacheLibraryModifier_hair_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Object", "Object whose cache to simulate");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "hair_system_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "hair_system");
+ RNA_def_property_ui_text(prop, "Hair System Index", "Hair system cache to simulate");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "hair_system", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_funcs(prop, "rna_ShrinkWrapCacheModifier_hair_system_get", "rna_ShrinkWrapCacheModifier_hair_system_set", NULL, "rna_ShrinkWrapCacheModifier_hair_system_poll");
+ RNA_def_property_struct_type(prop, "ParticleSystem");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Hair System", "Hair system cache to simulate");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "target");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Target", "Mesh object to wrap onto");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "use_internal_target", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", eShrinkWrapCacheModifier_Flag_InternalTarget);
+ RNA_def_property_ui_text(prop, "Use Internal Target", "Use a cached object from the group instead of an object in the scene");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+}
+
+static void rna_def_cache_modifier_strands_key(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "StrandsKeyCacheModifier", "CacheLibraryModifier");
+ RNA_def_struct_sdna(srna, "StrandsKeyCacheModifier");
+ RNA_def_struct_ui_text(srna, "Strands Key Cache Modifier", "");
+ RNA_def_struct_ui_icon(srna, ICON_SHAPEKEY_DATA);
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "object");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_CacheLibraryModifier_hair_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Object", "Object whose cache to simulate");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "hair_system_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "hair_system");
+ RNA_def_property_ui_text(prop, "Hair System Index", "Hair system cache to simulate");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "hair_system", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_funcs(prop, "rna_StrandsKeyCacheModifier_hair_system_get", "rna_StrandsKeyCacheModifier_hair_system_set", NULL, "rna_StrandsKeyCacheModifier_hair_system_poll");
+ RNA_def_property_struct_type(prop, "ParticleSystem");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Hair System", "Hair system cache to simulate");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ /* shape keys */
+ prop = RNA_def_property(srna, "shape_keys", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "key");
+ RNA_def_property_ui_text(prop, "Shape Keys", "");
+
+ prop = RNA_def_property(srna, "use_motion_state", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", eStrandsKeyCacheModifier_Flag_UseMotionState);
+ RNA_def_property_ui_text(prop, "Use Motion State", "Apply the shape key to the motion state instead of the base shape");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "show_only_shape_key", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", eStrandsKeyCacheModifier_Flag_ShapeLock);
+ RNA_def_property_ui_text(prop, "Shape Key Lock", "Always show the current Shape for this Object");
+ RNA_def_property_ui_icon(prop, ICON_UNPINNED, 1);
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "active_shape_key", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ShapeKey");
+ RNA_def_property_pointer_funcs(prop, "rna_StrandsKeyCacheModifier_active_shape_key_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Active Shape Key", "Current shape key");
+
+ prop = RNA_def_property(srna, "active_shape_key_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "shapenr");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); /* XXX this is really unpredictable... */
+ RNA_def_property_int_funcs(prop, "rna_StrandsKeyCacheModifier_active_shape_key_index_get", "rna_StrandsKeyCacheModifier_active_shape_key_index_set",
+ "rna_StrandsKeyCacheModifier_active_shape_key_index_range");
+ RNA_def_property_ui_text(prop, "Active Shape Key Index", "Current shape key index");
+ RNA_def_property_update(prop, 0, "rna_StrandsKeyCacheModifier_active_shape_update");
+}
+
+static void rna_def_cache_modifier_haircut(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem cut_mode_items[] = {
+ {eHaircutCacheModifier_CutMode_Enter, "ENTER", 0, "Enter", "Cut strands when entering the target mesh"},
+ {eHaircutCacheModifier_CutMode_Exit, "EXIT", 0, "Exit", "Cut strands when exiting the target mesh"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "HaircutCacheModifier", "CacheLibraryModifier");
+ RNA_def_struct_sdna(srna, "HaircutCacheModifier");
+ RNA_def_struct_ui_text(srna, "Hair Cut Cache Modifier", "");
+ RNA_def_struct_ui_icon(srna, ICON_HAIR);
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "object");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_CacheLibraryModifier_hair_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Object", "Object whose cache to simulate");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "hair_system_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "hair_system");
+ RNA_def_property_ui_text(prop, "Hair System Index", "Hair system cache to simulate");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "hair_system", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_funcs(prop, "rna_HaircutCacheModifier_hair_system_get", "rna_HaircutCacheModifier_hair_system_set", NULL, "rna_HaircutCacheModifier_hair_system_poll");
+ RNA_def_property_struct_type(prop, "ParticleSystem");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Hair System", "Hair system cache to simulate");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "target");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Target", "Mesh object to wrap onto");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "use_internal_target", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", eHaircutCacheModifier_Flag_InternalTarget);
+ RNA_def_property_ui_text(prop, "Use Internal Target", "Use a cached object from the group instead of an object in the scene");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+
+ prop = RNA_def_property(srna, "cut_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "cut_mode");
+ RNA_def_property_enum_items(prop, cut_mode_items);
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+ RNA_def_property_ui_text(prop, "Cut Mode", "When to cut strands with the target");
+ RNA_def_property_update(prop, 0, "rna_CacheModifier_update");
+}
+
+static void rna_def_cache_modifier(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "CacheLibraryModifier", NULL);
+ RNA_def_struct_sdna(srna, "CacheModifier");
+ RNA_def_struct_path_func(srna, "rna_CacheLibraryModifier_path");
+ RNA_def_struct_refine_func(srna, "rna_CacheModifier_refine");
+ RNA_def_struct_ui_text(srna, "Cache Modifier", "Cache Modifier");
+ RNA_def_struct_ui_icon(srna, ICON_PHYSICS);
+
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, cache_modifier_type_items);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Type", "Type of the cache modifier");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_CacheLibraryModifier_name_set");
+ RNA_def_property_ui_text(prop, "Name", "Modifier name");
+ RNA_def_property_update(prop, NC_ID | NA_RENAME, NULL);
+ RNA_def_struct_name_property(srna, prop);
+
+ rna_def_cache_modifier_hair_simulation(brna);
+ rna_def_cache_modifier_force_field(brna);
+ rna_def_cache_modifier_shrink_wrap(brna);
+ rna_def_cache_modifier_strands_key(brna);
+ rna_def_cache_modifier_haircut(brna);
+}
+
+static void rna_def_cache_library_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "CacheLibraryModifiers");
+ srna = RNA_def_struct(brna, "CacheLibraryModifiers", NULL);
+ RNA_def_struct_sdna(srna, "CacheLibrary");
+ RNA_def_struct_ui_text(srna, "Cache Modifiers", "Collection of cache modifiers");
+
+ /* add modifier */
+ func = RNA_def_function(srna, "new", "rna_CacheLibrary_modifier_new");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Add a new modifier");
+ parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the modifier");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ /* modifier to add */
+ parm = RNA_def_enum(func, "type", cache_modifier_type_items, 1, "", "Modifier type to add");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ /* return type */
+ parm = RNA_def_pointer(func, "modifier", "CacheLibraryModifier", "", "Newly created modifier");
+ RNA_def_function_return(func, parm);
+
+ /* remove modifier */
+ func = RNA_def_function(srna, "remove", "rna_CacheLibrary_modifier_remove");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Remove an existing modifier");
+ /* modifier to remove */
+ parm = RNA_def_pointer(func, "modifier", "CacheLibraryModifier", "", "Modifier to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+
+ /* clear all modifiers */
+ func = RNA_def_function(srna, "clear", "rna_CacheLibrary_modifier_clear");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Remove all modifiers");
+}
+
+static void rna_def_cache_library(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem source_mode_items[] = {
+ {CACHE_LIBRARY_SOURCE_SCENE, "SCENE", 0, "Scene", "Use generated scene data as source"},
+ {CACHE_LIBRARY_SOURCE_CACHE, "CACHE", 0, "Cache", "Use cache data as source"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem display_mode_items[] = {
+ {CACHE_LIBRARY_DISPLAY_SOURCE, "SOURCE", 0, "Source", "Display source data unmodified"},
+ {CACHE_LIBRARY_DISPLAY_MODIFIERS, "MODIFIERS", 0, "Modifiers", "Display source data with modifiers applied"},
+ {CACHE_LIBRARY_DISPLAY_RESULT, "RESULT", 0, "Result", "Display resulting data"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "CacheLibrary", "ID");
+ RNA_def_struct_ui_text(srna, "Cache Library", "Cache Library datablock for constructing an archive of caches");
+ RNA_def_struct_ui_icon(srna, ICON_PHYSICS);
+
+ prop = RNA_def_property(srna, "input_filepath", PROP_STRING, PROP_FILEPATH);
+ RNA_def_property_string_sdna(prop, NULL, "input_filepath");
+ RNA_def_property_ui_text(prop, "Input File Path", "Path to a cache archive for reading input");
+ RNA_def_property_update(prop, 0, "rna_CacheLibrary_update");
+
+ prop = RNA_def_property(srna, "output_filepath", PROP_STRING, PROP_FILEPATH);
+ RNA_def_property_string_sdna(prop, NULL, "output_filepath");
+ RNA_def_property_ui_text(prop, "Output File Path", "Path where cache output is written");
+ RNA_def_property_update(prop, 0, "rna_CacheLibrary_update");
+
+ prop = RNA_def_property(srna, "source_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "source_mode");
+ RNA_def_property_enum_items(prop, source_mode_items);
+ RNA_def_property_ui_text(prop, "Source Mode", "Source of the cache library data");
+ RNA_def_property_update(prop, 0, "rna_CacheLibrary_update");
+
+ prop = RNA_def_property(srna, "display_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "display_mode");
+ RNA_def_property_enum_items(prop, display_mode_items);
+ RNA_def_property_ui_text(prop, "Display Mode", "What data to display in the viewport");
+ RNA_def_property_update(prop, 0, "rna_CacheLibrary_update");
+
+ prop = RNA_def_property(srna, "display_motion", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "display_flag", CACHE_LIBRARY_DISPLAY_MOTION);
+ RNA_def_property_ui_text(prop, "Display Motion", "Display motion state result from simulation, if available");
+ RNA_def_property_update(prop, 0, "rna_CacheLibrary_update");
+
+ prop = RNA_def_property(srna, "display_children", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "display_flag", CACHE_LIBRARY_DISPLAY_CHILDREN);
+ RNA_def_property_ui_text(prop, "Display Children", "Display child strands, if available");
+ RNA_def_property_update(prop, 0, "rna_CacheLibrary_update");
+
+ prop = RNA_def_property(srna, "data_types", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "data_types");
+ RNA_def_property_enum_items(prop, cache_library_data_type_items);
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+ RNA_def_property_ui_text(prop, "Data Types", "Types of data to store in the cache");
+
+ prop = RNA_def_property(srna, "filter_group", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "filter_group");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Filter Group", "If set, only objects in this group will be cached");
+
+ prop = RNA_def_property(srna, "description", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Description", "Description of the output archive");
+
+ /* modifiers */
+ prop = RNA_def_property(srna, "modifiers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "CacheLibraryModifier");
+ RNA_def_property_ui_text(prop, "Modifiers", "Modifiers applying to the cached data");
+ rna_def_cache_library_modifiers(brna, prop);
+
+ prop = RNA_def_property(srna, "archive_info", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "CacheArchiveInfo");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Archive Info", "Information about structure and contents of the archive");
+}
+
+static void rna_def_cache_archive_info_node(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem type_items[] = {
+ {eCacheArchiveInfoNode_Type_Object, "OBJECT", 0, "Object", "Structural object node forming the hierarchy"},
+ {eCacheArchiveInfoNode_Type_ScalarProperty, "SCALAR_PROPERTY", 0, "Scalar Property", "Property with a single value per sample"},
+ {eCacheArchiveInfoNode_Type_ArrayProperty, "ARRAY_PROPERTY", 0, "Array Property", "Array property with an arbitrary number of values per sample"},
+ {eCacheArchiveInfoNode_Type_CompoundProperty, "COMPOUND_PROPERTY", 0, "Compound Property", "Compound property containing other properties"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "CacheArchiveInfoNode", NULL);
+ RNA_def_struct_ui_text(srna, "Cache Archive Info Node", "Node in the structure of a cache archive");
+
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, type_items);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Type", "Type of archive node");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Name", "Name of the archive node");
+ RNA_def_struct_name_property(srna, prop);
+
+ prop = RNA_def_property(srna, "child_nodes", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "CacheArchiveInfoNode");
+ RNA_def_property_ui_text(prop, "Child Nodes", "Nested archive nodes");
+
+ prop = RNA_def_property(srna, "expand", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", eCacheArchiveInfoNode_Flag_Expand);
+ RNA_def_property_ui_text(prop, "Expand", "Show contents of the node");
+ RNA_def_property_update(prop, 0, "rna_CacheArchiveInfo_update");
+
+ /* XXX this is a 64bit integer, not supported nicely by RNA,
+ * but string encoding is sufficient for feedback
+ */
+ prop = RNA_def_property(srna, "bytes_size", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, "rna_CacheArchiveInfoNode_bytes_size_get", "rna_CacheArchiveInfoNode_bytes_size_length", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Bytes Size", "Overall size of the node data in bytes");
+
+ prop = RNA_def_property(srna, "datatype", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "datatype_name");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Datatype", "Type of values stored in the property");
+
+ prop = RNA_def_property(srna, "datatype_extent", PROP_INT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Datatype Extent", "Array extent of a single data element");
+
+ prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "num_samples");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Samples", "Number of samples stored for the property");
+
+ prop = RNA_def_property(srna, "array_size", PROP_INT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Array Size", "Maximum array size for any sample of the property");
+}
+
+static void rna_def_cache_archive_info(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "CacheArchiveInfo", NULL);
+ RNA_def_struct_ui_text(srna, "Cache Archive Info", "Information about structure and contents of a cache file");
+
+ prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "File Path", "Path to the cache archive");
+
+ prop = RNA_def_property(srna, "app_name", PROP_STRING, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Application", "Name of the application that created the archive");
+
+ prop = RNA_def_property(srna, "date_written", PROP_STRING, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Date", "Date and time when the archive was created");
+
+ prop = RNA_def_property(srna, "description", PROP_STRING, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Description", "Description of the archive");
+
+ prop = RNA_def_property(srna, "root_node", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "CacheArchiveInfoNode");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Root Node", "Root node of the archive");
+}
+
+void RNA_def_cache_library(BlenderRNA *brna)
+{
+ rna_def_cache_modifier(brna);
+ rna_def_cache_library(brna);
+ rna_def_cache_archive_info_node(brna);
+ rna_def_cache_archive_info(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index 31e991dd2b6..16f74a05f7b 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -87,8 +87,74 @@ static void rna_Camera_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointer
DAG_id_tag_update(&camera->id, 0);
}
+static void rna_Camera_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ Camera *camera = (Camera *)ptr->id.data;
+ DAG_relations_tag_update(bmain);
+ DAG_id_tag_update(&camera->id, 0);
+}
+
#else
+static void rna_def_camera_stereo_data(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem convergence_mode_items[] = {
+ {CAM_S3D_OFFAXIS, "OFFAXIS", 0, "Off-Axis", "Off-axis frustums converging in a plane"},
+ {CAM_S3D_PARALLEL, "PARALLEL", 0, "Parallel", "Parallel cameras with no convergence"},
+ {CAM_S3D_TOE, "TOE", 0, "Toe-in", "Rotated cameras, looking at the convergence distance"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem pivot_items[] = {
+ {CAM_S3D_PIVOT_LEFT, "LEFT", 0, "Left", ""},
+ {CAM_S3D_PIVOT_RIGHT, "RIGHT", 0, "Right", ""},
+ {CAM_S3D_PIVOT_CENTER, "CENTER", 0, "Center", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "CameraStereoData", NULL);
+ RNA_def_struct_sdna(srna, "CameraStereoSettings");
+ RNA_def_struct_nested(brna, srna, "Camera");
+ RNA_def_struct_ui_text(srna, "Stereo", "Stereoscopy settings for a Camera datablock");
+
+ prop = RNA_def_property(srna, "convergence_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, convergence_mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "pivot", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, pivot_items);
+ RNA_def_property_ui_text(prop, "Pivot", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "interocular_distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_range(prop, 0.0f, 100.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.f, 1, 2);
+ RNA_def_property_ui_text(prop, "Interocular Distance",
+ "Set the distance between the eyes - the stereo plane distance / 30 should be fine");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "convergence_distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_range(prop, 0.00001f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 15.f, 1, 2);
+ RNA_def_property_ui_text(prop, "Convergence Plane Distance",
+ "The converge point for the stereo cameras "
+ "(often the distance between a projector and the projection screen)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "viewport_convergence", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "convergence_distance");
+ RNA_def_property_range(prop, 0.00001f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 15.f, 1, 2);
+ RNA_def_property_ui_text(prop, "Viewport Convergence",
+ "Preview convergence distance for the stereo effect in the viewport "
+ "(it does not affect the render!)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+}
+
void RNA_def_camera(BlenderRNA *brna)
{
StructRNA *srna;
@@ -241,6 +307,13 @@ void RNA_def_camera(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "DOF Distance", "Distance to the focus point for depth of field");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ /* Stereo Settings */
+ prop = RNA_def_property(srna, "stereo", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "stereo");
+ RNA_def_property_struct_type(prop, "CameraStereoData");
+ RNA_def_property_ui_text(prop, "Stereo", "");
+
/* flag */
prop = RNA_def_property(srna, "show_limits", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOWLIMITS);
@@ -265,7 +338,8 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_safe_center", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOW_SAFE_CENTER);
- RNA_def_property_ui_text(prop, "Show Center-cut safe areas", "Show safe areas to fit content in a different aspect ratio");
+ RNA_def_property_ui_text(prop, "Show Center-cut safe areas",
+ "Show safe areas to fit content in a different aspect ratio");
RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
prop = RNA_def_property(srna, "show_name", PROP_BOOLEAN, PROP_NONE);
@@ -289,7 +363,7 @@ void RNA_def_camera(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "dof_ob");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "DOF Object", "Use this object to define the depth of field focal point");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dependency_update");
prop = RNA_def_property(srna, "gpu_dof", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "GPUDOFSettings");
@@ -298,6 +372,12 @@ void RNA_def_camera(BlenderRNA *brna)
rna_def_animdata_common(srna);
+ /* Nested Data */
+ RNA_define_animate_sdna(true);
+
+ /* *** Animated *** */
+ rna_def_camera_stereo_data(brna);
+
/* Camera API */
RNA_api_camera(srna);
}
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 5e114a51ceb..8ea67a34fbb 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -447,6 +447,7 @@ static void rna_ColorManagedDisplaySettings_display_device_update(Main *UNUSED(b
IMB_colormanagement_validate_settings(&scene->display_settings, &scene->view_settings);
+ DAG_id_tag_update(id, 0);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL);
}
}
@@ -619,10 +620,8 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *UNUSED(bmain)
}
if (seq_found) {
- if (seq->anim) {
- IMB_free_anim(seq->anim);
- seq->anim = NULL;
- }
+ BKE_sequence_free_anim(seq);
+
if (seq->strip->proxy && seq->strip->proxy->anim) {
IMB_free_anim(seq->strip->proxy->anim);
seq->strip->proxy->anim = NULL;
@@ -634,10 +633,7 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *UNUSED(bmain)
else {
SEQ_BEGIN(scene->ed, seq);
{
- if (seq->anim) {
- IMB_free_anim(seq->anim);
- seq->anim = NULL;
- }
+ BKE_sequence_free_anim(seq);
}
SEQ_END;
@@ -677,7 +673,7 @@ static void rna_ColorManagement_update(Main *UNUSED(bmain), Scene *UNUSED(scene)
static float rna_CurveMap_evaluateF(struct CurveMap *cuma, ReportList *reports, float value)
{
if (!cuma->table) {
- BKE_reportf(reports, RPT_ERROR, "CurveMap table not initialized, call initialize() on CurveMapping owner of the CurveMap");
+ BKE_report(reports, RPT_ERROR, "CurveMap table not initialized, call initialize() on CurveMapping owner of the CurveMap");
return 0.0f;
}
return curvemap_evaluateF(cuma, value);
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index aaacf07567e..abc489bb9b0 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -241,7 +241,7 @@ static void rna_Constraint_name_set(PointerRNA *ptr, const char *value)
}
/* fix all the animation data which may link to this */
- BKE_all_animdata_fix_paths_rename(NULL, "constraints", oldname, con->name);
+ BKE_animdata_fix_paths_rename_all(NULL, "constraints", oldname, con->name);
}
static char *rna_Constraint_path(PointerRNA *ptr)
@@ -271,12 +271,12 @@ static char *rna_Constraint_path(PointerRNA *ptr)
static void rna_Constraint_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- ED_object_constraint_update(ptr->id.data);
+ ED_object_constraint_tag_update(ptr->id.data, ptr->data);
}
static void rna_Constraint_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
- ED_object_constraint_dependency_update(bmain, ptr->id.data);
+ ED_object_constraint_dependency_tag_update(bmain, ptr->id.data, ptr->data);
}
static void rna_Constraint_influence_update(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -323,7 +323,7 @@ static EnumPropertyItem *rna_Constraint_target_space_itemf(bContext *UNUSED(C),
PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
{
bConstraint *con = (bConstraint *)ptr->data;
- bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
@@ -1357,7 +1357,8 @@ static void rna_def_constraint_stretch_to(BlenderRNA *brna)
prop = RNA_def_property(srna, "rest_length", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "orglength");
- RNA_def_property_range(prop, 0.0, 100.f);
+ RNA_def_property_range(prop, 0.0, 1000.f);
+ RNA_def_property_ui_range(prop, 0, 100.0f, 10, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(prop, "Original Length", "Length at rest position");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c
index d7a679e9702..a512f1d750f 100644
--- a/source/blender/makesrna/intern/rna_context.c
+++ b/source/blender/makesrna/intern/rna_context.c
@@ -148,6 +148,7 @@ void RNA_def_context(BlenderRNA *brna)
{CTX_MODE_PAINT_VERTEX, "PAINT_VERTEX", 0, "Vertex Paint", ""},
{CTX_MODE_PAINT_TEXTURE, "PAINT_TEXTURE", 0, "Texture Paint", ""},
{CTX_MODE_PARTICLE, "PARTICLE", 0, "Particle", ""},
+ {CTX_MODE_HAIR, "HAIR", 0, "Hair", ""},
{CTX_MODE_OBJECT, "OBJECT", 0, "Object", ""},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_controller.c b/source/blender/makesrna/intern/rna_controller.c
index ba0214d36ec..605e28653f9 100644
--- a/source/blender/makesrna/intern/rna_controller.c
+++ b/source/blender/makesrna/intern/rna_controller.c
@@ -120,7 +120,7 @@ static int rna_Controller_state_number_get(struct PointerRNA *ptr)
int bit;
for (bit = 0; bit < 32; bit++) {
- if (cont->state_mask & (1 << bit))
+ if (cont->state_mask & (1u << bit))
return bit + 1;
}
return 0;
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index 29f1dd5f29f..9a9ac28a7fd 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -1300,16 +1300,13 @@ static void rna_def_curve_splines(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
func = RNA_def_function(srna, "clear", "rna_Curve_spline_clear");
- RNA_def_function_ui_description(func, "Remove all spline from a curve");
+ RNA_def_function_ui_description(func, "Remove all splines from a curve");
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_struct_type(prop, "Spline");
RNA_def_property_pointer_funcs(prop, "rna_Curve_active_spline_get", "rna_Curve_active_spline_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Active Spline", "Active curve spline");
- /* Could call: ED_base_object_activate(C, scene->basact);
- * but would be a bad level call and it seems the notifier is enough */
- RNA_def_property_update(prop, NC_SCENE | ND_OB_ACTIVE, NULL);
}
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 6a0ae0a60f8..dd2a49c8380 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -3411,7 +3411,7 @@ static void rna_def_property_free(StructOrFunctionRNA *cont_, PropertyRNA *prop)
if (prop->flag & PROP_RUNTIME) {
if (cont->prophash)
- BLI_ghash_remove(cont->prophash, (void *)prop->identifier, NULL, NULL);
+ BLI_ghash_remove(cont->prophash, prop->identifier, NULL, NULL);
RNA_def_property_free_pointers(prop);
rna_freelinkN(&cont->properties, prop);
diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c
new file mode 100644
index 00000000000..8ac1e2acc60
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_depsgraph.c
@@ -0,0 +1,112 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Foundation (2014).
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_depsgraph.c
+ * \ingroup RNA
+ */
+
+#include <stdlib.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_path_util.h"
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#include "DEG_depsgraph.h"
+
+#include "BKE_depsgraph.h"
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_report.h"
+
+#include "DEG_depsgraph_debug.h"
+
+static void rna_Depsgraph_debug_graphviz(Depsgraph *graph, const char *filename)
+{
+ FILE *f = fopen(filename, "w");
+ if (f == NULL)
+ return;
+
+ DEG_debug_graphviz(graph, f, "Depsgraph", false);
+
+ fclose(f);
+}
+
+static void rna_Depsgraph_debug_rebuild(Depsgraph *UNUSED(graph), Main *bmain)
+{
+ Scene *sce;
+ DAG_relations_tag_update(bmain);
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
+ DAG_scene_relations_rebuild(bmain, sce);
+ DEG_graph_on_visible_update(bmain, sce);
+ }
+}
+
+static void rna_Depsgraph_debug_stats(Depsgraph *graph, ReportList *reports)
+{
+ size_t outer, ops, rels;
+
+ DEG_stats_simple(graph, &outer, &ops, &rels);
+
+ // XXX: report doesn't seem to work
+ printf("Approx %lu Operations, %lu Relations, %lu Outer Nodes\n",
+ ops, rels, outer);
+
+ BKE_reportf(reports, RPT_WARNING, "Approx. %lu Operations, %lu Relations, %lu Outer Nodes",
+ ops, rels, outer);
+}
+
+#else
+
+static void rna_def_depsgraph(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ srna = RNA_def_struct(brna, "Depsgraph", NULL);
+ RNA_def_struct_ui_text(srna, "Dependency Graph", "");
+
+ func = RNA_def_function(srna, "debug_graphviz", "rna_Depsgraph_debug_graphviz");
+ parm = RNA_def_string_file_path(func, "filename", NULL, FILE_MAX, "File Name",
+ "File in which to store graphviz debug output");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+
+ func = RNA_def_function(srna, "debug_rebuild", "rna_Depsgraph_debug_rebuild");
+ RNA_def_function_flag(func, FUNC_USE_MAIN);
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+
+ func = RNA_def_function(srna, "debug_stats", "rna_Depsgraph_debug_stats");
+ RNA_def_function_ui_description(func, "Report the number of elements in the Dependency Graph");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+}
+
+void RNA_def_depsgraph(BlenderRNA *brna)
+{
+ rna_def_depsgraph(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 6c893255601..576af7b3a1c 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -574,7 +574,7 @@ static void rna_FModifier_blending_range(PointerRNA *ptr, float *min, float *max
static void rna_FModifier_verify_data_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
FModifier *fcm = (FModifier *)ptr->data;
- FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
/* call the verify callback on the modifier if applicable */
if (fmi && fmi->verify_data)
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 6b61b37ce5c..7d7df0f91a7 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -568,7 +568,7 @@ static void rna_def_gpencil_frame(BlenderRNA *brna)
prop = RNA_def_property(srna, "frame_number", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "framenum");
/* XXX note: this cannot occur on the same frame as another sketch */
- RNA_def_property_range(prop, MINAFRAME, MAXFRAME);
+ RNA_def_property_range(prop, -MAXFRAME, MAXFRAME);
RNA_def_property_ui_text(prop, "Frame Number", "The frame on which this sketch appears");
/* Flags */
@@ -579,7 +579,9 @@ static void rna_def_gpencil_frame(BlenderRNA *brna)
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_FRAME_SELECT);
RNA_def_property_ui_text(prop, "Select", "Frame is selected for editing in the Dope Sheet");
-
+
+
+ /* API */
func = RNA_def_function(srna, "clear", "rna_GPencil_frame_clear");
RNA_def_function_ui_description(func, "Remove all the grease pencil frame data");
}
@@ -773,8 +775,8 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_points", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_DRAWDEBUG);
RNA_def_property_ui_text(prop, "Show Points", "Draw the points which make up the strokes (for debugging purposes)");
- RNA_def_property_update_runtime(prop, "rna_GPencil_update");
-
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
/* X-Ray */
prop = RNA_def_property(srna, "show_x_ray", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GP_LAYER_NO_XRAY);
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 5ab6d1a231b..8b464e74569 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -35,6 +35,7 @@
#include "BKE_depsgraph.h"
#include "BKE_image.h"
+#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -137,6 +138,23 @@ static void rna_Image_colormanage_update(Main *UNUSED(bmain), Scene *UNUSED(scen
WM_main_add_notifier(NC_IMAGE | NA_EDITED, &ima->id);
}
+static void rna_Image_views_format_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+{
+ Image *ima = ptr->id.data;
+ ImBuf *ibuf;
+ void *lock;
+
+ ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
+
+ if (ibuf) {
+ ImageUser iuser = {NULL};
+ iuser.scene = scene;
+ BKE_image_signal(ima, &iuser, IMA_SIGNAL_FREE);
+ }
+
+ BKE_image_release_ibuf(ima, ibuf, lock);
+}
+
static void rna_ImageUser_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
{
ImageUser *iuser = ptr->data;
@@ -295,17 +313,16 @@ static int rna_Image_frame_duration_get(PointerRNA *ptr)
Image *ima = ptr->id.data;
int duration = 1;
- if (!ima->anim) {
+ if (BKE_image_has_anim(ima)) {
+ duration = IMB_anim_get_duration(((ImageAnim *)ima->anims.first)->anim, IMB_TC_RECORD_RUN);
+ }
+ else {
/* acquire ensures ima->anim is set, if possible! */
void *lock;
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
BKE_image_release_ibuf(ima, ibuf, lock);
}
- if (ima->anim) {
- duration = IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN);
- }
-
return duration;
}
@@ -409,6 +426,19 @@ static int rna_Image_is_float_get(PointerRNA *ptr)
return is_float;
}
+static PointerRNA rna_Image_packed_file_get(PointerRNA *ptr)
+{
+ Image *ima = (Image *)ptr->id.data;
+
+ if (BKE_image_has_packedfile(ima)) {
+ ImagePackedFile *imapf = ima->packedfiles.first;
+ return rna_pointer_inherit_refine(ptr, &RNA_PackedFile, imapf->packedfile);
+ }
+ else {
+ return PointerRNA_NULL;
+ }
+}
+
static void rna_Image_render_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Image *image = (Image *)ptr->id.data;
@@ -508,10 +538,31 @@ static void rna_def_imageuser(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* image_multi_cb */
RNA_def_property_ui_text(prop, "Layer", "Layer in multilayer image");
- prop = RNA_def_property(srna, "multilayer_pass", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "pass");
+ prop = RNA_def_property(srna, "multilayer_view", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "view");
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* image_multi_cb */
- RNA_def_property_ui_text(prop, "Pass", "Pass in multilayer image");
+ RNA_def_property_ui_text(prop, "View", "View in multilayer image");
+}
+
+/* image.packed_files */
+static void rna_def_image_packed_files(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ImagePackedFile", NULL);
+ RNA_def_struct_sdna(srna, "ImagePackedFile");
+
+ 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", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
+ RNA_def_property_string_sdna(prop, NULL, "filepath");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
static void rna_def_render_slot(BlenderRNA *brna)
@@ -613,15 +664,23 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
prop = RNA_def_property(srna, "packed_file", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "PackedFile");
RNA_def_property_pointer_sdna(prop, NULL, "packedfile");
- RNA_def_property_ui_text(prop, "Packed File", "");
-
+ RNA_def_property_pointer_funcs(prop, "rna_Image_packed_file_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Packed File", "First packed file of the image");
+
+ prop = RNA_def_property(srna, "packed_files", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "packedfiles", NULL);
+ RNA_def_property_struct_type(prop, "ImagePackedFile");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Packed Files", "Collection of packed images");
+
prop = RNA_def_property(srna, "field_order", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, prop_field_order_items);
RNA_def_property_ui_text(prop, "Field Order", "Order of video fields (select which lines are displayed first)");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
-
+
/* booleans */
prop = RNA_def_property(srna, "use_fields", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_FIELDS);
@@ -645,6 +704,21 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Deinterlace", "Deinterlace movie file on load");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_reload_update");
+ prop = RNA_def_property(srna, "use_multiview", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_USE_VIEWS);
+ RNA_def_property_ui_text(prop, "Use Multi-View", "Use Multiple Views (when available)");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_views_format_update");
+
+ prop = RNA_def_property(srna, "is_stereo_3d", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_IS_STEREO);
+ RNA_def_property_ui_text(prop, "Stereo 3D", "Image has left and right views");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "is_multiview", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_IS_MULTIVIEW);
+ RNA_def_property_ui_text(prop, "Multiple Views", "Image has more than one view");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
prop = RNA_def_property(srna, "is_dirty", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_Image_dirty_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -709,13 +783,13 @@ static void rna_def_image(BlenderRNA *brna)
prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "twsta");
- RNA_def_property_range(prop, 0, 128);
+ RNA_def_property_range(prop, 0, 255);
RNA_def_property_ui_text(prop, "Animation Start", "Start frame of an animated texture");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_animated_update");
prop = RNA_def_property(srna, "frame_end", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "twend");
- RNA_def_property_range(prop, 0, 128);
+ RNA_def_property_range(prop, 0, 255);
RNA_def_property_ui_text(prop, "Animation End", "End frame of an animated texture");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_animated_update");
@@ -825,6 +899,19 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Alpha Mode", "Representation of alpha information in the RGBA pixels");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update");
+ /* multiview */
+ prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "views_format");
+ RNA_def_property_enum_items(prop, views_format_items);
+ RNA_def_property_ui_text(prop, "Views Format", "Mode to load image views");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_views_format_update");
+
+ prop = RNA_def_property(srna, "stereo_3d_format", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "stereo3d_format");
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "Stereo3dFormat");
+ RNA_def_property_ui_text(prop, "Stereo 3D Format", "Settings for stereo 3d");
+
RNA_api_image(srna);
}
@@ -834,6 +921,7 @@ void RNA_def_image(BlenderRNA *brna)
rna_def_render_slots(brna);
rna_def_image(brna);
rna_def_imageuser(brna);
+ rna_def_image_packed_files(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 5fc65ea385c..945359515ab 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -35,6 +35,7 @@
#include <time.h>
#include "DNA_packedFile_types.h"
+#include "DNA_userdef_types.h"
#include "BLI_utildefines.h"
#include "BLI_path_util.h"
@@ -57,6 +58,7 @@
#include "BIF_gl.h"
#include "GPU_draw.h"
+#include "GPU_debug.h"
#include "DNA_image_types.h"
#include "DNA_scene_types.h"
@@ -72,7 +74,7 @@ static void rna_Image_save_render(Image *image, bContext *C, ReportList *reports
}
if (scene) {
- ImageUser iuser = {0};
+ ImageUser iuser = {NULL};
void *lock;
iuser.scene = scene;
@@ -115,9 +117,14 @@ static void rna_Image_save(Image *image, Main *bmain, bContext *C, ReportList *r
BLI_strncpy(filename, image->name, sizeof(filename));
BLI_path_abs(filename, ID_BLEND_PATH(bmain, &image->id));
- if (image->packedfile) {
- if (writePackedFile(reports, image->name, image->packedfile, 0) != RET_OK) {
- BKE_reportf(reports, RPT_ERROR, "Image '%s' could not save packed file to '%s'", image->id.name + 2, image->name);
+ if (BKE_image_has_packedfile(image)) {
+ ImagePackedFile *imapf;
+
+ for (imapf = image->packedfiles.first; imapf; imapf = imapf->next) {
+ if (writePackedFile(reports, imapf->filepath, imapf->packedfile, 0) != RET_OK) {
+ BKE_reportf(reports, RPT_ERROR, "Image '%s' could not save packed file to '%s'",
+ image->id.name + 2, imapf->filepath);
+ }
}
}
else if (IMB_saveiff(ibuf, filename, ibuf->flags)) {
@@ -152,20 +159,17 @@ static void rna_Image_pack(
BKE_report(reports, RPT_ERROR, "Cannot pack edited image from disk, only as internal PNG");
}
else {
- if (image->packedfile) {
- freePackedFile(image->packedfile);
- image->packedfile = NULL;
- }
+ BKE_image_free_packedfiles(image);
if (as_png) {
BKE_image_memorypack(image);
}
else if (data) {
char *data_dup = MEM_mallocN(sizeof(*data_dup) * (size_t)data_len, __func__);
memcpy(data_dup, data, (size_t)data_len);
- image->packedfile = newPackedFileMemory(data_dup, data_len);
+ BKE_image_packfiles_from_mem(reports, image, data_dup, (size_t)data_len);
}
else {
- image->packedfile = newPackedFile(reports, image->name, ID_BLEND_PATH(bmain, &image->id));
+ BKE_image_packfiles(reports, image, ID_BLEND_PATH(bmain, &image->id));
}
}
@@ -175,7 +179,7 @@ static void rna_Image_pack(
static void rna_Image_unpack(Image *image, ReportList *reports, int method)
{
- if (!image->packedfile) {
+ if (!BKE_image_has_packedfile(image)) {
BKE_report(reports, RPT_ERROR, "Image not packed");
}
else if (BKE_image_is_animated(image)) {
@@ -232,31 +236,23 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int f
ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
+ /* clean glError buffer */
+ while (glGetError() != GL_NO_ERROR) {}
+
if (ibuf == NULL || ibuf->rect == NULL) {
BKE_reportf(reports, RPT_ERROR, "Image '%s' does not have any image data", image->id.name + 2);
BKE_image_release_ibuf(image, ibuf, NULL);
return (int)GL_INVALID_OPERATION;
}
- /* could be made into a function? */
- glGenTextures(1, (GLuint *)bind);
- glBindTexture(GL_TEXTURE_2D, *bind);
+ GPU_create_gl_tex(bind, ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y,
+ (filter != GL_NEAREST && filter != GL_LINEAR), false, image);
- if (filter != GL_NEAREST && filter != GL_LINEAR)
- error = (int)gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLint)filter);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLint)mag);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- if (!error) {
- /* clean glError buffer */
- while (glGetError() != GL_NO_ERROR) {}
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, image->tpageflag & IMA_CLAMP_U ? GL_CLAMP : GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, image->tpageflag & IMA_CLAMP_V ? GL_CLAMP : GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLint)filter);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLint)mag);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ibuf->x, ibuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
- error = (int)glGetError();
- }
+ error = glGetError();
if (error) {
glDeleteTextures(1, (GLuint *)bind);
@@ -294,6 +290,11 @@ static void rna_Image_filepath_from_user(Image *image, ImageUser *image_user, ch
BKE_image_user_file_path(image_user, image, filepath);
}
+static void rna_Image_buffers_free(Image *image)
+{
+ BKE_image_free_buffers(image);
+}
+
#else
void RNA_api_image(StructRNA *srna)
@@ -380,6 +381,9 @@ void RNA_api_image(StructRNA *srna)
RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */
RNA_def_function_output(func, parm);
+ func = RNA_def_function(srna, "buffers_free", "rna_Image_buffers_free");
+ RNA_def_function_ui_description(func, "Free the image buffers from memory");
+
/* TODO, pack/unpack, maybe should be generic functions? */
}
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index ef3144f65de..62fe71fe8a5 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -35,16 +35,13 @@
#define RNA_MAGIC ((int)~0)
-struct ColorBand;
struct ID;
struct IDProperty;
struct Main;
struct Mesh;
struct Object;
-struct RenderEngine;
struct ReportList;
struct SDNA;
-struct Sequence;
/* Data structures used during define */
@@ -136,6 +133,7 @@ void RNA_def_armature(struct BlenderRNA *brna);
void RNA_def_actuator(struct BlenderRNA *brna);
void RNA_def_boid(struct BlenderRNA *brna);
void RNA_def_brush(struct BlenderRNA *brna);
+void RNA_def_cache_library(struct BlenderRNA *brna);
void RNA_def_camera(struct BlenderRNA *brna);
void RNA_def_cloth(struct BlenderRNA *brna);
void RNA_def_color(struct BlenderRNA *brna);
@@ -143,6 +141,7 @@ void RNA_def_constraint(struct BlenderRNA *brna);
void RNA_def_context(struct BlenderRNA *brna);
void RNA_def_controller(struct BlenderRNA *brna);
void RNA_def_curve(struct BlenderRNA *brna);
+void RNA_def_depsgraph(struct BlenderRNA *brna);
void RNA_def_dynamic_paint(struct BlenderRNA *brna);
void RNA_def_fluidsim(struct BlenderRNA *brna);
void RNA_def_fcurve(struct BlenderRNA *brna);
@@ -157,6 +156,7 @@ void RNA_def_linestyle(struct BlenderRNA *brna);
void RNA_def_main(struct BlenderRNA *brna);
void RNA_def_material(struct BlenderRNA *brna);
void RNA_def_mesh(struct BlenderRNA *brna);
+void RNA_def_mesh_sample(struct BlenderRNA *brna);
void RNA_def_meta(struct BlenderRNA *brna);
void RNA_def_modifier(struct BlenderRNA *brna);
void RNA_def_nla(struct BlenderRNA *brna);
@@ -164,6 +164,7 @@ void RNA_def_nodetree(struct BlenderRNA *brna);
void RNA_def_object(struct BlenderRNA *brna);
void RNA_def_object_force(struct BlenderRNA *brna);
void RNA_def_packedfile(struct BlenderRNA *brna);
+void RNA_def_palette(struct BlenderRNA *brna);
void RNA_def_particle(struct BlenderRNA *brna);
void RNA_def_pose(struct BlenderRNA *brna);
void RNA_def_render(struct BlenderRNA *brna);
@@ -177,6 +178,7 @@ void RNA_def_sequencer(struct BlenderRNA *brna);
void RNA_def_smoke(struct BlenderRNA *brna);
void RNA_def_space(struct BlenderRNA *brna);
void RNA_def_speaker(struct BlenderRNA *brna);
+void RNA_def_strands(struct BlenderRNA *brna);
void RNA_def_test(struct BlenderRNA *brna);
void RNA_def_text(struct BlenderRNA *brna);
void RNA_def_texture(struct BlenderRNA *brna);
@@ -327,10 +329,12 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop);
+void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop);
+void RNA_def_main_cache_libraries(BlenderRNA *brna, PropertyRNA *cprop);
/* ID Properties */
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index 845d76debd2..ba0705b5caa 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -38,10 +38,8 @@ struct StructRNA;
struct PropertyRNA;
struct PointerRNA;
struct FunctionRNA;
-struct ReportList;
struct CollectionPropertyIterator;
struct bContext;
-struct EnumProperty;
struct IDProperty;
struct GHash;
struct Main;
diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c
index fe62df57eed..b462729657c 100644
--- a/source/blender/makesrna/intern/rna_key.c
+++ b/source/blender/makesrna/intern/rna_key.c
@@ -48,10 +48,12 @@
#include <stddef.h>
+#include "DNA_cache_library_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BKE_animsys.h"
+#include "BKE_cache_library.h"
#include "BKE_depsgraph.h"
#include "BKE_key.h"
#include "BKE_main.h"
@@ -90,7 +92,7 @@ static void rna_ShapeKey_name_set(PointerRNA *ptr, const char *value)
}
/* fix all the animation data which may link to this */
- BKE_all_animdata_fix_paths_rename(NULL, "key_blocks", oldname, kb->name);
+ BKE_animdata_fix_paths_rename_all(NULL, "key_blocks", oldname, kb->name);
}
static float rna_ShapeKey_frame_get(PointerRNA *ptr)
@@ -304,7 +306,7 @@ static void rna_ShapeKey_data_begin(CollectionPropertyIterator *iter, PointerRNA
Nurb *nu;
int tot = kb->totelem, size = key->elemsize;
- if (key->from_extra.type == KEY_OWNER_CURVE) {
+ if (key->from && key->fromtype == KEY_OWNER_CURVE) {
cu = (Curve *)key->from;
nu = cu->nurb.first;
@@ -325,7 +327,7 @@ static int rna_ShapeKey_data_length(PointerRNA *ptr)
Nurb *nu;
int tot = kb->totelem;
- if (key->from_extra.type == KEY_OWNER_CURVE) {
+ if (key->from && key->fromtype == KEY_OWNER_CURVE) {
cu = (Curve *)key->from;
nu = cu->nurb.first;
@@ -343,7 +345,7 @@ static PointerRNA rna_ShapeKey_data_get(CollectionPropertyIterator *iter)
Curve *cu;
Nurb *nu;
- if (key->from_extra.type == KEY_OWNER_CURVE) {
+ if (key->from && key->fromtype == KEY_OWNER_CURVE) {
cu = (Curve *)key->from;
nu = cu->nurb.first;
@@ -376,8 +378,9 @@ static void rna_Key_update_data(Main *bmain, Scene *UNUSED(scene), PointerRNA *p
{
Key *key = ptr->id.data;
Object *ob;
+ CacheLibrary *cachelib;
- switch (key->from_extra.type) {
+ switch (key->fromtype) {
case KEY_OWNER_MESH:
case KEY_OWNER_CURVE:
case KEY_OWNER_LATTICE:
@@ -401,6 +404,13 @@ static void rna_Key_update_data(Main *bmain, Scene *UNUSED(scene), PointerRNA *p
}
break;
}
+
+ for (cachelib = bmain->cache_library.first; cachelib; cachelib = cachelib->id.next) {
+ if (BKE_cache_library_uses_key(cachelib, key)) {
+ DAG_id_tag_update(&cachelib->id, OB_RECALC_DATA);
+ WM_main_add_notifier(NC_WINDOW, NULL);
+ }
+ }
}
static KeyBlock *rna_ShapeKeyData_find_keyblock(Key *key, float *point)
diff --git a/source/blender/makesrna/intern/rna_lamp.c b/source/blender/makesrna/intern/rna_lamp.c
index 81c26af189d..6140a34b271 100644
--- a/source/blender/makesrna/intern/rna_lamp.c
+++ b/source/blender/makesrna/intern/rna_lamp.c
@@ -94,7 +94,7 @@ static int rna_use_shadow_get(PointerRNA *ptr)
Lamp *la = (Lamp *)ptr->data;
if (la->type == LA_SPOT) {
- return (la->mode & LA_SHAD_BUF) != 0;
+ return (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY)) != 0;
}
else {
return (la->mode & LA_SHAD_RAY) != 0;
@@ -104,14 +104,10 @@ static int rna_use_shadow_get(PointerRNA *ptr)
static void rna_use_shadow_set(PointerRNA *ptr, int value)
{
Lamp *la = (Lamp *)ptr->data;
+ la->mode &= ~(LA_SHAD_BUF | LA_SHAD_RAY);
if (value) {
- if (la->type == LA_SPOT)
- la->mode |= LA_SHAD_BUF;
- else
- la->mode |= LA_SHAD_RAY;
+ la->mode |= LA_SHAD_RAY;
}
- else
- la->mode &= ~(LA_SHAD_BUF | LA_SHAD_RAY);
}
static StructRNA *rna_Lamp_refine(struct PointerRNA *ptr)
@@ -829,6 +825,12 @@ static void rna_def_sun_lamp(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.001, 100.0, 2, 1);
RNA_def_property_ui_text(prop, "Frustum Size", "Size of the frustum used for creating the shadow map");
RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+
+ prop = RNA_def_property(srna, "show_shadow_box", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_SHOW_SHADOW_BOX);
+ RNA_def_property_ui_text(prop, "Show Shadow Box",
+ "Draw a box in 3D view to visualize which objects are contained in it");
+ RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
}
static void rna_def_hemi_lamp(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c
index 65d81359045..926c5db5ae6 100644
--- a/source/blender/makesrna/intern/rna_main.c
+++ b/source/blender/makesrna/intern/rna_main.c
@@ -251,6 +251,12 @@ static void rna_Main_particle_begin(CollectionPropertyIterator *iter, PointerRNA
rna_iterator_listbase_begin(iter, &bmain->particle, NULL);
}
+static void rna_Main_palettes_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Main *bmain = (Main *)ptr->data;
+ rna_iterator_listbase_begin(iter, &bmain->palettes, NULL);
+}
+
static void rna_Main_gpencil_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Main *bmain = (Main *)ptr->data;
@@ -281,6 +287,12 @@ static void rna_Main_linestyle_begin(CollectionPropertyIterator *iter, PointerRN
rna_iterator_listbase_begin(iter, &bmain->linestyle, NULL);
}
+static void rna_Main_cachelibraries_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Main *bmain = (Main *)ptr->data;
+ rna_iterator_listbase_begin(iter, &bmain->cache_library, NULL);
+}
+
static void rna_Main_version_get(PointerRNA *ptr, int *value)
{
Main *bmain = (Main *)ptr->data;
@@ -350,10 +362,12 @@ void RNA_def_main(BlenderRNA *brna)
{"armatures", "Armature", "rna_Main_armature_begin", "Armatures", "Armature datablocks", RNA_def_main_armatures},
{"actions", "Action", "rna_Main_action_begin", "Actions", "Action datablocks", RNA_def_main_actions},
{"particles", "ParticleSettings", "rna_Main_particle_begin", "Particles", "Particle datablocks", RNA_def_main_particles},
+ {"palettes", "Palette", "rna_Main_palettes_begin", "Palettes", "Palette datablocks", RNA_def_main_palettes},
{"grease_pencil", "GreasePencil", "rna_Main_gpencil_begin", "Grease Pencil", "Grease Pencil datablocks", RNA_def_main_gpencil},
{"movieclips", "MovieClip", "rna_Main_movieclips_begin", "Movie Clips", "Movie Clip datablocks", RNA_def_main_movieclips},
{"masks", "Mask", "rna_Main_masks_begin", "Masks", "Masks datablocks", RNA_def_main_masks},
{"linestyles", "FreestyleLineStyle", "rna_Main_linestyle_begin", "Line Styles", "Line Style datablocks", RNA_def_main_linestyles},
+ {"cache_libraries", "CacheLibrary", "rna_Main_cachelibraries_begin", "Cache Libraries", "Cache Library datablocks", RNA_def_main_cache_libraries},
{NULL, NULL, NULL, NULL, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index 8aa447f523e..b9b3bb519ca 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -35,6 +35,7 @@
#include "DNA_ID.h"
#include "DNA_modifier_types.h"
+#include "DNA_space_types.h"
#include "BLI_utildefines.h"
#include "BLI_path_util.h"
@@ -48,6 +49,8 @@
#ifdef RNA_RUNTIME
#include "BKE_main.h"
+#include "BKE_anim.h"
+#include "BKE_cache_library.h"
#include "BKE_camera.h"
#include "BKE_curve.h"
#include "BKE_DerivedMesh.h"
@@ -58,9 +61,11 @@
#include "BKE_library.h"
#include "BKE_object.h"
#include "BKE_material.h"
+#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_texture.h"
#include "BKE_scene.h"
+#include "BKE_sound.h"
#include "BKE_text.h"
#include "BKE_action.h"
#include "BKE_group.h"
@@ -69,6 +74,7 @@
#include "BKE_mball.h"
#include "BKE_world.h"
#include "BKE_particle.h"
+#include "BKE_paint.h"
#include "BKE_font.h"
#include "BKE_node.h"
#include "BKE_depsgraph.h"
@@ -79,6 +85,7 @@
#include "BKE_linestyle.h"
#include "DNA_armature_types.h"
+#include "DNA_cache_library_types.h"
#include "DNA_camera_types.h"
#include "DNA_curve_types.h"
#include "DNA_lamp_types.h"
@@ -86,6 +93,7 @@
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "DNA_speaker_types.h"
+#include "DNA_sound_types.h"
#include "DNA_text_types.h"
#include "DNA_texture_types.h"
#include "DNA_group_types.h"
@@ -307,6 +315,61 @@ Mesh *rna_Main_meshes_new_from_object(
return BKE_mesh_new_from_object(bmain, sce, ob, apply_modifiers, settings, calc_tessface, calc_undeformed);
}
+/* copied from Mesh_getFromObject and adapted to RNA interface */
+/* settings: 1 - preview, 2 - render */
+Mesh *rna_Main_meshes_new_from_dupli(
+ Main *bmain, ReportList *reports, Scene *scene, Object *parent, DupliObject *dob,
+ int settings, int calc_tessface, int calc_undeformed)
+{
+ Mesh *mesh = NULL;
+ bool is_cached = parent->cache_library && (parent->cache_library->source_mode == CACHE_LIBRARY_SOURCE_CACHE || parent->cache_library->display_mode == CACHE_LIBRARY_DISPLAY_RESULT);
+
+ switch (dob->ob->type) {
+ case OB_FONT:
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_MBALL:
+ case OB_MESH:
+ break;
+ default:
+ BKE_report(reports, RPT_ERROR, "Object does not have geometry data");
+ return NULL;
+ }
+
+ if (is_cached) {
+ float frame = (float)scene->r.cfra + scene->r.subframe;
+ bool use_render = (settings == 2);
+
+ if (!ELEM(settings, 1, 2))
+ return NULL;
+
+ if (settings == 1 && parent->dup_cache) {
+ DupliObjectData *data;
+
+ /* use dupli cache for realtime dupli data if possible */
+ data = BKE_dupli_cache_find_data(parent->dup_cache, dob->ob);
+ if (data)
+ mesh = BKE_mesh_new_from_dupli_data(bmain, data, calc_tessface, calc_undeformed);
+ }
+ else {
+ DupliObjectData data;
+
+ memset(&data, 0, sizeof(data));
+ if (BKE_cache_read_dupli_object(parent->cache_library, &data, scene, dob->ob, frame, use_render, true))
+ mesh = BKE_mesh_new_from_dupli_data(bmain, &data, calc_tessface, calc_undeformed);
+
+ BKE_dupli_object_data_clear(&data);
+ }
+ }
+
+ /* default, and fallback in case no mesh data was stored in the cache */
+ if (!mesh) {
+ mesh = BKE_mesh_new_from_object(bmain, scene, dob->ob, true, settings, calc_tessface, calc_undeformed);
+ }
+
+ return mesh;
+}
+
static void rna_Main_meshes_remove(Main *bmain, ReportList *reports, PointerRNA *mesh_ptr)
{
Mesh *mesh = mesh_ptr->data;
@@ -340,10 +403,10 @@ static void rna_Main_lamps_remove(Main *bmain, ReportList *reports, PointerRNA *
}
}
-static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int height, int alpha, int float_buffer)
+static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int height, int alpha, int float_buffer, int stereo3d)
{
float color[4] = {0.0, 0.0, 0.0, 1.0};
- Image *image = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, float_buffer, 0, color);
+ Image *image = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, float_buffer, 0, color, stereo3d);
id_us_min(&image->id);
return image;
}
@@ -460,8 +523,8 @@ static void rna_Main_fonts_remove(Main *bmain, ReportList *reports, PointerRNA *
static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type)
{
- Tex *tex = add_texture(bmain, name);
- tex_set_type(tex, type);
+ Tex *tex = BKE_texture_add(bmain, name);
+ BKE_texture_type_set(tex, type);
id_us_min(&tex->id);
return tex;
}
@@ -547,6 +610,25 @@ static void rna_Main_speakers_remove(Main *bmain, ReportList *reports, PointerRN
}
}
+static bSound *rna_Main_sounds_load(Main *bmain, const char *name)
+{
+ bSound *sound = BKE_sound_new_file(bmain, name);
+ id_us_min(&sound->id);
+ return sound;
+}
+static void rna_Main_sounds_remove(Main *bmain, ReportList *reports, PointerRNA *sound_ptr)
+{
+ Speaker *sound = sound_ptr->data;
+ if (ID_REAL_USERS(sound) <= 0) {
+ BKE_libblock_free(bmain, sound);
+ RNA_POINTER_INVALIDATE(sound_ptr);
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR, "Sound '%s' must have zero users to be removed, found %d",
+ sound->id.name + 2, ID_REAL_USERS(sound));
+ }
+}
+
static Text *rna_Main_texts_new(Main *bmain, const char *name)
{
return BKE_text_add(bmain, name);
@@ -631,6 +713,25 @@ static void rna_Main_particles_remove(Main *bmain, ReportList *reports, PointerR
}
}
+static Palette *rna_Main_palettes_new(Main *bmain, const char *name)
+{
+ Palette *palette = BKE_palette_add(bmain, name);
+ id_us_min(&palette->id);
+ return (Palette *)palette;
+}
+static void rna_Main_palettes_remove(Main *bmain, ReportList *reports, PointerRNA *palette_ptr)
+{
+ Palette *palette = palette_ptr->data;
+ if (ID_REAL_USERS(palette) <= 0) {
+ BKE_libblock_free(bmain, palette);
+ RNA_POINTER_INVALIDATE(palette_ptr);
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR, "Palette settings '%s' must have zero users to be removed, found %d",
+ palette->id.name + 2, ID_REAL_USERS(palette));
+ }
+}
+
static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, const char *filepath)
{
MovieClip *clip;
@@ -685,7 +786,7 @@ static void rna_Main_grease_pencil_remove(Main *bmain, ReportList *reports, Poin
static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name)
{
- FreestyleLineStyle *linestyle = BKE_linestyle_new(name, bmain);
+ FreestyleLineStyle *linestyle = BKE_linestyle_new(bmain, name);
id_us_min(&linestyle->id);
return linestyle;
}
@@ -701,6 +802,22 @@ static void rna_Main_linestyles_remove(Main *bmain, ReportList *reports, Freesty
/* XXX python now has invalid pointer? */
}
+static CacheLibrary *rna_Main_cachelibraries_new(Main *bmain, const char *name)
+{
+ CacheLibrary *cachelib = BKE_cache_library_add(bmain, name);
+ id_us_min(&cachelib->id);
+ return cachelib;
+}
+
+static void rna_Main_cachelibraries_remove(Main *bmain, ReportList *reports, CacheLibrary *cachelib)
+{
+ if (ID_REAL_USERS(cachelib) <= 0)
+ BKE_libblock_free(bmain, cachelib);
+ else
+ BKE_reportf(reports, RPT_ERROR, "Cache library '%s' must have zero users to be removed, found %d",
+ cachelib->id.name + 2, ID_REAL_USERS(cachelib));
+}
+
/* tag functions, all the same */
static void rna_Main_cameras_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->camera, value); }
static void rna_Main_scenes_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->scene, value); }
@@ -729,10 +846,12 @@ static void rna_Main_sounds_tag(Main *bmain, int value) { BKE_main_id_tag_listba
static void rna_Main_armatures_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->armature, value); }
static void rna_Main_actions_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->action, value); }
static void rna_Main_particles_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->particle, value); }
+static void rna_Main_palettes_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->palettes, value); }
static void rna_Main_gpencil_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->gpencil, value); }
static void rna_Main_movieclips_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->movieclip, value); }
static void rna_Main_masks_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->mask, value); }
static void rna_Main_linestyle_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->linestyle, value); }
+static void rna_Main_cachelibraries_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->cache_library, value); }
static int rna_Main_cameras_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_CA) != 0; }
static int rna_Main_scenes_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_SCE) != 0; }
@@ -759,16 +878,19 @@ static int rna_Main_sounds_is_updated_get(PointerRNA *ptr) { return DAG_id_type_
static int rna_Main_armatures_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_AR) != 0; }
static int rna_Main_actions_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_AC) != 0; }
static int rna_Main_particles_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_PA) != 0; }
+static int rna_Main_palettes_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_PAL) != 0; }
static int rna_Main_gpencil_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_GD) != 0; }
static int rna_Main_linestyle_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_LS) != 0; }
+static int rna_Main_cachelibraries_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_CL) != 0; }
#else
-void RNA_api_main(StructRNA *srna)
+void RNA_api_main(StructRNA *UNUSED(srna))
{
#if 0
FunctionRNA *func;
PropertyRNA *parm;
+
/* maybe we want to add functions in 'bpy.data' still?
* for now they are all in collections bpy.data.images.new(...) */
func = RNA_def_function(srna, "add_image", "rna_Main_add_image");
@@ -777,8 +899,6 @@ void RNA_api_main(StructRNA *srna)
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_pointer(func, "image", "Image", "", "New image");
RNA_def_function_return(func, parm);
-#else
- (void)srna;
#endif
}
@@ -1015,6 +1135,23 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
"Mesh created from object, remove it if it is only used for export");
RNA_def_function_return(func, parm);
+ func = RNA_def_function(srna, "new_from_dupli", "rna_Main_meshes_new_from_dupli");
+ RNA_def_function_ui_description(func, "Add a new mesh created from dupli cache data");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene within which to evaluate modifiers");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ parm = RNA_def_pointer(func, "parent", "Object", "", "Duplicator parent of the object");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ parm = RNA_def_pointer(func, "dupli_object", "DupliObject", "", "Dupli Object to create mesh from");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_boolean(func, "calc_tessface", true, "Calculate Tessellation", "Calculate tessellation faces");
+ RNA_def_boolean(func, "calc_undeformed", false, "Calculate Undeformed", "Calculate undeformed vertex coordinates");
+ parm = RNA_def_pointer(func, "mesh", "Mesh", "",
+ "Mesh created from object, remove it if it is only used for export");
+ RNA_def_function_return(func, parm);
+
func = RNA_def_function(srna, "remove", "rna_Main_meshes_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a mesh from the current blendfile");
@@ -1152,6 +1289,7 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_boolean(func, "alpha", 0, "Alpha", "Use alpha channel");
RNA_def_boolean(func, "float_buffer", 0, "Float Buffer", "Create an image with floating point color");
+ RNA_def_boolean(func, "stereo3d", 0, "Stereo 3D", "Create left and right views");
/* return type */
parm = RNA_def_pointer(func, "image", "Image", "", "New image datablock");
RNA_def_function_return(func, parm);
@@ -1562,7 +1700,21 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_struct_sdna(srna, "Main");
RNA_def_struct_ui_text(srna, "Main Sounds", "Collection of sounds");
- /* TODO, 'load' */
+ /* load func */
+ func = RNA_def_function(srna, "load", "rna_Main_sounds_load");
+ RNA_def_function_ui_description(func, "Add a new sound to the main database from a file");
+ parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the datablock");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ /* return type */
+ parm = RNA_def_pointer(func, "sound", "Sound", "", "New text datablock");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_Main_sounds_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Remove a sound from the current blendfile");
+ parm = RNA_def_pointer(func, "sound", "Sound", "", "Sound to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
@@ -1678,7 +1830,41 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Main_particles_is_updated_get", NULL);
}
+void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+ PropertyRNA *prop;
+
+ RNA_def_property_srna(cprop, "BlendDataPalettes");
+ srna = RNA_def_struct(brna, "BlendDataPalettes", NULL);
+ RNA_def_struct_sdna(srna, "Main");
+ RNA_def_struct_ui_text(srna, "Main Palettes", "Collection of palettes");
+
+ func = RNA_def_function(srna, "new", "rna_Main_palettes_new");
+ RNA_def_function_ui_description(func, "Add a new palette to the main database");
+ parm = RNA_def_string(func, "name", "Palette", 0, "", "New name for the datablock");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ /* return type */
+ parm = RNA_def_pointer(func, "palette", "Palette", "", "New palette datablock");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_Main_palettes_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Remove a palette from the current blendfile");
+ parm = RNA_def_pointer(func, "palette", "Palette", "", "Palette to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+
+ func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag");
+ parm = RNA_def_boolean(func, "value", 0, "Value", "");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_Main_palettes_is_updated_get", NULL);
+}
void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
@@ -1813,4 +1999,39 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_boolean_funcs(prop, "rna_Main_linestyle_is_updated_get", NULL);
}
+void RNA_def_main_cache_libraries(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+ PropertyRNA *prop;
+
+ RNA_def_property_srna(cprop, "BlendDataCacheLibraries");
+ srna = RNA_def_struct(brna, "BlendDataCacheLibraries", NULL);
+ RNA_def_struct_sdna(srna, "Main");
+ RNA_def_struct_ui_text(srna, "Main Cache Libraries", "Collection of cache libraries");
+
+ func = RNA_def_function(srna, "tag", "rna_Main_cachelibraries_tag");
+ parm = RNA_def_boolean(func, "value", 0, "Value", "");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+
+ func = RNA_def_function(srna, "new", "rna_Main_cachelibraries_new");
+ RNA_def_function_ui_description(func, "Add a new cache library to the main database");
+ parm = RNA_def_string(func, "name", "CacheLibrary", 0, "", "New name for the datablock");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ /* return type */
+ parm = RNA_def_pointer(func, "cachelib", "CacheLibrary", "", "New cache library datablock");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_Main_cachelibraries_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Remove a cache library from the current blendfile");
+ parm = RNA_def_pointer(func, "cachelib", "CacheLibrary", "", "Cache Library to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+
+ prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_Main_cachelibraries_is_updated_get", NULL);
+}
+
#endif
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index 7a06b647ae3..874e861f75f 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -377,7 +377,7 @@ static EnumPropertyItem *rna_Material_texture_coordinates_itemf(bContext *UNUSED
MTex *rna_mtex_texture_slots_add(ID *self_id, struct bContext *C, ReportList *reports)
{
- MTex *mtex = add_mtex_id(self_id, -1);
+ MTex *mtex = BKE_texture_mtex_add_id(self_id, -1);
if (mtex == NULL) {
BKE_reportf(reports, RPT_ERROR, "Maximum number of textures added %d", MAX_MTEX);
return NULL;
@@ -398,7 +398,7 @@ MTex *rna_mtex_texture_slots_create(ID *self_id, struct bContext *C, ReportList
return NULL;
}
- mtex = add_mtex_id(self_id, index);
+ mtex = BKE_texture_mtex_add_id(self_id, index);
/* for redraw only */
WM_event_add_notifier(C, NC_TEXTURE, CTX_data_scene(C));
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 400e98befd0..9b25fbbaca3 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -55,6 +55,8 @@ EnumPropertyItem mesh_delimit_mode_items[] = {
{BMO_DELIM_NORMAL, "NORMAL", 0, "Normal", "Delimit by face directions"},
{BMO_DELIM_MATERIAL, "MATERIAL", 0, "Material", "Delimit by face material"},
{BMO_DELIM_SEAM, "SEAM", 0, "Seam", "Delimit by edge seams"},
+ {BMO_DELIM_SHARP, "SHARP", 0, "Sharp", "Delimit by sharp edges"},
+ {BMO_DELIM_UV, "UV", 0, "UVs", "Delimit by UV coordinates"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c
index a994bf5e9d1..632b07c19ce 100644
--- a/source/blender/makesrna/intern/rna_mesh_api.c
+++ b/source/blender/makesrna/intern/rna_mesh_api.c
@@ -69,47 +69,6 @@ static void rna_Mesh_create_normals_split(Mesh *mesh)
}
}
-static void rna_Mesh_calc_normals_split(Mesh *mesh)
-{
- float (*r_loopnors)[3];
- float (*polynors)[3];
- short (*clnors)[2] = NULL;
- bool free_polynors = false;
-
- if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
- r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
- memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop);
- }
- else {
- r_loopnors = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop);
- CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
-
- /* may be NULL */
- clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
-
- if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
- /* This assume that layer is always up to date, not sure this is the case (esp. in Edit mode?)... */
- polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- free_polynors = false;
- }
- else {
- polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__);
- BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly,
- polynors, false);
- free_polynors = true;
- }
-
- BKE_mesh_normals_loop_split(
- mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge,
- mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly,
- (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, NULL, clnors, NULL);
-
- if (free_polynors) {
- MEM_freeN(polynors);
- }
-}
-
static void rna_Mesh_free_normals_split(Mesh *mesh)
{
CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop);
@@ -130,7 +89,7 @@ static void rna_Mesh_calc_tangents(Mesh *mesh, ReportList *reports, const char *
/* Compute loop normals if needed. */
if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
- rna_Mesh_calc_normals_split(mesh);
+ BKE_mesh_calc_normals_split(mesh);
}
BKE_mesh_loop_tangents(mesh, uvmap, r_looptangents, reports);
@@ -211,6 +170,8 @@ static void rna_Mesh_normals_split_custom_set(Mesh *mesh, ReportList *reports, i
}
rna_Mesh_normals_split_custom_do(mesh, loopnors, false);
+
+ DAG_id_tag_update(&mesh->id, 0);
}
static void rna_Mesh_normals_split_custom_set_from_vertices(
@@ -227,6 +188,8 @@ static void rna_Mesh_normals_split_custom_set_from_vertices(
}
rna_Mesh_normals_split_custom_do(mesh, vertnors, true);
+
+ DAG_id_tag_update(&mesh->id, 0);
}
static void rna_Mesh_transform(Mesh *mesh, float *mat, int shape_keys)
@@ -256,7 +219,7 @@ void RNA_api_mesh(StructRNA *srna)
func = RNA_def_function(srna, "create_normals_split", "rna_Mesh_create_normals_split");
RNA_def_function_ui_description(func, "Empty split vertex normals");
- func = RNA_def_function(srna, "calc_normals_split", "rna_Mesh_calc_normals_split");
+ func = RNA_def_function(srna, "calc_normals_split", "BKE_mesh_calc_normals_split");
RNA_def_function_ui_description(func, "Calculate split vertex normals, which preserve sharp edges");
func = RNA_def_function(srna, "free_normals_split", "rna_Mesh_free_normals_split");
@@ -279,7 +242,7 @@ void RNA_api_mesh(StructRNA *srna)
RNA_def_boolean(func, "free_mpoly", 0, "Free MPoly", "Free data used by polygons and loops. "
"WARNING: This destructive operation removes regular faces, "
"only used on temporary mesh data-blocks to reduce memory footprint of render "
- "engines and export scripts.");
+ "engines and export scripts");
func = RNA_def_function(srna, "calc_smooth_groups", "rna_Mesh_calc_smooth_groups");
RNA_def_function_ui_description(func, "Calculate smooth groups from sharp edges");
diff --git a/source/blender/makesrna/intern/rna_mesh_sample.c b/source/blender/makesrna/intern/rna_mesh_sample.c
new file mode 100644
index 00000000000..81a3f4bf5e4
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_mesh_sample.c
@@ -0,0 +1,73 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_mesh_sample.c
+ * \ingroup RNA
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_meshdata_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_mesh_sample.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_types.h"
+
+#include "rna_internal.h"
+
+#include "WM_types.h"
+
+
+#ifdef RNA_RUNTIME
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+
+
+#else
+
+static void rna_def_mesh_sample(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "MeshSample", NULL);
+ RNA_def_struct_sdna(srna, "MSurfaceSample");
+ RNA_def_struct_ui_text(srna, "Mesh Sample", "Point on a mesh that follows deformation");
+
+ prop = RNA_def_property(srna, "vertex_indices", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "orig_verts");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Vertex Indices", "Index of the mesh vertices used for interpolation");
+}
+
+void RNA_def_mesh_sample(BlenderRNA *brna)
+{
+ rna_def_mesh_sample(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index fb01a407b73..859f2760b29 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -92,6 +92,7 @@ EnumPropertyItem modifier_type_items[] = {
{0, "", 0, N_("Deform"), ""},
{eModifierType_Armature, "ARMATURE", ICON_MOD_ARMATURE, "Armature", ""},
{eModifierType_Cast, "CAST", ICON_MOD_CAST, "Cast", ""},
+ {eModifierType_CorrectiveSmooth, "CORRECTIVE_SMOOTH", ICON_MOD_SMOOTH, "Corrective Smooth", ""},
{eModifierType_Curve, "CURVE", ICON_MOD_CURVE, "Curve", ""},
{eModifierType_Displace, "DISPLACE", ICON_MOD_DISPLACE, "Displace", ""},
{eModifierType_Hook, "HOOK", ICON_HOOK, "Hook", ""},
@@ -379,6 +380,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_DataTransferModifier;
case eModifierType_NormalEdit:
return &RNA_NormalEditModifier;
+ case eModifierType_CorrectiveSmooth:
+ return &RNA_CorrectiveSmoothModifier;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:
@@ -407,7 +410,7 @@ static void rna_Modifier_name_set(PointerRNA *ptr, const char *value)
}
/* fix all the animation data which may link to this */
- BKE_all_animdata_fix_paths_rename(NULL, "modifiers", oldname, md->name);
+ BKE_animdata_fix_paths_rename_all(NULL, "modifiers", oldname, md->name);
}
static char *rna_Modifier_path(PointerRNA *ptr)
@@ -446,6 +449,7 @@ RNA_MOD_VGROUP_NAME_SET(Cast, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Curve, name);
RNA_MOD_VGROUP_NAME_SET(DataTransfer, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Decimate, defgrp_name);
+RNA_MOD_VGROUP_NAME_SET(CorrectiveSmooth, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Displace, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Hook, name);
RNA_MOD_VGROUP_NAME_SET(LaplacianDeform, anchor_grp_name);
@@ -1036,6 +1040,33 @@ static EnumPropertyItem *rna_DataTransferModifier_mix_mode_itemf(bContext *C, Po
return item;
}
+static void rna_CorrectiveSmoothModifier_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data;
+
+ MEM_SAFE_FREE(csmd->delta_cache);
+
+ rna_Modifier_update(bmain, scene, ptr);
+}
+
+static void rna_CorrectiveSmoothModifier_rest_source_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data;
+
+ if (csmd->rest_source != MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
+ MEM_SAFE_FREE(csmd->bind_coords);
+ csmd->bind_coords_num = 0;
+ }
+
+ rna_CorrectiveSmoothModifier_update(bmain, scene, ptr);
+}
+
+static int rna_CorrectiveSmoothModifier_is_bind_get(PointerRNA *ptr)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data;
+ return (csmd->bind_coords != NULL);
+}
+
static int rna_ParticleInstanceModifier_particle_system_poll(PointerRNA *ptr, const PointerRNA value)
{
ParticleInstanceModifierData *psmd = ptr->data;
@@ -1441,7 +1472,7 @@ static void rna_def_modifier_mirror(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "tolerance");
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 1, 0.01, 6);
- RNA_def_property_ui_text(prop, "Merge Limit", "Distance from axis within which mirrored vertices are merged");
+ RNA_def_property_ui_text(prop, "Merge Limit", "Distance within which mirrored vertices are merged");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "mirror_object", PROP_POINTER, PROP_NONE);
@@ -1514,6 +1545,13 @@ static void rna_def_modifier_decimate(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_DECIM_FLAG_TRIANGULATE);
RNA_def_property_ui_text(prop, "Triangulate", "Keep triangulated faces resulting from decimation (collapse only)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "defgrp_factor");
+ RNA_def_property_range(prop, 0, 1000);
+ RNA_def_property_ui_range(prop, 0, 10, 1, 4);
+ RNA_def_property_ui_text(prop, "Factor", "Vertex group strength");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
/* end collapse-only option */
/* (mode == MOD_DECIM_MODE_DISSOLVE) */
@@ -2155,6 +2193,90 @@ static void rna_def_modifier_smooth(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
+
+static void rna_def_modifier_correctivesmooth(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem modifier_smooth_type_items[] = {
+ {MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE, "SIMPLE", 0, "Simple",
+ "Use the average of adjacent edge-vertices"},
+ {MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT, "LENGTH_WEIGHTED", 0, "Length Weight",
+ "Use the average of adjacent edge-vertices weighted by their length"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem modifier_rest_source_items[] = {
+ {MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO, "ORCO", 0, "Original Coords",
+ "Use base mesh vert coords as the rest position"},
+ {MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND, "BIND", 0, "Bind Coords",
+ "Use bind vert coords for rest position"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "CorrectiveSmoothModifier", "Modifier");
+ RNA_def_struct_ui_text(srna, "Corrective Smooth Modifier", "Correct distortion caused by deformation");
+ RNA_def_struct_sdna(srna, "CorrectiveSmoothModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_SMOOTH);
+
+ prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "lambda");
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 5, 3);
+ RNA_def_property_ui_text(prop, "Lambda Factor", "Smooth factor effect");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+
+ prop = RNA_def_property(srna, "iterations", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "repeat");
+ RNA_def_property_ui_range(prop, 0, 200, 1, -1);
+ RNA_def_property_ui_text(prop, "Repeat", "");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+
+ prop = RNA_def_property(srna, "rest_source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "rest_source");
+ RNA_def_property_enum_items(prop, modifier_rest_source_items);
+ RNA_def_property_ui_text(prop, "Rest Source", "Select the source of rest positions");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_rest_source_update");
+
+ prop = RNA_def_property(srna, "smooth_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "smooth_type");
+ RNA_def_property_enum_items(prop, modifier_smooth_type_items);
+ RNA_def_property_ui_text(prop, "Smooth Type", "Method used for smoothing");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CORRECTIVESMOOTH_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
+ RNA_def_property_ui_text(prop, "Vertex Group",
+ "Name of Vertex Group which determines influence of modifier per point");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_CorrectiveSmoothModifier_defgrp_name_set");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+
+ prop = RNA_def_property(srna, "is_bind", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Bind current shape", "");
+ RNA_def_property_boolean_funcs(prop, "rna_CorrectiveSmoothModifier_is_bind_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "use_only_smooth", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CORRECTIVESMOOTH_ONLY_SMOOTH);
+ RNA_def_property_ui_text(prop, "Only Smooth",
+ "Apply smoothing without reconstructing the surface");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "use_pin_boundary", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CORRECTIVESMOOTH_PIN_BOUNDARY);
+ RNA_def_property_ui_text(prop, "Pin Boundaries",
+ "Excludes boundary vertices from being smoothed");
+ RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+}
+
+
static void rna_def_modifier_laplaciansmooth(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2485,6 +2607,18 @@ static void rna_def_modifier_particleinstance(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Random Position", "Randomize position along path");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "rotation");
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_text(prop, "Rotation", "Rotation around path");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "random_rotation", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "random_rotation");
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_text(prop, "Random Rotation", "Randomize rotation around path");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "particle_amount", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_ui_text(prop, "Particle Amount", "Amount of particles to use for instancing");
@@ -2584,7 +2718,7 @@ static void rna_def_modifier_cloth(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "ClothSolverResult");
RNA_def_property_pointer_sdna(prop, NULL, "solver_result");
RNA_def_property_ui_text(prop, "Solver Result", "");
-
+
prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_ui_text(prop, "Point Cache", "");
@@ -4504,7 +4638,7 @@ static void rna_def_modifier_normaledit(BlenderRNA *brna)
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NormalEditModifier_defgrp_name_set");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
- prop = RNA_def_property(srna, "use_invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_NORMALEDIT_INVERT_VGROUP);
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@@ -4606,6 +4740,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_displace(brna);
rna_def_modifier_uvproject(brna);
rna_def_modifier_smooth(brna);
+ rna_def_modifier_correctivesmooth(brna);
rna_def_modifier_cast(brna);
rna_def_modifier_meshdeform(brna);
rna_def_modifier_particlesystem(brna);
diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c
index e891ab520f9..9ccde654af2 100644
--- a/source/blender/makesrna/intern/rna_movieclip.c
+++ b/source/blender/makesrna/intern/rna_movieclip.c
@@ -196,7 +196,7 @@ static void rna_def_movieclip_proxy(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, clip_tc_items);
RNA_def_property_ui_text(prop, "Timecode", "");
- RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
+ RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_MovieClip_reload_update");
/* directory */
prop = RNA_def_property(srna, "directory", PROP_STRING, PROP_DIRPATH);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index eb2cb9e9312..f7570f7eaf0 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -39,6 +39,7 @@
#include "DNA_mesh_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
#include "DNA_text_types.h"
#include "DNA_texture_types.h"
@@ -64,6 +65,8 @@
#include "MEM_guardedalloc.h"
+#include "RE_render_ext.h"
+
EnumPropertyItem node_socket_in_out_items[] = {
{ SOCK_IN, "IN", 0, "Input", "" },
{ SOCK_OUT, "OUT", 0, "Output", "" },
@@ -1549,7 +1552,7 @@ static void rna_Node_name_set(PointerRNA *ptr, const char *value)
nodeUniqueName(ntree, node);
/* fix all the animation data which may link to this */
- BKE_all_animdata_fix_paths_rename(NULL, "nodes", oldname, node->name);
+ BKE_animdata_fix_paths_rename_all(NULL, "nodes", oldname, node->name);
}
static bNodeSocket *rna_Node_inputs_new(ID *id, bNode *node, ReportList *reports, const char *type, const char *name, const char *identifier)
@@ -1578,7 +1581,7 @@ static bNodeSocket *rna_Node_outputs_new(ID *id, bNode *node, ReportList *report
sock = nodeAddSocket(ntree, node, SOCK_OUT, type, identifier, name);
if (sock == NULL) {
- BKE_reportf(reports, RPT_ERROR, "Unable to create socket");
+ BKE_report(reports, RPT_ERROR, "Unable to create socket");
}
else {
ntreeUpdateTree(G.main, ntree);
@@ -2258,8 +2261,13 @@ static void rna_NodeSocketStandard_value_update(struct bContext *C, PointerRNA *
nodeFindNode(ntree, sock, &node, NULL);
}
- if (node)
+ if (node) {
nodeSynchronizeID(node, true);
+
+ /* extra update for sockets that get synced to material */
+ if (node->id && ELEM(node->type, SH_NODE_MATERIAL, SH_NODE_MATERIAL_EXT))
+ WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, node->id);
+ }
}
@@ -2616,6 +2624,70 @@ static EnumPropertyItem *rna_Node_image_layer_itemf(bContext *UNUSED(C), Pointer
return item;
}
+static int rna_Node_image_has_layers_get(PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ Image *ima = (Image *)node->id;
+
+ if (!ima || !(ima->rr)) return 0;
+
+ return RE_layers_have_name(ima->rr);
+}
+
+static int rna_Node_image_has_views_get(PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ Image *ima = (Image *)node->id;
+
+ if (!ima || !(ima->rr)) return 0;
+
+ return BLI_listbase_count_ex(&ima->rr->views, 2) > 1;
+}
+
+static EnumPropertyItem *renderresult_views_add_enum(RenderView *rv)
+{
+ EnumPropertyItem *item = NULL;
+ EnumPropertyItem tmp = {0, "ALL", 0, "All", ""};
+ int i = 1, totitem = 0;
+
+ /* option to use all views */
+ RNA_enum_item_add(&item, &totitem, &tmp);
+
+ while (rv) {
+ tmp.identifier = rv->name;
+ /* little trick: using space char instead empty string makes the item selectable in the dropdown */
+ if (rv->name[0] == '\0')
+ tmp.name = " ";
+ else
+ tmp.name = rv->name;
+ tmp.value = i++;
+ RNA_enum_item_add(&item, &totitem, &tmp);
+ rv = rv->next;
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+
+ return item;
+}
+
+static EnumPropertyItem *rna_Node_image_view_itemf(bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *free)
+{
+ bNode *node = (bNode *)ptr->data;
+ Image *ima = (Image *)node->id;
+ EnumPropertyItem *item = NULL;
+ RenderView *rv;
+
+ if (!ima || !(ima->rr)) return NULL;
+
+ rv = ima->rr->views.first;
+ item = renderresult_views_add_enum(rv);
+
+ *free = true;
+
+ return item;
+}
+
static EnumPropertyItem *rna_Node_scene_layer_itemf(bContext *UNUSED(C), PointerRNA *ptr,
PropertyRNA *UNUSED(prop), bool *r_free)
{
@@ -2701,7 +2773,7 @@ static void rna_Image_Node_update_id(Main *UNUSED(bmain), Scene *UNUSED(scene),
static void rna_Mapping_Node_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bNode *node = ptr->data;
- init_tex_mapping(node->storage);
+ BKE_texture_mapping_init(node->storage);
rna_Node_update(bmain, scene, ptr);
}
@@ -2900,6 +2972,89 @@ static void rna_CompositorNodeScale_update(Main *bmain, Scene *scene, PointerRNA
rna_Node_update(bmain, scene, ptr);
}
+static PointerRNA rna_ShaderNodePointDensity_psys_get(PointerRNA *ptr)
+{
+ bNode *node = ptr->data;
+ NodeShaderTexPointDensity *shader_point_density = node->storage;
+ Object *ob = (Object*)node->id;
+ ParticleSystem *psys = NULL;
+ PointerRNA value;
+
+ if (ob && shader_point_density->particle_system) {
+ psys = BLI_findlink(&ob->particlesystem, shader_point_density->particle_system - 1);
+ }
+
+ RNA_pointer_create(&ob->id, &RNA_ParticleSystem, psys, &value);
+ return value;
+}
+
+static void rna_ShaderNodePointDensity_psys_set(PointerRNA *ptr, PointerRNA value)
+{
+ bNode *node = ptr->data;
+ NodeShaderTexPointDensity *shader_point_density = node->storage;
+ Object *ob = (Object*)node->id;
+
+ if (ob && value.id.data == ob) {
+ shader_point_density->particle_system = BLI_findindex(&ob->particlesystem, value.data) + 1;
+ }
+ else {
+ shader_point_density->particle_system = 0;
+ }
+}
+
+static int point_density_color_source_from_shader(NodeShaderTexPointDensity *shader_point_density)
+{
+ switch (shader_point_density->color_source) {
+ case SHD_POINTDENSITY_COLOR_CONSTANT: return TEX_PD_COLOR_CONSTANT;
+ case SHD_POINTDENSITY_COLOR_PARTAGE: return TEX_PD_COLOR_PARTAGE;
+ case SHD_POINTDENSITY_COLOR_PARTSPEED: return TEX_PD_COLOR_PARTSPEED;
+ case SHD_POINTDENSITY_COLOR_PARTVEL: return TEX_PD_COLOR_PARTVEL;
+ case SHD_POINTDENSITY_COLOR_PARTTEX: return TEX_PD_COLOR_PARTTEX;
+ default: BLI_assert(false); return TEX_PD_COLOR_CONSTANT;
+ }
+}
+
+/* TODO(sergey): This functio nassumes allocated array was passed,
+ * works fine with Cycles via C++ RNA, but fails with call from python.
+ */
+void rna_ShaderNodePointDensity_density_calc(bNode *self, Scene *scene, int *length, float **values)
+{
+ NodeShaderTexPointDensity *shader_point_density = self->storage;
+ PointDensity pd;
+
+ *length = 4 * shader_point_density->resolution *
+ shader_point_density->resolution *
+ shader_point_density->resolution;
+
+ if (*values == NULL) {
+ *values = MEM_mallocN(sizeof(float) * (*length), "point density dynamic array");
+ }
+
+ /* Create PointDensity structure from node for sampling. */
+ BKE_texture_pointdensity_init_data(&pd);
+ pd.object = (Object *)self->id;
+ pd.radius = shader_point_density->radius;
+ if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
+ pd.source = TEX_PD_PSYS;
+ pd.psys = shader_point_density->particle_system;
+ pd.psys_cache_space = TEX_PD_OBJECTSPACE;
+ }
+ else {
+ BLI_assert(shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_OBJECT);
+ pd.source = TEX_PD_OBJECT;
+ pd.ob_cache_space = TEX_PD_OBJECTSPACE;
+ }
+ pd.color_source = point_density_color_source_from_shader(shader_point_density);
+
+ /* Single-threaded sampling of the voxel domain. */
+ RE_sample_point_density(scene, &pd,
+ shader_point_density->resolution,
+ *values);
+
+ /* We're done, time to clean up. */
+ BKE_texture_pointdensity_free_data(&pd);
+}
+
#else
static EnumPropertyItem prop_image_layer_items[] = {
@@ -2907,6 +3062,11 @@ static EnumPropertyItem prop_image_layer_items[] = {
{0, NULL, 0, NULL, NULL}
};
+static EnumPropertyItem prop_image_view_items[] = {
+ { 0, "ALL", 0, "All", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
static EnumPropertyItem prop_scene_layer_items[] = {
{ 0, "PLACEHOLDER", 0, "Placeholder", ""},
{0, NULL, 0, NULL, NULL}
@@ -3234,6 +3394,8 @@ static void def_sh_mapping(StructRNA *srna)
{0, NULL, 0, NULL, NULL}
};
+ static float default_1[3] = {1.f, 1.f, 1.f};
+
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "TexMapping", "storage");
@@ -3257,6 +3419,7 @@ static void def_sh_mapping(StructRNA *srna)
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "size");
+ RNA_def_property_float_array_default(prop, default_1);
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_ui_text(prop, "Scale", "");
RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
@@ -3268,6 +3431,7 @@ static void def_sh_mapping(StructRNA *srna)
prop = RNA_def_property(srna, "max", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "max");
+ RNA_def_property_float_array_default(prop, default_1);
RNA_def_property_ui_text(prop, "Maximum", "Maximum value for clipping");
RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
@@ -3410,6 +3574,7 @@ static void def_sh_tex_environment(StructRNA *srna)
prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_color_space_items);
+ RNA_def_property_enum_default(prop, SHD_COLORSPACE_COLOR);
RNA_def_property_ui_text(prop, "Color Space", "Image file color space");
RNA_def_property_update(prop, 0, "rna_Node_update");
@@ -3475,6 +3640,7 @@ static void def_sh_tex_image(StructRNA *srna)
prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_color_space_items);
+ RNA_def_property_enum_default(prop, SHD_COLORSPACE_COLOR);
RNA_def_property_ui_text(prop, "Color Space", "Image file color space");
RNA_def_property_update(prop, 0, "rna_Node_update");
@@ -3715,6 +3881,105 @@ static void def_sh_tex_wireframe(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_sh_tex_pointdensity(StructRNA *srna)
+{
+ PropertyRNA *prop;
+ FunctionRNA *func;
+
+ static EnumPropertyItem point_source_items[] = {
+ {SHD_POINTDENSITY_SOURCE_PSYS, "PARTICLE_SYSTEM", 0, "Particle System",
+ "Generate point density from a particle system"},
+ {SHD_POINTDENSITY_SOURCE_OBJECT, "OBJECT", 0, "Object Vertices",
+ "Generate point density from an object's vertices"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static const EnumPropertyItem prop_interpolation_items[] = {
+ {SHD_INTERP_CLOSEST, "Closest", 0, "Closest",
+ "No interpolation (sample closest texel)"},
+ {SHD_INTERP_LINEAR, "Linear", 0, "Linear",
+ "Linear interpolation"},
+ {SHD_INTERP_CUBIC, "Cubic", 0, "Cubic",
+ "Cubic interpolation (CPU only)"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem space_items[] = {
+ {SHD_POINTDENSITY_SPACE_OBJECT, "OBJECT", 0, "Object Space", ""},
+ {SHD_POINTDENSITY_SPACE_WORLD, "WORLD", 0, "World Space", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem color_source_items[] = {
+ {SHD_POINTDENSITY_COLOR_CONSTANT, "CONSTANT", 0, "Constant", ""},
+ {SHD_POINTDENSITY_COLOR_PARTAGE, "PARTICLE_AGE", 0, "Particle Age",
+ "Lifetime mapped as 0.0 - 1.0 intensity"},
+ {SHD_POINTDENSITY_COLOR_PARTSPEED, "PARTICLE_SPEED", 0, "Particle Speed",
+ "Particle speed (absolute magnitude of velocity) mapped as 0.0-1.0 intensity"},
+ {SHD_POINTDENSITY_COLOR_PARTVEL, "PARTICLE_VELOCITY", 0, "Particle Velocity",
+ "XYZ velocity mapped to RGB colors"},
+ {SHD_POINTDENSITY_COLOR_PARTTEX, "PARTICLE_TEXTURE", 0, "Particle Texture", "Texture color of particles"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "id");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Object", "Object to take point data from)");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ RNA_def_struct_sdna_from(srna, "NodeShaderTexPointDensity", "storage");
+
+ prop = RNA_def_property(srna, "point_source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, point_source_items);
+ RNA_def_property_ui_text(prop, "Point Source", "Point data to use as renderable point density");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Particle System", "Particle System to render as points");
+ RNA_def_property_struct_type(prop, "ParticleSystem");
+ RNA_def_property_pointer_funcs(prop, "rna_ShaderNodePointDensity_psys_get",
+ "rna_ShaderNodePointDensity_psys_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "resolution", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 1, 32768);
+ RNA_def_property_ui_text(prop, "Resolution", "Resolution used by the texture holding the point density");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "radius");
+ RNA_def_property_range(prop, 0.001, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Radius", "Radius from the shaded sample to look for points within");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, space_items);
+ RNA_def_property_ui_text(prop, "Space", "Coordinate system to calculate voxels in");
+ RNA_def_property_update(prop, 0, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_interpolation_items);
+ RNA_def_property_ui_text(prop, "Interpolation", "Texture interpolation");
+ RNA_def_property_update(prop, 0, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "color_source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "color_source");
+ RNA_def_property_enum_items(prop, color_source_items);
+ RNA_def_property_ui_text(prop, "Color Source", "Data to derive color results from");
+ RNA_def_property_update(prop, 0, "rna_Node_update");
+
+ func = RNA_def_function(srna, "calc_point_density", "rna_ShaderNodePointDensity_density_calc");
+ RNA_def_function_ui_description(func, "Calculate point density");
+ RNA_def_pointer(func, "scene", "Scene", "", "");
+ /* TODO, See how array size of 0 works, this shouldnt be used. */
+ prop = RNA_def_float_array(func, "rgba_values", 1, NULL, 0, 0, "", "RGBA Values", 0, 0);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_function_output(func, prop);
+}
+
static void def_glossy(StructRNA *srna)
{
PropertyRNA *prop;
@@ -4263,6 +4528,24 @@ static void def_node_image_user(StructRNA *srna)
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
RNA_def_property_ui_text(prop, "Layer", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_image_layer_update");
+
+ prop = RNA_def_property(srna, "has_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_Node_image_has_layers_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Has Layers", "True if this image has any named layer");
+
+ prop = RNA_def_property(srna, "view", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "view");
+ RNA_def_property_enum_items(prop, prop_image_view_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Node_image_view_itemf");
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ RNA_def_property_ui_text(prop, "View", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "has_views", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_Node_image_has_views_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Has View", "True if this image has multiple views");
}
static void def_cmp_image(StructRNA *srna)
@@ -5811,6 +6094,16 @@ static void def_cmp_switch(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_cmp_switch_view(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "check", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "custom1", 0);
+ RNA_def_property_ui_text(prop, "Switch", "Off: first socket, On: second socket");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_cmp_colorcorrection(StructRNA *srna)
{
PropertyRNA *prop;
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 6b7b6e538a9..17c75da2c87 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -71,6 +71,7 @@ EnumPropertyItem object_mode_items[] = {
{OB_MODE_WEIGHT_PAINT, "WEIGHT_PAINT", ICON_WPAINT_HLT, "Weight Paint", ""},
{OB_MODE_TEXTURE_PAINT, "TEXTURE_PAINT", ICON_TPAINT_HLT, "Texture Paint", ""},
{OB_MODE_PARTICLE_EDIT, "PARTICLE_EDIT", ICON_PARTICLEMODE, "Particle Edit", ""},
+ {OB_MODE_HAIR_EDIT, "HAIR_EDIT", ICON_PARTICLEMODE, "Hair Edit", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -183,12 +184,15 @@ EnumPropertyItem object_axis_unsigned_items[] = {
#include "BLI_math.h"
#include "DNA_key_types.h"
+#include "DNA_cache_library_types.h"
#include "DNA_constraint_types.h"
#include "DNA_lattice_types.h"
#include "DNA_node_types.h"
+#include "BKE_anim.h"
#include "BKE_armature.h"
#include "BKE_bullet.h"
+#include "BKE_cache_library.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_curve.h"
@@ -201,6 +205,7 @@ EnumPropertyItem object_axis_unsigned_items[] = {
#include "BKE_mesh.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
+#include "BKE_strands.h"
#include "BKE_deform.h"
#include "ED_mesh.h"
@@ -1031,6 +1036,7 @@ static void rna_MaterialSlot_update(Main *bmain, Scene *scene, PointerRNA *ptr)
WM_main_add_notifier(NC_OBJECT | ND_OB_SHADING, ptr->id.data);
WM_main_add_notifier(NC_MATERIAL | ND_SHADING_LINKS, NULL);
+ DAG_relations_tag_update(bmain);
}
static char *rna_MaterialSlot_path(PointerRNA *ptr)
@@ -1091,7 +1097,7 @@ static int rna_GameObjectSettings_physics_type_get(PointerRNA *ptr)
static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value)
{
Object *ob = (Object *)ptr->id.data;
- const int was_navmesh = (ob->gameflag & OB_NAVMESH);
+ const int gameflag_prev = ob->gameflag;
ob->body_type = value;
switch (ob->body_type) {
@@ -1149,7 +1155,7 @@ static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value)
break;
}
- if (was_navmesh != (ob->gameflag & OB_NAVMESH)) {
+ if ((gameflag_prev & OB_NAVMESH) != (ob->gameflag & OB_NAVMESH)) {
if (ob->type == OB_MESH) {
/* this is needed to refresh the derived meshes draw func */
DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
@@ -1469,7 +1475,7 @@ static void rna_Object_boundbox_get(PointerRNA *ptr, float *values)
memcpy(values, bb->vec, sizeof(bb->vec));
}
else {
- fill_vn_fl(values, sizeof(bb->vec) / sizeof(float), 0.0f);
+ copy_vn_fl(values, sizeof(bb->vec) / sizeof(float), 0.0f);
}
}
@@ -1661,6 +1667,120 @@ static void rna_Object_lod_distance_update(Main *UNUSED(bmain), Scene *UNUSED(sc
(void)ob;
#endif
}
+
+/* settings: 1 - preview, 2 - render */
+Strands *rna_DupliObject_strands_new(DupliObject *dob, ReportList *UNUSED(reports), Scene *scene, Object *parent, ParticleSystem *psys, int settings)
+{
+ Strands *strands = NULL;
+ bool is_cached = parent->cache_library && (parent->cache_library->source_mode == CACHE_LIBRARY_SOURCE_CACHE || parent->cache_library->display_mode == CACHE_LIBRARY_DISPLAY_RESULT);
+
+ if (is_cached) {
+ float frame = (float)scene->r.cfra + scene->r.subframe;
+ bool use_render = (settings == 2);
+
+ if (!ELEM(settings, 1, 2))
+ return NULL;
+
+ if (!use_render && parent->dup_cache) {
+ DupliObjectData *data;
+
+ /* use dupli cache for realtime dupli data if possible */
+ data = BKE_dupli_cache_find_data(parent->dup_cache, dob->ob);
+ if (data) {
+ /* TODO(sergey): Consider sharing the data between viewport and
+ * render engine.
+ */
+ BKE_dupli_object_data_find_strands(data, psys->name, &strands, NULL);
+ if (strands) {
+ strands = BKE_strands_copy(strands);
+ }
+ }
+ }
+ else {
+ DupliObjectData data;
+
+ memset(&data, 0, sizeof(data));
+ if (BKE_cache_read_dupli_object(parent->cache_library, &data, scene, dob->ob, frame, use_render, true)) {
+ BKE_dupli_object_data_find_strands(&data, psys->name, &strands, NULL);
+ if (strands)
+ BKE_dupli_object_data_acquire_strands(&data, strands);
+ }
+
+ BKE_dupli_object_data_clear(&data);
+ }
+ }
+
+ return strands;
+}
+
+static void rna_DupliObject_strands_free(DupliObject *UNUSED(dob), ReportList *UNUSED(reports), PointerRNA *strands_ptr)
+{
+ Strands *strands = strands_ptr->data;
+ if (strands)
+ BKE_strands_free(strands);
+}
+
+/* settings: 1 - preview, 2 - render */
+StrandsChildren *rna_DupliObject_strands_children_new(DupliObject *dob, ReportList *UNUSED(reports), Scene *scene, Object *parent, ParticleSystem *psys, int settings)
+{
+ StrandsChildren *strands = NULL;
+ bool is_cached = parent->cache_library && (parent->cache_library->source_mode == CACHE_LIBRARY_SOURCE_CACHE || parent->cache_library->display_mode == CACHE_LIBRARY_DISPLAY_RESULT);
+
+ if (is_cached) {
+ float frame = (float)scene->r.cfra + scene->r.subframe;
+ bool use_render = (settings == 2);
+
+ if (!ELEM(settings, 1, 2))
+ return NULL;
+
+ if (!use_render && parent->dup_cache) {
+ DupliObjectData *data;
+
+ /* use dupli cache for realtime dupli data if possible */
+ data = BKE_dupli_cache_find_data(parent->dup_cache, dob->ob);
+ if (data) {
+ /* TODO(sergey): Consider sharing the data between viewport and
+ * render engine.
+ */
+ BKE_dupli_object_data_find_strands(data, psys->name, NULL, &strands);
+ if (strands) {
+ strands = BKE_strands_children_copy(strands);
+ }
+ }
+ }
+ else {
+ DupliObjectData data;
+
+ memset(&data, 0, sizeof(data));
+ if (BKE_cache_read_dupli_object(parent->cache_library, &data, scene, dob->ob, frame, use_render, true)) {
+ Strands *parents;
+ BKE_dupli_object_data_find_strands(&data, psys->name, &parents, &strands);
+ if (strands) {
+ BKE_dupli_object_data_acquire_strands_children(&data, strands);
+
+ /* Deform child strands to follow parent motion.
+ * Note that this is an optional feature for viewport/render display,
+ * strand motion is not applied to raw child data in caches.
+ */
+ if (parents)
+ BKE_strands_children_deform(strands, parents, true);
+ }
+ }
+
+ BKE_dupli_object_data_clear(&data);
+ }
+ }
+
+ return strands;
+}
+
+static void rna_DupliObject_strands_children_free(DupliObject *UNUSED(dob), ReportList *UNUSED(reports), PointerRNA *strands_ptr)
+{
+ StrandsChildren *strands = strands_ptr->data;
+ if (strands)
+ BKE_strands_children_free(strands);
+}
+
#else
static void rna_def_vertex_group(BlenderRNA *brna)
@@ -1869,6 +1989,7 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "physics_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "body_type");
RNA_def_property_enum_items(prop, body_type_items);
+ RNA_def_property_enum_default(prop, OB_BODY_TYPE_STATIC);
RNA_def_property_enum_funcs(prop, "rna_GameObjectSettings_physics_type_get",
"rna_GameObjectSettings_physics_type_set", NULL);
RNA_def_property_ui_text(prop, "Physics Type", "Select the type of physical representation");
@@ -1888,12 +2009,14 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "mass", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.01, 10000.0);
+ RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Mass", "Mass of the object");
prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
RNA_def_property_float_sdna(prop, NULL, "inertia");
RNA_def_property_range(prop, 0.01f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.01f, 10.0f, 1, 3);
+ RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Radius", "Radius of bounding sphere and material physics");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
@@ -1904,11 +2027,13 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "damping", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "damping");
RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_default(prop, 0.04f);
RNA_def_property_ui_text(prop, "Damping", "General movement damping");
prop = RNA_def_property(srna, "rotation_damping", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "rdamping");
RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_ui_text(prop, "Rotation Damping", "General rotation damping");
prop = RNA_def_property(srna, "velocity_min", PROP_FLOAT, PROP_NONE);
@@ -1925,16 +2050,19 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "step_height", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "step_height");
RNA_def_property_range(prop, 0.01, 1.0);
+ RNA_def_property_float_default(prop, 0.15f);
RNA_def_property_ui_text(prop, "Step Height", "Maximum height of steps the character can run over");
prop = RNA_def_property(srna, "jump_speed", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "jump_speed");
RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_float_default(prop, 10.0f);
RNA_def_property_ui_text(prop, "Jump Force", "Upward velocity applied to the character when jumping");
prop = RNA_def_property(srna, "fall_speed", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "fall_speed");
RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_float_default(prop, 55.0f);
RNA_def_property_ui_text(prop, "Fall Speed Max", "Maximum speed at which the character will fall");
/* Collision Masks */
@@ -1995,6 +2123,7 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "form_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "formfactor");
RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_default(prop, 0.4f);
RNA_def_property_ui_text(prop, "Form Factor", "Form factor scales the inertia tensor");
prop = RNA_def_property(srna, "use_anisotropic_friction", PROP_BOOLEAN, PROP_NONE);
@@ -2027,6 +2156,7 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "collision_margin", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
RNA_def_property_float_sdna(prop, NULL, "margin");
RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_default(prop, 0.04f);
RNA_def_property_ui_text(prop, "Collision Margin",
"Extra margin around object for collision detection, small amount required "
"for stability");
@@ -2042,6 +2172,7 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "obstacle_radius", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
RNA_def_property_float_sdna(prop, NULL, "obstacleRad");
RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Obstacle Radius", "Radius of object representation in obstacle simulation");
/* state */
@@ -2320,6 +2451,14 @@ static void rna_def_object_lodlevel(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Distance", "Distance to begin using this level of detail");
RNA_def_property_update(prop, NC_OBJECT | ND_LOD, "rna_Object_lod_distance_update");
+ prop = RNA_def_property(srna, "object_hysteresis_percentage", PROP_INT, PROP_PERCENTAGE);
+ RNA_def_property_int_sdna(prop, NULL, "obhysteresis");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_range(prop, 0, 100, 10, 1);
+ RNA_def_property_ui_text(prop, "Hysteresis %",
+ "Minimum distance change required to transition to the previous level of detail");
+ RNA_def_property_update(prop, NC_OBJECT | ND_LOD, NULL);
+
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "source");
RNA_def_property_struct_type(prop, "Object");
@@ -2338,6 +2477,11 @@ static void rna_def_object_lodlevel(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use Material", "Use the material from this object at this level of detail");
RNA_def_property_ui_icon(prop, ICON_MATERIAL, 0);
RNA_def_property_update(prop, NC_OBJECT | ND_LOD, NULL);
+
+ prop = RNA_def_property(srna, "use_object_hysteresis", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", OB_LOD_USE_HYST);
+ RNA_def_property_ui_text(prop, "Hysteresis Override", "Override LoD Hysteresis scene setting for this LoD level");
+ RNA_def_property_update(prop, NC_OBJECT | ND_LOD, NULL);
}
@@ -2880,6 +3024,12 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Dupli Group", "Instance an existing group");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update");
+ prop = RNA_def_property(srna, "cache_library", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "cache_library");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Cache Library", "Cache Library to use");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update");
+
prop = RNA_def_property(srna, "dupli_frames_start", PROP_INT, PROP_NONE | PROP_UNIT_TIME);
RNA_def_property_int_sdna(prop, NULL, "dupsta");
RNA_def_property_range(prop, MINAFRAME, MAXFRAME);
@@ -3041,6 +3191,14 @@ static void rna_def_dupli_object(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ static EnumPropertyItem strand_settings_items[] = {
+ {1, "PREVIEW", 0, "Preview", "Apply preview settings"},
+ {2, "RENDER", 0, "Render", "Apply render settings"},
+ {0, NULL, 0, NULL, NULL}
+ };
srna = RNA_def_struct(brna, "DupliObject", NULL);
RNA_def_struct_sdna(srna, "DupliObject");
@@ -3089,6 +3247,60 @@ static void rna_def_dupli_object(BlenderRNA *brna)
RNA_def_property_enum_items(prop, dupli_items);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Dupli Type", "Duplicator type that generated this dupli object");
+
+ func = RNA_def_function(srna, "strands_new", "rna_DupliObject_strands_new");
+ RNA_def_function_ui_description(func, "Add new strands created from dupli cache data");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene within which to evaluate modifiers");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ parm = RNA_def_pointer(func, "parent", "Object", "", "Duplicator parent of the object");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ parm = RNA_def_pointer(func, "particle_system", "ParticleSystem", "", "Particle System");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ parm = RNA_def_enum(func, "settings", strand_settings_items, 0, "", "Modifier settings to apply");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "strands", "Strands", "",
+ "Strands created from object, remove it if it is only used for export");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "strands_free", "rna_DupliObject_strands_free");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Free strands data");
+ parm = RNA_def_pointer(func, "strands", "Strands", "", "Strands to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+
+ func = RNA_def_function(srna, "strands_children_new", "rna_DupliObject_strands_children_new");
+ RNA_def_function_ui_description(func, "Add new strands created from dupli cache data");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene within which to evaluate modifiers");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ parm = RNA_def_pointer(func, "parent", "Object", "", "Duplicator parent of the object");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ parm = RNA_def_pointer(func, "particle_system", "ParticleSystem", "", "Particle System");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ parm = RNA_def_enum(func, "settings", strand_settings_items, 0, "", "Modifier settings to apply");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "strands", "StrandsChildren", "",
+ "Strands created from object, remove it if it is only used for export");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "strands_children_free", "rna_DupliObject_strands_children_free");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Free strands data");
+ parm = RNA_def_pointer(func, "strands", "StrandsChildren", "", "Strands to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+}
+
+static void rna_def_dupli_object_data(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ /*PropertyRNA *prop;*/
+
+ srna = RNA_def_struct(brna, "DupliObjectData", NULL);
+ RNA_def_struct_sdna(srna, "DupliObjectData");
+ RNA_def_struct_ui_text(srna, "Object Duplicate Data", "Override of object data for duplis");
}
static void rna_def_object_base(BlenderRNA *brna)
@@ -3138,6 +3350,7 @@ void RNA_def_object(BlenderRNA *brna)
rna_def_face_map(brna);
rna_def_material_slot(brna);
rna_def_dupli_object(brna);
+ rna_def_dupli_object_data(brna);
RNA_define_animate_sdna(true);
rna_def_object_lodlevel(brna);
}
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index a312ec5d41a..c0aee13d37b 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -87,6 +87,8 @@ static EnumPropertyItem space_items[] = {
#include "MEM_guardedalloc.h"
+#include "DEG_depsgraph.h"
+
/* Convert a given matrix from a space to another (using the object and/or a bone as reference). */
static void rna_Scene_mat_convert_space(Object *ob, ReportList *reports, bPoseChannel *pchan,
float *mat, float *mat_ret, int from, int to)
@@ -131,7 +133,7 @@ static void rna_Object_calc_matrix_camera(
static void rna_Object_camera_fit_coords(
Object *ob, Scene *scene, int num_cos, float *cos, float co_ret[3], float *scale_ret)
{
- BKE_camera_view_frame_fit_to_coords(scene, (float (*)[3])cos, num_cos / 3, ob, co_ret, scale_ret);
+ BKE_camera_view_frame_fit_to_coords(scene, (const float (*)[3])cos, num_cos / 3, ob, co_ret, scale_ret);
}
/* copied from Mesh_getFromObject and adapted to RNA interface */
@@ -191,8 +193,8 @@ static void dupli_render_particle_set(Scene *scene, Object *ob, int level, int e
static void rna_Object_create_duplilist(Object *ob, ReportList *reports, Scene *sce, int settings)
{
bool for_render = (settings == DAG_EVAL_RENDER);
- EvaluationContext eval_ctx = {0};
- eval_ctx.mode = settings;
+ EvaluationContext eval_ctx;
+ DEG_evaluation_context_init(&eval_ctx, settings);
if (!(ob->transflag & OB_DUPLI)) {
BKE_report(reports, RPT_ERROR, "Object does not have duplis");
@@ -222,12 +224,24 @@ static void rna_Object_free_duplilist(Object *ob)
}
}
+static PointerRNA rna_Object_find_dupli_cache(Object *ob, Object *dupob)
+{
+ DupliObjectData *data = NULL;
+ PointerRNA ptr;
+
+ if (ob->dup_cache)
+ data = BKE_dupli_cache_find_data(ob->dup_cache, dupob);
+
+ RNA_pointer_create((ID *)ob, &RNA_DupliObjectData, data, &ptr);
+ return ptr;
+}
+
static PointerRNA rna_Object_shape_key_add(Object *ob, bContext *C, ReportList *reports,
const char *name, int from_mix)
{
KeyBlock *kb = NULL;
- if ((kb = BKE_object_insert_shape_key(ob, name, from_mix))) {
+ if ((kb = BKE_object_shapekey_insert(ob, name, from_mix))) {
PointerRNA keyptr;
RNA_pointer_create((ID *)ob->data, &RNA_ShapeKey, kb, &keyptr);
@@ -241,6 +255,29 @@ static PointerRNA rna_Object_shape_key_add(Object *ob, bContext *C, ReportList *
}
}
+static void rna_Object_shape_key_remove(
+ Object *ob, Main *bmain, ReportList *reports,
+ PointerRNA *kb_ptr)
+{
+ KeyBlock *kb = kb_ptr->data;
+ Key *key = BKE_key_from_object(ob);
+
+ if ((key == NULL) || BLI_findindex(&key->block, kb) == -1) {
+ BKE_reportf(reports, RPT_ERROR, "ShapeKey not found");
+ return;
+ }
+
+ if (!BKE_object_shapekey_remove(bmain, ob, kb)) {
+ BKE_reportf(reports, RPT_ERROR, "Could not remove ShapeKey");
+ return;
+ }
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
+
+ RNA_POINTER_INVALIDATE(kb_ptr);
+}
+
static int rna_Object_is_visible(Object *ob, Scene *sce)
{
return !(ob->restrictflag & OB_RESTRICT_VIEW) && (ob->lay & sce->lay);
@@ -441,6 +478,12 @@ static int rna_Object_update_from_editmode(Object *ob)
}
return false;
}
+
+static void rna_Object_cache_release(Object *object, int free_smoke_sim)
+{
+ BKE_object_free_caches(object, free_smoke_sim != 0);
+}
+
#else /* RNA_RUNTIME */
void RNA_api_object(StructRNA *srna)
@@ -547,6 +590,14 @@ void RNA_api_object(StructRNA *srna)
func = RNA_def_function(srna, "dupli_list_clear", "rna_Object_free_duplilist");
RNA_def_function_ui_description(func, "Free the list of dupli objects");
+ func = RNA_def_function(srna, "find_dupli_cache", "rna_Object_find_dupli_cache");
+ RNA_def_function_ui_description(func, "Find cached data for a dupli object");
+ parm = RNA_def_pointer(func, "object", "Object", "", "Object data to look up");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+ parm = RNA_def_pointer(func, "data", "DupliObjectData", "", "Cached object data");
+ RNA_def_property_flag(parm, PROP_RNAPTR);
+ RNA_def_function_return(func, parm);
+
/* Armature */
func = RNA_def_function(srna, "find_armature", "modifiers_isDeformedByArmature");
RNA_def_function_ui_description(func, "Find armature influencing this object as a parent or via a modifier");
@@ -555,14 +606,21 @@ void RNA_api_object(StructRNA *srna)
/* Shape key */
func = RNA_def_function(srna, "shape_key_add", "rna_Object_shape_key_add");
- RNA_def_function_ui_description(func, "Add shape key to an object");
+ RNA_def_function_ui_description(func, "Add shape key to this object");
RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
- RNA_def_string(func, "name", "Key", 0, "", "Unique name for the new keylock"); /* optional */
+ RNA_def_string(func, "name", "Key", 0, "", "Unique name for the new keyblock"); /* optional */
RNA_def_boolean(func, "from_mix", 1, "", "Create new shape from existing mix of shapes");
parm = RNA_def_pointer(func, "key", "ShapeKey", "", "New shape keyblock");
RNA_def_property_flag(parm, PROP_RNAPTR);
RNA_def_function_return(func, parm);
+ func = RNA_def_function(srna, "shape_key_remove", "rna_Object_shape_key_remove");
+ RNA_def_function_ui_description(func, "Remove a Shape Key from this object");
+ RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "key", "ShapeKey", "", "Keyblock to be removed");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+
/* Ray Cast */
func = RNA_def_function(srna, "ray_cast", "rna_Object_ray_cast");
RNA_def_function_ui_description(func, "Cast a ray onto in object space");
@@ -656,7 +714,8 @@ void RNA_api_object(StructRNA *srna)
parm = RNA_def_boolean(func, "result", 0, "", "Success");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "cache_release", "BKE_object_free_caches");
+ func = RNA_def_function(srna, "cache_release", "rna_Object_cache_release");
+ RNA_def_boolean(func, "free_smoke_sim", 0, "", "Free baked smoke simulation data");
RNA_def_function_ui_description(func, "Release memory used by caches associated with this object. Intended to be used by render engines only");
}
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index ac74c7e7580..21f53f86d90 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -845,7 +845,7 @@ static void rna_def_pointcache(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Cache is outdated", "");
- prop = RNA_def_property(srna, "frames_skipped", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "is_frame_skip", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PTCACHE_FRAMES_SKIPPED);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
diff --git a/source/blender/makesrna/intern/rna_palette.c b/source/blender/makesrna/intern/rna_palette.c
new file mode 100644
index 00000000000..8cbb57fde2c
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_palette.c
@@ -0,0 +1,181 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_palette.c
+ * \ingroup RNA
+ */
+
+#include <stdlib.h>
+
+#include "BLI_utildefines.h"
+
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "rna_internal.h"
+
+#include "WM_types.h"
+
+#ifdef RNA_RUNTIME
+
+#include "DNA_brush_types.h"
+
+#include "BKE_paint.h"
+#include "BKE_report.h"
+
+static PaletteColor *rna_Palette_color_new(Palette *palette)
+{
+ PaletteColor *color = BKE_palette_color_add(palette);
+ return color;
+}
+
+static void rna_Palette_color_remove(Palette *palette, ReportList *reports, PointerRNA *color_ptr)
+{
+ PaletteColor *color = color_ptr->data;
+
+ if (BLI_findindex(&palette->colors, color) == -1) {
+ BKE_reportf(reports, RPT_ERROR, "Palette '%s' does not contain color given", palette->id.name + 2);
+ return;
+ }
+
+ BKE_palette_color_remove(palette, color);
+
+ RNA_POINTER_INVALIDATE(color_ptr);
+}
+
+static void rna_Palette_color_clear(Palette *palette)
+{
+ BKE_palette_clear(palette);
+}
+
+static PointerRNA rna_Palette_active_color_get(PointerRNA *ptr)
+{
+ Palette *palette = ptr->data;
+ PaletteColor *color;
+
+ color = BLI_findlink(&palette->colors, palette->active_color);
+
+ if (color)
+ return rna_pointer_inherit_refine(ptr, &RNA_PaletteColor, color);
+
+ return rna_pointer_inherit_refine(ptr, NULL, NULL);
+}
+
+static void rna_Palette_active_color_set(PointerRNA *ptr, PointerRNA value)
+{
+ Palette *palette = ptr->data;
+ PaletteColor *color = value.data;
+
+ /* -1 is ok for an unset index */
+ if (color == NULL)
+ palette->active_color = -1;
+ else
+ palette->active_color = BLI_findindex(&palette->colors, color);
+}
+
+#else
+
+/* palette.colors */
+static void rna_def_palettecolors(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "PaletteColors");
+ srna = RNA_def_struct(brna, "PaletteColors", NULL);
+ RNA_def_struct_sdna(srna, "Palette");
+ RNA_def_struct_ui_text(srna, "Palette Splines", "Collection of palette colors");
+
+ func = RNA_def_function(srna, "new", "rna_Palette_color_new");
+ RNA_def_function_ui_description(func, "Add a new color to the palette");
+ parm = RNA_def_pointer(func, "color", "PaletteColor", "", "The newly created color");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_Palette_color_remove");
+ RNA_def_function_ui_description(func, "Remove a color from the palette");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "color", "PaletteColor", "", "The color to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+
+ func = RNA_def_function(srna, "clear", "rna_Palette_color_clear");
+ RNA_def_function_ui_description(func, "Remove all colors from the palette");
+
+ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "PaletteColor");
+ RNA_def_property_pointer_funcs(prop, "rna_Palette_active_color_get", "rna_Palette_active_color_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Active Palette Color", "");
+}
+
+static void rna_def_palettecolor(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "PaletteColor", NULL);
+ RNA_def_struct_ui_text(srna, "Palette Color", "");
+
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "rgb");
+ RNA_def_property_ui_text(prop, "Color", "");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "value");
+ RNA_def_property_ui_text(prop, "Value", "");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "value");
+ RNA_def_property_ui_text(prop, "Weight", "");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+}
+
+static void rna_def_palette(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "Palette", "ID");
+ RNA_def_struct_ui_text(srna, "Palette", "");
+ RNA_def_struct_ui_icon(srna, ICON_COLOR);
+
+ prop = RNA_def_property(srna, "colors", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "PaletteColor");
+ rna_def_palettecolors(brna, prop);
+}
+
+void RNA_def_palette(BlenderRNA *brna)
+{
+ /* *** Non-Animated *** */
+ RNA_define_animate_sdna(false);
+ rna_def_palettecolor(brna);
+ rna_def_palette(brna);
+ RNA_define_animate_sdna(true);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 0248c453e5a..a6bbbfcb8b4 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -1908,6 +1908,11 @@ static void rna_def_particle_settings_mtex(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Shape Key", "Affect the blend factor of a hair shape key");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
+ prop = RNA_def_property(srna, "use_map_particle_color", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mapto", PAMAP_COLOR);
+ RNA_def_property_ui_text(prop, "Color", "Affect the particle color");
+ RNA_def_property_update(prop, 0, "rna_Particle_reset");
+
/* influence factors */
prop = RNA_def_property(srna, "time_factor", PROP_FLOAT, PROP_NONE);
@@ -2000,6 +2005,12 @@ static void rna_def_particle_settings_mtex(BlenderRNA *brna)
RNA_def_property_string_sdna(prop, NULL, "shapekey");
RNA_def_property_ui_text(prop, "Shape Key", "Name of the shape key affected by the texture");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
+
+ prop = RNA_def_property(srna, "particle_color_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "pacolfac");
+ RNA_def_property_ui_range(prop, 0, 1, 10, 3);
+ RNA_def_property_ui_text(prop, "Particle Color Factor", "Amount texture affects particle color");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
}
static void rna_def_particle_settings(BlenderRNA *brna)
@@ -2121,6 +2132,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
#ifdef USE_PARTICLE_HULL_DRAWING
{PART_DRAW_COL_PARENT, "PARENT", 0, "Parent", ""},
#endif
+ {PART_DRAW_COL_TEX, "TEXTURE", 0, "Texture", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -2808,7 +2820,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "phase_factor_random", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "randphasefac");
- RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_range(prop, 0.0f, 2.0f);
RNA_def_property_ui_text(prop, "Random Phase", "Randomize rotation around the chosen orientation axis");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 0428f5d8a9f..3ff51423e9a 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -231,7 +231,7 @@ static void rna_Pose_ik_solver_update(Main *bmain, Scene *UNUSED(scene), Pointer
Object *ob = ptr->id.data;
bPose *pose = ptr->data;
- pose->flag |= POSE_RECALC; /* checks & sorts pose channels */
+ BKE_pose_tag_recalc(bmain, pose); /* checks & sorts pose channels */
DAG_relations_tag_update(bmain);
BKE_pose_update_constraint_flags(pose);
@@ -356,7 +356,7 @@ static void rna_Itasc_update_rebuild(Main *bmain, Scene *scene, PointerRNA *ptr)
Object *ob = ptr->id.data;
bPose *pose = ob->pose;
- pose->flag |= POSE_RECALC; /* checks & sorts pose channels */
+ BKE_pose_tag_recalc(bmain, pose); /* checks & sorts pose channels */
rna_Itasc_update(bmain, scene, ptr);
}
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index 124a83a5f30..ee51dcf2acf 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -27,6 +27,7 @@
#include <stdlib.h>
#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
#include "BLI_utildefines.h"
#include "BLI_path_util.h"
@@ -153,8 +154,10 @@ static void engine_render(RenderEngine *engine, struct Scene *scene)
RNA_parameter_list_free(&list);
}
-static void engine_bake(RenderEngine *engine, struct Scene *scene, struct Object *object, const int pass_type,
- const struct BakePixel *pixel_array, const int num_pixels, const int depth, void *result)
+static void engine_bake(RenderEngine *engine, struct Scene *scene,
+ struct Object *object, const int pass_type,
+ const int object_id, const struct BakePixel *pixel_array,
+ const int num_pixels, const int depth, void *result)
{
extern FunctionRNA rna_RenderEngine_bake_func;
PointerRNA ptr;
@@ -168,6 +171,7 @@ static void engine_bake(RenderEngine *engine, struct Scene *scene, struct Object
RNA_parameter_set_lookup(&list, "scene", &scene);
RNA_parameter_set_lookup(&list, "object", &object);
RNA_parameter_set_lookup(&list, "pass_type", &pass_type);
+ RNA_parameter_set_lookup(&list, "object_id", &object_id);
RNA_parameter_set_lookup(&list, "pixel_array", &pixel_array);
RNA_parameter_set_lookup(&list, "num_pixels", &num_pixels);
RNA_parameter_set_lookup(&list, "depth", &depth);
@@ -253,6 +257,7 @@ static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, vo
/* setup dummy engine & engine type to store static properties in */
dummyengine.type = &dummyet;
+ dummyet.flag |= RE_USE_SHADING_NODES_CUSTOM;
RNA_pointer_create(NULL, &RNA_RenderEngine, &dummyengine, &dummyptr);
/* validate the python class */
@@ -322,38 +327,35 @@ static PointerRNA rna_RenderEngine_render_get(PointerRNA *ptr)
}
}
-static void rna_RenderResult_layers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+static PointerRNA rna_RenderEngine_camera_override_get(PointerRNA *ptr)
{
- RenderResult *rr = (RenderResult *)ptr->data;
- rna_iterator_listbase_begin(iter, &rr->layers, NULL);
-}
+ RenderEngine *engine = (RenderEngine *)ptr->data;
-static void rna_RenderLayer_passes_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
-{
- RenderLayer *rl = (RenderLayer *)ptr->data;
- rna_iterator_listbase_begin(iter, &rl->passes, NULL);
+ if (engine->re) {
+ Object *cam = RE_GetCamera(engine->re);
+ return rna_pointer_inherit_refine(ptr, &RNA_Object, cam);
+ }
+ else {
+ return rna_pointer_inherit_refine(ptr, &RNA_Object, engine->camera_override);
+ }
}
-static int rna_RenderLayer_rect_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static void rna_RenderResult_views_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
- RenderLayer *rl = (RenderLayer *)ptr->data;
-
- length[0] = rl->rectx * rl->recty;
- length[1] = 4;
-
- return length[0] * length[1];
+ RenderResult *rr = (RenderResult *)ptr->data;
+ rna_iterator_listbase_begin(iter, &rr->views, NULL);
}
-static void rna_RenderLayer_rect_get(PointerRNA *ptr, float *values)
+static void rna_RenderResult_layers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
- RenderLayer *rl = (RenderLayer *)ptr->data;
- memcpy(values, rl->rectf, sizeof(float) * rl->rectx * rl->recty * 4);
+ RenderResult *rr = (RenderResult *)ptr->data;
+ rna_iterator_listbase_begin(iter, &rr->layers, NULL);
}
-void rna_RenderLayer_rect_set(PointerRNA *ptr, const float *values)
+static void rna_RenderLayer_passes_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
RenderLayer *rl = (RenderLayer *)ptr->data;
- memcpy(rl->rectf, values, sizeof(float) * rl->rectx * rl->recty * 4);
+ rna_iterator_listbase_begin(iter, &rl->passes, NULL);
}
static int rna_RenderPass_rect_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
@@ -384,6 +386,11 @@ static PointerRNA rna_BakePixel_next_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_BakePixel, bp + 1);
}
+static RenderPass *rna_RenderPass_find_by_type(RenderLayer *rl, int passtype, const char *view)
+{
+ return RE_pass_find_by_type(rl, passtype, view);
+}
+
#else /* RNA_RUNTIME */
static void rna_def_render_engine(BlenderRNA *brna)
@@ -420,6 +427,8 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REQUIRED);
prop = RNA_def_enum(func, "pass_type", render_pass_type_items, 0, "Pass", "Pass to bake");
RNA_def_property_flag(prop, PROP_REQUIRED);
+ prop = RNA_def_int(func, "object_id", 0, 0, INT_MAX, "Object Id", "Id of the current object being baked in relation to the others", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_REQUIRED);
prop = RNA_def_pointer(func, "pixel_array", "BakePixel", "", "");
RNA_def_property_flag(prop, PROP_REQUIRED);
prop = RNA_def_int(func, "num_pixels", 0, 0, INT_MAX, "Number of Pixels", "Size of the baking batch", 0, INT_MAX);
@@ -467,6 +476,7 @@ static void rna_def_render_engine(BlenderRNA *brna)
prop = RNA_def_int(func, "h", 0, 0, INT_MAX, "Height", "", 0, INT_MAX);
RNA_def_property_flag(prop, PROP_REQUIRED);
RNA_def_string(func, "layer", NULL, 0, "Layer", "Single layer to get render result for"); /* NULL ok here */
+ RNA_def_string(func, "view", NULL, 0, "View", "Single view to get render result for"); /* NULL ok here */
prop = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
RNA_def_function_return(func, prop);
@@ -487,6 +497,22 @@ static void rna_def_render_engine(BlenderRNA *brna)
prop = RNA_def_boolean(func, "do_break", 0, "Break", "");
RNA_def_function_return(func, prop);
+ func = RNA_def_function(srna, "active_view_set", "RE_engine_active_view_set");
+ RNA_def_string(func, "view", NULL, 0, "View", "Single view to set as active"); /* NULL ok here */
+ RNA_def_property_flag(prop, PROP_REQUIRED);
+
+ func = RNA_def_function(srna, "camera_shift_x", "RE_engine_get_camera_shift_x");
+ prop = RNA_def_pointer(func, "camera", "Object", "", "");
+ RNA_def_property_flag(prop, PROP_REQUIRED);
+ prop = RNA_def_float(func, "shift_x", 0.0f, 0.0f, FLT_MAX, "Shift X", "", 0.0f, FLT_MAX);
+ RNA_def_function_return(func, prop);
+
+ func = RNA_def_function(srna, "camera_model_matrix", "RE_engine_get_camera_model_matrix");
+ prop = RNA_def_pointer(func, "camera", "Object", "", "");
+ RNA_def_property_flag(prop, PROP_REQUIRED);
+ prop = RNA_def_float_matrix(func, "r_model_matrix", 4, 4, NULL, 0.0f, 0.0f, "Model Matrix", "Normalized camera model matrix", 0.0f, 0.0f);
+ RNA_def_property_flag(prop, PROP_REQUIRED);
+
func = RNA_def_function(srna, "update_stats", "RE_engine_update_stats");
RNA_def_function_ui_description(func, "Update and signal to redraw render status text");
prop = RNA_def_string(func, "stats", NULL, 0, "Stats", "");
@@ -548,7 +574,7 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", RE_ENGINE_PREVIEW);
prop = RNA_def_property(srna, "camera_override", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "camera_override");
+ RNA_def_property_pointer_funcs(prop, "rna_RenderEngine_camera_override_get", NULL, NULL, NULL);
RNA_def_property_struct_type(prop, "Object");
prop = RNA_def_property(srna, "layer_override", PROP_BOOLEAN, PROP_LAYER_MEMBER);
@@ -603,6 +629,11 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_SHADING_NODES);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ prop = RNA_def_property(srna, "bl_use_shading_nodes_custom", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_SHADING_NODES_CUSTOM);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+
prop = RNA_def_property(srna, "bl_use_exclude_layers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_EXCLUDE_LAYERS);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
@@ -647,9 +678,56 @@ static void rna_def_render_result(BlenderRNA *brna)
"rna_iterator_listbase_end", "rna_iterator_listbase_get",
NULL, NULL, NULL, NULL);
+ parm = RNA_def_property(srna, "views", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(parm, "RenderView");
+ RNA_def_property_collection_funcs(parm, "rna_RenderResult_views_begin", "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end", "rna_iterator_listbase_get",
+ NULL, NULL, NULL, NULL);
+
RNA_define_verify_sdna(1);
}
+static void rna_def_render_view(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "RenderView", NULL);
+ RNA_def_struct_ui_text(srna, "Render View", "");
+
+ RNA_define_verify_sdna(0);
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "name");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_struct_name_property(srna, prop);
+
+ RNA_define_verify_sdna(1);
+}
+
+static void rna_def_render_passes(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "RenderPasses");
+ srna = RNA_def_struct(brna, "RenderPasses", NULL);
+ RNA_def_struct_sdna(srna, "RenderLayer");
+ RNA_def_struct_ui_text(srna, "Render Passes", "Collection of render passes");
+
+ func = RNA_def_function(srna, "find_by_type", "rna_RenderPass_find_by_type");
+ RNA_def_function_ui_description(func, "Get the render pass for a given type and view");
+ parm = RNA_def_enum(func, "pass_type", render_pass_type_items, SCE_PASS_COMBINED, "Pass", "");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_string(func, "view", NULL, 0, "View", "Render view to get pass from"); /* NULL ok here */
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "render_pass", "RenderPass", "", "The matching render pass");
+ RNA_def_function_return(func, parm);
+
+}
+
static void rna_def_render_layer(BlenderRNA *brna)
{
StructRNA *srna;
@@ -679,12 +757,7 @@ static void rna_def_render_layer(BlenderRNA *brna)
RNA_def_property_collection_funcs(prop, "rna_RenderLayer_passes_begin", "rna_iterator_listbase_next",
"rna_iterator_listbase_end", "rna_iterator_listbase_get",
NULL, NULL, NULL, NULL);
-
- prop = RNA_def_property(srna, "rect", PROP_FLOAT, PROP_NONE);
- RNA_def_property_flag(prop, PROP_DYNAMIC);
- RNA_def_property_multi_array(prop, 2, NULL);
- RNA_def_property_dynamic_array_funcs(prop, "rna_RenderLayer_rect_get_length");
- RNA_def_property_float_funcs(prop, "rna_RenderLayer_rect_get", "rna_RenderLayer_rect_set", NULL);
+ rna_def_render_passes(brna, prop);
RNA_define_verify_sdna(1);
}
@@ -728,6 +801,10 @@ static void rna_def_render_pass(BlenderRNA *brna)
RNA_def_property_dynamic_array_funcs(prop, "rna_RenderPass_rect_get_length");
RNA_def_property_float_funcs(prop, "rna_RenderPass_rect_get", "rna_RenderPass_rect_set", NULL);
+ prop = RNA_def_property(srna, "view_id", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "view_id");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
prop = RNA_def_property(srna, "debug_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "debug_type");
RNA_def_property_enum_items(prop, render_pass_debug_type_items);
@@ -750,6 +827,10 @@ static void rna_def_render_bake_pixel(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "primitive_id");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ prop = RNA_def_property(srna, "object_id", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "object_id");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
prop = RNA_def_property(srna, "uv", PROP_FLOAT, PROP_NONE);
RNA_def_property_array(prop, 2);
RNA_def_property_float_sdna(prop, NULL, "uv");
@@ -783,6 +864,7 @@ void RNA_def_render(BlenderRNA *brna)
{
rna_def_render_engine(brna);
rna_def_render_result(brna);
+ rna_def_render_view(brna);
rna_def_render_layer(brna);
rna_def_render_pass(brna);
rna_def_render_bake_pixel(brna);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index d8feebaa129..810d83a8ddf 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -36,6 +36,8 @@
#include "DNA_userdef_types.h"
#include "DNA_world_types.h"
+#include "IMB_imbuf_types.h"
+
#include "BLI_math.h"
#include "BLF_translation.h"
@@ -45,6 +47,8 @@
#include "BKE_paint.h"
#include "BKE_scene.h"
+#include "GPU_extensions.h"
+
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -82,6 +86,11 @@ EnumPropertyItem exr_codec_items[] = {
{R_IMF_EXR_CODEC_ZIP, "ZIP", 0, "ZIP (lossless)", ""},
{R_IMF_EXR_CODEC_PIZ, "PIZ", 0, "PIZ (lossless)", ""},
{R_IMF_EXR_CODEC_RLE, "RLE", 0, "RLE (lossless)", ""},
+ {R_IMF_EXR_CODEC_ZIPS, "ZIPS", 0, "ZIPS (lossless)", ""},
+ {R_IMF_EXR_CODEC_B44, "B44", 0, "B44 (lossy)", ""},
+ {R_IMF_EXR_CODEC_B44A, "B44A", 0, "B44A (lossy)", ""},
+ {R_IMF_EXR_CODEC_DWAA, "DWAA", 0, "DWAA (lossy)", ""},
+ {R_IMF_EXR_CODEC_DWAB, "DWAB", 0, "DWAB (lossy)", ""},
{0, NULL, 0, NULL, NULL}
};
#endif
@@ -125,6 +134,7 @@ EnumPropertyItem proportional_falloff_curve_only_items[] = {
{PROP_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", "Smooth falloff"},
{PROP_SPHERE, "SPHERE", ICON_SPHERECURVE, "Sphere", "Spherical falloff"},
{PROP_ROOT, "ROOT", ICON_ROOTCURVE, "Root", "Root falloff"},
+ {PROP_INVSQUARE, "INVERSE_SQUARE", ICON_ROOTCURVE, "Inverse Square", "Inverse Square falloff"},
{PROP_SHARP, "SHARP", ICON_SHARPCURVE, "Sharp", "Sharp falloff"},
{PROP_LIN, "LINEAR", ICON_LINCURVE, "Linear", "Linear falloff"},
{0, NULL, 0, NULL, NULL}
@@ -210,13 +220,13 @@ EnumPropertyItem snap_uv_element_items[] = {
#endif
#ifdef WITH_OPENEXR
-# define R_IMF_ENUM_EXR_MULTI {R_IMF_IMTYPE_MULTILAYER, "OPEN_EXR_MULTILAYER", ICON_FILE_IMAGE, \
+# define R_IMF_ENUM_EXR_MULTILAYER {R_IMF_IMTYPE_MULTILAYER, "OPEN_EXR_MULTILAYER", ICON_FILE_IMAGE, \
"OpenEXR MultiLayer", \
"Output image in multilayer OpenEXR format"},
# define R_IMF_ENUM_EXR {R_IMF_IMTYPE_OPENEXR, "OPEN_EXR", ICON_FILE_IMAGE, "OpenEXR", \
"Output image in OpenEXR format"},
#else
-# define R_IMF_ENUM_EXR_MULTI
+# define R_IMF_ENUM_EXR_MULTILAYER
# define R_IMF_ENUM_EXR
#endif
@@ -245,7 +255,7 @@ EnumPropertyItem snap_uv_element_items[] = {
{0, "", 0, " ", NULL}, \
R_IMF_ENUM_CINEON \
R_IMF_ENUM_DPX \
- R_IMF_ENUM_EXR_MULTI \
+ R_IMF_ENUM_EXR_MULTILAYER \
R_IMF_ENUM_EXR \
R_IMF_ENUM_HDR \
R_IMF_ENUM_TIFF \
@@ -329,6 +339,62 @@ EnumPropertyItem bake_save_mode_items[] = {
{0, NULL, 0, NULL, NULL}
};
+#define R_IMF_VIEWS_ENUM_IND {R_IMF_VIEWS_INDIVIDUAL, "INDIVIDUAL", 0, "Individual", \
+ "Individual files for each view with the prefix as defined by the scene views"},
+#define R_IMF_VIEWS_ENUM_S3D {R_IMF_VIEWS_STEREO_3D, "STEREO_3D", 0, "Stereo 3D", \
+ "Single file with an encoded stereo pair"},
+#define R_IMF_VIEWS_ENUM_MV {R_IMF_VIEWS_MULTIVIEW, "MULTIVIEW", 0, "Multi-View", "Single file with all the views"},
+
+EnumPropertyItem views_format_items[] = {
+ R_IMF_VIEWS_ENUM_IND
+ R_IMF_VIEWS_ENUM_S3D
+ {0, NULL, 0, NULL, NULL}
+};
+
+EnumPropertyItem views_format_multilayer_items[] = {
+ R_IMF_VIEWS_ENUM_IND
+ R_IMF_VIEWS_ENUM_MV
+ {0, NULL, 0, NULL, NULL}
+};
+
+EnumPropertyItem views_format_multiview_items[] = {
+ R_IMF_VIEWS_ENUM_IND
+ R_IMF_VIEWS_ENUM_S3D
+ R_IMF_VIEWS_ENUM_MV
+ {0, NULL, 0, NULL, NULL}
+};
+
+#undef R_IMF_VIEWS_ENUM_IND
+#undef R_IMF_VIEWS_ENUM_S3D
+#undef R_IMF_VIEWS_ENUM_MV
+
+EnumPropertyItem stereo3d_display_items[] = {
+ {S3D_DISPLAY_ANAGLYPH, "ANAGLYPH", 0, "Anaglyph",
+ "Render views for left and right eyes as two differently filtered colors in a single image "
+ "(anaglyph glasses are required)"},
+ {S3D_DISPLAY_INTERLACE, "INTERLACE", 0, "Interlace",
+ "Render views for left and right eyes interlaced in a single image (3D-ready monitor is required)"},
+ {S3D_DISPLAY_PAGEFLIP, "TIMESEQUENTIAL", 0, "Time Sequential",
+ "Render alternate eyes (also known as page flip, quad buffer support in the graphic card is required)"},
+ {S3D_DISPLAY_SIDEBYSIDE, "SIDEBYSIDE", 0, "Side-by-Side", "Render views for left and right eyes side-by-side"},
+ {S3D_DISPLAY_TOPBOTTOM, "TOPBOTTOM", 0, "Top-Bottom", "Render views for left and right eyes one above another"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+EnumPropertyItem stereo3d_anaglyph_type_items[] = {
+ {S3D_ANAGLYPH_REDCYAN, "RED_CYAN", 0, "Red-Cyan", ""},
+ {S3D_ANAGLYPH_GREENMAGENTA, "GREEN_MAGENTA", 0, "Green-Magenta", ""},
+ {S3D_ANAGLYPH_YELLOWBLUE, "YELLOW_BLUE", 0, "Yellow-Blue", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+EnumPropertyItem stereo3d_interlace_type_items[] = {
+ {S3D_INTERLACE_ROW, "ROW_INTERLEAVED", 0, "Row Interleaved", ""},
+ {S3D_INTERLACE_COLUMN, "COLUMN_INTERLEAVED", 0, "Column Interleaved", ""},
+ {S3D_INTERLACE_CHECKERBOARD, "CHECKERBOARD_INTERLEAVED", 0, "Checkerboard Interleaved", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifdef RNA_RUNTIME
#include "DNA_anim_types.h"
@@ -533,13 +599,13 @@ static void rna_Scene_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr)
static void rna_Scene_fps_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
- sound_update_fps(scene);
+ BKE_sound_update_fps(scene);
BKE_sequencer_update_sound_bounds_all(scene);
}
static void rna_Scene_listener_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
- sound_update_scene_listener(scene);
+ BKE_sound_update_scene_listener(scene);
}
static void rna_Scene_volume_set(PointerRNA *ptr, float value)
@@ -548,7 +614,7 @@ static void rna_Scene_volume_set(PointerRNA *ptr, float value)
scene->audio.volume = value;
if (scene->sound_scene)
- sound_set_scene_volume(scene, value);
+ BKE_sound_set_scene_volume(scene, value);
}
static void rna_Scene_framelen_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
@@ -649,7 +715,7 @@ static void rna_Scene_preview_range_end_frame_set(PointerRNA *ptr, int value)
static void rna_Scene_frame_update(Main *bmain, Scene *UNUSED(current_scene), PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->id.data;
- sound_seek_scene(bmain, scene);
+ BKE_sound_seek_scene(bmain, scene);
}
static PointerRNA rna_Scene_active_keying_set_get(PointerRNA *ptr)
@@ -716,6 +782,26 @@ static void rna_Scene_all_keyingsets_next(CollectionPropertyIterator *iter)
iter->valid = (internal->link != NULL);
}
+static int rna_RenderSettings_stereoViews_skip(CollectionPropertyIterator *iter, void *UNUSED(data))
+{
+ ListBaseIterator *internal = &iter->internal.listbase;
+ SceneRenderView *srv = (SceneRenderView *)internal->link;
+
+ if ((STREQ(srv->name, STEREO_LEFT_NAME)) ||
+ (STREQ(srv->name, STEREO_RIGHT_NAME)))
+ {
+ return 0;
+ }
+
+ return 1;
+};
+
+static void rna_RenderSettings_stereoViews_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ RenderData *rd = (RenderData *)ptr->data;
+ rna_iterator_listbase_begin(iter, &rd->views, rna_RenderSettings_stereoViews_skip);
+}
+
static char *rna_RenderSettings_path(PointerRNA *UNUSED(ptr))
{
return BLI_sprintfN("render");
@@ -818,8 +904,8 @@ static void rna_ImageFormatSettings_file_format_set(PointerRNA *ptr, int value)
}
}
-static EnumPropertyItem *rna_ImageFormatSettings_file_format_itemf(bContext *UNUSED(C), PointerRNA *ptr,
- PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
+static EnumPropertyItem *rna_ImageFormatSettings_file_format_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
{
ID *id = ptr->id.data;
if (id && GS(id->name) == ID_SCE) {
@@ -830,8 +916,8 @@ static EnumPropertyItem *rna_ImageFormatSettings_file_format_itemf(bContext *UNU
}
}
-static EnumPropertyItem *rna_ImageFormatSettings_color_mode_itemf(bContext *UNUSED(C), PointerRNA *ptr,
- PropertyRNA *UNUSED(prop), bool *r_free)
+static EnumPropertyItem *rna_ImageFormatSettings_color_mode_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
ImageFormatData *imf = (ImageFormatData *)ptr->data;
ID *id = ptr->id.data;
@@ -875,8 +961,8 @@ static EnumPropertyItem *rna_ImageFormatSettings_color_mode_itemf(bContext *UNUS
}
}
-static EnumPropertyItem *rna_ImageFormatSettings_color_depth_itemf(bContext *UNUSED(C), PointerRNA *ptr,
- PropertyRNA *UNUSED(prop), bool *r_free)
+static EnumPropertyItem *rna_ImageFormatSettings_color_depth_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
ImageFormatData *imf = (ImageFormatData *)ptr->data;
@@ -938,6 +1024,54 @@ static EnumPropertyItem *rna_ImageFormatSettings_color_depth_itemf(bContext *UNU
}
}
+static EnumPropertyItem *rna_ImageFormatSettings_views_format_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
+{
+ ImageFormatData *imf = (ImageFormatData *)ptr->data;
+
+ if (imf == NULL) {
+ return views_format_items;
+ }
+ else if (imf->imtype == R_IMF_IMTYPE_OPENEXR) {
+ return views_format_multiview_items;
+ }
+ else if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
+ return views_format_multilayer_items;
+ }
+ else {
+ return views_format_items;
+ }
+}
+
+#ifdef WITH_OPENEXR
+ /* OpenEXR */
+
+static EnumPropertyItem *rna_ImageFormatSettings_exr_codec_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ ImageFormatData *imf = (ImageFormatData *)ptr->data;
+
+ EnumPropertyItem *item = NULL;
+ int i = 1, totitem = 0;
+
+ if (imf->depth == 16)
+ return exr_codec_items; /* All compression types are defined for halfs */
+
+ for (i = 0; i < R_IMF_EXR_CODEC_MAX; i++) {
+ if ((i == R_IMF_EXR_CODEC_B44 || i == R_IMF_EXR_CODEC_B44A)) {
+ continue; /* B44 and B44A are not defined for 32 bit floats */
+ }
+
+ RNA_enum_item_add(&item, &totitem, &exr_codec_items[i]);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+#endif
static int rna_SceneRender_file_ext_length(PointerRNA *ptr)
{
RenderData *rd = (RenderData *)ptr->data;
@@ -969,8 +1103,8 @@ static void rna_RenderSettings_qtcodecsettings_codecType_set(PointerRNA *ptr, in
settings->codecType = quicktime_videocodecType_from_rnatmpvalue(value);
}
-static EnumPropertyItem *rna_RenderSettings_qtcodecsettings_codecType_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop), bool *r_free)
+static EnumPropertyItem *rna_RenderSettings_qtcodecsettings_codecType_itemf(
+ bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
EnumPropertyItem *item = NULL;
EnumPropertyItem tmp = {0, "", 0, "", ""};
@@ -1007,8 +1141,8 @@ static void rna_RenderSettings_qtcodecsettings_audiocodecType_set(PointerRNA *pt
settings->audiocodecType = quicktime_audiocodecType_from_rnatmpvalue(value);
}
-static EnumPropertyItem *rna_RenderSettings_qtcodecsettings_audiocodecType_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop), bool *r_free)
+static EnumPropertyItem *rna_RenderSettings_qtcodecsettings_audiocodecType_itemf(
+ bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
EnumPropertyItem *item = NULL;
EnumPropertyItem tmp = {0, "", 0, "", ""};
@@ -1068,8 +1202,8 @@ static void rna_RenderSettings_active_layer_index_set(PointerRNA *ptr, int value
rd->actlay = min_ff(value, num_layers - 1);
}
-static void rna_RenderSettings_active_layer_index_range(PointerRNA *ptr, int *min, int *max,
- int *UNUSED(softmin), int *UNUSED(softmax))
+static void rna_RenderSettings_active_layer_index_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
{
RenderData *rd = (RenderData *)ptr->data;
@@ -1104,8 +1238,8 @@ static SceneRenderLayer *rna_RenderLayer_new(ID *id, RenderData *UNUSED(rd), con
return srl;
}
-static void rna_RenderLayer_remove(ID *id, RenderData *UNUSED(rd), Main *bmain, ReportList *reports,
- PointerRNA *srl_ptr)
+static void rna_RenderLayer_remove(
+ ID *id, RenderData *UNUSED(rd), Main *bmain, ReportList *reports, PointerRNA *srl_ptr)
{
SceneRenderLayer *srl = srl_ptr->data;
Scene *scene = (Scene *)id;
@@ -1122,6 +1256,70 @@ static void rna_RenderLayer_remove(ID *id, RenderData *UNUSED(rd), Main *bmain,
WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL);
}
+static int rna_RenderSettings_active_view_index_get(PointerRNA *ptr)
+{
+ RenderData *rd = (RenderData *)ptr->data;
+ return rd->actview;
+}
+
+static void rna_RenderSettings_active_view_index_set(PointerRNA *ptr, int value)
+{
+ RenderData *rd = (RenderData *)ptr->data;
+ rd->actview = value;
+}
+
+static void rna_RenderSettings_active_view_index_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ RenderData *rd = (RenderData *)ptr->data;
+
+ *min = 0;
+ *max = max_ii(0, BLI_listbase_count(&rd->views) - 1);
+}
+
+static PointerRNA rna_RenderSettings_active_view_get(PointerRNA *ptr)
+{
+ RenderData *rd = (RenderData *)ptr->data;
+ SceneRenderView *srv = BLI_findlink(&rd->views, rd->actview);
+
+ return rna_pointer_inherit_refine(ptr, &RNA_SceneRenderView, srv);
+}
+
+static void rna_RenderSettings_active_view_set(PointerRNA *ptr, PointerRNA value)
+{
+ RenderData *rd = (RenderData *)ptr->data;
+ SceneRenderView *srv = (SceneRenderView *)value.data;
+ const int index = BLI_findindex(&rd->views, srv);
+ if (index != -1) rd->actview = index;
+}
+
+static SceneRenderView *rna_RenderView_new(ID *id, RenderData *UNUSED(rd), const char *name)
+{
+ Scene *scene = (Scene *)id;
+ SceneRenderView *srv = BKE_scene_add_render_view(scene, name);
+
+ WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ return srv;
+}
+
+static void rna_RenderView_remove(
+ ID *id, RenderData *UNUSED(rd), Main *UNUSED(bmain), ReportList *reports, PointerRNA *srv_ptr)
+{
+ SceneRenderView *srv = srv_ptr->data;
+ Scene *scene = (Scene *)id;
+
+ if (!BKE_scene_remove_render_view(scene, srv)) {
+ BKE_reportf(reports, RPT_ERROR, "Render view '%s' could not be removed from scene '%s'",
+ srv->name, scene->id.name + 2);
+ return;
+ }
+
+ RNA_POINTER_INVALIDATE(srv_ptr);
+
+ WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL);
+}
+
static void rna_RenderSettings_engine_set(PointerRNA *ptr, int value)
{
RenderData *rd = (RenderData *)ptr->data;
@@ -1131,8 +1329,8 @@ static void rna_RenderSettings_engine_set(PointerRNA *ptr, int value)
BLI_strncpy_utf8(rd->engine, type->idname, sizeof(rd->engine));
}
-static EnumPropertyItem *rna_RenderSettings_engine_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop), bool *r_free)
+static EnumPropertyItem *rna_RenderSettings_engine_itemf(
+ bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
RenderEngineType *type;
EnumPropertyItem *item = NULL;
@@ -1215,7 +1413,7 @@ static void rna_SceneRenderLayer_name_set(PointerRNA *ptr, const char *value)
}
/* fix all the animation data which may link to this */
- BKE_all_animdata_fix_paths_rename(NULL, "render.layers", oldname, rl->name);
+ BKE_animdata_fix_paths_rename_all(NULL, "render.layers", oldname, rl->name);
}
static char *rna_SceneRenderLayer_path(PointerRNA *ptr)
@@ -1227,6 +1425,34 @@ static char *rna_SceneRenderLayer_path(PointerRNA *ptr)
return BLI_sprintfN("render.layers[\"%s\"]", name_esc);
}
+static void rna_SceneRenderView_name_set(PointerRNA *ptr, const char *value)
+{
+ Scene *scene = (Scene *)ptr->id.data;
+ SceneRenderView *rv = (SceneRenderView *)ptr->data;
+ BLI_strncpy_utf8(rv->name, value, sizeof(rv->name));
+ BLI_uniquename(&scene->r.views, rv, DATA_("RenderView"), '.', offsetof(SceneRenderView, name), sizeof(rv->name));
+}
+
+static char *rna_SceneRenderView_path(PointerRNA *ptr)
+{
+ SceneRenderView *srv = (SceneRenderView *)ptr->data;
+ return BLI_sprintfN("render.views[\"%s\"]", srv->name);
+}
+
+static void rna_RenderSettings_views_format_set(PointerRNA *ptr, int value)
+{
+ RenderData *rd = (RenderData *)ptr->data;
+
+ if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW &&
+ value == SCE_VIEWS_FORMAT_STEREO_3D)
+ {
+ /* make sure the actview is visible */
+ if (rd->actview > 1) rd->actview = 1;
+ }
+
+ rd->views_format = value;
+}
+
static int rna_RenderSettings_multiple_engines_get(PointerRNA *UNUSED(ptr))
{
return (BLI_listbase_count(&R_engines) > 1);
@@ -1388,7 +1614,7 @@ static void rna_Scene_use_audio_set(PointerRNA *ptr, int value)
else
scene->audio.flag &= ~AUDIO_MUTE;
- sound_mute_scene(scene, value);
+ BKE_sound_mute_scene(scene, value);
}
static int rna_Scene_sync_mode_get(PointerRNA *ptr)
@@ -1602,10 +1828,11 @@ static void rna_FreestyleLineSet_linestyle_set(PointerRNA *ptr, PointerRNA value
lineset->linestyle->id.us++;
}
-static FreestyleLineSet *rna_FreestyleSettings_lineset_add(ID *id, FreestyleSettings *config, const char *name)
+static FreestyleLineSet *rna_FreestyleSettings_lineset_add(
+ ID *id, FreestyleSettings *config, Main *bmain, const char *name)
{
Scene *scene = (Scene *)id;
- FreestyleLineSet *lineset = BKE_freestyle_lineset_add((FreestyleConfig *)config, name);
+ FreestyleLineSet *lineset = BKE_freestyle_lineset_add(bmain, (FreestyleConfig *)config, name);
DAG_id_tag_update(&scene->id, 0);
WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -1613,8 +1840,8 @@ static FreestyleLineSet *rna_FreestyleSettings_lineset_add(ID *id, FreestyleSett
return lineset;
}
-static void rna_FreestyleSettings_lineset_remove(ID *id, FreestyleSettings *config, ReportList *reports,
- PointerRNA *lineset_ptr)
+static void rna_FreestyleSettings_lineset_remove(
+ ID *id, FreestyleSettings *config, ReportList *reports, PointerRNA *lineset_ptr)
{
FreestyleLineSet *lineset = lineset_ptr->data;
Scene *scene = (Scene *)id;
@@ -1637,8 +1864,8 @@ static PointerRNA rna_FreestyleSettings_active_lineset_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_FreestyleLineSet, lineset);
}
-static void rna_FreestyleSettings_active_lineset_index_range(PointerRNA *ptr, int *min, int *max,
- int *UNUSED(softmin), int *UNUSED(softmax))
+static void rna_FreestyleSettings_active_lineset_index_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
{
FreestyleConfig *config = (FreestyleConfig *)ptr->data;
@@ -1669,8 +1896,8 @@ static FreestyleModuleConfig *rna_FreestyleSettings_module_add(ID *id, Freestyle
return module;
}
-static void rna_FreestyleSettings_module_remove(ID *id, FreestyleSettings *config, ReportList *reports,
- PointerRNA *module_ptr)
+static void rna_FreestyleSettings_module_remove(
+ ID *id, FreestyleSettings *config, ReportList *reports, PointerRNA *module_ptr)
{
Scene *scene = (Scene *)id;
FreestyleModuleConfig *module = module_ptr->data;
@@ -1679,7 +1906,7 @@ static void rna_FreestyleSettings_module_remove(ID *id, FreestyleSettings *confi
if (module->script)
BKE_reportf(reports, RPT_ERROR, "Style module '%s' could not be removed", module->script->id.name + 2);
else
- BKE_reportf(reports, RPT_ERROR, "Style module could not be removed");
+ BKE_report(reports, RPT_ERROR, "Style module could not be removed");
return;
}
@@ -1711,6 +1938,44 @@ static void rna_GPUFXSettings_fx_update(Main *UNUSED(bmain), Scene *UNUSED(scene
BKE_screen_gpu_fx_validate(fx_settings);
}
+static void rna_GPUDOFSettings_blades_set(PointerRNA *ptr, const int value)
+{
+ GPUDOFSettings *dofsettings = (GPUDOFSettings *)ptr->data;
+
+ if (value < 3 && dofsettings->num_blades > 2)
+ dofsettings->num_blades = 0;
+ else if (value > 0 && dofsettings->num_blades == 0)
+ dofsettings->num_blades = 3;
+ else
+ dofsettings->num_blades = value;
+}
+
+static void rna_Stereo3dFormat_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ ID *id = ptr->id.data;
+
+ if (id && GS(id->name) == ID_IM) {
+ Image *ima = (Image *)id;
+ ImBuf *ibuf;
+ void *lock;
+
+ if ((ima->flag & IMA_IS_STEREO) == 0)
+ return;
+
+ ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
+
+ if (ibuf) {
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
+ }
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ }
+}
+
+static int rna_gpu_is_hq_supported_get(PointerRNA *UNUSED(ptr))
+{
+ return GPU_instanced_drawing_support() && GPU_geometry_shader_support();
+}
+
#else
static void rna_def_transform_orientation(BlenderRNA *brna)
@@ -1796,9 +2061,11 @@ static void rna_def_tool_settings(BlenderRNA *brna)
static EnumPropertyItem gpencil_source_3d_items[] = {
{GP_TOOL_SOURCE_SCENE, "SCENE", 0, "Scene",
- "Grease Pencil data attached to the current scene is used, unless the active object already has Grease Pencil data (i.e. for old files)"},
+ "Grease Pencil data attached to the current scene is used, "
+ "unless the active object already has Grease Pencil data (i.e. for old files)"},
{GP_TOOL_SOURCE_OBJECT, "OBJECT", 0, "Object",
- "Grease Pencil datablocks attached to the active object are used (required using pre 2.73 add-ons, e.g. BSurfaces)"},
+ "Grease Pencil datablocks attached to the active object are used "
+ "(required using pre 2.73 add-ons, e.g. BSurfaces)"},
{0, NULL, 0, NULL, NULL}
};
@@ -1856,6 +2123,10 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "particle");
RNA_def_property_ui_text(prop, "Particle Edit", "");
+ prop = RNA_def_property(srna, "hair_edit", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "hair_edit");
+ RNA_def_property_ui_text(prop, "Hair Edit", "");
+
prop = RNA_def_property(srna, "use_uv_sculpt", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_uv_sculpt", 1);
RNA_def_property_ui_text(prop, "UV Sculpt", "Enable brush for UV sculpting");
@@ -1906,6 +2177,22 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_PROP_OFF, 1);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+ prop = RNA_def_property(srna, "use_proportional_action", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "proportional_action", 0);
+ RNA_def_property_ui_text(prop, "Proportional Editing Actions", "Proportional editing in action editor");
+ RNA_def_property_ui_icon(prop, ICON_PROP_OFF, 1);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+
+ prop = RNA_def_property(srna, "use_proportional_fcurve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "proportional_fcurve", 0);
+ RNA_def_property_ui_text(prop, "Proportional Editing FCurves", "Proportional editing in FCurve editor");
+ RNA_def_property_ui_icon(prop, ICON_PROP_OFF, 1);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+
+ prop = RNA_def_property(srna, "lock_markers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "lock_markers", 0);
+ RNA_def_property_ui_text(prop, "Lock Markers", "Prevent marker editing");
+
prop = RNA_def_property(srna, "proportional_edit_falloff", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "prop_mode");
RNA_def_property_enum_items(prop, proportional_falloff_items);
@@ -2086,7 +2373,8 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_etch_autoname", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "skgen_retarget_options", SK_RETARGET_AUTONAME);
- RNA_def_property_ui_text(prop, "Autoname Bones", "Automatically generate values to replace &N and &S suffix placeholders in template names");
+ RNA_def_property_ui_text(prop, "Autoname Bones",
+ "Automatically generate values to replace &N and &S suffix placeholders in template names");
prop = RNA_def_property(srna, "etch_number", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "skgen_num_string");
@@ -2813,7 +3101,7 @@ static void rna_def_freestyle_linesets(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_FreestyleSettings_lineset_add");
RNA_def_function_ui_description(func, "Add a line set to scene render layer Freestyle settings");
- RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+ RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_SELF_ID);
parm = RNA_def_string(func, "name", "LineSet", 0, "", "New name for the line set (not unique)");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_pointer(func, "lineset", "FreestyleLineSet", "", "Newly created line set");
@@ -2974,12 +3262,14 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "face_mark_condition", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
RNA_def_property_enum_items(prop, face_mark_condition_items);
- RNA_def_property_ui_text(prop, "Face Mark Condition", "Specify a feature edge selection condition based on face marks");
+ RNA_def_property_ui_text(prop, "Face Mark Condition",
+ "Specify a feature edge selection condition based on face marks");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_silhouette", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_SILHOUETTE);
- RNA_def_property_ui_text(prop, "Silhouette", "Select silhouettes (edges at the boundary of visible and hidden faces)");
+ RNA_def_property_ui_text(prop, "Silhouette",
+ "Select silhouettes (edges at the boundary of visible and hidden faces)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_border", PROP_BOOLEAN, PROP_NONE);
@@ -2989,12 +3279,14 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "select_crease", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_CREASE);
- RNA_def_property_ui_text(prop, "Crease", "Select crease edges (those between two faces making an angle smaller than the Crease Angle)");
+ RNA_def_property_ui_text(prop, "Crease",
+ "Select crease edges (those between two faces making an angle smaller than the Crease Angle)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_ridge_valley", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_RIDGE_VALLEY);
- RNA_def_property_ui_text(prop, "Ridge & Valley", "Select ridges and valleys (boundary lines between convex and concave areas of surface)");
+ RNA_def_property_ui_text(prop, "Ridge & Valley",
+ "Select ridges and valleys (boundary lines between convex and concave areas of surface)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_suggestive_contour", PROP_BOOLEAN, PROP_NONE);
@@ -3014,7 +3306,8 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "select_external_contour", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_EXTERNAL_CONTOUR);
- RNA_def_property_ui_text(prop, "External Contour", "Select external contours (outer silhouettes of occluding and occluded objects)");
+ RNA_def_property_ui_text(prop, "External Contour",
+ "Select external contours (outer silhouettes of occluding and occluded objects)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_edge_mark", PROP_BOOLEAN, PROP_NONE);
@@ -3163,7 +3456,8 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_view_map_cache", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_VIEW_MAP_CACHE);
- RNA_def_property_ui_text(prop, "View Map Cache", "Keep the computed view map and avoid re-calculating it if mesh geometry is unchanged");
+ RNA_def_property_ui_text(prop, "View Map Cache",
+ "Keep the computed view map and avoid re-calculating it if mesh geometry is unchanged");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_use_view_map_cache_update");
prop = RNA_def_property(srna, "sphere_radius", PROP_FLOAT, PROP_NONE);
@@ -3204,36 +3498,42 @@ static void rna_def_scene_game_recast_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "cell_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "cellsize");
RNA_def_property_ui_range(prop, 0.1, 1, 1, 2);
+ RNA_def_property_float_default(prop, 0.3f);
RNA_def_property_ui_text(prop, "Cell Size", "Rasterized cell size");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "cell_height", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "cellheight");
RNA_def_property_ui_range(prop, 0.1, 1, 1, 2);
+ RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_ui_text(prop, "Cell Height", "Rasterized cell height");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "agent_height", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "agentheight");
RNA_def_property_ui_range(prop, 0.1, 5, 1, 2);
+ RNA_def_property_float_default(prop, 2.0f);
RNA_def_property_ui_text(prop, "Agent Height", "Minimum height where the agent can still walk");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "agent_radius", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "agentradius");
RNA_def_property_ui_range(prop, 0.1, 5, 1, 2);
+ RNA_def_property_float_default(prop, 0.6f);
RNA_def_property_ui_text(prop, "Agent Radius", "Radius of the agent");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "climb_max", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "agentmaxclimb");
RNA_def_property_ui_range(prop, 0.1, 5, 1, 2);
+ RNA_def_property_float_default(prop, 0.9f);
RNA_def_property_ui_text(prop, "Max Climb", "Maximum height between grid cells the agent can climb");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "slope_max", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "agentmaxslope");
RNA_def_property_range(prop, 0, M_PI_2);
+ RNA_def_property_float_default(prop, M_PI_4);
RNA_def_property_ui_text(prop, "Max Slope", "Maximum walkable slope angle");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3241,42 +3541,49 @@ static void rna_def_scene_game_recast_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "region_min_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "regionminsize");
RNA_def_property_ui_range(prop, 0, 150, 1, 2);
+ RNA_def_property_float_default(prop, 8.0f);
RNA_def_property_ui_text(prop, "Min Region Size", "Minimum regions size (smaller regions will be deleted)");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "region_merge_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "regionmergesize");
RNA_def_property_ui_range(prop, 0, 150, 1, 2);
+ RNA_def_property_float_default(prop, 20.0f);
RNA_def_property_ui_text(prop, "Merged Region Size", "Minimum regions size (smaller regions will be merged)");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "edge_max_len", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "edgemaxlen");
RNA_def_property_ui_range(prop, 0, 50, 1, 2);
+ RNA_def_property_float_default(prop, 12.0f);
RNA_def_property_ui_text(prop, "Max Edge Length", "Maximum contour edge length");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "edge_max_error", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "edgemaxerror");
RNA_def_property_ui_range(prop, 0.1, 3.0, 1, 2);
+ RNA_def_property_float_default(prop, 1.3f);
RNA_def_property_ui_text(prop, "Max Edge Error", "Maximum distance error from contour to cells");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "verts_per_poly", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "vertsperpoly");
RNA_def_property_ui_range(prop, 3, 12, 1, -1);
+ RNA_def_property_int_default(prop, 6);
RNA_def_property_ui_text(prop, "Verts Per Poly", "Max number of vertices per polygon");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "sample_dist", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "detailsampledist");
RNA_def_property_ui_range(prop, 0.0, 16.0, 1, 2);
+ RNA_def_property_float_default(prop, 6.0f);
RNA_def_property_ui_text(prop, "Sample Distance", "Detail mesh sample spacing");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "sample_max_error", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "detailsamplemaxerror");
RNA_def_property_ui_range(prop, 0.0, 16.0, 1, 2);
+ RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Max Sample Error", "Detail mesh simplification max sample error");
RNA_def_property_update(prop, NC_SCENE, NULL);
}
@@ -3488,12 +3795,14 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "resolution_x", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "xplay");
RNA_def_property_range(prop, 4, 10000);
+ RNA_def_property_int_default(prop, 640);
RNA_def_property_ui_text(prop, "Resolution X", "Number of horizontal pixels in the screen");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "resolution_y", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "yplay");
RNA_def_property_range(prop, 4, 10000);
+ RNA_def_property_int_default(prop, 480);
RNA_def_property_ui_text(prop, "Resolution Y", "Number of vertical pixels in the screen");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3510,12 +3819,14 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "depth", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "depth");
RNA_def_property_range(prop, 8, 32);
+ RNA_def_property_int_default(prop, 32);
RNA_def_property_ui_text(prop, "Bits", "Display bit depth of full screen display");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "exit_key", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "exitkey");
RNA_def_property_enum_items(prop, event_type_items);
+ RNA_def_property_enum_default(prop, ESCKEY);
RNA_def_property_enum_funcs(prop, NULL, "rna_GameSettings_exit_key_set", NULL);
RNA_def_property_ui_text(prop, "Exit Key", "The key that exits the Game Engine");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3530,6 +3841,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "frequency", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "freqplay");
RNA_def_property_range(prop, 4, 2000);
+ RNA_def_property_int_default(prop, 60);
RNA_def_property_ui_text(prop, "Freq", "Display clock frequency of fullscreen display");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3567,12 +3879,14 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "stereo_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "stereomode");
RNA_def_property_enum_items(prop, stereo_modes_items);
+ RNA_def_property_enum_default(prop, STEREO_ANAGLYPH);
RNA_def_property_ui_text(prop, "Stereo Mode", "Stereographic techniques");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "stereo_eye_separation", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "eyeseparation");
RNA_def_property_range(prop, 0.01, 5.0);
+ RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_ui_text(prop, "Eye Separation",
"Set the distance between the eyes - the camera focal distance/30 should be fine");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3587,18 +3901,21 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "dome_tessellation", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "dome.res");
RNA_def_property_ui_range(prop, 1, 8, 1, 1);
+ RNA_def_property_int_default(prop, 4);
RNA_def_property_ui_text(prop, "Tessellation", "Tessellation level - check the generated mesh in wireframe mode");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "dome_buffer_resolution", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "dome.resbuf");
RNA_def_property_ui_range(prop, 0.1, 1.0, 0.1, 2);
+ RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Buffer Resolution", "Buffer Resolution - decrease it to increase speed");
RNA_def_property_update(prop, NC_SCENE, NULL);
prop = RNA_def_property(srna, "dome_angle", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "dome.angle");
RNA_def_property_ui_range(prop, 90, 250, 1, 1);
+ RNA_def_property_int_default(prop, 180);
RNA_def_property_ui_text(prop, "Angle", "Field of View of the Dome - it only works in mode Fisheye and Truncated");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3619,6 +3936,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "physics_engine", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "physicsEngine");
RNA_def_property_enum_items(prop, physics_engine_items);
+ RNA_def_property_enum_default(prop, WOPHY_BULLET);
RNA_def_property_ui_text(prop, "Physics Engine", "Physics engine used for physics simulation in the game engine");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3626,6 +3944,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "gravity");
RNA_def_property_ui_range(prop, 0.0, 25.0, 1, 2);
RNA_def_property_range(prop, 0.0, 10000.0);
+ RNA_def_property_float_default(prop, 9.8f);
RNA_def_property_ui_text(prop, "Physics Gravity",
"Gravitational constant used for physics simulation in the game engine");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3633,6 +3952,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "occlusion_culling_resolution", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "occlusionRes");
RNA_def_property_range(prop, 128.0, 1024.0);
+ RNA_def_property_int_default(prop, 128);
RNA_def_property_ui_text(prop, "Occlusion Resolution",
"Size of the occlusion buffer, use higher value for better precision (slower)");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3641,6 +3961,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "ticrate");
RNA_def_property_ui_range(prop, 1, 60, 1, 1);
RNA_def_property_range(prop, 1, 10000);
+ RNA_def_property_int_default(prop, 60);
RNA_def_property_ui_text(prop, "Frames Per Second",
"Nominal number of game frames per second "
"(physics fixed timestep = 1/fps, independently of actual frame rate)");
@@ -3650,6 +3971,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "maxlogicstep");
RNA_def_property_range(prop, 1, 10000);
RNA_def_property_ui_range(prop, 1, 50, 1, 1);
+ RNA_def_property_int_default(prop, 5);
RNA_def_property_ui_text(prop, "Max Logic Steps",
"Maximum number of logic frame per game frame if graphics slows down the game, "
"higher value allows better synchronization with physics");
@@ -3659,6 +3981,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "maxphystep");
RNA_def_property_range(prop, 1, 10000);
RNA_def_property_ui_range(prop, 1, 50, 1, 1);
+ RNA_def_property_int_default(prop, 5);
RNA_def_property_ui_text(prop, "Max Physics Steps",
"Maximum number of physics step per game frame if graphics slows down the game, "
"higher value allows physics to keep up with realtime");
@@ -3668,6 +3991,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "physubstep");
RNA_def_property_range(prop, 1, 50);
RNA_def_property_ui_range(prop, 1, 5, 1, 1);
+ RNA_def_property_int_default(prop, 1);
RNA_def_property_ui_text(prop, "Physics Sub Steps",
"Number of simulation substep per physic timestep, "
"higher value give better physics precision");
@@ -3677,6 +4001,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "lineardeactthreshold");
RNA_def_property_ui_range(prop, 0.001, 10000.0, 2, 3);
RNA_def_property_range(prop, 0.001, 10000.0);
+ RNA_def_property_float_default(prop, 0.8f);
RNA_def_property_ui_text(prop, "Deactivation Linear Threshold",
"Linear velocity that an object must be below before the deactivation timer can start");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3685,6 +4010,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "angulardeactthreshold");
RNA_def_property_ui_range(prop, 0.001, 10000.0, 2, 3);
RNA_def_property_range(prop, 0.001, 10000.0);
+ RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Deactivation Angular Threshold",
"Angular velocity that an object must be below before the deactivation timer can start");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3828,6 +4154,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "level_height", PROP_FLOAT, PROP_ACCELERATION);
RNA_def_property_float_sdna(prop, NULL, "levelHeight");
RNA_def_property_range(prop, 0.0f, 200.0f);
+ RNA_def_property_float_default(prop, 2.0f);
RNA_def_property_ui_text(prop, "Level height",
"Max difference in heights of obstacles to enable their interaction");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3845,6 +4172,21 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
/* Nestled Data */
rna_def_scene_game_recast_data(brna);
+
+ /* LoD */
+ prop = RNA_def_property(srna, "use_scene_hysteresis", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "lodflag", SCE_LOD_USE_HYST);
+ RNA_def_property_ui_text(prop, "Hysteresis", "Use LoD Hysteresis setting for the scene");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "scene_hysteresis_percentage", PROP_INT, PROP_PERCENTAGE);
+ RNA_def_property_int_sdna(prop, NULL, "scehysteresis");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_range(prop, 0, 100, 10, 1);
+ RNA_def_property_int_default(prop, 10);
+ RNA_def_property_ui_text(prop, "Hysteresis %",
+ "Minimum distance change required to transition to the previous level of detail");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
}
static void rna_def_gpu_dof_fx(BlenderRNA *brna)
@@ -3876,10 +4218,28 @@ static void rna_def_gpu_dof_fx(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "fstop", PROP_FLOAT, PROP_NONE);
- RNA_def_property_ui_text(prop, "Viewport F-stop", "F-stop for dof effect");
+ RNA_def_property_ui_text(prop, "F-stop", "F-stop for dof effect");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.1f, 128.0f, 10, 1);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "blades", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "num_blades");
+ RNA_def_property_ui_text(prop, "Blades", "Blades for dof effect");
+ RNA_def_property_range(prop, 0, 16);
+ RNA_def_property_int_funcs(prop, NULL, "rna_GPUDOFSettings_blades_set", NULL);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "use_high_quality", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "high_quality", 1);
+ RNA_def_property_ui_text(prop, "High Quality", "Use high quality depth of field");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "is_hq_supported", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_gpu_is_hq_supported_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "High Quality", "Use high quality depth of field");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
static void rna_def_gpu_ssao_fx(BlenderRNA *brna)
@@ -3939,7 +4299,8 @@ static void rna_def_gpu_fx(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_dof", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "fx_flag", GPU_FX_FLAG_DOF);
- RNA_def_property_ui_text(prop, "Depth Of Field", "Use depth of field on viewport using the values from active camera");
+ RNA_def_property_ui_text(prop, "Depth Of Field",
+ "Use depth of field on viewport using the values from active camera");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPUFXSettings_fx_update");
@@ -4023,6 +4384,138 @@ static void rna_def_render_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
}
+/* Render Views - MultiView */
+static void rna_def_scene_render_view(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SceneRenderView", NULL);
+ RNA_def_struct_ui_text(srna, "Scene Render View", "Render viewpoint for 3D stereo and multiview rendering");
+ RNA_def_struct_ui_icon(srna, ICON_RESTRICT_RENDER_OFF);
+ RNA_def_struct_path_func(srna, "rna_SceneRenderView_path");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SceneRenderView_name_set");
+ RNA_def_property_ui_text(prop, "Name", "Render view name");
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "file_suffix", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "suffix");
+ RNA_def_property_ui_text(prop, "File Suffix", "Suffix added to the render images for this view");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "camera_suffix", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "suffix");
+ RNA_def_property_ui_text(prop, "Camera Suffix",
+ "Suffix to identify the cameras to use, and added to the render images for this view");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "viewflag", SCE_VIEW_DISABLE);
+ RNA_def_property_ui_text(prop, "Enabled", "Disable or enable the render view");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+}
+
+static void rna_def_render_views(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "RenderViews");
+ srna = RNA_def_struct(brna, "RenderViews", NULL);
+ RNA_def_struct_sdna(srna, "RenderData");
+ RNA_def_struct_ui_text(srna, "Render Views", "Collection of render views");
+
+ prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "actview");
+ RNA_def_property_int_funcs(prop, "rna_RenderSettings_active_view_index_get",
+ "rna_RenderSettings_active_view_index_set",
+ "rna_RenderSettings_active_view_index_range");
+ RNA_def_property_ui_text(prop, "Active View Index", "Active index in render view array");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "SceneRenderView");
+ RNA_def_property_pointer_funcs(prop, "rna_RenderSettings_active_view_get",
+ "rna_RenderSettings_active_view_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL);
+ RNA_def_property_ui_text(prop, "Active Render View", "Active Render View");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ func = RNA_def_function(srna, "new", "rna_RenderView_new");
+ RNA_def_function_ui_description(func, "Add a render view to scene");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+ parm = RNA_def_string(func, "name", "RenderView", 0, "", "New name for the marker (not unique)");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "result", "SceneRenderView", "", "Newly created render view");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_RenderView_remove");
+ RNA_def_function_ui_description(func, "Remove a render view");
+ RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
+ parm = RNA_def_pointer(func, "view", "SceneRenderView", "", "Render view to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+}
+
+static void rna_def_image_format_stereo3d_format(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem stereo3d_display_items[] = {
+ {S3D_DISPLAY_ANAGLYPH, "ANAGLYPH", 0, "Anaglyph",
+ "Render views for left and right eyes as two differently filtered colors in a single image "
+ "(anaglyph glasses are required)"},
+ {S3D_DISPLAY_INTERLACE, "INTERLACE", 0, "Interlace",
+ "Render views for left and right eyes interlaced in a single image (3D-ready monitor is required)"},
+ {S3D_DISPLAY_SIDEBYSIDE, "SIDEBYSIDE", 0, "Side-by-Side", "Render views for left and right eyes side-by-side"},
+ {S3D_DISPLAY_TOPBOTTOM, "TOPBOTTOM", 0, "Top-Bottom", "Render views for left and right eyes one above another"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "Stereo3dFormat", NULL);
+ RNA_def_struct_sdna(srna, "Stereo3dFormat");
+ RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
+ RNA_def_struct_ui_text(srna, "Stereo Output", "Settings for stereo output");
+
+ prop = RNA_def_property(srna, "display_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "display_mode");
+ RNA_def_property_enum_items(prop, stereo3d_display_items);
+ RNA_def_property_ui_text(prop, "Stereo Mode", "");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Stereo3dFormat_update");
+
+ prop = RNA_def_property(srna, "anaglyph_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, stereo3d_anaglyph_type_items);
+ RNA_def_property_ui_text(prop, "Anaglyph Type", "");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Stereo3dFormat_update");
+
+ prop = RNA_def_property(srna, "interlace_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, stereo3d_interlace_type_items);
+ RNA_def_property_ui_text(prop, "Interlace Type", "");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Stereo3dFormat_update");
+
+ prop = RNA_def_property(srna, "use_interlace_swap", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", S3D_INTERLACE_SWAP);
+ RNA_def_property_ui_text(prop, "Swap Left/Right", "Swap left and right stereo channels");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Stereo3dFormat_update");
+
+ prop = RNA_def_property(srna, "use_sidebyside_crosseyed", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", S3D_SIDEBYSIDE_CROSSEYED);
+ RNA_def_property_ui_text(prop, "Cross-Eyed", "Right eye should see left image and vice-versa");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Stereo3dFormat_update");
+
+ prop = RNA_def_property(srna, "use_squeezed_frame", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", S3D_SQUEEZED_FRAME);
+ RNA_def_property_ui_text(prop, "Squeezed Frame", "Combine both views in a squeezed image");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Stereo3dFormat_update");
+}
+
/* use for render output and image save operator,
* note: there are some cases where the members act differently when this is
* used from a scene, video formats can only be selected for render output
@@ -4042,6 +4535,8 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
+ rna_def_image_format_stereo3d_format(brna);
+
srna = RNA_def_struct(brna, "ImageFormatSettings", NULL);
RNA_def_struct_sdna(srna, "ImageFormatData");
RNA_def_struct_nested(brna, srna, "Scene");
@@ -4107,9 +4602,9 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "exr_codec", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "exr_codec");
RNA_def_property_enum_items(prop, exr_codec_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_ImageFormatSettings_exr_codec_itemf");
RNA_def_property_ui_text(prop, "Codec", "Codec settings for OpenEXR");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
#endif
#ifdef WITH_OPENJPEG
@@ -4161,6 +4656,20 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "G", "Log conversion gamma");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ /* multiview */
+ prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "views_format");
+ RNA_def_property_enum_items(prop, views_format_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_ImageFormatSettings_views_format_itemf");
+ RNA_def_property_ui_text(prop, "Views Format", "Format of multiview media");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "stereo_3d_format", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "stereo3d_format");
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "Stereo3dFormat");
+ RNA_def_property_ui_text(prop, "Stereo 3D Format", "Settings for stereo 3d");
+
/* color management */
prop = RNA_def_property(srna, "view_settings", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "view_settings");
@@ -4563,6 +5072,16 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
"resolution to 480 pixels"},
{0, NULL, 0, NULL, NULL}};
+ static EnumPropertyItem views_format_items[] = {
+ {SCE_VIEWS_FORMAT_STEREO_3D, "STEREO_3D", 0, "Stereo 3D",
+ "Single stereo camera system, adjust the stereo settings in the camera panel"},
+ {SCE_VIEWS_FORMAT_MULTIVIEW, "MULTIVIEW", 0, "Multi-View",
+ "Multi camera system, adjust the cameras individually"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+
+
rna_def_scene_ffmpeg_settings(brna);
#ifdef WITH_QUICKTIME
rna_def_scene_quicktime_settings(brna);
@@ -5245,6 +5764,32 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_UNPINNED, 1);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ /* views (stereoscopy et al) */
+ prop = RNA_def_property(srna, "views", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "SceneRenderView");
+ RNA_def_property_ui_text(prop, "Render Views", "");
+ rna_def_render_views(brna, prop);
+
+ prop = RNA_def_property(srna, "stereo_views", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "views", NULL);
+ RNA_def_property_collection_funcs(prop, "rna_RenderSettings_stereoViews_begin", "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end", "rna_iterator_listbase_get",
+ NULL, NULL, NULL, NULL);
+ RNA_def_property_struct_type(prop, "SceneRenderView");
+ RNA_def_property_ui_text(prop, "Render Views", "");
+
+ prop = RNA_def_property(srna, "use_multiview", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_MULTIVIEW);
+ RNA_def_property_ui_text(prop, "Multiple Views", "Use multiple views in the scene");
+ RNA_def_property_update(prop, NC_WINDOW, NULL);
+
+ prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, views_format_items);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Setup Stereo Mode", "");
+ RNA_def_property_enum_funcs(prop, NULL, "rna_RenderSettings_views_format_set", NULL);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
/* engine */
prop = RNA_def_property(srna, "engine", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, engine_items);
@@ -5286,6 +5831,17 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Simplify Child Particles", "Global child particles percentage");
RNA_def_property_update(prop, 0, "rna_Scene_simplify_update");
+ prop = RNA_def_property(srna, "simplify_subdivision_render", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "simplify_subsurf_render");
+ RNA_def_property_ui_range(prop, 0, 6, 1, -1);
+ RNA_def_property_ui_text(prop, "Simplify Subdivision", "Global maximum subdivision level during rendering");
+ RNA_def_property_update(prop, 0, "rna_Scene_simplify_update");
+
+ prop = RNA_def_property(srna, "simplify_child_particles_render", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "simplify_particles_render");
+ RNA_def_property_ui_text(prop, "Simplify Child Particles", "Global child particles percentage during rendering");
+ RNA_def_property_update(prop, 0, "rna_Scene_simplify_update");
+
prop = RNA_def_property(srna, "simplify_shadow_samples", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "simplify_shadowsamples");
RNA_def_property_ui_range(prop, 1, 16, 1, -1);
@@ -5979,6 +6535,11 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "ColorManagedSequencerColorspaceSettings");
RNA_def_property_ui_text(prop, "Sequencer Color Space Settings", "Settings of color space sequencer is working in");
+ /* Dependency Graph */
+ prop = RNA_def_property(srna, "depsgraph", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Depsgraph");
+ RNA_def_property_ui_text(prop, "Dependency Graph", "Dependencies in the scene data");
+
/* Nestled Data */
/* *** Non-Animated *** */
RNA_define_animate_sdna(false);
@@ -5995,8 +6556,8 @@ void RNA_def_scene(BlenderRNA *brna)
/* *** Animated *** */
rna_def_scene_render_data(brna);
rna_def_scene_render_layer(brna);
-
rna_def_gpu_fx(brna);
+ rna_def_scene_render_view(brna);
/* Scene API */
RNA_api_scene(srna);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 36657c8a898..9d63dfe0f55 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -119,15 +119,21 @@ static void rna_Scene_update_tagged(Scene *scene)
#endif
}
-static void rna_SceneRender_get_frame_path(RenderData *rd, int frame, char *name)
+static void rna_SceneRender_get_frame_path(RenderData *rd, int frame, int preview, const char *view, char *name)
{
+ const char *suffix = BKE_scene_multiview_view_suffix_get(rd, view);
+
+ /* avoid NULL pointer */
+ if (!suffix)
+ suffix = "";
+
if (BKE_imtype_is_movie(rd->im_format.imtype)) {
- BKE_movie_filepath_get(name, rd);
+ BKE_movie_filepath_get(name, rd, preview != 0, suffix);
}
else {
BKE_image_path_from_imformat(
name, rd->pic, G.main->name, (frame == INT_MIN) ? rd->cfra : frame,
- &rd->im_format, (rd->scemode & R_EXTENSION) != 0, true);
+ &rd->im_format, (rd->scemode & R_EXTENSION) != 0, true, suffix);
}
}
@@ -287,6 +293,10 @@ void RNA_api_scene_render(StructRNA *srna)
RNA_def_function_ui_description(func, "Return the absolute path to the filename to be written for a given frame");
RNA_def_int(func, "frame", INT_MIN, INT_MIN, INT_MAX, "",
"Frame number to use, if unset the current frame will be used", MINAFRAME, MAXFRAME);
+ parm = RNA_def_boolean(func, "preview", 0, "Preview", "Use preview range");
+ parm = RNA_def_string_file_path(func, "view", NULL, FILE_MAX, "View",
+ "The name of the view to use to replace the \"%\" chars");
+
parm = RNA_def_string_file_path(func, "filepath", NULL, FILE_MAX, "File Path",
"The resulting filepath from the scenes render settings");
RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index fd27381c0d6..acde663a799 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -77,6 +77,8 @@ EnumPropertyItem symmetrize_direction_items[] = {
#include "BKE_context.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_editstrands.h"
+#include "BKE_effect.h"
#include "BKE_pointcache.h"
#include "BKE_particle.h"
#include "BKE_depsgraph.h"
@@ -221,6 +223,8 @@ static int rna_Brush_mode_poll(PointerRNA *ptr, PointerRNA value)
mode = OB_MODE_VERTEX_PAINT;
else if (ptr->data == ts->wpaint)
mode = OB_MODE_WEIGHT_PAINT;
+ else if (ptr->data == &ts->hair_edit)
+ mode = OB_MODE_HAIR_EDIT;
return brush->ob_mode & mode;
}
@@ -359,51 +363,32 @@ static int rna_ImaPaint_detect_data(ImagePaintSettings *imapaint)
{
return imapaint->missing_data == 0;
}
-#else
-static void rna_def_palettecolor(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
+/* ==== Hair Edit ==== */
- srna = RNA_def_struct(brna, "PaletteColor", NULL);
- RNA_def_struct_ui_text(srna, "Palette Color", "");
-
- prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_float_sdna(prop, NULL, "rgb");
- RNA_def_property_ui_text(prop, "Color", "");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_float_sdna(prop, NULL, "value");
- RNA_def_property_ui_text(prop, "Value", "");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_float_sdna(prop, NULL, "value");
- RNA_def_property_ui_text(prop, "Weight", "");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+static char *rna_HairEdit_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("tool_settings.hair_edit");
}
-
-static void rna_def_palette(BlenderRNA *brna)
+static void rna_HairEdit_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
- StructRNA *srna;
- PropertyRNA *prop;
+ Object *ob = OBACT;
- srna = RNA_def_struct(brna, "Palette", "ID");
- RNA_def_struct_ui_text(srna, "Palette", "");
- RNA_def_struct_ui_icon(srna, ICON_COLOR);
+ if (ob)
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+}
- prop = RNA_def_property(srna, "colors", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(prop, "PaletteColor");
- RNA_def_property_ui_text(prop, "Palette Color", "Colors that are part of this palette");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+static void rna_HairEdit_brush_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ HairEditSettings *settings = ptr->data;
+ Brush *brush = settings->brush;
+ BKE_paint_invalidate_overlay_all();
+ WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush);
}
+#else
+
static void rna_def_paint_curve(BlenderRNA *brna)
{
StructRNA *srna;
@@ -505,6 +490,8 @@ static void rna_def_sculpt(BlenderRNA *brna)
"Relative Detail", "Mesh detail is relative to the brush size and detail size"},
{SCULPT_DYNTOPO_DETAIL_CONSTANT, "CONSTANT", 0,
"Constant Detail", "Mesh detail is constant in object space according to detail size"},
+ {SCULPT_DYNTOPO_DETAIL_BRUSH, "BRUSH", 0,
+ "Brush Detail", "Mesh detail is relative to brush radius"},
{0, NULL, 0, NULL, NULL}
};
@@ -562,6 +549,11 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Detail Size", "Maximum edge length for dynamic topology sculpting (in pixels)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "detail_percent", PROP_FLOAT, PROP_PERCENTAGE);
+ RNA_def_property_ui_range(prop, 0.5, 100.0, 10, 2);
+ RNA_def_property_ui_text(prop, "Detail Percentage", "Maximum edge length for dynamic topology sculpting (in brush percenage)");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
prop = RNA_def_property(srna, "constant_detail", PROP_FLOAT, PROP_PERCENTAGE);
RNA_def_property_range(prop, 0.001, 10000.0);
RNA_def_property_ui_range(prop, 0.1, 100.0, 10, 2);
@@ -907,6 +899,7 @@ static void rna_def_particle_edit(BlenderRNA *brna)
prop = RNA_def_property(srna, "shape_object", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Shape Object", "Outer shape to use for tools");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Mesh_object_poll");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_ParticleEdit_redo");
/* brush */
@@ -918,7 +911,7 @@ static void rna_def_particle_edit(BlenderRNA *brna)
prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL);
RNA_def_property_range(prop, 1, SHRT_MAX);
- RNA_def_property_ui_range(prop, 1, 100, 10, 3);
+ RNA_def_property_ui_range(prop, 1, MAX_BRUSH_PIXEL_RADIUS, 10, 3);
RNA_def_property_ui_text(prop, "Radius", "Radius of the brush in pixels");
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_FACTOR);
@@ -962,12 +955,45 @@ static void rna_def_particle_edit(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Curve", "");
}
+static void rna_def_hair_edit(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem select_mode_items[] = {
+ {HAIR_SELECT_STRAND, "STRAND", ICON_PARTICLE_PATH, "Strand", "Strand edit mode"},
+ {HAIR_SELECT_VERTEX, "VERTEX", ICON_PARTICLE_POINT, "Vertex", "Vertex select mode"},
+ {HAIR_SELECT_TIP, "TIP", ICON_PARTICLE_TIP, "Tip", "Tip select mode"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "HairEdit", NULL);
+ RNA_def_struct_sdna(srna, "HairEditSettings");
+ RNA_def_struct_path_func(srna, "rna_HairEdit_path");
+ RNA_def_struct_ui_text(srna, "Hair Edit", "Settings for hair editing mode");
+
+ prop = RNA_def_property(srna, "brush", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Brush_mode_poll");
+ RNA_def_property_ui_text(prop, "Brush", "Active Brush");
+ RNA_def_property_update(prop, 0, "rna_HairEdit_brush_update");
+
+ prop = RNA_def_property(srna, "select_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "select_mode");
+ RNA_def_property_enum_items(prop, select_mode_items);
+ RNA_def_property_ui_text(prop, "Selection Mode", "Hair selection mode");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_HairEdit_update");
+
+ prop = RNA_def_property(srna, "shape_object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Shape Object", "Outer shape to use for tools");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_HairEdit_update");
+}
+
void RNA_def_sculpt_paint(BlenderRNA *brna)
{
/* *** Non-Animated *** */
RNA_define_animate_sdna(false);
- rna_def_palettecolor(brna);
- rna_def_palette(brna);
rna_def_paint_curve(brna);
rna_def_paint(brna);
rna_def_sculpt(brna);
@@ -975,6 +1001,7 @@ void RNA_def_sculpt_paint(BlenderRNA *brna)
rna_def_vertex_paint(brna);
rna_def_image_paint(brna);
rna_def_particle_edit(brna);
+ rna_def_hair_edit(brna);
RNA_define_animate_sdna(true);
}
diff --git a/source/blender/makesrna/intern/rna_sensor.c b/source/blender/makesrna/intern/rna_sensor.c
index 5d7bb6d2d94..cbc02858f78 100644
--- a/source/blender/makesrna/intern/rna_sensor.c
+++ b/source/blender/makesrna/intern/rna_sensor.c
@@ -325,9 +325,11 @@ static void rna_def_sensor(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Pulse False Level", "Activate FALSE level triggering (pulse mode)");
RNA_def_property_update(prop, NC_LOGIC, NULL);
- prop = RNA_def_property(srna, "frequency", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "tick_skip", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "freq");
- RNA_def_property_ui_text(prop, "Frequency", "Delay between repeated pulses(in logic tics, 0=no delay)");
+ RNA_def_property_ui_text(prop, "Skip",
+ "Number of logic ticks skipped between 2 active pulses "
+ "(0 = pulse every logic tick, 1 = skip 1 logic tick between pulses, etc.)");
RNA_def_property_range(prop, 0, 10000);
RNA_def_property_update(prop, NC_LOGIC, NULL);
@@ -402,8 +404,8 @@ static void rna_def_mouse_sensor(BlenderRNA *brna)
};
static const EnumPropertyItem prop_mouse_type_items[] = {
- {SENS_COLLISION_PROPERTY, "PROPERTY", ICON_LOGIC, "Property", "Use a material for ray intersections"},
- {SENS_COLLISION_MATERIAL, "MATERIAL", ICON_MATERIAL_DATA, "Material", "Use a property for ray intersections"},
+ {SENS_COLLISION_PROPERTY, "PROPERTY", ICON_LOGIC, "Property", "Use a property for ray intersections"},
+ {SENS_COLLISION_MATERIAL, "MATERIAL", ICON_MATERIAL_DATA, "Material", "Use a material for ray intersections"},
{0, NULL, 0, NULL, NULL}
};
@@ -736,8 +738,8 @@ static void rna_def_ray_sensor(BlenderRNA *brna)
};
static const EnumPropertyItem prop_ray_type_items[] = {
- {SENS_COLLISION_PROPERTY, "PROPERTY", ICON_LOGIC, "Property", "Use a material for ray intersections"},
- {SENS_COLLISION_MATERIAL, "MATERIAL", ICON_MATERIAL_DATA, "Material", "Use a property for ray intersections"},
+ {SENS_COLLISION_PROPERTY, "PROPERTY", ICON_LOGIC, "Property", "Use a property for ray intersections"},
+ {SENS_COLLISION_MATERIAL, "MATERIAL", ICON_MATERIAL_DATA, "Material", "Use a material for ray intersections"},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index e9ba9b45ccf..b0d9c22887f 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -72,6 +72,7 @@ EnumPropertyItem sequence_modifier_type_items[] = {
#ifdef RNA_RUNTIME
#include "BKE_report.h"
+#include "BKE_idprop.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -134,6 +135,14 @@ static void rna_SequenceEditor_sequences_all_begin(CollectionPropertyIterator *i
rna_iterator_listbase_begin(iter, &ed->seqbase, NULL);
}
+static void rna_SequenceEditor_update_cache(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+{
+ Editing *ed = scene->ed;
+
+ BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
+}
+
+
static void rna_SequenceEditor_sequences_all_next(CollectionPropertyIterator *iter)
{
ListBaseIterator *internal = &iter->internal.listbase;
@@ -177,6 +186,11 @@ static void rna_SequenceEditor_elements_begin(CollectionPropertyIterator *iter,
rna_SequenceEditor_elements_length(ptr), 0, NULL);
}
+static void rna_Sequence_views_format_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ rna_Sequence_update(bmain, scene, ptr);
+}
+
static void do_sequence_frame_change_update(Scene *scene, Sequence *seq)
{
Editing *ed = BKE_sequencer_editing_get(scene, false);
@@ -476,7 +490,7 @@ static void rna_Sequence_name_set(PointerRNA *ptr, const char *value)
/* fix all the animation data which may link to this */
/* don't rename everywhere because these are per scene */
- /* BKE_all_animdata_fix_paths_rename(NULL, "sequence_editor.sequences_all", oldname, seq->name + 2); */
+ /* BKE_animdata_fix_paths_rename_all(NULL, "sequence_editor.sequences_all", oldname, seq->name + 2); */
adt = BKE_animdata_from_id(&scene->id);
if (adt)
BKE_animdata_fix_paths_rename(&scene->id, adt, NULL, "sequence_editor.sequences_all", oldname, seq->name + 2, 0, 0, 1);
@@ -556,6 +570,18 @@ static char *rna_Sequence_path(PointerRNA *ptr)
}
}
+static IDProperty *rna_Sequence_idprops(PointerRNA *ptr, bool create)
+{
+ Sequence *seq = ptr->data;
+
+ if (create && !seq->prop) {
+ IDPropertyTemplate val = {0};
+ seq->prop = IDP_New(IDP_GROUP, &val, "Sequence ID properties");
+ }
+
+ return seq->prop;
+}
+
static PointerRNA rna_SequenceEditor_meta_stack_get(CollectionPropertyIterator *iter)
{
ListBaseIterator *internal = &iter->internal.listbase;
@@ -577,8 +603,8 @@ static void rna_Sequence_filepath_set(PointerRNA *ptr, const char *value)
PointerRNA id_ptr;
RNA_id_pointer_create((ID *)seq->sound, &id_ptr);
RNA_string_set(&id_ptr, "filepath", value);
- sound_load(G.main, seq->sound);
- sound_update_scene_sound(seq->scene_sound, seq->sound);
+ BKE_sound_load(G.main, seq->sound);
+ BKE_sound_update_scene_sound(seq->scene_sound, seq->sound);
}
BLI_split_dirfile(value, seq->strip->dir, seq->strip->stripdata->name, sizeof(seq->strip->dir),
@@ -633,7 +659,7 @@ static void rna_Sequence_volume_set(PointerRNA *ptr, float value)
seq->volume = value;
if (seq->scene_sound)
- sound_set_scene_sound_volume(seq->scene_sound, value, (seq->flag & SEQ_AUDIO_VOLUME_ANIMATED) != 0);
+ BKE_sound_set_scene_sound_volume(seq->scene_sound, value, (seq->flag & SEQ_AUDIO_VOLUME_ANIMATED) != 0);
}
static void rna_Sequence_pitch_set(PointerRNA *ptr, float value)
@@ -642,7 +668,7 @@ static void rna_Sequence_pitch_set(PointerRNA *ptr, float value)
seq->pitch = value;
if (seq->scene_sound)
- sound_set_scene_sound_pitch(seq->scene_sound, value, (seq->flag & SEQ_AUDIO_PITCH_ANIMATED) != 0);
+ BKE_sound_set_scene_sound_pitch(seq->scene_sound, value, (seq->flag & SEQ_AUDIO_PITCH_ANIMATED) != 0);
}
static void rna_Sequence_pan_set(PointerRNA *ptr, float value)
@@ -651,7 +677,7 @@ static void rna_Sequence_pan_set(PointerRNA *ptr, float value)
seq->pan = value;
if (seq->scene_sound)
- sound_set_scene_sound_pan(seq->scene_sound, value, (seq->flag & SEQ_AUDIO_PAN_ANIMATED) != 0);
+ BKE_sound_set_scene_sound_pan(seq->scene_sound, value, (seq->flag & SEQ_AUDIO_PAN_ANIMATED) != 0);
}
@@ -783,7 +809,7 @@ static int colbalance_seq_cmp_cb(Sequence *seq, void *arg_pt)
return 1;
}
-static Sequence *sequence_get_by_colorbalance(Editing *ed, StripColorBalance *cb, SequenceModifierData **smd_r)
+static Sequence *sequence_get_by_colorbalance(Editing *ed, StripColorBalance *cb, SequenceModifierData **r_smd)
{
SequenceSearchData data;
@@ -794,7 +820,7 @@ static Sequence *sequence_get_by_colorbalance(Editing *ed, StripColorBalance *cb
/* irritating we need to search for our sequence! */
BKE_sequencer_base_recursive_apply(&ed->seqbase, colbalance_seq_cmp_cb, &data);
- *smd_r = data.smd;
+ *r_smd = data.smd;
return data.seq;
}
@@ -1222,6 +1248,15 @@ static void rna_def_strip_proxy(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Timecode", "");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_tcindex_update");
+ prop = RNA_def_property(srna, "use_proxy_custom_directory", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "storage", SEQ_STORAGE_PROXY_CUSTOM_DIR);
+ RNA_def_property_ui_text(prop, "Proxy Custom Directory", "Use a custom directory to store data");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
+
+ prop = RNA_def_property(srna, "use_proxy_custom_file", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "storage", SEQ_STORAGE_PROXY_CUSTOM_FILE);
+ RNA_def_property_ui_text(prop, "Proxy Custom File", "Use a custom file to read proxy data from");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
}
static void rna_def_color_balance(BlenderRNA *brna)
@@ -1380,6 +1415,7 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Sequence", "Sequence strip in the sequence editor");
RNA_def_struct_refine_func(srna, "rna_Sequence_refine");
RNA_def_struct_path_func(srna, "rna_Sequence_path");
+ RNA_def_struct_idprops_func(srna, "rna_Sequence_idprops");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, "rna_Sequence_name_get", "rna_Sequence_name_length", "rna_Sequence_name_set");
@@ -1559,7 +1595,12 @@ static void rna_def_editor(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
-
+
+ static const EnumPropertyItem editing_storage_items[] = {
+ {0, "PER_STRIP", 0, "Per Strip", "Store proxies using per strip settings"},
+ {SEQ_EDIT_PROXY_DIR_STORAGE, "PROJECT", 0, "Project", "Store proxies using project directory"},
+ {0, NULL, 0, NULL, NULL}
+ };
srna = RNA_def_struct(brna, "SequenceEditor", NULL);
RNA_def_struct_ui_text(srna, "Sequence Editor", "Sequence editing data for a Scene datablock");
RNA_def_struct_ui_icon(srna, ICON_SEQUENCE);
@@ -1607,6 +1648,16 @@ static void rna_def_editor(BlenderRNA *brna)
RNA_def_property_int_funcs(prop, "rna_SequenceEditor_overlay_frame_get",
"rna_SequenceEditor_overlay_frame_set", NULL);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "proxy_storage", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, editing_storage_items);
+ RNA_def_property_ui_text(prop, "Proxy Storage", "How to store proxies for this project");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, "rna_SequenceEditor_update_cache");
+
+ prop = RNA_def_property(srna, "proxy_dir", PROP_STRING, PROP_DIRPATH);
+ RNA_def_property_string_sdna(prop, NULL, "proxy_dir");
+ RNA_def_property_ui_text(prop, "Proxy Directory", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, "rna_SequenceEditor_update_cache");
}
static void rna_def_filter_video(StructRNA *srna)
@@ -1702,16 +1753,6 @@ static void rna_def_proxy(StructRNA *srna)
prop = RNA_def_property(srna, "proxy", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "strip->proxy");
RNA_def_property_ui_text(prop, "Proxy", "");
-
- prop = RNA_def_property(srna, "use_proxy_custom_directory", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_PROXY_CUSTOM_DIR);
- RNA_def_property_ui_text(prop, "Proxy Custom Directory", "Use a custom directory to store data");
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
-
- prop = RNA_def_property(srna, "use_proxy_custom_file", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_PROXY_CUSTOM_FILE);
- RNA_def_property_ui_text(prop, "Proxy Custom File", "Use a custom file to read proxy data from");
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
}
static void rna_def_input(StructRNA *srna)
@@ -1798,6 +1839,24 @@ static void rna_def_image(BlenderRNA *brna)
"rna_SequenceEditor_elements_length", NULL, NULL, NULL);
RNA_api_sequence_elements(brna, prop);
+ /* multiview */
+ prop = RNA_def_property(srna, "use_multiview", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_VIEWS);
+ RNA_def_property_ui_text(prop, "Use Multi-View", "Use Multiple Views (when available)");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_views_format_update");
+
+ prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "views_format");
+ RNA_def_property_enum_items(prop, views_format_items);
+ RNA_def_property_ui_text(prop, "Views Format", "Mode to load image views");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Sequence_views_format_update");
+
+ prop = RNA_def_property(srna, "stereo_3d_format", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "stereo3d_format");
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "Stereo3dFormat");
+ RNA_def_property_ui_text(prop, "Stereo 3D Format", "Settings for stereo 3d");
+
rna_def_filter_video(srna);
rna_def_proxy(srna);
rna_def_input(srna);
@@ -1894,6 +1953,24 @@ static void rna_def_movie(BlenderRNA *brna)
"rna_Sequence_filepath_set");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_filepath_update");
+ /* multiview */
+ prop = RNA_def_property(srna, "use_multiview", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_VIEWS);
+ RNA_def_property_ui_text(prop, "Use Multi-View", "Use Multiple Views (when available)");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_views_format_update");
+
+ prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "views_format");
+ RNA_def_property_enum_items(prop, views_format_items);
+ RNA_def_property_ui_text(prop, "Views Format", "Mode to load movie views");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Sequence_views_format_update");
+
+ prop = RNA_def_property(srna, "stereo_3d_format", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "stereo3d_format");
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "Stereo3dFormat");
+ RNA_def_property_ui_text(prop, "Stereo 3D Format", "Settings for stereo 3d");
+
rna_def_filter_video(srna);
rna_def_proxy(srna);
rna_def_input(srna);
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index 351a15c0171..44169fa641e 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -158,7 +158,7 @@ static Sequence *rna_Sequences_new_scene(ID *id, Editing *ed,
seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_SCENE, NULL);
seq->scene = sce_seq;
seq->len = sce_seq->r.efra - sce_seq->r.sfra + 1;
- seq->scene_sound = sound_scene_add_scene_sound(scene, seq, frame_start, frame_start + seq->len, 0);
+ seq->scene_sound = BKE_sound_scene_add_scene_sound(scene, seq, frame_start, frame_start + seq->len, 0);
id_us_plus((ID *)sce_seq);
BKE_sequence_calc_disp(scene, seq);
@@ -198,6 +198,7 @@ static Sequence *rna_Sequences_new_movie(ID *id, Editing *ed, ReportList *report
{
Scene *scene = (Scene *)id;
Sequence *seq;
+ StripAnim *sanim;
struct anim *an = openanim(file, IB_rect, 0, NULL);
@@ -207,7 +208,11 @@ static Sequence *rna_Sequences_new_movie(ID *id, Editing *ed, ReportList *report
}
seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_MOVIE, file);
- seq->anim = an;
+
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = an;
+
seq->anim_preseek = IMB_anim_get_preseek(an);
seq->len = IMB_anim_get_duration(an, IMB_TC_RECORD_RUN);
@@ -225,18 +230,19 @@ static Sequence *rna_Sequences_new_sound(ID *id, Editing *ed, Main *bmain, Repor
Scene *scene = (Scene *)id;
Sequence *seq;
- bSound *sound = sound_new_file(bmain, file);
+ bSound *sound = BKE_sound_new_file(bmain, file);
- if (sound == NULL || sound->playback_handle == NULL) {
+ if (sound->playback_handle == NULL) {
+ BKE_libblock_free(bmain, sound);
BKE_report(reports, RPT_ERROR, "Sequences.new_sound: unable to open sound file");
return NULL;
}
seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_SOUND_RAM, sound->name);
seq->sound = sound;
- seq->len = ceil((double)sound_get_length(sound) * FPS);
+ seq->len = ceil((double)BKE_sound_get_length(sound) * FPS);
- seq->scene_sound = sound_add_scene_sound(scene, seq, frame_start, frame_start + seq->len, 0);
+ seq->scene_sound = BKE_sound_add_scene_sound(scene, seq, frame_start, frame_start + seq->len, 0);
BKE_sequence_calc_disp(scene, seq);
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index 55262a98b2e..420aede872d 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -414,6 +414,14 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, smoke_cache_comp_items);
RNA_def_property_ui_text(prop, "Cache Compression", "Compression method to be used");
+ prop = RNA_def_property(srna, "point_cache_offset", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "point_cache_offset");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_range(prop, -10000, 10000);
+ RNA_def_property_ui_range(prop, -10000, 10000, 1, -1);
+ RNA_def_property_ui_text(prop, "Point Cache Offset", "Offset to add to cached frames");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_update");
+
prop = RNA_def_property(srna, "collision_extents", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "border_collisions");
RNA_def_property_enum_items(prop, smoke_domain_colli_items);
@@ -544,6 +552,14 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Threshold",
"Maximum amount of fluid cell can contain before it is considered empty");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ /* display */
+ prop = RNA_def_property(srna, "display_thickness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "display_thickness");
+ RNA_def_property_range(prop, 0.001f, 1000.0f);
+ RNA_def_property_ui_range(prop, 0.1f, 10.0f, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Thickness", "Thickness of smoke drawing in the viewport");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
}
static void rna_def_smoke_flow_settings(BlenderRNA *brna)
@@ -675,6 +691,11 @@ static void rna_def_smoke_flow_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Set Size", "Set particle size in simulation cells or use nearest cell");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+ prop = RNA_def_property(srna, "use_particle_texture_color", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_USE_PART_TEXCOLOR);
+ RNA_def_property_ui_text(prop, "Set Texture Color", "Set particle texture color in simulation cells");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
prop = RNA_def_property(srna, "subframes", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 0, 50);
RNA_def_property_ui_range(prop, 0, 10, 1, -1);
diff --git a/source/blender/makesrna/intern/rna_sound.c b/source/blender/makesrna/intern/rna_sound.c
index 4b745c60b5b..25b3475c423 100644
--- a/source/blender/makesrna/intern/rna_sound.c
+++ b/source/blender/makesrna/intern/rna_sound.c
@@ -42,7 +42,7 @@
static void rna_Sound_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
- sound_load(bmain, (bSound *)ptr->data);
+ BKE_sound_load(bmain, (bSound *)ptr->data);
}
static int rna_Sound_caching_get(PointerRNA *ptr)
@@ -55,9 +55,9 @@ static void rna_Sound_caching_set(PointerRNA *ptr, const int value)
{
bSound *sound = (bSound *)(ptr->data);
if (value)
- sound_cache(sound);
+ BKE_sound_cache(sound);
else
- sound_delete_cache(sound);
+ BKE_sound_delete_cache(sound);
}
static void rna_Sound_caching_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index d7ea3d9ca48..f97cc1eadd9 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -31,6 +31,7 @@
#include "BLF_translation.h"
+#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
@@ -90,6 +91,41 @@ EnumPropertyItem space_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
+#define V3D_S3D_CAMERA_LEFT {STEREO_LEFT_ID, "LEFT", ICON_RESTRICT_RENDER_OFF, "Left", ""},
+#define V3D_S3D_CAMERA_RIGHT {STEREO_RIGHT_ID, "RIGHT", ICON_RESTRICT_RENDER_OFF, "Right", ""},
+#define V3D_S3D_CAMERA_S3D {STEREO_3D_ID, "S3D", ICON_CAMERA_STEREO, "3D", ""},
+#ifdef RNA_RUNTIME
+#define V3D_S3D_CAMERA_VIEWS {STEREO_MONO_ID, "MONO", ICON_RESTRICT_RENDER_OFF, "Views", ""},
+#endif
+
+static EnumPropertyItem stereo3d_camera_items[] = {
+ V3D_S3D_CAMERA_LEFT
+ V3D_S3D_CAMERA_RIGHT
+ V3D_S3D_CAMERA_S3D
+ {0, NULL, 0, NULL, NULL}
+};
+
+#ifdef RNA_RUNTIME
+static EnumPropertyItem multiview_camera_items[] = {
+ V3D_S3D_CAMERA_VIEWS
+ V3D_S3D_CAMERA_S3D
+ {0, NULL, 0, NULL, NULL}
+};
+#endif
+
+#undef V3D_S3D_CAMERA_LEFT
+#undef V3D_S3D_CAMERA_RIGHT
+#undef V3D_S3D_CAMERA_S3D
+#undef V3D_S3D_CAMERA_VIEWS
+
+#ifndef RNA_RUNTIME
+static EnumPropertyItem stereo3d_eye_items[] = {
+ {STEREO_LEFT_ID, "LEFT_EYE", ICON_NONE, "Left Eye"},
+ {STEREO_RIGHT_ID, "RIGHT_EYE", ICON_NONE, "Right Eye"},
+ {0, NULL, 0, NULL, NULL}
+};
+#endif
+
static EnumPropertyItem pivot_items_full[] = {
{V3D_CENTER, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center",
"Pivot around bounding box center of selected object(s)"},
@@ -201,6 +237,7 @@ static EnumPropertyItem buttons_texture_context_items[] = {
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_nla.h"
#include "BKE_paint.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@@ -413,8 +450,8 @@ static void rna_SpaceView3D_lock_camera_and_layers_set(PointerRNA *ptr, int valu
/* seek for layact */
bit = 0;
while (bit < 32) {
- if (v3d->lay & (1 << bit)) {
- v3d->layact = 1 << bit;
+ if (v3d->lay & (1u << bit)) {
+ v3d->layact = (1u << bit);
break;
}
bit++;
@@ -493,8 +530,11 @@ static void rna_SpaceView3D_matcap_enable(Main *UNUSED(bmain), Scene *UNUSED(sce
{
View3D *v3d = (View3D *)(ptr->data);
- if (v3d->matcap_icon == 0)
+ if (v3d->matcap_icon < ICON_MATCAP_01 ||
+ v3d->matcap_icon > ICON_MATCAP_24)
+ {
v3d->matcap_icon = ICON_MATCAP_01;
+ }
}
static void rna_SpaceView3D_pivot_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
@@ -656,6 +696,17 @@ static EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *UNUSED(C
return item;
}
+static EnumPropertyItem *rna_SpaceView3D_stereo3d_camera_itemf(bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
+{
+ Scene *scene = ((bScreen *)ptr->id.data)->scene;
+
+ if (scene->r.views_format == SCE_VIEWS_FORMAT_MULTIVIEW)
+ return multiview_camera_items;
+ else
+ return stereo3d_camera_items;
+}
+
/* Space Image Editor */
static PointerRNA rna_SpaceImageEditor_uvedit_get(PointerRNA *ptr)
@@ -668,6 +719,38 @@ static void rna_SpaceImageEditor_mode_update(Main *bmain, Scene *scene, PointerR
ED_space_image_paint_update(bmain->wm.first, scene->toolsettings);
}
+
+static void rna_SpaceImageEditor_show_stereo_set(PointerRNA *ptr, int value)
+{
+ SpaceImage *sima = (SpaceImage *)(ptr->data);
+
+ if (value)
+ sima->iuser.flag |= IMA_SHOW_STEREO;
+ else
+ sima->iuser.flag &= ~IMA_SHOW_STEREO;
+}
+
+static int rna_SpaceImageEditor_show_stereo_get(PointerRNA *ptr)
+{
+ SpaceImage *sima = (SpaceImage *)(ptr->data);
+ return (sima->iuser.flag & IMA_SHOW_STEREO) != 0;
+}
+
+static void rna_SpaceImageEditor_show_stereo_update(Main *UNUSED(bmain), Scene *UNUSED(unused), PointerRNA *ptr)
+{
+ SpaceImage *sima = (SpaceImage *)(ptr->data);
+ Image *ima = sima->image;
+
+ if (ima) {
+ if (ima->rr) {
+ BKE_image_multilayer_index(ima->rr, &sima->iuser);
+ }
+ else {
+ BKE_image_multiview_index(ima, &sima->iuser);
+ }
+ }
+}
+
static int rna_SpaceImageEditor_show_render_get(PointerRNA *ptr)
{
SpaceImage *sima = (SpaceImage *)(ptr->data);
@@ -795,6 +878,24 @@ static void rna_SpaceImageEditor_cursor_location_set(PointerRNA *ptr, const floa
}
}
+static void rna_SpaceImageEditor_image_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ SpaceImage *sima = (SpaceImage *)ptr->data;
+ Image *ima = sima->image;
+
+ /* make sure all the iuser settings are valid for the sima image */
+ if (ima) {
+ if (ima->rr) {
+ if (BKE_image_multilayer_index(sima->image->rr, &sima->iuser) == NULL) {
+ BKE_image_init_imageuser(sima->image, &sima->iuser);
+ }
+ }
+ else {
+ BKE_image_multiview_index(ima, &sima->iuser);
+ }
+ }
+}
+
static void rna_SpaceImageEditor_scopes_update(struct bContext *C, struct PointerRNA *ptr)
{
SpaceImage *sima = (SpaceImage *)ptr->data;
@@ -1114,24 +1215,60 @@ static void rna_SpaceDopeSheetEditor_action_update(Main *UNUSED(bmain), Scene *s
if (saction->mode == SACTCONT_ACTION) {
/* TODO: context selector could help decide this with more control? */
- adt = BKE_id_add_animdata(&obact->id); /* this only adds if non-existent */
+ adt = BKE_animdata_add_id(&obact->id); /* this only adds if non-existent */
}
else if (saction->mode == SACTCONT_SHAPEKEY) {
Key *key = BKE_key_from_object(obact);
if (key)
- adt = BKE_id_add_animdata(&key->id); /* this only adds if non-existent */
+ adt = BKE_animdata_add_id(&key->id); /* this only adds if non-existent */
}
/* set action */
+ // FIXME: this overlaps a lot with the BKE_animdata_set_action() API method
if (adt) {
- /* fix id-count of action we're replacing */
- id_us_min(&adt->action->id);
-
- /* assign new action, and adjust the usercounts accordingly */
- adt->action = saction->action;
- id_us_plus(&adt->action->id);
+ /* Don't do anything if old and new actions are the same... */
+ if (adt->action != saction->action) {
+ /* NLA Tweak Mode needs special handling... */
+ if (adt->flag & ADT_NLA_EDIT_ON) {
+ /* Exit editmode first - we cannot change actions while in tweakmode
+ * NOTE: This will clear the action ref properly
+ */
+ BKE_nla_tweakmode_exit(adt);
+
+ /* Assign new action, and adjust the usercounts accordingly */
+ adt->action = saction->action;
+ id_us_plus((ID *)adt->action);
+ }
+ else {
+ /* Handle old action... */
+ if (adt->action) {
+ /* Fix id-count of action we're replacing */
+ id_us_min(&adt->action->id);
+
+ /* To prevent data loss (i.e. if users flip between actions using the Browse menu),
+ * stash this action if nothing else uses it.
+ *
+ * EXCEPTION:
+ * This callback runs when unlinking actions. In that case, we don't want to
+ * stash the action, as the user is signalling that they want to detach it.
+ * This can be reviewed again later, but it could get annoying if we keep these instead.
+ */
+ if ((adt->action->id.us <= 0) && (saction->action != NULL)) {
+ /* XXX: Things here get dodgy if this action is only partially completed,
+ * and the user then uses the browse menu to get back to this action,
+ * assigning it as the active action (i.e. the stash strip gets out of sync)
+ */
+ BKE_nla_action_stash(adt);
+ }
+ }
+
+ /* Assign new action, and adjust the usercounts accordingly */
+ adt->action = saction->action;
+ id_us_plus((ID *)adt->action);
+ }
+ }
- /* force update of animdata */
+ /* Force update of animdata */
adt->recalc |= ADT_RECALC_ANIM;
}
@@ -1211,6 +1348,19 @@ static void rna_BackgroundImage_opacity_set(PointerRNA *ptr, float value)
bgpic->blend = 1.0f - value;
}
+/* radius internally (expose as a distance value) */
+static float rna_BackgroundImage_size_get(PointerRNA *ptr)
+{
+ BGpic *bgpic = ptr->data;
+ return bgpic->size * 2.0f;
+}
+
+static void rna_BackgroundImage_size_set(PointerRNA *ptr, float value)
+{
+ BGpic *bgpic = ptr->data;
+ bgpic->size = value * 0.5f;
+}
+
static BGpic *rna_BackgroundImage_new(View3D *v3d)
{
BGpic *bgpic = ED_view3D_background_image_new(v3d);
@@ -1780,6 +1930,11 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Draw Other Objects", "Draw other selected objects that share the same image");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+ prop = RNA_def_property(srna, "show_metadata", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_DRAW_METADATA);
+ RNA_def_property_ui_text(prop, "Draw Metadata", "Draw metadata properties of the image");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+
prop = RNA_def_property(srna, "show_texpaint", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SI_NO_DRAW_TEXPAINT);
RNA_def_property_ui_text(prop, "Draw Texture Paint UVs", "Draw overlay of texture paint uv layer");
@@ -1966,15 +2121,16 @@ static void rna_def_background_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Y Offset", "Offset image vertically from the world origin");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "size");
- RNA_def_property_ui_text(prop, "Size", "Scaling factor for the background image");
+ RNA_def_property_float_funcs(prop, "rna_BackgroundImage_size_get", "rna_BackgroundImage_size_set", NULL);
+ RNA_def_property_ui_text(prop, "Size", "Size of the background image (ortho view only)");
RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER);
RNA_def_property_float_sdna(prop, NULL, "rotation");
- RNA_def_property_ui_text(prop, "Rotation", "Rotation for the background image");
+ RNA_def_property_ui_text(prop, "Rotation", "Rotation for the background image (ortho view only)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "use_flip_x", PROP_BOOLEAN, PROP_NONE);
@@ -2479,6 +2635,48 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "FX Options", "Options used for real time compositing");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ /* Stereo Settings */
+ prop = RNA_def_property(srna, "stereo_3d_eye", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "multiview_eye");
+ RNA_def_property_enum_items(prop, stereo3d_eye_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_SpaceView3D_stereo3d_camera_itemf");
+ RNA_def_property_ui_text(prop, "Stereo Eye", "Current stereo eye being drawn");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "stereo_3d_camera", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "stereo3d_camera");
+ RNA_def_property_enum_items(prop, stereo3d_camera_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_SpaceView3D_stereo3d_camera_itemf");
+ RNA_def_property_ui_text(prop, "Camera", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_stereo_3d_cameras", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "stereo3d_flag", V3D_S3D_DISPCAMERAS);
+ RNA_def_property_ui_text(prop, "Cameras", "Show the left and right cameras");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_stereo_3d_convergence_plane", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "stereo3d_flag", V3D_S3D_DISPPLANE);
+ RNA_def_property_ui_text(prop, "Plane", "Show the stereo 3d convergence plane");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "stereo_3d_convergence_plane_alpha", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "stereo3d_convergence_alpha");
+ RNA_def_property_ui_text(prop, "Plane Alpha", "Opacity (alpha) of the convergence plane");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_stereo_3d_volume", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "stereo3d_flag", V3D_S3D_DISPVOLUME);
+ RNA_def_property_ui_text(prop, "Volume", "Show the stereo 3d frustum volume");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "stereo_3d_volume_alpha", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "stereo3d_volume_alpha");
+ RNA_def_property_ui_text(prop, "Volume Alpha", "Opacity (alpha) of the cameras' frustum volume");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ /* *** Animated *** */
+ RNA_define_animate_sdna(true);
/* region */
srna = RNA_def_struct(brna, "RegionView3D", NULL);
@@ -2652,7 +2850,7 @@ static void rna_def_space_image(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, NULL, "rna_SpaceImageEditor_image_set", NULL, NULL);
RNA_def_property_ui_text(prop, "Image", "Image displayed and edited in this space");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_update(prop, NC_GEOM | ND_DATA, NULL); /* is handled in image editor too */
+ RNA_def_property_update(prop, NC_GEOM | ND_DATA, "rna_SpaceImageEditor_image_update"); /* is handled in image editor too */
prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
@@ -2704,6 +2902,12 @@ static void rna_def_space_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Draw Channels", "Channels of the image to draw");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+ prop = RNA_def_property(srna, "show_stereo_3d", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_SpaceImageEditor_show_stereo_get", "rna_SpaceImageEditor_show_stereo_set");
+ RNA_def_property_ui_text(prop, "Show Stereo", "Display the image in Stereo 3D");
+ RNA_def_property_ui_icon(prop, ICON_CAMERA_STEREO, 0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, "rna_SpaceImageEditor_show_stereo_update");
+
/* uv */
prop = RNA_def_property(srna, "uv_editor", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
@@ -2880,6 +3084,16 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Center-Cut Safe Areas", "Show safe areas to fit content in a different aspect ratio");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+ prop = RNA_def_property(srna, "show_metadata", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_METADATA);
+ RNA_def_property_ui_text(prop, "Show Metadata", "Show metadata of first visible strip");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "show_info", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SEQ_NO_INFO);
+ RNA_def_property_ui_text(prop, "Show Strip Info", "Show source info on the strip");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
prop = RNA_def_property(srna, "show_seconds", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SEQ_DRAWFRAMES);
RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames");
@@ -3311,6 +3525,23 @@ static void rna_def_space_graph(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Auto Normalization",
"Automatically recalculate curve normalization on every curve edit");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
+
+ prop = RNA_def_property(srna, "show_backdrop", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_DRAW_BACKDROP);
+ RNA_def_property_ui_text(prop, "Show Backdrop", "Draw a backdrop showing the content of the 3D View");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
+
+ prop = RNA_def_property(srna, "backdrop_camera", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Camera_object_poll");
+ RNA_def_property_ui_text(prop, "Backdrop Camera", "The camera that is used to project the backdrop");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
+
+ prop = RNA_def_property(srna, "backdrop_opacity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "backdrop_opacity");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Backdrop Opacity", "Opacity of the backdrop");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
}
static void rna_def_space_nla(BlenderRNA *brna)
@@ -3516,6 +3747,14 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem thumbnail_size_items[] = {
+ {32, "TINY", 0, "Tiny", ""},
+ {64, "SMALL", 0, "Small", ""},
+ {128, "NORMAL", 0, "Normal", ""},
+ {256, "LARGE", 0, "Large", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "FileSelectParams", NULL);
RNA_def_struct_ui_text(srna, "File Select Parameters", "File Select Parameters");
@@ -3550,6 +3789,11 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Hidden", "Show hidden dot files");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+ prop = RNA_def_property(srna, "collapse_seq", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", FILE_COLLAPSE_IMAGES);
+ RNA_def_property_ui_text(prop, "Collapse Image Sequences", "Collapse image sequences");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+
prop = RNA_def_property(srna, "sort_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "sort");
RNA_def_property_enum_items(prop, file_sort_items);
@@ -3620,6 +3864,12 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Name Filter", "Filter by name, supports '*' wildcard");
RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
+
+ prop = RNA_def_property(srna, "thumbnail_size", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "thumbnail_size");
+ RNA_def_property_enum_items(prop, thumbnail_size_items);
+ RNA_def_property_ui_text(prop, "Thumbnails Size", "Change the size of the thumbnails");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
static void rna_def_filemenu_entry(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c
index 4114ee8a289..3cfbd798ad6 100644
--- a/source/blender/makesrna/intern/rna_space_api.c
+++ b/source/blender/makesrna/intern/rna_space_api.c
@@ -101,7 +101,7 @@ void RNA_api_space_text(StructRNA *srna)
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_int(func, "column", 0, INT_MIN, INT_MAX, "Column", "Column index", 0, INT_MAX);
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_int_array(func, "result", 2, 0, -1, INT_MAX, "", "Region coordinates", -1, INT_MAX);
+ parm = RNA_def_int_array(func, "result", 2, NULL, -1, INT_MAX, "", "Region coordinates", -1, INT_MAX);
RNA_def_function_output(func, parm);
}
diff --git a/source/blender/makesrna/intern/rna_strands.c b/source/blender/makesrna/intern/rna_strands.c
new file mode 100644
index 00000000000..f6154fd1e01
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_strands.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file blender/makesrna/intern/rna_strands.c
+ * \ingroup RNA
+ */
+
+#include <stdlib.h>
+
+#include "BLI_utildefines.h"
+
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "rna_internal.h"
+
+#include "WM_types.h"
+
+#ifdef RNA_RUNTIME
+
+#include "BLI_math.h"
+
+#include "BKE_strands.h"
+#include "BKE_report.h"
+
+static int rna_Strands_has_motion_state_get(PointerRNA *ptr)
+{
+ Strands *strands = ptr->data;
+ return (bool)(strands->state != NULL);
+}
+
+static int rna_StrandsChildCurve_render_size_get(PointerRNA *ptr)
+{
+ StrandsChildCurve *curve = ptr->data;
+ return curve->cutoff < 0.0f ? curve->numverts : min_ii(curve->numverts, (int)ceilf(curve->cutoff) + 1);
+}
+
+static void rna_StrandsChildren_curve_uvs_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ StrandsChildren *strands = ptr->data;
+ rna_iterator_array_begin(iter, strands->curve_uvs, sizeof(StrandsChildCurveUV), strands->totcurves * strands->numuv, false, NULL);
+}
+
+static int rna_StrandsChildren_curve_uvs_length(PointerRNA *ptr)
+{
+ StrandsChildren *strands = ptr->data;
+ return strands->totcurves * strands->numuv;
+}
+
+static int rna_StrandsChildren_curve_uvs_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr)
+{
+ StrandsChildren *strands = ptr->data;
+ if (index >= 0 && index < strands->totcurves * strands->numuv) {
+ RNA_pointer_create(ptr->id.data, &RNA_StrandsChildCurveUV, strands->curve_uvs + index, r_ptr);
+ return true;
+ }
+ else {
+ RNA_pointer_create(ptr->id.data, &RNA_StrandsChildCurveUV, NULL, r_ptr);
+ return false;
+ }
+}
+
+static void rna_StrandsChildren_curve_vcols_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ StrandsChildren *strands = ptr->data;
+ rna_iterator_array_begin(iter, strands->curve_vcols, sizeof(StrandsChildCurveVCol), strands->totcurves * strands->numvcol, false, NULL);
+}
+
+static int rna_StrandsChildren_curve_vcols_length(PointerRNA *ptr)
+{
+ StrandsChildren *strands = ptr->data;
+ return strands->totcurves * strands->numvcol;
+}
+
+static int rna_StrandsChildren_curve_vcols_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr)
+{
+ StrandsChildren *strands = ptr->data;
+ if (index >= 0 && index < strands->totcurves * strands->numvcol) {
+ RNA_pointer_create(ptr->id.data, &RNA_StrandsChildCurveVCol, strands->curve_vcols + index, r_ptr);
+ return true;
+ }
+ else {
+ RNA_pointer_create(ptr->id.data, &RNA_StrandsChildCurveVCol, NULL, r_ptr);
+ return false;
+ }
+}
+
+#else
+
+static void rna_def_strands_curve(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "StrandsCurve", NULL);
+ RNA_def_struct_sdna(srna, "StrandsCurve");
+ RNA_def_struct_ui_text(srna, "Strand Curve", "Strand curve");
+
+ prop = RNA_def_property(srna, "size", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "numverts");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Size", "Number of vertices of the curve");
+
+ /* same as "size", defined for consistency */
+ prop = RNA_def_property(srna, "render_size", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "numverts");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Render Size", "Number of vertices of the curve for rendering based on cutoff length");
+}
+
+static void rna_def_strands_vertex(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "StrandsVertex", NULL);
+ RNA_def_struct_sdna(srna, "StrandsVertex");
+ RNA_def_struct_ui_text(srna, "Strand Vertex", "Strand vertex");
+
+ prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_float_sdna(prop, NULL, "co");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Location", "");
+}
+
+static void rna_def_strands_motion_state(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "StrandsMotionState", NULL);
+ RNA_def_struct_sdna(srna, "StrandsMotionState");
+ RNA_def_struct_ui_text(srna, "Strand Vertex Motion State", "Physical motion state of a vertex");
+
+ prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_float_sdna(prop, NULL, "co");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Location", "");
+}
+
+static void rna_def_strands(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "Strands", NULL);
+ RNA_def_struct_sdna(srna, "Strands");
+ RNA_def_struct_ui_text(srna, "Strands", "Strand geometry to represent hair and similar linear structures");
+
+ prop = RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "curves", "totcurves");
+ RNA_def_property_struct_type(prop, "StrandsCurve");
+ RNA_def_property_ui_text(prop, "Strand Curves", "");
+
+ prop = RNA_def_property(srna, "vertices", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "verts", "totverts");
+ RNA_def_property_struct_type(prop, "StrandsVertex");
+ RNA_def_property_ui_text(prop, "Strand Vertex", "");
+
+ prop = RNA_def_property(srna, "has_motion_state", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_Strands_has_motion_state_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Has Motion State", "Strands have physical motion data associated with vertices");
+
+ prop = RNA_def_property(srna, "motion_state", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "state", "totverts");
+ RNA_def_property_struct_type(prop, "StrandsMotionState");
+ RNA_def_property_ui_text(prop, "Strand Motion State", "");
+}
+
+static void rna_def_strands_child_curve(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "StrandsChildCurve", NULL);
+ RNA_def_struct_sdna(srna, "StrandsChildCurve");
+ RNA_def_struct_ui_text(srna, "Strand Child Curve", "Strand child curve");
+
+ prop = RNA_def_property(srna, "size", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "numverts");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Size", "Number of vertices of the curve");
+
+ prop = RNA_def_property(srna, "render_size", PROP_INT, PROP_NONE);
+ RNA_def_property_int_funcs(prop, "rna_StrandsChildCurve_render_size_get", NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Render Size", "Number of vertices of the curve for rendering based on cutoff length");
+
+ prop = RNA_def_property(srna, "cutoff", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "cutoff");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Cutoff", "Curve parameter at which the curve is cut short for rendering");
+}
+
+static void rna_def_strands_child_curve_uv(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "StrandsChildCurveUV", NULL);
+ RNA_def_struct_sdna(srna, "StrandsChildCurveUV");
+ RNA_def_struct_ui_text(srna, "Strand Child Curve UV", "UV data for child strand curves");
+
+ prop = RNA_def_property(srna, "uv", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_text(prop, "UV", "");
+}
+
+static void rna_def_strands_child_curve_vcol(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "StrandsChildCurveVCol", NULL);
+ RNA_def_struct_sdna(srna, "StrandsChildCurveVCol");
+ RNA_def_struct_ui_text(srna, "Strand Child Curve Vertex Color", "Vertex color data for child strand curves");
+
+ prop = RNA_def_property(srna, "vcol", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Vertex Color", "");
+}
+
+static void rna_def_strands_child_vertex(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "StrandsChildVertex", NULL);
+ RNA_def_struct_sdna(srna, "StrandsChildVertex");
+ RNA_def_struct_ui_text(srna, "Strand Child Vertex", "Strand child vertex");
+
+ prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_float_sdna(prop, NULL, "co");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Location", "");
+}
+
+static void rna_def_strands_children(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "StrandsChildren", NULL);
+ RNA_def_struct_sdna(srna, "StrandsChildren");
+ RNA_def_struct_ui_text(srna, "Child Strands", "Strand geometry to represent hair and similar linear structures");
+
+ prop = RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "curves", "totcurves");
+ RNA_def_property_struct_type(prop, "StrandsChildCurve");
+ RNA_def_property_ui_text(prop, "Strand Child Curves", "");
+
+ prop = RNA_def_property(srna, "curve_uvs", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_funcs(prop, "rna_StrandsChildren_curve_uvs_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get",
+ "rna_StrandsChildren_curve_uvs_length", "rna_StrandsChildren_curve_uvs_lookup_int", NULL, NULL);
+ RNA_def_property_struct_type(prop, "StrandsChildCurveUV");
+ RNA_def_property_ui_text(prop, "Strand Child Curves UV", "");
+
+ prop = RNA_def_property(srna, "num_curve_uv_layers", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "numuv");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "UV Layers", "Number of UV layers");
+
+ prop = RNA_def_property(srna, "curve_vcols", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_funcs(prop, "rna_StrandsChildren_curve_vcols_begin", "rna_iterator_array_next", "rna_iterator_array_end", "rna_iterator_array_get",
+ "rna_StrandsChildren_curve_vcols_length", "rna_StrandsChildren_curve_vcols_lookup_int", NULL, NULL);
+ RNA_def_property_struct_type(prop, "StrandsChildCurveVCol");
+ RNA_def_property_ui_text(prop, "Strand Child Curves Vertex Colors", "");
+
+ prop = RNA_def_property(srna, "num_curve_vcol_layers", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "numvcol");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Vertex Color Layers", "Number of Vertex Color layers");
+
+ prop = RNA_def_property(srna, "vertices", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "verts", "totverts");
+ RNA_def_property_struct_type(prop, "StrandsChildVertex");
+ RNA_def_property_ui_text(prop, "Strand Child Vertex", "");
+}
+
+void RNA_def_strands(BlenderRNA *brna)
+{
+ rna_def_strands_curve(brna);
+ rna_def_strands_vertex(brna);
+ rna_def_strands_motion_state(brna);
+ rna_def_strands(brna);
+ rna_def_strands_child_curve(brna);
+ rna_def_strands_child_curve_uv(brna);
+ rna_def_strands_child_curve_vcol(brna);
+ rna_def_strands_child_vertex(brna);
+ rna_def_strands_children(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index c1882e7767d..88f164193d4 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -181,7 +181,7 @@ static void rna_Texture_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *pt
static void rna_Texture_mapping_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
TexMapping *texmap = ptr->data;
- init_tex_mapping(texmap);
+ BKE_texture_mapping_init(texmap);
rna_Texture_update(bmain, scene, ptr);
}
@@ -222,7 +222,7 @@ static void rna_Texture_type_set(PointerRNA *ptr, int value)
{
Tex *tex = (Tex *)ptr->data;
- tex_set_type(tex, value);
+ BKE_texture_type_set(tex, value);
}
void rna_TextureSlot_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
@@ -445,7 +445,7 @@ static void rna_Envmap_update_generic(Main *bmain, Scene *scene, PointerRNA *ptr
Tex *tex = ptr->id.data;
if (tex->env) {
ED_preview_kill_jobs(bmain->wm.first, bmain);
- BKE_free_envmapdata(tex->env);
+ BKE_texture_envmap_free_data(tex->env);
}
rna_Texture_update(bmain, scene, ptr);
}
@@ -1674,6 +1674,7 @@ static void rna_def_texture_pointdensity(BlenderRNA *brna)
{TEX_PD_COLOR_PARTSPEED, "PARTICLE_SPEED", 0, "Particle Speed",
"Particle speed (absolute magnitude of velocity) mapped as 0.0-1.0 intensity"},
{TEX_PD_COLOR_PARTVEL, "PARTICLE_VELOCITY", 0, "Particle Velocity", "XYZ velocity mapped to RGB colors"},
+ {TEX_PD_COLOR_PARTTEX, "PARTICLE_TEXTURE", 0, "Particle Texture", "Texture color of particles"},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_texture_api.c b/source/blender/makesrna/intern/rna_texture_api.c
index acf8333d6dc..a27ba6ea06d 100644
--- a/source/blender/makesrna/intern/rna_texture_api.c
+++ b/source/blender/makesrna/intern/rna_texture_api.c
@@ -60,7 +60,7 @@ static void clear_envmap(struct EnvMap *env, bContext *C)
Main *bmain = CTX_data_main(C);
Tex *tex;
- BKE_free_envmapdata(env);
+ BKE_texture_envmap_free_data(env);
for (tex = bmain->tex.first; tex; tex = tex->id.next)
if (tex->env == env) {
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index f56da1e92b7..d19b7dc9efa 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -464,15 +464,6 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_float(func, "percentage", 0.0f, 0.0f, 1.0f, "Percentage", "Percentage of width to split at", 0.0f, 1.0f);
RNA_def_boolean(func, "align", false, "", "Align buttons to each other");
- /* sub-block */
- func = RNA_def_function(srna, "subblock_begin", "uiLayoutSubblockBegin");
- parm = RNA_def_string(func, "identifier", NULL, MAX_NAME, "", "Name/ID of the sub-block");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- RNA_def_function_ui_description(func, "Set the beginning of a sub-block");
-
- func = RNA_def_function(srna, "subblock_end", "uiLayoutSubblockEnd");
- RNA_def_function_ui_description(func, "Set the end of a sub-block");
-
/* radial/pie layout */
func = RNA_def_function(srna, "menu_pie", "uiLayoutRadial");
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
@@ -728,11 +719,12 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_ui_description(func, "Item. A color ramp widget");
api_ui_item_rna_common(func);
RNA_def_boolean(func, "expand", false, "", "Expand button to show more detail");
-
+
func = RNA_def_function(srna, "template_icon_view", "uiTemplateIconView");
RNA_def_function_ui_description(func, "Enum. Large widget showing Icon previews");
api_ui_item_rna_common(func);
-
+ RNA_def_boolean(func, "show_labels", false, "", "Show enum label in preview buttons");
+
func = RNA_def_function(srna, "template_histogram", "uiTemplateHistogram");
RNA_def_function_ui_description(func, "Item. A histogramm widget to analyze imaga data");
api_ui_item_rna_common(func);
@@ -788,6 +780,16 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
RNA_def_boolean(func, "color_management", false, "", "Show color management settings");
+ func = RNA_def_function(srna, "template_image_stereo_3d", "uiTemplateImageStereo3d");
+ RNA_def_function_ui_description(func, "User interface for setting image stereo 3d options");
+ parm = RNA_def_pointer(func, "stereo_3d_format", "Stereo3dFormat", "", "");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+
+ func = RNA_def_function(srna, "template_image_views", "uiTemplateImageViews");
+ RNA_def_function_ui_description(func, "User interface for setting image views output options");
+ parm = RNA_def_pointer(func, "image_settings", "ImageFormatSettings", "", "");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+
func = RNA_def_function(srna, "template_movieclip", "uiTemplateMovieClip");
RNA_def_function_ui_description(func, "Item(s). User interface for selecting movie clips and their source paths");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
@@ -908,6 +910,19 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_ui_description(func, "Node Socket Icon");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
RNA_def_float_array(func, "color", 4, node_socket_color_default, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f);
+
+ /* cache library item */
+ func = RNA_def_function(srna, "template_cache_library_item", "uiTemplateCacheLibraryItem");
+ RNA_def_function_ui_description(func, "Cache Library Item");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_pointer(func, "cachelib", "CacheLibrary", "Cache Library", "Cache library containing the item");
+ RNA_def_pointer(func, "object", "Object", "Object", "Object to cache");
+ parm = RNA_def_enum(func, "datatype", cache_library_data_type_items, 0, "Data Type", "Type of cached data");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_int(func, "index", -1, -1, INT_MAX, "Index", "Index of cached data", -1, INT_MAX);
+ RNA_def_boolean(func, "enabled", true, "Enabled", "Enable the item");
+ parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
+ RNA_def_function_return(func, parm);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 92409b80adc..535ade75e13 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -331,7 +331,7 @@ static PointerRNA rna_UserDef_system_get(PointerRNA *ptr)
static void rna_UserDef_audio_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
- sound_init(bmain);
+ BKE_sound_init(bmain);
}
static void rna_Userdef_memcache_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
@@ -548,7 +548,7 @@ static EnumPropertyItem *rna_userdef_audio_device_itemf(bContext *UNUSED(C), Poi
#endif
#ifdef WITH_JACK
- if (sound_is_jack_supported()) {
+ if (BKE_sound_is_jack_supported()) {
RNA_enum_item_add(&item, &totitem, &audio_device_items[index]);
}
index++;
@@ -2386,6 +2386,18 @@ static void rna_def_userdef_theme_space_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Current Frame", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "metadatabg", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "metadatabg");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Metadata Background", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "metadatatext", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "metadatatext");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Metadata Text", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
rna_def_userdef_theme_spaces_curves(srna, false, false, false, true);
rna_def_userdef_theme_spaces_paint_curves(srna);
@@ -2488,6 +2500,18 @@ static void rna_def_userdef_theme_space_seq(BlenderRNA *brna)
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Preview Background", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "metadatabg", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "metadatabg");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Metadata Background", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "metadatatext", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "metadatatext");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Metadata Text", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
}
static void rna_def_userdef_theme_space_action(BlenderRNA *brna)
@@ -3239,7 +3263,14 @@ static void rna_def_userdef_view(BlenderRNA *brna)
"Direct conversion of frame numbers to seconds"},
{0, NULL, 0, NULL, NULL}
};
-
+
+ static EnumPropertyItem zoom_frame_modes[] = {
+ {ZOOM_FRAME_MODE_KEEP_RANGE, "KEEP_RANGE", 0, "Keep Range", ""},
+ {ZOOM_FRAME_MODE_SECONDS, "SECONDS", 0, "Seconds", ""},
+ {ZOOM_FRAME_MODE_KEYFRAMES, "KEYFRAMES", 0, "Keyframes", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
PropertyRNA *prop;
StructRNA *srna;
@@ -3491,6 +3522,22 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "TimeCode Style",
"Format of Time Codes displayed when not displaying timing in terms of frames");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "view_frame_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, zoom_frame_modes);
+ RNA_def_property_enum_sdna(prop, NULL, "view_frame_type");
+ RNA_def_property_ui_text(prop, "Zoom To Frame Type", "How zooming to frame focuses around current frame");
+
+ prop = RNA_def_property(srna, "view_frame_keyframes", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 1, 500);
+ RNA_def_property_ui_text(prop, "Zoom Keyframes",
+ "Keyframes around cursor that we zoom around");
+
+ prop = RNA_def_property(srna, "view_frame_seconds", PROP_FLOAT, PROP_TIME);
+ RNA_def_property_range(prop, 0.0, 10000.0);
+ RNA_def_property_ui_text(prop, "Zoom Seconds",
+ "Seconds around cursor that we zoom around");
+
}
static void rna_def_userdef_edit(BlenderRNA *brna)
@@ -3611,7 +3658,7 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "New Interpolation Type",
"Interpolation mode used for first keyframe on newly added F-Curves "
"(subsequent keyframes take interpolation from preceding keyframe)");
-
+
prop = RNA_def_property(srna, "keyframe_new_handle_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, keyframe_handle_type_items);
RNA_def_property_enum_sdna(prop, NULL, "keyhandles_new");
@@ -3658,7 +3705,7 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Grease Pencil Eraser Radius", "Radius of eraser 'brush'");
- prop = RNA_def_property(srna, "grease_pencil_default_color", PROP_FLOAT, PROP_COLOR);
+ prop = RNA_def_property(srna, "grease_pencil_default_color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "gpencil_new_layer_col");
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Grease Pencil Default Color", "Color of new Grease Pencil layers");
@@ -4134,8 +4181,8 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "uiflag2", USER_REGION_OVERLAP);
RNA_def_property_ui_text(prop, "Region Overlap",
"Draw tool/property regions over the main region, when using Triple Buffer");
- RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
-
+ RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
+
#ifdef WITH_CYCLES
prop = RNA_def_property(srna, "compute_device_type", PROP_ENUM, PROP_NONE);
RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 0b63539aab9..c23b56582b6 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -415,7 +415,7 @@ static EnumPropertyItem operator_flag_items[] = {
{OPTYPE_UNDO, "UNDO", 0, "Undo", "Push an undo event (needed for operator redo)"},
{OPTYPE_BLOCKING, "BLOCKING", 0, "Blocking", "Block anything else from using the cursor"},
{OPTYPE_MACRO, "MACRO", 0, "Macro", "Use to check if an operator is a macro"},
- {OPTYPE_GRAB_POINTER, "GRAB_POINTER", 0, "Grab Pointer",
+ {OPTYPE_GRAB_CURSOR, "GRAB_CURSOR", 0, "Grab Pointer",
"Use so the operator grabs the mouse focus, enables wrapping when continuous grab "
"is enabled"},
{OPTYPE_PRESET, "PRESET", 0, "Preset", "Display a preset button with the operators settings"},
@@ -512,6 +512,11 @@ static int rna_Operator_has_reports_get(PointerRNA *ptr)
return (op->reports && op->reports->list.first);
}
+static PointerRNA rna_Operator_options_get(PointerRNA *ptr)
+{
+ return rna_pointer_inherit_refine(ptr, &RNA_OperatorOptions, ptr->data);
+}
+
static PointerRNA rna_Operator_properties_get(PointerRNA *ptr)
{
wmOperator *op = (wmOperator *)ptr->data;
@@ -811,6 +816,29 @@ static void rna_KeyMapItem_any_set(PointerRNA *ptr, int value)
}
}
+static int rna_KeyMapItem_shift_get(PointerRNA *ptr)
+{
+ wmKeyMapItem *kmi = (wmKeyMapItem *)ptr->data;
+ return kmi->shift != 0;
+}
+
+static int rna_KeyMapItem_ctrl_get(PointerRNA *ptr)
+{
+ wmKeyMapItem *kmi = (wmKeyMapItem *)ptr->data;
+ return kmi->ctrl != 0;
+}
+
+static int rna_KeyMapItem_alt_get(PointerRNA *ptr)
+{
+ wmKeyMapItem *kmi = (wmKeyMapItem *)ptr->data;
+ return kmi->alt != 0;
+}
+
+static int rna_KeyMapItem_oskey_get(PointerRNA *ptr)
+{
+ wmKeyMapItem *kmi = (wmKeyMapItem *)ptr->data;
+ return kmi->oskey != 0;
+}
static PointerRNA rna_WindowManager_active_keyconfig_get(PointerRNA *ptr)
{
@@ -1562,6 +1590,33 @@ static void rna_KeyMapItem_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
#else /* RNA_RUNTIME */
+/**
+ * expose ``Operator.options`` as its own type so we can control each flags use (some are read-only).
+ */
+static void rna_def_operator_options_runtime(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "OperatorOptions", NULL);
+ RNA_def_struct_ui_text(srna, "Operator Options", "Runtime options");
+ RNA_def_struct_sdna(srna, "wmOperator");
+
+ prop = RNA_def_property(srna, "is_grab_cursor", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", OP_IS_MODAL_GRAB_CURSOR);
+ RNA_def_property_ui_text(prop, "Grab Cursor", "True when the cursor is grabbed");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "is_invoke", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", OP_IS_INVOKE);
+ RNA_def_property_ui_text(prop, "Invoke", "True when invoked (even if only the execute callbacks available)");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "use_cursor_region", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", OP_IS_MODAL_CURSOR_REGION);
+ RNA_def_property_ui_text(prop, "Focus Region", "Enable to use the region under the cursor for modal execution");
+}
+
static void rna_def_operator(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1596,6 +1651,12 @@ static void rna_def_operator(BlenderRNA *brna)
prop = RNA_def_property(srna, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "UILayout");
+ prop = RNA_def_property(srna, "options", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "OperatorOptions");
+ RNA_def_property_pointer_funcs(prop, "rna_Operator_options_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Options", "Runtime options");
+
/* Registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "type->idname");
@@ -1635,6 +1696,11 @@ static void rna_def_operator(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL | PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Options", "Options for this operator type");
+ prop = RNA_def_property(srna, "macros", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "macro", NULL);
+ RNA_def_property_struct_type(prop, "Macro");
+ RNA_def_property_ui_text(prop, "Macros", "");
+
RNA_api_operator(srna);
srna = RNA_def_struct(brna, "OperatorProperties", NULL);
@@ -1998,6 +2064,37 @@ static void rna_def_piemenu(BlenderRNA *brna)
RNA_define_verify_sdna(1); /* not in sdna */
}
+static void rna_def_window_stereo3d(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "Stereo3dDisplay", NULL);
+ RNA_def_struct_sdna(srna, "Stereo3dFormat");
+ RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
+ RNA_def_struct_ui_text(srna, "Stereo 3D Display", "Settings for stereo 3D display");
+
+ prop = RNA_def_property(srna, "display_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, stereo3d_display_items);
+ RNA_def_property_ui_text(prop, "Display Mode", "");
+
+ prop = RNA_def_property(srna, "anaglyph_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, stereo3d_anaglyph_type_items);
+ RNA_def_property_ui_text(prop, "Anaglyph Type", "");
+
+ prop = RNA_def_property(srna, "interlace_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, stereo3d_interlace_type_items);
+ RNA_def_property_ui_text(prop, "Interlace Type", "");
+
+ prop = RNA_def_property(srna, "use_interlace_swap", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", S3D_INTERLACE_SWAP);
+ RNA_def_property_ui_text(prop, "Swap Left/Right", "Swap left and right stereo channels");
+
+ prop = RNA_def_property(srna, "use_sidebyside_crosseyed", PROP_BOOLEAN, PROP_BOOLEAN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", S3D_SIDEBYSIDE_CROSSEYED);
+ RNA_def_property_ui_text(prop, "Cross-Eyed", "Right eye should see left image and vice-versa");
+}
+
static void rna_def_window(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2007,6 +2104,8 @@ static void rna_def_window(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Window", "Open window");
RNA_def_struct_sdna(srna, "wmWindow");
+ rna_def_window_stereo3d(brna);
+
prop = RNA_def_property(srna, "screen", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_struct_type(prop, "Screen");
@@ -2036,6 +2135,12 @@ static void rna_def_window(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Height", "Window height");
+ prop = RNA_def_property(srna, "stereo_3d_display", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "stereo3d_format");
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "Stereo3dDisplay");
+ RNA_def_property_ui_text(prop, "Stereo 3D Display", "Settings for stereo 3d display");
+
RNA_api_window(srna);
}
@@ -2284,6 +2389,7 @@ static void rna_def_keyconfig(BlenderRNA *brna)
prop = RNA_def_property(srna, "shift", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "shift", 0);
+ RNA_def_property_boolean_funcs(prop, "rna_KeyMapItem_shift_get", NULL);
/* RNA_def_property_enum_sdna(prop, NULL, "shift"); */
/* RNA_def_property_enum_items(prop, keymap_modifiers_items); */
RNA_def_property_ui_text(prop, "Shift", "Shift key pressed");
@@ -2291,6 +2397,7 @@ static void rna_def_keyconfig(BlenderRNA *brna)
prop = RNA_def_property(srna, "ctrl", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "ctrl", 0);
+ RNA_def_property_boolean_funcs(prop, "rna_KeyMapItem_ctrl_get", NULL);
/* RNA_def_property_enum_sdna(prop, NULL, "ctrl"); */
/* RNA_def_property_enum_items(prop, keymap_modifiers_items); */
RNA_def_property_ui_text(prop, "Ctrl", "Control key pressed");
@@ -2298,6 +2405,7 @@ static void rna_def_keyconfig(BlenderRNA *brna)
prop = RNA_def_property(srna, "alt", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "alt", 0);
+ RNA_def_property_boolean_funcs(prop, "rna_KeyMapItem_alt_get", NULL);
/* RNA_def_property_enum_sdna(prop, NULL, "alt"); */
/* RNA_def_property_enum_items(prop, keymap_modifiers_items); */
RNA_def_property_ui_text(prop, "Alt", "Alt key pressed");
@@ -2305,6 +2413,7 @@ static void rna_def_keyconfig(BlenderRNA *brna)
prop = RNA_def_property(srna, "oskey", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "oskey", 0);
+ RNA_def_property_boolean_funcs(prop, "rna_KeyMapItem_oskey_get", NULL);
/* RNA_def_property_enum_sdna(prop, NULL, "oskey"); */
/* RNA_def_property_enum_items(prop, keymap_modifiers_items); */
RNA_def_property_ui_text(prop, "OS Key", "Operating system key pressed");
@@ -2353,6 +2462,7 @@ static void rna_def_keyconfig(BlenderRNA *brna)
void RNA_def_wm(BlenderRNA *brna)
{
rna_def_operator(brna);
+ rna_def_operator_options_runtime(brna);
rna_def_operator_utils(brna);
rna_def_operator_filelist_element(brna);
rna_def_macro_operator(brna);
diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c
index 721cbaf21c7..3f55ad9c668 100644
--- a/source/blender/makesrna/intern/rna_world.c
+++ b/source/blender/makesrna/intern/rna_world.c
@@ -92,6 +92,7 @@ static void rna_World_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerR
WM_main_add_notifier(NC_WORLD | ND_WORLD, wo);
}
+#if 0
static void rna_World_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
World *wo = ptr->id.data;
@@ -99,6 +100,7 @@ static void rna_World_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
DAG_id_tag_update(&wo->id, 0);
WM_main_add_notifier(NC_WORLD | ND_WORLD_DRAW, wo);
}
+#endif
/* so camera mist limits redraw */
static void rna_World_draw_mist_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
@@ -403,13 +405,13 @@ static void rna_def_world_mist(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_mist", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", WO_MIST);
RNA_def_property_ui_text(prop, "Use Mist", "Occlude objects with the environment color as they are further away");
- RNA_def_property_update(prop, 0, "rna_World_draw_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "misi");
RNA_def_property_range(prop, 0, 1);
RNA_def_property_ui_text(prop, "Minimum", "Overall minimum intensity of the mist effect");
- RNA_def_property_update(prop, 0, "rna_World_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
prop = RNA_def_property(srna, "start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "miststa");
@@ -435,7 +437,7 @@ static void rna_def_world_mist(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "mistype");
RNA_def_property_enum_items(prop, falloff_items);
RNA_def_property_ui_text(prop, "Falloff", "Type of transition used to fade mist");
- RNA_def_property_update(prop, 0, "rna_World_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
}
void RNA_def_world(BlenderRNA *brna)
@@ -460,8 +462,7 @@ void RNA_def_world(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Horizon Color", "Color at the horizon");
/* RNA_def_property_update(prop, 0, "rna_World_update"); */
/* render-only uses this */
- RNA_def_property_update(prop, NC_WORLD | ND_WORLD_DRAW, "rna_World_update");
-
+ RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
prop = RNA_def_property(srna, "zenith_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "zenr");
@@ -473,7 +474,7 @@ void RNA_def_world(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "ambr");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Ambient Color", "Ambient color of the world");
- RNA_def_property_update(prop, 0, "rna_World_update");
+ RNA_def_property_update(prop, 0, "rna_World_draw_mist_update");
/* exp, range */
prop = RNA_def_property(srna, "exposure", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 57e927fffed..5306f6d34ba 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -30,9 +30,11 @@ set(INC
../blenkernel
../blenlib
../blenfont
+ ../depsgraph
../makesdna
../makesrna
../bmesh
+ ../pointcache
../render/extern/include
../../../intern/elbeem/extern
../../../intern/guardedalloc
@@ -51,6 +53,7 @@ set(SRC
intern/MOD_cast.c
intern/MOD_cloth.c
intern/MOD_collision.c
+ intern/MOD_correctivesmooth.c
intern/MOD_curve.c
intern/MOD_datatransfer.c
intern/MOD_decimate.c
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index 66e613be68a..a5d96759952 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -83,6 +83,7 @@ extern ModifierTypeInfo modifierType_LaplacianDeform;
extern ModifierTypeInfo modifierType_Wireframe;
extern ModifierTypeInfo modifierType_DataTransfer;
extern ModifierTypeInfo modifierType_NormalEdit;
+extern ModifierTypeInfo modifierType_CorrectiveSmooth;
/* MOD_util.c */
void modifier_type_init(ModifierTypeInfo *types[]);
diff --git a/source/blender/modifiers/SConscript b/source/blender/modifiers/SConscript
index b4c8299250e..761342b79d6 100644
--- a/source/blender/modifiers/SConscript
+++ b/source/blender/modifiers/SConscript
@@ -40,10 +40,12 @@ incs = [
'../include',
'../blenlib',
'../blenfont',
+ '../depsgraph',
'../makesdna',
'../makesrna',
'../blenkernel',
'../gpu',
+ '../pointcache',
env['BF_ZLIB_INC'],
]
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index a4248df5ea1..9ce31cebb66 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -100,6 +100,7 @@ static void foreachObjectLink(
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
DagNode *obNode)
@@ -114,6 +115,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ ArmatureModifierData *amd = (ArmatureModifierData *)md;
+ if (amd->object != NULL) {
+ DEG_add_object_relation(node, amd->object, DEG_OB_COMP_EVAL_POSE, "Armature Modifier");
+ }
+}
+
static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
@@ -207,6 +220,7 @@ ModifierTypeInfo modifierType_Armature = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 7430a4300a5..efb77f73ec9 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -102,7 +102,9 @@ static void foreachObjectLink(
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
- struct Scene *UNUSED(scene), Object *UNUSED(ob), DagNode *obNode)
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob), DagNode *obNode)
{
ArrayModifierData *amd = (ArrayModifierData *) md;
@@ -133,6 +135,28 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *scene,
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ ArrayModifierData *amd = (ArrayModifierData *)md;
+ if (amd->start_cap != NULL) {
+ DEG_add_object_relation(node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier Start Cap");
+ }
+ if (amd->end_cap != NULL) {
+ DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier End Cap");
+ }
+ if (amd->curve_ob) {
+ DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_GEOMETRY, "Hook Modifier Curve");
+ DEG_add_special_eval_flag(scene->depsgraph, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH);
+ }
+ if (amd->offset_ob != NULL) {
+ DEG_add_object_relation(node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Hook Modifier Offset");
+ }
+}
+
static float vertarray_size(const MVert *mvert, int numVerts, int axis)
{
int i;
@@ -362,22 +386,22 @@ static void dm_merge_transform(
/* set origindex */
index_orig = result->getVertDataArray(result, CD_ORIGINDEX);
if (index_orig) {
- fill_vn_i(index_orig + cap_verts_index, cap_nverts, ORIGINDEX_NONE);
+ copy_vn_i(index_orig + cap_verts_index, cap_nverts, ORIGINDEX_NONE);
}
index_orig = result->getEdgeDataArray(result, CD_ORIGINDEX);
if (index_orig) {
- fill_vn_i(index_orig + cap_edges_index, cap_nedges, ORIGINDEX_NONE);
+ copy_vn_i(index_orig + cap_edges_index, cap_nedges, ORIGINDEX_NONE);
}
index_orig = result->getPolyDataArray(result, CD_ORIGINDEX);
if (index_orig) {
- fill_vn_i(index_orig + cap_polys_index, cap_npolys, ORIGINDEX_NONE);
+ copy_vn_i(index_orig + cap_polys_index, cap_npolys, ORIGINDEX_NONE);
}
index_orig = result->getLoopDataArray(result, CD_ORIGINDEX);
if (index_orig) {
- fill_vn_i(index_orig + cap_loops_index, cap_nloops, ORIGINDEX_NONE);
+ copy_vn_i(index_orig + cap_loops_index, cap_nloops, ORIGINDEX_NONE);
}
}
@@ -499,7 +523,7 @@ static DerivedMesh *arrayModifier_doArray(
if (dist > eps) {
/* this gives length = first copy start to last copy end
* add a tiny offset for floating point rounding errors */
- count = (length + eps) / dist;
+ count = (length + eps) / dist + 1;
}
else {
/* if the offset has no translation, just make one copy */
@@ -523,7 +547,7 @@ static DerivedMesh *arrayModifier_doArray(
if (use_merge) {
/* Will need full_doubles_map for handling merge */
full_doubles_map = MEM_mallocN(sizeof(int) * result_nverts, "mod array doubles map");
- fill_vn_i(full_doubles_map, result_nverts, -1);
+ copy_vn_i(full_doubles_map, result_nverts, -1);
}
/* copy customdata to original geometry */
@@ -769,6 +793,7 @@ ModifierTypeInfo modifierType_Array = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index 1dca18dce37..c2b5a29939f 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -213,6 +213,7 @@ ModifierTypeInfo modifierType_Bevel = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index 22636e7c4d0..eb54a3c4e9c 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -74,6 +74,7 @@ static void foreachObjectLink(
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
DagNode *obNode)
@@ -88,6 +89,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ BooleanModifierData *bmd = (BooleanModifierData *)md;
+ if (bmd->object != NULL) {
+ DEG_add_object_relation(node, bmd->object, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
+ DEG_add_object_relation(node, bmd->object, DEG_OB_COMP_GEOMETRY, "Boolean Modifier");
+ }
+ /* We need own transformation as well. */
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
+}
+
#ifdef WITH_MOD_BOOLEAN
static DerivedMesh *get_quick_derivedMesh(DerivedMesh *derivedData, DerivedMesh *dm, int operation)
{
@@ -192,6 +208,7 @@ ModifierTypeInfo modifierType_Boolean = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_boolean_util.h b/source/blender/modifiers/intern/MOD_boolean_util.h
index 04d76d45652..00d7c37b266 100644
--- a/source/blender/modifiers/intern/MOD_boolean_util.h
+++ b/source/blender/modifiers/intern/MOD_boolean_util.h
@@ -33,9 +33,7 @@
#ifndef __MOD_BOOLEAN_UTIL_H__
#define __MOD_BOOLEAN_UTIL_H__
-struct Scene;
struct Object;
-struct Base;
struct DerivedMesh;
/* Performs a boolean between two mesh objects, it is assumed that both objects
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index 1dc1a1f8d64..507fad466a3 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -131,6 +131,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
MPoly *mpoly, *mp;
MLoop *ml, *mloop;
MEdge *medge;
+ uintptr_t hash_num, hash_num_alt;
if (bmd->flag & MOD_BUILD_FLAG_RANDOMIZE) {
BLI_array_randomize(faceMap, sizeof(*faceMap),
@@ -142,40 +143,44 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
*/
mpoly = mpoly_src;
mloop = mloop_src;
+ hash_num = 0;
for (i = 0; i < numFaces_dst; i++) {
mp = mpoly + faceMap[i];
ml = mloop + mp->loopstart;
for (j = 0; j < mp->totloop; j++, ml++) {
- if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml->v)))
- BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(ml->v),
- SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
+ void **val_p;
+ if (!BLI_ghash_ensure_p(vertHash, SET_INT_IN_POINTER(ml->v), &val_p)) {
+ *val_p = (void *)hash_num;
+ hash_num++;
+ }
}
-
+
numLoops_dst += mp->totloop;
}
+ BLI_assert(hash_num == BLI_ghash_size(vertHash));
/* get the set of edges that will be in the new mesh (i.e. all edges
* that have both verts in the new mesh)
*/
medge = medge_src;
- for (i = 0; i < numEdge_src; i++) {
+ hash_num = 0;
+ hash_num_alt = 0;
+ for (i = 0; i < numEdge_src; i++, hash_num_alt++) {
MEdge *me = medge + i;
if (BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v1)) &&
BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v2)))
{
- j = BLI_ghash_size(edgeHash);
-
- BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(j),
- SET_INT_IN_POINTER(i));
- BLI_ghash_insert(edgeHash2, SET_INT_IN_POINTER(i),
- SET_INT_IN_POINTER(j));
+ BLI_ghash_insert(edgeHash, (void *)hash_num, (void *)hash_num_alt);
+ BLI_ghash_insert(edgeHash2, (void *)hash_num_alt, (void *)hash_num);
+ hash_num++;
}
}
}
else if (numEdges_dst) {
MEdge *medge, *me;
+ uintptr_t hash_num;
if (bmd->flag & MOD_BUILD_FLAG_RANDOMIZE)
BLI_array_randomize(edgeMap, sizeof(*edgeMap),
@@ -185,17 +190,22 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
* mapped to the new indices
*/
medge = medge_src;
+ hash_num = 0;
+ BLI_assert(hash_num == BLI_ghash_size(vertHash));
for (i = 0; i < numEdges_dst; i++) {
+ void **val_p;
me = medge + edgeMap[i];
- if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v1))) {
- BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me->v1),
- SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
+ if (!BLI_ghash_ensure_p(vertHash, SET_INT_IN_POINTER(me->v1), &val_p)) {
+ *val_p = (void *)hash_num;
+ hash_num++;
}
- if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v2))) {
- BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me->v2), SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
+ if (!BLI_ghash_ensure_p(vertHash, SET_INT_IN_POINTER(me->v2), &val_p)) {
+ *val_p = (void *)hash_num;
+ hash_num++;
}
}
+ BLI_assert(hash_num == BLI_ghash_size(vertHash));
/* get the set of edges that will be in the new mesh */
for (i = 0; i < numEdges_dst; i++) {
@@ -319,6 +329,7 @@ ModifierTypeInfo modifierType_Build = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index c4654287cfc..7c3d65a5c9a 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -106,6 +106,7 @@ static void foreachObjectLink(
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
DagNode *obNode)
@@ -120,6 +121,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ CastModifierData *cmd = (CastModifierData *)md;
+ if (cmd->object != NULL) {
+ DEG_add_object_relation(node, cmd->object, DEG_OB_COMP_TRANSFORM, "Cast Modifier");
+ }
+}
+
static void sphere_do(
CastModifierData *cmd, Object *ob, DerivedMesh *dm,
float (*vertexCos)[3], int numVerts)
@@ -499,6 +512,7 @@ ModifierTypeInfo modifierType_Cast = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index 71a83dfa742..25fd54d1d3e 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -98,7 +98,7 @@ static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData,
if (derivedData == NULL && clmd->sim_parms->shapekey_rest) {
KeyBlock *kb = BKE_keyblock_from_key(BKE_key_from_object(ob),
clmd->sim_parms->shapekey_rest);
- if (kb->data != NULL) {
+ if (kb && kb->data != NULL) {
float (*layerorco)[3];
if (!(layerorco = DM_get_vert_data_layer(dm, CD_CLOTH_ORCO))) {
DM_add_vert_layer(dm, CD_CLOTH_ORCO, CD_CALLOC, NULL);
@@ -118,7 +118,9 @@ static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData,
dm->release(dm);
}
-static void updateDepgraph(ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode)
+static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
+ Scene *scene, Object *ob, DagNode *obNode)
{
ClothModifierData *clmd = (ClothModifierData *) md;
@@ -138,6 +140,27 @@ static void updateDepgraph(ModifierData *md, DagForest *forest, Scene *scene, Ob
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *scene,
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ ClothModifierData *clmd = (ClothModifierData *)md;
+ if (clmd != NULL) {
+ Base *base;
+ for (base = scene->base.first; base; base = base->next) {
+ Object *ob1 = base->object;
+ if (ob1 != ob) {
+ CollisionModifierData *coll_clmd = (CollisionModifierData *)modifiers_findByType(ob1, eModifierType_Collision);
+ if (coll_clmd) {
+ DEG_add_object_relation(node, ob1, DEG_OB_COMP_TRANSFORM, "Cloth Modifier");
+ }
+ }
+ }
+ }
+}
+
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
CustomDataMask dataMask = 0;
@@ -249,6 +272,7 @@ ModifierTypeInfo modifierType_Cloth = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index 130e332ef69..931f82c98e9 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -241,6 +241,7 @@ ModifierTypeInfo modifierType_Collision = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
new file mode 100644
index 00000000000..d5b4daca3b7
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -0,0 +1,769 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if 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 by the Blender Foundation.
+* All rights reserved.
+*
+* Contributor(s): Jack Simpson,
+* Campbell Barton
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+*/
+
+/** \file blender/modifiers/intern/MOD_correctivesmooth.c
+ * \ingroup modifiers
+ *
+ * Method of smoothing deformation, also known as 'delta-mush'.
+ */
+
+#include "DNA_scene_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_deform.h"
+#include "BKE_mesh.h"
+#include "BKE_editmesh.h"
+
+#include "MOD_modifiertypes.h"
+#include "MOD_util.h"
+
+#include "BLI_strict_flags.h"
+
+
+// #define DEBUG_TIME
+
+#include "PIL_time.h"
+#ifdef DEBUG_TIME
+# include "PIL_time_utildefines.h"
+#endif
+
+/* minor optimization, calculate this inline */
+#define USE_TANGENT_CALC_INLINE
+
+static void initData(ModifierData *md)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+
+ csmd->bind_coords = NULL;
+ csmd->bind_coords_num = 0;
+
+ csmd->lambda = 0.5f;
+ csmd->repeat = 5;
+ csmd->flag = 0;
+ csmd->smooth_type = MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE;
+
+ csmd->defgrp_name[0] = '\0';
+
+ csmd->delta_cache = NULL;
+}
+
+
+static void copyData(ModifierData *md, ModifierData *target)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+ CorrectiveSmoothModifierData *tcsmd = (CorrectiveSmoothModifierData *)target;
+
+ modifier_copyData_generic(md, target);
+
+ if (csmd->bind_coords) {
+ tcsmd->bind_coords = MEM_dupallocN(csmd->bind_coords);
+ }
+
+ tcsmd->delta_cache = NULL;
+ tcsmd->delta_cache_num = 0;
+}
+
+
+static void freeBind(CorrectiveSmoothModifierData *csmd)
+{
+ MEM_SAFE_FREE(csmd->bind_coords);
+ MEM_SAFE_FREE(csmd->delta_cache);
+
+ csmd->bind_coords_num = 0;
+}
+
+
+static void freeData(ModifierData *md)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+ freeBind(csmd);
+}
+
+
+static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+ CustomDataMask dataMask = 0;
+ /* ask for vertex groups if we need them */
+ if (csmd->defgrp_name[0]) {
+ dataMask |= CD_MASK_MDEFORMVERT;
+ }
+ return dataMask;
+}
+
+
+/* check individual weights for changes and cache values */
+static void dm_get_weights(
+ MDeformVert *dvert, const int defgrp_index,
+ const unsigned int numVerts, const bool use_invert_vgroup,
+ float *smooth_weights)
+{
+ unsigned int i;
+
+ for (i = 0; i < numVerts; i++, dvert++) {
+ const float w = defvert_find_weight(dvert, defgrp_index);
+
+ if (use_invert_vgroup == false) {
+ smooth_weights[i] = w;
+ }
+ else {
+ smooth_weights[i] = 1.0f - w;
+ }
+ }
+}
+
+
+static void dm_get_boundaries(DerivedMesh *dm, float *smooth_weights)
+{
+ const MPoly *mpoly = dm->getPolyArray(dm);
+ const MLoop *mloop = dm->getLoopArray(dm);
+ const MEdge *medge = dm->getEdgeArray(dm);
+ unsigned int mpoly_num, medge_num, i;
+ unsigned short *boundaries;
+
+ mpoly_num = (unsigned int)dm->getNumPolys(dm);
+ medge_num = (unsigned int)dm->getNumEdges(dm);
+
+ boundaries = MEM_callocN(medge_num * sizeof(*boundaries), __func__);
+
+ /* count the number of adjacent faces */
+ for (i = 0; i < mpoly_num; i++) {
+ const MPoly *p = &mpoly[i];
+ const int totloop = p->totloop;
+ int j;
+ for (j = 0; j < totloop; j++) {
+ boundaries[mloop[p->loopstart + j].e]++;
+ }
+ }
+
+ for (i = 0; i < medge_num; i++) {
+ if (boundaries[i] == 1) {
+ smooth_weights[medge[i].v1] = 0.0f;
+ smooth_weights[medge[i].v2] = 0.0f;
+ }
+ }
+
+ MEM_freeN(boundaries);
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Simple Weighted Smoothing
+ *
+ * (average of surrounding verts)
+ */
+static void smooth_iter__simple(
+ CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ float (*vertexCos)[3], unsigned int numVerts,
+ const float *smooth_weights,
+ unsigned int iterations)
+{
+ const float lambda = csmd->lambda;
+ unsigned int i;
+
+ const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm);
+ const MEdge *edges = dm->getEdgeArray(dm);
+ float *vertex_edge_count_div;
+
+ struct SmoothingData_Simple {
+ float delta[3];
+ } *smooth_data = MEM_callocN((size_t)numVerts * sizeof(*smooth_data), __func__);
+
+ vertex_edge_count_div = MEM_callocN((size_t)numVerts * sizeof(float), __func__);
+
+ /* calculate as floats to avoid int->float conversion in #smooth_iter */
+ for (i = 0; i < numEdges; i++) {
+ vertex_edge_count_div[edges[i].v1] += 1.0f;
+ vertex_edge_count_div[edges[i].v2] += 1.0f;
+ }
+
+ /* a little confusing, but we can include 'lambda' and smoothing weight
+ * here to avoid multiplying for every iteration */
+ if (smooth_weights == NULL) {
+ for (i = 0; i < numVerts; i++) {
+ vertex_edge_count_div[i] =
+ lambda * (vertex_edge_count_div[i] ? (1.0f / vertex_edge_count_div[i]) : 1.0f);
+ }
+ }
+ else {
+ for (i = 0; i < numVerts; i++) {
+ vertex_edge_count_div[i] =
+ smooth_weights[i] * lambda * (vertex_edge_count_div[i] ? (1.0f / vertex_edge_count_div[i]) : 1.0f);
+ }
+ }
+
+ /* -------------------------------------------------------------------- */
+ /* Main Smoothing Loop */
+
+ while (iterations--) {
+ for (i = 0; i < numEdges; i++) {
+ struct SmoothingData_Simple *sd_v1;
+ struct SmoothingData_Simple *sd_v2;
+ float edge_dir[3];
+
+ sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]);
+
+ sd_v1 = &smooth_data[edges[i].v1];
+ sd_v2 = &smooth_data[edges[i].v2];
+
+ add_v3_v3(sd_v1->delta, edge_dir);
+ sub_v3_v3(sd_v2->delta, edge_dir);
+ }
+
+
+ for (i = 0; i < numVerts; i++) {
+ struct SmoothingData_Simple *sd = &smooth_data[i];
+ madd_v3_v3fl(vertexCos[i], sd->delta, vertex_edge_count_div[i]);
+ /* zero for the next iteration (saves memset on entire array) */
+ memset(sd, 0, sizeof(*sd));
+ }
+ }
+
+ MEM_freeN(vertex_edge_count_div);
+ MEM_freeN(smooth_data);
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Edge-Length Weighted Smoothing
+ */
+static void smooth_iter__length_weight(
+ CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ float (*vertexCos)[3], unsigned int numVerts,
+ const float *smooth_weights,
+ unsigned int iterations)
+{
+ const float eps = FLT_EPSILON * 10.0f;
+ const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm);
+ /* note: the way this smoothing method works, its approx half as strong as the simple-smooth,
+ * and 2.0 rarely spikes, double the value for consistent behavior. */
+ const float lambda = csmd->lambda * 2.0f;
+ const MEdge *edges = dm->getEdgeArray(dm);
+ float *vertex_edge_count;
+ unsigned int i;
+
+ struct SmoothingData_Weighted {
+ float delta[3];
+ float edge_length_sum;
+ } *smooth_data = MEM_callocN((size_t)numVerts * sizeof(*smooth_data), __func__);
+
+
+ /* calculate as floats to avoid int->float conversion in #smooth_iter */
+ vertex_edge_count = MEM_callocN((size_t)numVerts * sizeof(float), __func__);
+ for (i = 0; i < numEdges; i++) {
+ vertex_edge_count[edges[i].v1] += 1.0f;
+ vertex_edge_count[edges[i].v2] += 1.0f;
+ }
+
+
+ /* -------------------------------------------------------------------- */
+ /* Main Smoothing Loop */
+
+ while (iterations--) {
+ for (i = 0; i < numEdges; i++) {
+ struct SmoothingData_Weighted *sd_v1;
+ struct SmoothingData_Weighted *sd_v2;
+ float edge_dir[3];
+ float edge_dist;
+
+ sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]);
+ edge_dist = len_v3(edge_dir);
+
+ /* weight by distance */
+ mul_v3_fl(edge_dir, edge_dist);
+
+
+ sd_v1 = &smooth_data[edges[i].v1];
+ sd_v2 = &smooth_data[edges[i].v2];
+
+ add_v3_v3(sd_v1->delta, edge_dir);
+ sub_v3_v3(sd_v2->delta, edge_dir);
+
+ sd_v1->edge_length_sum += edge_dist;
+ sd_v2->edge_length_sum += edge_dist;
+ }
+
+ if (smooth_weights == NULL) {
+ /* fast-path */
+ for (i = 0; i < numVerts; i++) {
+ struct SmoothingData_Weighted *sd = &smooth_data[i];
+ /* divide by sum of all neighbour distances (weighted) and amount of neighbours, (mean average) */
+ const float div = sd->edge_length_sum * vertex_edge_count[i];
+ if (div > eps) {
+#if 0
+ /* first calculate the new location */
+ mul_v3_fl(sd->delta, 1.0f / div);
+ /* then interpolate */
+ madd_v3_v3fl(vertexCos[i], sd->delta, lambda);
+#else
+ /* do this in one step */
+ madd_v3_v3fl(vertexCos[i], sd->delta, lambda / div);
+#endif
+ }
+ /* zero for the next iteration (saves memset on entire array) */
+ memset(sd, 0, sizeof(*sd));
+ }
+ }
+ else {
+ for (i = 0; i < numVerts; i++) {
+ struct SmoothingData_Weighted *sd = &smooth_data[i];
+ const float div = sd->edge_length_sum * vertex_edge_count[i];
+ if (div > eps) {
+ const float lambda_w = lambda * smooth_weights[i];
+ madd_v3_v3fl(vertexCos[i], sd->delta, lambda_w / div);
+ }
+
+ memset(sd, 0, sizeof(*sd));
+ }
+ }
+ }
+
+ MEM_freeN(vertex_edge_count);
+ MEM_freeN(smooth_data);
+}
+
+
+static void smooth_iter(
+ CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ float (*vertexCos)[3], unsigned int numVerts,
+ const float *smooth_weights,
+ unsigned int iterations)
+{
+ switch (csmd->smooth_type) {
+ case MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT:
+ smooth_iter__length_weight(csmd, dm, vertexCos, numVerts, smooth_weights, iterations);
+ break;
+
+ /* case MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE: */
+ default:
+ smooth_iter__simple(csmd, dm, vertexCos, numVerts, smooth_weights, iterations);
+ break;
+ }
+}
+
+static void smooth_verts(
+ CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ MDeformVert *dvert, const int defgrp_index,
+ float (*vertexCos)[3], unsigned int numVerts)
+{
+ float *smooth_weights = NULL;
+
+ if (dvert || (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY)) {
+
+ smooth_weights = MEM_mallocN(numVerts * sizeof(float), __func__);
+
+ if (dvert) {
+ dm_get_weights(
+ dvert, defgrp_index,
+ numVerts, (csmd->flag & MOD_CORRECTIVESMOOTH_INVERT_VGROUP) != 0,
+ smooth_weights);
+ }
+ else {
+ copy_vn_fl(smooth_weights, (int)numVerts, 1.0f);
+ }
+
+ if (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY) {
+ dm_get_boundaries(dm, smooth_weights);
+ }
+ }
+
+ smooth_iter(csmd, dm, vertexCos, numVerts, smooth_weights, (unsigned int)csmd->repeat);
+
+ if (smooth_weights) {
+ MEM_freeN(smooth_weights);
+ }
+}
+
+/**
+ * finalize after accumulation.
+ */
+static void calc_tangent_ortho(float ts[3][3])
+{
+ float v_tan_a[3], v_tan_b[3];
+ float t_vec_a[3], t_vec_b[3];
+
+ normalize_v3(ts[2]);
+
+ copy_v3_v3(v_tan_a, ts[0]);
+ copy_v3_v3(v_tan_b, ts[1]);
+
+ cross_v3_v3v3(ts[1], ts[2], v_tan_a);
+ mul_v3_fl(ts[1], dot_v3v3(ts[1], v_tan_b) < 0.0f ? -1.0f : 1.0f);
+
+ /* orthognalise tangent */
+ mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], v_tan_a));
+ sub_v3_v3v3(ts[0], v_tan_a, t_vec_a);
+
+ /* orthognalise bitangent */
+ mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], ts[1]));
+ mul_v3_v3fl(t_vec_b, ts[0], dot_v3v3(ts[0], ts[1]) / dot_v3v3(v_tan_a, v_tan_a));
+ sub_v3_v3(ts[1], t_vec_a);
+ sub_v3_v3(ts[1], t_vec_b);
+
+ normalize_v3(ts[0]);
+ normalize_v3(ts[1]);
+}
+
+/**
+ * accumulate edge-vectors from all polys.
+ */
+static void calc_tangent_loop_accum(
+ const float v_dir_prev[3],
+ const float v_dir_next[3],
+ float r_tspace[3][3])
+{
+ add_v3_v3v3(r_tspace[1], v_dir_prev, v_dir_next);
+
+ if (compare_v3v3(v_dir_prev, v_dir_next, FLT_EPSILON * 10.0f) == false) {
+ const float weight = fabsf(acosf(dot_v3v3(v_dir_next, v_dir_prev)));
+ float nor[3];
+
+ cross_v3_v3v3(nor, v_dir_prev, v_dir_next);
+ normalize_v3(nor);
+
+ cross_v3_v3v3(r_tspace[0], r_tspace[1], nor);
+
+ mul_v3_fl(nor, weight);
+ /* accumulate weighted normals */
+ add_v3_v3(r_tspace[2], nor);
+ }
+}
+
+
+static void calc_tangent_spaces(
+ DerivedMesh *dm, float (*vertexCos)[3],
+ float (*r_tangent_spaces)[3][3])
+{
+ const unsigned int mpoly_num = (unsigned int)dm->getNumPolys(dm);
+#ifndef USE_TANGENT_CALC_INLINE
+ const unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
+#endif
+ const MPoly *mpoly = dm->getPolyArray(dm);
+ const MLoop *mloop = dm->getLoopArray(dm);
+ unsigned int i;
+
+ for (i = 0; i < mpoly_num; i++) {
+ const MPoly *mp = &mpoly[i];
+ const MLoop *l_next = &mloop[mp->loopstart];
+ const MLoop *l_term = l_next + mp->totloop;
+ const MLoop *l_prev = l_term - 2;
+ const MLoop *l_curr = l_term - 1;
+
+ /* loop directions */
+ float v_dir_prev[3], v_dir_next[3];
+
+ /* needed entering the loop */
+ sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]);
+ normalize_v3(v_dir_prev);
+
+ for (;
+ l_next != l_term;
+ l_prev = l_curr, l_curr = l_next, l_next++)
+ {
+ float (*ts)[3] = r_tangent_spaces[l_curr->v];
+
+ /* re-use the previous value */
+#if 0
+ sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]);
+ normalize_v3(v_dir_prev);
+#endif
+ sub_v3_v3v3(v_dir_next, vertexCos[l_curr->v], vertexCos[l_next->v]);
+ normalize_v3(v_dir_next);
+
+ calc_tangent_loop_accum(v_dir_prev, v_dir_next, ts);
+
+ copy_v3_v3(v_dir_prev, v_dir_next);
+ }
+ }
+
+ /* do inline */
+#ifndef USE_TANGENT_CALC_INLINE
+ for (i = 0; i < mvert_num; i++) {
+ float (*ts)[3] = r_tangent_spaces[i];
+ calc_tangent_ortho(ts);
+ }
+#endif
+}
+
+/**
+ * This calculates #CorrectiveSmoothModifierData.delta_cache
+ * It's not run on every update (during animation for example).
+ */
+static void calc_deltas(
+ CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ MDeformVert *dvert, const int defgrp_index,
+ const float (*rest_coords)[3], unsigned int numVerts)
+{
+ float (*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords);
+ float (*tangent_spaces)[3][3];
+ unsigned int i;
+
+ tangent_spaces = MEM_callocN((size_t)(numVerts) * sizeof(float[3][3]), __func__);
+
+ if (csmd->delta_cache_num != numVerts) {
+ MEM_SAFE_FREE(csmd->delta_cache);
+ }
+
+ /* allocate deltas if they have not yet been allocated, otheriwse we will just write over them */
+ if (!csmd->delta_cache) {
+ csmd->delta_cache_num = numVerts;
+ csmd->delta_cache = MEM_mallocN((size_t)numVerts * sizeof(float[3]), __func__);
+ }
+
+ smooth_verts(csmd, dm, dvert, defgrp_index, smooth_vertex_coords, numVerts);
+
+ calc_tangent_spaces(dm, smooth_vertex_coords, tangent_spaces);
+
+ for (i = 0; i < numVerts; i++) {
+ float imat[3][3], delta[3];
+
+#ifdef USE_TANGENT_CALC_INLINE
+ calc_tangent_ortho(tangent_spaces[i]);
+#endif
+
+ sub_v3_v3v3(delta, rest_coords[i], smooth_vertex_coords[i]);
+ if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[i]))) {
+ transpose_m3_m3(imat, tangent_spaces[i]);
+ }
+ mul_v3_m3v3(csmd->delta_cache[i], imat, delta);
+ }
+
+ MEM_freeN(tangent_spaces);
+ MEM_freeN(smooth_vertex_coords);
+}
+
+
+static void correctivesmooth_modifier_do(
+ ModifierData *md, Object *ob, DerivedMesh *dm,
+ float (*vertexCos)[3], unsigned int numVerts,
+ struct BMEditMesh *em)
+{
+ CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
+
+ const bool force_delta_cache_update =
+ /* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */
+ ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) &&
+ (((ID *)ob->data)->flag & LIB_ID_RECALC));
+
+ bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0;
+ MDeformVert *dvert = NULL;
+ int defgrp_index;
+
+ modifier_get_vgroup(ob, dm, csmd->defgrp_name, &dvert, &defgrp_index);
+
+ /* if rest bind_coords not are defined, set them (only run during bind) */
+ if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) &&
+ /* signal to recalculate, whoever sets MUST also free bind coords */
+ (csmd->bind_coords_num == (unsigned int)-1))
+ {
+ BLI_assert(csmd->bind_coords == NULL);
+ csmd->bind_coords = MEM_dupallocN(vertexCos);
+ csmd->bind_coords_num = numVerts;
+ BLI_assert(csmd->bind_coords != NULL);
+ }
+
+ if (UNLIKELY(use_only_smooth)) {
+ smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts);
+ return;
+ }
+
+ if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && (csmd->bind_coords == NULL)) {
+ modifier_setError(md, "Bind data required");
+ goto error;
+ }
+
+ /* If the number of verts has changed, the bind is invalid, so we do nothing */
+ if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
+ if (csmd->bind_coords_num != numVerts) {
+ modifier_setError(md, "Bind vertex count mismatch: %u to %u", csmd->bind_coords_num, numVerts);
+ goto error;
+ }
+ }
+ else {
+ /* MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO */
+ if (ob->type != OB_MESH) {
+ modifier_setError(md, "Object is not a mesh");
+ goto error;
+ }
+ else {
+ unsigned int me_numVerts = (unsigned int)((em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert);
+
+ if (me_numVerts != numVerts) {
+ modifier_setError(md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts);
+ goto error;
+ }
+ }
+ }
+
+ /* check to see if our deltas are still valid */
+ if (!csmd->delta_cache || (csmd->delta_cache_num != numVerts) || force_delta_cache_update) {
+ const float (*rest_coords)[3];
+ bool is_rest_coords_alloc = false;
+
+ if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
+ /* caller needs to do sanity check here */
+ csmd->bind_coords_num = numVerts;
+ rest_coords = (const float (*)[3])csmd->bind_coords;
+ }
+ else {
+ int me_numVerts;
+ rest_coords = (const float (*)[3]) ((em) ?
+ BKE_editmesh_vertexCos_get_orco(em, &me_numVerts) :
+ BKE_mesh_vertexCos_get(ob->data, &me_numVerts));
+
+ BLI_assert((unsigned int)me_numVerts == numVerts);
+ is_rest_coords_alloc = true;
+ }
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(corrective_smooth_deltas);
+#endif
+
+ calc_deltas(csmd, dm, dvert, defgrp_index, rest_coords, numVerts);
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(corrective_smooth_deltas);
+#endif
+ if (is_rest_coords_alloc) {
+ MEM_freeN((void *)rest_coords);
+ }
+ }
+
+ if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
+ /* this could be a check, but at this point it _must_ be valid */
+ BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache);
+ }
+
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(corrective_smooth);
+#endif
+
+ /* do the actual delta mush */
+ smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts);
+
+ {
+ unsigned int i;
+
+ float (*tangent_spaces)[3][3];
+
+ /* calloc, since values are accumulated */
+ tangent_spaces = MEM_callocN((size_t)numVerts * sizeof(float[3][3]), __func__);
+
+ calc_tangent_spaces(dm, vertexCos, tangent_spaces);
+
+ for (i = 0; i < numVerts; i++) {
+ float delta[3];
+
+#ifdef USE_TANGENT_CALC_INLINE
+ calc_tangent_ortho(tangent_spaces[i]);
+#endif
+
+ mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache[i]);
+ add_v3_v3(vertexCos[i], delta);
+ }
+
+ MEM_freeN(tangent_spaces);
+ }
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(corrective_smooth);
+#endif
+
+ return;
+
+ /* when the modifier fails to execute */
+error:
+ MEM_SAFE_FREE(csmd->delta_cache);
+ csmd->delta_cache_num = 0;
+
+}
+
+
+static void deformVerts(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ float (*vertexCos)[3], int numVerts, ModifierApplyFlag UNUSED(flag))
+{
+ DerivedMesh *dm = get_dm(ob, NULL, derivedData, NULL, false, false);
+
+ correctivesmooth_modifier_do(md, ob, dm, vertexCos, (unsigned int)numVerts, NULL);
+
+ if (dm != derivedData) {
+ dm->release(dm);
+ }
+}
+
+
+static void deformVertsEM(
+ ModifierData *md, Object *ob, struct BMEditMesh *editData,
+ DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+{
+ DerivedMesh *dm = get_dm(ob, editData, derivedData, NULL, false, false);
+
+ correctivesmooth_modifier_do(md, ob, dm, vertexCos, (unsigned int)numVerts, editData);
+
+ if (dm != derivedData) {
+ dm->release(dm);
+ }
+}
+
+
+ModifierTypeInfo modifierType_CorrectiveSmooth = {
+ /* name */ "CorrectiveSmooth",
+ /* structName */ "CorrectiveSmoothModifierData",
+ /* structSize */ sizeof(CorrectiveSmoothModifierData),
+ /* type */ eModifierTypeType_OnlyDeform,
+ /* flags */ eModifierTypeFlag_AcceptsMesh |
+ eModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+ /* deformVerts */ deformVerts,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ deformVertsEM,
+ /* deformMatricesEM */ NULL,
+ /* applyModifier */ NULL,
+ /* applyModifierEM */ NULL,
+ /* initData */ initData,
+ /* requiredDataMask */ requiredDataMask,
+ /* freeData */ freeData,
+ /* isDisabled */ NULL,
+ /* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* dependsOnNormals */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index 9c3ccf033a5..1488296caf9 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -45,6 +45,7 @@
#include "BKE_modifier.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
@@ -92,6 +93,7 @@ static void foreachObjectLink(
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
Scene *UNUSED(scene),
Object *UNUSED(ob),
DagNode *obNode)
@@ -107,6 +109,25 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *scene,
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ CurveModifierData *cmd = (CurveModifierData *)md;
+ if (cmd->object != NULL) {
+ /* TODO(sergey): Need to do the same eval_flags trick for path
+ * as happening in legacy depsgraph callback.
+ */
+ /* TODO(sergey): Currently path is evaluated as a part of modifier stack,
+ * might be changed in the future.
+ */
+ DEG_add_object_relation(node, cmd->object, DEG_OB_COMP_GEOMETRY, "Curve Modifier");
+ DEG_add_special_eval_flag(scene->depsgraph, &cmd->object->id, DAG_EVAL_NEED_CURVE_PATH);
+ }
+}
+
static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
@@ -155,6 +176,7 @@ ModifierTypeInfo modifierType_Curve = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c
index acb58f6b767..e133c4785b7 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -131,7 +131,9 @@ static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *u
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
-static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
+static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
Object *UNUSED(ob), DagNode *obNode)
{
DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
@@ -145,6 +147,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UN
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
+ if (dtmd->ob_source != NULL) {
+ DEG_add_object_relation(node, dtmd->ob_source, DEG_OB_COMP_GEOMETRY, "DataTransfer Modifier");
+ }
+}
+
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
@@ -211,6 +225,15 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
#undef HIGH_POLY_WARNING
#undef DT_TYPES_AFFECT_MESH
+static void copyData(ModifierData *md, ModifierData *target)
+{
+#if 0
+ DataTransferModifierData *dtmd = (DecimateModifierData *) md;
+ DataTransferModifierData *tdtmd = (DecimateModifierData *) target;
+#endif
+ modifier_copyData_generic(md, target);
+}
+
ModifierTypeInfo modifierType_DataTransfer = {
/* name */ "DataTransfer",
/* structName */ "DataTransferModifierData",
@@ -221,7 +244,7 @@ ModifierTypeInfo modifierType_DataTransfer = {
eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_UsesPreview,
- /* copyData */ NULL,
+ /* copyData */ copyData,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
@@ -233,6 +256,7 @@ ModifierTypeInfo modifierType_DataTransfer = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index 8a92deec8eb..14468ab7c12 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -61,6 +61,7 @@ static void initData(ModifierData *md)
dmd->percent = 1.0;
dmd->angle = DEG2RADF(5.0f);
+ dmd->defgrp_factor = 1.0;
}
static void copyData(ModifierData *md, ModifierData *target)
@@ -78,7 +79,9 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
CustomDataMask dataMask = 0;
/* ask for vertexgroups if we need them */
- if (dmd->defgrp_name[0]) dataMask |= CD_MASK_MDEFORMVERT;
+ if (dmd->defgrp_name[0] && (dmd->defgrp_factor > 0.0f)) {
+ dataMask |= CD_MASK_MDEFORMVERT;
+ }
return dataMask;
}
@@ -130,7 +133,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
if (dmd->mode == MOD_DECIM_MODE_COLLAPSE) {
- if (dmd->defgrp_name[0]) {
+ if (dmd->defgrp_name[0] && (dmd->defgrp_factor > 0.0f)) {
MDeformVert *dvert;
int defgrp_index;
@@ -144,14 +147,12 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
if (dmd->flag & MOD_DECIM_FLAG_INVERT_VGROUP) {
for (i = 0; i < vert_tot; i++) {
- const float f = 1.0f - defvert_find_weight(&dvert[i], defgrp_index);
- vweights[i] = f > BM_MESH_DECIM_WEIGHT_EPS ? (1.0f / f) : BM_MESH_DECIM_WEIGHT_MAX;
+ vweights[i] = 1.0f - defvert_find_weight(&dvert[i], defgrp_index);
}
}
else {
for (i = 0; i < vert_tot; i++) {
- const float f = defvert_find_weight(&dvert[i], defgrp_index);
- vweights[i] = f > BM_MESH_DECIM_WEIGHT_EPS ? (1.0f / f) : BM_MESH_DECIM_WEIGHT_MAX;
+ vweights[i] = defvert_find_weight(&dvert[i], defgrp_index);
}
}
}
@@ -163,8 +164,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
switch (dmd->mode) {
case MOD_DECIM_MODE_COLLAPSE:
{
- const int do_triangulate = (dmd->flag & MOD_DECIM_FLAG_TRIANGULATE) != 0;
- BM_mesh_decimate_collapse(bm, dmd->percent, vweights, do_triangulate);
+ const bool do_triangulate = (dmd->flag & MOD_DECIM_FLAG_TRIANGULATE) != 0;
+ BM_mesh_decimate_collapse(bm, dmd->percent, vweights, dmd->defgrp_factor, do_triangulate);
break;
}
case MOD_DECIM_MODE_UNSUBDIV:
@@ -174,7 +175,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
case MOD_DECIM_MODE_DISSOLVE:
{
- const int do_dissolve_boundaries = (dmd->flag & MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS) != 0;
+ const bool do_dissolve_boundaries = (dmd->flag & MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS) != 0;
BM_mesh_decimate_dissolve(bm, dmd->angle, do_dissolve_boundaries, (BMO_Delimit)dmd->delimit);
break;
}
@@ -224,6 +225,7 @@ ModifierTypeInfo modifierType_Decimate = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index a23873fcd8a..2921472fe99 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -150,6 +150,7 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
DagNode *obNode)
@@ -170,6 +171,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ DisplaceModifierData *dmd = (DisplaceModifierData *)md;
+ if (dmd->map_object != NULL && dmd->texmapping == MOD_DISP_MAP_OBJECT) {
+ DEG_add_object_relation(node, dmd->map_object, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
+ }
+ if (dmd->texmapping == MOD_DISP_MAP_GLOBAL) {
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
+ }
+}
+
/* dm must be a CDDerivedMesh */
static void displaceModifier_do(
DisplaceModifierData *dmd, Object *ob,
@@ -301,6 +317,7 @@ ModifierTypeInfo modifierType_Displace = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c
index 5236365da70..95bc4706dc9 100644
--- a/source/blender/modifiers/intern/MOD_dynamicpaint.c
+++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c
@@ -38,6 +38,7 @@
#include "BKE_modifier.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
@@ -112,6 +113,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
struct Scene *scene,
Object *ob,
DagNode *obNode)
@@ -134,6 +136,26 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *scene,
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
+ /* Add relation from canvases to all brush objects. */
+ if (pmd->canvas != NULL) {
+ Base *base = scene->base.first;
+ for (; base; base = base->next) {
+ DynamicPaintModifierData *pmd2 =
+ (DynamicPaintModifierData *)modifiers_findByType(base->object, eModifierType_DynamicPaint);
+ if (pmd2 && pmd2->brush && ob != base->object) {
+ DEG_add_object_relation(node, base->object, DEG_OB_COMP_TRANSFORM, "Dynamic Paint Brush");
+ }
+ }
+ }
+}
+
static bool dependsOnTime(ModifierData *UNUSED(md))
{
return true;
@@ -186,6 +208,7 @@ ModifierTypeInfo modifierType_DynamicPaint = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index fa29921b325..4441edb299b 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -158,6 +158,7 @@ ModifierTypeInfo modifierType_EdgeSplit = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 32a6303d19d..82600421736 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -771,7 +771,7 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm)
for (i = 0; i < curdupface; i++) {
mf = CDDM_get_tessface(splitdm, i);
- test_index_face(mf, &splitdm->faceData, i, (mf->flag & ME_FACE_SEL ? 4 : 3));
+ test_index_face(mf, &splitdm->faceData, i, ((mf->flag & ME_FACE_SEL) ? 4 : 3));
}
BLI_edgehash_free(edgehash, NULL);
@@ -1058,6 +1058,7 @@ ModifierTypeInfo modifierType_Explode = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_fluidsim.c b/source/blender/modifiers/intern/MOD_fluidsim.c
index 9c973cd0d50..c202c5e1cb4 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim.c
@@ -44,6 +44,7 @@
#include "BKE_modifier.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
#include "MOD_fluidsim_util.h"
#include "MEM_guardedalloc.h"
@@ -71,6 +72,9 @@ static void copyData(ModifierData *md, ModifierData *target)
MEM_freeN(tfluidmd->fss);
tfluidmd->fss = MEM_dupallocN(fluidmd->fss);
+ if (tfluidmd->fss && (tfluidmd->fss->meshVelocities != NULL)) {
+ tfluidmd->fss->meshVelocities = MEM_dupallocN(tfluidmd->fss->meshVelocities);
+ }
}
@@ -97,7 +101,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
static void updateDepgraph(
- ModifierData *md, DagForest *forest, Scene *scene,
+ ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain), Scene *scene,
Object *ob, DagNode *obNode)
{
FluidsimModifierData *fluidmd = (FluidsimModifierData *) md;
@@ -122,6 +127,32 @@ static void updateDepgraph(
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *scene,
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ FluidsimModifierData *fluidmd = (FluidsimModifierData *) md;
+ if (fluidmd && fluidmd->fss) {
+ if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) {
+ Base *base;
+ for (base = scene->base.first; base; base = base->next) {
+ Object *ob1 = base->object;
+ if (ob1 != ob) {
+ FluidsimModifierData *fluidmdtmp =
+ (FluidsimModifierData *)modifiers_findByType(ob1, eModifierType_Fluidsim);
+
+ /* Only put dependencies from NON-DOMAIN fluids in here. */
+ if (fluidmdtmp && fluidmdtmp->fss && (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN)) {
+ DEG_add_object_relation(node, ob1, DEG_OB_COMP_TRANSFORM, "Fluidsim Object");
+ }
+ }
+ }
+ }
+ }
+}
+
static bool dependsOnTime(ModifierData *UNUSED(md))
{
return true;
@@ -150,6 +181,7 @@ ModifierTypeInfo modifierType_Fluidsim = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 2b512a6ba25..3a10fabbb8e 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -112,6 +112,7 @@ static void foreachObjectLink(
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
DagNode *obNode)
@@ -128,6 +129,25 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ HookModifierData *hmd = (HookModifierData *)md;
+ if (hmd->object != NULL) {
+ if (hmd->subtarget[0]) {
+ /* TODO(sergey): Hpw do we add relation to bone here? */
+ //DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_EVAL_POSE, "Hook Modifier");
+ DEG_add_bone_relation(node, hmd->object, hmd->subtarget, DEG_OB_COMP_BONE, "Hook Modifier");
+ }
+ else {
+ DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
+ }
+ }
+}
+
struct HookData_cb {
float (*vertexCos)[3];
@@ -402,6 +422,7 @@ ModifierTypeInfo modifierType_Hook = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index a4f6d005d94..c3cfafb7e27 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -862,6 +862,7 @@ ModifierTypeInfo modifierType_LaplacianDeform = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
index 93cd92196b2..a142d18a6d3 100644
--- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c
+++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
@@ -716,6 +716,7 @@ ModifierTypeInfo modifierType_LaplacianSmooth = {
/* freeData */ NULL,
/* isDisabled */ is_disabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c
index 86687865d02..b8975beaf83 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -92,6 +92,7 @@ static void foreachObjectLink(
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
DagNode *obNode)
@@ -106,6 +107,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ LatticeModifierData *lmd = (LatticeModifierData *)md;
+ if (lmd->object != NULL) {
+ DEG_add_object_relation(node, lmd->object, DEG_OB_COMP_GEOMETRY, "Lattice Modifier");
+ }
+}
+
static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
@@ -154,6 +167,7 @@ ModifierTypeInfo modifierType_Lattice = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index c1d4e41c19f..06fbab65d7b 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -50,6 +50,7 @@
#include "BKE_deform.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
#include "BLI_strict_flags.h"
@@ -77,6 +78,7 @@ static void foreachObjectLink(
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
DagNode *obNode)
@@ -93,6 +95,22 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ MaskModifierData *mmd = (MaskModifierData *)md;
+ if (mmd->ob_arm) {
+ bArmature *arm = (bArmature *)mmd->ob_arm->data;
+ /* Tag relationship in depsgraph, but also on the armature. */
+ /* TODO(sergey): Is it a proper relation here? */
+ DEG_add_object_relation(node, mmd->ob_arm, DEG_OB_COMP_TRANSFORM, "Mask Modifier");
+ arm->flag |= ARM_HAS_VIZ_DEPS;
+ }
+}
+
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DerivedMesh *dm,
ModifierApplyFlag UNUSED(flag))
@@ -384,6 +402,7 @@ ModifierTypeInfo modifierType_Mask = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c
index db50d49f790..92926ed9424 100644
--- a/source/blender/modifiers/intern/MOD_meshcache.c
+++ b/source/blender/modifiers/intern/MOD_meshcache.c
@@ -313,6 +313,7 @@ ModifierTypeInfo modifierType_MeshCache = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_meshcache_util.h b/source/blender/modifiers/intern/MOD_meshcache_util.h
index f3b5f43009d..241806f49e1 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_util.h
+++ b/source/blender/modifiers/intern/MOD_meshcache_util.h
@@ -27,8 +27,6 @@
#ifndef __MOD_MESHCACHE_UTIL_H__
#define __MOD_MESHCACHE_UTIL_H__
-struct MPoly;
-struct MLoop;
/* MOD_meshcache_mdd.c */
bool MOD_meshcache_read_mdd_index(FILE *fp,
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index 584b5b5fc76..22148d1f5ae 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -123,6 +123,7 @@ static void foreachObjectLink(
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
DagNode *obNode)
@@ -138,6 +139,19 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
+ if (mmd->object != NULL) {
+ /* TODO(sergey): Do we need transform component here? */
+ DEG_add_object_relation(node, mmd->object, DEG_OB_COMP_GEOMETRY, "Mesh Deform Modifier");
+ }
+}
+
static float meshdeform_dynamic_bind(MeshDeformModifierData *mmd, float (*dco)[3], float vec[3])
{
MDefCell *cell;
@@ -520,6 +534,7 @@ ModifierTypeInfo modifierType_MeshDeform = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 7a7308639f5..d3080ca235a 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -43,7 +43,9 @@
#include "BKE_deform.h"
#include "MEM_guardedalloc.h"
+
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
{
@@ -73,6 +75,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob,
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
DagNode *obNode)
@@ -87,13 +90,25 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ MirrorModifierData *mmd = (MirrorModifierData *)md;
+ if (mmd->mirror_ob != NULL) {
+ DEG_add_object_relation(node, mmd->mirror_ob, DEG_OB_COMP_TRANSFORM, "Mirror Modifier");
+ }
+}
+
static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
Object *ob,
DerivedMesh *dm,
int axis)
{
const float tolerance_sq = mmd->tolerance * mmd->tolerance;
- const int do_vtargetmap = !(mmd->flag & MOD_MIR_NO_MERGE);
+ const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0;
int tot_vtargetmap = 0; /* total merge vertices */
DerivedMesh *result;
@@ -360,6 +375,7 @@ ModifierTypeInfo modifierType_Mirror = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index 4754813a744..90ad1bdfdc2 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -162,6 +162,7 @@ ModifierTypeInfo modifierType_Multires = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_none.c b/source/blender/modifiers/intern/MOD_none.c
index 579f65a9c50..d9d9ba2966d 100644
--- a/source/blender/modifiers/intern/MOD_none.c
+++ b/source/blender/modifiers/intern/MOD_none.c
@@ -68,6 +68,7 @@ ModifierTypeInfo modifierType_None = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index db20823bf0c..87d75c6f1a7 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -60,7 +60,8 @@ static void generate_vert_coordinates(
/* Get size (i.e. deformation of the spheroid generating normals), either from target object, or own geometry. */
if (ob_center) {
- copy_v3_v3(r_size, ob_center->size);
+ /* Not we are not interested in signs here - they are even troublesome actually, due to security clamping! */
+ abs_v3_v3(r_size, ob_center->size);
}
else {
minmax_v3v3_v3_array(min_co, max_co, r_cos, num_verts);
@@ -79,13 +80,14 @@ static void generate_vert_coordinates(
}
if (ob_center) {
- /* Translate our coordinates so that center of ob_center is at (0, 0, 0). */
- float mat[4][4];
+ float inv_obmat[4][4];
- /* Get ob_center coordinates in ob local coordinates. */
- invert_m4_m4(mat, ob_center->obmat);
- mul_m4_m4m4(mat, mat, ob->obmat);
- copy_v3_v3(diff, mat[3]);
+ /* Translate our coordinates so that center of ob_center is at (0, 0, 0). */
+ /* Get ob_center (world) coordinates in ob local coordinates.
+ * No need to take into accound ob_center's space here, see T44027. */
+ invert_m4_m4(inv_obmat, ob->obmat);
+ mul_v3_m4v3(diff, inv_obmat, ob_center->obmat[3]);
+ negate_v3(diff);
do_diff = true;
}
@@ -465,7 +467,9 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
return !is_valid_target(smd);
}
-static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
+static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
Object *UNUSED(ob), DagNode *obNode)
{
NormalEditModifierData *smd = (NormalEditModifierData *) md;
@@ -477,6 +481,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UN
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ NormalEditModifierData *smd = (NormalEditModifierData *) md;
+ if (smd->target) {
+ DEG_add_object_relation(node, smd->target, DEG_OB_COMP_GEOMETRY, "NormalEdit Modifier");
+ }
+}
+
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag))
{
return normalEditModifier_do((NormalEditModifierData *)md, ob, dm);
@@ -504,6 +520,7 @@ ModifierTypeInfo modifierType_NormalEdit = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index 1c8dcdff46d..913c2f25c15 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -48,14 +48,14 @@ static void init_cache_data(Object *ob, struct OceanModifierData *omd)
{
const char *relbase = modifier_path_relbase(ob);
- omd->oceancache = BKE_init_ocean_cache(omd->cachepath, relbase,
+ omd->oceancache = BKE_ocean_init_cache(omd->cachepath, relbase,
omd->bakestart, omd->bakeend, omd->wave_scale,
omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution);
}
static void clear_cache_data(struct OceanModifierData *omd)
{
- BKE_free_ocean_cache(omd->oceancache);
+ BKE_ocean_free_cache(omd->oceancache);
omd->oceancache = NULL;
omd->cached = false;
}
@@ -72,8 +72,8 @@ static void init_ocean_modifier(struct OceanModifierData *omd)
do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS);
do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM);
- BKE_free_ocean_data(omd->ocean);
- BKE_init_ocean(omd->ocean, omd->resolution * omd->resolution, omd->resolution * omd->resolution,
+ BKE_ocean_free_data(omd->ocean);
+ BKE_ocean_init(omd->ocean, omd->resolution * omd->resolution, omd->resolution * omd->resolution,
omd->spatial_size, omd->spatial_size,
omd->wind_velocity, omd->smallest_wave, 1.0, omd->wave_direction, omd->damp, omd->wave_alignment,
omd->depth, omd->time,
@@ -85,7 +85,7 @@ static void simulate_ocean_modifier(struct OceanModifierData *omd)
{
if (!omd || !omd->ocean) return;
- BKE_simulate_ocean(omd->ocean, omd->time, omd->wave_scale, omd->chop_amount);
+ BKE_ocean_simulate(omd->ocean, omd->time, omd->wave_scale, omd->chop_amount);
}
#endif /* WITH_OCEANSIM */
@@ -133,7 +133,7 @@ static void initData(ModifierData *md)
omd->foam_fade = 0.98;
omd->foamlayername[0] = '\0'; /* layer name empty by default */
- omd->ocean = BKE_add_ocean();
+ omd->ocean = BKE_ocean_add();
init_ocean_modifier(omd);
simulate_ocean_modifier(omd);
#else /* WITH_OCEANSIM */
@@ -147,9 +147,9 @@ static void freeData(ModifierData *md)
#ifdef WITH_OCEANSIM
OceanModifierData *omd = (OceanModifierData *) md;
- BKE_free_ocean(omd->ocean);
+ BKE_ocean_free(omd->ocean);
if (omd->oceancache)
- BKE_free_ocean_cache(omd->oceancache);
+ BKE_ocean_free_cache(omd->oceancache);
#else /* WITH_OCEANSIM */
/* unused */
(void)md;
@@ -195,7 +195,7 @@ static void copyData(ModifierData *md, ModifierData *target)
tomd->bakeend = omd->bakeend;
tomd->oceancache = NULL;
- tomd->ocean = BKE_add_ocean();
+ tomd->ocean = BKE_ocean_add();
init_ocean_modifier(tomd);
simulate_ocean_modifier(tomd);
#else /* WITH_OCEANSIM */
@@ -426,7 +426,7 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob,
/* update modifier */
if (omd->refresh & MOD_OCEAN_REFRESH_ADD)
- omd->ocean = BKE_add_ocean();
+ omd->ocean = BKE_ocean_add();
if (omd->refresh & MOD_OCEAN_REFRESH_RESET)
init_ocean_modifier(omd);
if (omd->refresh & MOD_OCEAN_REFRESH_CLEAR_CACHE)
@@ -437,7 +437,7 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob,
/* do ocean simulation */
if (omd->cached == true) {
if (!omd->oceancache) init_cache_data(ob, omd);
- BKE_simulate_ocean_cache(omd->oceancache, md->scene->r.cfra);
+ BKE_ocean_simulate_cache(omd->oceancache, md->scene->r.cfra);
}
else {
simulate_ocean_modifier(omd);
@@ -580,6 +580,7 @@ ModifierTypeInfo modifierType_Ocean = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 853790e7eb9..218a74ec9fb 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -52,7 +52,7 @@
#include "BKE_pointcache.h"
#include "depsgraph_private.h"
-
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
{
@@ -117,6 +117,7 @@ static bool isDisabled(ModifierData *md, int useRenderParams)
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
DagNode *obNode)
@@ -132,6 +133,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
+ if (pimd->ob != NULL) {
+ DEG_add_object_relation(node, pimd->ob, DEG_OB_COMP_TRANSFORM, "Particle Instance Modifier");
+ }
+}
+
static void foreachObjectLink(ModifierData *md, Object *ob,
ObjectWalkFunc walk, void *userData)
{
@@ -399,6 +412,15 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
/* to quaternion */
mat3_to_quat(frame, mat);
+ if (pimd->rotation > 0.0f || pimd->random_rotation > 0.0f) {
+ float angle = 2.0f*M_PI * (pimd->rotation + pimd->random_rotation * (psys_frand(psys, 19957323 + p) - 0.5f));
+ float eul[3] = { 0.0f, 0.0f, angle };
+ float rot[4];
+
+ eul_to_quat(rot, eul);
+ mul_qt_qtqt(frame, frame, rot);
+ }
+
/* note: direction is same as normal vector currently,
* but best to keep this separate so the frame can be
* rotated later if necessary
@@ -506,6 +528,7 @@ ModifierTypeInfo modifierType_ParticleInstance = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index 9860daeda4c..de1b11eddd9 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -206,6 +206,7 @@ ModifierTypeInfo modifierType_ParticleSystem = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c
index 6d76dc51ac7..9df064db44d 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -232,6 +232,7 @@ ModifierTypeInfo modifierType_Remesh = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 5900baaf537..2e431884845 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -46,6 +46,8 @@
#include "BKE_cdderivedmesh.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
+
#include "MOD_modifiertypes.h"
#include "MEM_guardedalloc.h"
@@ -138,15 +140,15 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DerivedMesh *dm = derivedData;
DerivedMesh *result;
ScrewModifierData *ltmd = (ScrewModifierData *) md;
- const int useRenderParams = flag & MOD_APPLY_RENDER;
+ const bool use_render_params = (flag & MOD_APPLY_RENDER) != 0;
int *origindex;
int mpoly_index = 0;
unsigned int step;
unsigned int i, j;
unsigned int i1, i2;
- unsigned int step_tot = useRenderParams ? ltmd->render_steps : ltmd->steps;
- const bool do_flip = ltmd->flag & MOD_SCREW_NORMAL_FLIP ? 1 : 0;
+ unsigned int step_tot = use_render_params ? ltmd->render_steps : ltmd->steps;
+ const bool do_flip = (ltmd->flag & MOD_SCREW_NORMAL_FLIP) != 0;
const int quad_ord[4] = {
do_flip ? 3 : 0,
@@ -156,9 +158,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
};
const int quad_ord_ofs[4] = {
do_flip ? 2 : 0,
- do_flip ? 1 : 1,
+ 1,
do_flip ? 0 : 2,
- do_flip ? 3 : 3,
+ 3,
};
unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0;
@@ -1058,6 +1060,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
DagNode *obNode)
@@ -1073,6 +1076,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ ScrewModifierData *ltmd = (ScrewModifierData *)md;
+ if (ltmd->ob_axis != NULL) {
+ DEG_add_object_relation(node, ltmd->ob_axis, DEG_OB_COMP_TRANSFORM, "Screw Modifier");
+ }
+}
+
static void foreachObjectLink(
ModifierData *md, Object *ob,
void (*walk)(void *userData, Object *ob, Object **obpoin),
@@ -1106,6 +1121,7 @@ ModifierTypeInfo modifierType_Screw = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c
index f3327a03f2c..a543aac74b9 100644
--- a/source/blender/modifiers/intern/MOD_shapekey.c
+++ b/source/blender/modifiers/intern/MOD_shapekey.c
@@ -138,6 +138,7 @@ ModifierTypeInfo modifierType_ShapeKey = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index 302013b9b07..91be0c40059 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -143,6 +143,7 @@ static void deformVertsEM(ModifierData *md, Object *ob, struct BMEditMesh *editD
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
DagNode *obNode)
@@ -158,6 +159,23 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Shrinkwrap Modifier");
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md;
+ if (smd->target != NULL) {
+ DEG_add_object_relation(node, smd->target, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
+ DEG_add_object_relation(node, smd->target, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
+ }
+ if (smd->auxTarget != NULL) {
+ DEG_add_object_relation(node, smd->auxTarget, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
+ DEG_add_object_relation(node, smd->auxTarget, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
+ }
+}
+
static bool dependsOnNormals(ModifierData *md)
{
ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md;
@@ -190,6 +208,7 @@ ModifierTypeInfo modifierType_Shrinkwrap = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index 19761c43cf0..706a296f5a1 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -287,6 +287,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob,
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
DagNode *obNode)
@@ -297,6 +298,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
dag_add_relation(forest, dag_get_node(forest, smd->origin), obNode, DAG_RL_OB_DATA, "SimpleDeform Modifier");
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md;
+ if (smd->origin != NULL) {
+ DEG_add_object_relation(node, smd->origin, DEG_OB_COMP_TRANSFORM, "SimpleDeform Modifier");
+ }
+}
+
static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
@@ -361,6 +374,7 @@ ModifierTypeInfo modifierType_SimpleDeform = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index 4a99168f351..1b8b29666e2 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -104,6 +104,9 @@ typedef struct Frame {
/* Merge to target frame/corner (no merge if frame is null) */
struct Frame *frame;
int corner;
+ /* checked to avoid chaining.
+ * (merging when we're already been referenced), see T39775 */
+ unsigned int is_target : 1;
} merge[4];
/* For hull frames, whether each vertex is detached or not */
@@ -249,6 +252,7 @@ static bool build_hull(SkinOutput *so, Frame **frames, int totframe)
/* Apply face attributes to hull output */
BMO_ITER (f, &oiter, op.slots_out, "geom.out", BM_FACE) {
+ BM_face_normal_update(f);
if (so->smd->flag & MOD_SKIN_SMOOTH_SHADING)
BM_elem_flag_enable(f, BM_ELEM_SMOOTH);
f->mat_nr = so->mat_nr;
@@ -362,7 +366,7 @@ static void merge_frame_corners(Frame **frames, int totframe)
/* Compare with each corner of all other frames... */
for (l = 0; l < 4; l++) {
- if (frames[k]->merge[l].frame)
+ if (frames[k]->merge[l].frame || frames[k]->merge[l].is_target)
continue;
/* Some additional concerns that could be checked
@@ -392,6 +396,7 @@ static void merge_frame_corners(Frame **frames, int totframe)
frames[k]->merge[l].frame = frames[i];
frames[k]->merge[l].corner = j;
+ frames[i]->merge[j].is_target = true;
/* Can't merge another corner into the same
* frame corner, so move on to frame k+1 */
@@ -960,6 +965,7 @@ static void add_poly(SkinOutput *so,
BLI_assert(v1 && v2 && v3);
f = BM_face_create_verts(so->bm, verts, v4 ? 4 : 3, NULL, BM_CREATE_NO_DOUBLE, true);
+ BM_face_normal_update(f);
if (so->smd->flag & MOD_SKIN_SMOOTH_SHADING)
BM_elem_flag_enable(f, BM_ELEM_SMOOTH);
f->mat_nr = so->mat_nr;
@@ -996,13 +1002,13 @@ static void connect_frames(
float dot = 0.0f;
for (i = 0; i < 4; i++) {
- mid_v3_v3v3v3v3(cent_sides[i], UNPACK4_EX(,q[i],->co));
+ mid_v3_v3v3v3v3(cent_sides[i], UNPACK4_EX(, q[i], ->co));
}
mid_v3_v3v3v3v3(cent, UNPACK4(cent_sides));
for (i = 0; i < 4; i++) {
float p[3], no[3];
- normal_quad_v3(no, UNPACK4_EX(,q[i],->co));
+ normal_quad_v3(no, UNPACK4_EX(, q[i], ->co));
sub_v3_v3v3(p, cent, cent_sides[i]);
dot += dot_v3v3(no, p);
}
@@ -1421,6 +1427,9 @@ static void hull_merge_triangles(SkinOutput *so, const SkinModifierData *smd)
if (adj[0]->len == 3 && adj[1]->len == 3) {
BMVert *quad[4];
+ BLI_assert(BM_face_is_normal_valid(adj[0]));
+ BLI_assert(BM_face_is_normal_valid(adj[1]));
+
/* Construct quad using the two triangles adjacent to
* the edge */
quad_from_tris(e, adj, quad);
@@ -1783,6 +1792,9 @@ static BMesh *build_skin(SkinNode *skin_nodes,
skin_output_connections(&so, skin_nodes, medge, totedge);
hull_merge_triangles(&so, smd);
+ bmesh_edit_end(so.bm, 0);
+ BMO_pop(so.bm);
+
return so.bm;
}
@@ -1793,7 +1805,7 @@ static void skin_set_orig_indices(DerivedMesh *dm)
totpoly = dm->getNumPolys(dm);
orig = CustomData_add_layer(&dm->polyData, CD_ORIGINDEX,
CD_CALLOC, NULL, totpoly);
- fill_vn_i(orig, totpoly, ORIGINDEX_NONE);
+ copy_vn_i(orig, totpoly, ORIGINDEX_NONE);
}
/*
@@ -1844,7 +1856,6 @@ static DerivedMesh *base_skin(DerivedMesh *origdm,
result = CDDM_from_bmesh(bm, false);
BM_mesh_free(bm);
- CDDM_calc_edges(result);
result->dirty |= DM_DIRTY_NORMALS;
skin_set_orig_indices(result);
@@ -1930,6 +1941,7 @@ ModifierTypeInfo modifierType_Skin = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c
index f260c0491ee..657c4e09d96 100644
--- a/source/blender/modifiers/intern/MOD_smoke.c
+++ b/source/blender/modifiers/intern/MOD_smoke.c
@@ -47,10 +47,13 @@
#include "BKE_cdderivedmesh.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_smoke.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
{
@@ -114,7 +117,65 @@ static bool dependsOnTime(ModifierData *UNUSED(md))
return true;
}
+static void update_depsgraph_flow_coll_object(DagForest *forest,
+ DagNode *obNode,
+ Object *object2)
+{
+ SmokeModifierData *smd;
+ if ((object2->id.flag & LIB_DOIT) == 0) {
+ return;
+ }
+ object2->id.flag &= ~LIB_DOIT;
+ smd = (SmokeModifierData *)modifiers_findByType(object2, eModifierType_Smoke);
+ if (smd && (((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) ||
+ ((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll)))
+ {
+ DagNode *curNode = dag_get_node(forest, object2);
+ dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Smoke Flow/Coll");
+ }
+ if ((object2->transflag & OB_DUPLIGROUP) && object2->dup_group) {
+ GroupObject *go;
+ for (go = object2->dup_group->gobject.first;
+ go != NULL;
+ go = go->next)
+ {
+ if (go->ob == NULL) {
+ continue;
+ }
+ update_depsgraph_flow_coll_object(forest, obNode, go->ob);
+ }
+ }
+}
+
+static void update_depsgraph_field_source_object(DagForest *forest,
+ DagNode *obNode,
+ Object *object,
+ Object *object2)
+{
+ if ((object2->id.flag & LIB_DOIT) == 0) {
+ return;
+ }
+ object2->id.flag &= ~LIB_DOIT;
+ if (object2->pd && object2->pd->forcefield == PFIELD_SMOKEFLOW && object2->pd->f_source == object) {
+ DagNode *node2 = dag_get_node(forest, object2);
+ dag_add_relation(forest, obNode, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Field Source Object");
+ }
+ if ((object2->transflag & OB_DUPLIGROUP) && object2->dup_group) {
+ GroupObject *go;
+ for (go = object2->dup_group->gobject.first;
+ go != NULL;
+ go = go->next)
+ {
+ if (go->ob == NULL) {
+ continue;
+ }
+ update_depsgraph_field_source_object(forest, obNode, object, go->ob);
+ }
+ }
+}
+
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *bmain,
struct Scene *scene, struct Object *ob,
DagNode *obNode)
{
@@ -152,23 +213,122 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
else {
+ BKE_main_id_tag_listbase(&bmain->object, true);
base = scene->base.first;
for (; base; base = base->next) {
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(base->object, eModifierType_Smoke);
+ update_depsgraph_flow_coll_object(forest, obNode, base->object);
+ }
+ }
+ /* add relation to all "smoke flow" force fields */
+ base = scene->base.first;
+ BKE_main_id_tag_listbase(&bmain->object, true);
+ for (; base; base = base->next) {
+ update_depsgraph_field_source_object(forest, obNode, ob, base->object);
+ }
+ }
+}
+
+static void update_depsgraph_flow_coll_object_new(struct DepsNodeHandle *node,
+ Object *object2)
+{
+ SmokeModifierData *smd;
+ if ((object2->id.flag & LIB_DOIT) == 0) {
+ return;
+ }
+ object2->id.flag &= ~LIB_DOIT;
+ smd = (SmokeModifierData *)modifiers_findByType(object2, eModifierType_Smoke);
+ if (smd && (((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) ||
+ ((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll)))
+ {
+ DEG_add_object_relation(node, object2, DEG_OB_COMP_TRANSFORM, "Smoke Flow/Coll");
+ DEG_add_object_relation(node, object2, DEG_OB_COMP_GEOMETRY, "Smoke Flow/Coll");
+ }
+ if ((object2->transflag & OB_DUPLIGROUP) && object2->dup_group) {
+ GroupObject *go;
+ for (go = object2->dup_group->gobject.first;
+ go != NULL;
+ go = go->next)
+ {
+ if (go->ob == NULL) {
+ continue;
+ }
+ update_depsgraph_flow_coll_object_new(node, go->ob);
+ }
+ }
+}
- if (smd2 && (((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) || ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll))) {
- DagNode *curNode = dag_get_node(forest, base->object);
- dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Smoke Flow/Coll");
+static void update_depsgraph_field_source_object_new(struct DepsNodeHandle *node,
+ Object *object,
+ Object *object2)
+{
+ if ((object2->id.flag & LIB_DOIT) == 0) {
+ return;
+ }
+ object2->id.flag &= ~LIB_DOIT;
+ if (object2->pd && object2->pd->forcefield == PFIELD_SMOKEFLOW && object2->pd->f_source == object) {
+ DEG_add_object_relation(node, object2, DEG_OB_COMP_TRANSFORM, "Field Source Object");
+ DEG_add_object_relation(node, object2, DEG_OB_COMP_GEOMETRY, "Field Source Object");
+ }
+ if ((object2->transflag & OB_DUPLIGROUP) && object2->dup_group) {
+ GroupObject *go;
+ for (go = object2->dup_group->gobject.first;
+ go != NULL;
+ go = go->next)
+ {
+ if (go->ob == NULL) {
+ continue;
+ }
+ update_depsgraph_field_source_object_new(node, object, go->ob);
+ }
+ }
+}
+
+static void updateDepsgraph(ModifierData *md,
+ struct Main *bmain,
+ struct Scene *scene,
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ Base *base;
+ if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
+ if (smd->domain->fluid_group || smd->domain->coll_group) {
+ GroupObject *go = NULL;
+ if (smd->domain->fluid_group != NULL) {
+ for (go = smd->domain->fluid_group->gobject.first; go; go = go->next) {
+ if (go->ob != NULL) {
+ SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke);
+ /* Check for initialized smoke object. */
+ if (smd2 && (smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
+ DEG_add_object_relation(node, go->ob, DEG_OB_COMP_TRANSFORM, "Smoke Flow");
+ }
+ }
+ }
+ }
+ if (smd->domain->coll_group != NULL) {
+ for (go = smd->domain->coll_group->gobject.first; go; go = go->next) {
+ if (go->ob != NULL) {
+ SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke);
+ /* Check for initialized smoke object. */
+ if (smd2 && (smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) {
+ DEG_add_object_relation(node, go->ob, DEG_OB_COMP_TRANSFORM, "Smoke Coll");
+ }
+ }
}
}
}
+ else {
+ BKE_main_id_tag_listbase(&bmain->object, true);
+ base = scene->base.first;
+ for (; base; base = base->next) {
+ update_depsgraph_flow_coll_object_new(node, base->object);
+ }
+ }
/* add relation to all "smoke flow" force fields */
base = scene->base.first;
+ BKE_main_id_tag_listbase(&bmain->object, true);
for (; base; base = base->next) {
- if (base->object->pd && base->object->pd->forcefield == PFIELD_SMOKEFLOW && base->object->pd->f_source == ob) {
- DagNode *node2 = dag_get_node(forest, base->object);
- dag_add_relation(forest, obNode, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Field Source Object");
- }
+ update_depsgraph_field_source_object_new(node, ob, base->object);
}
}
}
@@ -214,6 +374,7 @@ ModifierTypeInfo modifierType_Smoke = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c
index d1ad8f1fcfc..d45c8528510 100644
--- a/source/blender/modifiers/intern/MOD_smooth.c
+++ b/source/blender/modifiers/intern/MOD_smooth.c
@@ -262,6 +262,7 @@ ModifierTypeInfo modifierType_Smooth = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c
index 5f5347a46b0..d958badc33c 100644
--- a/source/blender/modifiers/intern/MOD_softbody.c
+++ b/source/blender/modifiers/intern/MOD_softbody.c
@@ -80,6 +80,7 @@ ModifierTypeInfo modifierType_Softbody = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 08b8854c728..ca2dcfec3a3 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -255,7 +255,7 @@ static DerivedMesh *applyModifier(
/* weights */
MDeformVert *dvert;
- const int defgrp_invert = ((smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0);
+ const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0;
int defgrp_index;
/* array size is doubled in case of using a shell */
@@ -298,7 +298,7 @@ static DerivedMesh *applyModifier(
/* save doing 2 loops here... */
#if 0
- fill_vn_i(edge_users, numEdges, INVALID_UNUSED);
+ copy_vn_i(edge_users, numEdges, INVALID_UNUSED);
#endif
for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) {
@@ -505,7 +505,7 @@ static DerivedMesh *applyModifier(
unsigned int i;
vert_lens = MEM_mallocN(sizeof(float) * numVerts, "vert_lens");
- fill_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
+ copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
for (i = 0; i < numEdges; i++) {
const float ed_len_sq = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
vert_lens[medge[i].v1] = min_ff(vert_lens[medge[i].v1], ed_len_sq);
@@ -672,7 +672,7 @@ static DerivedMesh *applyModifier(
float *vert_lens_sq = MEM_mallocN(sizeof(float) * numVerts, "vert_lens");
const float offset = fabsf(smd->offset) * smd->offset_clamp;
const float offset_sq = offset * offset;
- fill_vn_fl(vert_lens_sq, (int)numVerts, FLT_MAX);
+ copy_vn_fl(vert_lens_sq, (int)numVerts, FLT_MAX);
for (i = 0; i < numEdges; i++) {
const float ed_len = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
vert_lens_sq[medge[i].v1] = min_ff(vert_lens_sq[medge[i].v1], ed_len);
@@ -961,6 +961,7 @@ ModifierTypeInfo modifierType_Solidify = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index f17858264f8..2a62a9e6081 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -88,7 +88,7 @@ static bool isDisabled(ModifierData *md, int useRenderParams)
SubsurfModifierData *smd = (SubsurfModifierData *) md;
int levels = (useRenderParams) ? smd->renderLevels : smd->levels;
- return get_render_subsurf_level(&md->scene->r, levels) == 0;
+ return get_render_subsurf_level(&md->scene->r, levels, useRenderParams != 0) == 0;
}
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
@@ -159,6 +159,7 @@ ModifierTypeInfo modifierType_Subsurf = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index 36a175950ed..31ff8dee562 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -187,6 +187,7 @@ ModifierTypeInfo modifierType_Surface = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 592ab4194ec..194a46b6f28 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -119,6 +119,7 @@ ModifierTypeInfo modifierType_Triangulate = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index c23c22b5fec..be6f7af7791 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -59,7 +59,7 @@
#include "BLI_threads.h"
#endif
-void modifier_init_texture(Scene *scene, Tex *tex)
+void modifier_init_texture(const Scene *scene, Tex *tex)
{
if (!tex)
return;
@@ -306,5 +306,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(Wireframe);
INIT_TYPE(DataTransfer);
INIT_TYPE(NormalEdit);
+ INIT_TYPE(CorrectiveSmooth);
#undef INIT_TYPE
}
diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h
index cb851a51c64..b74ff9c2a25 100644
--- a/source/blender/modifiers/intern/MOD_util.h
+++ b/source/blender/modifiers/intern/MOD_util.h
@@ -31,16 +31,16 @@
/* so modifier types match their defines */
#include "MOD_modifiertypes.h"
-struct CustomData;
+#include "DEG_depsgraph_build.h"
+
struct DerivedMesh;
struct MDeformVert;
struct ModifierData;
struct Object;
struct Scene;
struct Tex;
-struct TexResult;
-void modifier_init_texture(struct Scene *scene, struct Tex *texture);
+void modifier_init_texture(const struct Scene *scene, struct Tex *texture);
void get_texture_coords(struct MappingInfoModifierData *dmd, struct Object *ob, struct DerivedMesh *dm,
float (*co)[3], float (*texco)[3], int numVerts);
void modifier_vgroup_cache(struct ModifierData *md, float (*vertexCos)[3]);
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index 75a074a245a..1b1474ee666 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -51,7 +51,9 @@
#include "MOD_modifiertypes.h"
#include "MEM_guardedalloc.h"
+
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
{
@@ -104,6 +106,7 @@ static void foreachIDLink(ModifierData *md, Object *ob,
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
DagNode *obNode)
@@ -121,6 +124,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ UVProjectModifierData *umd = (UVProjectModifierData *)md;
+ int i;
+ for (i = 0; i < umd->num_projectors; ++i) {
+ if (umd->projectors[i] != NULL) {
+ DEG_add_object_relation(node, umd->projectors[i], DEG_OB_COMP_TRANSFORM, "UV Project Modifier");
+ }
+ }
+}
+
typedef struct Projector {
Object *ob; /* object this projector is derived from */
float projmat[4][4]; /* projection matrix */
@@ -138,7 +156,7 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
Image *image = umd->image;
MPoly *mpoly, *mp;
MLoop *mloop;
- int override_image = ((umd->flags & MOD_UVPROJECT_OVERRIDEIMAGE) != 0);
+ const bool override_image = (umd->flags & MOD_UVPROJECT_OVERRIDEIMAGE) != 0;
Projector projectors[MOD_UVPROJECT_MAXPROJECTORS];
int num_projectors = 0;
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
@@ -368,6 +386,7 @@ ModifierTypeInfo modifierType_UVProject = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c
index f5ff30e35d9..3c4ca66485d 100644
--- a/source/blender/modifiers/intern/MOD_uvwarp.c
+++ b/source/blender/modifiers/intern/MOD_uvwarp.c
@@ -218,6 +218,7 @@ static void uv_warp_deps_object_bone(DagForest *forest, DagNode *obNode,
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
Object *UNUSED(ob),
DagNode *obNode)
@@ -228,6 +229,30 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
uv_warp_deps_object_bone(forest, obNode, umd->object_dst, umd->bone_dst);
}
+static void uv_warp_deps_object_bone_new(struct DepsNodeHandle *node,
+ Object *object,
+ const char *bonename)
+{
+ if (object != NULL) {
+ if (bonename[0])
+ DEG_add_object_relation(node, object, DEG_OB_COMP_EVAL_POSE, "UVWarp Modifier");
+ else
+ DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, "UVWarp Modifier");
+ }
+}
+
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ UVWarpModifierData *umd = (UVWarpModifierData *) md;
+
+ uv_warp_deps_object_bone_new(node, umd->object_src, umd->bone_src);
+ uv_warp_deps_object_bone_new(node, umd->object_dst, umd->bone_dst);
+}
+
ModifierTypeInfo modifierType_UVWarp = {
/* name */ "UVWarp",
/* structName */ "UVWarpModifierData",
@@ -248,6 +273,7 @@ ModifierTypeInfo modifierType_UVWarp = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index 3eb34e56700..ae2dbd4a37c 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -136,7 +136,9 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
walk(userData, ob, md, "texture");
}
-static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
+static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
Object *UNUSED(ob), DagNode *obNode)
{
WarpModifierData *wmd = (WarpModifierData *) md;
@@ -155,6 +157,22 @@ static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UN
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ WarpModifierData *wmd = (WarpModifierData *) md;
+ if (wmd->object_from != NULL && wmd->object_to != NULL) {
+ DEG_add_object_relation(node, wmd->object_from, DEG_OB_COMP_TRANSFORM, "Warp Modifier from");
+ DEG_add_object_relation(node, wmd->object_to, DEG_OB_COMP_TRANSFORM, "Warp Modifier to");
+ }
+ if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object != NULL) {
+ DEG_add_object_relation(node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Warp Modifier map");
+ }
+}
+
static void warpModifier_do(WarpModifierData *wmd, Object *ob,
DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
{
@@ -370,6 +388,7 @@ ModifierTypeInfo modifierType_Warp = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index 47e4c502a90..5b98f221489 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -131,6 +131,7 @@ static void foreachTexLink(ModifierData *md, Object *ob,
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
Scene *UNUSED(scene),
Object *UNUSED(ob),
DagNode *obNode)
@@ -152,6 +153,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ WaveModifierData *wmd = (WaveModifierData *)md;
+ if (wmd->objectcenter != NULL) {
+ DEG_add_object_relation(node, wmd->objectcenter, DEG_OB_COMP_TRANSFORM, "Wave Modifier");
+ }
+ if (wmd->map_object != NULL) {
+ DEG_add_object_relation(node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Wave Modifier");
+ }
+}
+
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
WaveModifierData *wmd = (WaveModifierData *)md;
@@ -380,6 +396,7 @@ ModifierTypeInfo modifierType_Wave = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index 5a6e958457e..cba077a2f8d 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -46,6 +46,8 @@
#include "BKE_texture.h" /* Texture masking. */
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
+
#include "MEM_guardedalloc.h"
#include "MOD_weightvg_util.h"
@@ -142,7 +144,9 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
walk(userData, ob, md, "mask_texture");
}
-static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
+static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
Object *UNUSED(ob), DagNode *obNode)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
@@ -160,6 +164,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UN
"WeightVGEdit Modifier");
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
+ if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
+ DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGEdit Modifier");
+ }
+ if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "WeightVGEdit Modifier");
+ }
+}
+
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
@@ -290,6 +309,7 @@ ModifierTypeInfo modifierType_WeightVGEdit = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index 099d4c7116e..3d60c4a8b8b 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -43,6 +43,8 @@
#include "BKE_texture.h" /* Texture masking. */
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
+
#include "MEM_guardedalloc.h"
#include "MOD_weightvg_util.h"
@@ -191,7 +193,9 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
walk(userData, ob, md, "mask_texture");
}
-static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
+static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
Object *UNUSED(ob), DagNode *obNode)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
@@ -209,6 +213,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UN
"WeightVGMix Modifier");
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
+ if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
+ DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
+ }
+ if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
+ }
+}
+
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
@@ -232,7 +251,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
int i;
/* Flags. */
#if 0
- int do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview);
+ const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0;
#endif
/* Get number of verts. */
@@ -420,6 +439,7 @@ ModifierTypeInfo modifierType_WeightVGMix = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index 766ffe529ab..033516016d3 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -46,6 +46,8 @@
#include "BKE_texture.h" /* Texture masking. */
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
+
#include "MEM_guardedalloc.h"
#include "MOD_weightvg_util.h"
@@ -312,7 +314,9 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
walk(userData, ob, md, "mask_texture");
}
-static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
+static void updateDepgraph(ModifierData *md, DagForest *forest,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
Object *UNUSED(ob), DagNode *obNode)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
@@ -336,6 +340,24 @@ static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UN
"WeightVGProximity Modifier");
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md;
+ if (wmd->proximity_ob_target != NULL) {
+ DEG_add_object_relation(node, wmd->proximity_ob_target, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ }
+ if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
+ DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ }
+ if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ }
+}
+
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
@@ -364,7 +386,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
int i;
/* Flags. */
#if 0
- int do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview);
+ const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0;
#endif
#ifdef USE_TIMEIT
@@ -564,6 +586,7 @@ ModifierTypeInfo modifierType_WeightVGProximity = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index aa5e6116516..fe21757d5c2 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -133,6 +133,7 @@ ModifierTypeInfo modifierType_Wireframe = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 9eb6c1674a3..3fd1241f3fa 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -122,6 +122,7 @@ set(SRC
composite/nodes/node_composite_boxmask.c
composite/nodes/node_composite_ellipsemask.c
composite/nodes/node_composite_switch.c
+ composite/nodes/node_composite_switchview.c
composite/nodes/node_composite_colorcorrection.c
composite/nodes/node_composite_pixelate.c
@@ -199,6 +200,7 @@ set(SRC
shader/nodes/node_shader_tex_magic.c
shader/nodes/node_shader_tex_musgrave.c
shader/nodes/node_shader_tex_noise.c
+ shader/nodes/node_shader_tex_pointdensity.c
shader/nodes/node_shader_tex_sky.c
shader/nodes/node_shader_tex_voronoi.c
shader/nodes/node_shader_tex_wave.c
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index 961fdbfc0fb..0215db1dd55 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -133,6 +133,7 @@ void register_node_type_cmp_ellipsemask(void);
void register_node_type_cmp_bokehimage(void);
void register_node_type_cmp_bokehblur(void);
void register_node_type_cmp_switch(void);
+void register_node_type_cmp_switch_view(void);
void register_node_type_cmp_pixelate(void);
void register_node_type_cmp_trackpos(void);
void register_node_type_cmp_planetrackdeform(void);
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 595a3b12bc6..4c0047f1d58 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -75,6 +75,7 @@ void register_node_type_sh_sepxyz(void);
void register_node_type_sh_combxyz(void);
void register_node_type_sh_hue_sat(void);
void register_node_type_sh_tex_brick(void);
+void register_node_type_sh_tex_pointdensity(void);
void register_node_type_sh_attribute(void);
void register_node_type_sh_geometry(void);
diff --git a/source/blender/nodes/NOD_socket.h b/source/blender/nodes/NOD_socket.h
index 81230456193..5c8875593e7 100644
--- a/source/blender/nodes/NOD_socket.h
+++ b/source/blender/nodes/NOD_socket.h
@@ -43,7 +43,6 @@
struct bNodeTree;
struct bNode;
-struct bNodeStack;
struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocketTemplate *stemp, int in_out);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 166fa29fca0..9e1a0c926fa 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -71,7 +71,7 @@ DefNode( ShaderNode, SH_NODE_OUTPUT_LAMP, def_sh_output, "OU
DefNode( ShaderNode, SH_NODE_OUTPUT_WORLD, def_sh_output, "OUTPUT_WORLD", OutputWorld, "World Output", "" )
DefNode( ShaderNode, SH_NODE_OUTPUT_LINESTYLE, def_sh_output_linestyle,"OUTPUT_LINESTYLE", OutputLineStyle, "Line Style Output", "" )
DefNode( ShaderNode, SH_NODE_FRESNEL, 0, "FRESNEL", Fresnel, "Fresnel", "" )
-DefNode( ShaderNode, SH_NODE_LAYER_WEIGHT, 0, "LAYER_WEIGHT", LayerWeight, "Layer Weight", "" )
+DefNode( ShaderNode, SH_NODE_LAYER_WEIGHT, 0, "LAYER_WEIGHT", LayerWeight, "Layer Weight", "" )
DefNode( ShaderNode, SH_NODE_MIX_SHADER, 0, "MIX_SHADER", MixShader, "Mix Shader", "" )
DefNode( ShaderNode, SH_NODE_ADD_SHADER, 0, "ADD_SHADER", AddShader, "Add Shader", "" )
DefNode( ShaderNode, SH_NODE_ATTRIBUTE, def_sh_attribute, "ATTRIBUTE", Attribute, "Attribute", "" )
@@ -116,6 +116,7 @@ DefNode( ShaderNode, SH_NODE_TEX_MUSGRAVE, def_sh_tex_musgrave, "TE
DefNode( ShaderNode, SH_NODE_TEX_VORONOI, def_sh_tex_voronoi, "TEX_VORONOI", TexVoronoi, "Voronoi Texture", "" )
DefNode( ShaderNode, SH_NODE_TEX_CHECKER, def_sh_tex_checker, "TEX_CHECKER", TexChecker, "Checker Texture", "" )
DefNode( ShaderNode, SH_NODE_TEX_BRICK, def_sh_tex_brick, "TEX_BRICK", TexBrick, "Brick Texture", "" )
+DefNode( ShaderNode, SH_NODE_TEX_POINTDENSITY, def_sh_tex_pointdensity,"TEX_POINTDENSITY", TexPointDensity, "Point Density", "" )
DefNode( ShaderNode, SH_NODE_TEX_COORD, def_sh_tex_coord, "TEX_COORD", TexCoord, "Texture Coordinate","" )
DefNode( ShaderNode, SH_NODE_VECT_TRANSFORM, def_sh_vect_transform, "VECT_TRANSFORM", VectorTransform, "Vector Transform", "" )
DefNode( ShaderNode, SH_NODE_SEPHSV, 0, "SEPHSV", SeparateHSV, "Separate HSV", "" )
@@ -202,13 +203,14 @@ DefNode( CompositorNode, CMP_NODE_MASK_ELLIPSE, def_cmp_ellipsemask, "ELLIP
DefNode( CompositorNode, CMP_NODE_BOKEHIMAGE, def_cmp_bokehimage, "BOKEHIMAGE", BokehImage, "Bokeh Image", "" )
DefNode( CompositorNode, CMP_NODE_BOKEHBLUR, def_cmp_bokehblur, "BOKEHBLUR", BokehBlur, "Bokeh Blur", "" )
DefNode( CompositorNode, CMP_NODE_SWITCH, def_cmp_switch, "SWITCH", Switch, "Switch", "" )
+DefNode( CompositorNode, CMP_NODE_SWITCH_VIEW, def_cmp_switch_view, "VIEWSWITCH", SwitchView, "View Switch", "" )
DefNode( CompositorNode, CMP_NODE_COLORCORRECTION,def_cmp_colorcorrection,"COLORCORRECTION",ColorCorrection, "Color Correction", "" )
DefNode( CompositorNode, CMP_NODE_MASK, def_cmp_mask, "MASK", Mask, "Mask", "" )
DefNode( CompositorNode, CMP_NODE_KEYINGSCREEN, def_cmp_keyingscreen, "KEYINGSCREEN", KeyingScreen, "Keying Screen", "" )
DefNode( CompositorNode, CMP_NODE_KEYING, def_cmp_keying, "KEYING", Keying, "Keying", "" )
DefNode( CompositorNode, CMP_NODE_TRACKPOS, def_cmp_trackpos, "TRACKPOS", TrackPos, "Track Position", "" )
DefNode( CompositorNode, CMP_NODE_PIXELATE, 0, "PIXELATE", Pixelate, "Pixelate", "" )
-DefNode( CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLANETRACKDEFORM",PlaneTrackDeform,"Plane Track Deform","" )
+DefNode( CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLANETRACKDEFORM",PlaneTrackDeform,"Plane Track Deform","" )
DefNode( CompositorNode, CMP_NODE_CORNERPIN, 0, "CORNERPIN", CornerPin, "Corner Pin", "" )
DefNode( CompositorNode, CMP_NODE_SUNBEAMS, def_cmp_sunbeams, "SUNBEAMS", SunBeams, "Sun Beams", "" )
diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c
index e616680647e..8bc61862458 100644
--- a/source/blender/nodes/composite/node_composite_tree.c
+++ b/source/blender/nodes/composite/node_composite_tree.c
@@ -226,12 +226,13 @@ void *COM_linker_hack = NULL;
void ntreeCompositExecTree(Scene *scene, bNodeTree *ntree, RenderData *rd, int rendering, int do_preview,
const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings)
+ const ColorManagedDisplaySettings *display_settings,
+ const char *view_name)
{
#ifdef WITH_COMPOSITOR
- COM_execute(rd, scene, ntree, rendering, view_settings, display_settings);
+ COM_execute(rd, scene, ntree, rendering, view_settings, display_settings, view_name);
#else
- UNUSED_VARS(scene, ntree, rd, rendering, view_settings, display_settings);
+ UNUSED_VARS(scene, ntree, rd, rendering, view_settings, display_settings, view_name);
#endif
UNUSED_VARS(do_preview);
diff --git a/source/blender/nodes/composite/node_composite_util.c b/source/blender/nodes/composite/node_composite_util.c
index 8e279cf6d68..bbfb07a316d 100644
--- a/source/blender/nodes/composite/node_composite_util.c
+++ b/source/blender/nodes/composite/node_composite_util.c
@@ -43,7 +43,7 @@ void cmp_node_update_default(bNodeTree *UNUSED(ntree), bNode *node)
for (sock = node->outputs.first; sock; sock = sock->next) {
if (sock->cache) {
//free_compbuf(sock->cache);
- //sock->cache= NULL;
+ //sock->cache = NULL;
}
}
node->need_exec = 1;
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c
index 34f3350c2ff..19e93447608 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.c
+++ b/source/blender/nodes/composite/nodes/node_composite_image.c
@@ -168,14 +168,21 @@ static void cmp_node_image_add_multilayer_outputs(bNodeTree *ntree, bNode *node,
NodeImageLayer *sockdata;
RenderPass *rpass;
int index;
+ int passflag = 0;
for (rpass = rl->passes.first, index = 0; rpass; rpass = rpass->next, ++index) {
int type;
if (rpass->channels == 1)
type = SOCK_FLOAT;
else
type = SOCK_RGBA;
-
- sock = nodeAddStaticSocket(ntree, node, SOCK_OUT, type, PROP_NONE, rpass->name, rpass->name);
+
+ /* we only need one socket per type */
+ if (passflag & rpass->passtype)
+ continue;
+
+ passflag |= rpass->passtype;
+
+ sock = nodeAddStaticSocket(ntree, node, SOCK_OUT, type, PROP_NONE, rpass->internal_name, rpass->internal_name);
/* extra socket info */
sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
sock->storage = sockdata;
@@ -183,7 +190,7 @@ static void cmp_node_image_add_multilayer_outputs(bNodeTree *ntree, bNode *node,
sockdata->pass_index = index;
sockdata->pass_flag = rpass->passtype;
- if (STREQ(rpass->chan_id, "RGBA")) {
+ if (rpass->passtype == SCE_PASS_COMBINED) {
sock = nodeAddStaticSocket(ntree, node, SOCK_OUT, SOCK_FLOAT, PROP_NONE, "Alpha", "Alpha");
sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
sock->storage = sockdata;
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapValue.c b/source/blender/nodes/composite/nodes/node_composite_mapValue.c
index 22d16e93879..35096d57a4e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapValue.c
+++ b/source/blender/nodes/composite/nodes/node_composite_mapValue.c
@@ -44,7 +44,7 @@ static bNodeSocketTemplate cmp_node_map_value_out[] = {
static void node_composit_init_map_value(bNodeTree *UNUSED(ntree), bNode *node)
{
- node->storage = add_tex_mapping(TEXMAP_TYPE_POINT);
+ node->storage = BKE_texture_mapping_add(TEXMAP_TYPE_POINT);
}
void register_node_type_cmp_map_value(void)
diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.c b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
index 8e602c6179c..7d1087435c2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_outputFile.c
+++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
@@ -127,7 +127,7 @@ bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, bNode *node, con
BKE_imformat_defaults(&sockdata->format);
/* use node data format by default */
sockdata->use_node_format = true;
-
+
nimf->active_input = BLI_findindex(&node->inputs, sock);
return sock;
@@ -189,7 +189,7 @@ static void init_output_file(const bContext *C, PointerRNA *ptr)
}
else
BKE_imformat_defaults(&nimf->format);
-
+
/* add one socket by default */
ntreeCompositOutputFileAddSocket(ntree, node, "Image", format);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_switchview.c b/source/blender/nodes/composite/nodes/node_composite_switchview.c
new file mode 100644
index 00000000000..d805cf4d87f
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_switchview.c
@@ -0,0 +1,153 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s):
+ * Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_switchview.c
+ * \ingroup cmpnodes
+ */
+
+#include "BKE_context.h"
+#include "../node_composite_util.h"
+
+/* **************** SWITCH VIEW ******************** */
+static bNodeSocketTemplate cmp_node_switch_view_out[] = {
+ { SOCK_RGBA, 0, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocket *ntreeCompositSwitchViewAddSocket(bNodeTree *ntree, bNode *node, const char *name)
+{
+ bNodeSocket *sock = nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, NULL, name);
+ return sock;
+}
+
+static void cmp_node_switch_view_sanitycheck(bNodeTree *ntree, bNode *node)
+{
+ bNodeSocket *sock;
+
+ if (!BLI_listbase_is_empty(&node->inputs))
+ return;
+
+ sock = ntreeCompositSwitchViewAddSocket(ntree, node, "No View");
+ sock->flag |= SOCK_HIDDEN;
+}
+
+static void cmp_node_switch_view_update(bNodeTree *ntree, bNode *node)
+{
+ bNodeSocket *sock;
+ SceneRenderView *srv;
+ Scene *scene = (Scene *)node->id;
+
+ /* only update when called from the operator button */
+ if (node->update != NODE_UPDATE_OPERATOR)
+ return;
+
+ if (scene == NULL) {
+ nodeRemoveAllSockets(ntree, node);
+ /* make sure there is always one socket */
+ cmp_node_switch_view_sanitycheck(ntree, node);
+ return;
+ }
+
+ /* remove the views that were removed */
+ sock = node->inputs.last;
+ while (sock) {
+ srv = BLI_findstring(&scene->r.views, sock->name, offsetof(SceneRenderView, name));
+
+ if (srv == NULL) {
+ bNodeSocket *sock_del = sock;
+ sock = sock->prev;
+ nodeRemoveSocket(ntree, node, sock_del);
+ }
+ else {
+ if (srv->viewflag & SCE_VIEW_DISABLE)
+ sock->flag |= SOCK_HIDDEN;
+ else
+ sock->flag &= ~SOCK_HIDDEN;
+
+ sock = sock->prev;
+ }
+ }
+
+ /* add the new views */
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ sock = BLI_findstring(&node->inputs, srv->name, offsetof(bNodeSocket, name));
+
+ if (sock == NULL)
+ sock = ntreeCompositSwitchViewAddSocket(ntree, node, srv->name);
+
+ if (srv->viewflag & SCE_VIEW_DISABLE)
+ sock->flag |= SOCK_HIDDEN;
+ else
+ sock->flag &= ~SOCK_HIDDEN;
+ }
+
+ /* make sure there is always one socket */
+ cmp_node_switch_view_sanitycheck(ntree, node);
+}
+
+static void init_switch_view(const bContext *C, PointerRNA *ptr)
+{
+ Scene *scene = CTX_data_scene(C);
+ bNodeTree *ntree = ptr->id.data;
+ bNode *node = ptr->data;
+ SceneRenderView *srv;
+ bNodeSocket *sock;
+ int nr;
+
+ /* store scene for updates */
+ node->id = (ID *)scene;
+
+ if (scene) {
+ RenderData *rd = &scene->r;
+
+ for (nr = 0, srv = rd->views.first; srv; srv = srv->next, nr++) {
+ sock = ntreeCompositSwitchViewAddSocket(ntree, node, srv->name);
+
+ if ((srv->viewflag & SCE_VIEW_DISABLE))
+ sock->flag |= SOCK_HIDDEN;
+ }
+ }
+
+ /* make sure there is always one socket */
+ cmp_node_switch_view_sanitycheck(ntree, node);
+}
+
+/* custom1 = mix type */
+void register_node_type_cmp_switch_view(void)
+{
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_SWITCH_VIEW, "Switch View", NODE_CLASS_CONVERTOR, 0);
+ node_type_socket_templates(&ntype, NULL, cmp_node_switch_view_out);
+
+ ntype.initfunc_api = init_switch_view;
+
+ node_type_update(&ntype, cmp_node_switch_view_update, NULL);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c
index 0e250dc3aa4..c397af97783 100644
--- a/source/blender/nodes/intern/node_common.c
+++ b/source/blender/nodes/intern/node_common.c
@@ -50,6 +50,10 @@
#include "node_util.h"
#include "NOD_common.h"
+enum {
+ REFINE_FORWARD = 1 << 0,
+ REFINE_BACKWARD = 1 << 1,
+};
/**** Group ****/
@@ -251,7 +255,7 @@ void register_node_type_reroute(void)
nodeRegisterType(ntype);
}
-static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node)
+static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, int flag)
{
bNodeSocket *input = node->inputs.first;
bNodeSocket *output = node->outputs.first;
@@ -275,11 +279,14 @@ static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node)
if (nodeLinkIsHidden(link))
continue;
- if (tonode == node && fromnode->type == NODE_REROUTE && !fromnode->done)
- node_reroute_inherit_type_recursive(ntree, fromnode);
-
- if (fromnode == node && tonode->type == NODE_REROUTE && !tonode->done)
- node_reroute_inherit_type_recursive(ntree, tonode);
+ if (flag & REFINE_FORWARD) {
+ if (tonode == node && fromnode->type == NODE_REROUTE && !fromnode->done)
+ node_reroute_inherit_type_recursive(ntree, fromnode, REFINE_FORWARD);
+ }
+ if (flag & REFINE_BACKWARD) {
+ if (fromnode == node && tonode->type == NODE_REROUTE && !tonode->done)
+ node_reroute_inherit_type_recursive(ntree, tonode, REFINE_BACKWARD);
+ }
}
/* determine socket type from unambiguous input/output connection if possible */
@@ -329,7 +336,7 @@ void ntree_update_reroute_nodes(bNodeTree *ntree)
for (node = ntree->nodes.first; node; node = node->next)
if (node->type == NODE_REROUTE && !node->done)
- node_reroute_inherit_type_recursive(ntree, node);
+ node_reroute_inherit_type_recursive(ntree, node, REFINE_FORWARD | REFINE_BACKWARD);
}
static bool node_is_connected_to_output_recursive(bNodeTree *ntree, bNode *node)
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index f18ee1d649f..cd2c6f68726 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -69,7 +69,8 @@ static int shader_tree_poll(const bContext *C, bNodeTreeType *UNUSED(treetype))
return (scene->r.engine[0] == '\0' ||
STREQ(scene->r.engine, RE_engine_id_BLENDER_RENDER) ||
STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME) ||
- STREQ(scene->r.engine, RE_engine_id_CYCLES));
+ STREQ(scene->r.engine, RE_engine_id_CYCLES) ||
+ !BKE_scene_use_shading_nodes_custom(scene));
}
static void shader_get_from_context(const bContext *C, bNodeTreeType *UNUSED(treetype), bNodeTree **r_ntree, ID **r_id, ID **r_from)
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
index b9c94fc3aee..8dda7b0859b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
@@ -51,8 +51,8 @@ static void node_shader_init_anisotropic(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_bsdf_anisotropic(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[3].link)
- in[3].link = GPU_builtin(GPU_VIEW_NORMAL);
+ if (!in[4].link)
+ in[4].link = GPU_builtin(GPU_VIEW_NORMAL);
return GPU_stack_link(mat, "node_bsdf_anisotropic", in, out);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.c
index de152ee45d1..3146454f26d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bump.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bump.c
@@ -47,7 +47,10 @@ static bNodeSocketTemplate sh_node_bump_out[] = {
static int gpu_shader_bump(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "node_bump", in, out, GPU_builtin(GPU_VIEW_NORMAL));
+ if (!in[3].link)
+ in[3].link = GPU_builtin(GPU_VIEW_NORMAL);
+
+ return GPU_stack_link(mat, "node_bump", in, out);
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c
index cff4a039602..2af6e19565b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mapping.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mapping.c
@@ -71,7 +71,7 @@ static void node_shader_exec_mapping(void *UNUSED(data), int UNUSED(thread), bNo
static void node_shader_init_mapping(bNodeTree *UNUSED(ntree), bNode *node)
{
- node->storage = add_tex_mapping(TEXMAP_TYPE_POINT);
+ node->storage = BKE_texture_mapping_add(TEXMAP_TYPE_POINT);
}
static int gpu_shader_mapping(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.c b/source/blender/nodes/shader/nodes/node_shader_object_info.c
index a862c621248..d1905246fd4 100644
--- a/source/blender/nodes/shader/nodes/node_shader_object_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_object_info.c
@@ -30,10 +30,10 @@
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_object_info_out[] = {
- { SOCK_VECTOR, 0, N_("Location"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 0, N_("Object Index"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 0, N_("Material Index"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 0, N_("Random"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 0, N_("Location"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_("Object Index"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_("Material Index"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_("Random"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ -1, 0, "" }
};
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
index f75f6a654d1..569eaf5ff9b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
@@ -51,8 +51,8 @@ static bNodeSocketTemplate sh_node_tex_brick_out[] = {
static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexBrick *tex = MEM_callocN(sizeof(NodeTexBrick), "NodeTexBrick");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->offset = 0.5f;
tex->squash = 1.0f;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
index 30e51c7cb7d..b7498df1706 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
@@ -46,8 +46,8 @@ static bNodeSocketTemplate sh_node_tex_checker_out[] = {
static void node_shader_init_tex_checker(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexChecker *tex = MEM_callocN(sizeof(NodeTexChecker), "NodeTexChecker");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
node->storage = tex;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
index 8d6a77455bb..2b43667a009 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -42,8 +42,8 @@ static bNodeSocketTemplate sh_node_tex_environment_out[] = {
static void node_shader_init_tex_environment(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexEnvironment *tex = MEM_callocN(sizeof(NodeTexEnvironment), "NodeTexEnvironment");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->color_space = SHD_COLORSPACE_COLOR;
tex->projection = SHD_PROJ_EQUIRECTANGULAR;
tex->iuser.frames = 1;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
index e11591ab5ce..24916e8f013 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
@@ -43,8 +43,8 @@ static bNodeSocketTemplate sh_node_tex_gradient_out[] = {
static void node_shader_init_tex_gradient(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexGradient *tex = MEM_callocN(sizeof(NodeTexGradient), "NodeTexGradient");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->gradient_type = SHD_BLEND_LINEAR;
node->storage = tex;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
index 62db5b70891..f87e792399b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -43,8 +43,8 @@ static bNodeSocketTemplate sh_node_tex_image_out[] = {
static void node_shader_init_tex_image(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexImage *tex = MEM_callocN(sizeof(NodeTexImage), "NodeTexImage");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->color_space = SHD_COLORSPACE_COLOR;
tex->iuser.frames = 1;
tex->iuser.sfra = 1;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
index de2daeb8ee1..80904e376bc 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
@@ -45,8 +45,8 @@ static bNodeSocketTemplate sh_node_tex_magic_out[] = {
static void node_shader_init_tex_magic(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexMagic *tex = MEM_callocN(sizeof(NodeTexMagic), "NodeTexMagic");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->depth = 2;
node->storage = tex;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
index 75566773ea2..825ba7eb3c1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
@@ -49,8 +49,8 @@ static bNodeSocketTemplate sh_node_tex_musgrave_out[] = {
static void node_shader_init_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexMusgrave *tex = MEM_callocN(sizeof(NodeTexMusgrave), "NodeTexMusgrave");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->musgrave_type = SHD_MUSGRAVE_FBM;
node->storage = tex;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
index 601a31dff00..d806140694e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
@@ -46,8 +46,8 @@ static bNodeSocketTemplate sh_node_tex_noise_out[] = {
static void node_shader_init_tex_noise(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexNoise *tex = MEM_callocN(sizeof(NodeTexNoise), "NodeTexNoise");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
node->storage = tex;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c
new file mode 100644
index 00000000000..3cdbfacb95c
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c
@@ -0,0 +1,75 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** OUTPUT ******************** */
+
+static bNodeSocketTemplate sh_node_tex_pointdensity_in[] = {
+ {SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ {-1, 0, ""}
+};
+
+static bNodeSocketTemplate sh_node_tex_pointdensity_out[] = {
+ {SOCK_FLOAT, 0, N_("Density"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {SOCK_RGBA, 0, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ {-1, 0, ""}
+};
+
+static void node_shader_init_tex_pointdensity(bNodeTree *UNUSED(ntree),
+ bNode *node)
+{
+ NodeShaderTexPointDensity *point_density =
+ MEM_callocN(sizeof(NodeShaderTexPointDensity), "new pd node");
+ point_density->resolution = 100;
+ point_density->radius = 0.3f;
+ point_density->space = SHD_POINTDENSITY_SPACE_OBJECT;
+ node->storage = point_density;
+}
+
+/* node type definition */
+void register_node_type_sh_tex_pointdensity(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype,
+ SH_NODE_TEX_POINTDENSITY,
+ "Point Density",
+ NODE_CLASS_TEXTURE,
+ 0);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_socket_templates(&ntype,
+ sh_node_tex_pointdensity_in,
+ sh_node_tex_pointdensity_out);
+ node_type_init(&ntype, node_shader_init_tex_pointdensity);
+ node_type_storage(&ntype,
+ "NodeShaderTexPointDensity",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c
index 51cca0df851..495c78ca929 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c
@@ -42,8 +42,8 @@ static bNodeSocketTemplate sh_node_tex_sky_out[] = {
static void node_shader_init_tex_sky(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexSky *tex = MEM_callocN(sizeof(NodeTexSky), "NodeTexSky");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->sun_direction[0] = 0.0f;
tex->sun_direction[1] = 0.0f;
tex->sun_direction[2] = 1.0f;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
index 5eba5f3f59d..88596a4a72f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
@@ -44,8 +44,8 @@ static bNodeSocketTemplate sh_node_tex_voronoi_out[] = {
static void node_shader_init_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexVoronoi *tex = MEM_callocN(sizeof(NodeTexVoronoi), "NodeTexVoronoi");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->coloring = SHD_VORONOI_INTENSITY;
node->storage = tex;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
index ef79aac0d32..100510641e8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
@@ -47,8 +47,8 @@ static bNodeSocketTemplate sh_node_tex_wave_out[] = {
static void node_shader_init_tex_wave(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexWave *tex = MEM_callocN(sizeof(NodeTexWave), "NodeTexWave");
- default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
- default_color_mapping(&tex->base.color_mapping);
+ BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
+ BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->wave_type = SHD_WAVE_BANDS;
node->storage = tex;
diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
index fa5d9b43ee7..72942cce9c5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
@@ -31,6 +31,7 @@
#include "node_shader_util.h"
+#include "IMB_colormanagement.h"
/* **************** VALTORGB ******************** */
static bNodeSocketTemplate sh_node_valtorgb_in[] = {
@@ -106,7 +107,7 @@ static void node_shader_exec_rgbtobw(void *UNUSED(data), int UNUSED(thread), bNo
float col[3];
nodestack_get_vec(col, SOCK_VECTOR, in[0]);
- out[0]->vec[0] = rgb_to_bw(col);
+ out[0]->vec[0] = IMB_colormanagement_get_luminance(col);
}
static int gpu_shader_rgbtobw(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c
index 79923c5f7d5..d716c2565c7 100644
--- a/source/blender/nodes/texture/node_texture_tree.c
+++ b/source/blender/nodes/texture/node_texture_tree.c
@@ -336,7 +336,7 @@ int ntreeTexExecTree(
data.osatex = osatex;
data.target = texres;
data.do_preview = preview;
- data.do_manage = (shi) ? shi->do_manage : 0;
+ data.do_manage = (shi) ? shi->do_manage : true;
data.thread = thread;
data.which_output = which_output;
data.cfra = cfra;
diff --git a/source/blender/nodes/texture/nodes/node_texture_proc.c b/source/blender/nodes/texture/nodes/node_texture_proc.c
index b49ec1fd503..0be5f875a23 100644
--- a/source/blender/nodes/texture/nodes/node_texture_proc.c
+++ b/source/blender/nodes/texture/nodes/node_texture_proc.c
@@ -286,7 +286,7 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node)
Tex *tex = MEM_callocN(sizeof(Tex), "Tex");
node->storage = tex;
- default_tex(tex);
+ BKE_texture_default(tex);
tex->type = node->type - TEX_NODE_PROC;
if (tex->type == TEX_WOOD)
diff --git a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
index 7f8adab2da5..a49d82d27a9 100644
--- a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
+++ b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
@@ -32,6 +32,7 @@
#include "node_texture_util.h"
#include "NOD_texture.h"
+#include "IMB_colormanagement.h"
/* **************** VALTORGB ******************** */
static bNodeSocketTemplate valtorgb_in[] = {
@@ -91,7 +92,7 @@ static void rgbtobw_valuefn(float *out, TexParams *p, bNode *UNUSED(node), bNode
{
float cin[4];
tex_input_rgba(cin, in[0], p, thread);
- *out = rgb_to_bw(cin);
+ *out = IMB_colormanagement_get_luminance(cin);
}
static void rgbtobw_exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
diff --git a/source/blender/physics/BPH_mass_spring.h b/source/blender/physics/BPH_mass_spring.h
index f2bd34e226d..db355c18f2e 100644
--- a/source/blender/physics/BPH_mass_spring.h
+++ b/source/blender/physics/BPH_mass_spring.h
@@ -25,6 +25,10 @@
* ***** END GPL LICENSE BLOCK *****
*/
+/** \file blender/physics/BPH_mass_spring.h
+ * \ingroup bph
+ */
+
#ifndef __BPH_MASS_SPRING_H__
#define __BPH_MASS_SPRING_H__
@@ -36,7 +40,10 @@ struct Implicit_Data;
struct Object;
struct ClothModifierData;
struct ListBase;
+struct Strands;
+struct HairSimParams;
struct VoxelData;
+struct CacheEffector;
typedef enum eMassSpringSolverStatus {
BPH_SOLVER_SUCCESS = (1 << 0),
@@ -56,6 +63,10 @@ void BPH_cloth_solver_set_positions(struct ClothModifierData *clmd);
bool BPH_cloth_solver_get_texture_data(struct Object *ob, struct ClothModifierData *clmd, struct VoxelData *vd);
+struct Implicit_Data *BPH_strands_solver_create(struct Strands *strands, struct HairSimParams *params);
+bool BPH_strands_solve(struct Strands *strands, float mat[4][4], struct Implicit_Data *id, struct HairSimParams *params, float frame, float frame_prev, struct Scene *scene,
+ struct ListBase *effectors, struct CacheEffector *cache_effectors, int tot_cache_effectors);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/physics/BPH_strands.h b/source/blender/physics/BPH_strands.h
new file mode 100644
index 00000000000..068c47f1c4c
--- /dev/null
+++ b/source/blender/physics/BPH_strands.h
@@ -0,0 +1,44 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BPH_STRANDS_H__
+#define __BPH_STRANDS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Object;
+struct BMEditStrands;
+
+void BPH_strands_solve_constraints(struct Object *ob, struct BMEditStrands *es, float (*orig)[3]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/blender/physics/CMakeLists.txt b/source/blender/physics/CMakeLists.txt
index 08ff1faca49..12080567585 100644
--- a/source/blender/physics/CMakeLists.txt
+++ b/source/blender/physics/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
intern
../blenlib
../blenkernel
+ ../bmesh
../imbuf
../makesdna
../../../intern/guardedalloc
@@ -46,8 +47,10 @@ set(SRC
intern/implicit_blender.c
intern/implicit_eigen.cpp
intern/eigen_utils.h
+ intern/strands.cpp
BPH_mass_spring.h
+ BPH_strands.h
)
blender_add_lib(bf_physics "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/physics/SConscript b/source/blender/physics/SConscript
index c8165886cab..4156cecd1a3 100644
--- a/source/blender/physics/SConscript
+++ b/source/blender/physics/SConscript
@@ -35,6 +35,7 @@ incs = [
'intern',
'../blenlib',
'../blenkernel',
+ '../bmesh',
'../imbuf',
'../makesdna',
'../../../intern/guardedalloc',
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index faf8ac9e2d6..b0c0f4fa4df 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -32,6 +32,7 @@
extern "C" {
#include "MEM_guardedalloc.h"
+#include "DNA_cache_library_types.h"
#include "DNA_cloth_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_force.h"
@@ -43,9 +44,12 @@ extern "C" {
#include "BLI_linklist.h"
#include "BLI_utildefines.h"
+#include "BKE_cache_library.h"
#include "BKE_cloth.h"
#include "BKE_collision.h"
+#include "BKE_colortools.h"
#include "BKE_effect.h"
+#include "BKE_strands.h"
}
#include "BPH_mass_spring.h"
@@ -154,7 +158,7 @@ static bool collision_response(ClothModifierData *clmd, CollisionModifierData *c
float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
float epsilon2 = BLI_bvhtree_getepsilon(collmd->bvhtree);
- float margin_distance = collpair->distance - epsilon2;
+ float margin_distance = (float)collpair->distance - epsilon2;
float mag_v_rel;
zero_v3(r_impulse);
@@ -434,7 +438,7 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
cb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
/* XXX assuming same restlen for ij and jk segments here, this can be done correctly for hair later */
- BPH_mass_spring_force_spring_bending_angular(data, s->ij, s->kl, s->mn, s->target, kb, cb);
+ BPH_mass_spring_force_spring_bending_angular(data, s->ij, s->kl, s->mn, s->target, kb, cb, NULL, NULL, NULL);
#if 0
{
@@ -526,6 +530,7 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
/* Hair has only edges */
if (cloth->numfaces == 0) {
+ const float density = 0.01f; /* XXX arbitrary value, corresponds to effect of air density */
#if 0
ClothHairData *hairdata = clmd->hairdata;
ClothHairData *hair_ij, *hair_kl;
@@ -556,10 +561,10 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
for (i = 0; i < cloth->numverts; i++, vert++) {
if (hairdata) {
ClothHairData *hair = &hairdata[i];
- BPH_mass_spring_force_vertex_wind(data, i, hair->radius, winvec);
+ BPH_mass_spring_force_vertex_wind(data, i, hair->radius * density, winvec);
}
else
- BPH_mass_spring_force_vertex_wind(data, i, 1.0f, winvec);
+ BPH_mass_spring_force_vertex_wind(data, i, density, winvec);
}
#endif
}
@@ -848,7 +853,7 @@ static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, Lis
// call collision function
// TODO: check if "step" or "step+dt" is correct - dg
- do_extra_solve = cloth_bvh_objcollision(ob, clmd, step/clmd->sim_parms->timescale, dt/clmd->sim_parms->timescale);
+ do_extra_solve = cloth_bvh_objcollision(ob, clmd, step / clmd->sim_parms->timescale, dt / clmd->sim_parms->timescale);
// copy corrected positions back to simulation
for (i = 0; i < numverts; i++) {
@@ -1084,3 +1089,636 @@ bool BPH_cloth_solver_get_texture_data(Object *UNUSED(ob), ClothModifierData *cl
return true;
}
+
+/* ========================================================================= */
+
+struct Implicit_Data *BPH_strands_solver_create(struct Strands *strands, struct HairSimParams *params)
+{
+ static float I3[3][3] = { {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f} };
+
+ struct Implicit_Data *id;
+ int numverts = strands->totverts;
+ int numcurves = strands->totcurves;
+ int numgoalverts = numverts - numcurves; /* extra virtual vertices to act as goal spring targets */
+ int numedges = max_ii(numverts - numcurves, 0);
+ int numbends = max_ii(numverts - 2*numcurves, 0);
+
+ /* goal springs: 1 per vertex, except roots
+ * stretch springs: 1 per edge
+ * bending sprints: 3 per bend // XXX outdated, 1 is enough
+ */
+ int numsprings = numgoalverts + numedges + 3*numbends;
+ int i;
+
+ id = BPH_mass_spring_solver_create(numverts + numgoalverts, numsprings);
+
+ for (i = 0; i < numverts; i++) {
+ float mass = params->mass;
+ BPH_mass_spring_set_vertex_mass(id, i, mass);
+ }
+ for (i = numverts; i < numverts + numgoalverts; i++) {
+ BPH_mass_spring_set_vertex_mass(id, i, 1.0f);
+ }
+
+ for (i = 0; i < numverts; i++) {
+ BPH_mass_spring_set_rest_transform(id, i, I3);
+ }
+ for (i = numverts; i < numverts + numgoalverts; i++) {
+ BPH_mass_spring_set_rest_transform(id, i, I3);
+ }
+
+ return id;
+}
+
+/* Init constraint matrix
+ * This is part of the modified CG method suggested by Baraff/Witkin in
+ * "Large Steps in Cloth Simulation" (Siggraph 1998)
+ */
+static void strands_setup_constraints(Strands *strands, Implicit_Data *data, ColliderContacts *UNUSED(contacts), int UNUSED(totcolliders), float UNUSED(dt))
+{
+ static const float ZERO[3] = { 0.0f, 0.0f, 0.0f };
+
+ BPH_mass_spring_clear_constraints(data);
+
+ StrandIterator it_strand;
+ for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+ int index = BKE_strand_iter_vertex_offset(strands, &it_strand);
+
+ /* pin strand roots */
+ BPH_mass_spring_add_constraint_ndof0(data, index, ZERO); /* velocity is defined externally */
+
+// StrandVertexIterator it_vert;
+// for (BKE_strand_vertex_iter_init(&it_vert, &it_strand); BKE_strand_vertex_iter_valid(&it_vert); BKE_strand_vertex_iter_next(&it_vert)) {
+// }
+ }
+
+ /* pin virtual goal targets */
+ {
+ int goalstart = strands->totverts;
+ int goalend = goalstart + strands->totverts - strands->totcurves;
+ for (int i = goalstart; i < goalend; ++i) {
+ BPH_mass_spring_add_constraint_ndof0(data, i, ZERO); /* velocity is defined externally */
+ }
+ }
+
+#if 0
+ for (i = 0; i < totcolliders; ++i) {
+ ColliderContacts *ct = &contacts[i];
+ for (j = 0; j < ct->totcollisions; ++j) {
+ CollPair *collpair = &ct->collisions[j];
+// float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - ct->ob->pd->pdef_sbdamp);
+ float restitution = 0.0f;
+ int v = collpair->face1;
+ float impulse[3];
+
+ /* pinned verts handled separately */
+ if (verts[v].flags & CLOTH_VERT_FLAG_PINNED)
+ continue;
+
+ /* XXX cheap way of avoiding instability from multiple collisions in the same step
+ * this should eventually be supported ...
+ */
+ if (verts[v].impulse_count > 0)
+ continue;
+
+ /* calculate collision response */
+ if (!collision_response(clmd, ct->collmd, collpair, dt, restitution, impulse))
+ continue;
+
+ BPH_mass_spring_add_constraint_ndof2(data, v, collpair->normal, impulse);
+ ++verts[v].impulse_count;
+ }
+ }
+#endif
+}
+
+/* stretch forces are created between 2 vertices of each segment */
+static void strands_calc_curve_stretch_forces(Strands *strands, float UNUSED(space[4][4]), HairSimParams *params, Implicit_Data *data, StrandIterator *it_strand)
+{
+ StrandEdgeIterator it_edge;
+
+ for (BKE_strand_edge_iter_init(&it_edge, it_strand); BKE_strand_edge_iter_valid(&it_edge); BKE_strand_edge_iter_next(&it_edge)) {
+ int vi = BKE_strand_edge_iter_vertex0_offset(strands, &it_edge);
+ int vj = BKE_strand_edge_iter_vertex1_offset(strands, &it_edge);
+ float restlen = len_v3v3(it_edge.vertex0->co, it_edge.vertex1->co);
+
+ float stiffness = params->stretch_stiffness;
+ float damping = stiffness * params->stretch_damping;
+ float f[3];
+ BPH_mass_spring_force_spring_linear(data, vi, vj, restlen, stiffness, damping, true, 0.0f, f, NULL, NULL);
+ }
+}
+
+static float strands_bending_stiffness(Strands *UNUSED(strands), HairSimParams *params, StrandsVertex *UNUSED(vert), float t)
+{
+ float weight;
+
+ if (params->flag & eHairSimParams_Flag_UseBendStiffnessCurve)
+ weight = curvemapping_evaluateF(params->bend_stiffness_mapping, 0, t);
+ else
+ weight = 1.0f;
+ CLAMP(weight, 0.0f, 1.0f);
+
+ return params->bend_stiffness * weight;
+}
+
+/* bending forces aim to restore the rest shape of each strand locally */
+static void strands_calc_curve_bending_forces(Strands *strands, float space[4][4], HairSimParams *params, Implicit_Data *data, StrandIterator *it_strand)
+{
+ StrandBendIterator it_bend;
+
+ float length = 0.0f;
+ StrandEdgeIterator it_edge;
+ for (BKE_strand_edge_iter_init(&it_edge, it_strand); BKE_strand_edge_iter_valid(&it_edge); BKE_strand_edge_iter_next(&it_edge))
+ length += len_v3v3(it_edge.vertex1->co, it_edge.vertex0->co);
+ float length_inv = length > 0.0f ? 1.0f / length : 0.0f;
+
+ float t = 0.0f;
+ BKE_strand_bend_iter_init(&it_bend, it_strand);
+ if (!BKE_strand_bend_iter_valid(&it_bend))
+ return;
+
+ /* The 'mat' matrix (here: A) contains the relative transform between the local rest and motion state coordinate systems.
+ * In the beginning both systems are the root matrix R, so the relative transform is the unit matrix.
+ *
+ * A = M_state * M_rest^T
+ * = R * R^T
+ * = I
+ *
+ * With each bend the matrices are rotated along the curvature, described by matrix B^T. Since we are only
+ * interested in the combined transform however, the resulting operation becomes
+ *
+ * A' = M_state' * M_rest'
+ * = (B_state^T * M_state) * (B_rest^T * M_rest)^T
+ * = B_state^T * M_state * M_rest^T * B_rest
+ * = B_state^T * A * B_rest
+ *
+ * The target vector is originally the direction of the first segment. For each bend, the target vector
+ * is the _previous_ segment's direction, i.e. the target vector is rotated by B with a 1-step delay.
+ *
+ * The target vector in the current motion state system for each segment could thus be calculated by multiplying
+ *
+ * t_state = M * t_rest
+ *
+ * but using the edge vector directly is more practical.
+ *
+ */
+ float mat[3][3];
+// float Mrest[3][3], Mstate[3][3];
+
+ { /* initialize using the first edge deviation from the rest direction */
+ float edge_rest[3], edge_state[3], rot[3][3];
+ sub_v3_v3v3(edge_rest, it_strand->verts[1].co, it_strand->verts[0].co);
+ sub_v3_v3v3(edge_state, it_strand->state[1].co, it_strand->state[0].co);
+ normalize_v3(edge_rest);
+ normalize_v3(edge_state);
+ rotation_between_vecs_to_mat3(rot, edge_rest, edge_state);
+
+ copy_m3_m3(mat, rot);
+// copy_m3_m3(Mrest, it_strand->curve->root_matrix);
+// mul_m3_m3m3(Mstate, rot, Mrest);
+ }
+
+ { /* apply force */
+ /* Note: applying forces to the first segment is necessary to equalize forces on the root,
+ * otherwise energy gets introduced at the root and can destabilize the simulation.
+ */
+ float target[3];
+ sub_v3_v3v3(target, it_strand->verts[1].co, it_strand->verts[0].co);
+ mul_mat3_m4_v3(space, target); /* to solver space (world space) */
+
+ float target_state[3];
+ mul_v3_m3v3(target_state, mat, target);
+
+ const float stiffness = strands_bending_stiffness(strands, params, it_bend.vertex0, t * length_inv);
+ const float damping = stiffness * params->bend_damping;
+
+ int vroot = BKE_strand_bend_iter_vertex0_offset(strands, &it_bend); /* root velocity used as goal velocity */
+ int vj = BKE_strand_bend_iter_vertex1_offset(strands, &it_bend);
+ float goal[3], rootvel[3];
+ mul_v3_m4v3(goal, space, it_strand->verts[1].co);
+ BPH_mass_spring_get_velocity(data, vroot, rootvel);
+ BPH_mass_spring_force_spring_goal(data, vj, goal, rootvel, stiffness, damping, NULL, NULL, NULL);
+ }
+
+ do {
+ float restlen = len_v3v3(it_bend.vertex1->co, it_bend.vertex0->co);
+ t += restlen;
+
+ { /* advance the coordinate frame */
+ float rotrest[3][3], rotrest_inv[3][3], rotstate[3][3], rotstate_inv[3][3];
+ BKE_strand_bend_iter_transform_rest(&it_bend, rotrest);
+ BKE_strand_bend_iter_transform_state(&it_bend, rotstate);
+ transpose_m3_m3(rotrest_inv, rotrest);
+ transpose_m3_m3(rotstate_inv, rotstate);
+
+// mul_m3_m3m3(Mrest, rotrest_inv, Mrest);
+// mul_m3_m3m3(Mstate, rotstate_inv, Mstate);
+
+ mul_m3_m3m3(mat, mat, rotrest);
+ mul_m3_m3m3(mat, rotstate_inv, mat);
+ }
+
+ { /* apply force */
+ float target[3];
+ sub_v3_v3v3(target, it_bend.vertex1->co, it_bend.vertex0->co);
+ mul_mat3_m4_v3(space, target); /* to solver space (world space) */
+
+ float target_state[3];
+ mul_v3_m3v3(target_state, mat, target);
+
+ const float stiffness = strands_bending_stiffness(strands, params, it_bend.vertex1, t * length_inv);
+ const float damping = stiffness * params->bend_damping;
+
+ int vi = BKE_strand_bend_iter_vertex0_offset(strands, &it_bend);
+ int vj = BKE_strand_bend_iter_vertex1_offset(strands, &it_bend);
+ int vk = BKE_strand_bend_iter_vertex2_offset(strands, &it_bend);
+ float f[3];
+ BPH_mass_spring_force_spring_bending_angular(data, vi, vj, vk, target_state, stiffness, damping, f, NULL, NULL);
+
+#if 0 /* debug */
+ {
+ float mscale = 0.1f;
+
+ float x[3];
+ BPH_mass_spring_get_position(data, vj, x);
+ BKE_sim_debug_data_add_vector(x, target, 0,0,1, "hairsim", 2598, vi, vj, vk);
+ BKE_sim_debug_data_add_vector(x, target_state, 0.4,0.4,1, "hairsim", 2599, vi, vj, vk);
+
+ float mr[3][3];
+ copy_m3_m3(mr, Mrest);
+ mul_m3_fl(mr, mscale);
+ BKE_sim_debug_data_add_vector(x, mr[0], 0.7,0.0,0.0, "hairsim", 1957, vi, vj, vk);
+ BKE_sim_debug_data_add_vector(x, mr[1], 0.0,0.7,0.0, "hairsim", 1958, vi, vj, vk);
+ BKE_sim_debug_data_add_vector(x, mr[2], 0.0,0.0,0.7, "hairsim", 1959, vi, vj, vk);
+
+ float ms[3][3];
+ copy_m3_m3(ms, Mstate);
+ mul_m3_fl(ms, mscale);
+ BKE_sim_debug_data_add_vector(x, ms[0], 1.0,0.4,0.4, "hairsim", 1857, vi, vj, vk);
+ BKE_sim_debug_data_add_vector(x, ms[1], 0.4,1.0,0.4, "hairsim", 1858, vi, vj, vk);
+ BKE_sim_debug_data_add_vector(x, ms[2], 0.4,0.4,1.0, "hairsim", 1859, vi, vj, vk);
+ }
+#endif
+ }
+
+ BKE_strand_bend_iter_next(&it_bend);
+ } while (BKE_strand_bend_iter_valid(&it_bend));
+}
+
+static float strands_goal_stiffness(Strands *UNUSED(strands), HairSimParams *params, StrandsVertex *vert, float t)
+{
+ /* XXX There is no possibility of tweaking them in linked data currently,
+ * so the original workflow of painting weights in particle edit mode is virtually useless.
+ */
+ float weight;
+
+ if (params->flag & eHairSimParams_Flag_UseGoalStiffnessCurve)
+ weight = curvemapping_evaluateF(params->goal_stiffness_mapping, 0, t);
+ else
+ weight = vert->weight;
+ CLAMP(weight, 0.0f, 1.0f);
+
+ return params->goal_stiffness * weight;
+}
+
+static bool strands_deflector_filter(void *UNUSED(data), CacheEffector *eff)
+{
+ return eff->type == eCacheEffector_Type_Deflect;
+}
+
+static bool strands_test_deflector(StrandsVertex *UNUSED(vertex), int index, CacheEffector *cache_effectors, int tot_cache_effectors, Implicit_Data *data)
+{
+ CacheEffectorPoint point;
+ point.index = index;
+ BPH_mass_spring_get_motion_state(data, index, point.x, point.v);
+
+ CacheEffectorResult result;
+ if (BKE_cache_effectors_eval_ex(cache_effectors, tot_cache_effectors, &point, &result, strands_deflector_filter, NULL) > 0) {
+ return true;
+ }
+
+ return false;
+}
+
+/* goal forces pull vertices toward their rest position */
+static void strands_calc_vertex_goal_forces(Strands *strands, float UNUSED(space[4][4]), HairSimParams *params, CacheEffector *cache_effectors, int tot_cache_effectors,
+ Implicit_Data *data, StrandIterator *it_strand)
+{
+ const int goalstart = strands->totverts;
+ StrandEdgeIterator it_edge;
+
+ float length = 0.0f;
+ for (BKE_strand_edge_iter_init(&it_edge, it_strand); BKE_strand_edge_iter_valid(&it_edge); BKE_strand_edge_iter_next(&it_edge))
+ length += len_v3v3(it_edge.vertex1->co, it_edge.vertex0->co);
+ float length_inv = length > 0.0f ? 1.0f / length : 0.0f;
+
+ float t = 0.0f;
+ for (BKE_strand_edge_iter_init(&it_edge, it_strand); BKE_strand_edge_iter_valid(&it_edge); BKE_strand_edge_iter_next(&it_edge)) {
+ int vj = BKE_strand_edge_iter_vertex1_offset(strands, &it_edge);
+ int numroots = it_strand->index + 1; /* roots don't have goal verts, skip this many */
+ int goalj = goalstart + vj - numroots;
+
+ if (params->flag & eHairSimParams_Flag_UseGoalDeflect) {
+ if (strands_test_deflector(it_edge.vertex1, vj, cache_effectors, tot_cache_effectors, data))
+ continue;
+ }
+
+ float restlen = len_v3v3(it_edge.vertex1->co, it_edge.vertex0->co);
+ t += restlen;
+
+ float stiffness = strands_goal_stiffness(strands, params, it_edge.vertex1, t * length_inv);
+ float damping = stiffness * params->goal_damping;
+
+ float f[3];
+ BPH_mass_spring_force_spring_linear(data, vj, goalj, 0.0f, stiffness, damping, true, 0.0f, f, NULL, NULL);
+ }
+
+#if 0
+ StrandEdgeIterator it_edge;
+
+ float rootvel[3];
+ BPH_mass_spring_get_velocity(data, BKE_strand_iter_vertex_offset(strands, it_strand), rootvel);
+
+ float length = 0.0f;
+ for (BKE_strand_edge_iter_init(&it_edge, it_strand); BKE_strand_edge_iter_valid(&it_edge); BKE_strand_edge_iter_next(&it_edge))
+ length += len_v3v3(it_edge.vertex1->co, it_edge.vertex0->co);
+ float length_inv = length > 0.0f ? 1.0f / length : 0.0f;
+
+ float t = 0.0f;
+ for (BKE_strand_edge_iter_init(&it_edge, it_strand); BKE_strand_edge_iter_valid(&it_edge); BKE_strand_edge_iter_next(&it_edge)) {
+ int vj = BKE_strand_edge_iter_vertex1_offset(strands, &it_edge);
+ t += len_v3v3(it_edge.vertex1->co, it_edge.vertex0->co);
+
+ float stiffness = strands_goal_stiffness(strands, params, it_edge.vertex1, t * length_inv);
+ float damping = stiffness * params->goal_damping;
+
+ float goal[3];
+ mul_v3_m4v3(goal, space, it_edge.vertex1->co);
+
+ float f[3];
+ BPH_mass_spring_force_spring_goal(data, vj, goal, rootvel, stiffness, damping, f, NULL, NULL);
+ }
+#endif
+}
+
+/* calculates internal forces for a single strand curve */
+static void strands_calc_curve_forces(Strands *strands, float space[4][4], HairSimParams *params, CacheEffector *cache_effectors, int tot_cache_effectors,
+ Implicit_Data *data, StrandIterator *it_strand)
+{
+ strands_calc_curve_stretch_forces(strands, space, params, data, it_strand);
+ strands_calc_curve_bending_forces(strands, space, params, data, it_strand);
+ strands_calc_vertex_goal_forces(strands, space, params, cache_effectors, tot_cache_effectors, data, it_strand);
+}
+
+/* Collect forces and derivatives: F, dFdX, dFdV */
+static void strands_calc_force(Strands *strands, float space[4][4], HairSimParams *params, Implicit_Data *data, float UNUSED(frame), Scene *scene,
+ ListBase *effectors, CacheEffector *cache_effectors, int tot_cache_effectors)
+{
+ unsigned int numverts = strands->totverts;
+
+ int i = 0;
+ float gravity[3] = {0.0f, 0.0f, 0.0f};
+
+ /* global acceleration (gravitation) */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ /* scale gravity force */
+ mul_v3_v3fl(gravity, scene->physics_settings.gravity, params->effector_weights->global_gravity);
+ }
+ for (i = 0; i < numverts; i++) {
+ float mass = params->mass;
+ BPH_mass_spring_force_gravity(data, i, mass, gravity);
+ }
+
+ BPH_mass_spring_force_drag(data, params->drag);
+
+ /* handle external forces like wind */
+ if (effectors || (cache_effectors && tot_cache_effectors > 0)) {
+ /* cache per-vertex forces to avoid redundant calculation */
+ float (*ext_forces)[3] = (float (*)[3])MEM_callocN(sizeof(float) * 3 * numverts, "effector forces");
+
+ if (effectors) {
+ for (i = 0; i < numverts; ++i) {
+ float x[3], v[3];
+ EffectedPoint epoint;
+
+ BPH_mass_spring_get_motion_state(data, i, x, v);
+ pd_point_from_loc(scene, x, v, i, &epoint);
+ pdDoEffectors(effectors, NULL, params->effector_weights, &epoint, ext_forces[i], NULL);
+ }
+ }
+
+ if (cache_effectors && tot_cache_effectors > 0) {
+ for (i = 0; i < numverts; ++i) {
+ CacheEffectorPoint point;
+ point.index = i;
+ BPH_mass_spring_get_motion_state(data, i, point.x, point.v);
+
+ CacheEffectorResult result;
+ if (BKE_cache_effectors_eval(cache_effectors, tot_cache_effectors, &point, &result) > 0) {
+ add_v3_v3(ext_forces[i], result.f);
+ }
+ }
+ }
+
+ for (i = 0; i < numverts; ++i) {
+ BPH_mass_spring_force_vertex_wind(data, i, 1.0f, ext_forces);
+ }
+
+ MEM_freeN(ext_forces);
+ }
+
+ /* spring forces */
+ StrandIterator it_strand;
+ for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+ strands_calc_curve_forces(strands, space, params, cache_effectors, tot_cache_effectors, data, &it_strand);
+ }
+}
+
+/* calculates the velocity of strand roots using the new rest location (verts->co) and the current motion state */
+static void strands_calc_root_velocity(Strands *strands, float mat[4][4], Implicit_Data *data, float timestep)
+{
+ StrandIterator it_strand;
+ for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+ if (it_strand.curve->numverts > 0) {
+ int index = BKE_strand_iter_vertex_offset(strands, &it_strand);
+
+ float vel[3];
+ sub_v3_v3v3(vel, it_strand.verts[0].co, it_strand.state[0].co);
+ mul_v3_fl(vel, 1.0f/timestep);
+ mul_mat3_m4_v3(mat, vel);
+
+ BPH_mass_spring_set_velocity(data, index, vel);
+ }
+ }
+}
+
+/* calculates the location of strand roots using the new rest location (verts->co) and the current motion state */
+static void strands_calc_root_location(Strands *strands, float mat[4][4], Implicit_Data *data, float step)
+{
+ StrandIterator it_strand;
+ for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+ if (it_strand.curve->numverts > 0) {
+ int index = BKE_strand_iter_vertex_offset(strands, &it_strand);
+
+ float co[3];
+ interp_v3_v3v3(co, it_strand.state[0].co, it_strand.verts[0].co, step);
+ mul_m4_v3(mat, co);
+
+ BPH_mass_spring_set_position(data, index, co);
+ }
+ }
+}
+
+/* calculates the location of virtual goal vertices */
+static void strands_calc_goal_velocities(Strands *strands, float mat[4][4], Implicit_Data *data, float timestep)
+{
+ const int goalstart = strands->totverts;
+ int goalindex = goalstart;
+
+ StrandIterator it_strand;
+ for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+ StrandVertexIterator it_vert;
+ for (BKE_strand_vertex_iter_init(&it_vert, &it_strand); BKE_strand_vertex_iter_valid(&it_vert); BKE_strand_vertex_iter_next(&it_vert)) {
+ /* skip root */
+ if (it_vert.index == 0)
+ continue;
+
+ int index = BKE_strand_vertex_iter_vertex_offset(strands, &it_vert);
+
+ float vel[3];
+ sub_v3_v3v3(vel, strands->verts[index].co, strands->state[index].co);
+ mul_v3_fl(vel, 1.0f/timestep);
+ mul_mat3_m4_v3(mat, vel);
+
+ BPH_mass_spring_set_velocity(data, goalindex, vel);
+
+ ++goalindex;
+ }
+ }
+}
+
+/* calculates the location of virtual goal vertices */
+static void strands_calc_goal_locations(Strands *strands, float mat[4][4], Implicit_Data *data, float step)
+{
+ const int goalstart = strands->totverts;
+ int goalindex = goalstart;
+
+ StrandIterator it_strand;
+ for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+ StrandVertexIterator it_vert;
+ for (BKE_strand_vertex_iter_init(&it_vert, &it_strand); BKE_strand_vertex_iter_valid(&it_vert); BKE_strand_vertex_iter_next(&it_vert)) {
+ /* skip root */
+ if (it_vert.index == 0)
+ continue;
+
+ int index = BKE_strand_vertex_iter_vertex_offset(strands, &it_vert);
+
+ float co[3];
+ interp_v3_v3v3(co, strands->state[index].co, strands->verts[index].co, step);
+ mul_m4_v3(mat, co);
+
+ BPH_mass_spring_set_position(data, goalindex, co);
+
+ ++goalindex;
+ }
+ }
+}
+
+/* XXX Do we need to take fictitious forces from the moving and/or accelerated frame of reference into account?
+ * This would mean we pass not only the basic world transform mat, but also linear/angular velocity and acceleration.
+ */
+bool BPH_strands_solve(Strands *strands, float mat[4][4], Implicit_Data *id, HairSimParams *params, float frame, float frame_prev, Scene *scene,
+ ListBase *effectors, CacheEffector *cache_effectors, int tot_cache_effectors)
+{
+ if (params->timescale == 0.0f || params->substeps < 1)
+ return false;
+
+ float timestep = (FRA2TIME(frame) - FRA2TIME(frame_prev)) * params->timescale;
+ float dstep = 1.0f / params->substeps;
+ float dtime = timestep * dstep;
+ int numverts = strands->totverts;
+
+ int i;
+ ColliderContacts *contacts = NULL;
+ int totcolliders = 0;
+
+ float imat[4][4];
+ invert_m4_m4(imat, mat);
+
+// if (!clmd->solver_result)
+// clmd->solver_result = (ClothSolverResult *)MEM_callocN(sizeof(ClothSolverResult), "cloth solver result");
+// cloth_clear_result(clmd);
+
+ /* initialize solver data */
+ for (i = 0; i < numverts; i++) {
+ float wco[3], wvel[3];
+ copy_v3_v3(wco, strands->state[i].co);
+ copy_v3_v3(wvel, strands->state[i].vel);
+ mul_m4_v3(mat, wco);
+ mul_mat3_m4_v3(mat, wvel);
+ BPH_mass_spring_set_motion_state(id, i, wco, wvel);
+ }
+ strands_calc_root_velocity(strands, mat, id, timestep);
+
+ strands_calc_goal_locations(strands, mat, id, 0.0f);
+ strands_calc_goal_velocities(strands, mat, id, timestep);
+
+ for (float step = 0.0f; step < 1.0f; step += dstep) {
+ ImplicitSolverResult result;
+
+#if 0
+ /* determine contact points */
+ if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
+ cloth_find_point_contacts(ob, clmd, 0.0f, tf, &contacts, &totcolliders);
+ }
+#endif
+
+ /* setup vertex constraints for pinned vertices and contacts */
+ strands_setup_constraints(strands, id, contacts, totcolliders, dtime);
+
+ /* initialize forces to zero */
+ BPH_mass_spring_clear_forces(id);
+
+ // calculate forces
+ strands_calc_force(strands, mat, params, id, frame, scene, effectors, cache_effectors, tot_cache_effectors);
+
+ // calculate new velocity and position
+ BPH_mass_spring_solve_velocities(id, dtime, &result);
+// cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame);
+
+#if 0
+ if (is_hair) {
+ cloth_continuum_step(clmd, dtime);
+ }
+#endif
+
+ BPH_mass_spring_solve_positions(id, dtime);
+
+ BPH_mass_spring_apply_result(id);
+
+ /* move pinned verts to correct position */
+ strands_calc_root_location(strands, mat, id, step + dstep);
+ strands_calc_goal_locations(strands, mat, id, step + dstep);
+
+#if 0
+ /* free contact points */
+ if (contacts) {
+ cloth_free_contacts(contacts, totcolliders);
+ }
+#endif
+
+ }
+
+ /* copy results back to strand data */
+ for (i = 0; i < numverts; i++) {
+ float co[3], vel[3];
+ BPH_mass_spring_get_motion_state(id, i, co, vel);
+ mul_m4_v3(imat, co);
+ mul_mat3_m4_v3(imat, vel);
+ copy_v3_v3(strands->state[i].co, co);
+ copy_v3_v3(strands->state[i].vel, vel);
+ }
+
+ return true;
+}
diff --git a/source/blender/physics/intern/eigen_utils.h b/source/blender/physics/intern/eigen_utils.h
index cd3bd5ee45d..ebfed7cb690 100644
--- a/source/blender/physics/intern/eigen_utils.h
+++ b/source/blender/physics/intern/eigen_utils.h
@@ -28,7 +28,7 @@
#ifndef __EIGEN_UTILS_H__
#define __EIGEN_UTILS_H__
-/** \file eigen_utils.h
+/** \file blender/physics/intern/eigen_utils.h
* \ingroup bph
*/
@@ -39,6 +39,7 @@
#endif
#include <Eigen/Sparse>
+#include <Eigen/SVD>
#include <Eigen/src/Core/util/DisableStupidWarnings.h>
#ifdef __GNUC__
@@ -113,6 +114,7 @@ public:
};
typedef Eigen::VectorXf lVector;
+typedef Eigen::VectorXf VectorX;
/* Extension of dense Eigen vectors,
* providing 3-float block access for blenlib math functions
@@ -146,6 +148,7 @@ public:
typedef Eigen::Triplet<Scalar> Triplet;
typedef std::vector<Triplet> TripletList;
+typedef Eigen::MatrixXf MatrixX;
typedef Eigen::SparseMatrix<Scalar> lMatrix;
/* Constructor type that provides more convenient handling of Eigen triplets
@@ -201,6 +204,33 @@ typedef Eigen::ConjugateGradient<lMatrix, Eigen::Lower, Eigen::DiagonalPrecondit
using Eigen::ComputationInfo;
+template <typename MatrixType>
+BLI_INLINE MatrixType pseudo_inverse(const MatrixType& mat, double epsilon = std::numeric_limits<double>::epsilon())
+{
+ typedef Eigen::JacobiSVD<MatrixType> SVD;
+// typedef typename SVD::SingularValuesType SingularValues;
+
+ SVD svd(mat, Eigen::ComputeThinU | Eigen::ComputeThinV);
+
+ double tolerance = epsilon * std::max(mat.cols(), mat.rows()) * svd.singularValues().array().abs()(0);
+ return svd.matrixV() * (svd.singularValues().array().abs() > tolerance).select(svd.singularValues().array().inverse(), 0).matrix().asDiagonal() * svd.matrixU().adjoint();
+
+// const double pinvtoler=1.e-6; // choose your tolerance wisely!
+// SingularValues singularValues_inv = svd.singularValues();
+// for (long i = 0; i < mat.cols(); ++i) {
+// if (svd.singularValues(i) > pinvtoler )
+// singularValues_inv(i) = 1.0 / svd.singularValues(i);
+// else singularValues_inv(i) = 0;
+// }
+
+// return (svd.matrixV() * singularValues_inv.asDiagonal() * svd.matrixU().transpose());
+}
+
+BLI_INLINE void print_matrix_elem(float v)
+{
+ printf("%-8.3f", v);
+}
+
BLI_INLINE void print_lvector(const lVector3f &v)
{
for (int i = 0; i < v.rows(); ++i) {
@@ -221,7 +251,7 @@ BLI_INLINE void print_lmatrix(const lMatrix &m)
if (i > 0 && i % 3 == 0)
printf(" ");
- implicit_print_matrix_elem(m.coeff(j, i));
+ print_matrix_elem(m.coeff(j, i));
}
printf("\n");
}
diff --git a/source/blender/physics/intern/hair_volume.cpp b/source/blender/physics/intern/hair_volume.cpp
index b07af1d201c..d79cf7d8c31 100644
--- a/source/blender/physics/intern/hair_volume.cpp
+++ b/source/blender/physics/intern/hair_volume.cpp
@@ -594,7 +594,7 @@ BLI_INLINE float hair_volume_density_divergence(float density, float target_dens
return 0.0f;
}
-bool BPH_hair_volume_solve_divergence(HairGrid *grid, float dt, float target_density, float target_strength)
+bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target_density, float target_strength)
{
const float flowfac = grid->cellsize;
const float inv_flowfac = 1.0f / grid->cellsize;
diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h
index d286d3df1a5..79cf35ffb49 100644
--- a/source/blender/physics/intern/implicit.h
+++ b/source/blender/physics/intern/implicit.h
@@ -59,7 +59,6 @@ extern "C" {
//#define IMPLICIT_ENABLE_EIGEN_DEBUG
struct Implicit_Data;
-struct ImplicitSolverInput;
typedef struct ImplicitSolverResult {
int status;
@@ -68,11 +67,6 @@ typedef struct ImplicitSolverResult {
float error;
} ImplicitSolverResult;
-BLI_INLINE void implicit_print_matrix_elem(float v)
-{
- printf("%-8.3f", v);
-}
-
void BPH_mass_spring_set_vertex_mass(struct Implicit_Data *data, int index, float mass);
void BPH_mass_spring_set_rest_transform(struct Implicit_Data *data, int index, float rot[3][3]);
@@ -81,6 +75,7 @@ void BPH_mass_spring_set_position(struct Implicit_Data *data, int index, const f
void BPH_mass_spring_set_velocity(struct Implicit_Data *data, int index, const float v[3]);
void BPH_mass_spring_get_motion_state(struct Implicit_Data *data, int index, float x[3], float v[3]);
void BPH_mass_spring_get_position(struct Implicit_Data *data, int index, float x[3]);
+void BPH_mass_spring_get_velocity(struct Implicit_Data *data, int index, float v[3]);
/* access to modified motion state during solver step */
void BPH_mass_spring_get_new_position(struct Implicit_Data *data, int index, float x[3]);
@@ -112,7 +107,7 @@ void BPH_mass_spring_force_face_wind(struct Implicit_Data *data, int v1, int v2,
/* Wind force, acting on an edge */
void BPH_mass_spring_force_edge_wind(struct Implicit_Data *data, int v1, int v2, float radius1, float radius2, const float (*winvec)[3]);
/* Wind force, acting on a vertex */
-void BPH_mass_spring_force_vertex_wind(struct Implicit_Data *data, int v, float radius, const float (*winvec)[3]);
+void BPH_mass_spring_force_vertex_wind(struct Implicit_Data *data, int v, float factor, const float (*winvec)[3]);
/* Linear spring force between two points */
bool BPH_mass_spring_force_spring_linear(struct Implicit_Data *data, int i, int j, float restlen,
float stiffness, float damping, bool no_compress, float clamp_force,
@@ -123,7 +118,8 @@ bool BPH_mass_spring_force_spring_bending(struct Implicit_Data *data, int i, int
float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]);
/* Angular bending force based on local target vectors */
bool BPH_mass_spring_force_spring_bending_angular(struct Implicit_Data *data, int i, int j, int k,
- const float target[3], float stiffness, float damping);
+ const float target[3], float stiffness, float damping,
+ float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]);
/* Global goal spring */
bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data, int i, const float goal_x[3], const float goal_v[3],
float stiffness, float damping,
@@ -133,7 +129,6 @@ bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data, int i, const
struct HairGrid;
-struct Object;
struct VoxelData;
#define MAX_HAIR_GRID_RES 256
diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c
index dbeb1ff07c4..a2dd1ea76b4 100644
--- a/source/blender/physics/intern/implicit_blender.c
+++ b/source/blender/physics/intern/implicit_blender.c
@@ -373,7 +373,7 @@ static void print_bfmatrix(fmatrix3x3 *m)
if (i > 0 && i % 3 == 0)
printf(" ");
- implicit_print_matrix_elem(t[i + j * size]);
+ print_matrix_elem(t[i + j * size]);
}
printf("\n");
}
@@ -1229,6 +1229,11 @@ void BPH_mass_spring_get_position(struct Implicit_Data *data, int index, float x
root_to_world_v3(data, index, x, data->X[index]);
}
+void BPH_mass_spring_get_velocity(struct Implicit_Data *data, int index, float v[3])
+{
+ root_to_world_v3(data, index, v, data->V[index]);
+}
+
void BPH_mass_spring_get_new_position(struct Implicit_Data *data, int index, float x[3])
{
root_to_world_v3(data, index, x, data->Xnew[index]);
@@ -1507,15 +1512,13 @@ void BPH_mass_spring_force_edge_wind(Implicit_Data *data, int v1, int v2, float
add_v3_v3(data->F[v2], f);
}
-void BPH_mass_spring_force_vertex_wind(Implicit_Data *data, int v, float UNUSED(radius), const float (*winvec)[3])
+void BPH_mass_spring_force_vertex_wind(Implicit_Data *data, int v, float factor, const float (*winvec)[3])
{
- const float density = 0.01f; /* XXX arbitrary value, corresponds to effect of air density */
-
float wind[3];
float f[3];
world_to_root_v3(data, v, wind, winvec[v]);
- mul_v3_v3fl(f, wind, density);
+ mul_v3_v3fl(f, wind, factor);
add_v3_v3(data->F[v], f);
}
@@ -1523,10 +1526,15 @@ BLI_INLINE void dfdx_spring(float to[3][3], const float dir[3], float length, fl
{
// dir is unit length direction, rest is spring's restlength, k is spring constant.
//return ( (I-outerprod(dir, dir))*Min(1.0f, rest/length) - I) * -k;
- outerproduct(to, dir, dir);
- sub_m3_m3m3(to, I, to);
+ if (L > ALMOST_ZERO) {
+ outerproduct(to, dir, dir);
+ sub_m3_m3m3(to, I, to);
+
+ mul_m3_fl(to, (L / length));
+ }
+ else
+ zero_m3(to);
- mul_m3_fl(to, (L/length));
sub_m3_m3m3(to, to, I);
mul_m3_fl(to, k);
}
@@ -1540,7 +1548,7 @@ BLI_INLINE void dfdv_damp(float to[3][3], const float dir[3], float damping)
BLI_INLINE float fb(float length, float L)
{
- float x = length / L;
+ float x = L > ALMOST_ZERO ? length / L : 0.0f;
float xx = x * x;
float xxx = xx * x;
float xxxx = xxx * x;
@@ -1549,7 +1557,7 @@ BLI_INLINE float fb(float length, float L)
BLI_INLINE float fbderiv(float length, float L)
{
- float x = length / L;
+ float x = L > ALMOST_ZERO ? length / L : 0.0f;
float xx = x * x;
float xxx = xx * x;
return (-46.164f * xxx + 102.579f * xx - 78.166f * x + 23.116f);
@@ -1846,7 +1854,8 @@ BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data, int i, int j,
* See "Artistic Simulation of Curly Hair" (Pixar technical memo #12-03a)
*/
bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, int j, int k,
- const float target[3], float stiffness, float damping)
+ const float target[3], float stiffness, float damping,
+ float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
{
float goal[3];
float fj[3], fk[3];
@@ -1983,6 +1992,13 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in
add_m3_m3m3(data->dFdX[block_ik].m, data->dFdX[block_ik].m, dfk_dxi);
#endif
+ if (r_f)
+ copy_v3_v3(r_f, fj);
+ if (r_dfdx)
+ copy_m3_m3(r_dfdx, dfj_dxj);
+ if (r_dfdv)
+ copy_m3_m3(r_dfdx, dfj_dvj);
+
return true;
}
diff --git a/source/blender/physics/intern/implicit_eigen.cpp b/source/blender/physics/intern/implicit_eigen.cpp
index 0ea8ccb0a49..69feb3c19e2 100644
--- a/source/blender/physics/intern/implicit_eigen.cpp
+++ b/source/blender/physics/intern/implicit_eigen.cpp
@@ -269,7 +269,7 @@ static void print_lmatrix(const lMatrix &m)
if (i > 0 && i % 3 == 0)
printf(" ");
- implicit_print_matrix_elem(m.coeff(j, i));
+ print_matrix_elem(m.coeff(j, i));
}
printf("\n");
}
diff --git a/source/blender/physics/intern/strands.cpp b/source/blender/physics/intern/strands.cpp
new file mode 100644
index 00000000000..f8bba6a615c
--- /dev/null
+++ b/source/blender/physics/intern/strands.cpp
@@ -0,0 +1,472 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/physics/intern/strands.c
+ * \ingroup bke
+ */
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "DNA_customdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_customdata.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_editstrands.h"
+#include "BKE_effect.h"
+#include "BKE_mesh_sample.h"
+
+#include "bmesh.h"
+}
+
+#include "BPH_strands.h"
+
+#include "eigen_utils.h"
+
+/* === constraints === */
+
+static bool strand_get_root_vectors(BMEditStrands *edit, BMVert *root, float loc[3], float nor[3], float tang[3])
+{
+ BMesh *bm = edit->bm;
+ DerivedMesh *root_dm = edit->root_dm;
+ MSurfaceSample root_sample;
+
+ if (!CustomData_has_layer(&bm->vdata, CD_MSURFACE_SAMPLE))
+ return false;
+
+ BM_elem_meshsample_data_named_get(&bm->vdata, root, CD_MSURFACE_SAMPLE, CD_HAIR_ROOT_LOCATION, &root_sample);
+ return BKE_mesh_sample_eval(root_dm, &root_sample, loc, nor, tang);
+}
+
+static int strand_count_vertices(BMVert *root)
+{
+ BMVert *v;
+ BMIter iter;
+
+ int len = 0;
+ BM_ITER_STRANDS_ELEM(v, &iter, root, BM_VERTS_OF_STRAND) {
+ ++len;
+ }
+ return len;
+}
+
+static int UNUSED_FUNCTION(strands_get_max_length)(BMEditStrands *edit)
+{
+ BMVert *root;
+ BMIter iter;
+ int maxlen = 0;
+
+ BM_ITER_STRANDS(root, &iter, edit->bm, BM_STRANDS_OF_MESH) {
+ int len = strand_count_vertices(root);
+ if (len > maxlen)
+ maxlen = len;
+ }
+ return maxlen;
+}
+
+static void strands_apply_root_locations(BMEditStrands *edit)
+{
+ BMVert *root;
+ BMIter iter;
+
+ if (!edit->root_dm)
+ return;
+
+ BM_ITER_STRANDS(root, &iter, edit->bm, BM_STRANDS_OF_MESH) {
+ float loc[3], nor[3], tang[3];
+
+ if (strand_get_root_vectors(edit, root, loc, nor, tang)) {
+ copy_v3_v3(root->co, loc);
+ }
+ }
+}
+
+static void strands_adjust_segment_lengths(BMesh *bm)
+{
+ BMVert *root;
+ BMIter iter;
+
+ BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) {
+ BMVert *v, *vprev = NULL;
+ BMIter iter_strand;
+ BM_ITER_STRANDS_ELEM(v, &iter_strand, root, BM_VERTS_OF_STRAND) {
+ if (vprev) {
+ float base_length = BM_elem_float_data_named_get(&bm->vdata, vprev, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH);
+ float dist[3];
+ float length;
+
+ sub_v3_v3v3(dist, v->co, vprev->co);
+ length = len_v3(dist);
+ if (length > 0.0f)
+ madd_v3_v3v3fl(v->co, vprev->co, dist, base_length / length);
+ }
+ vprev = v;
+ }
+ }
+}
+
+static void strands_vertex_relax(BMesh *bm, float relax_factor, const BMVert *vprev, const BMVert *v, const BMVert *vnext, float relax[3])
+{
+ float D_pos[3], D_neg[3];
+
+ if (vprev) {
+ sub_v3_v3v3(D_neg, vprev->co, v->co);
+ float len = len_v3(D_neg);
+ if (len > 0.0f) {
+ float Lprev = BM_elem_float_data_named_get(&bm->vdata, (void *)vprev, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH);
+ mul_v3_fl(D_neg, (1.0f - Lprev / len) * relax_factor);
+ }
+ else
+ zero_v3(D_neg);
+ }
+ else
+ zero_v3(D_neg);
+
+ if (vnext) {
+ sub_v3_v3v3(D_pos, vnext->co, v->co);
+ float len = len_v3(D_pos);
+ if (len > 0.0f) {
+ float L = BM_elem_float_data_named_get(&bm->vdata, (void *)v, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH);
+ mul_v3_fl(D_pos, (1.0f - L / len) * relax_factor);
+ }
+ else
+ zero_v3(D_pos);
+ }
+ else
+ zero_v3(D_pos);
+
+ add_v3_v3v3(relax, D_neg, D_pos);
+}
+
+/* single relaxation iteration, must be repeated totkey times for complete relaxation */
+static void strands_relax(BMesh *bm, BMVert *root, bool skip_first)
+{
+ const int numvert = BM_strands_keys_count(root);
+ const float relax_factor = numvert > 0 ? 1.0f / numvert : 0.0f;
+
+ BMVert *vert_next, *vert = NULL, *vert_prev = NULL;
+ float relax_prev[3], relax[3];
+ BMIter iter;
+
+ BM_ITER_STRANDS_ELEM(vert_next, &iter, root, BM_VERTS_OF_STRAND) {
+
+ if (vert) {
+ /* note: relaxation is applied *after* calculating the next segment, so vertex location can be modified safely */
+ strands_vertex_relax(bm, relax_factor, vert_prev, vert, vert_next, relax);
+
+ /* don't modify fixed root */
+ if (vert_prev && !(skip_first && vert_prev == root)) {
+ add_v3_v3(vert_prev->co, relax_prev);
+ }
+ }
+
+ vert_prev = vert;
+ vert = vert_next;
+ copy_v3_v3(relax_prev, relax);
+ }
+
+ /* last segment */
+ {
+ /* don't modify fixed root */
+ if (vert_prev && !(skip_first && vert_prev == root)) {
+ add_v3_v3(vert_prev->co, relax_prev);
+ }
+ }
+}
+
+/* try to find a nice solution to keep distances between neighboring keys */
+/* XXX Stub implementation ported from particles:
+ * Successively relax each segment starting from the root,
+ * repeat this for every vertex (O(n^2))
+ * This should be replaced by a more advanced method using a least-squares
+ * error metric with length and root location constraints (IK solver)
+ */
+static void strands_solve_edge_relaxation(BMEditStrands *edit)
+{
+ BMesh *bm = edit->bm;
+ BMVert *root;
+ BMIter iter;
+
+ if (!edit)
+ return;
+// if (!(pset->flag & PE_KEEP_LENGTHS)) // XXX TODO
+// return;
+
+ BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) {
+ BMVert *vj;
+ BMIter iterj;
+ int j;
+
+ BM_ITER_STRANDS_ELEM_INDEX(vj, &iterj, root, BM_VERTS_OF_STRAND, j) {
+
+ if (j < 1)
+ continue;
+
+ /* XXX particles use PE_LOCK_FIRST option */
+ bool skip_first = true;
+
+ strands_relax(bm, root, skip_first);
+ }
+ }
+}
+
+typedef struct IKTarget {
+ BMVert *vertex;
+ float weight;
+} IKTarget;
+
+static int strand_find_ik_targets(BMVert *root, IKTarget *targets)
+{
+ BMVert *v;
+ BMIter iter;
+ int k, index;
+
+ index = 0;
+ BM_ITER_STRANDS_ELEM_INDEX(v, &iter, root, BM_VERTS_OF_STRAND, k) {
+ /* XXX TODO allow multiple targets and do weight calculation here */
+ if (BM_strands_vert_is_tip(v)) {
+ IKTarget *target = &targets[index];
+ target->vertex = v;
+ target->weight = 1.0f;
+ ++index;
+ }
+ }
+
+ return index;
+}
+
+static void calc_jacobian_entry(Object *ob, BMEditStrands * /*edit*/, IKTarget *target, int index_target, int index_angle,
+ const float point[3], const float axis1[3], const float axis2[3], MatrixX &J)
+{
+ float (*obmat)[4] = ob->obmat;
+
+ float dist[3], jac1[3], jac2[3];
+
+ sub_v3_v3v3(dist, target->vertex->co, point);
+
+ cross_v3_v3v3(jac1, axis1, dist);
+ cross_v3_v3v3(jac2, axis2, dist);
+
+ for (int i = 0; i < 3; ++i) {
+ J.coeffRef(index_target + i, index_angle + 0) = jac1[i];
+ J.coeffRef(index_target + i, index_angle + 1) = jac2[i];
+ }
+
+#if 1
+ {
+ float wco[3], wdir[3];
+
+ mul_v3_m4v3(wco, obmat, point);
+
+ mul_v3_m4v3(wdir, obmat, jac1);
+ BKE_sim_debug_data_add_vector(wco, wdir, 1,1,0, "strands", index_angle, 1);
+ mul_v3_m4v3(wdir, obmat, jac2);
+ BKE_sim_debug_data_add_vector(wco, wdir, 0,1,1, "strands", index_angle + 1, 2);
+ }
+#endif
+}
+
+static MatrixX strand_calc_target_jacobian(Object *ob, BMEditStrands *edit, BMVert *root, int numjoints, IKTarget *targets, int numtargets)
+{
+ BMVert *v, *vprev;
+ BMIter iter_strand;
+ int k;
+
+ float loc[3], axis[3], dir[3];
+
+ MatrixX J(3 * numtargets, 2 * numjoints);
+ if (!strand_get_root_vectors(edit, root, loc, dir, axis)) {
+ return J;
+ }
+
+ BM_ITER_STRANDS_ELEM_INDEX(v, &iter_strand, root, BM_VERTS_OF_STRAND, k) {
+ float dirprev[3];
+
+ if (k > 0) {
+ float rot[3][3];
+
+ copy_v3_v3(dirprev, dir);
+ sub_v3_v3v3(dir, v->co, vprev->co);
+ normalize_v3(dir);
+
+ rotation_between_vecs_to_mat3(rot, dirprev, dir);
+ mul_m3_v3(rot, axis);
+ }
+
+ calc_jacobian_entry(ob, edit, &targets[0], 0, 2*k, v->co, axis, dir, J);
+
+#if 0
+ {
+ float (*obmat)[4] = ob->obmat;
+ float wco[3], wdir[3];
+
+ mul_v3_m4v3(wco, obmat, v->co);
+
+ mul_v3_m4v3(wdir, obmat, axis);
+ BKE_sim_debug_data_add_vector(edit->debug_data, wco, wdir, 1,0,0, "strands", BM_elem_index_get(v), 1);
+ mul_v3_m4v3(wdir, obmat, dir);
+ BKE_sim_debug_data_add_vector(edit->debug_data, wco, wdir, 0,1,0, "strands", BM_elem_index_get(v), 2);
+ cross_v3_v3v3(wdir, axis, dir);
+ mul_m4_v3(obmat, wdir);
+ BKE_sim_debug_data_add_vector(edit->debug_data, wco, wdir, 0,0,1, "strands", BM_elem_index_get(v), 3);
+ }
+#endif
+
+ vprev = v;
+ }
+
+ return J;
+}
+
+static VectorX strand_angles_to_loc(Object * /*ob*/, BMEditStrands *edit, BMVert *root, int numjoints, const VectorX &angles)
+{
+ BMVert *v, *vprev;
+ BMIter iter_strand;
+ int k;
+
+ float loc[3], axis[3], dir[3];
+ float mat_theta[3][3], mat_phi[3][3];
+
+ if (!strand_get_root_vectors(edit, root, loc, dir, axis))
+ return VectorX();
+
+ VectorX result(3*numjoints);
+
+ BM_ITER_STRANDS_ELEM_INDEX(v, &iter_strand, root, BM_VERTS_OF_STRAND, k) {
+ float dirprev[3];
+
+ if (k > 0) {
+ const float base_length = BM_elem_float_data_named_get(&edit->bm->vdata, v, CD_PROP_FLT, CD_HAIR_SEGMENT_LENGTH);
+ float rot[3][3];
+
+ copy_v3_v3(dirprev, dir);
+ sub_v3_v3v3(dir, v->co, vprev->co);
+ normalize_v3(dir);
+
+ rotation_between_vecs_to_mat3(rot, dirprev, dir);
+ mul_m3_v3(rot, axis);
+
+ /* apply rotations from previous joint on the vertex */
+ float vec[3];
+ mul_v3_v3fl(vec, dir, base_length);
+
+ mul_m3_v3(mat_theta, vec);
+ mul_m3_v3(mat_phi, vec);
+ add_v3_v3v3(&result.coeffRef(3*k), &result.coeff(3*(k-1)), vec);
+ }
+ else {
+ copy_v3_v3(&result.coeffRef(3*k), v->co);
+ }
+
+ float theta = angles[2*k + 0];
+ float phi = angles[2*k + 1];
+ axis_angle_normalized_to_mat3(mat_theta, axis, theta);
+ axis_angle_normalized_to_mat3(mat_phi, dir, phi);
+
+ vprev = v;
+ }
+
+ return result;
+}
+
+static void UNUSED_FUNCTION(strand_apply_ik_result)(Object *UNUSED(ob), BMEditStrands *UNUSED(edit), BMVert *root, const VectorX &solution)
+{
+ BMVert *v;
+ BMIter iter_strand;
+ int k;
+
+ BM_ITER_STRANDS_ELEM_INDEX(v, &iter_strand, root, BM_VERTS_OF_STRAND, k) {
+ copy_v3_v3(v->co, &solution.coeff(3*k));
+ }
+}
+
+static void strands_solve_inverse_kinematics(Object *ob, BMEditStrands *edit, float (*orig)[3])
+{
+ BMesh *bm = edit->bm;
+
+ BMVert *root;
+ BMIter iter;
+
+ BM_ITER_STRANDS(root, &iter, bm, BM_STRANDS_OF_MESH) {
+ int numjoints = strand_count_vertices(root);
+ if (numjoints <= 0)
+ continue;
+
+ IKTarget targets[1]; /* XXX placeholder, later should be allocated to max. strand length */
+ int numtargets = strand_find_ik_targets(root, targets);
+
+ MatrixX J = strand_calc_target_jacobian(ob, edit, root, numjoints, targets, numtargets);
+ MatrixX Jinv = pseudo_inverse(J, 1.e-6);
+
+ VectorX x(3 * numtargets);
+ for (int i = 0; i < numtargets; ++i) {
+ sub_v3_v3v3(&x.coeffRef(3*i), targets[i].vertex->co, orig[i]);
+ /* TODO calculate deviation of vertices from their origin (whatever that is) */
+// x[3*i + 0] = 0.0f;
+// x[3*i + 1] = 0.0f;
+// x[3*i + 2] = 0.0f;
+ }
+ VectorX angles = Jinv * x;
+ VectorX solution = strand_angles_to_loc(ob, edit, root, numjoints, angles);
+
+// strand_apply_ik_result(ob, edit, root, solution);
+
+#if 1
+ {
+ BMVert *v;
+ BMIter iter_strand;
+ int k;
+ float wco[3];
+
+ BM_ITER_STRANDS_ELEM_INDEX(v, &iter_strand, root, BM_VERTS_OF_STRAND, k) {
+ mul_v3_m4v3(wco, ob->obmat, &solution.coeff(3*k));
+ BKE_sim_debug_data_add_circle(wco, 0.05f, 1,0,1, "strands", k, BM_elem_index_get(root), 2344);
+ }
+ }
+#endif
+ }
+}
+
+void BPH_strands_solve_constraints(Object *ob, BMEditStrands *edit, float (*orig)[3])
+{
+ strands_apply_root_locations(edit);
+
+ if (true) {
+ strands_solve_edge_relaxation(edit);
+ }
+ else {
+ if (orig)
+ strands_solve_inverse_kinematics(ob, edit, orig);
+ }
+
+ strands_adjust_segment_lengths(edit->bm);
+}
diff --git a/source/blender/pointcache/CMakeLists.txt b/source/blender/pointcache/CMakeLists.txt
new file mode 100644
index 00000000000..2898785c11e
--- /dev/null
+++ b/source/blender/pointcache/CMakeLists.txt
@@ -0,0 +1,66 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2013, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ intern
+ util
+ ../blenkernel
+ ../blenlib
+ ../makesdna
+ ../makesrna
+ ../../../intern/guardedalloc
+)
+
+set(INC_SYS
+)
+
+set(SRC
+ intern/ptc_types.h
+ intern/ptc_types.cpp
+ intern/reader.h
+ intern/reader.cpp
+ intern/writer.h
+ intern/writer.cpp
+
+ util/util_error_handler.h
+ util/util_error_handler.cpp
+ util/util_task.cpp
+ util/util_task.h
+ util/util_thread.h
+ util/util_types.h
+
+ PTC_api.h
+ PTC_api.cpp
+)
+
+if(NOT WITH_CPP11)
+ list(APPEND INC_SYS ${BOOST_INCLUDE_DIR})
+endif()
+
+if(WITH_ALEMBIC)
+ add_definitions(-DWITH_PTC_ALEMBIC)
+ add_subdirectory(alembic)
+endif()
+
+blender_add_lib(bf_pointcache "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/pointcache/PTC_api.cpp b/source/blender/pointcache/PTC_api.cpp
new file mode 100644
index 00000000000..3e659399970
--- /dev/null
+++ b/source/blender/pointcache/PTC_api.cpp
@@ -0,0 +1,417 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2013, Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "PTC_api.h"
+
+#include "util/util_error_handler.h"
+
+#include "reader.h"
+#include "writer.h"
+
+#include "ptc_types.h"
+
+extern "C" {
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "DNA_listBase.h"
+#include "DNA_modifier_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_modifier.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+
+#include "RNA_access.h"
+}
+
+using namespace PTC;
+
+class StubFactory : public Factory {
+ const std::string &get_default_extension() { static std::string ext = ""; return ext; }
+ WriterArchive *open_writer_archive(double /*fps*/, float /*start_frame*/, const std::string &/*name*/, PTCArchiveResolution /*resolutions*/,
+ const char */*app_name*/, const char */*description*/, const struct tm */*time*/, struct IDProperty */*metadata*/, ErrorHandler */*error_handler*/) { return NULL; }
+ ReaderArchive *open_reader_archive(double /*fps*/, float /*start_frame*/, const std::string &/*name*/, ErrorHandler * /*error_handler*/) { return NULL; }
+ void slice(ReaderArchive * /*in*/, WriterArchive * /*out*/, float /*start_frame*/, float /*end_frame*/) {}
+ Writer *create_writer_object(const std::string &/*name*/, Scene */*scene*/, Object */*ob*/) { return NULL; }
+ Reader *create_reader_object(const std::string &/*name*/, Object */*ob*/) { return NULL; }
+ Writer *create_writer_group(const std::string &/*name*/, Group */*group*/) { return NULL; }
+ Reader *create_reader_group(const std::string &/*name*/, Group */*group*/) { return NULL; }
+ Writer *create_writer_cloth(const std::string &/*name*/, Object */*ob*/, ClothModifierData */*clmd*/) { return NULL; }
+ Reader *create_reader_cloth(const std::string &/*name*/, Object */*ob*/, ClothModifierData */*clmd*/) { return NULL; }
+ Writer *create_writer_derived_mesh(const std::string &/*name*/, Object */*ob*/, DerivedMesh **/*dm_ptr*/) { return NULL; }
+ Reader *create_reader_derived_mesh(const std::string &/*name*/, Object */*ob*/) { return NULL; }
+ Writer *create_writer_derived_final_realtime(const std::string &/*name*/, Object */*ob*/) { return NULL; }
+ Writer *create_writer_derived_final_render(const std::string &/*name*/, Scene */*scene*/, Object */*ob*/, DerivedMesh **/*render_dm_ptr*/) { return NULL; }
+ Writer *create_writer_dupligroup(const std::string &/*name*/, EvaluationContext */*eval_ctx*/, Scene */*scene*/, Group */*group*/, CacheLibrary */*cachelib*/) { return NULL; }
+ Writer *create_writer_duplicache(const std::string &/*name*/, Group */*group*/, DupliCache */*dupcache*/, int /*datatypes*/, bool /*do_sim_debug*/) { return NULL; }
+ Reader *create_reader_duplicache(const std::string &/*name*/, Group */*group*/, DupliCache */*dupcache*/, bool /*read_strands_motion*/, bool /*read_strands_children*/, bool /*do_sim_debug*/) { return NULL; }
+ Reader *create_reader_duplicache_object(const std::string &/*name*/, Object */*ob*/, DupliObjectData */*data*/, bool /*read_strands_motion*/, bool /*read_strands_children*/) { return NULL; }
+};
+
+#ifndef WITH_PTC_ALEMBIC
+void PTC_alembic_init()
+{
+ static StubFactory stub_factory;
+ PTC::Factory::alembic = &stub_factory;
+}
+#endif
+
+void PTC_error_handler_std(void)
+{
+ ErrorHandler::clear_default_handler();
+}
+
+void PTC_error_handler_callback(PTCErrorCallback cb, void *userdata)
+{
+ ErrorHandler::set_default_handler(new CallbackErrorHandler(cb, userdata));
+}
+
+static ReportType report_type_from_error_level(PTCErrorLevel level)
+{
+ switch (level) {
+ case PTC_ERROR_NONE: return RPT_DEBUG;
+ case PTC_ERROR_INFO: return RPT_INFO;
+ case PTC_ERROR_WARNING: return RPT_WARNING;
+ case PTC_ERROR_CRITICAL: return RPT_ERROR;
+ }
+ return RPT_ERROR;
+}
+
+static void error_handler_reports_cb(void *vreports, PTCErrorLevel level, const char *message)
+{
+ ReportList *reports = (ReportList *)vreports;
+
+ BKE_report(reports, report_type_from_error_level(level), message);
+}
+
+void PTC_error_handler_reports(struct ReportList *reports)
+{
+ ErrorHandler::set_default_handler(new CallbackErrorHandler(error_handler_reports_cb, reports));
+}
+
+static void error_handler_modifier_cb(void *vmd, PTCErrorLevel UNUSED(level), const char *message)
+{
+ ModifierData *md = (ModifierData *)vmd;
+
+ modifier_setError(md, "%s", message);
+}
+
+void PTC_error_handler_modifier(struct ModifierData *md)
+{
+ ErrorHandler::set_default_handler(new CallbackErrorHandler(error_handler_modifier_cb, md));
+}
+
+
+const char *PTC_get_default_archive_extension(void)
+{
+ return PTC::Factory::alembic->get_default_extension().c_str();
+}
+
+PTCWriterArchive *PTC_open_writer_archive(double fps, float start_frame, const char *path, PTCArchiveResolution resolutions,
+ const char *app_name, const char *description, const struct tm *time, struct IDProperty *metadata)
+{
+ return (PTCWriterArchive *)PTC::Factory::alembic->open_writer_archive(fps, start_frame, path, resolutions, app_name, description, time, metadata, NULL);
+}
+
+void PTC_close_writer_archive(PTCWriterArchive *_archive)
+{
+ PTC::WriterArchive *archive = (PTC::WriterArchive *)_archive;
+ delete archive;
+}
+
+void PTC_writer_archive_use_render(PTCWriterArchive *_archive, bool enable)
+{
+ PTC::WriterArchive *archive = (PTC::WriterArchive *)_archive;
+ archive->use_render(enable);
+}
+
+PTCReaderArchive *PTC_open_reader_archive(Scene *scene, const char *path)
+{
+ double fps = FPS;
+ float start_frame = scene->r.sfra;
+ return PTC_open_reader_archive_ex(fps, start_frame, path);
+}
+
+PTCReaderArchive *PTC_open_reader_archive_ex(double fps, float start_frame, const char *path)
+{
+ return (PTCReaderArchive *)PTC::Factory::alembic->open_reader_archive(fps, start_frame, path, NULL);
+}
+
+void PTC_close_reader_archive(PTCReaderArchive *_archive)
+{
+ PTC::ReaderArchive *archive = (PTC::ReaderArchive *)_archive;
+ delete archive;
+}
+
+PTCArchiveResolution PTC_reader_archive_get_resolutions(PTCReaderArchive *_archive)
+{
+ PTC::ReaderArchive *archive = (PTC::ReaderArchive *)_archive;
+ return archive->get_resolutions();
+}
+
+void PTC_reader_archive_use_render(PTCReaderArchive *_archive, bool enable)
+{
+ PTC::ReaderArchive *archive = (PTC::ReaderArchive *)_archive;
+ archive->use_render(enable);
+}
+
+void PTC_writer_init(PTCWriter *_writer, PTCWriterArchive *_archive)
+{
+ PTC::Writer *writer = (PTC::Writer *)_writer;
+ PTC::WriterArchive *archive = (PTC::WriterArchive *)_archive;
+ writer->init(archive);
+}
+
+void PTC_writer_create_refs(PTCWriter *_writer)
+{
+ PTC::Writer *writer = (PTC::Writer *)_writer;
+ writer->create_refs();
+}
+
+void PTC_reader_init(PTCReader *_reader, PTCReaderArchive *_archive)
+{
+ PTC::Reader *reader = (PTC::Reader *)_reader;
+ PTC::ReaderArchive *archive = (PTC::ReaderArchive *)_archive;
+ reader->init(archive);
+}
+
+/* ========================================================================= */
+
+void PTC_writer_free(PTCWriter *_writer)
+{
+ PTC::Writer *writer = (PTC::Writer *)_writer;
+ delete writer;
+}
+
+void PTC_write_sample(struct PTCWriter *_writer)
+{
+ PTC::Writer *writer = (PTC::Writer *)_writer;
+ writer->write_sample();
+}
+
+
+void PTC_reader_free(PTCReader *_reader)
+{
+ PTC::Reader *reader = (PTC::Reader *)_reader;
+ delete reader;
+}
+
+bool PTC_reader_get_frame_range(PTCReader *_reader, int *start_frame, int *end_frame)
+{
+ PTC::Reader *reader = (PTC::Reader *)_reader;
+ int sfra, efra;
+ if (reader->get_frame_range(sfra, efra)) {
+ if (start_frame) *start_frame = sfra;
+ if (end_frame) *end_frame = efra;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+PTCReadSampleResult PTC_read_sample(PTCReader *_reader, float frame)
+{
+ PTC::Reader *reader = (PTC::Reader *)_reader;
+ return reader->read_sample(frame);
+}
+
+PTCReadSampleResult PTC_test_sample(PTCReader *_reader, float frame)
+{
+ PTC::Reader *reader = (PTC::Reader *)_reader;
+ return reader->test_sample(frame);
+}
+
+void PTC_get_archive_info_stream(PTCReaderArchive *_archive, void (*stream)(void *, const char *), void *userdata)
+{
+ PTC::ReaderArchive *archive = (PTC::ReaderArchive *)_archive;
+ archive->get_info_stream(stream, userdata);
+}
+
+void PTC_get_archive_info(PTCReaderArchive *_archive, struct CacheArchiveInfo *info, IDProperty *metadata)
+{
+ PTC::ReaderArchive *archive = (PTC::ReaderArchive *)_archive;
+ archive->get_info(info, metadata);
+}
+
+void PTC_get_archive_info_nodes(PTCReaderArchive *_archive, struct CacheArchiveInfo *info, bool calc_bytes_size)
+{
+ PTC::ReaderArchive *archive = (PTC::ReaderArchive *)_archive;
+ archive->get_info_nodes(info, calc_bytes_size);
+}
+
+void PTC_archive_slice(PTCReaderArchive *_in, PTCWriterArchive *_out, float start_frame, float end_frame)
+{
+ PTC::ReaderArchive *in = (PTC::ReaderArchive *)_in;
+ PTC::WriterArchive *out = (PTC::WriterArchive *)_out;
+
+ PTC::Factory::alembic->slice(in, out, start_frame, end_frame);
+}
+
+
+PTCWriter *PTC_writer_dupligroup(const char *name, struct EvaluationContext *eval_ctx, struct Scene *scene, struct Group *group, struct CacheLibrary *cachelib)
+{
+ return (PTCWriter *)PTC::Factory::alembic->create_writer_dupligroup(name, eval_ctx, scene, group, cachelib);
+}
+
+PTCWriter *PTC_writer_duplicache(const char *name, struct Group *group, struct DupliCache *dupcache, int datatypes, bool do_sim_debug)
+{
+ return (PTCWriter *)PTC::Factory::alembic->create_writer_duplicache(name, group, dupcache, datatypes, do_sim_debug);
+}
+
+PTCReader *PTC_reader_duplicache(const char *name, struct Group *group, struct DupliCache *dupcache,
+ bool read_strands_motion, bool read_strands_children, bool read_sim_debug)
+{
+ return (PTCReader *)PTC::Factory::alembic->create_reader_duplicache(name, group, dupcache,
+ read_strands_motion, read_strands_children, read_sim_debug);
+}
+
+PTCReader *PTC_reader_duplicache_object(const char *name, struct Object *ob, struct DupliObjectData *data,
+ bool read_strands_motion, bool read_strands_children)
+{
+ return (PTCReader *)PTC::Factory::alembic->create_reader_duplicache_object(name, ob, data, read_strands_motion, read_strands_children);
+}
+
+
+/* get writer/reader from RNA type */
+PTCWriter *PTC_writer_from_rna(Scene */*scene*/, PointerRNA */*ptr*/)
+{
+#if 0
+#if 0
+ if (RNA_struct_is_a(ptr->type, &RNA_ParticleSystem)) {
+ Object *ob = (Object *)ptr->id.data;
+ ParticleSystem *psys = (ParticleSystem *)ptr->data;
+ return PTC_writer_particles_combined(scene, ob, psys);
+ }
+#endif
+ if (RNA_struct_is_a(ptr->type, &RNA_ClothModifier)) {
+ Object *ob = (Object *)ptr->id.data;
+ ClothModifierData *clmd = (ClothModifierData *)ptr->data;
+ return PTC_writer_cloth(scene, ob, clmd);
+ }
+#endif
+ return NULL;
+}
+
+PTCReader *PTC_reader_from_rna(Scene */*scene*/, PointerRNA */*ptr*/)
+{
+#if 0
+ if (RNA_struct_is_a(ptr->type, &RNA_ParticleSystem)) {
+ Object *ob = (Object *)ptr->id.data;
+ ParticleSystem *psys = (ParticleSystem *)ptr->data;
+ /* XXX particles are bad ...
+ * this can be either the actual particle cache or the hair dynamics cache,
+ * which is actually the cache of the internal cloth modifier
+ */
+ bool use_cloth_cache = psys->part->type == PART_HAIR && (psys->flag & PSYS_HAIR_DYNAMICS);
+ if (use_cloth_cache && psys->clmd)
+ return PTC_reader_cloth(scene, ob, psys->clmd);
+ else
+ return PTC_reader_particles(scene, ob, psys);
+ }
+ if (RNA_struct_is_a(ptr->type, &RNA_ClothModifier)) {
+ Object *ob = (Object *)ptr->id.data;
+ ClothModifierData *clmd = (ClothModifierData *)ptr->data;
+ return PTC_reader_cloth(scene, ob, clmd);
+ }
+#endif
+ return NULL;
+}
+
+
+/* ==== CLOTH ==== */
+
+PTCWriter *PTC_writer_cloth(const char *name, Object *ob, ClothModifierData *clmd)
+{
+ return (PTCWriter *)PTC::Factory::alembic->create_writer_cloth(name, ob, clmd);
+}
+
+PTCReader *PTC_reader_cloth(const char *name, Object *ob, ClothModifierData *clmd)
+{
+ return (PTCReader *)PTC::Factory::alembic->create_reader_cloth(name, ob, clmd);
+}
+
+
+/* ==== MESH ==== */
+
+PTCWriter *PTC_writer_derived_mesh(const char *name, Object *ob, DerivedMesh **dm_ptr)
+{
+ return (PTCWriter *)PTC::Factory::alembic->create_writer_derived_mesh(name, ob, dm_ptr);
+}
+
+PTCReader *PTC_reader_derived_mesh(const char *name, Object *ob)
+{
+ return (PTCReader *)PTC::Factory::alembic->create_reader_derived_mesh(name, ob);
+}
+
+struct DerivedMesh *PTC_reader_derived_mesh_acquire_result(PTCReader *_reader)
+{
+ DerivedMeshReader *reader = (DerivedMeshReader *)_reader;
+ return reader->acquire_result();
+}
+
+void PTC_reader_derived_mesh_discard_result(PTCReader *_reader)
+{
+ DerivedMeshReader *reader = (DerivedMeshReader *)_reader;
+ reader->discard_result();
+}
+
+
+PTCWriter *PTC_writer_derived_final_realtime(const char *name, Object *ob)
+{
+ return (PTCWriter *)PTC::Factory::alembic->create_writer_derived_final_realtime(name, ob);
+}
+
+PTCWriter *PTC_writer_derived_final_render(const char *name, Scene *scene, Object *ob, DerivedMesh **render_dm_ptr)
+{
+ return (PTCWriter *)PTC::Factory::alembic->create_writer_derived_final_render(name, scene, ob, render_dm_ptr);
+}
+
+
+/* ==== OBJECT ==== */
+
+PTCWriter *PTC_writer_object(const char *name, Scene *scene, Object *ob)
+{
+ return (PTCWriter *)PTC::Factory::alembic->create_writer_object(name, scene, ob);
+}
+
+PTCReader *PTC_reader_object(const char *name, Object *ob)
+{
+ return (PTCReader *)PTC::Factory::alembic->create_reader_object(name, ob);
+}
+
+
+/* ==== GROUP ==== */
+
+PTCWriter *PTC_writer_group(const char *name, Group *group)
+{
+ return (PTCWriter *)PTC::Factory::alembic->create_writer_group(name, group);
+}
+
+PTCReader *PTC_reader_group(const char *name, Group *group)
+{
+ return (PTCReader *)PTC::Factory::alembic->create_writer_group(name, group);
+}
diff --git a/source/blender/pointcache/PTC_api.h b/source/blender/pointcache/PTC_api.h
new file mode 100644
index 00000000000..1795d2b68c6
--- /dev/null
+++ b/source/blender/pointcache/PTC_api.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __PTC_API_H__
+#define __PTC_API_H__
+
+#include "util/util_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct tm;
+
+struct Main;
+struct Scene;
+struct EvaluationContext;
+struct ListBase;
+struct PointerRNA;
+struct ReportList;
+struct CacheArchiveInfo;
+
+struct DupliCache;
+struct ClothModifierData;
+struct DerivedMesh;
+struct Group;
+struct IDProperty;
+struct ModifierData;
+struct Object;
+struct ParticleSystem;
+struct SoftBody;
+
+struct PTCWriterArchive;
+struct PTCReaderArchive;
+struct PTCWriter;
+struct PTCReader;
+
+void PTC_alembic_init(void);
+
+/*** Error Handling ***/
+void PTC_error_handler_std(void);
+void PTC_error_handler_callback(PTCErrorCallback cb, void *userdata);
+void PTC_error_handler_reports(struct ReportList *reports);
+void PTC_error_handler_modifier(struct ModifierData *md);
+
+/*** Archive ***/
+
+const char *PTC_get_default_archive_extension(void);
+
+struct PTCWriterArchive *PTC_open_writer_archive(double fps, float start_frame, const char *path, PTCArchiveResolution resolutions,
+ const char *app_name, const char *description, const struct tm *time, struct IDProperty *metadata);
+void PTC_close_writer_archive(struct PTCWriterArchive *archive);
+void PTC_writer_archive_use_render(struct PTCWriterArchive *archive, bool enable);
+
+struct PTCReaderArchive *PTC_open_reader_archive(struct Scene *scene, const char *path);
+struct PTCReaderArchive *PTC_open_reader_archive_ex(double fps, float start_frame, const char *path);
+void PTC_close_reader_archive(struct PTCReaderArchive *archive);
+PTCArchiveResolution PTC_reader_archive_get_resolutions(struct PTCReaderArchive *archive);
+void PTC_reader_archive_use_render(struct PTCReaderArchive *archive, bool enable);
+
+void PTC_writer_init(struct PTCWriter *writer, struct PTCWriterArchive *archive);
+void PTC_writer_create_refs(struct PTCWriter *writer);
+void PTC_reader_init(struct PTCReader *reader, struct PTCReaderArchive *archive);
+
+/*** Reader/Writer Interface ***/
+
+void PTC_writer_free(struct PTCWriter *writer);
+void PTC_write_sample(struct PTCWriter *writer);
+
+void PTC_reader_free(struct PTCReader *reader);
+bool PTC_reader_get_frame_range(struct PTCReader *reader, int *start_frame, int *end_frame);
+PTCReadSampleResult PTC_read_sample(struct PTCReader *reader, float frame);
+PTCReadSampleResult PTC_test_sample(struct PTCReader *reader, float frame);
+
+void PTC_get_archive_info_stream(struct PTCReaderArchive *archive, void (*stream)(void *, const char *), void *userdata);
+void PTC_get_archive_info(struct PTCReaderArchive *_archive, struct CacheArchiveInfo *info, struct IDProperty *metadata);
+void PTC_get_archive_info_nodes(struct PTCReaderArchive *_archive, struct CacheArchiveInfo *info, bool calc_bytes_size);
+
+void PTC_archive_slice(struct PTCReaderArchive *in, struct PTCWriterArchive *out, float start_frame, float end_frame);
+
+struct PTCWriter *PTC_writer_dupligroup(const char *name, struct EvaluationContext *eval_ctx, struct Scene *scene, struct Group *group, struct CacheLibrary *cachelib);
+struct PTCWriter *PTC_writer_duplicache(const char *name, struct Group *group, struct DupliCache *dupcache, int datatypes, bool do_sim_debug);
+
+struct PTCReader *PTC_reader_duplicache(const char *name, struct Group *group, struct DupliCache *dupcache,
+ bool read_strands_motion, bool read_strands_children, bool read_sim_debug);
+struct PTCReader *PTC_reader_duplicache_object(const char *name, struct Object *ob, struct DupliObjectData *data,
+ bool read_strands_motion, bool read_strands_children);
+
+/* get writer/reader from RNA type */
+struct PTCWriter *PTC_writer_from_rna(struct Scene *scene, struct PointerRNA *ptr);
+struct PTCReader *PTC_reader_from_rna(struct Scene *scene, struct PointerRNA *ptr);
+
+/* Object */
+struct PTCWriter *PTC_writer_object(const char *name, struct Scene *scene, struct Object *ob);
+struct PTCReader *PTC_reader_object(const char *name, struct Object *ob);
+
+/* Group */
+struct PTCWriter *PTC_writer_group(const char *name, struct Group *group);
+struct PTCReader *PTC_reader_group(const char *name, struct Group *group);
+
+/* Cloth */
+struct PTCWriter *PTC_writer_cloth(const char *name, struct Object *ob, struct ClothModifierData *clmd);
+struct PTCReader *PTC_reader_cloth(const char *name, struct Object *ob, struct ClothModifierData *clmd);
+
+struct PTCWriter *PTC_writer_derived_mesh(const char *name, struct Object *ob, struct DerivedMesh **dm_ptr);
+struct PTCReader *PTC_reader_derived_mesh(const char *name, struct Object *ob);
+struct DerivedMesh *PTC_reader_derived_mesh_acquire_result(struct PTCReader *reader);
+void PTC_reader_derived_mesh_discard_result(struct PTCReader *reader);
+
+struct PTCWriter *PTC_writer_derived_final_realtime(const char *name, struct Object *ob);
+struct PTCWriter *PTC_writer_derived_final_render(const char *name, struct Scene *scene, struct Object *ob, struct DerivedMesh **render_dm_ptr);
+
+#ifdef __cplusplus
+} /* extern C */
+#endif
+
+#endif /* __PTC_API_H__ */
diff --git a/source/blender/pointcache/SConscript b/source/blender/pointcache/SConscript
new file mode 100644
index 00000000000..f94bbd43668
--- /dev/null
+++ b/source/blender/pointcache/SConscript
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+#
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2014, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Lukas Toenne.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+Import ('env')
+
+sources = env.Glob('intern/*.cpp') + env.Glob('util/*.cpp') + env.Glob('*.cpp')
+
+incs = [
+ '.',
+ 'intern',
+ 'util',
+ '../blenkernel',
+ '../blenlib',
+ '../makesdna',
+ '../makesrna',
+ '../../../intern/guardedalloc',
+ ]
+
+defs = []
+
+if not env['WITH_BF_CPP11']:
+ incs.append(env['BF_BOOST_INC'])
+
+if env['WITH_BF_INTERNATIONAL']:
+ defs.append('WITH_INTERNATIONAL')
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
+ incs.append(env['BF_PTHREADS_INC'])
+
+if env['WITH_BF_ALEMBIC']:
+ defs.append('WITH_PTC_ALEMBIC')
+ SConscript(['alembic/SConscript'])
+
+env.BlenderLib('bf_pointcache', sources, incs, defines=defs, libtype=['core','player'], priority=[902,902])
diff --git a/source/blender/pointcache/alembic/CMakeLists.txt b/source/blender/pointcache/alembic/CMakeLists.txt
new file mode 100644
index 00000000000..d7391428d5d
--- /dev/null
+++ b/source/blender/pointcache/alembic/CMakeLists.txt
@@ -0,0 +1,75 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2013, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ../
+ ../intern
+ ../util
+ ../../blenkernel
+ ../../blenlib
+ ../../makesdna
+ ../../makesrna
+ ../../../../intern/guardedalloc
+)
+
+set(INC_SYS
+ ${ALEMBIC_INCLUDE_DIRS}
+ ${OPENEXR_INCLUDE_DIR}/OpenEXR
+)
+
+set(SRC
+ alembic.cpp
+ alembic.h
+
+ abc_frame_mapper.cpp
+ abc_frame_mapper.h
+ abc_info.cpp
+ abc_interpolate.cpp
+ abc_interpolate.h
+ abc_reader.cpp
+ abc_reader.h
+ abc_schema.h
+ abc_split.cpp
+ abc_writer.cpp
+ abc_writer.h
+
+ abc_cloth.cpp
+ abc_cloth.h
+ abc_customdata.cpp
+ abc_customdata.h
+ abc_group.cpp
+ abc_group.h
+ abc_mesh.cpp
+ abc_mesh.h
+ abc_object.cpp
+ abc_object.h
+ abc_particles.cpp
+ abc_particles.h
+ abc_simdebug.cpp
+ abc_simdebug.h
+)
+
+add_definitions(-DWITH_ALEMBIC)
+
+blender_add_lib(bf_pointcache_alembic "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/pointcache/alembic/SConscript b/source/blender/pointcache/alembic/SConscript
new file mode 100644
index 00000000000..b9da2df57c2
--- /dev/null
+++ b/source/blender/pointcache/alembic/SConscript
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+#
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2014, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Lukas Toenne.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+Import ('env')
+
+sources = env.Glob('*.cpp')
+
+incs = [
+ '.',
+ '../',
+ '../intern',
+ '../util',
+ '../../blenkernel',
+ '../../blenlib',
+ '../../makesdna',
+ '../../makesrna',
+ '../../../../intern/guardedalloc',
+ ]
+
+incs += Split(env['BF_OPENEXR_INC'])
+
+defs = []
+
+if env['WITH_BF_INTERNATIONAL']:
+ defs.append('WITH_INTERNATIONAL')
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
+ incs.append(env['BF_PTHREADS_INC'])
+
+incs.append(env['BF_OPENEXR_INC'])
+incs.append(env['BF_ALEMBIC_INC'])
+
+if not env['WITH_BF_CPP11']:
+ incs.append(env['BF_BOOST_INC'])
+
+defs.append('WITH_ALEMBIC')
+
+env.BlenderLib('bf_pointcache_alembic', sources, incs, defines=defs, libtype=['core','player'], priority=[901, 901])
diff --git a/source/blender/pointcache/alembic/abc_cloth.cpp b/source/blender/pointcache/alembic/abc_cloth.cpp
new file mode 100644
index 00000000000..a722bc2b725
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_cloth.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "abc_cloth.h"
+
+extern "C" {
+#include "BLI_math.h"
+
+#include "DNA_cloth_types.h"
+#include "DNA_object_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BKE_cloth.h"
+}
+
+#include "PTC_api.h"
+
+namespace PTC {
+
+using namespace Abc;
+using namespace AbcGeom;
+
+AbcClothWriter::AbcClothWriter(const std::string &name, Object *ob, ClothModifierData *clmd) :
+ ClothWriter(ob, clmd, name)
+{
+ set_error_handler(new ModifierErrorHandler(&clmd->modifier));
+}
+
+AbcClothWriter::~AbcClothWriter()
+{
+}
+
+void AbcClothWriter::init_abc(OObject parent)
+{
+ if (m_points)
+ return;
+
+ m_points = OPoints(parent, m_name, abc_archive()->frame_sampling_index());
+
+ OPointsSchema &schema = m_points.getSchema();
+ OCompoundProperty geom_params = schema.getArbGeomParams();
+
+ m_param_velocities = OV3fGeomParam(geom_params, "velocities", false, kVaryingScope, 1, 0);
+ m_param_goal_positions = OP3fGeomParam(geom_params, "goal_positions", false, kVaryingScope, 1, 0);
+}
+
+static V3fArraySample create_sample_velocities(Cloth *cloth, std::vector<V3f> &data)
+{
+ ClothVertex *vert;
+ int i, totvert = cloth->numverts;
+
+ data.reserve(totvert);
+ for (i = 0, vert = cloth->verts; i < totvert; ++i, ++vert) {
+ float *co = vert->v;
+ data.push_back(V3f(co[0], co[1], co[2]));
+ }
+
+ return V3fArraySample(data);
+}
+
+static P3fArraySample create_sample_goal_positions(Cloth *cloth, std::vector<V3f> &data)
+{
+ ClothVertex *vert;
+ int i, totvert = cloth->numverts;
+
+ data.reserve(totvert);
+ for (i = 0, vert = cloth->verts; i < totvert; ++i, ++vert) {
+ float *co = vert->xconst;
+ data.push_back(V3f(co[0], co[1], co[2]));
+ }
+
+ return P3fArraySample(data);
+}
+
+void AbcClothWriter::write_sample()
+{
+ if (!m_points)
+ return;
+
+ Cloth *cloth = m_clmd->clothObject;
+ if (!cloth)
+ return;
+
+ OPointsSchema &schema = m_points.getSchema();
+
+ int totpoint = cloth->numverts;
+ ClothVertex *vert;
+ int i;
+
+ /* XXX TODO only needed for the first frame/sample */
+ std::vector<Util::uint64_t> ids;
+ ids.reserve(totpoint);
+ for (i = 0, vert = cloth->verts; i < totpoint; ++i, ++vert)
+ ids.push_back(i);
+
+ std::vector<V3f> positions;
+ positions.reserve(totpoint);
+ for (i = 0, vert = cloth->verts; i < totpoint; ++i, ++vert) {
+ float *co = vert->x;
+ positions.push_back(V3f(co[0], co[1], co[2]));
+ }
+
+ std::vector<V3f> velocities_buffer;
+ std::vector<V3f> goal_positions_buffer;
+ V3fArraySample velocities = create_sample_velocities(cloth, velocities_buffer);
+ P3fArraySample goal_positions = create_sample_goal_positions(cloth, goal_positions_buffer);
+
+ OPointsSchema::Sample sample = OPointsSchema::Sample(V3fArraySample(positions), UInt64ArraySample(ids));
+ schema.set(sample);
+
+ m_param_velocities.set(OV3fGeomParam::Sample(velocities, kVaryingScope));
+ m_param_goal_positions.set(OP3fGeomParam::Sample(goal_positions, kVaryingScope));
+}
+
+
+AbcClothReader::AbcClothReader(const std::string &name, Object *ob, ClothModifierData *clmd) :
+ ClothReader(ob, clmd, name)
+{
+ set_error_handler(new ModifierErrorHandler(&clmd->modifier));
+}
+
+AbcClothReader::~AbcClothReader()
+{
+}
+
+void AbcClothReader::init_abc(IObject object)
+{
+ if (m_points)
+ return;
+ m_points = IPoints(object, kWrapExisting);
+
+ IPointsSchema &schema = m_points.getSchema();
+ ICompoundProperty geom_params = schema.getArbGeomParams();
+
+ m_param_velocities = IV3fGeomParam(geom_params, "velocities", 0);
+ m_param_goal_positions = IP3fGeomParam(geom_params, "goal_positions", 0);
+}
+
+static void apply_sample_positions(Cloth *cloth, P3fArraySamplePtr sample)
+{
+ ClothVertex *vert;
+ int i, totvert = cloth->numverts;
+
+ BLI_assert(sample->size() == totvert);
+
+ const V3f *data = sample->get();
+ for (i = 0, vert = cloth->verts; i < totvert; ++i, ++vert) {
+ const V3f &co = data[i];
+ copy_v3_v3(vert->x, co.getValue());
+ }
+}
+
+static void apply_sample_velocities(Cloth *cloth, V3fArraySamplePtr sample)
+{
+ ClothVertex *vert;
+ int i, totvert = cloth->numverts;
+
+ BLI_assert(sample->size() == totvert);
+
+ const V3f *data = sample->get();
+ for (i = 0, vert = cloth->verts; i < totvert; ++i, ++vert) {
+ const V3f &vel = data[i];
+ copy_v3_v3(vert->v, vel.getValue());
+ }
+}
+
+static void apply_sample_goal_positions(Cloth *cloth, P3fArraySamplePtr sample)
+{
+ ClothVertex *vert;
+ int i, totvert = cloth->numverts;
+
+ BLI_assert(sample->size() == totvert);
+
+ const V3f *data = sample->get();
+ for (i = 0, vert = cloth->verts; i < totvert; ++i, ++vert) {
+ const V3f &co = data[i];
+ copy_v3_v3(vert->xconst, co.getValue());
+ }
+}
+
+PTCReadSampleResult AbcClothReader::read_sample_abc(chrono_t time)
+{
+ Cloth *cloth = m_clmd->clothObject;
+
+ if (!m_points)
+ return PTC_READ_SAMPLE_INVALID;
+
+ IPointsSchema &schema = m_points.getSchema();
+ if (schema.getNumSamples() == 0)
+ return PTC_READ_SAMPLE_INVALID;
+
+ ISampleSelector ss = get_frame_sample_selector(time);
+
+ IPointsSchema::Sample sample;
+ schema.get(sample, ss);
+
+ P3fArraySamplePtr positions = sample.getPositions();
+
+ V3fArraySamplePtr velocities;
+ if (m_param_velocities && m_param_velocities.getNumSamples() > 0) {
+ IV3fGeomParam::Sample sample_velocities;
+ m_param_velocities.getExpanded(sample_velocities, ss);
+ velocities = sample_velocities.getVals();
+ }
+
+ P3fArraySamplePtr goal_positions;
+ if (m_param_goal_positions && m_param_goal_positions.getNumSamples() > 0) {
+ IP3fGeomParam::Sample sample_goal_positions;
+ m_param_goal_positions.getExpanded(sample_goal_positions, ss);
+ goal_positions = sample_goal_positions.getVals();
+ }
+
+ apply_sample_positions(cloth, positions);
+ if (velocities)
+ apply_sample_velocities(cloth, velocities);
+ if (goal_positions)
+ apply_sample_goal_positions(cloth, goal_positions);
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/alembic/abc_cloth.h b/source/blender/pointcache/alembic/abc_cloth.h
new file mode 100644
index 00000000000..9b30b183a6c
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_cloth.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_ABC_CLOTH_H
+#define PTC_ABC_CLOTH_H
+
+#include <Alembic/AbcGeom/IPoints.h>
+#include <Alembic/AbcGeom/OPoints.h>
+
+#include "ptc_types.h"
+
+#include "abc_reader.h"
+#include "abc_schema.h"
+#include "abc_writer.h"
+
+struct Object;
+struct ClothModifierData;
+
+namespace PTC {
+
+class AbcClothWriter : public ClothWriter, public AbcWriter {
+public:
+ AbcClothWriter(const std::string &name, Object *ob, ClothModifierData *clmd);
+ ~AbcClothWriter();
+
+ void init_abc(Abc::OObject parent);
+
+ void write_sample();
+
+private:
+ AbcGeom::OPoints m_points;
+ AbcGeom::OV3fGeomParam m_param_velocities;
+ AbcGeom::OP3fGeomParam m_param_goal_positions;
+};
+
+class AbcClothReader : public ClothReader, public AbcReader {
+public:
+ AbcClothReader(const std::string &name, Object *ob, ClothModifierData *clmd);
+ ~AbcClothReader();
+
+ void init_abc(Abc::IObject parent);
+
+ PTCReadSampleResult read_sample_abc(chrono_t time);
+
+private:
+ AbcGeom::IPoints m_points;
+ AbcGeom::IV3fGeomParam m_param_velocities;
+ AbcGeom::IP3fGeomParam m_param_goal_positions;
+};
+
+} /* namespace PTC */
+
+#endif /* PTC_CLOTH_H */
diff --git a/source/blender/pointcache/alembic/abc_customdata.cpp b/source/blender/pointcache/alembic/abc_customdata.cpp
new file mode 100644
index 00000000000..77a9ea73a5b
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_customdata.cpp
@@ -0,0 +1,804 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <sstream>
+
+#include <Alembic/AbcGeom/IGeomParam.h>
+#include <Alembic/AbcGeom/OGeomParam.h>
+
+#include "abc_customdata.h"
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_customdata_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_customdata.h"
+}
+
+namespace PTC {
+
+using namespace Abc;
+using namespace AbcGeom;
+
+/* DEBUG */
+BLI_INLINE void print_writer_compound(OCompoundProperty &prop)
+{
+ CompoundPropertyWriterPtr ptr = prop.getPtr()->asCompoundPtr();
+ printf("compound %s: [%p] (%d)\n", ptr->getName().c_str(), ptr.get(), (int)ptr->getNumProperties());
+ for (int i = 0; i < ptr->getNumProperties(); ++i) {
+ printf(" %d: [%p]\n", i, prop.getProperty(i).getPtr().get());
+ printf(" %s\n", prop.getProperty(i).getName().c_str());
+ }
+}
+
+/* ========================================================================= */
+
+template <CustomDataType CDTYPE>
+static void write_sample(CustomDataWriter */*writer*/, OCompoundProperty &/*parent*/, const std::string &/*name*/, void */*data*/, int /*num_data*/)
+{
+ /* no implementation available, should not happen */
+ printf("ERROR: CustomData type %s has no write_sample implementation\n", CustomData_layertype_name((int)CDTYPE));
+}
+
+template <>
+void write_sample<CD_MDEFORMVERT>(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void *data, int num_data)
+{
+ OCompoundProperty prop = writer->add_compound_property<OCompoundProperty>(name, parent);
+
+ OInt32ArrayProperty totweight_prop = writer->add_array_property<OInt32ArrayProperty>(name + ":totweight", prop);
+ OInt32ArrayProperty flag_prop = writer->add_array_property<OInt32ArrayProperty>(name + ":flag", prop);
+ OInt32ArrayProperty def_nr_prop = writer->add_array_property<OInt32ArrayProperty>(name + ":def_nr", prop);
+ OFloatArrayProperty weight_prop = writer->add_array_property<OFloatArrayProperty>(name + ":weight", prop);
+
+ MDeformVert *mdef = (MDeformVert *)data;
+
+ /* sum all totweight for the sample size */
+ int num_mdefweight = 0;
+ for (int i = 0; i < num_data; ++i)
+ num_mdefweight += mdef[i].totweight;
+
+ std::vector<int32_t> totweight_data;
+ std::vector<int32_t> flag_data;
+ std::vector<int32_t> def_nr_data;
+ std::vector<float> weight_data;
+ totweight_data.reserve(num_data);
+ flag_data.reserve(num_data);
+ def_nr_data.reserve(num_mdefweight);
+ weight_data.reserve(num_mdefweight);
+
+ for (int i = 0; i < num_data; ++i) {
+ totweight_data.push_back(mdef->totweight);
+ flag_data.push_back(mdef->flag);
+
+ MDeformWeight *mw = mdef->dw;
+ for (int j = 0; j < mdef->totweight; ++j) {
+ def_nr_data.push_back(mw->def_nr);
+ weight_data.push_back(mw->weight);
+
+ ++mw;
+ }
+
+ ++mdef;
+ }
+
+ totweight_prop.set(Int32ArraySample(totweight_data));
+ flag_prop.set(Int32ArraySample(flag_data));
+ def_nr_prop.set(Int32ArraySample(def_nr_data));
+ weight_prop.set(FloatArraySample(weight_data));
+}
+
+template <>
+void write_sample<CD_MTFACE>(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void */*data*/, int /*num_data*/)
+{
+ /* XXX this is a dummy layer, to have access to active render layers etc. */
+ writer->add_compound_property<OCompoundProperty>(name, parent);
+}
+
+template <>
+void write_sample<CD_MCOL>(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void *data, int num_data)
+{
+ OC4fArrayProperty prop = writer->add_array_property<OC4fArrayProperty>(name, parent);
+
+ MCol *mcol = (MCol *)data;
+
+ std::vector<C4f> mcol_data;
+ mcol_data.reserve(num_data);
+ for (int i = 0; i < num_data; ++i) {
+ unsigned char icol[4] = {mcol->r, mcol->g, mcol->b, mcol->a};
+ C4f fcol;
+ rgba_uchar_to_float(fcol.getValue(), icol);
+ mcol_data.push_back(fcol);
+
+ ++mcol;
+ }
+ prop.set(OC4fArrayProperty::sample_type(mcol_data));
+}
+
+template <>
+void write_sample<CD_ORIGINDEX>(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void *data, int num_data)
+{
+ OInt32ArrayProperty prop = writer->add_array_property<OInt32ArrayProperty>(name, parent);
+
+ prop.set(OInt32ArrayProperty::sample_type((int *)data, num_data));
+}
+
+template <>
+void write_sample<CD_NORMAL>(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void *data, int num_data)
+{
+ ON3fArrayProperty prop = writer->add_array_property<ON3fArrayProperty>(name, parent);
+
+ prop.set(ON3fArrayProperty::sample_type((N3f *)data, num_data));
+}
+
+template <>
+void write_sample<CD_ORIGSPACE>(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void *data, int num_data)
+{
+ OCompoundProperty prop = writer->add_compound_property<OCompoundProperty>(name, parent);
+
+ OV2fArrayProperty uv_prop[4];
+ uv_prop[0] = writer->add_array_property<OV2fArrayProperty>(name + ":uv0", prop);
+ uv_prop[1] = writer->add_array_property<OV2fArrayProperty>(name + ":uv1", prop);
+ uv_prop[2] = writer->add_array_property<OV2fArrayProperty>(name + ":uv2", prop);
+ uv_prop[3] = writer->add_array_property<OV2fArrayProperty>(name + ":uv3", prop);
+
+ OrigSpaceFace *ospace = (OrigSpaceFace *)data;
+ std::vector<V2f> uv_data[4];
+ uv_data[0].reserve(num_data);
+ uv_data[1].reserve(num_data);
+ uv_data[2].reserve(num_data);
+ uv_data[3].reserve(num_data);
+ for (int i = 0; i < num_data; ++i) {
+ uv_data[0].push_back(V2f(ospace->uv[0][0], ospace->uv[0][1]));
+ uv_data[1].push_back(V2f(ospace->uv[1][0], ospace->uv[1][1]));
+ uv_data[2].push_back(V2f(ospace->uv[2][0], ospace->uv[2][1]));
+ uv_data[3].push_back(V2f(ospace->uv[3][0], ospace->uv[3][1]));
+
+ ++ospace;
+ }
+ uv_prop[0].set(V2fArraySample(uv_data[0]));
+ uv_prop[1].set(V2fArraySample(uv_data[1]));
+ uv_prop[2].set(V2fArraySample(uv_data[2]));
+ uv_prop[3].set(V2fArraySample(uv_data[3]));
+}
+
+template <>
+void write_sample<CD_ORCO>(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void *data, int num_data)
+{
+ OV3fArrayProperty prop = writer->add_array_property<OV3fArrayProperty>(name, parent);
+
+ prop.set(OV3fArrayProperty::sample_type((V3f *)data, num_data));
+}
+
+template <>
+void write_sample<CD_MTEXPOLY>(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void */*data*/, int /*num_data*/)
+{
+ /* XXX this is a dummy layer, to have access to active render layers etc. */
+ writer->add_compound_property<OCompoundProperty>(name, parent);
+}
+
+template <>
+void write_sample<CD_MLOOPUV>(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void *data, int num_data)
+{
+ OCompoundProperty prop = writer->add_compound_property<OCompoundProperty>(name, parent);
+
+ OV2fArrayProperty prop_uv = writer->add_array_property<OV2fArrayProperty>(name + ":uv", prop);
+ OInt32ArrayProperty prop_flag = writer->add_array_property<OInt32ArrayProperty>(name + ":flag", prop);
+
+ MLoopUV *loop_uv = (MLoopUV *)data;
+ std::vector<V2f> uv_data;
+ std::vector<int32_t> flag_data;
+ uv_data.reserve(num_data);
+ flag_data.reserve(num_data);
+ for (int i = 0; i < num_data; ++i) {
+ uv_data.push_back(V2f(loop_uv->uv[0], loop_uv->uv[1]));
+ flag_data.push_back(loop_uv->flag);
+
+ ++loop_uv;
+ }
+ prop_uv.set(V2fArraySample(uv_data));
+ prop_flag.set(Int32ArraySample(flag_data));
+}
+
+template <>
+void write_sample<CD_MLOOPCOL>(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void *data, int num_data)
+{
+ OCompoundProperty prop = writer->add_compound_property<OCompoundProperty>(name, parent);
+
+ OC4fArrayProperty prop_col = writer->add_array_property<OC4fArrayProperty>(name + ":color", prop);
+
+ MLoopCol *loop_col = (MLoopCol *)data;
+ std::vector<C4f> col_data;
+ col_data.reserve(num_data);
+ for (int i = 0; i < num_data; ++i) {
+ col_data.push_back(C4f(loop_col->r, loop_col->g, loop_col->b, loop_col->a));
+
+ ++loop_col;
+ }
+ prop_col.set(C4fArraySample(col_data));
+}
+
+template <>
+void write_sample<CD_ORIGSPACE_MLOOP>(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void *data, int num_data)
+{
+ OCompoundProperty prop = writer->add_compound_property<OCompoundProperty>(name, parent);
+
+ OV2fArrayProperty prop_uv = writer->add_array_property<OV2fArrayProperty>(name + ":uv", prop);
+
+ OrigSpaceLoop *ospaceloop = (OrigSpaceLoop *)data;
+ std::vector<V2f> uv_data;
+ uv_data.reserve(num_data);
+ for (int i = 0; i < num_data; ++i) {
+ uv_data.push_back(V2f(ospaceloop->uv[0], ospaceloop->uv[1]));
+
+ ++ospaceloop;
+ }
+ prop_uv.set(V2fArraySample(uv_data));
+}
+
+template <>
+void write_sample<CD_MSURFACE_SAMPLE>(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void *data, int num_data)
+{
+ OCompoundProperty prop = writer->add_compound_property<OCompoundProperty>(name, parent);
+
+ OUInt32ArrayProperty prop_orig_verts = writer->add_array_property<OUInt32ArrayProperty>(name + ":orig_verts", prop);
+ OFloatArrayProperty prop_orig_weights = writer->add_array_property<OFloatArrayProperty>(name + ":orig_weights", prop);
+ OInt32ArrayProperty prop_orig_poly = writer->add_array_property<OInt32ArrayProperty>(name + ":orig_poly", prop);
+ OUInt32ArrayProperty prop_orig_loops = writer->add_array_property<OUInt32ArrayProperty>(name + ":orig_loops", prop);
+
+ MSurfaceSample *surf = (MSurfaceSample *)data;
+ std::vector<uint32_t> orig_verts_data;
+ std::vector<float32_t> orig_weights_data;
+ std::vector<int32_t> orig_poly_data;
+ std::vector<uint32_t> orig_loops_data;
+ orig_verts_data.reserve(num_data * 3);
+ orig_weights_data.reserve(num_data * 3);
+ orig_poly_data.reserve(num_data);
+ orig_loops_data.reserve(num_data * 3);
+ for (int i = 0; i < num_data; ++i) {
+ orig_verts_data.push_back(surf->orig_verts[0]);
+ orig_verts_data.push_back(surf->orig_verts[1]);
+ orig_verts_data.push_back(surf->orig_verts[2]);
+ orig_weights_data.push_back(surf->orig_weights[0]);
+ orig_weights_data.push_back(surf->orig_weights[1]);
+ orig_weights_data.push_back(surf->orig_weights[2]);
+ orig_poly_data.push_back(surf->orig_poly);
+ orig_loops_data.push_back(surf->orig_loops[0]);
+ orig_loops_data.push_back(surf->orig_loops[1]);
+ orig_loops_data.push_back(surf->orig_loops[2]);
+
+ ++surf;
+ }
+ prop_orig_verts.set(UInt32ArraySample(orig_verts_data));
+ prop_orig_weights.set(FloatArraySample(orig_weights_data));
+ prop_orig_poly.set(Int32ArraySample(orig_poly_data));
+ prop_orig_loops.set(UInt32ArraySample(orig_loops_data));
+}
+
+/* ------------------------------------------------------------------------- */
+
+template <CustomDataType CDTYPE>
+static PTCReadSampleResult read_sample(CustomDataReader */*reader*/, ICompoundProperty &/*parent*/, const ISampleSelector &/*ss*/, const std::string &/*name*/, void */*data*/, int /*num_data*/)
+{
+ /* no implementation available, should not happen */
+ printf("ERROR: CustomData type %s has no read_sample implementation\n", CustomData_layertype_name((int)CDTYPE));
+ return PTC_READ_SAMPLE_INVALID;
+}
+
+template <>
+PTCReadSampleResult read_sample<CD_MDEFORMVERT>(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, const std::string &name, void *data, int num_data)
+{
+ ICompoundProperty prop = reader->add_compound_property<ICompoundProperty>(name, parent);
+
+ IInt32ArrayProperty totweight_prop = reader->add_array_property<IInt32ArrayProperty>(name + ":totweight", prop);
+ IInt32ArrayProperty flag_prop = reader->add_array_property<IInt32ArrayProperty>(name + ":flag", prop);
+ IInt32ArrayProperty def_nr_prop = reader->add_array_property<IInt32ArrayProperty>(name + ":def_nr", prop);
+ IFloatArrayProperty weight_prop = reader->add_array_property<IFloatArrayProperty>(name + ":weight", prop);
+
+ Int32ArraySamplePtr sample_totweight = totweight_prop.getValue(ss);
+ Int32ArraySamplePtr sample_flag = flag_prop.getValue(ss);
+ Int32ArraySamplePtr sample_def_nr = def_nr_prop.getValue(ss);
+ FloatArraySamplePtr sample_weight = weight_prop.getValue(ss);
+
+ if (sample_totweight->size() != num_data ||
+ sample_flag->size() != num_data)
+ {
+ return PTC_READ_SAMPLE_INVALID;
+ }
+
+ const int32_t *data_totweight = (const int32_t *)sample_totweight->getData();
+ const int32_t *data_flag = (const int32_t *)sample_flag->getData();
+ const int32_t *data_def_nr = (const int32_t *)sample_def_nr->getData();
+ const float *data_weight = (const float *)sample_weight->getData();
+
+ MDeformVert *mdef = (MDeformVert *)data;
+ for (int i = 0; i < num_data; ++i) {
+
+ mdef->totweight = *data_totweight;
+ mdef->flag = *data_flag;
+
+ MDeformWeight *mw = mdef->dw = (MDeformWeight *)MEM_mallocN(sizeof(MDeformWeight) * mdef->totweight, "deformWeight");
+ for (int j = 0; j < mdef->totweight; ++j) {
+ mw->def_nr = *data_def_nr;
+ mw->weight = *data_weight;
+
+ ++data_def_nr;
+ ++data_weight;
+ ++mw;
+ }
+
+ ++data_totweight;
+ ++data_flag;
+ ++mdef;
+ }
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+template <>
+PTCReadSampleResult read_sample<CD_MTFACE>(CustomDataReader */*reader*/, ICompoundProperty &/*parent*/, const ISampleSelector &/*ss*/, const std::string &/*name*/, void */*data*/, int /*num_data*/)
+{
+ /* XXX this is a dummy layer, to have access to active render layers etc. */
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+template <>
+PTCReadSampleResult read_sample<CD_MCOL>(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, const std::string &name, void *data, int num_data)
+{
+ IC4fArrayProperty prop = reader->add_array_property<IC4fArrayProperty>(name, parent);
+
+ C4fArraySamplePtr sample = prop.getValue(ss);
+
+ if (sample->size() != num_data)
+ return PTC_READ_SAMPLE_INVALID;
+
+ MCol *mcol = (MCol *)data;
+ C4f *data_mcol = (C4f *)sample->getData();
+ for (int i = 0; i < num_data; ++i) {
+ unsigned char icol[4];
+ rgba_float_to_uchar(icol, data_mcol->getValue());
+ mcol->r = icol[0];
+ mcol->g = icol[1];
+ mcol->b = icol[2];
+ mcol->a = icol[3];
+
+ ++data_mcol;
+ ++mcol;
+ }
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+template <>
+PTCReadSampleResult read_sample<CD_ORIGINDEX>(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, const std::string &name, void *data, int num_data)
+{
+ IInt32ArrayProperty prop = reader->add_array_property<IInt32ArrayProperty>(name, parent);
+
+ Int32ArraySamplePtr sample = prop.getValue(ss);
+
+ if (sample->size() != num_data)
+ return PTC_READ_SAMPLE_INVALID;
+
+ memcpy(data, sample->getData(), sizeof(int32_t) * num_data);
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+template <>
+PTCReadSampleResult read_sample<CD_NORMAL>(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, const std::string &name, void *data, int num_data)
+{
+ IN3fArrayProperty prop = reader->add_array_property<IN3fArrayProperty>(name, parent);
+
+ N3fArraySamplePtr sample = prop.getValue(ss);
+
+ if (sample->size() != num_data)
+ return PTC_READ_SAMPLE_INVALID;
+
+ memcpy(data, sample->getData(), sizeof(N3f) * num_data);
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+template <>
+PTCReadSampleResult read_sample<CD_ORIGSPACE>(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, const std::string &name, void *data, int num_data)
+{
+ ICompoundProperty prop = reader->add_compound_property<ICompoundProperty>(name, parent);
+
+ IV2fArrayProperty uv_prop[4];
+ uv_prop[0] = reader->add_array_property<IV2fArrayProperty>(name + ":uv0", prop);
+ uv_prop[1] = reader->add_array_property<IV2fArrayProperty>(name + ":uv1", prop);
+ uv_prop[2] = reader->add_array_property<IV2fArrayProperty>(name + ":uv2", prop);
+ uv_prop[3] = reader->add_array_property<IV2fArrayProperty>(name + ":uv3", prop);
+
+ V2fArraySamplePtr sample0 = uv_prop[0].getValue(ss);
+ V2fArraySamplePtr sample1 = uv_prop[1].getValue(ss);
+ V2fArraySamplePtr sample2 = uv_prop[2].getValue(ss);
+ V2fArraySamplePtr sample3 = uv_prop[3].getValue(ss);
+
+ if (sample0->size() != num_data ||
+ sample1->size() != num_data ||
+ sample2->size() != num_data ||
+ sample3->size() != num_data)
+ {
+ return PTC_READ_SAMPLE_INVALID;
+ }
+
+ OrigSpaceFace *ospace = (OrigSpaceFace *)data;
+ const V2f *data0 = (const V2f *)sample0->getData();
+ const V2f *data1 = (const V2f *)sample1->getData();
+ const V2f *data2 = (const V2f *)sample2->getData();
+ const V2f *data3 = (const V2f *)sample3->getData();
+ for (int i = 0; i < num_data; ++i) {
+ copy_v2_v2(ospace->uv[0], data0->getValue());
+ copy_v2_v2(ospace->uv[1], data1->getValue());
+ copy_v2_v2(ospace->uv[2], data2->getValue());
+ copy_v2_v2(ospace->uv[3], data3->getValue());
+
+ ++data0;
+ ++data1;
+ ++data2;
+ ++data3;
+ ++ospace;
+ }
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+template <>
+PTCReadSampleResult read_sample<CD_ORCO>(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, const std::string &name, void *data, int num_data)
+{
+ IV3fArrayProperty prop = reader->add_array_property<IV3fArrayProperty>(name, parent);
+
+ V3fArraySamplePtr sample = prop.getValue(ss);
+
+ if (sample->size() != num_data)
+ return PTC_READ_SAMPLE_INVALID;
+
+ memcpy(data, sample->getData(), sizeof(V3f) * num_data);
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+template <>
+PTCReadSampleResult read_sample<CD_MTEXPOLY>(CustomDataReader */*reader*/, ICompoundProperty &/*parent*/, const ISampleSelector &/*ss*/, const std::string &/*name*/, void */*data*/, int /*num_data*/)
+{
+ /* XXX this is a dummy layer, to have access to active render layers etc. */
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+template <>
+PTCReadSampleResult read_sample<CD_MLOOPUV>(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, const std::string &name, void *data, int num_data)
+{
+ ICompoundProperty prop = reader->add_compound_property<ICompoundProperty>(name, parent);
+
+ IV2fArrayProperty uv_prop = reader->add_array_property<IV2fArrayProperty>(name + ":uv", prop);
+ IInt32ArrayProperty flag_prop = reader->add_array_property<IInt32ArrayProperty>(name + ":flag", prop);
+
+ V2fArraySamplePtr uv_sample = uv_prop.getValue(ss);
+ Int32ArraySamplePtr flag_sample = flag_prop.getValue(ss);
+
+ if (uv_sample->size() != num_data || flag_sample->size() != num_data)
+ return PTC_READ_SAMPLE_INVALID;
+
+ MLoopUV *loop_uv = (MLoopUV *)data;
+ const V2f *uv_data = (const V2f *)uv_sample->getData();
+ const int32_t *flag_data = (const int32_t *)flag_sample->getData();
+ for (int i = 0; i < num_data; ++i) {
+ copy_v2_v2(loop_uv->uv, uv_data->getValue());
+ loop_uv->flag = *flag_data;
+
+ ++uv_data;
+ ++flag_data;
+ ++loop_uv;
+ }
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+template <>
+PTCReadSampleResult read_sample<CD_MLOOPCOL>(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, const std::string &name, void *data, int num_data)
+{
+ ICompoundProperty prop = reader->add_compound_property<ICompoundProperty>(name, parent);
+
+ IC4fArrayProperty col_prop = reader->add_array_property<IC4fArrayProperty>(name + ":color", prop);
+
+ C4fArraySamplePtr col_sample = col_prop.getValue(ss);
+
+ if (col_sample->size() != num_data)
+ return PTC_READ_SAMPLE_INVALID;
+
+ MLoopCol *loop_col = (MLoopCol *)data;
+ const C4f *col_data = (const C4f *)col_sample->getData();
+ for (int i = 0; i < num_data; ++i) {
+ loop_col->r = col_data->r;
+ loop_col->g = col_data->g;
+ loop_col->b = col_data->b;
+ loop_col->a = col_data->a;
+
+ ++col_data;
+ ++loop_col;
+ }
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+template <>
+PTCReadSampleResult read_sample<CD_ORIGSPACE_MLOOP>(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, const std::string &name, void *data, int num_data)
+{
+ ICompoundProperty prop = reader->add_compound_property<ICompoundProperty>(name, parent);
+
+ IV2fArrayProperty uv_prop = reader->add_array_property<IV2fArrayProperty>(name + ":uv", prop);
+
+ V2fArraySamplePtr sample = uv_prop.getValue(ss);
+
+ if (sample->size() != num_data)
+ return PTC_READ_SAMPLE_INVALID;
+
+ OrigSpaceLoop *ospace = (OrigSpaceLoop *)data;
+ const V2f *sample_data = (const V2f *)sample->getData();
+ for (int i = 0; i < num_data; ++i) {
+ copy_v2_v2(ospace->uv, sample_data->getValue());
+
+ ++sample_data;
+ ++ospace;
+ }
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+template <>
+PTCReadSampleResult read_sample<CD_MSURFACE_SAMPLE>(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, const std::string &name, void *data, int num_data)
+{
+ ICompoundProperty prop = reader->add_compound_property<ICompoundProperty>(name, parent);
+
+ IUInt32ArrayProperty orig_verts_prop = reader->add_array_property<IUInt32ArrayProperty>(name + ":orig_verts", prop);
+ IFloatArrayProperty orig_weights_prop = reader->add_array_property<IFloatArrayProperty>(name + ":orig_weights", prop);
+ IInt32ArrayProperty orig_poly_prop = reader->add_array_property<IInt32ArrayProperty>(name + ":orig_poly", prop);
+ IUInt32ArrayProperty orig_loops_prop = reader->add_array_property<IUInt32ArrayProperty>(name + ":orig_loops", prop);
+
+ UInt32ArraySamplePtr orig_verts_sample = orig_verts_prop.getValue(ss);
+ FloatArraySamplePtr orig_weights_sample = orig_weights_prop.getValue(ss);
+ Int32ArraySamplePtr orig_poly_sample = orig_poly_prop.getValue(ss);
+ UInt32ArraySamplePtr orig_loops_sample = orig_loops_prop.getValue(ss);
+
+ if (orig_verts_sample->size() != num_data*3 ||
+ orig_weights_sample->size() != num_data*3 ||
+ orig_poly_sample->size() != num_data ||
+ orig_loops_sample->size() != num_data*3)
+ return PTC_READ_SAMPLE_INVALID;
+
+ MSurfaceSample *surf = (MSurfaceSample *)data;
+ const uint32_t *orig_verts_data = (const uint32_t *)orig_verts_sample->getData();
+ const float32_t *orig_weights_data = (const float32_t *)orig_weights_sample->getData();
+ const int32_t *orig_poly_data = (const int32_t *)orig_poly_sample->getData();
+ const uint32_t *orig_loops_data = (const uint32_t *)orig_loops_sample->getData();
+ for (int i = 0; i < num_data; ++i) {
+ surf->orig_verts[0] = orig_verts_data[0];
+ surf->orig_verts[1] = orig_verts_data[1];
+ surf->orig_verts[2] = orig_verts_data[2];
+ surf->orig_weights[0] = orig_weights_data[0];
+ surf->orig_weights[1] = orig_weights_data[1];
+ surf->orig_weights[2] = orig_weights_data[2];
+ surf->orig_poly = *orig_poly_data;
+ surf->orig_loops[0] = orig_loops_data[0];
+ surf->orig_loops[1] = orig_loops_data[1];
+ surf->orig_loops[2] = orig_loops_data[2];
+
+ orig_verts_data += 3;
+ orig_weights_data += 3;
+ orig_poly_data += 1;
+ orig_loops_data += 3;
+ ++surf;
+ }
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+/* ========================================================================= */
+
+/* recursive template that handles dispatch by CD layer type */
+template <int CDTYPE>
+BLI_INLINE void write_sample_call(CustomDataWriter *writer, OCompoundProperty &parent, CustomDataType type, const std::string &name, void *data, int num_data)
+{
+ if (type == CDTYPE)
+ write_sample<(CustomDataType)CDTYPE>(writer, parent, name, data, num_data);
+ else
+ write_sample_call<CDTYPE + 1>(writer, parent, type, name, data, num_data);
+}
+
+/* terminator specialization */
+template <>
+void write_sample_call<CD_NUMTYPES>(CustomDataWriter */*writer*/, OCompoundProperty &/*parent*/, CustomDataType /*type*/, const std::string &/*name*/, void */*data*/, int /*num_data*/)
+{
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* recursive template that handles dispatch by CD layer type */
+template <int CDTYPE>
+BLI_INLINE PTCReadSampleResult read_sample_call(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, CustomDataType type, const std::string &name, void *data, int num_data)
+{
+ if (type == CDTYPE)
+ return read_sample<(CustomDataType)CDTYPE>(reader, parent, ss, name, data, num_data);
+ else
+ return read_sample_call<CDTYPE + 1>(reader, parent, ss, type, name, data, num_data);
+}
+
+/* terminator specialization */
+template <>
+PTCReadSampleResult read_sample_call<CD_NUMTYPES>(CustomDataReader */*reader*/, ICompoundProperty &/*parent*/, const ISampleSelector &/*ss*/, CustomDataType /*type*/, const std::string &/*name*/, void */*data*/, int /*num_data*/)
+{
+ return PTC_READ_SAMPLE_INVALID;
+}
+
+/* ========================================================================= */
+
+CustomDataWriter::CustomDataWriter(const std::string &name, CustomDataMask cdmask) :
+ m_name(name),
+ m_cdmask(cdmask)
+{
+}
+
+CustomDataWriter::~CustomDataWriter()
+{
+ for (LayerPropsMap::iterator it = m_layer_props.begin(); it != m_layer_props.end(); ++it) {
+ BasePropertyWriterPtr prop = it->second;
+ if (prop)
+ prop.reset();
+ }
+}
+
+void CustomDataWriter::init(TimeSamplingPtr time_sampling)
+{
+ m_time_sampling = time_sampling;
+}
+
+/* unique property name based on either layer name or index */
+std::string CustomDataWriter::cdtype_to_name(CustomData *cdata, CustomDataType type, int n)
+{
+ const char *layertype_name = CustomData_layertype_name(type);
+ const char *layer_name = CustomData_get_layer_name(cdata, type, n);
+ std::string name;
+ if (layer_name && layer_name[0] != '\0') {
+ name = m_name + ":" + std::string(layertype_name) + ":S" + std::string(layer_name);
+ }
+ else {
+ std::stringstream ss; ss << n;
+ name = m_name + ":" + std::string(layertype_name) + ":N" + ss.str();
+ }
+ return name;
+}
+
+/* parse property name to CD layer name based on S or N prefix for named/unnamed layers */
+void CustomDataReader::cdtype_from_name(CustomData */*cdata*/, const std::string &name, int type, int *n, char *layer_name, int max_layer_name)
+{
+ const char *layertype_name = CustomData_layertype_name(type);
+ /* We can safely assume all properties in the compound share the correct prefix
+ * <m_name>:<layertype_name>:
+ * The layertype_name is only prepended to avoid name collisions
+ */
+ const size_t start = m_name.size() + 1 + strlen(layertype_name) + 1;
+
+ if (name.size() <= start) {
+ printf("ERROR: invalid CustomData layer property name '%s'\n", name.c_str());
+ *n = -1;
+ layer_name[0] = '\0';
+ }
+ else if (name[start] == 'S') {
+ /* named layer */
+ *n = -1;
+ BLI_strncpy(layer_name, name.c_str() + start + 1, max_layer_name);
+ }
+ else if (name[start] == 'N') {
+ /* unnamed layer */
+ std::istringstream ss(name.c_str() + start + 1);
+ ss >> (*n);
+ layer_name[0] = '\0';
+ }
+ else {
+ *n = -1;
+ layer_name[0] = '\0';
+ }
+}
+
+void CustomDataWriter::write_sample(CustomData *cdata, int num_data, OCompoundProperty &parent)
+{
+ /* compound property for all CD layers in the CustomData instance */
+ m_props = add_compound_property<OCompoundProperty>(m_name, parent);
+
+ for (int type = 0; type < CD_NUMTYPES; ++type) {
+ CustomDataMask mask = (1ull << type);
+ /* only use specified types */
+ if (!(mask & m_cdmask))
+ continue;
+
+ const char *layertype_name = CustomData_layertype_name(type);
+ int num = CustomData_number_of_layers(cdata, type);
+
+ bool has_props = false;
+ OCompoundProperty layertype_props;
+ for (int n = 0; n < num; ++n) {
+ /* compound for all CD layers of the same type */
+ if (!has_props) {
+ has_props = true;
+ layertype_props = add_compound_property<OCompoundProperty>(m_name + ":" + layertype_name, m_props);
+ }
+
+ std::string name = cdtype_to_name(cdata, (CustomDataType)type, n);
+ void *data = CustomData_get_layer_n(cdata, type, n);
+ write_sample_call<0>(this, layertype_props, (CustomDataType)type, name, data, num_data);
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+CustomDataReader::CustomDataReader(const std::string &name, CustomDataMask cdmask) :
+ m_name(name),
+ m_cdmask(cdmask)
+{
+}
+
+CustomDataReader::~CustomDataReader()
+{
+ for (LayerPropsMap::iterator it = m_layer_props.begin(); it != m_layer_props.end(); ++it) {
+ BasePropertyReaderPtr prop = it->second;
+ if (prop)
+ prop.reset();
+ }
+}
+
+PTCReadSampleResult CustomDataReader::read_sample(const ISampleSelector &ss, CustomData *cdata, int num_data, ICompoundProperty &parent)
+{
+ m_props = add_compound_property<ICompoundProperty>(m_name, parent);
+
+ for (int type = 0; type < CD_NUMTYPES; ++type) {
+ CustomDataMask mask = (1ull << type);
+ /* only use specified types */
+ if (!(mask & m_cdmask))
+ continue;
+
+ const char *layertype_name = CustomData_layertype_name(type);
+
+ BasePropertyReaderPtr ptr = m_props.getPtr()->asCompoundPtr()->getProperty(m_name + ":" + layertype_name);
+ if (!ptr) {
+ /* no layer of this type stored */
+ continue;
+ }
+ ICompoundProperty layertype_props(ptr->asCompoundPtr(), kWrapExisting);
+
+ for (int i = 0; i < layertype_props.getNumProperties(); ++i) {
+ const std::string &name = layertype_props.getPropertyHeader(i).getName();
+ char layer_name[MAX_CUSTOMDATA_LAYER_NAME];
+ int n;
+ void *data;
+
+ cdtype_from_name(cdata, name, type, &n, layer_name, sizeof(layer_name));
+ if (layer_name[0] == '\0')
+ data = CustomData_add_layer(cdata, type, CD_DEFAULT, NULL, num_data);
+ else
+ data = CustomData_add_layer_named(cdata, type, CD_DEFAULT, NULL, num_data, layer_name);
+
+ read_sample_call<0>(this, layertype_props, ss, (CustomDataType)type, name, data, num_data);
+ }
+ }
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/alembic/abc_customdata.h b/source/blender/pointcache/alembic/abc_customdata.h
new file mode 100644
index 00000000000..9da3b92c584
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_customdata.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_ABC_CUSTOMDATA_H
+#define PTC_ABC_CUSTOMDATA_H
+
+#include <map>
+
+#include <Alembic/AbcGeom/IGeomParam.h>
+#include <Alembic/AbcGeom/OGeomParam.h>
+#include <Alembic/Abc/IBaseProperty.h>
+#include <Alembic/Abc/TypedPropertyTraits.h>
+
+#include "abc_reader.h"
+#include "abc_writer.h"
+
+extern "C" {
+#include "BKE_customdata.h"
+
+#include "DNA_customdata_types.h"
+}
+
+namespace PTC {
+
+using namespace Alembic;
+
+std::string abc_customdata_layer_name(CustomData *cdata, CustomDataType type, int n);
+
+struct CustomDataWriter {
+ typedef std::map<std::string, Abc::BasePropertyWriterPtr> LayerPropsMap;
+ typedef std::pair<std::string, Abc::BasePropertyWriterPtr> LayerPropsPair;
+
+ CustomDataWriter(const std::string &name, CustomDataMask cdmask);
+ ~CustomDataWriter();
+
+ void init(Abc::TimeSamplingPtr time_sampling);
+
+ void write_sample(CustomData *cdata, int num_data, Abc::OCompoundProperty &parent);
+
+ Abc::OCompoundProperty &props() { return m_props; }
+
+ template <typename PropertyT, typename ParentT>
+ PropertyT add_scalar_property(const std::string &name, ParentT &parent)
+ {
+ LayerPropsMap::iterator it = m_layer_props.find(name);
+ if (it == m_layer_props.end()) {
+ PropertyT prop = PropertyT(parent, name, m_time_sampling);
+ m_layer_props.insert(LayerPropsPair(name, prop.getPtr()));
+ return prop;
+ }
+ else {
+ return PropertyT(it->second->asScalarPtr(), Abc::kWrapExisting);
+ }
+ }
+
+ template <typename PropertyT, typename ParentT>
+ PropertyT add_array_property(const std::string &name, ParentT &parent)
+ {
+ LayerPropsMap::iterator it = m_layer_props.find(name);
+ if (it == m_layer_props.end()) {
+ PropertyT prop = PropertyT(parent, name, m_time_sampling);
+ m_layer_props.insert(LayerPropsPair(name, prop.getPtr()));
+ return prop;
+ }
+ else {
+ return PropertyT(it->second->asArrayPtr(), Abc::kWrapExisting);
+ }
+ }
+
+ template <typename PropertyT, typename ParentT>
+ PropertyT add_compound_property(const std::string &name, ParentT &parent)
+ {
+ LayerPropsMap::iterator it = m_layer_props.find(name);
+ if (it == m_layer_props.end()) {
+ PropertyT prop = PropertyT(parent, name, m_time_sampling);
+ m_layer_props.insert(LayerPropsPair(name, prop.getPtr()));
+ return prop;
+ }
+ else {
+ return PropertyT(it->second->asCompoundPtr(), Abc::kWrapExisting);
+ }
+ }
+
+ std::string cdtype_to_name(CustomData *cdata, CustomDataType type, int n);
+
+private:
+ std::string m_name;
+ CustomDataMask m_cdmask;
+
+ Abc::TimeSamplingPtr m_time_sampling;
+ Abc::OCompoundProperty m_props;
+ LayerPropsMap m_layer_props;
+};
+
+struct CustomDataReader {
+ typedef std::map<std::string, Abc::BasePropertyReaderPtr> LayerPropsMap;
+ typedef std::pair<std::string, Abc::BasePropertyReaderPtr> LayerPropsPair;
+
+ CustomDataReader(const std::string &name, CustomDataMask cdmask);
+ ~CustomDataReader();
+
+ PTCReadSampleResult read_sample(const Abc::ISampleSelector &ss, CustomData *cdata, int num_data, Abc::ICompoundProperty &parent);
+
+ Abc::ICompoundProperty &props() { return m_props; }
+
+ template <typename PropertyT, typename ParentT>
+ PropertyT add_scalar_property(const std::string &name, ParentT &parent)
+ {
+ LayerPropsMap::iterator it = m_layer_props.find(name);
+ if (it == m_layer_props.end()) {
+ PropertyT prop = PropertyT(parent, name, 0);
+ m_layer_props.insert(LayerPropsPair(name, prop.getPtr()));
+ return prop;
+ }
+ else {
+ return PropertyT(it->second->asScalarPtr(), Abc::kWrapExisting);
+ }
+ }
+
+ template <typename PropertyT, typename ParentT>
+ PropertyT add_array_property(const std::string &name, ParentT &parent)
+ {
+ LayerPropsMap::iterator it = m_layer_props.find(name);
+ if (it == m_layer_props.end()) {
+ PropertyT prop = PropertyT(parent, name, 0);
+ m_layer_props.insert(LayerPropsPair(name, prop.getPtr()));
+ return prop;
+ }
+ else {
+ return PropertyT(it->second->asArrayPtr(), Abc::kWrapExisting);
+ }
+ }
+
+ template <typename PropertyT, typename ParentT>
+ PropertyT add_compound_property(const std::string &name, ParentT &parent)
+ {
+ LayerPropsMap::iterator it = m_layer_props.find(name);
+ if (it == m_layer_props.end()) {
+ PropertyT prop = PropertyT(parent, name, 0);
+ m_layer_props.insert(LayerPropsPair(name, prop.getPtr()));
+ return prop;
+ }
+ else {
+ return PropertyT(it->second->asCompoundPtr(), Abc::kWrapExisting);
+ }
+ }
+
+ void cdtype_from_name(CustomData *cdata, const std::string &name, int type, int *n, char *layer_name, int max_layer_name);
+
+private:
+ std::string m_name;
+ CustomDataMask m_cdmask;
+
+ Abc::ICompoundProperty m_props;
+ LayerPropsMap m_layer_props;
+};
+
+} /* namespace PTC */
+
+#endif /* PTC_CLOTH_H */
diff --git a/source/blender/pointcache/alembic/abc_frame_mapper.cpp b/source/blender/pointcache/alembic/abc_frame_mapper.cpp
new file mode 100644
index 00000000000..ba5ded10b6e
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_frame_mapper.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "abc_frame_mapper.h"
+
+extern "C" {
+#include "DNA_scene_types.h"
+}
+
+namespace PTC {
+
+#ifdef WITH_ALEMBIC
+
+using namespace Abc;
+using namespace AbcCoreAbstract;
+
+FrameMapper::FrameMapper(double fps, float start_frame)
+{
+ m_frames_per_sec = fps;
+ m_sec_per_frame = (fps == 0.0 ? 0.0 : 1.0 / fps);
+ m_start_frame = start_frame;
+ m_start_time = start_frame * m_sec_per_frame;
+}
+
+chrono_t FrameMapper::frame_to_time(float frame) const
+{
+ return (double)frame * m_sec_per_frame;
+}
+
+float FrameMapper::time_to_frame(chrono_t time) const
+{
+ return (float)(time * m_frames_per_sec);
+}
+
+#endif /* WITH_ALEMBIC */
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/alembic/abc_frame_mapper.h b/source/blender/pointcache/alembic/abc_frame_mapper.h
new file mode 100644
index 00000000000..b61baeeb4a7
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_frame_mapper.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_ABC_FRAME_MAPPER_H
+#define PTC_ABC_FRAME_MAPPER_H
+
+#ifdef WITH_ALEMBIC
+#include <Alembic/AbcCoreAbstract/Foundation.h>
+#include <Alembic/Abc/ISampleSelector.h>
+#endif
+
+struct Scene;
+
+namespace PTC {
+
+#ifdef WITH_ALEMBIC
+
+using namespace Alembic;
+using Alembic::AbcCoreAbstract::chrono_t;
+
+class FrameMapper {
+public:
+ FrameMapper(double fps, float start_frame);
+
+ double frames_per_second() const { return m_frames_per_sec; }
+ double seconds_per_frame() const { return m_sec_per_frame; }
+ double start_frame() const { return m_start_frame; }
+ double start_time() const { return m_start_time; }
+
+ chrono_t frame_to_time(float frame) const;
+ float time_to_frame(chrono_t time) const;
+
+private:
+ double m_frames_per_sec, m_sec_per_frame;
+ double m_start_frame, m_start_time;
+};
+
+#endif /* WITH_ALEMBIC */
+
+} /* namespace PTC */
+
+#endif /* PTC_UTIL_FRAME_MAPPER_H */
diff --git a/source/blender/pointcache/alembic/abc_group.cpp b/source/blender/pointcache/alembic/abc_group.cpp
new file mode 100644
index 00000000000..38cbc19694e
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_group.cpp
@@ -0,0 +1,770 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <map>
+#include <sstream>
+#include <string>
+
+#include <Alembic/Abc/IObject.h>
+#include <Alembic/Abc/OObject.h>
+
+#include "abc_mesh.h"
+#include "abc_group.h"
+#include "abc_interpolate.h"
+#include "abc_object.h"
+#include "abc_particles.h"
+#include "abc_simdebug.h"
+
+extern "C" {
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "DNA_group_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_anim.h"
+#include "BKE_cache_library.h"
+#include "BKE_global.h"
+#include "BKE_group.h"
+#include "BKE_library.h"
+#include "BKE_strands.h"
+}
+
+#include "util_task.h"
+
+namespace PTC {
+
+using namespace Abc;
+using namespace AbcGeom;
+
+AbcGroupWriter::AbcGroupWriter(const std::string &name, Group *group) :
+ GroupWriter(group, name)
+{
+}
+
+void AbcGroupWriter::init_abc()
+{
+ if (m_abc_object)
+ return;
+
+ m_abc_object = abc_archive()->add_id_object<OObject>((ID *)m_group);
+}
+
+void AbcGroupWriter::create_refs()
+{
+ GroupObject *gob = (GroupObject *)m_group->gobject.first;
+ int i = 0;
+ for (; gob; gob = gob->next, ++i) {
+ OObject abc_object = abc_archive()->get_id_object((ID *)gob->ob);
+ if (abc_object) {
+ std::stringstream ss;
+ ss << i;
+ m_abc_object.addChildInstance(abc_object, std::string("group_object") + ss.str());
+ }
+ }
+}
+
+void AbcGroupWriter::write_sample()
+{
+ if (!m_abc_object)
+ return;
+}
+
+
+AbcGroupReader::AbcGroupReader(const std::string &name, Group *group) :
+ GroupReader(group, name)
+{
+}
+
+void AbcGroupReader::init_abc(IObject object)
+{
+ if (m_abc_object)
+ return;
+ m_abc_object = object;
+}
+
+PTCReadSampleResult AbcGroupReader::read_sample_abc(chrono_t /*time*/)
+{
+ if (!m_abc_object)
+ return PTC_READ_SAMPLE_INVALID;
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+/* ========================================================================= */
+
+AbcDupligroupWriter::AbcDupligroupWriter(const std::string &name, EvaluationContext *eval_ctx, Scene *scene, Group *group, CacheLibrary *cachelib) :
+ GroupWriter(group, name),
+ m_eval_ctx(eval_ctx),
+ m_scene(scene),
+ m_cachelib(cachelib)
+{
+}
+
+AbcDupligroupWriter::~AbcDupligroupWriter()
+{
+ for (IDWriterMap::iterator it = m_id_writers.begin(); it != m_id_writers.end(); ++it) {
+ if (it->second)
+ delete it->second;
+ }
+}
+
+void AbcDupligroupWriter::init_abc()
+{
+ if (m_abc_group)
+ return;
+
+ m_abc_group = abc_archive()->add_id_object<OObject>((ID *)m_group);
+}
+
+void AbcDupligroupWriter::write_sample_object(Object *ob, bool write_data)
+{
+ AbcWriter *ob_writer;
+
+ /* TODO(sergey): Optimize this out using RW mutex. */
+ {
+ thread_scoped_lock lock(m_init_mutex);
+ ob_writer = find_id_writer((ID *)ob);
+ if (!ob_writer) {
+ bool do_mesh = write_data && (m_cachelib->data_types & CACHE_TYPE_DERIVED_MESH);
+ bool do_hair = write_data && (m_cachelib->data_types & CACHE_TYPE_HAIR);
+
+ ob_writer = new AbcObjectWriter(ob->id.name, m_scene, ob, do_mesh, do_hair);
+ ob_writer->init(abc_archive());
+ m_id_writers.insert(IDWriterPair((ID *)ob, ob_writer));
+ }
+ }
+
+ ob_writer->write_sample();
+}
+
+void AbcDupligroupWriter::write_sample_dupli(DupliObject *dob, int index)
+{
+ OObject abc_object = abc_archive()->get_id_object((ID *)dob->ob);
+ if (!abc_object)
+ return;
+
+ std::stringstream ss;
+ ss << "DupliObject" << index;
+ std::string name = ss.str();
+
+ OObject abc_dupli = m_abc_group.getChild(name);
+ OCompoundProperty props;
+ OM44fProperty prop_matrix;
+ OBoolProperty prop_visible;
+ if (!abc_dupli) {
+ abc_dupli = OObject(m_abc_group, name, 0);
+ m_object_writers.push_back(abc_dupli.getPtr());
+ props = abc_dupli.getProperties();
+
+ abc_dupli.addChildInstance(abc_object, "object");
+
+ prop_matrix = OM44fProperty(props, "matrix", abc_archive()->frame_sampling());
+ m_property_writers.push_back(prop_matrix.getPtr());
+ prop_visible = OBoolProperty(props, "visible", abc_archive()->frame_sampling());
+ m_property_writers.push_back(prop_visible.getPtr());
+ }
+ else {
+ props = abc_dupli.getProperties();
+
+ prop_matrix = OM44fProperty(props.getProperty("matrix").getPtr()->asScalarPtr(), kWrapExisting);
+ prop_visible = OBoolProperty(props.getProperty("visible").getPtr()->asScalarPtr(), kWrapExisting);
+ }
+
+ prop_matrix.set(M44f(dob->mat));
+
+ bool show_object = (abc_archive()->use_render())? !(dob->ob->restrictflag & OB_RESTRICT_RENDER) : !(dob->ob->restrictflag & OB_RESTRICT_VIEW);
+ bool visible = show_object && (!dob->no_draw);
+ prop_visible.set(visible);
+}
+
+void AbcDupligroupWriter::write_sample()
+{
+ if (!m_abc_group)
+ return;
+
+ ListBase *duplilist = group_duplilist_ex(m_eval_ctx, m_scene, m_group, true);
+ DupliObject *dob;
+ int i;
+
+ /* use a set to ensure each object is handled only once */
+ std::set<Object*> objects;
+ for (dob = (DupliObject *)duplilist->first; dob; dob = dob->next) {
+ if (dob->ob)
+ objects.insert(dob->ob);
+ }
+
+ /* tag objects for which to store data */
+ BKE_cache_library_tag_used_objects(m_cachelib);
+
+ UtilTaskPool pool;
+ /* write actual object data: duplicator itself + all instanced objects */
+ for (std::set<Object*>::const_iterator it = objects.begin(); it != objects.end(); ++it) {
+ Object *ob = *it;
+ bool write_data = (ob->id.flag & LIB_DOIT);
+ pool.push(function_bind(&AbcDupligroupWriter::write_sample_object, this, ob, write_data));
+ }
+
+ pool.wait_work();
+
+ /* write dupli instances */
+ for (dob = (DupliObject *)duplilist->first, i = 0; dob; dob = dob->next, ++i) {
+ write_sample_dupli(dob, i);
+ }
+
+ free_object_duplilist(duplilist);
+}
+
+AbcWriter *AbcDupligroupWriter::find_id_writer(ID *id) const
+{
+ IDWriterMap::const_iterator it = m_id_writers.find(id);
+ if (it == m_id_writers.end())
+ return NULL;
+ else
+ return it->second;
+}
+
+/* ------------------------------------------------------------------------- */
+
+AbcDupliCacheWriter::AbcDupliCacheWriter(const std::string &name, Group *group, DupliCache *dupcache, int data_types, bool do_sim_debug) :
+ GroupWriter(group, name),
+ m_dupcache(dupcache),
+ m_data_types(data_types),
+ m_simdebug_writer(NULL)
+{
+ if (do_sim_debug) {
+ BKE_sim_debug_data_set_enabled(true);
+ if (_sim_debug_data)
+ m_simdebug_writer = new AbcSimDebugWriter("sim_debug", _sim_debug_data);
+ }
+}
+
+AbcDupliCacheWriter::~AbcDupliCacheWriter()
+{
+ for (IDWriterMap::iterator it = m_id_writers.begin(); it != m_id_writers.end(); ++it) {
+ if (it->second)
+ delete it->second;
+ }
+
+ if (m_simdebug_writer)
+ delete m_simdebug_writer;
+}
+
+void AbcDupliCacheWriter::init_abc()
+{
+ if (m_abc_group)
+ return;
+
+ m_abc_group = abc_archive()->add_id_object<OObject>((ID *)m_group);
+
+ if (m_simdebug_writer) {
+ m_simdebug_writer->init(abc_archive());
+ m_simdebug_writer->init_abc(abc_archive()->root());
+ }
+}
+
+void AbcDupliCacheWriter::write_sample_object_data(DupliObjectData *data)
+{
+ AbcWriter *ob_writer = find_id_writer((ID *)data->ob);
+ if (!ob_writer) {
+ bool do_mesh = (m_data_types & CACHE_TYPE_DERIVED_MESH);
+ bool do_hair = (m_data_types & CACHE_TYPE_HAIR);
+
+ ob_writer = new AbcDupliObjectWriter(data->ob->id.name, data, do_mesh, do_hair);
+ ob_writer->init(abc_archive());
+ m_id_writers.insert(IDWriterPair((ID *)data->ob, ob_writer));
+ }
+
+ ob_writer->write_sample();
+}
+
+void AbcDupliCacheWriter::write_sample_dupli(DupliObject *dob, int index)
+{
+ OObject abc_object = abc_archive()->get_id_object((ID *)dob->ob);
+ if (!abc_object)
+ return;
+
+ std::stringstream ss;
+ ss << "DupliObject" << index;
+ std::string name = ss.str();
+
+ OObject abc_dupli = m_abc_group.getChild(name);
+ OCompoundProperty props;
+ OBoolProperty prop_visible;
+ OM44fProperty prop_matrix;
+ if (!abc_dupli) {
+ abc_dupli = OObject(m_abc_group, name, 0);
+ m_object_writers.push_back(abc_dupli.getPtr());
+ props = abc_dupli.getProperties();
+
+ abc_dupli.addChildInstance(abc_object, "object");
+
+ prop_matrix = OM44fProperty(props, "matrix", abc_archive()->frame_sampling());
+ m_property_writers.push_back(prop_matrix.getPtr());
+ prop_visible = OBoolProperty(props, "visible", abc_archive()->frame_sampling());
+ m_property_writers.push_back(prop_visible.getPtr());
+ }
+ else {
+ props = abc_dupli.getProperties();
+
+ prop_matrix = OM44fProperty(props.getProperty("matrix").getPtr()->asScalarPtr(), kWrapExisting);
+ prop_visible = OBoolProperty(props.getProperty("visible").getPtr()->asScalarPtr(), kWrapExisting);
+ }
+
+ prop_matrix.set(M44f(dob->mat));
+
+ bool show_object = (abc_archive()->use_render())? !(dob->ob->restrictflag & OB_RESTRICT_RENDER) : !(dob->ob->restrictflag & OB_RESTRICT_VIEW);
+ bool visible = show_object && (!dob->no_draw);
+ prop_visible.set(visible);
+}
+
+void AbcDupliCacheWriter::write_sample()
+{
+ if (!m_abc_group)
+ return;
+
+ DupliObject *dob;
+ int i;
+
+ struct DupliCacheIterator *iter = BKE_dupli_cache_iter_new(m_dupcache);
+ for (; BKE_dupli_cache_iter_valid(iter); BKE_dupli_cache_iter_next(iter)) {
+ DupliObjectData *data = BKE_dupli_cache_iter_get(iter);
+
+ write_sample_object_data(data);
+ }
+ BKE_dupli_cache_iter_free(iter);
+
+ /* write dupli instances */
+ for (dob = (DupliObject *)m_dupcache->duplilist.first, i = 0; dob; dob = dob->next, ++i) {
+ write_sample_dupli(dob, i);
+ }
+
+ if (m_simdebug_writer) {
+ m_simdebug_writer->write_sample();
+ }
+}
+
+AbcWriter *AbcDupliCacheWriter::find_id_writer(ID *id) const
+{
+ IDWriterMap::const_iterator it = m_id_writers.find(id);
+ if (it == m_id_writers.end())
+ return NULL;
+ else
+ return it->second;
+}
+
+/* ------------------------------------------------------------------------- */
+
+AbcDupliCacheReader::AbcDupliCacheReader(const std::string &name, Group *group, DupliCache *dupli_cache,
+ bool read_strands_motion, bool read_strands_children, bool read_sim_debug) :
+ GroupReader(group, name),
+ dupli_cache(dupli_cache),
+ m_read_strands_motion(read_strands_motion),
+ m_read_strands_children(read_strands_children),
+ m_simdebug_reader(NULL)
+{
+ /* XXX this mapping allows fast lookup of existing objects in Blender data
+ * to associate with duplis. Later i may be possible to create instances of
+ * non-DNA data, but for the time being this is a requirement due to other code parts (drawing, rendering)
+ */
+ build_object_map(G.main, group);
+
+ if (read_sim_debug) {
+ BKE_sim_debug_data_set_enabled(true);
+ if (_sim_debug_data)
+ m_simdebug_reader = new AbcSimDebugReader(_sim_debug_data);
+ }
+}
+
+AbcDupliCacheReader::~AbcDupliCacheReader()
+{
+ if (m_simdebug_reader)
+ delete m_simdebug_reader;
+}
+
+void AbcDupliCacheReader::init_abc(IObject /*object*/)
+{
+}
+
+void AbcDupliCacheReader::read_dupligroup_object(IObject object, chrono_t time)
+{
+ if (GS(object.getName().c_str()) == ID_OB) {
+ /* instances are handled later, we create true object data here */
+ if (object.isInstanceDescendant())
+ return;
+
+ Object *b_ob = find_object(object.getName());
+ if (!b_ob)
+ return;
+
+ /* Always add dupli data, even if no geometry is stored.
+ * Any missing geometry data will be replaced by the original uncached data in drawing/rendering if available.
+ */
+ DupliObjectData *dupli_data = BKE_dupli_cache_add_object(dupli_cache, b_ob);
+ insert_dupli_data(object.getPtr(), dupli_data);
+
+ for (int i = 0; i < object.getNumChildren(); ++i) {
+ IObject child = object.getChild(i);
+ const MetaData &metadata = child.getMetaData();
+
+ if (IPolyMeshSchema::matches(metadata)) {
+ AbcDerivedMeshReader dm_reader("mesh", b_ob);
+ dm_reader.init(abc_archive());
+ dm_reader.init_abc(child);
+ if (dm_reader.read_sample_abc(time) != PTC_READ_SAMPLE_INVALID) {
+ BKE_dupli_object_data_set_mesh(dupli_data, dm_reader.acquire_result());
+ }
+ else {
+ dm_reader.discard_result();
+ }
+ }
+ else if (ICurvesSchema::matches(metadata)) {
+ Strands *strands;
+ StrandsChildren *children;
+ BKE_dupli_object_data_find_strands(dupli_data, child.getName().c_str(), &strands, &children);
+
+ AbcStrandsReader strands_reader(strands, children, m_read_strands_motion, m_read_strands_children);
+ strands_reader.init(abc_archive());
+ strands_reader.init_abc(child);
+ if (strands_reader.read_sample_abc(time) != PTC_READ_SAMPLE_INVALID) {
+ Strands *newstrands = strands_reader.acquire_result();
+ if (strands && strands != newstrands) {
+ /* reader can replace strands internally if topology does not match */
+ BKE_strands_free(strands);
+ }
+ BKE_dupli_object_data_add_strands(dupli_data, child.getName().c_str(), newstrands);
+
+ StrandsChildren *newchildren = strands_reader.child_reader().acquire_result();
+ if (children && children != newchildren) {
+ /* reader can replace strands internally if topology does not match */
+ BKE_strands_children_free(children);
+ }
+ BKE_dupli_object_data_add_strands_children(dupli_data, child.getName().c_str(), newchildren);
+ }
+ else {
+ strands_reader.discard_result();
+ strands_reader.child_reader().discard_result();
+ }
+ }
+ }
+ }
+}
+
+void AbcDupliCacheReader::read_dupligroup_group(IObject abc_group, chrono_t time)
+{
+ ISampleSelector ss = get_frame_sample_selector(time);
+
+ if (GS(abc_group.getName().c_str()) == ID_GR) {
+ size_t num_child = abc_group.getNumChildren();
+
+ for (size_t i = 0; i < num_child; ++i) {
+ IObject abc_dupli = abc_group.getChild(i);
+ ICompoundProperty props = abc_dupli.getProperties();
+
+ IM44fProperty prop_matrix(props, "matrix", 0);
+ M44f abc_matrix = abc_interpolate_sample_linear(prop_matrix, time);
+ float matrix[4][4];
+ memcpy(matrix, abc_matrix.getValue(), sizeof(matrix));
+
+ IBoolProperty prop_visible(props, "visible", 0);
+ bool visible = prop_visible.getValue(ss);
+
+ IObject abc_dupli_object = abc_dupli.getChild("object");
+ if (abc_dupli_object.isInstanceRoot()) {
+ DupliObjectData *dupli_data = find_dupli_data(abc_dupli_object.getPtr());
+ if (dupli_data) {
+ DupliObject *dob = BKE_dupli_cache_add_instance(dupli_cache, matrix, dupli_data);
+ dob->no_draw = !visible;
+ }
+ }
+ }
+ }
+}
+
+PTCReadSampleResult AbcDupliCacheReader::read_sample_abc(chrono_t time)
+{
+ IObject abc_top = abc_archive()->root();
+ IObject abc_group = abc_archive()->get_id_object((ID *)m_group);
+ if (!abc_group)
+ return PTC_READ_SAMPLE_INVALID;
+
+ /* first create shared object data */
+ for (size_t i = 0; i < abc_top.getNumChildren(); ++i) {
+ read_dupligroup_object(abc_top.getChild(i), time);
+ }
+
+ BKE_dupli_cache_clear_instances(dupli_cache);
+
+ /* now generate dupli instances for the group */
+ read_dupligroup_group(abc_group, time);
+
+ // XXX reader init is a mess ...
+ if (m_simdebug_reader) {
+ if (abc_top.getChildHeader("sim_debug")) {
+ m_simdebug_reader->init(abc_archive());
+ m_simdebug_reader->init_abc(abc_top.getChild("sim_debug"));
+
+ m_simdebug_reader->read_sample_abc(time);
+ }
+ }
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+DupliObjectData *AbcDupliCacheReader::find_dupli_data(ObjectReaderPtr ptr) const
+{
+ DupliMap::const_iterator it = dupli_map.find(ptr);
+ if (it == dupli_map.end())
+ return NULL;
+ else
+ return it->second;
+}
+
+void AbcDupliCacheReader::insert_dupli_data(ObjectReaderPtr ptr, DupliObjectData *data)
+{
+ dupli_map.insert(DupliPair(ptr, data));
+}
+
+void AbcDupliCacheReader::build_object_map(Main *bmain, Group *group)
+{
+ BKE_main_id_tag_idcode(bmain, ID_OB, false);
+ BKE_main_id_tag_idcode(bmain, ID_GR, false);
+ object_map.clear();
+
+ build_object_map_add_group(group);
+}
+
+Object *AbcDupliCacheReader::find_object(const std::string &name) const
+{
+ ObjectMap::const_iterator it = object_map.find(name);
+ if (it == object_map.end())
+ return NULL;
+ else
+ return it->second;
+}
+
+void AbcDupliCacheReader::build_object_map_add_group(Group *group)
+{
+ if (group->id.flag & LIB_DOIT)
+ return;
+ group->id.flag |= LIB_DOIT;
+
+ for (GroupObject *gob = (GroupObject *)group->gobject.first; gob; gob = gob->next) {
+ Object *ob = gob->ob;
+ if (ob->id.flag & LIB_DOIT)
+ continue;
+ ob->id.flag |= LIB_DOIT;
+ object_map.insert(ObjectPair(ob->id.name, ob));
+
+ if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) {
+ build_object_map_add_group(ob->dup_group);
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+AbcDupliObjectWriter::AbcDupliObjectWriter(const std::string &name, DupliObjectData *dupdata, bool do_mesh, bool do_strands) :
+ ObjectWriter(dupdata->ob, name),
+ m_dupdata(dupdata),
+ m_do_strands(do_strands),
+ m_dm_writer(0)
+{
+ if (do_mesh) {
+ if (m_ob && m_ob->type == OB_MESH) {
+ m_dm_writer = new AbcDerivedMeshWriter("mesh", dupdata->ob, &dupdata->dm);
+ }
+ }
+}
+
+AbcStrandsWriter *AbcDupliObjectWriter::find_strands_writer(const std::string &name) const
+{
+ StrandsWriters::const_iterator it = m_strands_writers.find(name);
+ return (it != m_strands_writers.end()) ? it->second : NULL;
+}
+
+AbcStrandsWriter *AbcDupliObjectWriter::add_strands_writer(const std::string &name)
+{
+ StrandsWriters::const_iterator it = m_strands_writers.find(name);
+ if (it != m_strands_writers.end()) {
+ return it->second;
+ }
+ else {
+ AbcStrandsWriter *writer = new AbcStrandsWriter(name, m_dupdata);
+ m_strands_writers.insert(StrandsWritersPair(name, writer));
+
+ writer->init(abc_archive());
+ writer->init_abc(m_abc_object);
+
+ return writer;
+ }
+}
+
+AbcDupliObjectWriter::~AbcDupliObjectWriter()
+{
+ if (m_dm_writer)
+ delete m_dm_writer;
+ for (StrandsWriters::iterator it = m_strands_writers.begin(); it != m_strands_writers.end(); ++it) {
+ if (it->second)
+ delete it->second;
+ }
+}
+
+void AbcDupliObjectWriter::init_abc()
+{
+ if (m_abc_object)
+ return;
+
+ m_abc_object = abc_archive()->add_id_object<OObject>((ID *)m_ob);
+
+ if (m_dm_writer) {
+ /* XXX not nice */
+ m_dm_writer->init(abc_archive());
+ m_dm_writer->init_abc(m_abc_object);
+ }
+}
+
+void AbcDupliObjectWriter::write_sample()
+{
+ if (!m_abc_object)
+ return;
+
+ if (m_dm_writer) {
+ m_dm_writer->write_sample();
+ }
+
+ if (m_do_strands) {
+ int index = 0;
+ for (DupliObjectDataStrands *link = (DupliObjectDataStrands *)m_dupdata->strands.first;
+ link;
+ link = link->next, ++index) {
+ AbcStrandsWriter *writer = add_strands_writer(link->name);
+ writer->write_sample();
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+AbcDupliObjectReader::AbcDupliObjectReader(const std::string &name, Object *ob, DupliObjectData *dupli_data,
+ bool read_strands_motion, bool read_strands_children) :
+ ObjectReader(ob, name),
+ dupli_data(dupli_data),
+ m_read_strands_motion(read_strands_motion),
+ m_read_strands_children(read_strands_children)
+{
+}
+
+AbcDupliObjectReader::~AbcDupliObjectReader()
+{
+}
+
+void AbcDupliObjectReader::init(ReaderArchive *archive)
+{
+ AbcReader::init(archive);
+
+ if (abc_archive()->root().getChildHeader(m_name))
+ m_abc_object = abc_archive()->root().getChild(m_name);
+}
+
+void AbcDupliObjectReader::init_abc(IObject object)
+{
+ m_abc_object = object;
+}
+
+void AbcDupliObjectReader::read_dupligroup_object(IObject object, chrono_t time)
+{
+ if (GS(object.getName().c_str()) == ID_OB) {
+ /* instances are handled later, we create true object data here */
+ if (object.isInstanceDescendant())
+ return;
+
+ BKE_dupli_object_data_init(dupli_data, m_ob);
+
+ for (int i = 0; i < object.getNumChildren(); ++i) {
+ IObject child = object.getChild(i);
+ const MetaData &metadata = child.getMetaData();
+
+ if (IPolyMeshSchema::matches(metadata)) {
+ AbcDerivedMeshReader dm_reader("mesh", m_ob);
+ dm_reader.init(abc_archive());
+ dm_reader.init_abc(child);
+ if (dm_reader.read_sample_abc(time) != PTC_READ_SAMPLE_INVALID) {
+ BKE_dupli_object_data_set_mesh(dupli_data, dm_reader.acquire_result());
+ }
+ else {
+ dm_reader.discard_result();
+ }
+ }
+ else if (ICurvesSchema::matches(metadata)) {
+ Strands *strands;
+ StrandsChildren *children;
+ BKE_dupli_object_data_find_strands(dupli_data, child.getName().c_str(), &strands, &children);
+
+ AbcStrandsReader strands_reader(strands, children, m_read_strands_motion, m_read_strands_children);
+ strands_reader.init(abc_archive());
+ strands_reader.init_abc(child);
+ if (strands_reader.read_sample_abc(time) != PTC_READ_SAMPLE_INVALID) {
+ Strands *newstrands = strands_reader.acquire_result();
+ if (strands && strands != newstrands) {
+ /* reader can replace strands internally if topology does not match */
+ BKE_strands_free(strands);
+ }
+ BKE_dupli_object_data_add_strands(dupli_data, child.getName().c_str(), newstrands);
+
+ StrandsChildren *newchildren = strands_reader.child_reader().acquire_result();
+ if (children && children != newchildren) {
+ /* reader can replace strands internally if topology does not match */
+ BKE_strands_children_free(children);
+ }
+ BKE_dupli_object_data_add_strands_children(dupli_data, child.getName().c_str(), newchildren);
+ }
+ else {
+ strands_reader.discard_result();
+ strands_reader.child_reader().discard_result();
+ }
+ }
+ }
+ }
+}
+
+PTCReadSampleResult AbcDupliObjectReader::read_sample_abc(chrono_t time)
+{
+ if (!m_abc_object)
+ return PTC_READ_SAMPLE_INVALID;
+
+ read_dupligroup_object(m_abc_object, time);
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+DupliObjectData *AbcDupliObjectReader::find_dupli_data(ObjectReaderPtr ptr) const
+{
+ DupliMap::const_iterator it = dupli_map.find(ptr);
+ if (it == dupli_map.end())
+ return NULL;
+ else
+ return it->second;
+}
+
+void AbcDupliObjectReader::insert_dupli_data(ObjectReaderPtr ptr, DupliObjectData *data)
+{
+ dupli_map.insert(DupliPair(ptr, data));
+}
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/alembic/abc_group.h b/source/blender/pointcache/alembic/abc_group.h
new file mode 100644
index 00000000000..ae8c58edc45
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_group.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_ABC_GROUP_H
+#define PTC_ABC_GROUP_H
+
+#include "ptc_types.h"
+
+#include "abc_reader.h"
+#include "abc_schema.h"
+#include "abc_writer.h"
+
+#include "util_thread.h"
+
+struct CacheLibrary;
+struct DupliCache;
+struct DupliObject;
+struct DupliObjectData;
+struct Group;
+struct Object;
+struct Scene;
+
+namespace PTC {
+
+class AbcDerivedMeshWriter;
+class AbcStrandsWriter;
+class AbcSimDebugWriter;
+class AbcSimDebugReader;
+
+class AbcGroupWriter : public GroupWriter, public AbcWriter {
+public:
+ AbcGroupWriter(const std::string &name, Group *group);
+
+ void init_abc();
+ void create_refs();
+
+ void write_sample();
+
+private:
+ Abc::OObject m_abc_object;
+};
+
+class AbcGroupReader : public GroupReader, public AbcReader {
+public:
+ AbcGroupReader(const std::string &name, Group *group);
+
+ void init_abc(Abc::IObject object);
+
+ PTCReadSampleResult read_sample_abc(chrono_t time);
+
+private:
+ Abc::IObject m_abc_object;
+};
+
+/* ========================================================================= */
+
+class AbcDupligroupWriter : public GroupWriter, public AbcWriter {
+public:
+ typedef std::vector<Abc::ObjectWriterPtr> ObjectWriterList;
+ typedef std::vector<Abc::BasePropertyWriterPtr> PropertyWriterList;
+
+ typedef std::map<ID *, AbcWriter *> IDWriterMap;
+ typedef std::pair<ID *, AbcWriter *> IDWriterPair;
+
+ AbcDupligroupWriter(const std::string &name, EvaluationContext *eval_ctx, Scene *scene, Group *group, CacheLibrary *cachelib);
+ ~AbcDupligroupWriter();
+
+ void init_abc();
+
+ void write_sample();
+ void write_sample_object(Object *ob, bool write_data);
+ void write_sample_dupli(DupliObject *dob, int index);
+
+ AbcWriter *find_id_writer(ID *id) const;
+
+private:
+ EvaluationContext *m_eval_ctx;
+ Scene *m_scene;
+ CacheLibrary *m_cachelib;
+
+ Abc::OObject m_abc_group;
+ ObjectWriterList m_object_writers;
+ PropertyWriterList m_property_writers;
+ IDWriterMap m_id_writers;
+ thread_mutex m_init_mutex;
+};
+
+class AbcDupliCacheWriter : public GroupWriter, public AbcWriter {
+public:
+ typedef std::vector<Abc::ObjectWriterPtr> ObjectWriterList;
+ typedef std::vector<Abc::BasePropertyWriterPtr> PropertyWriterList;
+
+ typedef std::map<ID *, AbcWriter *> IDWriterMap;
+ typedef std::pair<ID *, AbcWriter *> IDWriterPair;
+
+ AbcDupliCacheWriter(const std::string &name, Group *group, DupliCache *dupcache, int data_types, bool do_sim_debug = false);
+ ~AbcDupliCacheWriter();
+
+ void init_abc();
+
+ void write_sample();
+ void write_sample_object_data(DupliObjectData *data);
+ void write_sample_dupli(DupliObject *dob, int index);
+
+ AbcWriter *find_id_writer(ID *id) const;
+
+private:
+ DupliCache *m_dupcache;
+ int m_data_types;
+
+ Abc::OObject m_abc_group;
+ ObjectWriterList m_object_writers;
+ PropertyWriterList m_property_writers;
+ IDWriterMap m_id_writers;
+ AbcSimDebugWriter *m_simdebug_writer;
+};
+
+class AbcDupliCacheReader : public GroupReader, public AbcReader {
+public:
+ typedef std::map<Abc::ObjectReaderPtr, DupliObjectData*> DupliMap;
+ typedef std::pair<Abc::ObjectReaderPtr, DupliObjectData*> DupliPair;
+
+ typedef std::map<std::string, Object*> ObjectMap;
+ typedef std::pair<std::string, Object*> ObjectPair;
+
+public:
+ AbcDupliCacheReader(const std::string &name, Group *group, DupliCache *dupcache,
+ bool read_strands_motion, bool read_strands_children, bool read_sim_debug);
+ ~AbcDupliCacheReader();
+
+ void init_abc(Abc::IObject object);
+
+ PTCReadSampleResult read_sample_abc(chrono_t time);
+
+protected:
+ void read_dupligroup_object(Abc::IObject object, chrono_t time);
+ void read_dupligroup_group(Abc::IObject abc_group, chrono_t time);
+
+ DupliObjectData *find_dupli_data(Abc::ObjectReaderPtr ptr) const;
+ void insert_dupli_data(Abc::ObjectReaderPtr ptr, DupliObjectData *data);
+
+ void build_object_map(Main *bmain, Group *group);
+ void build_object_map_add_group(Group *group);
+ Object *find_object(const std::string &name) const;
+
+private:
+ DupliMap dupli_map;
+ DupliCache *dupli_cache;
+
+ ObjectMap object_map;
+ bool m_read_strands_motion, m_read_strands_children;
+ AbcSimDebugReader *m_simdebug_reader;
+};
+
+
+class AbcDupliObjectWriter : public ObjectWriter, public AbcWriter {
+public:
+ typedef std::map<std::string, AbcStrandsWriter *> StrandsWriters;
+ typedef std::pair<std::string, AbcStrandsWriter *> StrandsWritersPair;
+
+ AbcDupliObjectWriter(const std::string &name, DupliObjectData *dupdata, bool do_mesh, bool do_strands);
+ ~AbcDupliObjectWriter();
+
+ void init_abc();
+
+ void write_sample();
+
+ AbcStrandsWriter *find_strands_writer(const std::string &name) const;
+ AbcStrandsWriter *add_strands_writer(const std::string &name);
+
+private:
+ DupliObjectData *m_dupdata;
+ bool m_do_strands;
+
+ Abc::OObject m_abc_object;
+ AbcDerivedMeshWriter *m_dm_writer;
+ StrandsWriters m_strands_writers;
+};
+
+class AbcDupliObjectReader : public ObjectReader, public AbcReader {
+public:
+ typedef std::map<Abc::ObjectReaderPtr, DupliObjectData*> DupliMap;
+ typedef std::pair<Abc::ObjectReaderPtr, DupliObjectData*> DupliPair;
+
+public:
+ AbcDupliObjectReader(const std::string &name, Object *ob, DupliObjectData *dupli_data,
+ bool read_strands_motion, bool read_strands_children);
+ ~AbcDupliObjectReader();
+
+ void init(ReaderArchive *archive);
+ void init_abc(Abc::IObject object);
+
+ PTCReadSampleResult read_sample_abc(chrono_t time);
+
+protected:
+ void read_dupligroup_object(Abc::IObject object, chrono_t time);
+
+ DupliObjectData *find_dupli_data(Abc::ObjectReaderPtr ptr) const;
+ void insert_dupli_data(Abc::ObjectReaderPtr ptr, DupliObjectData *data);
+
+private:
+ DupliMap dupli_map;
+ DupliObjectData *dupli_data;
+ bool m_read_strands_motion, m_read_strands_children;
+
+ Abc::IObject m_abc_object;
+};
+
+} /* namespace PTC */
+
+#endif /* PTC_OBJECT_H */
diff --git a/source/blender/pointcache/alembic/abc_info.cpp b/source/blender/pointcache/alembic/abc_info.cpp
new file mode 100644
index 00000000000..35d30cb6d0c
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_info.cpp
@@ -0,0 +1,516 @@
+//-*****************************************************************************
+//
+// Copyright (c) 2009-2013,
+// Sony Pictures Imageworks, Inc. and
+// Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Sony Pictures Imageworks, nor
+// Industrial Light & Magic nor the names of their 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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//-*****************************************************************************
+
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <Alembic/AbcGeom/All.h>
+#include <Alembic/AbcCoreAbstract/All.h>
+#include <Alembic/AbcCoreFactory/All.h>
+#include <Alembic/Util/All.h>
+#include <Alembic/Abc/TypedPropertyTraits.h>
+
+#include <sstream>
+
+#include "alembic.h"
+
+extern "C" {
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_ID.h"
+
+#include "BKE_cache_library.h"
+#include "BKE_idprop.h"
+}
+
+using namespace ::Alembic::AbcGeom;
+
+namespace PTC {
+
+static void metadata_from_idprops(MetaData &md, IDProperty *prop);
+
+void abc_metadata_from_idprops_group(MetaData &md, IDProperty *prop)
+{
+ if (!prop)
+ return;
+
+ IDProperty *child;
+ for (child = (IDProperty *)prop->data.group.first; child; child = child->next)
+ metadata_from_idprops(md, child);
+}
+
+static void metadata_from_idprops(MetaData &md, IDProperty *prop)
+{
+ /* skip default metadata entries, these are set explicitly */
+ std::string key(prop->name);
+ if (key.compare(kApplicationNameKey)==0 || key.compare(kDateWrittenKey)==0 || key.compare(kUserDescriptionKey)==0)
+ return;
+
+ switch (prop->type) {
+#if 0 /* don't support recursion yet */
+ case IDP_GROUP: {
+ metadata_from_idprops_group(md, child);
+ break;
+ }
+
+ case IDP_ARRAY: {
+ if (prop->data.pointer) {
+ IDProperty **array = (IDProperty **)prop->data.pointer;
+ for (int a = 0; a < prop->len; a++)
+ metadata_from_idprops(md, array[a]);
+ }
+ break;
+ }
+#endif
+
+ /* only string properties are used */
+ case IDP_STRING: {
+ md.set(prop->name, IDP_String(prop));
+ break;
+ }
+ }
+}
+
+void abc_metadata_to_idprops_group(const MetaData &md, IDProperty *prop)
+{
+ if (!prop)
+ return;
+
+ for (MetaData::const_iterator it = md.begin(); it != md.end(); ++it) {
+ const std::string &key = it->first;
+ const std::string &value = it->second;
+
+ /* skip default metadata entries, these are stored in CacheArchiveInfo */
+ if (key.compare(kApplicationNameKey)==0 || key.compare(kDateWrittenKey)==0 || key.compare(kUserDescriptionKey)==0)
+ continue;
+
+ IDPropertyTemplate val;
+ val.string.str = value.c_str();
+ val.string.len = value.length();
+ IDP_ReplaceInGroup(prop, IDP_New(IDP_STRING, &val, key.c_str()));
+ }
+}
+
+MetaData abc_create_archive_info(const char *app_name, const char *description, const struct tm *t, IDProperty *props)
+{
+ MetaData md;
+
+ md.set(kApplicationNameKey, app_name);
+ md.set(kUserDescriptionKey, description);
+
+ if (!t) {
+ time_t curtime = time(NULL);
+ t = localtime(&curtime);
+ }
+
+ if (t) {
+ char buf[256];
+ strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M", t);
+ md.set(kDateWrittenKey, buf);
+ }
+
+ /* store custom properties as metadata */
+ if (props && props->type == IDP_GROUP)
+ abc_metadata_from_idprops_group(md, props);
+
+ return md;
+}
+
+/* ========================================================================= */
+
+struct stringstream {
+ stringstream(void (*cb)(void *, const char *), void *userdata) :
+ cb(cb),
+ userdata(userdata)
+ {
+ }
+
+ void (*cb)(void *, const char *);
+ void *userdata;
+
+ template <typename T>
+ friend stringstream& operator << (stringstream &stream, T s);
+};
+
+template <typename T>
+stringstream& operator << (stringstream &stream, T s)
+{
+ std::stringstream ss;
+ ss << s;
+ stream.cb(stream.userdata, ss.str().c_str());
+ return stream;
+}
+
+static const std::string g_sep(";");
+static const std::string g_endl("\n");
+
+static void info_stream_properties(stringstream &ss, ICompoundProperty, std::string &);
+
+template <class PROP>
+static void info_stream_array_property(stringstream &ss, PROP iProp, const std::string &iIndent)
+{
+ std::string ptype = "ArrayProperty ";
+ size_t asize = 0;
+
+ AbcA::ArraySamplePtr samp;
+ index_t maxSamples = iProp.getNumSamples();
+ for (index_t i = 0 ; i < maxSamples; ++i) {
+ iProp.get(samp, ISampleSelector(i));
+ asize = samp->size();
+ }
+
+ std::string mdstring = "interpretation=";
+ mdstring += iProp.getMetaData().get("interpretation");
+
+ std::stringstream dtype;
+ dtype << "datatype=";
+ dtype << iProp.getDataType();
+
+ std::stringstream asizestr;
+ asizestr << ";arraysize=";
+ asizestr << asize;
+
+ mdstring += g_sep;
+
+ mdstring += dtype.str();
+
+ mdstring += asizestr.str();
+
+ ss << iIndent << " " << ptype << "name=" << iProp.getName()
+ << g_sep << mdstring << g_sep << "numsamps="
+ << iProp.getNumSamples() << g_endl;
+}
+
+template <class PROP>
+static void info_stream_scalar_property(stringstream &ss, PROP iProp, const std::string &iIndent)
+{
+ std::string ptype = "ScalarProperty ";
+ size_t asize = 0;
+
+ const AbcA::DataType &dt = iProp.getDataType();
+ const Alembic::Util ::uint8_t extent = dt.getExtent();
+ Alembic::Util::Dimensions dims(extent);
+ AbcA::ArraySamplePtr samp = AbcA::AllocateArraySample( dt, dims );
+ index_t maxSamples = iProp.getNumSamples();
+ for (index_t i = 0 ; i < maxSamples; ++i) {
+ iProp.get(const_cast<void *>(samp->getData()), ISampleSelector(i));
+ asize = samp->size();
+ }
+
+ std::string mdstring = "interpretation=";
+ mdstring += iProp.getMetaData().get("interpretation");
+
+ std::stringstream dtype;
+ dtype << "datatype=";
+ dtype << dt;
+
+ std::stringstream asizestr;
+ asizestr << ";arraysize=";
+ asizestr << asize;
+
+ mdstring += g_sep;
+
+ mdstring += dtype.str();
+
+ mdstring += asizestr.str();
+
+ ss << iIndent << " " << ptype << "name=" << iProp.getName()
+ << g_sep << mdstring << g_sep << "numsamps="
+ << iProp.getNumSamples() << g_endl;
+}
+
+static void info_stream_compound_property(stringstream &ss, ICompoundProperty iProp, std::string &ioIndent)
+{
+ std::string oldIndent = ioIndent;
+ ioIndent += " ";
+
+ std::string interp = "schema=";
+ interp += iProp.getMetaData().get("schema");
+
+ ss << ioIndent << "CompoundProperty " << "name=" << iProp.getName()
+ << g_sep << interp << g_endl;
+
+ info_stream_properties(ss, iProp, ioIndent);
+
+ ioIndent = oldIndent;
+}
+
+static void info_stream_properties(stringstream &ss, ICompoundProperty iParent, std::string &ioIndent )
+{
+ std::string oldIndent = ioIndent;
+ for (size_t i = 0 ; i < iParent.getNumProperties() ; i++) {
+ PropertyHeader header = iParent.getPropertyHeader(i);
+
+ if (header.isCompound()) {
+ info_stream_compound_property(ss, ICompoundProperty(iParent, header.getName()), ioIndent);
+ }
+ else if (header.isScalar()) {
+ info_stream_scalar_property(ss, IScalarProperty(iParent, header.getName()), ioIndent);
+ }
+ else {
+ BLI_assert(header.isArray());
+ info_stream_array_property(ss, IArrayProperty(iParent, header.getName()), ioIndent);
+ }
+ }
+
+ ioIndent = oldIndent;
+}
+
+static void info_stream_object(stringstream &ss, IObject iObj, std::string iIndent)
+{
+ // Object has a name, a full name, some meta data,
+ // and then it has a compound property full of properties.
+ std::string path = iObj.getFullName();
+
+ if (iObj.isInstanceRoot()) {
+ if (path != "/") {
+ ss << "Object " << "name=" << path
+ << " [Instance " << iObj.instanceSourcePath() << "]"
+ << g_endl;
+ }
+ }
+ else if (iObj.isInstanceDescendant()) {
+ /* skip non-root instances to avoid repetition */
+ return;
+ }
+ else {
+ if (path != "/") {
+ ss << "Object " << "name=" << path << g_endl;
+ }
+
+ // Get the properties.
+ ICompoundProperty props = iObj.getProperties();
+ info_stream_properties(ss, props, iIndent);
+
+ // now the child objects
+ for (size_t i = 0 ; i < iObj.getNumChildren() ; i++) {
+ info_stream_object(ss, IObject(iObj, iObj.getChildHeader(i).getName()), iIndent);
+ }
+ }
+}
+
+void abc_archive_info_stream(IArchive &archive, void (*stream)(void *, const char *), void *userdata)
+{
+ stringstream ss(stream, userdata);
+
+ ss << "Alembic Archive Info for "
+ << Alembic::AbcCoreAbstract::GetLibraryVersion()
+ << g_endl;
+
+ std::string appName;
+ std::string libraryVersionString;
+ Alembic::Util::uint32_t libraryVersion;
+ std::string whenWritten;
+ std::string userDescription;
+ GetArchiveInfo(archive,
+ appName,
+ libraryVersionString,
+ libraryVersion,
+ whenWritten,
+ userDescription);
+
+ if (appName != "") {
+ ss << " file written by: " << appName << g_endl;
+ ss << " using Alembic : " << libraryVersionString << g_endl;
+ ss << " written on : " << whenWritten << g_endl;
+ ss << " user description : " << userDescription << g_endl;
+ ss << g_endl;
+ }
+ else {
+// ss << argv[1] << g_endl;
+ ss << " (file doesn't have any ArchiveInfo)"
+ << g_endl;
+ ss << g_endl;
+ }
+
+ info_stream_object(ss, archive.getTop(), "");
+}
+
+/* ========================================================================= */
+
+static void info_nodes_properties(CacheArchiveInfo *info, ICompoundProperty, CacheArchiveInfoNode *parent, bool calc_bytes_size);
+
+template <class PROP>
+static void info_nodes_array_property(CacheArchiveInfo *info, PROP iProp, CacheArchiveInfoNode *parent, bool calc_bytes_size)
+{
+ CacheArchiveInfoNode *node = BKE_cache_archive_info_add_node(info, parent, eCacheArchiveInfoNode_Type_ArrayProperty, iProp.getName().c_str());
+
+ index_t num_samples = iProp.getNumSamples();
+
+ const DataType &datatype = iProp.getDataType();
+
+ node->num_samples = num_samples;
+ BLI_strncpy(node->datatype_name, PODName(datatype.getPod()), sizeof(node->datatype_name));
+ node->datatype_extent = (short)datatype.getExtent();
+
+ if (calc_bytes_size) {
+ size_t max_array_size = 0;
+ size_t tot_array_size = 0;
+ for (index_t i = 0; i < num_samples; ++i) {
+ AbcA::ArraySamplePtr samp;
+ iProp.get(samp, ISampleSelector(i));
+ size_t array_size = samp->size();
+ max_array_size = std::max(max_array_size, array_size);
+ tot_array_size += array_size;
+ }
+ node->bytes_size = datatype.getNumBytes() * tot_array_size;
+ node->array_size = max_array_size;
+
+ if (parent)
+ parent->bytes_size += node->bytes_size;
+ }
+}
+
+template <class PROP>
+static void info_nodes_scalar_property(CacheArchiveInfo *info, PROP iProp, CacheArchiveInfoNode *parent, bool calc_bytes_size)
+{
+ CacheArchiveInfoNode *node = BKE_cache_archive_info_add_node(info, parent, eCacheArchiveInfoNode_Type_ScalarProperty, iProp.getName().c_str());
+
+ index_t num_samples = iProp.getNumSamples();
+
+ const DataType &datatype = iProp.getDataType();
+
+ node->num_samples = num_samples;
+ BLI_strncpy(node->datatype_name, PODName(datatype.getPod()), sizeof(node->datatype_name));
+ node->datatype_extent = (short)datatype.getExtent();
+
+ if (calc_bytes_size) {
+ node->bytes_size = datatype.getNumBytes() * num_samples;
+
+ if (parent)
+ parent->bytes_size += node->bytes_size;
+ }
+}
+
+static void info_nodes_compound_property(CacheArchiveInfo *info, ICompoundProperty iProp, CacheArchiveInfoNode *parent, bool calc_bytes_size)
+{
+ CacheArchiveInfoNode *node = BKE_cache_archive_info_add_node(info, parent, eCacheArchiveInfoNode_Type_CompoundProperty, iProp.getName().c_str());
+
+ info_nodes_properties(info, iProp, node, calc_bytes_size);
+
+ if (calc_bytes_size && parent)
+ parent->bytes_size += node->bytes_size;
+}
+
+static void info_nodes_properties(CacheArchiveInfo *info, ICompoundProperty iParent, CacheArchiveInfoNode *parent, bool calc_bytes_size)
+{
+ for (size_t i = 0 ; i < iParent.getNumProperties() ; i++) {
+ PropertyHeader header = iParent.getPropertyHeader(i);
+
+ if (header.isCompound()) {
+ info_nodes_compound_property(info, ICompoundProperty(iParent, header.getName()), parent, calc_bytes_size);
+ }
+ else if (header.isScalar()) {
+ info_nodes_scalar_property(info, IScalarProperty(iParent, header.getName()), parent, calc_bytes_size);
+ }
+ else {
+ BLI_assert(header.isArray());
+ info_nodes_array_property(info, IArrayProperty(iParent, header.getName()), parent, calc_bytes_size);
+ }
+ }
+}
+
+static void info_nodes_object(CacheArchiveInfo *info, IObject iObj, CacheArchiveInfoNode *parent, bool calc_bytes_size)
+{
+ CacheArchiveInfoNode *node = BKE_cache_archive_info_add_node(info, parent, eCacheArchiveInfoNode_Type_Object, iObj.getName().c_str());
+
+ if (iObj.isInstanceRoot()) {
+ }
+ else if (iObj.isInstanceDescendant()) {
+ }
+ else {
+ // Get the properties.
+ ICompoundProperty props = iObj.getProperties();
+ info_nodes_properties(info, props, node, calc_bytes_size);
+
+ // now the child objects
+ for (size_t i = 0 ; i < iObj.getNumChildren() ; i++) {
+ info_nodes_object(info, IObject(iObj, iObj.getChildHeader(i).getName()), node, calc_bytes_size);
+ }
+ }
+
+ if (calc_bytes_size && parent)
+ parent->bytes_size += node->bytes_size;
+}
+
+void abc_archive_info_nodes(IArchive &archive, CacheArchiveInfo *info, IDProperty *metadata, bool calc_nodes, bool calc_bytes_size)
+{
+// ss << "Alembic Archive Info for "
+// << Alembic::AbcCoreAbstract::GetLibraryVersion()
+// << g_endl;
+
+ std::string appName;
+ std::string libraryVersionString;
+ uint32_t libraryVersion;
+ std::string whenWritten;
+ std::string userDescription;
+ GetArchiveInfo(archive, appName, libraryVersionString, libraryVersion, whenWritten, userDescription);
+
+ if (appName != "") {
+ BLI_strncpy(info->app_name, appName.c_str(), sizeof(info->app_name));
+ BLI_strncpy(info->date_written, whenWritten.c_str(), sizeof(info->date_written));
+ BLI_strncpy(info->description, userDescription.c_str(), sizeof(info->description));
+ }
+ else {
+ info->app_name[0] = '\0';
+ info->date_written[0] = '\0';
+ info->description[0] = '\0';
+ }
+
+ if (metadata)
+ abc_metadata_to_idprops_group(archive.getPtr()->getMetaData(), metadata);
+
+ if (calc_nodes)
+ info_nodes_object(info, archive.getTop(), NULL, calc_bytes_size);
+}
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/alembic/abc_interpolate.cpp b/source/blender/pointcache/alembic/abc_interpolate.cpp
new file mode 100644
index 00000000000..989734f3c56
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_interpolate.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "abc_interpolate.h"
+
+extern "C" {
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+}
+
+namespace PTC {
+
+using namespace Abc;
+
+
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/alembic/abc_interpolate.h b/source/blender/pointcache/alembic/abc_interpolate.h
new file mode 100644
index 00000000000..102f4680c81
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_interpolate.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_ABC_INTERPOLATE_H
+#define PTC_ABC_INTERPOLATE_H
+
+#include <Alembic/Abc/ISampleSelector.h>
+#include <Alembic/Abc/IScalarProperty.h>
+#include <Alembic/Abc/TypedPropertyTraits.h>
+#include <Alembic/Abc/ITypedArrayProperty.h>
+#include <Alembic/Abc/ITypedScalarProperty.h>
+#include <Alembic/Abc/TypedArraySample.h>
+
+extern "C" {
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+}
+
+namespace PTC {
+
+using namespace Alembic;
+using namespace Abc;
+
+using Alembic::Util::shared_ptr;
+
+enum InterpolateSemanticDefault {
+ InterpolateSemanticDefault_None = 0,
+};
+
+enum InterpolateSemanticVector {
+ InterpolateSemanticVector_Linear = 0,
+ InterpolateSemanticVector_Slerp = 1,
+};
+
+/* linear blending for primitive types */
+template <typename T>
+BLI_INLINE T interpolate_sample(const T &val0, const T &val1, float t)
+{
+ return val0 * (1.0f-t) + val1 * t;
+}
+
+/* vector semantics */
+BLI_INLINE V3f interpolate_sample(const V3f &val0, const V3f &val1, float t, InterpolateSemanticVector semantic)
+{
+ switch (semantic) {
+ case InterpolateSemanticVector_Linear:
+ return val0 * (1.0f-t) + val1 * t;
+ case InterpolateSemanticVector_Slerp:
+ V3f result;
+ interp_v3_v3v3_slerp_safe(result.getValue(), val0.getValue(), val1.getValue(), t);
+ return result;
+ }
+ return V3f(0.0f, 0.0f, 0.0f);
+}
+
+BLI_INLINE Quatf interpolate_sample(const Quatf &val0, const Quatf &val1, float t)
+{
+ float qt0[4] = {val0.r, val0.v.x, val0.v.y, val0.v.z};
+ float qt1[4] = {val1.r, val1.v.x, val1.v.y, val1.v.z};
+ float result[4];
+ interp_qt_qtqt(result, qt0, qt1, t);
+ return Quatf(result[0], result[1], result[2], result[3]);
+}
+
+BLI_INLINE M44f interpolate_sample(const M44f &val0, const M44f &val1, float t)
+{
+ float loc[3], quat[4], size[3];
+ float loc0[3], quat0[4], size0[3];
+ float loc1[3], quat1[4], size1[3];
+ mat4_decompose(loc0, quat0, size0, (float (*)[4])val0.getValue());
+ mat4_decompose(loc1, quat1, size1, (float (*)[4])val1.getValue());
+
+ /* linear interpolation for rotation and scale */
+ interp_v3_v3v3(loc, loc0, loc1, t);
+
+ /* use simpe nlerp instead of slerp. it's faster and almost the same */
+ interp_v4_v4v4(quat, quat0, quat1, t);
+ normalize_qt(quat);
+
+ interp_v3_v3v3(size, size0, size1, t);
+
+ M44f result;
+ loc_quat_size_to_mat4((float (*)[4])result.getValue(), loc, quat, size);
+
+ return result;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* These wrapper types allow calling all the interpolate_sample variants without knowing the semantics type
+ * structs are required for this, since partial specialization does not work with functions.
+ */
+
+/* forward declaration */
+template <typename ArraySampleT, typename SemanticT>
+BLI_INLINE shared_ptr<ArraySampleT> interpolate_sample(const ArraySampleT &val0, const ArraySampleT &val1, float t, SemanticT semantic);
+
+template <typename T, typename SemanticT>
+struct InterpolateSampleCaller {
+ BLI_INLINE T call(const T &val0, const T &val1, float t, SemanticT semantic)
+ {
+ return interpolate_sample(val0, val1, t, semantic);
+ }
+};
+
+template <typename T>
+struct InterpolateSampleCaller<T, InterpolateSemanticDefault> {
+ BLI_INLINE T call(const T &val0, const T &val1, float t, InterpolateSemanticDefault)
+ {
+ return interpolate_sample(val0, val1, t);
+ }
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Scalar Properties */
+
+template <typename PropT, typename SemanticT>
+typename PropT::value_type abc_interpolate_sample_linear(const PropT &prop, chrono_t time, SemanticT semantic)
+{
+ typedef typename PropT::value_type value_type;
+
+ ISampleSelector ss0(time, ISampleSelector::kFloorIndex);
+ ISampleSelector ss1(time, ISampleSelector::kCeilIndex);
+
+ index_t index0 = ss0.getIndex(prop.getTimeSampling(), prop.getNumSamples());
+ index_t index1 = ss1.getIndex(prop.getTimeSampling(), prop.getNumSamples());
+ if (index0 == index1) {
+ /* no interpolation needed */
+ return prop.getValue(ss0);
+ }
+ else {
+ chrono_t time0 = prop.getTimeSampling()->getSampleTime(index0);
+ chrono_t time1 = prop.getTimeSampling()->getSampleTime(index1);
+
+ float t = (time1 > time0) ? (time - time0) / (time1 - time0) : 0.0f;
+ return InterpolateSampleCaller<value_type, SemanticT>::call(prop.getValue(ss0), prop.getValue(ss1), t, semantic);
+ }
+}
+
+template <typename PropT>
+typename PropT::value_type abc_interpolate_sample_linear(const PropT &prop, chrono_t time)
+{
+ return abc_interpolate_sample_linear(prop, time, InterpolateSemanticDefault_None);
+}
+
+
+/* Array Properties */
+
+template <typename ArraySampleT, typename SemanticT>
+BLI_INLINE shared_ptr<ArraySampleT> interpolate_array_sample(const ArraySampleT &val0, const ArraySampleT &val1, float t, SemanticT semantic)
+{
+ typedef ArraySampleT sample_type;
+ typedef shared_ptr<ArraySampleT> sample_ptr_type;
+ typedef typename ArraySampleT::value_type value_type;
+
+ size_t size0 = val0.size();
+ size_t size1 = val1.size();
+ size_t maxsize = size0 > size1 ? size0 : size1;
+ size_t minsize = size0 < size1 ? size0 : size1;
+
+ const value_type *data0 = val0.get();
+ const value_type *data1 = val1.get();
+ value_type *result = new value_type[maxsize];
+ value_type *data = result;
+
+ for (size_t i = 0; i < minsize; ++i) {
+ *data = InterpolateSampleCaller<value_type, SemanticT>::call(*data0, *data1, t, semantic);
+ ++data;
+ ++data0;
+ ++data1;
+ }
+
+ if (size0 > minsize) {
+ for (size_t i = minsize; i < size0; ++i) {
+ *data = *data0;
+ ++data;
+ ++data0;
+ }
+ }
+ else if (size1 > minsize) {
+ for (size_t i = minsize; i < size1; ++i) {
+ *data = *data1;
+ ++data;
+ ++data1;
+ }
+ }
+
+ return sample_ptr_type(new sample_type(result, maxsize));
+}
+
+template <typename TraitsT, typename SemanticT>
+shared_ptr<typename ITypedArrayProperty<TraitsT>::sample_type> abc_interpolate_sample_linear(const ITypedArrayProperty<TraitsT> &prop, chrono_t time, SemanticT semantic)
+{
+ ISampleSelector ss0(time, ISampleSelector::kFloorIndex);
+ ISampleSelector ss1(time, ISampleSelector::kCeilIndex);
+
+ index_t index0 = ss0.getIndex(prop.getTimeSampling(), prop.getNumSamples());
+ index_t index1 = ss1.getIndex(prop.getTimeSampling(), prop.getNumSamples());
+ if (index0 == index1) {
+ /* no interpolation needed */
+ return prop.getValue(ss0);
+ }
+ else {
+ chrono_t time0 = prop.getTimeSampling()->getSampleTime(index0);
+ chrono_t time1 = prop.getTimeSampling()->getSampleTime(index1);
+
+ float t = (time1 > time0) ? (time - time0) / (time1 - time0) : 0.0f;
+ return interpolate_array_sample(*prop.getValue(ss0), *prop.getValue(ss1), t, semantic);
+ }
+}
+
+template <typename TraitsT>
+shared_ptr<typename ITypedArrayProperty<TraitsT>::sample_type> abc_interpolate_sample_linear(const ITypedArrayProperty<TraitsT> &prop, chrono_t time)
+{
+ return abc_interpolate_sample_linear(prop, time, InterpolateSemanticDefault_None);
+}
+
+} /* namespace PTC */
+
+#endif /* PTC_ABC_INTERPOLATE_H */
diff --git a/source/blender/pointcache/alembic/abc_mesh.cpp b/source/blender/pointcache/alembic/abc_mesh.cpp
new file mode 100644
index 00000000000..57f07d47099
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_mesh.cpp
@@ -0,0 +1,630 @@
+/*
+ * Copyright 2014, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "abc_interpolate.h"
+#include "abc_mesh.h"
+
+extern "C" {
+#include "BLI_math.h"
+
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_mesh.h"
+
+#include "PIL_time.h"
+}
+
+#include "PTC_api.h"
+
+//#define USE_TIMING
+
+namespace PTC {
+
+using namespace Abc;
+using namespace AbcGeom;
+
+/* CD layers that are stored in generic customdata arrays created with CD_ALLOC */
+/* XXX CD_MASK_MTFACE and CD_MASK_MTEXPOLY are currently still needed as dummies for syncing
+ * particle UV and MCol layers to the mesh shader attributes ...
+ */
+static CustomDataMask CD_MASK_CACHE_EXCLUDE =
+ CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE | CD_MASK_MPOLY | CD_MASK_MLOOP |
+ /*CD_MASK_MTFACE | CD_MASK_MTEXPOLY |*/
+ CD_MASK_PROP_STR |
+ CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX |
+ CD_MASK_MDISPS | CD_MASK_CREASE | CD_MASK_BWEIGHT | CD_MASK_RECAST | CD_MASK_PAINT_MASK |
+ CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE;
+
+static CustomDataMask CD_MASK_CACHE_VERT = ~(CD_MASK_CACHE_EXCLUDE | CD_MASK_NORMAL);
+static CustomDataMask CD_MASK_CACHE_EDGE = ~(CD_MASK_CACHE_EXCLUDE);
+static CustomDataMask CD_MASK_CACHE_FACE = ~(CD_MASK_CACHE_EXCLUDE);
+static CustomDataMask CD_MASK_CACHE_POLY = ~(CD_MASK_CACHE_EXCLUDE);
+static CustomDataMask CD_MASK_CACHE_LOOP = ~(CD_MASK_CACHE_EXCLUDE);
+
+struct MVertSample {
+ std::vector<V3f> co;
+ std::vector<N3f> no;
+ std::vector<int8_t> flag;
+ std::vector<int8_t> bweight;
+};
+
+struct MEdgeSample {
+ std::vector<uint32_t> verts;
+ std::vector<int16_t> flag;
+ std::vector<int8_t> crease;
+ std::vector<int8_t> bweight;
+};
+
+struct MPolySample {
+ /*std::vector<int32_t> loopstart;*/ /* loopstart is not stored explicitly */
+ std::vector<int32_t> totloop;
+ std::vector<int16_t> mat_nr;
+ std::vector<int8_t> flag;
+};
+
+struct MLoopSample {
+ /* XXX these are unsigned int in DNA, but Alembic expects signed int */
+ std::vector<int32_t> verts;
+ std::vector<int32_t> edges;
+};
+
+AbcDerivedMeshWriter::AbcDerivedMeshWriter(const std::string &name, Object *ob, DerivedMesh **dm_ptr) :
+ DerivedMeshWriter(ob, dm_ptr, name),
+ m_vert_data_writer("vertex_data", CD_MASK_CACHE_VERT),
+ m_edge_data_writer("edge_data", CD_MASK_CACHE_EDGE),
+ m_face_data_writer("face_data", CD_MASK_CACHE_FACE),
+ m_poly_data_writer("poly_data", CD_MASK_CACHE_POLY),
+ m_loop_data_writer("loop_data", CD_MASK_CACHE_LOOP)
+{
+}
+
+AbcDerivedMeshWriter::~AbcDerivedMeshWriter()
+{
+}
+
+void AbcDerivedMeshWriter::init_abc(OObject parent)
+{
+ if (m_mesh)
+ return;
+
+ m_mesh = OPolyMesh(parent, m_name, abc_archive()->frame_sampling_index());
+
+ OPolyMeshSchema &schema = m_mesh.getSchema();
+// OCompoundProperty geom_props = schema.getArbGeomParams();
+ OCompoundProperty user_props = schema.getUserProperties();
+
+ m_prop_vert_normals = ON3fArrayProperty(user_props, "vertex_normals", frame_sampling());
+ m_prop_vert_flag = OCharArrayProperty(user_props, "vertex_flag", frame_sampling());
+ m_prop_vert_bweight = OCharArrayProperty(user_props, "vertex_bweight", frame_sampling());
+
+ m_prop_edge_verts = OUInt32ArrayProperty(user_props, "edge_verts", frame_sampling());
+ m_prop_edge_flag = OInt16ArrayProperty(user_props, "edge_flag", frame_sampling());
+ m_prop_edge_crease = OCharArrayProperty(user_props, "edge_crease", frame_sampling());
+ m_prop_edge_bweight = OCharArrayProperty(user_props, "edge_bweight", frame_sampling());
+
+ m_prop_poly_mat_nr = OInt16ArrayProperty(user_props, "poly_mat_nr", frame_sampling());
+ m_prop_poly_flag = OCharArrayProperty(user_props, "poly_flag", frame_sampling());
+
+ m_prop_loop_verts = OInt32ArrayProperty(user_props, "loop_verts", frame_sampling());
+ m_prop_loop_edges = OInt32ArrayProperty(user_props, "loop_edges", frame_sampling());
+
+ m_vert_data_writer.init(frame_sampling());
+ m_edge_data_writer.init(frame_sampling());
+ m_face_data_writer.init(frame_sampling());
+ m_poly_data_writer.init(frame_sampling());
+ m_loop_data_writer.init(frame_sampling());
+}
+
+/* XXX modifiers are not allowed to generate poly normals on their own!
+ * see assert in DerivedMesh.c : dm_ensure_display_normals
+ */
+#if 0
+static void ensure_normal_data(DerivedMesh *dm)
+{
+ MVert *mverts = dm->getVertArray(dm);
+ MLoop *mloops = dm->getLoopArray(dm);
+ MPoly *mpolys = dm->getPolyArray(dm);
+ CustomData *cdata = dm->getPolyDataLayout(dm);
+ float (*polynors)[3];
+ int totvert = dm->getNumVerts(dm);
+ int totloop = dm->getNumLoops(dm);
+ int totpoly = dm->getNumPolys(dm);
+
+ if (CustomData_has_layer(cdata, CD_NORMAL))
+ polynors = (float (*)[3])CustomData_get_layer(cdata, CD_NORMAL);
+ else
+ polynors = (float (*)[3])CustomData_add_layer(cdata, CD_NORMAL, CD_CALLOC, NULL, totpoly);
+
+ BKE_mesh_calc_normals_poly(mverts, totvert, mloops, mpolys, totloop, totpoly, polynors, false);
+}
+#endif
+
+static void create_sample_verts(DerivedMesh *dm, MVertSample &sample)
+{
+ MVert *mv, *mverts = dm->getVertArray(dm);
+ int i, totvert = dm->getNumVerts(dm);
+
+ sample.co.reserve(totvert);
+ sample.no.reserve(totvert);
+ sample.flag.reserve(totvert);
+ sample.bweight.reserve(totvert);
+ for (i = 0, mv = mverts; i < totvert; ++i, ++mv) {
+ float nor[3];
+
+ sample.co.push_back(V3f(mv->co[0], mv->co[1], mv->co[2]));
+
+ normal_short_to_float_v3(nor, mv->no);
+ sample.no.push_back(N3f(nor[0], nor[1], nor[2]));
+
+ sample.flag.push_back(mv->flag);
+ sample.bweight.push_back(mv->bweight);
+ }
+}
+
+static void create_sample_edges(DerivedMesh *dm, MEdgeSample &sample)
+{
+ MEdge *me, *medges = dm->getEdgeArray(dm);
+ int i, totedge = dm->getNumEdges(dm);
+
+ sample.verts.reserve(totedge * 2);
+ sample.flag.reserve(totedge);
+ sample.crease.reserve(totedge);
+ sample.bweight.reserve(totedge);
+
+ for (i = 0, me = medges; i < totedge; ++i, ++me) {
+ sample.verts.push_back(me->v1);
+ sample.verts.push_back(me->v2);
+ sample.flag.push_back(me->flag);
+ sample.crease.push_back(me->crease);
+ sample.bweight.push_back(me->bweight);
+ }
+}
+
+static void create_sample_polys(DerivedMesh *dm, MPolySample &sample)
+{
+ MPoly *mp, *mpolys = dm->getPolyArray(dm);
+ int i, totpoly = dm->getNumPolys(dm);
+
+ sample.totloop.reserve(totpoly);
+ sample.mat_nr.reserve(totpoly);
+ sample.flag.reserve(totpoly);
+
+ for (i = 0, mp = mpolys; i < totpoly; ++i, ++mp) {
+ sample.totloop.push_back(mp->totloop);
+ sample.mat_nr.push_back(mp->mat_nr);
+ sample.flag.push_back(mp->flag);
+ }
+}
+
+static void create_sample_loops(DerivedMesh *dm, MLoopSample &sample)
+{
+ MLoop *ml, *mloops = dm->getLoopArray(dm);
+ int i, totloop = dm->getNumLoops(dm);
+
+ sample.verts.reserve(totloop);
+ sample.edges.reserve(totloop);
+
+ for (i = 0, ml = mloops; i < totloop; ++i, ++ml) {
+ sample.verts.push_back(ml->v);
+ sample.edges.push_back(ml->e);
+ }
+}
+
+static N3fArraySample create_sample_loop_normals(DerivedMesh *dm, std::vector<N3f> &data)
+{
+ CustomData *cdata = dm->getLoopDataLayout(dm);
+ float (*nor)[3], (*loopnors)[3];
+ int i, totloop = dm->getNumLoops(dm);
+
+ if (!CustomData_has_layer(cdata, CD_NORMAL))
+ return N3fArraySample();
+
+ loopnors = (float (*)[3])CustomData_get_layer(cdata, CD_NORMAL);
+
+ data.reserve(totloop);
+ for (i = 0, nor = loopnors; i < totloop; ++i, ++nor) {
+ float *vec = *nor;
+ data.push_back(N3f(vec[0], vec[1], vec[2]));
+ }
+
+ return N3fArraySample(data);
+}
+
+void AbcDerivedMeshWriter::write_sample()
+{
+ if (!m_mesh)
+ return;
+
+ DerivedMesh *output_dm = *m_dm_ptr;
+ if (!output_dm)
+ return;
+
+ /* TODO make this optional by a flag? */
+ /* XXX does not work atm, see comment above */
+ /*ensure_normal_data(output_dm);*/
+
+ OPolyMeshSchema &schema = m_mesh.getSchema();
+ OCompoundProperty user_props = schema.getUserProperties();
+
+ MVertSample vert_sample;
+ MEdgeSample edge_sample;
+ MPolySample poly_sample;
+ MLoopSample loop_sample;
+
+ std::vector<N3f> loop_normals_buffer;
+
+ // TODO decide how to handle vertex/face normals, in caching vs. export ...
+ DM_ensure_normals(output_dm);
+
+ create_sample_verts(output_dm, vert_sample);
+ create_sample_edges(output_dm, edge_sample);
+ create_sample_polys(output_dm, poly_sample);
+ create_sample_loops(output_dm, loop_sample);
+
+ N3fArraySample lnormals = create_sample_loop_normals(output_dm, loop_normals_buffer);
+
+ OPolyMeshSchema::Sample sample = OPolyMeshSchema::Sample(
+ P3fArraySample(vert_sample.co),
+ Int32ArraySample(loop_sample.verts),
+ Int32ArraySample(poly_sample.totloop),
+ OV2fGeomParam::Sample(), /* XXX define how/which UV map should be considered primary for the alembic schema */
+ ON3fGeomParam::Sample(lnormals, kFacevaryingScope)
+ );
+ schema.set(sample);
+
+ m_prop_vert_normals.set(N3fArraySample(vert_sample.no));
+ m_prop_vert_flag.set(CharArraySample(vert_sample.flag));
+ m_prop_vert_bweight.set(CharArraySample(vert_sample.bweight));
+
+ m_prop_edge_verts.set(UInt32ArraySample(edge_sample.verts));
+ m_prop_edge_flag.set(Int16ArraySample(edge_sample.flag));
+ m_prop_edge_crease.set(CharArraySample(edge_sample.crease));
+ m_prop_edge_bweight.set(CharArraySample(edge_sample.bweight));
+
+ m_prop_poly_mat_nr.set(Int16ArraySample(poly_sample.mat_nr));
+ m_prop_poly_flag.set(CharArraySample(poly_sample.flag));
+
+ m_prop_loop_verts.set(Int32ArraySample(loop_sample.verts));
+ m_prop_loop_edges.set(Int32ArraySample(loop_sample.edges));
+
+ CustomData *vdata = output_dm->getVertDataLayout(output_dm);
+ int num_vdata = output_dm->getNumVerts(output_dm);
+ m_vert_data_writer.write_sample(vdata, num_vdata, user_props);
+
+ CustomData *edata = output_dm->getEdgeDataLayout(output_dm);
+ int num_edata = output_dm->getNumEdges(output_dm);
+ m_edge_data_writer.write_sample(edata, num_edata, user_props);
+
+ CustomData *pdata = output_dm->getPolyDataLayout(output_dm);
+ int num_pdata = output_dm->getNumPolys(output_dm);
+ m_poly_data_writer.write_sample(pdata, num_pdata, user_props);
+
+ CustomData *ldata = output_dm->getLoopDataLayout(output_dm);
+ int num_ldata = output_dm->getNumLoops(output_dm);
+ m_loop_data_writer.write_sample(ldata, num_ldata, user_props);
+
+ DM_ensure_tessface(output_dm);
+ CustomData *fdata = output_dm->getTessFaceDataLayout(output_dm);
+ int num_fdata = output_dm->getNumTessFaces(output_dm);
+ m_face_data_writer.write_sample(fdata, num_fdata, user_props);
+}
+
+/* ========================================================================= */
+
+AbcDerivedMeshReader::AbcDerivedMeshReader(const std::string &name, Object *ob) :
+ DerivedMeshReader(ob, name),
+ m_vert_data_reader("vertex_data", CD_MASK_CACHE_VERT),
+ m_edge_data_reader("edge_data", CD_MASK_CACHE_EDGE),
+ m_face_data_reader("face_data", CD_MASK_CACHE_FACE),
+ m_poly_data_reader("poly_data", CD_MASK_CACHE_POLY),
+ m_loop_data_reader("loop_data", CD_MASK_CACHE_LOOP)
+{
+}
+
+AbcDerivedMeshReader::~AbcDerivedMeshReader()
+{
+}
+
+void AbcDerivedMeshReader::init_abc(IObject object)
+{
+ if (m_mesh)
+ return;
+ m_mesh = IPolyMesh(object, kWrapExisting);
+
+ IPolyMeshSchema &schema = m_mesh.getSchema();
+ ICompoundProperty geom_props = schema.getArbGeomParams();
+ ICompoundProperty user_props = schema.getUserProperties();
+
+ m_prop_vert_normals = IN3fArrayProperty(user_props, "vertex_normals", 0);
+ m_prop_vert_flag = ICharArrayProperty(user_props, "vertex_flag", 0);
+ m_prop_vert_bweight = ICharArrayProperty(user_props, "vertex_bweight", 0);
+
+ m_prop_edge_verts = IUInt32ArrayProperty(user_props, "edge_verts", 0);
+ m_prop_edge_flag = IInt16ArrayProperty(user_props, "edge_flag", 0);
+ m_prop_edge_crease = ICharArrayProperty(user_props, "edge_crease", 0);
+ m_prop_edge_bweight = ICharArrayProperty(user_props, "edge_bweight", 0);
+
+ m_prop_poly_mat_nr = IInt16ArrayProperty(user_props, "poly_mat_nr", 0);
+ m_prop_poly_flag = ICharArrayProperty(user_props, "poly_flag", 0);
+
+ m_prop_loop_verts = IInt32ArrayProperty(user_props, "loop_verts", 0);
+ m_prop_loop_edges = IInt32ArrayProperty(user_props, "loop_edges", 0);
+}
+
+static PTCReadSampleResult apply_sample_verts(DerivedMesh *dm, P3fArraySamplePtr sample_co, N3fArraySamplePtr sample_no,
+ CharArraySamplePtr sample_flag, CharArraySamplePtr sample_bweight)
+{
+ int totvert = dm->getNumVerts(dm);
+
+ if (sample_co->size() != totvert ||
+ sample_no->size() != totvert ||
+ sample_flag->size() != totvert ||
+ sample_bweight->size() != totvert)
+ {
+ return PTC_READ_SAMPLE_INVALID;
+ }
+
+ MVert *mv = dm->getVertArray(dm);
+ for (int i = 0; i < totvert; ++i) {
+ copy_v3_v3(mv->co, (*sample_co)[i].getValue());
+ normal_float_to_short_v3(mv->no, (*sample_no)[i].getValue());
+ mv->flag = (*sample_flag)[i];
+ mv->bweight = (*sample_bweight)[i];
+
+ ++mv;
+ }
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+static PTCReadSampleResult apply_sample_edges(DerivedMesh *dm, UInt32ArraySamplePtr sample_verts, Int16ArraySamplePtr sample_flag,
+ CharArraySamplePtr sample_crease, CharArraySamplePtr sample_bweight, bool &has_edges)
+{
+ int totedge = dm->getNumEdges(dm);
+ if (sample_verts->size() != totedge * 2 ||
+ sample_flag->size() != totedge ||
+ sample_crease->size() != totedge ||
+ sample_bweight->size() != totedge)
+ {
+ has_edges = false;
+ return PTC_READ_SAMPLE_INVALID;
+ }
+
+ const uint32_t *data_verts = sample_verts->get();
+ const int16_t *data_flag = sample_flag->get();
+ const int8_t *data_crease = sample_crease->get();
+ const int8_t *data_bweight = sample_bweight->get();
+
+ MEdge *me = dm->getEdgeArray(dm);
+ for (int i = 0; i < totedge; ++i) {
+ me->v1 = data_verts[0];
+ me->v2 = data_verts[1];
+ me->flag = *data_flag;
+ me->crease = *data_crease;
+ me->bweight = *data_bweight;
+
+ ++me;
+ data_verts += 2;
+ ++data_flag;
+ ++data_crease;
+ ++data_bweight;
+ }
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+static PTCReadSampleResult apply_sample_polys(DerivedMesh *dm, Int32ArraySamplePtr sample_totloop, Int16ArraySamplePtr sample_mat_nr, CharArraySamplePtr sample_flag)
+{
+ int totpoly = dm->getNumPolys(dm);
+ if (sample_totloop->size() != totpoly ||
+ sample_mat_nr->size() != totpoly ||
+ sample_flag->size() != totpoly)
+ {
+ return PTC_READ_SAMPLE_INVALID;
+ }
+
+ const int32_t *data_totloop = sample_totloop->get();
+ const int16_t *data_mat_nr = sample_mat_nr->get();
+ const int8_t *data_flag = sample_flag->get();
+
+ int loopstart = 0;
+ MPoly *mp = dm->getPolyArray(dm);
+ for (int i = 0; i < totpoly; ++i) {
+ mp->totloop = *data_totloop;
+ mp->loopstart = loopstart;
+ mp->mat_nr = *data_mat_nr;
+ mp->flag = *data_flag;
+
+ loopstart += mp->totloop;
+
+ ++mp;
+ ++data_totloop;
+ ++data_mat_nr;
+ ++data_flag;
+ }
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+static PTCReadSampleResult apply_sample_loops(DerivedMesh *dm, Int32ArraySamplePtr sample_verts, Int32ArraySamplePtr sample_edges, bool &has_edges)
+{
+ int totloop = dm->getNumLoops(dm);
+ if (sample_verts->size() != totloop)
+ return PTC_READ_SAMPLE_INVALID;
+
+ const int32_t *data_verts = sample_verts->get();
+
+ MLoop *ml = dm->getLoopArray(dm);
+ for (int i = 0; i < totloop; ++i) {
+ ml->v = *data_verts;
+
+ ++ml;
+ ++data_verts;
+ }
+
+ /* edge data is optional, if not available the edges must be recalculated */
+ if (sample_edges->size() == totloop) {
+ const int32_t *data_edges = sample_edges->get();
+
+ MLoop *ml = dm->getLoopArray(dm);
+ for (int i = 0; i < totloop; ++i) {
+ ml->e = *data_edges;
+
+ ++ml;
+ ++data_edges;
+ }
+ }
+ else {
+ has_edges = false;
+ }
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+PTCReadSampleResult AbcDerivedMeshReader::read_sample_abc(chrono_t time)
+{
+#ifdef USE_TIMING
+ double start_time;
+ double time_get_sample, time_build_mesh, time_calc_edges, time_calc_normals;
+
+#define PROFILE_START \
+ start_time = PIL_check_seconds_timer();
+#define PROFILE_END(var) \
+ var = PIL_check_seconds_timer() - start_time;
+#else
+#define PROFILE_START ;
+#define PROFILE_END(var) ;
+#endif
+
+ /* discard existing result data */
+ discard_result();
+
+ if (!m_mesh)
+ return PTC_READ_SAMPLE_INVALID;
+
+ IPolyMeshSchema &schema = m_mesh.getSchema();
+ if (schema.getNumSamples() == 0)
+ return PTC_READ_SAMPLE_INVALID;
+ ICompoundProperty user_props = schema.getUserProperties();
+
+ ISampleSelector ss = get_frame_sample_selector(time);
+
+ PROFILE_START;
+ IPolyMeshSchema::Sample sample;
+ schema.get(sample, ss);
+
+ P3fArraySamplePtr vert_co = abc_interpolate_sample_linear(schema.getPositionsProperty(), time);
+ Int32ArraySamplePtr loop_verts = sample.getFaceIndices();
+ Int32ArraySamplePtr poly_totloop = sample.getFaceCounts();
+
+ N3fArraySamplePtr vnormals;
+ bool has_normals = false;
+ if (m_prop_vert_normals && m_prop_vert_normals.getNumSamples() > 0) {
+ vnormals = abc_interpolate_sample_linear(m_prop_vert_normals, time, InterpolateSemanticVector_Slerp);
+ has_normals = vnormals->valid();
+ }
+
+ UInt32ArraySamplePtr edge_verts = m_prop_edge_verts.getValue(ss);
+ Int32ArraySamplePtr loop_edges = m_prop_loop_edges.getValue(ss);
+ PROFILE_END(time_get_sample);
+
+ PROFILE_START;
+ bool has_edges = true; // XXX do we have to check for existing sample in advance?
+ int totverts = vert_co->size();
+ int totloops = loop_verts->size();
+ int totpolys = poly_totloop->size();
+ int totedges = has_edges ? edge_verts->size() >> 1 : 0;
+ m_result = CDDM_new(totverts, totedges, 0, totloops, totpolys);
+
+ apply_sample_verts(m_result, vert_co, vnormals, m_prop_vert_flag.getValue(ss), m_prop_vert_bweight.getValue(ss));
+ apply_sample_edges(m_result, edge_verts, m_prop_edge_flag.getValue(ss), m_prop_edge_crease.getValue(ss), m_prop_edge_bweight.getValue(ss), has_edges);
+ apply_sample_polys(m_result, poly_totloop, m_prop_poly_mat_nr.getValue(ss), m_prop_poly_flag.getValue(ss));
+ apply_sample_loops(m_result, loop_verts, loop_edges, has_edges);
+ PROFILE_END(time_build_mesh);
+
+ CustomData *vdata = m_result->getVertDataLayout(m_result);
+ int num_vdata = totverts;
+ m_vert_data_reader.read_sample(ss, vdata, num_vdata, user_props);
+
+ CustomData *edata = m_result->getEdgeDataLayout(m_result);
+ int num_edata = totedges;
+ m_edge_data_reader.read_sample(ss, edata, num_edata, user_props);
+
+ CustomData *pdata = m_result->getPolyDataLayout(m_result);
+ int num_pdata = totpolys;
+ m_poly_data_reader.read_sample(ss, pdata, num_pdata, user_props);
+
+ CustomData *ldata = m_result->getLoopDataLayout(m_result);
+ int num_ldata = totloops;
+ m_loop_data_reader.read_sample(ss, ldata, num_ldata, user_props);
+
+ DM_ensure_tessface(m_result);
+ CustomData *fdata = m_result->getTessFaceDataLayout(m_result);
+ int num_fdata = m_result->getNumTessFaces(m_result);
+ m_face_data_reader.read_sample(ss, fdata, num_fdata, user_props);
+
+ PROFILE_START;
+ if (!has_edges)
+ CDDM_calc_edges(m_result);
+ PROFILE_END(time_calc_edges);
+
+ PROFILE_START;
+ /* we need all normal properties defined, otherwise have to recalculate */
+ has_normals &= CustomData_has_layer(pdata, CD_NORMAL);
+ if (!has_normals) {
+ /* make sure normals are recalculated if there is no sample data */
+ m_result->dirty = (DMDirtyFlag)((int)m_result->dirty | DM_DIRTY_NORMALS);
+ }
+ DM_ensure_normals(m_result); /* only recalculates normals if no valid samples were found (has_normals == false) */
+ PROFILE_END(time_calc_normals);
+
+// BLI_assert(DM_is_valid(m_result));
+
+#ifdef USE_TIMING
+ printf("-------- Point Cache Timing --------\n");
+ printf("read sample: %f seconds\n", time_get_sample);
+ printf("build mesh: %f seconds\n", time_build_mesh);
+ printf("calculate edges: %f seconds\n", time_calc_edges);
+ printf("calculate normals: %f seconds\n", time_calc_normals);
+ printf("------------------------------------\n");
+#endif
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+/* ========================================================================= */
+
+AbcDerivedFinalRealtimeWriter::AbcDerivedFinalRealtimeWriter(const std::string &name, Object *ob) :
+ AbcDerivedMeshWriter(name, ob, &ob->derivedFinal)
+{
+}
+
+
+AbcDerivedFinalRenderWriter::AbcDerivedFinalRenderWriter(const std::string &name, Scene *scene, Object *ob, DerivedMesh **render_dm_ptr) :
+ AbcDerivedMeshWriter(name, ob, render_dm_ptr),
+ m_scene(scene)
+{
+}
+
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/alembic/abc_mesh.h b/source/blender/pointcache/alembic/abc_mesh.h
new file mode 100644
index 00000000000..e00ccc3eef1
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_mesh.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2014, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_ABC_MESH_H
+#define PTC_ABC_MESH_H
+
+#include <Alembic/AbcGeom/IPolyMesh.h>
+#include <Alembic/AbcGeom/OPolyMesh.h>
+
+#include "ptc_types.h"
+
+#include "abc_customdata.h"
+#include "abc_reader.h"
+#include "abc_schema.h"
+#include "abc_writer.h"
+
+extern "C" {
+#include "DNA_modifier_types.h"
+
+#include "BKE_DerivedMesh.h"
+}
+
+struct Object;
+struct DerivedMesh;
+
+namespace PTC {
+
+class AbcDerivedMeshWriter : public DerivedMeshWriter, public AbcWriter {
+public:
+ AbcDerivedMeshWriter(const std::string &name, Object *ob, DerivedMesh **dm_ptr);
+ ~AbcDerivedMeshWriter();
+
+ void init_abc(Abc::OObject parent);
+
+ void write_sample();
+
+private:
+ AbcGeom::OPolyMesh m_mesh;
+
+ /* MVert attributes */
+ AbcGeom::ON3fArrayProperty m_prop_vert_normals;
+ AbcGeom::OCharArrayProperty m_prop_vert_flag;
+ AbcGeom::OCharArrayProperty m_prop_vert_bweight;
+
+ /* MEdge attributes */
+ AbcGeom::OUInt32ArrayProperty m_prop_edge_verts;
+ AbcGeom::OInt16ArrayProperty m_prop_edge_flag;
+ AbcGeom::OCharArrayProperty m_prop_edge_crease;
+ AbcGeom::OCharArrayProperty m_prop_edge_bweight;
+
+ /* MPoly attributes */
+ AbcGeom::OInt16ArrayProperty m_prop_poly_mat_nr;
+ AbcGeom::OCharArrayProperty m_prop_poly_flag;
+
+ /* MLoop attributes */
+ AbcGeom::OInt32ArrayProperty m_prop_loop_verts;
+ AbcGeom::OInt32ArrayProperty m_prop_loop_edges;
+
+ CustomDataWriter m_vert_data_writer;
+ CustomDataWriter m_edge_data_writer;
+ CustomDataWriter m_face_data_writer;
+ CustomDataWriter m_poly_data_writer;
+ CustomDataWriter m_loop_data_writer;
+};
+
+class AbcDerivedMeshReader : public DerivedMeshReader, public AbcReader {
+public:
+ AbcDerivedMeshReader(const std::string &name, Object *ob);
+ ~AbcDerivedMeshReader();
+
+ void init_abc(Abc::IObject object);
+
+ PTCReadSampleResult read_sample_abc(chrono_t time);
+
+private:
+ AbcGeom::IPolyMesh m_mesh;
+
+ /* MVert attributes */
+ AbcGeom::IN3fArrayProperty m_prop_vert_normals;
+ AbcGeom::ICharArrayProperty m_prop_vert_flag;
+ AbcGeom::ICharArrayProperty m_prop_vert_bweight;
+
+ /* MEdge attributes */
+ AbcGeom::IUInt32ArrayProperty m_prop_edge_verts;
+ AbcGeom::IInt16ArrayProperty m_prop_edge_flag;
+ AbcGeom::ICharArrayProperty m_prop_edge_crease;
+ AbcGeom::ICharArrayProperty m_prop_edge_bweight;
+
+ /* MPoly attributes */
+ AbcGeom::IInt16ArrayProperty m_prop_poly_mat_nr;
+ AbcGeom::ICharArrayProperty m_prop_poly_flag;
+
+ /* MLoop attributes */
+ AbcGeom::IInt32ArrayProperty m_prop_loop_verts;
+ AbcGeom::IInt32ArrayProperty m_prop_loop_edges;
+
+ CustomDataReader m_vert_data_reader;
+ CustomDataReader m_edge_data_reader;
+ CustomDataReader m_face_data_reader;
+ CustomDataReader m_poly_data_reader;
+ CustomDataReader m_loop_data_reader;
+};
+
+
+/* -------------------------------------------------------------------------
+ * Writing derived mesh results requires different variants
+ * depending on viewport/render output and whether a cache modifier is used.
+ *
+ * Render DMs are constructed on-the-fly for each sample write, since they
+ * are not constructed immediately during scene frame updates. The writer is
+ * expected to only be called once per frame and object.
+ *
+ * If a cache modifier is used it must be have be activate at the time when
+ * the DM is built. For viewport output this means it should activate the
+ * modifier during it's whole lifetime, so that it caches meshes during the
+ * scene frame update. For render output the modifier should only be active
+ * during the render DM construction.
+ * ------------------------------------------------------------------------- */
+
+
+class AbcDerivedFinalRealtimeWriter : public AbcDerivedMeshWriter {
+public:
+ AbcDerivedFinalRealtimeWriter(const std::string &name, Object *ob);
+};
+
+
+class AbcDerivedFinalRenderWriter : public AbcDerivedMeshWriter {
+public:
+ AbcDerivedFinalRenderWriter(const std::string &name, Scene *scene, Object *ob, DerivedMesh **render_dm_ptr);
+
+private:
+ Scene *m_scene;
+};
+
+
+} /* namespace PTC */
+
+#endif /* PTC_MESH_H */
diff --git a/source/blender/pointcache/alembic/abc_object.cpp b/source/blender/pointcache/alembic/abc_object.cpp
new file mode 100644
index 00000000000..6d4fcdb5b1e
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_object.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "abc_mesh.h"
+#include "abc_object.h"
+#include "abc_particles.h"
+
+extern "C" {
+#include "BLI_math.h"
+
+#include "DNA_object_types.h"
+
+#include "BKE_object.h"
+}
+
+namespace PTC {
+
+using namespace Abc;
+using namespace AbcGeom;
+
+thread_mutex AbcObjectWriter::m_sample_write_mutex;
+
+AbcObjectWriter::AbcObjectWriter(const std::string &name, Scene *scene, Object *ob, bool do_mesh, bool do_hair) :
+ ObjectWriter(ob, name),
+ m_scene(scene),
+ m_final_dm(NULL),
+ m_dm_writer(0)
+{
+ if (do_mesh) {
+ if (m_ob->type == OB_MESH) {
+ m_dm_writer = new AbcDerivedMeshWriter("mesh", ob, &m_final_dm);
+ }
+ }
+
+ if (do_hair) {
+ for (ParticleSystem *psys = (ParticleSystem *)ob->particlesystem.first; psys; psys = psys->next) {
+ if (psys->part && psys->part->type == PART_HAIR) {
+ m_hair_writers.push_back(new AbcHairWriter(psys->name, ob, psys));
+ }
+ }
+ }
+}
+
+AbcObjectWriter::~AbcObjectWriter()
+{
+ if (m_dm_writer)
+ delete m_dm_writer;
+ for (int i = 0; i < m_hair_writers.size(); ++i)
+ if (m_hair_writers[i])
+ delete m_hair_writers[i];
+}
+
+void AbcObjectWriter::init_abc()
+{
+ if (m_abc_object)
+ return;
+
+ m_abc_object = abc_archive()->add_id_object<OObject>((ID *)m_ob);
+
+ if (m_dm_writer) {
+ /* XXX not nice */
+ m_dm_writer->init(abc_archive());
+ m_dm_writer->init_abc(m_abc_object);
+ }
+
+ for (int i = 0; i < m_hair_writers.size(); ++i) {
+ AbcHairWriter *hair_writer = m_hair_writers[i];
+ if (hair_writer) {
+ hair_writer->init(abc_archive());
+ hair_writer->init_abc(m_abc_object);
+ }
+ }
+}
+
+#if 0
+void AbcObjectWriter::create_refs()
+{
+ if ((m_ob->transflag & OB_DUPLIGROUP) && m_ob->dup_group) {
+ OObject abc_group = abc_archive()->get_id_object((ID *)m_ob->dup_group);
+ if (abc_group)
+ m_abc_object.addChildInstance(abc_group, "dup_group");
+ }
+}
+#endif
+
+void AbcObjectWriter::write_sample()
+{
+ if (!m_abc_object)
+ return;
+
+ if (m_dm_writer) {
+ if (abc_archive()->use_render()) {
+ m_final_dm = mesh_create_derived_render(m_scene, m_ob, CD_MASK_BAREMESH);
+
+ if (m_final_dm) {
+ {
+ thread_scoped_lock lock(m_sample_write_mutex);
+ m_dm_writer->write_sample();
+ }
+
+ m_final_dm->release(m_final_dm);
+ }
+ }
+ else {
+ m_final_dm = m_ob->derivedFinal;
+ if (!m_final_dm)
+ m_final_dm = mesh_get_derived_final(m_scene, m_ob, CD_MASK_BAREMESH);
+
+ if (m_final_dm) {
+ thread_scoped_lock lock(m_sample_write_mutex);
+ m_dm_writer->write_sample();
+ }
+ }
+ }
+
+ for (int i = 0; i < m_hair_writers.size(); ++i) {
+ AbcHairWriter *hair_writer = m_hair_writers[i];
+ if (hair_writer) {
+ thread_scoped_lock lock(m_sample_write_mutex);
+ hair_writer->write_sample();
+ }
+ }
+}
+
+
+AbcObjectReader::AbcObjectReader(const std::string &name, Object *ob) :
+ ObjectReader(ob, name)
+{
+}
+
+void AbcObjectReader::init_abc(IObject object)
+{
+ if (m_abc_object)
+ return;
+ m_abc_object = object;
+}
+
+PTCReadSampleResult AbcObjectReader::read_sample_abc(chrono_t /*time*/)
+{
+ if (!m_abc_object)
+ return PTC_READ_SAMPLE_INVALID;
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/alembic/abc_object.h b/source/blender/pointcache/alembic/abc_object.h
new file mode 100644
index 00000000000..973a3312d1b
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_object.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_ABC_OBJECT_H
+#define PTC_ABC_OBJECT_H
+
+#include <vector>
+
+#include <Alembic/Abc/IObject.h>
+#include <Alembic/Abc/OObject.h>
+#include <Alembic/AbcGeom/IXform.h>
+#include <Alembic/AbcGeom/OXform.h>
+
+#include "ptc_types.h"
+
+#include "abc_reader.h"
+#include "abc_schema.h"
+#include "abc_writer.h"
+
+#include "util_thread.h"
+
+struct DerivedMesh;
+struct Object;
+struct Scene;
+
+namespace PTC {
+
+class AbcDerivedMeshWriter;
+class AbcHairWriter;
+
+class AbcObjectWriter : public ObjectWriter, public AbcWriter {
+public:
+ typedef std::vector<AbcHairWriter *> HairWriters;
+
+ AbcObjectWriter(const std::string &name, Scene *scene, Object *ob, bool do_mesh, bool do_hair);
+ ~AbcObjectWriter();
+
+ void init_abc();
+#if 0
+ void create_refs();
+#endif
+
+ void write_sample();
+
+private:
+ Scene *m_scene;
+ DerivedMesh *m_final_dm;
+
+ Abc::OObject m_abc_object;
+ AbcDerivedMeshWriter *m_dm_writer;
+ HairWriters m_hair_writers;
+ static thread_mutex m_sample_write_mutex;
+};
+
+class AbcObjectReader : public ObjectReader, public AbcReader {
+public:
+ AbcObjectReader(const std::string &name, Object *ob);
+
+ void init_abc(Abc::IObject object);
+
+ PTCReadSampleResult read_sample_abc(chrono_t time);
+
+private:
+ Abc::IObject m_abc_object;
+};
+
+} /* namespace PTC */
+
+#endif /* PTC_OBJECT_H */
diff --git a/source/blender/pointcache/alembic/abc_particles.cpp b/source/blender/pointcache/alembic/abc_particles.cpp
new file mode 100644
index 00000000000..10e3ee55d3a
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_particles.cpp
@@ -0,0 +1,1284 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "abc_cloth.h"
+#include "abc_interpolate.h"
+#include "abc_mesh.h"
+#include "abc_particles.h"
+
+extern "C" {
+#include "BLI_listbase.h"
+#include "BLI_math_color.h"
+#include "BLI_math.h"
+
+#include "DNA_listBase.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+
+#include "BKE_anim.h"
+#include "BKE_mesh_sample.h"
+#include "BKE_particle.h"
+#include "BKE_strands.h"
+}
+
+namespace PTC {
+
+using namespace Abc;
+using namespace AbcGeom;
+
+
+struct StrandsChildrenSample {
+ std::vector<int32_t> numverts;
+ std::vector<Quatf> root_rotations;
+ std::vector<V3f> root_positions;
+ std::vector<float32_t> cutoff;
+
+ std::vector<V3f> positions;
+ std::vector<float32_t> times;
+ std::vector<int32_t> parents;
+ std::vector<float32_t> parent_weights;
+ std::vector<V2f> curve_uvs;
+ std::vector<C3f> curve_vcols;
+};
+
+struct StrandsSample {
+ std::vector<int32_t> numverts;
+ std::vector<Quatf> root_rotations;
+ std::vector<uint32_t> root_orig_verts;
+ std::vector<float32_t> root_orig_weights;
+ std::vector<int32_t> root_orig_poly;
+ std::vector<uint32_t> root_orig_loops;
+
+ std::vector<V3f> positions;
+ std::vector<float32_t> times;
+ std::vector<float32_t> weights;
+
+ std::vector<V3f> motion_co;
+ std::vector<V3f> motion_vel;
+};
+
+AbcHairChildrenWriter::AbcHairChildrenWriter(const std::string &name, Object *ob, ParticleSystem *psys) :
+ ParticlesWriter(ob, psys, name)
+{
+ m_psmd = psys_get_modifier(ob, psys);
+}
+
+AbcHairChildrenWriter::~AbcHairChildrenWriter()
+{
+}
+
+void AbcHairChildrenWriter::init_abc(OObject parent)
+{
+ if (m_curves)
+ return;
+
+ /* XXX non-escaped string construction here ... */
+ m_curves = OCurves(parent, m_name, abc_archive()->frame_sampling_index());
+
+ OCurvesSchema &schema = m_curves.getSchema();
+ OCompoundProperty geom_props = schema.getArbGeomParams();
+ OCompoundProperty user_props = schema.getUserProperties();
+
+ m_prop_root_rot = OQuatfArrayProperty(user_props, "root_rotations", abc_archive()->frame_sampling());
+ m_prop_root_positions = OV3fArrayProperty(user_props, "root_positions", abc_archive()->frame_sampling());
+ m_param_cutoff = OFloatGeomParam(geom_props, "cutoff", false, kUniformScope, 1, 0);
+ m_param_times = OFloatGeomParam(geom_props, "times", false, kVertexScope, 1, 0);
+ m_prop_parents = OInt32ArrayProperty(user_props, "parents", abc_archive()->frame_sampling());
+ m_prop_parent_weights = OFloatArrayProperty(user_props, "parent_weights", abc_archive()->frame_sampling());
+ m_prop_curve_uvs = AbcGeom::OV2fArrayProperty(user_props, "curve_uvs", abc_archive()->frame_sampling());
+ m_prop_curve_vcols = AbcGeom::OC3fArrayProperty(user_props, "curve_vcols", abc_archive()->frame_sampling());
+}
+
+static int hair_children_count_totkeys(ParticleCacheKey **pathcache, int totpart)
+{
+ int p;
+ int totkeys = 0;
+
+ if (pathcache) {
+ for (p = 0; p < totpart; ++p) {
+ ParticleCacheKey *keys = pathcache[p];
+ totkeys += keys->segments + 1;
+ }
+ }
+
+ return totkeys;
+}
+
+#if 0
+static int hair_children_parent_advance(HairKey *keys, int totkeys, float time, int k)
+{
+ for (; k + 1 < totkeys; ++k) {
+ if (keys[k+1].time > time)
+ break;
+ }
+ return k;
+}
+
+static void hair_children_calc_strand(Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, ChildParticle *cpa, ParticleCacheKey *keys, int maxkeys, StrandsChildrenSample &sample)
+{
+ const bool between = (psys->part->childtype == PART_CHILD_FACES);
+ ParticleData *parent[4];
+ float weight[4];
+ float hairmat[4][4][4];
+ int parent_key[4] = {0,0,0,0};
+
+ int i, k;
+
+ if (between) {
+ for (i = 0; i < 4; ++i) {
+ parent[i] = &psys->particles[cpa->pa[i]];
+ weight[i] = cpa->w[i];
+ if (parent[i])
+ psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, parent[i], hairmat[i]);
+ }
+ }
+ else {
+ parent[0] = &psys->particles[cpa->parent];
+ parent[1] = parent[2] = parent[3] = NULL;
+ weight[0] = 1.0f;
+ weight[1] = weight[2] = weight[3] = 0.0f;
+ if (parent[0])
+ psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, parent[0], hairmat[0]);
+ }
+
+ int numkeys = keys->segments + 1;
+ for (k = 0; k < numkeys; ++k) {
+ ParticleCacheKey *key = &keys[k];
+ /* XXX particle time values are too messy and confusing, recalculate */
+ float time = maxkeys > 1 ? (float)k / (float)(maxkeys-1) : 0.0f;
+
+ float parent_co[3];
+ zero_v3(parent_co);
+ for (i = 0; i < 4; ++i) {
+ if (!parent[i] || weight[i] <= 0.0f)
+ continue;
+ parent_key[i] = hair_children_parent_advance(parent[i]->hair, parent[i]->totkey, time, parent_key[i]);
+
+ float key_co[3];
+ if (parent_key[i] + 1 < parent[i]->totkey) {
+ HairKey *key0 = &parent[i]->hair[parent_key[i]];
+ HairKey *key1 = &parent[i]->hair[parent_key[i] + 1];
+ float x = (key1->time > key0->time) ? (time - key0->time) / (key1->time - key0->time) : 0.0f;
+ interp_v3_v3v3(key_co, key0->co, key1->co, x);
+ }
+ else {
+ HairKey *key0 = &parent[i]->hair[parent_key[i]];
+ copy_v3_v3(key_co, key0->co);
+ }
+
+ madd_v3_v3fl(parent_co, key_co, weight[i]);
+
+ /* Hair keys are in hair root space, pathcache keys are in world space,
+ * transform both to world space to calculate the offset
+ */
+ mul_m4_v3(hairmat[i], parent_co);
+ }
+
+ /* child position is an offset from the parent */
+ float co[3];
+ sub_v3_v3v3(co, key->co, parent_co);
+
+ sample.positions.push_back(V3f(parent_co[0], parent_co[1], parent_co[2]));
+ sample.times.push_back(time);
+ }
+}
+#endif
+
+BLI_INLINE bool particle_get_face(ParticleSystem *psys, int num_tessface, ChildParticle *cpa, int *r_num, float **r_fuv)
+{
+ ParticleSettings *part = psys->part;
+ const bool between = (part->childtype == PART_CHILD_FACES);
+
+ int num = DMCACHE_NOTFOUND;
+ float *fuv;
+ if (between) {
+ num = cpa->num;
+ fuv = cpa->fuv;
+ }
+ else if (part->from == PART_FROM_FACE) {
+ ParticleData *pa = psys->particles + cpa->pa[0];
+ num = pa->num_dmcache;
+ if (num == DMCACHE_NOTFOUND)
+ num = pa->num;
+ if (num >= num_tessface) {
+ /* happens when simplify is enabled gives invalid coords but would crash otherwise */
+ num = DMCACHE_NOTFOUND;
+ }
+ fuv = pa->fuv;
+ }
+
+ if (ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
+ return false;
+ }
+ else {
+ *r_num = num;
+ *r_fuv = fuv;
+ return true;
+ }
+}
+
+static void hair_children_get_uvs(ParticleSystem *psys, ParticleSystemModifierData *psmd, int totpart, StrandsChildrenSample &sample)
+{
+ const int num_tessface = psmd->dm->getNumTessFaces(psmd->dm);
+
+ MFace *mface = (MFace *)psmd->dm->getTessFaceArray(psmd->dm);
+ const CustomData *facedata = psmd->dm->getTessFaceDataLayout(psmd->dm);
+ int tot_layers = CustomData_number_of_layers(facedata, CD_MTFACE);
+
+ sample.curve_uvs.reserve(tot_layers * totpart);
+
+ for (int num_uv = 0; num_uv < tot_layers; ++num_uv) {
+ MTFace *mtface = (MTFace *)CustomData_get_layer_n(facedata, CD_MTFACE, num_uv);
+ if (!mtface)
+ continue;
+
+ for (int p = 0; p < totpart; ++p) {
+ ChildParticle *cpa = &psys->child[p];
+
+ int num;
+ float *fuv;
+ if (particle_get_face(psys, num_tessface, cpa, &num, &fuv)) {
+ MFace *mf = mface + num;
+ MTFace *mtf = mtface + num;
+
+ float uv[2];
+ psys_interpolate_uvs(mtf, mf->v4, fuv, uv);
+ sample.curve_uvs.push_back(V2f(uv[0], uv[1]));
+ }
+ else {
+ sample.curve_uvs.push_back(V2f(0.0f, 0.0f));
+ }
+ }
+ }
+}
+
+static void hair_children_get_vcols(ParticleSystem *psys, ParticleSystemModifierData *psmd, int totpart, StrandsChildrenSample &sample)
+{
+ const int num_tessface = psmd->dm->getNumTessFaces(psmd->dm);
+
+ MFace *mface = (MFace *)psmd->dm->getTessFaceArray(psmd->dm);
+ const CustomData *facedata = psmd->dm->getTessFaceDataLayout(psmd->dm);
+ int tot_layers = CustomData_number_of_layers(facedata, CD_MCOL);
+
+ sample.curve_vcols.reserve(tot_layers * totpart);
+
+ for (int num_vcol = 0; num_vcol < tot_layers; ++num_vcol) {
+ MCol *mcol = (MCol *)CustomData_get_layer_n(facedata, CD_MCOL, num_vcol);
+ if (!mcol)
+ continue;
+
+ for (int p = 0; p < totpart; ++p) {
+ ChildParticle *cpa = &psys->child[p];
+
+ int num;
+ float *fuv;
+ if (particle_get_face(psys, num_tessface, cpa, &num, &fuv)) {
+ MFace *mf = mface + num;
+ /* XXX another legacy thing: MCol are tessface data, but 4 values per face ... */
+ MCol *mc = mcol + 4 * num;
+
+ MCol col;
+ psys_interpolate_mcol(mc, mf->v4, fuv, &col);
+ /* XXX stupid legacy code: MCol stores values are BGR */
+ unsigned char icol[3] = {col.b, col.g, col.r};
+ C3f fcol;
+ rgb_uchar_to_float(fcol.getValue(), icol);
+ sample.curve_vcols.push_back(fcol);
+ }
+ else {
+ sample.curve_vcols.push_back(C3f(0.0f, 0.0f, 0.0f));
+ }
+ }
+ }
+}
+
+static void hair_children_create_sample(Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, ParticleCacheKey **pathcache, int totpart, int totkeys, int maxkeys,
+ StrandsChildrenSample &sample, bool write_constants)
+{
+ ParticleSettings *part = psys->part;
+ const bool between = (part->childtype == PART_CHILD_FACES);
+
+ int p, k;
+
+ if (write_constants) {
+ sample.numverts.reserve(totpart);
+ sample.parents.reserve(4*totpart);
+ sample.parent_weights.reserve(4*totpart);
+
+ sample.positions.reserve(totkeys);
+ sample.times.reserve(totkeys);
+ }
+
+ sample.root_rotations.reserve(totpart);
+ sample.root_positions.reserve(totpart);
+
+ for (p = 0; p < totpart; ++p) {
+ ChildParticle *cpa = &psys->child[p];
+
+ float hairmat[4][4];
+ psys_child_mat_to_object(ob, psys, psmd, cpa, hairmat);
+
+ if (pathcache) {
+ ParticleCacheKey *keys = pathcache[p];
+ int numkeys = keys->segments + 1;
+
+ if (write_constants) {
+ sample.numverts.push_back(numkeys);
+ if (between) {
+ sample.parents.push_back(cpa->pa[0]);
+ sample.parents.push_back(cpa->pa[1]);
+ sample.parents.push_back(cpa->pa[2]);
+ sample.parents.push_back(cpa->pa[3]);
+ sample.parent_weights.push_back(cpa->w[0]);
+ sample.parent_weights.push_back(cpa->w[1]);
+ sample.parent_weights.push_back(cpa->w[2]);
+ sample.parent_weights.push_back(cpa->w[3]);
+ }
+ else {
+ sample.parents.push_back(cpa->parent);
+ sample.parents.push_back(-1);
+ sample.parents.push_back(-1);
+ sample.parents.push_back(-1);
+ sample.parent_weights.push_back(1.0f);
+ sample.parent_weights.push_back(0.0f);
+ sample.parent_weights.push_back(0.0f);
+ sample.parent_weights.push_back(0.0f);
+ }
+
+ float imat[4][4];
+ mul_m4_m4m4(imat, ob->obmat, hairmat);
+ invert_m4(imat);
+
+ for (k = 0; k < numkeys; ++k) {
+ ParticleCacheKey *key = &keys[k];
+
+ /* pathcache keys are in world space, transform to hair root space */
+ float co[3];
+ mul_v3_m4v3(co, imat, key->co);
+
+ sample.positions.push_back(V3f(co[0], co[1], co[2]));
+ /* XXX particle time values are too messy and confusing, recalculate */
+ sample.times.push_back(maxkeys > 1 ? (float)k / (float)(maxkeys-1) : 0.0f);
+ }
+ }
+ }
+
+ float qt[4];
+ mat4_to_quat(qt, hairmat);
+ sample.root_rotations.push_back(Quatf(qt[0], qt[1], qt[2], qt[3]));
+ float *co = hairmat[3];
+ sample.root_positions.push_back(V3f(co[0], co[1], co[2]));
+ sample.cutoff.push_back(-1.0f);
+ }
+
+ if (write_constants) {
+ DM_ensure_tessface(psmd->dm);
+ hair_children_get_uvs(psys, psmd, totpart, sample);
+ hair_children_get_vcols(psys, psmd, totpart, sample);
+ }
+}
+
+void AbcHairChildrenWriter::write_sample()
+{
+ if (!m_curves)
+ return;
+
+ int totkeys = hair_children_count_totkeys(m_psys->childcache, m_psys->totchild);
+
+ int keysteps = abc_archive()->use_render() ? m_psys->part->ren_step : m_psys->part->draw_step;
+ int maxkeys = (1 << keysteps) + 1 + (m_psys->part->kink);
+ if (ELEM(m_psys->part->kink, PART_KINK_SPIRAL))
+ maxkeys += m_psys->part->kink_extra_steps;
+
+ OCurvesSchema &schema = m_curves.getSchema();
+
+ StrandsChildrenSample child_sample;
+ OCurvesSchema::Sample sample;
+ if (schema.getNumSamples() == 0) {
+ /* write curve sizes only first time, assuming they are constant! */
+ hair_children_create_sample(m_ob, m_psys, m_psmd, m_psys->childcache, m_psys->totchild, totkeys, maxkeys, child_sample, true);
+ sample = OCurvesSchema::Sample(child_sample.positions, child_sample.numverts);
+
+ m_prop_parents.set(Int32ArraySample(child_sample.parents));
+ m_prop_parent_weights.set(FloatArraySample(child_sample.parent_weights));
+ m_prop_curve_uvs.set(V2fArraySample(child_sample.curve_uvs));
+ m_prop_curve_vcols.set(C3fArraySample(child_sample.curve_vcols));
+
+ m_param_times.set(OFloatGeomParam::Sample(FloatArraySample(child_sample.times), kVertexScope));
+
+ schema.set(sample);
+ }
+ else {
+ hair_children_create_sample(m_ob, m_psys, m_psmd, m_psys->childcache, m_psys->totchild, totkeys, maxkeys, child_sample, false);
+ }
+
+ m_prop_root_rot.set(QuatfArraySample(child_sample.root_rotations));
+ m_prop_root_positions.set(V3fArraySample(child_sample.root_positions));
+ m_param_cutoff.set(OFloatGeomParam::Sample(FloatArraySample(child_sample.cutoff), kUniformScope));
+}
+
+
+AbcHairWriter::AbcHairWriter(const std::string &name, Object *ob, ParticleSystem *psys) :
+ ParticlesWriter(ob, psys, name),
+ m_child_writer("children", ob, psys)
+{
+ m_psmd = psys_get_modifier(ob, psys);
+}
+
+AbcHairWriter::~AbcHairWriter()
+{
+}
+
+void AbcHairWriter::init(WriterArchive *archive)
+{
+ AbcWriter::init(archive);
+ m_child_writer.init(archive);
+}
+
+void AbcHairWriter::init_abc(OObject parent)
+{
+ if (m_curves)
+ return;
+ m_curves = OCurves(parent, m_name, abc_archive()->frame_sampling_index());
+
+ OCurvesSchema &schema = m_curves.getSchema();
+ OCompoundProperty geom_props = schema.getArbGeomParams();
+
+ m_param_root_rot = OQuatfGeomParam(geom_props, "root_rotations", false, kUniformScope, 1, 0);
+ m_param_root_orig_verts = OUInt32GeomParam(geom_props, "root_orig_verts", false, kUniformScope, 1, 0);
+ m_param_root_orig_weights = OFloatGeomParam(geom_props, "root_orig_weights", false, kUniformScope, 1, 0);
+ m_param_root_orig_poly = OInt32GeomParam(geom_props, "root_orig_poly", false, kUniformScope, 1, 0);
+ m_param_root_orig_loops = OUInt32GeomParam(geom_props, "root_orig_loops", false, kUniformScope, 1, 0);
+
+ m_param_times = OFloatGeomParam(geom_props, "times", false, kVertexScope, 1, 0);
+ m_param_weights = OFloatGeomParam(geom_props, "weights", false, kVertexScope, 1, 0);
+
+ m_child_writer.init_abc(m_curves);
+}
+
+static int hair_count_totverts(ParticleSystem *psys)
+{
+ int p;
+ int totverts = 0;
+
+ for (p = 0; p < psys->totpart; ++p) {
+ ParticleData *pa = &psys->particles[p];
+ totverts += pa->totkey;
+ }
+
+ return totverts;
+}
+
+static void hair_create_sample(Object *ob, DerivedMesh *dm, ParticleSystem *psys, StrandsSample &sample, bool do_numverts)
+{
+ int totpart = psys->totpart;
+ int totverts = hair_count_totverts(psys);
+ int p, k;
+
+ if (totverts == 0)
+ return;
+
+ if (do_numverts)
+ sample.numverts.reserve(totpart);
+ sample.root_rotations.reserve(totpart);
+ sample.root_orig_verts.reserve(totpart * 3);
+ sample.root_orig_weights.reserve(totpart * 3);
+ sample.root_orig_poly.reserve(totpart);
+ sample.root_orig_loops.reserve(totpart * 3);
+ sample.positions.reserve(totverts);
+ sample.times.reserve(totverts);
+ sample.weights.reserve(totverts);
+
+ for (p = 0; p < totpart; ++p) {
+ ParticleData *pa = &psys->particles[p];
+ int numverts = pa->totkey;
+ float hairmat[4][4];
+
+ if (do_numverts)
+ sample.numverts.push_back(numverts);
+
+ psys_mat_hair_to_object(ob, dm, psys->part->from, pa, hairmat);
+ float root_qt[4];
+ mat4_to_quat(root_qt, hairmat);
+ sample.root_rotations.push_back(Quatf(root_qt[0], root_qt[1], root_qt[2], root_qt[3]));
+
+ MSurfaceSample surf;
+ BKE_mesh_sample_from_particle(&surf, psys, dm, pa);
+ sample.root_orig_verts.push_back(surf.orig_verts[0]);
+ sample.root_orig_verts.push_back(surf.orig_verts[1]);
+ sample.root_orig_verts.push_back(surf.orig_verts[2]);
+ sample.root_orig_weights.push_back(surf.orig_weights[0]);
+ sample.root_orig_weights.push_back(surf.orig_weights[1]);
+ sample.root_orig_weights.push_back(surf.orig_weights[2]);
+ sample.root_orig_poly.push_back(surf.orig_poly);
+ sample.root_orig_loops.push_back(surf.orig_loops[0]);
+ sample.root_orig_loops.push_back(surf.orig_loops[1]);
+ sample.root_orig_loops.push_back(surf.orig_loops[2]);
+
+ for (k = 0; k < numverts; ++k) {
+ HairKey *key = &pa->hair[k];
+
+ /* hair keys are in "hair space" relative to the mesh,
+ * store them in object space for compatibility and to avoid
+ * complexities of how particles work.
+ */
+ float co[3];
+ mul_v3_m4v3(co, hairmat, key->co);
+
+ sample.positions.push_back(V3f(co[0], co[1], co[2]));
+ /* XXX particle time values are too messy and confusing, recalculate */
+ sample.times.push_back(numverts > 1 ? (float)k / (float)(numverts-1) : 0.0f);
+ sample.weights.push_back(key->weight);
+ }
+ }
+}
+
+void AbcHairWriter::write_sample()
+{
+ if (!m_curves)
+ return;
+ if (!m_psmd || !m_psmd->dm)
+ return;
+
+ OCurvesSchema &schema = m_curves.getSchema();
+
+ StrandsSample hair_sample;
+ OCurvesSchema::Sample sample;
+ if (schema.getNumSamples() == 0) {
+ /* write curve sizes only first time, assuming they are constant! */
+ hair_create_sample(m_ob, m_psmd->dm, m_psys, hair_sample, true);
+ sample = OCurvesSchema::Sample(hair_sample.positions, hair_sample.numverts);
+ }
+ else {
+ hair_create_sample(m_ob, m_psmd->dm, m_psys, hair_sample, false);
+ sample = OCurvesSchema::Sample(hair_sample.positions);
+ }
+ schema.set(sample);
+
+ m_param_root_rot.set(OQuatfGeomParam::Sample(QuatfArraySample(hair_sample.root_rotations), kUniformScope));
+ m_param_root_orig_verts.set(OUInt32GeomParam::Sample(UInt32ArraySample(hair_sample.root_orig_verts), kUniformScope));
+ m_param_root_orig_weights.set(OFloatGeomParam::Sample(FloatArraySample(hair_sample.root_orig_weights), kUniformScope));
+ m_param_root_orig_poly.set(OInt32GeomParam::Sample(Int32ArraySample(hair_sample.root_orig_poly), kUniformScope));
+ m_param_root_orig_loops.set(OUInt32GeomParam::Sample(UInt32ArraySample(hair_sample.root_orig_loops), kUniformScope));
+
+ m_param_times.set(OFloatGeomParam::Sample(FloatArraySample(hair_sample.times), kVertexScope));
+ m_param_weights.set(OFloatGeomParam::Sample(FloatArraySample(hair_sample.weights), kVertexScope));
+
+ m_child_writer.write_sample();
+}
+
+
+AbcStrandsChildrenWriter::AbcStrandsChildrenWriter(const std::string &name, const std::string &abc_name, DupliObjectData *dobdata) :
+ m_name(name),
+ m_abc_name(abc_name),
+ m_dobdata(dobdata)
+{
+}
+
+StrandsChildren *AbcStrandsChildrenWriter::get_strands() const
+{
+ StrandsChildren *children;
+ BKE_dupli_object_data_find_strands(m_dobdata, m_name.c_str(), NULL, &children);
+ return children;
+}
+
+void AbcStrandsChildrenWriter::init_abc(OObject parent)
+{
+ if (m_curves)
+ return;
+ m_curves = OCurves(parent, m_abc_name, abc_archive()->frame_sampling_index());
+
+ OCurvesSchema &schema = m_curves.getSchema();
+ OCompoundProperty geom_props = schema.getArbGeomParams();
+ OCompoundProperty user_props = schema.getUserProperties();
+
+ m_prop_root_rot = OQuatfArrayProperty(user_props, "root_rotations", abc_archive()->frame_sampling());
+ m_prop_root_positions = OV3fArrayProperty(user_props, "root_positions", abc_archive()->frame_sampling());
+ m_param_cutoff = OFloatGeomParam(geom_props, "cutoff", false, kUniformScope, 1, abc_archive()->frame_sampling());
+ m_param_times = OFloatGeomParam(geom_props, "times", false, kVertexScope, 1, abc_archive()->frame_sampling());
+ m_prop_parents = OInt32ArrayProperty(user_props, "parents", abc_archive()->frame_sampling());
+ m_prop_parent_weights = OFloatArrayProperty(user_props, "parent_weights", abc_archive()->frame_sampling());
+ m_prop_curve_uvs = AbcGeom::OV2fArrayProperty(user_props, "curve_uvs", abc_archive()->frame_sampling());
+ m_prop_curve_vcols = AbcGeom::OC3fArrayProperty(user_props, "curve_vcols", abc_archive()->frame_sampling());
+}
+
+static void strands_children_get_uvs(StrandsChildren *strands, StrandsChildrenSample &sample)
+{
+ int totuv = strands->numuv * strands->totcurves;
+
+ sample.curve_uvs.reserve(totuv);
+
+ for (int i = 0; i < totuv; ++i) {
+ StrandsChildCurveUV *uv = &strands->curve_uvs[i];
+ sample.curve_uvs.push_back(V2f(uv->uv[0], uv->uv[1]));
+ }
+}
+
+static void strands_children_get_vcols(StrandsChildren *strands, StrandsChildrenSample &sample)
+{
+ int totvcol = strands->numvcol * strands->totcurves;
+
+ sample.curve_vcols.reserve(totvcol);
+
+ for (int i = 0; i < totvcol; ++i) {
+ StrandsChildCurveVCol *vcol = &strands->curve_vcols[i];
+ sample.curve_vcols.push_back(C3f(vcol->vcol[0], vcol->vcol[1], vcol->vcol[2]));
+ }
+}
+
+static void strands_children_create_sample(StrandsChildren *strands, StrandsChildrenSample &sample, bool write_constants)
+{
+ int totcurves = strands->totcurves;
+ int totverts = strands->totverts;
+
+ if (write_constants) {
+ sample.numverts.reserve(totcurves);
+ sample.parents.reserve(4*totcurves);
+ sample.parent_weights.reserve(4*totcurves);
+
+ sample.positions.reserve(totverts);
+ sample.times.reserve(totverts);
+ }
+
+ sample.root_rotations.reserve(totcurves);
+ sample.root_positions.reserve(totcurves);
+
+ StrandChildIterator it_strand;
+ for (BKE_strand_child_iter_init(&it_strand, strands); BKE_strand_child_iter_valid(&it_strand); BKE_strand_child_iter_next(&it_strand)) {
+ int numverts = it_strand.curve->numverts;
+
+ if (write_constants) {
+ sample.numverts.push_back(numverts);
+
+ sample.parents.push_back(it_strand.curve->parents[0]);
+ sample.parents.push_back(it_strand.curve->parents[1]);
+ sample.parents.push_back(it_strand.curve->parents[2]);
+ sample.parents.push_back(it_strand.curve->parents[3]);
+ sample.parent_weights.push_back(it_strand.curve->parent_weights[0]);
+ sample.parent_weights.push_back(it_strand.curve->parent_weights[1]);
+ sample.parent_weights.push_back(it_strand.curve->parent_weights[2]);
+ sample.parent_weights.push_back(it_strand.curve->parent_weights[3]);
+
+ StrandChildVertexIterator it_vert;
+ for (BKE_strand_child_vertex_iter_init(&it_vert, &it_strand); BKE_strand_child_vertex_iter_valid(&it_vert); BKE_strand_child_vertex_iter_next(&it_vert)) {
+ const float *co = it_vert.vertex->base;
+ sample.positions.push_back(V3f(co[0], co[1], co[2]));
+ sample.times.push_back(it_vert.vertex->time);
+ }
+ }
+
+ float qt[4];
+ mat4_to_quat(qt, it_strand.curve->root_matrix);
+ sample.root_rotations.push_back(Quatf(qt[0], qt[1], qt[2], qt[3]));
+ float *co = it_strand.curve->root_matrix[3];
+ sample.root_positions.push_back(V3f(co[0], co[1], co[2]));
+ sample.cutoff.push_back(it_strand.curve->cutoff);
+ }
+
+ if (write_constants) {
+ strands_children_get_uvs(strands, sample);
+ strands_children_get_vcols(strands, sample);
+ }
+}
+
+void AbcStrandsChildrenWriter::write_sample()
+{
+ if (!m_curves)
+ return;
+ StrandsChildren *strands = get_strands();
+ if (!strands)
+ return;
+
+ OCurvesSchema &schema = m_curves.getSchema();
+
+ StrandsChildrenSample strands_sample;
+ OCurvesSchema::Sample sample;
+ if (schema.getNumSamples() == 0) {
+ /* write curve sizes only first time, assuming they are constant! */
+ strands_children_create_sample(strands, strands_sample, true);
+ sample = OCurvesSchema::Sample(strands_sample.positions, strands_sample.numverts);
+
+ m_prop_parents.set(Int32ArraySample(strands_sample.parents));
+ m_prop_parent_weights.set(FloatArraySample(strands_sample.parent_weights));
+ m_prop_curve_uvs.set(V2fArraySample(strands_sample.curve_uvs));
+ m_prop_curve_vcols.set(C3fArraySample(strands_sample.curve_vcols));
+
+ m_param_times.set(OFloatGeomParam::Sample(FloatArraySample(strands_sample.times), kVertexScope));
+
+ schema.set(sample);
+ }
+ else {
+ strands_children_create_sample(strands, strands_sample, false);
+ }
+
+ m_prop_root_rot.set(QuatfArraySample(strands_sample.root_rotations));
+ m_prop_root_positions.set(V3fArraySample(strands_sample.root_positions));
+ m_param_cutoff.set(OFloatGeomParam::Sample(FloatArraySample(strands_sample.cutoff), kUniformScope));
+}
+
+
+AbcStrandsWriter::AbcStrandsWriter(const std::string &name, DupliObjectData *dobdata) :
+ m_name(name),
+ m_dobdata(dobdata),
+ m_child_writer(name, "children", dobdata)
+{
+}
+
+Strands *AbcStrandsWriter::get_strands() const
+{
+ Strands *strands;
+ BKE_dupli_object_data_find_strands(m_dobdata, m_name.c_str(), &strands, NULL);
+ return strands;
+}
+
+void AbcStrandsWriter::init(WriterArchive *archive)
+{
+ AbcWriter::init(archive);
+ m_child_writer.init(archive);
+}
+
+void AbcStrandsWriter::init_abc(OObject parent)
+{
+ if (m_curves)
+ return;
+ m_curves = OCurves(parent, m_name, abc_archive()->frame_sampling_index());
+
+ OCurvesSchema &schema = m_curves.getSchema();
+ OCompoundProperty geom_props = schema.getArbGeomParams();
+
+ m_param_root_rot = OQuatfGeomParam(geom_props, "root_rotations", false, kUniformScope, 1, abc_archive()->frame_sampling());
+ m_param_root_orig_verts = OUInt32GeomParam(geom_props, "root_orig_verts", false, kUniformScope, 1, 0);
+ m_param_root_orig_weights = OFloatGeomParam(geom_props, "root_orig_weights", false, kUniformScope, 1, 0);
+ m_param_root_orig_poly = OInt32GeomParam(geom_props, "root_orig_poly", false, kUniformScope, 1, 0);
+ m_param_root_orig_loops = OUInt32GeomParam(geom_props, "root_orig_loops", false, kUniformScope, 1, 0);
+
+ m_param_times = OFloatGeomParam(geom_props, "times", false, kVertexScope, 1, abc_archive()->frame_sampling());
+ m_param_weights = OFloatGeomParam(geom_props, "weights", false, kVertexScope, 1, abc_archive()->frame_sampling());
+
+ m_param_motion_state = OCompoundProperty(geom_props, "motion_state", abc_archive()->frame_sampling());
+ m_param_motion_co = OP3fGeomParam(m_param_motion_state, "position", false, kVertexScope, 1, abc_archive()->frame_sampling());
+ m_param_motion_vel = OV3fGeomParam(m_param_motion_state, "velocity", false, kVertexScope, 1, abc_archive()->frame_sampling());
+
+ m_child_writer.init_abc(m_curves);
+}
+
+static void strands_create_sample(Strands *strands, StrandsSample &sample, bool do_numverts)
+{
+ const bool do_state = strands->state;
+
+ int totcurves = strands->totcurves;
+ int totverts = strands->totverts;
+
+ if (totverts == 0)
+ return;
+
+ if (do_numverts)
+ sample.numverts.reserve(totcurves);
+ sample.root_rotations.reserve(totcurves);
+ sample.root_orig_verts.reserve(totcurves * 3);
+ sample.root_orig_weights.reserve(totcurves * 3);
+ sample.root_orig_poly.reserve(totcurves);
+ sample.root_orig_loops.reserve(totcurves * 3);
+
+ sample.positions.reserve(totverts);
+ sample.times.reserve(totverts);
+ sample.weights.reserve(totverts);
+ if (do_state) {
+ sample.motion_co.reserve(totverts);
+ sample.motion_vel.reserve(totverts);
+ }
+
+ StrandIterator it_strand;
+ for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+ int numverts = it_strand.curve->numverts;
+
+ if (do_numverts)
+ sample.numverts.push_back(numverts);
+ float qt[4];
+ mat3_to_quat(qt, it_strand.curve->root_matrix);
+ sample.root_rotations.push_back(Quatf(qt[0], qt[1], qt[2], qt[3]));
+
+ sample.root_orig_verts.push_back(it_strand.curve->msurf.orig_verts[0]);
+ sample.root_orig_verts.push_back(it_strand.curve->msurf.orig_verts[1]);
+ sample.root_orig_verts.push_back(it_strand.curve->msurf.orig_verts[2]);
+ sample.root_orig_weights.push_back(it_strand.curve->msurf.orig_weights[0]);
+ sample.root_orig_weights.push_back(it_strand.curve->msurf.orig_weights[1]);
+ sample.root_orig_weights.push_back(it_strand.curve->msurf.orig_weights[2]);
+ sample.root_orig_poly.push_back(it_strand.curve->msurf.orig_poly);
+ sample.root_orig_loops.push_back(it_strand.curve->msurf.orig_loops[0]);
+ sample.root_orig_loops.push_back(it_strand.curve->msurf.orig_loops[1]);
+ sample.root_orig_loops.push_back(it_strand.curve->msurf.orig_loops[2]);
+
+ StrandVertexIterator it_vert;
+ for (BKE_strand_vertex_iter_init(&it_vert, &it_strand); BKE_strand_vertex_iter_valid(&it_vert); BKE_strand_vertex_iter_next(&it_vert)) {
+ const float *co = it_vert.vertex->co;
+ sample.positions.push_back(V3f(co[0], co[1], co[2]));
+ sample.times.push_back(it_vert.vertex->time);
+ sample.weights.push_back(it_vert.vertex->weight);
+
+ if (do_state) {
+ float *co = it_vert.state->co;
+ float *vel = it_vert.state->vel;
+ sample.motion_co.push_back(V3f(co[0], co[1], co[2]));
+ sample.motion_vel.push_back(V3f(vel[0], vel[1], vel[2]));
+ }
+ }
+ }
+}
+
+void AbcStrandsWriter::write_sample()
+{
+ if (!m_curves)
+ return;
+ Strands *strands = get_strands();
+ if (!strands)
+ return;
+
+ OCurvesSchema &schema = m_curves.getSchema();
+
+ StrandsSample strands_sample;
+ OCurvesSchema::Sample sample;
+ if (schema.getNumSamples() == 0) {
+ /* write curve sizes only first time, assuming they are constant! */
+ strands_create_sample(strands, strands_sample, true);
+ sample = OCurvesSchema::Sample(strands_sample.positions, strands_sample.numverts);
+ }
+ else {
+ strands_create_sample(strands, strands_sample, false);
+ sample = OCurvesSchema::Sample(strands_sample.positions);
+ }
+ schema.set(sample);
+
+ m_param_root_rot.set(OQuatfGeomParam::Sample(QuatfArraySample(strands_sample.root_rotations), kUniformScope));
+ m_param_root_orig_verts.set(OUInt32GeomParam::Sample(UInt32ArraySample(strands_sample.root_orig_verts), kUniformScope));
+ m_param_root_orig_weights.set(OFloatGeomParam::Sample(FloatArraySample(strands_sample.root_orig_weights), kUniformScope));
+ m_param_root_orig_poly.set(OInt32GeomParam::Sample(Int32ArraySample(strands_sample.root_orig_poly), kUniformScope));
+ m_param_root_orig_loops.set(OUInt32GeomParam::Sample(UInt32ArraySample(strands_sample.root_orig_loops), kUniformScope));
+
+ m_param_times.set(OFloatGeomParam::Sample(FloatArraySample(strands_sample.times), kVertexScope));
+ m_param_weights.set(OFloatGeomParam::Sample(FloatArraySample(strands_sample.weights), kVertexScope));
+
+ if (strands->state) {
+ m_param_motion_co.set(OP3fGeomParam::Sample(P3fArraySample(strands_sample.motion_co), kVertexScope));
+ m_param_motion_vel.set(OV3fGeomParam::Sample(V3fArraySample(strands_sample.motion_vel), kVertexScope));
+ }
+
+ m_child_writer.write_sample();
+}
+
+#if 0
+#define PRINT_M3_FORMAT "((%.3f, %.3f, %.3f), (%.3f, %.3f, %.3f), (%.3f, %.3f, %.3f))"
+#define PRINT_M3_ARGS(m) (double)m[0][0], (double)m[0][1], (double)m[0][2], (double)m[1][0], (double)m[1][1], (double)m[1][2], (double)m[2][0], (double)m[2][1], (double)m[2][2]
+#define PRINT_M4_FORMAT "((%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f))"
+#define PRINT_M4_ARGS(m) (double)m[0][0], (double)m[0][1], (double)m[0][2], (double)m[0][3], (double)m[1][0], (double)m[1][1], (double)m[1][2], (double)m[1][3], \
+ (double)m[2][0], (double)m[2][1], (double)m[2][2], (double)m[2][3], (double)m[3][0], (double)m[3][1], (double)m[3][2], (double)m[3][3]
+#endif
+
+AbcStrandsChildrenReader::AbcStrandsChildrenReader(StrandsChildren *strands) :
+ m_strands(strands)
+{
+}
+
+AbcStrandsChildrenReader::~AbcStrandsChildrenReader()
+{
+ discard_result();
+}
+
+void AbcStrandsChildrenReader::init_abc(IObject object)
+{
+ if (m_curves)
+ return;
+ m_curves = ICurves(object, kWrapExisting);
+
+ ICurvesSchema &schema = m_curves.getSchema();
+ ICompoundProperty geom_props = schema.getArbGeomParams();
+ ICompoundProperty user_props = schema.getUserProperties();
+
+ m_prop_root_rot = IQuatfArrayProperty(user_props, "root_rotations");
+ m_prop_root_positions = IV3fArrayProperty(user_props, "root_positions");
+ if (geom_props.getPropertyHeader("cutoff"))
+ m_param_cutoff = IFloatGeomParam(geom_props, "cutoff");
+ m_param_times = IFloatGeomParam(geom_props, "times");
+ m_prop_parents = IInt32ArrayProperty(user_props, "parents", 0);
+ m_prop_parent_weights = IFloatArrayProperty(user_props, "parent_weights", 0);
+ m_prop_curve_uvs = IV2fArrayProperty(user_props, "curve_uvs", 0);
+ m_prop_curve_vcols = IC3fArrayProperty(user_props, "curve_vcols", 0);
+}
+
+PTCReadSampleResult AbcStrandsChildrenReader::read_sample_abc(chrono_t time)
+{
+ ISampleSelector ss = get_frame_sample_selector(time);
+
+ if (!m_curves.valid()) {
+ return PTC_READ_SAMPLE_INVALID;
+ }
+
+ ICurvesSchema &schema = m_curves.getSchema();
+ if (schema.getNumSamples() == 0) {
+ return PTC_READ_SAMPLE_INVALID;
+ }
+
+ ICurvesSchema::Sample sample;
+ schema.get(sample, ss);
+
+ P3fArraySamplePtr sample_co = sample.getPositions();
+ Int32ArraySamplePtr sample_numvert = sample.getCurvesNumVertices();
+ QuatfArraySamplePtr sample_root_rotations = abc_interpolate_sample_linear(m_prop_root_rot, time);
+ V3fArraySamplePtr sample_root_positions = abc_interpolate_sample_linear(m_prop_root_positions, time);
+ IFloatGeomParam::Sample sample_cutoff;
+ if (m_param_cutoff)
+ sample_cutoff = m_param_cutoff.getExpandedValue(ss);
+ IFloatGeomParam::Sample sample_time = m_param_times.getExpandedValue(ss);
+ Int32ArraySamplePtr sample_parents = m_prop_parents.getValue(ss);
+ FloatArraySamplePtr sample_parent_weights = m_prop_parent_weights.getValue(ss);
+ V2fArraySamplePtr sample_curve_uvs = m_prop_curve_uvs.getValue(ss);
+ C3fArraySamplePtr sample_curve_vcols = m_prop_curve_vcols.getValue(ss);
+
+ if (!sample_co || !sample_numvert) {
+ return PTC_READ_SAMPLE_INVALID;
+ }
+
+ int totcurves = sample_numvert->size();
+ int totverts = sample_co->size();
+
+ if (!totcurves) {
+ return PTC_READ_SAMPLE_INVALID;
+ }
+
+ if (sample_root_rotations->size() != totcurves ||
+ sample_root_positions->size() != totcurves ||
+ sample_parents->size() != 4 * totcurves ||
+ sample_parent_weights->size() != 4 * totcurves)
+ return PTC_READ_SAMPLE_INVALID;
+
+ if (m_strands && (m_strands->totcurves != totcurves || m_strands->totverts != totverts))
+ m_strands = NULL;
+ if (!m_strands)
+ m_strands = BKE_strands_children_new(totcurves, totverts);
+
+ const int32_t *numvert = sample_numvert->get();
+ const Quatf *root_rot = sample_root_rotations->get();
+ const V3f *root_positions = sample_root_positions->get();
+ const float32_t *cutoff = sample_cutoff ? sample_cutoff.getVals()->get() : NULL;
+ const int32_t *parents = sample_parents->get();
+ const float32_t *parent_weights = sample_parent_weights->get();
+ for (int i = 0; i < sample_numvert->size(); ++i) {
+ StrandsChildCurve *scurve = &m_strands->curves[i];
+ scurve->numverts = *numvert;
+ scurve->cutoff = -1.0f;
+
+ float qt[4] = {root_rot->r, root_rot->v.x, root_rot->v.y, root_rot->v.z};
+ quat_to_mat4(scurve->root_matrix, qt);
+ copy_v3_v3(scurve->root_matrix[3], root_positions->getValue());
+
+ scurve->cutoff = cutoff ? *cutoff : -1.0f;
+
+ scurve->parents[0] = parents[0];
+ scurve->parents[1] = parents[1];
+ scurve->parents[2] = parents[2];
+ scurve->parents[3] = parents[3];
+ scurve->parent_weights[0] = parent_weights[0];
+ scurve->parent_weights[1] = parent_weights[1];
+ scurve->parent_weights[2] = parent_weights[2];
+ scurve->parent_weights[3] = parent_weights[3];
+
+ ++numvert;
+ ++root_rot;
+ ++root_positions;
+ parents += 4;
+ parent_weights += 4;
+ if (cutoff) ++cutoff;
+ }
+
+ if (sample_curve_uvs->size() > 0 && sample_curve_uvs->size() % totcurves == 0) {
+ int num_layers = sample_curve_uvs->size() / totcurves;
+
+ const V2f *uvs = sample_curve_uvs->get();
+
+ BKE_strands_children_add_uvs(m_strands, num_layers);
+
+ StrandsChildCurveUV *scurve_uv = m_strands->curve_uvs;
+ for (int j = 0; j < num_layers; ++j) {
+ for (int i = 0; i < totcurves; ++i) {
+ copy_v2_v2(scurve_uv->uv, uvs->getValue());
+
+ ++uvs;
+ ++scurve_uv;
+ }
+ }
+ }
+
+ if (sample_curve_vcols->size() > 0 && sample_curve_vcols->size() % totcurves == 0) {
+ int num_layers = sample_curve_vcols->size() / totcurves;
+
+ const C3f *vcols = sample_curve_vcols->get();
+
+ BKE_strands_children_add_vcols(m_strands, num_layers);
+
+ StrandsChildCurveVCol *scurve_vcol = m_strands->curve_vcols;
+ for (int j = 0; j < num_layers; ++j) {
+ for (int i = 0; i < totcurves; ++i) {
+ copy_v3_v3(scurve_vcol->vcol, vcols->getValue());
+
+ ++vcols;
+ ++scurve_vcol;
+ }
+ }
+ }
+
+ const V3f *co = sample_co->get();
+ const float32_t *curve_time = sample_time.getVals()->get();
+ for (int i = 0; i < sample_co->size(); ++i) {
+ StrandsChildVertex *svert = &m_strands->verts[i];
+ copy_v3_v3(svert->co, co->getValue());
+ copy_v3_v3(svert->base, svert->co);
+ svert->time = *curve_time;
+
+ ++co;
+ ++curve_time;
+ }
+
+ BKE_strands_children_ensure_normals(m_strands);
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+StrandsChildren *AbcStrandsChildrenReader::acquire_result()
+{
+ StrandsChildren *strands = m_strands;
+ m_strands = NULL;
+ return strands;
+}
+
+void AbcStrandsChildrenReader::discard_result()
+{
+ BKE_strands_children_free(m_strands);
+ m_strands = NULL;
+}
+
+
+AbcStrandsReader::AbcStrandsReader(Strands *strands, StrandsChildren *children, bool read_motion, bool read_children) :
+ m_read_motion(read_motion),
+ m_read_children(read_children),
+ m_strands(strands),
+ m_child_reader(children)
+{
+}
+
+AbcStrandsReader::~AbcStrandsReader()
+{
+ discard_result();
+}
+
+void AbcStrandsReader::init(ReaderArchive *archive)
+{
+ AbcReader::init(archive);
+ m_child_reader.init(archive);
+}
+
+void AbcStrandsReader::init_abc(IObject object)
+{
+ if (m_curves)
+ return;
+ m_curves = ICurves(object, kWrapExisting);
+
+ ICurvesSchema &schema = m_curves.getSchema();
+ ICompoundProperty geom_props = schema.getArbGeomParams();
+
+ m_param_root_rot = IQuatfGeomParam(geom_props, "root_rotations");
+ m_param_root_orig_verts = IUInt32GeomParam(geom_props, "root_orig_verts");
+ m_param_root_orig_weights = IFloatGeomParam(geom_props, "root_orig_weights");
+ m_param_root_orig_poly = IInt32GeomParam(geom_props, "root_orig_poly");
+ m_param_root_orig_loops = IUInt32GeomParam(geom_props, "root_orig_loops");
+
+ m_param_times = IFloatGeomParam(geom_props, "times");
+ m_param_weights = IFloatGeomParam(geom_props, "weights");
+
+ if (m_read_motion && geom_props.getPropertyHeader("motion_state")) {
+ m_param_motion_state = ICompoundProperty(geom_props, "motion_state");
+ m_param_motion_co = IP3fGeomParam(m_param_motion_state, "position");
+ m_param_motion_vel = IV3fGeomParam(m_param_motion_state, "velocity");
+ }
+
+ if (m_read_children && m_curves.getChildHeader("children")) {
+ IObject child = m_curves.getChild("children");
+ m_child_reader.init_abc(child);
+ }
+}
+
+PTCReadSampleResult AbcStrandsReader::read_sample_abc(chrono_t time)
+{
+ ISampleSelector ss = get_frame_sample_selector(time);
+
+ if (!m_curves.valid())
+ return PTC_READ_SAMPLE_INVALID;
+
+ ICurvesSchema &schema = m_curves.getSchema();
+ if (schema.getNumSamples() == 0)
+ return PTC_READ_SAMPLE_INVALID;
+
+ ICurvesSchema::Sample sample, sample_base;
+ schema.get(sample, ss);
+ schema.get(sample_base, ISampleSelector((index_t)0));
+
+ P3fArraySamplePtr sample_co = sample.getPositions();
+ P3fArraySamplePtr sample_co_base = sample_base.getPositions();
+ Int32ArraySamplePtr sample_numvert = sample.getCurvesNumVertices();
+ IQuatfGeomParam::Sample sample_root_rotations = m_param_root_rot.getExpandedValue(ss);
+ IUInt32GeomParam::Sample sample_root_orig_verts = m_param_root_orig_verts.getExpandedValue(ss);
+ IFloatGeomParam::Sample sample_root_orig_weights = m_param_root_orig_weights.getExpandedValue(ss);
+ IInt32GeomParam::Sample sample_root_orig_poly = m_param_root_orig_poly.getExpandedValue(ss);
+ IUInt32GeomParam::Sample sample_root_orig_loops = m_param_root_orig_loops.getExpandedValue(ss);
+ IQuatfGeomParam::Sample sample_root_rotations_base = m_param_root_rot.getExpandedValue(ISampleSelector((index_t)0));
+ IFloatGeomParam::Sample sample_time = m_param_times.getExpandedValue(ss);
+ IFloatGeomParam::Sample sample_weight = m_param_weights.getExpandedValue(ss);
+
+ if (!sample_co || !sample_numvert || !sample_co_base || sample_co_base->size() != sample_co->size())
+ return PTC_READ_SAMPLE_INVALID;
+
+ if (m_strands && (m_strands->totcurves != sample_numvert->size() || m_strands->totverts != sample_co->size()))
+ m_strands = NULL;
+ if (!m_strands)
+ m_strands = BKE_strands_new(sample_numvert->size(), sample_co->size());
+
+ const int32_t *numvert = sample_numvert->get();
+ const Quatf *root_rot = sample_root_rotations.getVals()->get();
+ const uint32_t *orig_verts = sample_root_orig_verts.getVals()->get();
+ const float32_t *orig_weights = sample_root_orig_weights.getVals()->get();
+ const int32_t *orig_poly = sample_root_orig_poly.getVals()->get();
+ const uint32_t *orig_loops = sample_root_orig_loops.getVals()->get();
+ for (int i = 0; i < sample_numvert->size(); ++i) {
+ StrandsCurve *scurve = &m_strands->curves[i];
+ scurve->numverts = *numvert;
+ float qt[4] = {root_rot->r, root_rot->v.x, root_rot->v.y, root_rot->v.z};
+ quat_to_mat3(scurve->root_matrix, qt);
+ scurve->msurf.orig_verts[0] = orig_verts[0];
+ scurve->msurf.orig_verts[1] = orig_verts[1];
+ scurve->msurf.orig_verts[2] = orig_verts[2];
+ scurve->msurf.orig_weights[0] = orig_weights[0];
+ scurve->msurf.orig_weights[1] = orig_weights[1];
+ scurve->msurf.orig_weights[2] = orig_weights[2];
+ scurve->msurf.orig_poly = *orig_poly;
+ scurve->msurf.orig_loops[0] = orig_loops[0];
+ scurve->msurf.orig_loops[1] = orig_loops[1];
+ scurve->msurf.orig_loops[2] = orig_loops[2];
+
+ ++numvert;
+ ++root_rot;
+ orig_verts += 3;
+ orig_weights += 3;
+ orig_poly += 1;
+ orig_loops += 3;
+ }
+
+ const V3f *co = sample_co->get();
+ const float32_t *curve_time = sample_time.getVals()->get();
+ const float32_t *weight = sample_weight.getVals()->get();
+ for (int i = 0; i < sample_co->size(); ++i) {
+ StrandsVertex *svert = &m_strands->verts[i];
+ copy_v3_v3(svert->co, co->getValue());
+ svert->time = *curve_time;
+ svert->weight = *weight;
+
+ ++co;
+ ++curve_time;
+ ++weight;
+ }
+
+ /* Correction for base coordinates: these are in object space of frame 1,
+ * but we want the relative shape. Offset them to the current root location.
+ */
+ const Quatf *root_rot_base = sample_root_rotations_base.getVals()->get();
+ const V3f *co_base = sample_co_base->get();
+ StrandIterator it_strand;
+ for (BKE_strand_iter_init(&it_strand, m_strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+ if (it_strand.curve->numverts <= 0)
+ continue;
+
+ float hairmat_base[4][4];
+ float qt[4] = {root_rot_base->r, root_rot_base->v.x, root_rot_base->v.y, root_rot_base->v.z};
+ quat_to_mat4(hairmat_base, qt);
+ copy_v3_v3(hairmat_base[3], co_base[0].getValue());
+
+ float hairmat[4][4];
+ copy_m4_m3(hairmat, it_strand.curve->root_matrix);
+ copy_v3_v3(hairmat[3], it_strand.verts[0].co);
+
+ float mat[4][4];
+ invert_m4_m4(mat, hairmat_base);
+ mul_m4_m4m4(mat, hairmat, mat);
+
+ StrandVertexIterator it_vert;
+ for (BKE_strand_vertex_iter_init(&it_vert, &it_strand); BKE_strand_vertex_iter_valid(&it_vert); BKE_strand_vertex_iter_next(&it_vert)) {
+// mul_v3_m4v3(it_vert.vertex->base, mat, co_base->getValue());
+ copy_v3_v3(it_vert.vertex->base, it_vert.vertex->co);
+
+ ++co_base;
+ }
+
+ ++root_rot_base;
+ }
+
+ if (m_read_motion &&
+ m_param_motion_co && m_param_motion_co.getNumSamples() > 0 &&
+ m_param_motion_vel && m_param_motion_vel.getNumSamples() > 0)
+ {
+ IP3fGeomParam::Sample sample_motion_co = m_param_motion_co.getExpandedValue(ss);
+ IV3fGeomParam::Sample sample_motion_vel = m_param_motion_vel.getExpandedValue(ss);
+
+ const V3f *co = sample_motion_co.getVals()->get();
+ const V3f *vel = sample_motion_vel.getVals()->get();
+ if (co && vel) {
+ BKE_strands_add_motion_state(m_strands);
+
+ for (int i = 0; i < m_strands->totverts; ++i) {
+ StrandsMotionState *ms = &m_strands->state[i];
+ copy_v3_v3(ms->co, co->getValue());
+ copy_v3_v3(ms->vel, vel->getValue());
+
+ ++co;
+ ++vel;
+ }
+ }
+ }
+
+ BKE_strands_ensure_normals(m_strands);
+
+ if (m_read_children) {
+ m_child_reader.read_sample_abc(time);
+ }
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+Strands *AbcStrandsReader::acquire_result()
+{
+ Strands *strands = m_strands;
+ m_strands = NULL;
+ return strands;
+}
+
+void AbcStrandsReader::discard_result()
+{
+ BKE_strands_free(m_strands);
+ m_strands = NULL;
+}
+
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/alembic/abc_particles.h b/source/blender/pointcache/alembic/abc_particles.h
new file mode 100644
index 00000000000..26d1bce78bd
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_particles.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_ABC_PARTICLES_H
+#define PTC_ABC_PARTICLES_H
+
+#include <Alembic/AbcGeom/IPoints.h>
+#include <Alembic/AbcGeom/OPoints.h>
+#include <Alembic/AbcGeom/ICurves.h>
+#include <Alembic/AbcGeom/OCurves.h>
+
+#include "ptc_types.h"
+
+#include "PTC_api.h"
+
+#include "abc_reader.h"
+#include "abc_schema.h"
+#include "abc_writer.h"
+#include "abc_cloth.h"
+
+struct ListBase;
+struct Object;
+struct ParticleSystem;
+struct ParticleCacheKey;
+struct Strands;
+struct StrandsChildren;
+
+namespace PTC {
+
+class AbcDerivedMeshWriter;
+class AbcDerivedMeshReader;
+
+
+class AbcHairChildrenWriter : public ParticlesWriter, public AbcWriter {
+public:
+ AbcHairChildrenWriter(const std::string &name, Object *ob, ParticleSystem *psys);
+ ~AbcHairChildrenWriter();
+
+ void init_abc(Abc::OObject parent);
+
+ void write_sample();
+
+private:
+ ParticleSystemModifierData *m_psmd;
+
+ AbcGeom::OCurves m_curves;
+ AbcGeom::OQuatfArrayProperty m_prop_root_rot;
+ AbcGeom::OV3fArrayProperty m_prop_root_positions;
+ AbcGeom::OFloatGeomParam m_param_cutoff;
+ AbcGeom::OFloatGeomParam m_param_times;
+ AbcGeom::OInt32ArrayProperty m_prop_parents;
+ AbcGeom::OFloatArrayProperty m_prop_parent_weights;
+ AbcGeom::OV2fArrayProperty m_prop_curve_uvs;
+ AbcGeom::OC3fArrayProperty m_prop_curve_vcols;
+};
+
+
+class AbcHairWriter : public ParticlesWriter, public AbcWriter {
+public:
+ AbcHairWriter(const std::string &name, Object *ob, ParticleSystem *psys);
+ ~AbcHairWriter();
+
+ void init(WriterArchive *archive);
+ void init_abc(Abc::OObject parent);
+
+ void write_sample();
+
+private:
+ ParticleSystemModifierData *m_psmd;
+
+ AbcGeom::OCurves m_curves;
+ AbcGeom::OQuatfGeomParam m_param_root_rot;
+ AbcGeom::OUInt32GeomParam m_param_root_orig_verts;
+ AbcGeom::OFloatGeomParam m_param_root_orig_weights;
+ AbcGeom::OInt32GeomParam m_param_root_orig_poly;
+ AbcGeom::OUInt32GeomParam m_param_root_orig_loops;
+ AbcGeom::OFloatGeomParam m_param_times;
+ AbcGeom::OFloatGeomParam m_param_weights;
+
+ AbcHairChildrenWriter m_child_writer;
+};
+
+
+class AbcStrandsChildrenWriter : public AbcWriter {
+public:
+ AbcStrandsChildrenWriter(const std::string &name, const std::string &abc_name, DupliObjectData *dobdata);
+
+ StrandsChildren *get_strands() const;
+
+ void init_abc(Abc::OObject parent);
+
+ void write_sample();
+
+private:
+ std::string m_name;
+ std::string m_abc_name;
+ DupliObjectData *m_dobdata;
+
+ AbcGeom::OCurves m_curves;
+ AbcGeom::OQuatfArrayProperty m_prop_root_rot;
+ AbcGeom::OV3fArrayProperty m_prop_root_positions;
+ AbcGeom::OFloatGeomParam m_param_cutoff;
+ AbcGeom::OFloatGeomParam m_param_times;
+ AbcGeom::OInt32ArrayProperty m_prop_parents;
+ AbcGeom::OFloatArrayProperty m_prop_parent_weights;
+ AbcGeom::OV2fArrayProperty m_prop_curve_uvs;
+ AbcGeom::OC3fArrayProperty m_prop_curve_vcols;
+};
+
+
+class AbcStrandsWriter : public AbcWriter {
+public:
+ AbcStrandsWriter(const std::string &name, DupliObjectData *dobdata);
+
+ Strands *get_strands() const;
+
+ void init(WriterArchive *archive);
+ void init_abc(Abc::OObject parent);
+
+ void write_sample();
+
+private:
+ std::string m_name;
+ DupliObjectData *m_dobdata;
+
+ AbcGeom::OCurves m_curves;
+ AbcGeom::OQuatfGeomParam m_param_root_rot;
+ AbcGeom::OUInt32GeomParam m_param_root_orig_verts;
+ AbcGeom::OFloatGeomParam m_param_root_orig_weights;
+ AbcGeom::OInt32GeomParam m_param_root_orig_poly;
+ AbcGeom::OUInt32GeomParam m_param_root_orig_loops;
+ AbcGeom::OFloatGeomParam m_param_times;
+ AbcGeom::OFloatGeomParam m_param_weights;
+ AbcGeom::OCompoundProperty m_param_motion_state;
+ AbcGeom::OP3fGeomParam m_param_motion_co;
+ AbcGeom::OV3fGeomParam m_param_motion_vel;
+
+ AbcStrandsChildrenWriter m_child_writer;
+};
+
+
+class AbcStrandsChildrenReader : public AbcReader {
+public:
+ AbcStrandsChildrenReader(StrandsChildren *strands);
+ ~AbcStrandsChildrenReader();
+
+ void init_abc(Abc::IObject object);
+
+ PTCReadSampleResult read_sample_abc(chrono_t time);
+
+ StrandsChildren *get_result() { return m_strands; }
+ StrandsChildren *acquire_result();
+ void discard_result();
+
+private:
+ StrandsChildren *m_strands;
+
+ AbcGeom::ICurves m_curves;
+ AbcGeom::IQuatfArrayProperty m_prop_root_rot;
+ AbcGeom::IV3fArrayProperty m_prop_root_positions;
+ AbcGeom::IFloatGeomParam m_param_cutoff;
+ AbcGeom::IFloatGeomParam m_param_times;
+ AbcGeom::IInt32ArrayProperty m_prop_parents;
+ AbcGeom::IFloatArrayProperty m_prop_parent_weights;
+ AbcGeom::IV2fArrayProperty m_prop_curve_uvs;
+ AbcGeom::IC3fArrayProperty m_prop_curve_vcols;
+};
+
+
+class AbcStrandsReader : public AbcReader {
+public:
+ AbcStrandsReader(Strands *strands, StrandsChildren *children, bool read_motion, bool read_children);
+ ~AbcStrandsReader();
+
+ void init(ReaderArchive *archive);
+ void init_abc(Abc::IObject object);
+
+ PTCReadSampleResult read_sample_abc(chrono_t time);
+
+ Strands *acquire_result();
+ void discard_result();
+
+ AbcStrandsChildrenReader &child_reader() { return m_child_reader; }
+
+private:
+ bool m_read_motion, m_read_children;
+ Strands *m_strands;
+
+ AbcGeom::ICurves m_curves;
+ AbcGeom::IQuatfGeomParam m_param_root_rot;
+ AbcGeom::IUInt32GeomParam m_param_root_orig_verts;
+ AbcGeom::IFloatGeomParam m_param_root_orig_weights;
+ AbcGeom::IInt32GeomParam m_param_root_orig_poly;
+ AbcGeom::IUInt32GeomParam m_param_root_orig_loops;
+ AbcGeom::IFloatGeomParam m_param_times;
+ AbcGeom::IFloatGeomParam m_param_weights;
+ AbcGeom::ICompoundProperty m_param_motion_state;
+ AbcGeom::IP3fGeomParam m_param_motion_co;
+ AbcGeom::IV3fGeomParam m_param_motion_vel;
+
+ AbcStrandsChildrenReader m_child_reader;
+};
+
+
+} /* namespace PTC */
+
+#endif /* PTC_PARTICLES_H */
diff --git a/source/blender/pointcache/alembic/abc_reader.cpp b/source/blender/pointcache/alembic/abc_reader.cpp
new file mode 100644
index 00000000000..17f574af7ac
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_reader.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+//#include <Alembic/AbcCoreHDF5/ReadWrite.h>
+#include <Alembic/AbcCoreOgawa/ReadWrite.h>
+#include <Alembic/Abc/ArchiveInfo.h>
+#include <Alembic/Abc/IArchive.h>
+#include <Alembic/Abc/IObject.h>
+
+#include "alembic.h"
+#include "abc_reader.h"
+
+#include "util_error_handler.h"
+
+extern "C" {
+#include "DNA_ID.h"
+}
+
+namespace PTC {
+
+using namespace Abc;
+
+AbcReaderArchive *AbcReaderArchive::open(double fps, float start_frame, const std::string &filename, ErrorHandler *error_handler)
+{
+ IArchive abc_archive;
+ PTC_SAFE_CALL_BEGIN
+// abc_archive = IArchive(AbcCoreHDF5::ReadArchive(), filename, Abc::ErrorHandler::kThrowPolicy);
+ abc_archive = IArchive(AbcCoreOgawa::ReadArchive(), filename, Abc::ErrorHandler::kThrowPolicy);
+ PTC_SAFE_CALL_END_HANDLER(error_handler)
+
+ if (abc_archive)
+ return new AbcReaderArchive(fps, start_frame, error_handler, abc_archive);
+ else
+ return NULL;
+}
+
+AbcReaderArchive::AbcReaderArchive(double fps, float start_frame, ErrorHandler *error_handler, IArchive abc_archive) :
+ FrameMapper(fps, start_frame),
+ m_error_handler(error_handler),
+ m_use_render(false),
+ m_abc_archive(abc_archive)
+{
+ if (m_abc_archive.getTop().getChildHeader("root"))
+ m_abc_root = IObject(m_abc_archive.getTop(), "root");
+ else
+ m_abc_root = IObject();
+
+ if (m_abc_archive.getTop().getChildHeader("root_render"))
+ m_abc_root_render = IObject(m_abc_archive.getTop(), "root_render");
+ else
+ m_abc_root_render = IObject();
+}
+
+AbcReaderArchive::~AbcReaderArchive()
+{
+}
+
+PTCArchiveResolution AbcReaderArchive::get_resolutions()
+{
+ int res = 0;
+ if (m_abc_root)
+ res |= PTC_RESOLUTION_PREVIEW;
+ if (m_abc_root_render)
+ res |= PTC_RESOLUTION_RENDER;
+ return (PTCArchiveResolution)res;
+}
+
+Abc::IObject AbcReaderArchive::root()
+{
+ if (m_use_render)
+ return m_abc_root_render ? m_abc_root_render : m_abc_root;
+ else
+ return m_abc_root ? m_abc_root : m_abc_root_render;
+}
+
+IObject AbcReaderArchive::get_id_object(ID *id)
+{
+ if (!m_abc_archive)
+ return IObject();
+
+ IObject root = this->root();
+ return root.getChild(id->name);
+}
+
+bool AbcReaderArchive::has_id_object(ID *id)
+{
+ if (!m_abc_archive)
+ return false;
+
+ IObject root = this->root();
+ return root.getChild(id->name).valid();
+}
+
+bool AbcReaderArchive::get_frame_range(int &start_frame, int &end_frame)
+{
+ if (m_abc_archive) {
+ double start_time, end_time;
+ GetArchiveStartAndEndTime(m_abc_archive, start_time, end_time);
+ start_frame = (int)time_to_frame(start_time);
+ end_frame = (int)time_to_frame(end_time);
+ return true;
+ }
+ else {
+ start_frame = end_frame = 1;
+ return false;
+ }
+}
+
+void AbcReaderArchive::get_info_stream(void (*stream)(void *, const char *), void *userdata)
+{
+ if (m_abc_archive)
+ abc_archive_info_stream(m_abc_archive, stream, userdata);
+}
+
+void AbcReaderArchive::get_info(CacheArchiveInfo *info, IDProperty *metadata)
+{
+ if (m_abc_archive)
+ abc_archive_info_nodes(m_abc_archive, info, metadata, false, false);
+}
+
+void AbcReaderArchive::get_info_nodes(CacheArchiveInfo *info, bool calc_bytes_size)
+{
+ if (m_abc_archive)
+ abc_archive_info_nodes(m_abc_archive, info, NULL, true, calc_bytes_size);
+}
+
+ISampleSelector AbcReaderArchive::get_frame_sample_selector(float frame)
+{
+ return ISampleSelector(frame_to_time(frame), ISampleSelector::kFloorIndex);
+}
+
+ISampleSelector AbcReaderArchive::get_frame_sample_selector(chrono_t time)
+{
+ return ISampleSelector(time, ISampleSelector::kFloorIndex);
+}
+
+
+bool AbcReader::get_frame_range(int &start_frame, int &end_frame)
+{
+ return m_abc_archive->get_frame_range(start_frame, end_frame);
+}
+
+PTCReadSampleResult AbcReader::test_sample(float frame)
+{
+ if (m_abc_archive) {
+ int start_frame, end_frame;
+ m_abc_archive->get_frame_range(start_frame, end_frame);
+
+ if (frame < start_frame)
+ return PTC_READ_SAMPLE_EARLY;
+ else if (frame > end_frame)
+ return PTC_READ_SAMPLE_LATE;
+ else {
+ /* TODO could also be EXACT, but INTERPOLATED is more general
+ * do we need to support this?
+ * checking individual time samplings is also possible, but more involved.
+ */
+ return PTC_READ_SAMPLE_INTERPOLATED;
+ }
+ }
+ else {
+ return PTC_READ_SAMPLE_INVALID;
+ }
+}
+
+PTCReadSampleResult AbcReader::read_sample(float frame)
+{
+
+ try {
+ return read_sample_abc(m_abc_archive->frame_to_time(frame));
+ }
+ catch (Alembic::Util::Exception e) {
+ handle_alembic_exception(ErrorHandler::get_default_handler(), PTC_ERROR_CRITICAL, e);
+ return PTC_READ_SAMPLE_INVALID;
+ }
+ return PTC_READ_SAMPLE_INVALID;
+}
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/alembic/abc_reader.h b/source/blender/pointcache/alembic/abc_reader.h
new file mode 100644
index 00000000000..86cfdd91d51
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_reader.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_ABC_READER_H
+#define PTC_ABC_READER_H
+
+#include <string>
+
+#include <Alembic/Abc/IArchive.h>
+#include <Alembic/Abc/IObject.h>
+#include <Alembic/Abc/ISampleSelector.h>
+
+#include "reader.h"
+
+#include "abc_frame_mapper.h"
+
+#include "util_error_handler.h"
+#include "util_types.h"
+
+namespace PTC {
+
+using namespace Alembic;
+
+using Abc::chrono_t;
+
+class AbcReaderArchive : public ReaderArchive, public FrameMapper {
+public:
+ virtual ~AbcReaderArchive();
+
+ static AbcReaderArchive *open(double fps, float start_frame, const std::string &filename, ErrorHandler *error_handler);
+
+ PTCArchiveResolution get_resolutions();
+ bool use_render() const { return m_use_render; }
+ void use_render(bool enable) { m_use_render = enable; }
+
+ Abc::IArchive abc_archive() const { return m_abc_archive; }
+ Abc::IObject root();
+
+ Abc::IObject get_id_object(ID *id);
+ bool has_id_object(ID *id);
+
+ bool get_frame_range(int &start_frame, int &end_frame);
+ Abc::ISampleSelector get_frame_sample_selector(float frame);
+ Abc::ISampleSelector get_frame_sample_selector(chrono_t time);
+
+ void get_info_stream(void (*stream)(void *, const char *), void *userdata);
+ void get_info(CacheArchiveInfo *info, IDProperty *metadata);
+ void get_info_nodes(CacheArchiveInfo *info, bool calc_bytes_size);
+
+protected:
+ AbcReaderArchive(double fps, float start_frame, ErrorHandler *error_handler, Abc::IArchive abc_archive);
+
+protected:
+ ErrorHandler *m_error_handler;
+ bool m_use_render;
+
+ Abc::IArchive m_abc_archive;
+ Abc::IObject m_abc_root;
+ Abc::IObject m_abc_root_render;
+};
+
+class AbcReader : public Reader {
+public:
+ AbcReader() :
+ m_abc_archive(0)
+ {}
+
+ void init(ReaderArchive *archive)
+ {
+ BLI_assert(dynamic_cast<AbcReaderArchive*>(archive));
+ m_abc_archive = static_cast<AbcReaderArchive*>(archive);
+ }
+
+ virtual void init_abc(Abc::IObject /*object*/) {}
+
+ AbcReaderArchive *abc_archive() const { return m_abc_archive; }
+
+ bool get_frame_range(int &start_frame, int &end_frame);
+
+ Abc::ISampleSelector get_frame_sample_selector(float frame) { return m_abc_archive->get_frame_sample_selector(frame); }
+ Abc::ISampleSelector get_frame_sample_selector(chrono_t time) { return m_abc_archive->get_frame_sample_selector(time); }
+
+ PTCReadSampleResult test_sample(float frame);
+ PTCReadSampleResult read_sample(float frame);
+ virtual PTCReadSampleResult read_sample_abc(chrono_t time) = 0;
+
+private:
+ AbcReaderArchive *m_abc_archive;
+};
+
+} /* namespace PTC */
+
+#endif /* PTC_READER_H */
diff --git a/source/blender/pointcache/alembic/abc_schema.h b/source/blender/pointcache/alembic/abc_schema.h
new file mode 100644
index 00000000000..d8d70ddac05
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_schema.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_ABC_SCHEMA_H
+#define PTC_ABC_SCHEMA_H
+
+#include <Alembic/AbcGeom/SchemaInfoDeclarations.h>
+#include <Alembic/AbcGeom/IGeomBase.h>
+#include <Alembic/AbcGeom/OGeomBase.h>
+
+namespace PTC {
+
+#if 0
+#define PTC_SCHEMA_INFO ALEMBIC_ABCGEOM_DECLARE_SCHEMA_INFO
+
+using namespace Alembic::AbcGeom;
+#endif
+
+
+#if 0
+/* XXX We define an extended schema class to implement the wrapper constructor.
+ * This was removed in Alembic 1.1 for some reason ...
+ */
+template <class SCHEMA>
+class OSchemaObject : public Abc::OSchemaObject<SCHEMA>
+{
+public:
+ //! The default constructor creates an empty OSchemaObject function set.
+ //! ...
+ OSchemaObject() : Abc::OSchemaObject<SCHEMA>() {}
+
+ //! The primary constructor creates an OSchemaObject as a child of the
+ //! first argument, which is any Abc or AbcCoreAbstract (or other)
+ //! object which can be intrusively cast to an ObjectWriterPtr.
+ template <class OBJECT_PTR>
+ OSchemaObject(OBJECT_PTR iParentObject,
+ const std::string &iName,
+
+ const Argument &iArg0 = Argument(),
+ const Argument &iArg1 = Argument(),
+ const Argument &iArg2 = Argument())
+ : Abc::OSchemaObject<SCHEMA>(iParentObject, iName, iArg0, iArg1, iArg2)
+ {}
+
+ //! Wrap an existing schema object.
+ //! ...
+ template <class OBJECT_PTR>
+ OSchemaObject(OBJECT_PTR iThisObject,
+ WrapExistingFlag iFlag,
+ const Argument &iArg0 = Argument(),
+ const Argument &iArg1 = Argument(),
+ const Argument &iArg2 = Argument() );
+};
+
+//-*****************************************************************************
+template<class SCHEMA>
+template<class OBJECT_PTR>
+inline OSchemaObject<SCHEMA>::OSchemaObject(
+ OBJECT_PTR iObject,
+ WrapExistingFlag iFlag,
+ const Argument &iArg0,
+ const Argument &iArg1,
+ const Argument &iArg2 )
+ : OObject(iObject,
+ iFlag,
+ GetErrorHandlerPolicy(iObject,
+ iArg0, iArg1, iArg2))
+{
+ ALEMBIC_ABC_SAFE_CALL_BEGIN("OSchemaObject::OSchemaObject( wrap )");
+
+ const AbcA::ObjectHeader &oheader = this->getHeader();
+
+ Abc::OSchemaObject<SCHEMA>::m_schema = SCHEMA(
+ this->getProperties().getProperty(SCHEMA::getDefaultSchemaName()).getPtr()->asCompoundPtr(),
+ iFlag,
+ this->getErrorHandlerPolicy(),
+ GetSchemaInterpMatching(iArg0, iArg1, iArg2));
+
+ /* XXX TODO gives compiler error atm */
+// ABCA_ASSERT(matches(oheader, GetSchemaInterpMatching(iArg0, iArg1, iArg2)),
+// "Incorrect match of schema: "
+// << oheader.getMetaData().get( "schemaObjTitle" )
+// << " to expected: "
+// << getSchemaObjTitle());
+
+ ALEMBIC_ABC_SAFE_CALL_END_RESET();
+}
+#endif
+
+} /* namespace PTC */
+
+#endif /* PTC_SCHEMA_H */
diff --git a/source/blender/pointcache/alembic/abc_simdebug.cpp b/source/blender/pointcache/alembic/abc_simdebug.cpp
new file mode 100644
index 00000000000..191b2856dc9
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_simdebug.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2014, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "abc_simdebug.h"
+
+extern "C" {
+#include "BLI_ghash.h"
+#include "BLI_math.h"
+}
+
+#include "PTC_api.h"
+
+namespace PTC {
+
+using namespace Abc;
+
+struct SimDebugSample {
+ std::vector<uint32_t> category_hash;
+ std::vector<uint32_t> hash;
+
+ std::vector<int32_t> type;
+ std::vector<C3f> color;
+ std::vector<V3f> v1;
+ std::vector<V3f> v2;
+};
+
+AbcSimDebugWriter::AbcSimDebugWriter(const std::string &name, SimDebugData *data) :
+ m_name(name),
+ m_data(data)
+{
+}
+
+AbcSimDebugWriter::~AbcSimDebugWriter()
+{
+}
+
+void AbcSimDebugWriter::init_abc(OObject parent)
+{
+ if (m_object)
+ return;
+
+ m_object = OObject(parent, m_name, abc_archive()->frame_sampling_index());
+ OCompoundProperty props = m_object.getProperties();
+
+ m_prop_category_hash = OUInt32ArrayProperty(props, "category_hash", abc_archive()->frame_sampling_index());
+ m_prop_hash = OUInt32ArrayProperty(props, "hash", abc_archive()->frame_sampling_index());
+ m_prop_type = OInt32ArrayProperty(props, "type", abc_archive()->frame_sampling_index());
+ m_prop_color = OC3fArrayProperty(props, "color", abc_archive()->frame_sampling_index());
+ m_prop_v1 = OV3fArrayProperty(props, "v1", abc_archive()->frame_sampling_index());
+ m_prop_v2 = OV3fArrayProperty(props, "v2", abc_archive()->frame_sampling_index());
+}
+
+static void create_sample(SimDebugData *data, SimDebugSample &sample)
+{
+ int numelem = BLI_ghash_size(data->gh);
+ GHashIterator iter;
+
+ sample.category_hash.reserve(numelem);
+ sample.hash.reserve(numelem);
+ sample.type.reserve(numelem);
+ sample.color.reserve(numelem);
+ sample.v1.reserve(numelem);
+ sample.v2.reserve(numelem);
+
+ for (BLI_ghashIterator_init(&iter, data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
+ SimDebugElement *elem = (SimDebugElement *)BLI_ghashIterator_getValue(&iter);
+
+ sample.category_hash.push_back(elem->category_hash);
+ sample.hash.push_back(elem->hash);
+ sample.type.push_back(elem->type);
+ sample.color.push_back(C3f(elem->color[0], elem->color[1], elem->color[2]));
+ sample.v1.push_back(V3f(elem->v1[0], elem->v1[1], elem->v1[2]));
+ sample.v2.push_back(V3f(elem->v2[0], elem->v2[1], elem->v2[2]));
+ }
+}
+
+void AbcSimDebugWriter::write_sample()
+{
+ if (!m_object)
+ return;
+
+ SimDebugSample sample;
+
+ create_sample(m_data, sample);
+
+ m_prop_category_hash.set(UInt32ArraySample(sample.category_hash));
+ m_prop_hash.set(UInt32ArraySample(sample.hash));
+ m_prop_type.set(Int32ArraySample(sample.type));
+ m_prop_color.set(C3fArraySample(sample.color));
+ m_prop_v1.set(V3fArraySample(sample.v1));
+ m_prop_v2.set(V3fArraySample(sample.v2));
+}
+
+/* ========================================================================= */
+
+AbcSimDebugReader::AbcSimDebugReader(SimDebugData *data) :
+ m_data(data)
+{
+}
+
+AbcSimDebugReader::~AbcSimDebugReader()
+{
+}
+
+void AbcSimDebugReader::init_abc(IObject object)
+{
+ if (m_object)
+ return;
+ m_object = IObject(object, kWrapExisting);
+ ICompoundProperty props = m_object.getProperties();
+
+ m_prop_category_hash = IUInt32ArrayProperty(props, "category_hash");
+ m_prop_hash = IUInt32ArrayProperty(props, "hash");
+ m_prop_type = IInt32ArrayProperty(props, "type");
+ m_prop_color = IC3fArrayProperty(props, "color");
+ m_prop_v1 = IV3fArrayProperty(props, "v1");
+ m_prop_v2 = IV3fArrayProperty(props, "v2");
+}
+
+static PTCReadSampleResult apply_sample(SimDebugData *data,
+ UInt32ArraySamplePtr sample_category_hash, UInt32ArraySamplePtr sample_hash,
+ Int32ArraySamplePtr sample_type, C3fArraySamplePtr sample_color,
+ V3fArraySamplePtr sample_v1, V3fArraySamplePtr sample_v2)
+{
+ int numelem = sample_hash->size();
+
+ if (sample_category_hash->size() != numelem ||
+ sample_type->size() != numelem ||
+ sample_color->size() != numelem ||
+ sample_v1->size() != numelem ||
+ sample_v2->size() != numelem)
+ {
+ return PTC_READ_SAMPLE_INVALID;
+ }
+
+ const uint32_t *data_category_hash = sample_category_hash->get();
+ const uint32_t *data_hash = sample_hash->get();
+ const int32_t *data_type = sample_type->get();
+ const C3f *data_color = sample_color->get();
+ const V3f *data_v1 = sample_v1->get();
+ const V3f *data_v2 = sample_v2->get();
+
+ for (int i = 0; i < numelem; ++i) {
+ BKE_sim_debug_data_add_element_ex(data, *data_type, data_v1->getValue(), data_v2->getValue(), data_color->x, data_color->y, data_color->z, *data_category_hash, *data_hash);
+
+ ++data_category_hash;
+ ++data_hash;
+ ++data_type;
+ ++data_color;
+ ++data_v1;
+ ++data_v2;
+ }
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+PTCReadSampleResult AbcSimDebugReader::read_sample_abc(chrono_t time)
+{
+ if (!m_object)
+ return PTC_READ_SAMPLE_INVALID;
+
+ ISampleSelector ss = get_frame_sample_selector(time);
+
+ apply_sample(m_data, m_prop_category_hash.getValue(ss), m_prop_hash.getValue(ss), m_prop_type.getValue(ss),
+ m_prop_color.getValue(ss), m_prop_v1.getValue(ss), m_prop_v2.getValue(ss));
+
+ return PTC_READ_SAMPLE_EXACT;
+}
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/alembic/abc_simdebug.h b/source/blender/pointcache/alembic/abc_simdebug.h
new file mode 100644
index 00000000000..b549a31cf34
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_simdebug.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2014, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_ABC_SIMDEBUG_H
+#define PTC_ABC_SIMDEBUG_H
+
+#include <Alembic/Abc/IObject.h>
+#include <Alembic/Abc/OObject.h>
+#include <Alembic/AbcGeom/Foundation.h>
+
+#include "ptc_types.h"
+
+#include "abc_reader.h"
+#include "abc_writer.h"
+
+extern "C" {
+#include "BKE_effect.h"
+}
+
+namespace PTC {
+
+class AbcSimDebugWriter : public AbcWriter {
+public:
+ AbcSimDebugWriter(const std::string &name, SimDebugData *data);
+ ~AbcSimDebugWriter();
+
+ void init_abc(Abc::OObject parent);
+
+ void write_sample();
+
+private:
+ std::string m_name;
+ SimDebugData *m_data;
+
+ Abc::OObject m_object;
+ AbcGeom::OUInt32ArrayProperty m_prop_category_hash;
+ AbcGeom::OUInt32ArrayProperty m_prop_hash;
+ AbcGeom::OInt32ArrayProperty m_prop_type;
+ AbcGeom::OC3fArrayProperty m_prop_color;
+ AbcGeom::OV3fArrayProperty m_prop_v1;
+ AbcGeom::OV3fArrayProperty m_prop_v2;
+};
+
+class AbcSimDebugReader : public AbcReader {
+public:
+ AbcSimDebugReader(SimDebugData *data);
+ ~AbcSimDebugReader();
+
+ void init_abc(Abc::IObject object);
+
+ PTCReadSampleResult read_sample_abc(chrono_t time);
+
+private:
+ SimDebugData *m_data;
+
+ Abc::IObject m_object;
+ AbcGeom::IUInt32ArrayProperty m_prop_category_hash;
+ AbcGeom::IUInt32ArrayProperty m_prop_hash;
+ AbcGeom::IInt32ArrayProperty m_prop_type;
+ AbcGeom::IC3fArrayProperty m_prop_color;
+ AbcGeom::IV3fArrayProperty m_prop_v1;
+ AbcGeom::IV3fArrayProperty m_prop_v2;
+};
+
+} /* namespace PTC */
+
+#endif /* PTC_SIMDEBUG_H */
diff --git a/source/blender/pointcache/alembic/abc_split.cpp b/source/blender/pointcache/alembic/abc_split.cpp
new file mode 100644
index 00000000000..bbca2862d30
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_split.cpp
@@ -0,0 +1,239 @@
+//-*****************************************************************************
+//
+// Copyright (c) 2009-2013,
+// Sony Pictures Imageworks, Inc. and
+// Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Sony Pictures Imageworks, nor
+// Industrial Light & Magic nor the names of their 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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//-*****************************************************************************
+
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <map>
+
+#include <Alembic/AbcGeom/All.h>
+#include <Alembic/AbcCoreAbstract/All.h>
+#include <Alembic/AbcCoreFactory/All.h>
+#include <Alembic/Util/All.h>
+#include <Alembic/Abc/TypedPropertyTraits.h>
+
+#include "alembic.h"
+
+extern "C" {
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_cache_library.h"
+}
+
+using namespace ::Alembic::AbcGeom;
+
+namespace PTC {
+
+static void slice_properties(ICompoundProperty iParent, OCompoundProperty out_parent, TimeSamplingPtr time_sampling, chrono_t start, chrono_t end);
+
+static void slice_array_property(IArrayProperty iProp, OCompoundProperty out_parent, TimeSamplingPtr time_sampling, chrono_t start, chrono_t end)
+{
+ OArrayProperty out(out_parent, iProp.getName(), iProp.getDataType(), iProp.getMetaData(), time_sampling);
+
+ ArrayPropertyReaderPtr reader = iProp.getPtr();
+ ArrayPropertyWriterPtr writer = out.getPtr();
+
+ size_t num_samples = iProp.getNumSamples();
+ if (num_samples == 0)
+ return;
+
+ index_t istart = reader->getFloorIndex(start).first;
+ index_t iend = reader->getFloorIndex(end).first;
+// index_t ostart = time_sampling->getFloorIndex(start).first;
+// index_t oend = time_sampling->getFloorIndex(end).first;
+
+ char *buf = NULL;
+
+#if 0
+ if (istart > ostart) {
+ /* fill the gap between start indices with the first sample,
+ * so that output sample times match input sample times as close as possible.
+ */
+ for (index_t index = istart)
+ }
+#endif
+
+ for (index_t index = istart; index <= iend; ++index) {
+
+ ArraySamplePtr sample_ptr;
+ reader->getSample(index, sample_ptr);
+
+ writer->setSample(*sample_ptr);
+ }
+
+ if (buf)
+ delete[] buf;
+}
+
+static void slice_scalar_property(IScalarProperty iProp, OCompoundProperty out_parent, TimeSamplingPtr time_sampling, chrono_t start, chrono_t end)
+{
+ OScalarProperty out(out_parent, iProp.getName(), iProp.getDataType(), iProp.getMetaData(), time_sampling);
+
+ ScalarPropertyReaderPtr reader = iProp.getPtr();
+ ScalarPropertyWriterPtr writer = out.getPtr();
+ size_t num_bytes = reader->getDataType().getNumBytes();
+
+ size_t num_samples = iProp.getNumSamples();
+ if (num_samples == 0)
+ return;
+
+ index_t istart = reader->getFloorIndex(start).first;
+ index_t iend = reader->getFloorIndex(end).first;
+// index_t ostart = time_sampling->getFloorIndex(start).first;
+// index_t oend = time_sampling->getFloorIndex(end).first;
+
+ char *buf = new char[num_bytes];
+
+#if 0
+ if (istart > ostart) {
+ /* fill the gap between start indices with the first sample,
+ * so that output sample times match input sample times as close as possible.
+ */
+ for (index_t index = istart)
+ }
+#endif
+
+ for (index_t index = istart; index <= iend; ++index) {
+
+ reader->getSample(index, (void*)buf);
+
+ writer->setSample((void*)buf);
+ }
+
+ delete[] buf;
+}
+
+static void slice_compound_property(ICompoundProperty iProp, OCompoundProperty out_parent, TimeSamplingPtr time_sampling, chrono_t start, chrono_t end)
+{
+ OCompoundProperty out(out_parent, iProp.getName(), iProp.getMetaData());
+
+ slice_properties(iProp, out, time_sampling, start, end);
+}
+
+static void slice_properties(ICompoundProperty iParent, OCompoundProperty out_parent, TimeSamplingPtr time_sampling, chrono_t start, chrono_t end)
+{
+ for (size_t i = 0 ; i < iParent.getNumProperties() ; i++) {
+ PropertyHeader header = iParent.getPropertyHeader(i);
+
+ if (header.isCompound()) {
+ slice_compound_property(ICompoundProperty(iParent, header.getName()), out_parent, time_sampling, start, end);
+ }
+ else if (header.isScalar()) {
+ slice_scalar_property(IScalarProperty(iParent, header.getName()), out_parent, time_sampling, start, end);
+ }
+ else {
+ BLI_assert(header.isArray());
+ slice_array_property(IArrayProperty(iParent, header.getName()), out_parent, time_sampling, start, end);
+ }
+ }
+}
+
+typedef std::map<ObjectReaderPtr, ObjectWriterPtr> ObjectMap;
+typedef std::pair<ObjectReaderPtr, ObjectWriterPtr> ObjectPair;
+
+static void slice_object(IObject iObj, OObject out, TimeSamplingPtr time_sampling, chrono_t start, chrono_t end, ObjectMap &object_map)
+{
+ // Get the properties.
+ slice_properties(iObj.getProperties(), out.getProperties(), time_sampling, start, end);
+
+ // now the child objects
+ for (size_t i = 0 ; i < iObj.getNumChildren() ; i++) {
+ const ObjectHeader &child_header = iObj.getChildHeader(i);
+ IObject child = IObject(iObj, child_header.getName());
+
+ /* Note: child instances are added later, once all actual objects have been copied */
+ if (!child.isInstanceRoot()) {
+ /* XXX reuse if the output object already exists.
+ * This should not happen, but currently some root objects are created
+ * in advance when opening writer archives. In the future these will not be needed
+ * and this check will become unnecessary.
+ */
+ OObject out_child = out.getChild(child_header.getName());
+ if (!out_child)
+ out_child = OObject(out, child_header.getName(), child_header.getMetaData());
+ object_map[child.getPtr()] = out_child.getPtr();
+
+ slice_object(child, out_child, time_sampling, start, end, object_map);
+ }
+ }
+}
+
+static void slice_object_instances(IObject iObj, OObject out, const ObjectMap &object_map)
+{
+ // now the child objects
+ for (size_t i = 0 ; i < iObj.getNumChildren() ; i++) {
+ const ObjectHeader &child_header = iObj.getChildHeader(i);
+ IObject child = IObject(iObj, child_header.getName());
+
+ if (child.isInstanceRoot()) {
+ ObjectMap::const_iterator it = object_map.find(child.getPtr());
+ BLI_assert(it != object_map.end());
+ OObject out_target(it->second, kWrapExisting);
+
+ out.addChildInstance(out_target, child_header.getName());
+ }
+ else {
+ OObject out_child(out.getChild(child_header.getName()).getPtr(), kWrapExisting);
+ slice_object_instances(child, out_child, object_map);
+ }
+ }
+}
+
+void abc_archive_slice(IArchive in, OArchive out, TimeSamplingPtr time_sampling, chrono_t start, chrono_t end)
+{
+ ObjectMap object_map;
+
+ slice_object(in.getTop(), out.getTop(), time_sampling, start, end, object_map);
+ slice_object_instances(in.getTop(), out.getTop(), object_map);
+}
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/alembic/abc_writer.cpp b/source/blender/pointcache/alembic/abc_writer.cpp
new file mode 100644
index 00000000000..a294858f2e5
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_writer.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+//#include <Alembic/AbcCoreHDF5/ReadWrite.h>
+#include <Alembic/AbcCoreOgawa/ReadWrite.h>
+#include <Alembic/Abc/OObject.h>
+#include <Alembic/Abc/ArchiveInfo.h>
+
+#include "alembic.h"
+#include "abc_writer.h"
+
+#include "util_error_handler.h"
+
+extern "C" {
+#include <ctime>
+
+#include "BLI_fileops.h"
+#include "BLI_path_util.h"
+}
+
+namespace PTC {
+
+using namespace Abc;
+
+/* make sure the file's directory exists */
+static void ensure_directory(const char *filename)
+{
+ char dir[FILE_MAXDIR];
+ BLI_split_dir_part(filename, dir, sizeof(dir));
+ BLI_dir_create_recursive(dir);
+}
+
+AbcWriterArchive *AbcWriterArchive::open(double fps, float start_frame, const std::string &filename, PTCArchiveResolution resolutions,
+ const char *app_name, const char *description, const struct tm *time, IDProperty *metadata, ErrorHandler *error_handler)
+{
+ ensure_directory(filename.c_str());
+
+ MetaData md = abc_create_archive_info(app_name, description, time, metadata);
+
+ OArchive abc_archive;
+ PTC_SAFE_CALL_BEGIN
+// abc_archive = OArchive(AbcCoreHDF5::WriteArchive(), filename, md, Abc::ErrorHandler::kThrowPolicy);
+ abc_archive = OArchive(AbcCoreOgawa::WriteArchive(), filename, md, Abc::ErrorHandler::kThrowPolicy);
+ PTC_SAFE_CALL_END_HANDLER(error_handler)
+
+ if (abc_archive)
+ return new AbcWriterArchive(fps, start_frame, resolutions, error_handler, abc_archive);
+ else
+ return NULL;
+}
+
+AbcWriterArchive::AbcWriterArchive(double fps, float start_frame, PTCArchiveResolution resolutions, ErrorHandler *error_handler, OArchive abc_archive) :
+ FrameMapper(fps, start_frame),
+ m_error_handler(error_handler),
+ m_use_render(false),
+ m_abc_archive(abc_archive)
+{
+ if (m_abc_archive) {
+ chrono_t cycle_time = this->seconds_per_frame();
+ chrono_t start_time = this->start_time();
+ m_frame_sampling = m_abc_archive.addTimeSampling(TimeSampling(cycle_time, start_time));
+
+ if (resolutions & PTC_RESOLUTION_PREVIEW)
+ m_abc_root = OObject(m_abc_archive.getTop(), "root");
+ if (resolutions & PTC_RESOLUTION_RENDER)
+ m_abc_root_render = OObject(m_abc_archive.getTop(), "root_render");
+ }
+}
+
+AbcWriterArchive::~AbcWriterArchive()
+{
+}
+
+OObject AbcWriterArchive::get_id_object(ID *id)
+{
+ if (!m_abc_archive)
+ return OObject();
+
+ ObjectWriterPtr root_ptr = root().getPtr();
+
+ ObjectWriterPtr child = root_ptr->getChild(id->name);
+ if (child)
+ return OObject(child, kWrapExisting);
+ else {
+ const ObjectHeader *child_header = root_ptr->getChildHeader(id->name);
+ if (child_header)
+ return OObject(root_ptr->createChild(*child_header), kWrapExisting);
+ else {
+ return OObject();
+ }
+ }
+}
+
+OObject AbcWriterArchive::root()
+{
+ if (m_use_render)
+ return m_abc_root_render ? m_abc_root_render : OObject();
+ else
+ return m_abc_root ? m_abc_root : OObject();
+}
+
+bool AbcWriterArchive::has_id_object(ID *id)
+{
+ if (!m_abc_archive)
+ return false;
+
+ ObjectWriterPtr root_ptr = root().getPtr();
+
+ return root_ptr->getChildHeader(id->name) != NULL;
+}
+
+TimeSamplingPtr AbcWriterArchive::frame_sampling()
+{
+ return m_abc_archive.getTimeSampling(m_frame_sampling);
+}
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/alembic/abc_writer.h b/source/blender/pointcache/alembic/abc_writer.h
new file mode 100644
index 00000000000..60a25ff1e0a
--- /dev/null
+++ b/source/blender/pointcache/alembic/abc_writer.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_ABC_WRITER_H
+#define PTC_ABC_WRITER_H
+
+#include <string>
+
+#include <Alembic/Abc/OArchive.h>
+#include <Alembic/Abc/OObject.h>
+
+#include "writer.h"
+
+#include "abc_frame_mapper.h"
+
+#include "util_error_handler.h"
+#include "util_types.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+
+#include "DNA_ID.h"
+}
+
+struct tm;
+
+namespace PTC {
+
+using namespace Alembic;
+
+class AbcWriterArchive : public WriterArchive, public FrameMapper {
+public:
+ virtual ~AbcWriterArchive();
+
+ static AbcWriterArchive *open(double fps, float start_frame, const std::string &filename, PTCArchiveResolution resolutions,
+ const char *app_name, const char *description, const struct tm *time, IDProperty *metadata, ErrorHandler *error_handler);
+
+ bool use_render() const { return m_use_render; }
+ void use_render(bool enable) { m_use_render = enable; }
+
+ Abc::OArchive abc_archive() const { return m_abc_archive; }
+ Abc::OObject root();
+
+ Abc::OObject get_id_object(ID *id);
+ bool has_id_object(ID *id);
+
+ template <class OObjectT>
+ OObjectT add_id_object(ID *id);
+
+ uint32_t frame_sampling_index() const { return m_frame_sampling; }
+ Abc::TimeSamplingPtr frame_sampling();
+
+protected:
+ AbcWriterArchive(double fps, float start_frame, PTCArchiveResolution resolutions, ErrorHandler *error_handler, Abc::OArchive abc_archive);
+
+protected:
+ ErrorHandler *m_error_handler;
+ uint32_t m_frame_sampling;
+ bool m_use_render;
+
+ Abc::OArchive m_abc_archive;
+ Abc::OObject m_abc_root;
+ Abc::OObject m_abc_root_render;
+};
+
+class AbcWriter : public Writer {
+public:
+ Abc::TimeSamplingPtr frame_sampling() { return m_abc_archive->frame_sampling(); }
+
+ void init(WriterArchive *archive)
+ {
+ BLI_assert(dynamic_cast<AbcWriterArchive*>(archive));
+ m_abc_archive = static_cast<AbcWriterArchive*>(archive);
+
+ init_abc();
+ }
+
+ /* one of these should be implemented by subclasses */
+ virtual void init_abc() {}
+ virtual void init_abc(Abc::OObject /*parent*/) {}
+
+ AbcWriterArchive *abc_archive() const { return m_abc_archive; }
+
+private:
+ AbcWriterArchive *m_abc_archive;
+};
+
+/* ------------------------------------------------------------------------- */
+
+template <class OObjectT>
+OObjectT AbcWriterArchive::add_id_object(ID *id)
+{
+ using namespace Abc;
+
+ if (!m_abc_archive)
+ return OObjectT();
+
+ ObjectWriterPtr root_ptr = this->root().getPtr();
+
+ ObjectWriterPtr child = root_ptr->getChild(id->name);
+ if (child)
+ return OObjectT(child, kWrapExisting);
+ else {
+ const ObjectHeader *child_header = root_ptr->getChildHeader(id->name);
+ if (child_header)
+ return OObjectT(root_ptr->createChild(*child_header), kWrapExisting);
+ else {
+ return OObjectT(root_ptr, id->name, frame_sampling_index());
+ }
+ }
+}
+
+} /* namespace PTC */
+
+#endif /* PTC_WRITER_H */
diff --git a/source/blender/pointcache/alembic/alembic.cpp b/source/blender/pointcache/alembic/alembic.cpp
new file mode 100644
index 00000000000..669b3a33662
--- /dev/null
+++ b/source/blender/pointcache/alembic/alembic.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "PTC_api.h"
+
+#include "ptc_types.h"
+
+#include "abc_reader.h"
+#include "abc_writer.h"
+#include "abc_cloth.h"
+#include "abc_group.h"
+#include "abc_mesh.h"
+#include "abc_object.h"
+#include "abc_particles.h"
+
+#include "alembic.h"
+
+namespace PTC {
+
+class AbcFactory : public Factory {
+ const std::string &get_default_extension()
+ {
+ static std::string ext = "abc";
+ return ext;
+ }
+
+ WriterArchive *open_writer_archive(double fps, float start_frame, const std::string &name, PTCArchiveResolution resolutions,
+ const char *app_name, const char *description, const struct tm *time, struct IDProperty *metadata, ErrorHandler *error_handler)
+ {
+ return AbcWriterArchive::open(fps, start_frame, name, resolutions, app_name, description, time, metadata, error_handler);
+ }
+
+ ReaderArchive *open_reader_archive(double fps, float start_frame, const std::string &name, ErrorHandler *error_handler)
+ {
+ return AbcReaderArchive::open(fps, start_frame, name, error_handler);
+ }
+
+ void slice(ReaderArchive *in, WriterArchive *out, float start_frame, float end_frame)
+ {
+ BLI_assert(dynamic_cast<AbcReaderArchive*>(in));
+ BLI_assert(dynamic_cast<AbcWriterArchive*>(out));
+ AbcReaderArchive *abc_in = static_cast<AbcReaderArchive*>(in);
+ AbcWriterArchive *abc_out = static_cast<AbcWriterArchive*>(out);
+
+ abc_archive_slice(abc_in->abc_archive(), abc_out->abc_archive(), abc_out->frame_sampling(), abc_in->frame_to_time(start_frame), abc_in->frame_to_time(end_frame));
+ }
+
+ Writer *create_writer_object(const std::string &name, Scene *scene, Object *ob)
+ {
+ return new AbcObjectWriter(name, scene, ob, true, true);
+ }
+
+ Reader *create_reader_object(const std::string &name, Object *ob)
+ {
+ return new AbcObjectReader(name, ob);
+ }
+
+ Writer *create_writer_group(const std::string &name, Group *group)
+ {
+ return new AbcGroupWriter(name, group);
+ }
+
+ Reader *create_reader_group(const std::string &name, Group *group)
+ {
+ return new AbcGroupReader(name, group);
+ }
+
+
+ /* Cloth */
+ Writer *create_writer_cloth(const std::string &name, Object *ob, ClothModifierData *clmd)
+ {
+ return new AbcClothWriter(name, ob, clmd);
+ }
+
+ Reader *create_reader_cloth(const std::string &name, Object *ob, ClothModifierData *clmd)
+ {
+ return new AbcClothReader(name, ob, clmd);
+ }
+
+ /* Modifier Stack */
+ Writer *create_writer_derived_mesh(const std::string &name, Object *ob, DerivedMesh **dm_ptr)
+ {
+ return new AbcDerivedMeshWriter(name, ob, dm_ptr);
+ }
+
+ Reader *create_reader_derived_mesh(const std::string &name, Object *ob)
+ {
+ return new AbcDerivedMeshReader(name, ob);
+ }
+
+ Writer *create_writer_derived_final_realtime(const std::string &name, Object *ob)
+ {
+ return new AbcDerivedFinalRealtimeWriter(name, ob);
+ }
+
+ Writer *create_writer_derived_final_render(const std::string &name, Scene *scene, Object *ob, DerivedMesh **render_dm_ptr)
+ {
+ return new AbcDerivedFinalRenderWriter(name, scene, ob, render_dm_ptr);
+ }
+
+
+ Writer *create_writer_dupligroup(const std::string &name, EvaluationContext *eval_ctx, Scene *scene, Group *group, CacheLibrary *cachelib)
+ {
+ return new AbcDupligroupWriter(name, eval_ctx, scene, group, cachelib);
+ }
+
+ Writer *create_writer_duplicache(const std::string &name, Group *group, DupliCache *dupcache, int datatypes, bool do_sim_debug)
+ {
+ return new AbcDupliCacheWriter(name, group, dupcache, datatypes, do_sim_debug);
+ }
+
+ Reader *create_reader_duplicache(const std::string &name, Group *group, DupliCache *dupcache,
+ bool read_strands_motion, bool read_strands_children, bool read_sim_debug)
+ {
+ return new AbcDupliCacheReader(name, group, dupcache, read_strands_motion, read_strands_children, read_sim_debug);
+ }
+
+ Reader *create_reader_duplicache_object(const std::string &name, Object *ob, DupliObjectData *data,
+ bool read_strands_motion, bool read_strands_children)
+ {
+ return new AbcDupliObjectReader(name, ob, data, read_strands_motion, read_strands_children);
+ }
+};
+
+}
+
+void PTC_alembic_init()
+{
+ static PTC::AbcFactory abc_factory;
+
+ PTC::Factory::alembic = &abc_factory;
+}
diff --git a/source/blender/pointcache/alembic/alembic.h b/source/blender/pointcache/alembic/alembic.h
new file mode 100644
index 00000000000..c73b095933f
--- /dev/null
+++ b/source/blender/pointcache/alembic/alembic.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_ALEMBIC_H
+#define PTC_ALEMBIC_H
+
+#include <string>
+
+#include <Alembic/Abc/IArchive.h>
+
+struct CacheArchiveInfo;
+struct IDProperty;
+
+namespace PTC {
+
+using namespace Alembic;
+
+void abc_metadata_from_idprops_group(Abc::MetaData &md, IDProperty *prop);
+void abc_metadata_to_idprops_group(const Abc::MetaData &md, IDProperty *prop);
+Abc::MetaData abc_create_archive_info(const char *app_name, const char *description, const struct tm *t, struct IDProperty *props);
+
+void abc_archive_info_stream(Alembic::Abc::IArchive &archive, void (*stream)(void *, const char *), void *userdata);
+void abc_archive_info_nodes(Alembic::Abc::IArchive &archive, CacheArchiveInfo *info, IDProperty *metadata, bool calc_nodes, bool calc_bytes_size);
+
+void abc_archive_slice(Alembic::Abc::IArchive in, Alembic::Abc::OArchive out, Alembic::Abc::TimeSamplingPtr time_sampling, Alembic::Abc::chrono_t start, Alembic::Abc::chrono_t end);
+
+} /* namespace PTC */
+
+#endif /* PTC_CLOTH_H */
diff --git a/source/blender/pointcache/intern/ptc_types.cpp b/source/blender/pointcache/intern/ptc_types.cpp
new file mode 100644
index 00000000000..f2df356ca5b
--- /dev/null
+++ b/source/blender/pointcache/intern/ptc_types.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "ptc_types.h"
+
+extern "C" {
+#include "BKE_DerivedMesh.h"
+}
+
+namespace PTC {
+
+Factory *Factory::alembic = NULL;
+
+DerivedMesh *DerivedMeshReader::acquire_result()
+{
+ DerivedMesh *dm = m_result;
+ m_result = NULL;
+ return dm;
+}
+
+void DerivedMeshReader::discard_result()
+{
+ if (m_result) {
+ m_result->release(m_result);
+ m_result = NULL;
+ }
+}
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/intern/ptc_types.h b/source/blender/pointcache/intern/ptc_types.h
new file mode 100644
index 00000000000..c9e63d7abb6
--- /dev/null
+++ b/source/blender/pointcache/intern/ptc_types.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_TYPES_H
+#define PTC_TYPES_H
+
+#include "reader.h"
+#include "writer.h"
+
+extern "C" {
+#include "DNA_group_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_particle_types.h"
+}
+
+struct CacheLibrary;
+struct IDProperty;
+
+namespace PTC {
+
+class ClothWriter {
+public:
+ ClothWriter(Object *ob, ClothModifierData *clmd, const std::string &name) :
+ m_ob(ob),
+ m_clmd(clmd),
+ m_name(name)
+ {}
+
+ ~ClothWriter()
+ {}
+
+protected:
+ Object *m_ob;
+ ClothModifierData *m_clmd;
+ std::string m_name;
+};
+
+class ClothReader {
+public:
+ ClothReader(Object *ob, ClothModifierData *clmd, const std::string &name) :
+ m_ob(ob),
+ m_clmd(clmd),
+ m_name(name)
+ {}
+
+ ~ClothReader()
+ {}
+
+protected:
+ Object *m_ob;
+ ClothModifierData *m_clmd;
+ std::string m_name;
+};
+
+
+class DerivedMeshWriter {
+public:
+ /** \note Targeted DerivedMesh at \a dm_ptr must be available only on \fn write_sample calls */
+ DerivedMeshWriter(Object *ob, DerivedMesh **dm_ptr, const std::string &name) :
+ m_ob(ob),
+ m_dm_ptr(dm_ptr),
+ m_name(name)
+ {}
+
+ ~DerivedMeshWriter()
+ {}
+
+protected:
+ Object *m_ob;
+ DerivedMesh **m_dm_ptr;
+ std::string m_name;
+};
+
+class DerivedMeshReader {
+public:
+ DerivedMeshReader(Object *ob, const std::string &name) :
+ m_ob(ob),
+ m_result(0),
+ m_name(name)
+ {}
+
+ ~DerivedMeshReader()
+ {
+ discard_result();
+ }
+
+ DerivedMesh *acquire_result();
+ void discard_result();
+
+protected:
+ Object *m_ob;
+ DerivedMesh *m_result;
+ std::string m_name;
+};
+
+class GroupWriter {
+public:
+ GroupWriter(Group *group, const std::string &name) :
+ m_group(group),
+ m_name(name)
+ {}
+
+protected:
+ Group *m_group;
+ std::string m_name;
+};
+
+class GroupReader {
+public:
+ GroupReader(Group *group, const std::string &name) :
+ m_group(group),
+ m_name(name)
+ {}
+
+protected:
+ Group *m_group;
+ std::string m_name;
+};
+
+class ObjectWriter {
+public:
+ ObjectWriter(Object *ob, const std::string &name) :
+ m_ob(ob),
+ m_name(name)
+ {}
+
+protected:
+ Object *m_ob;
+ std::string m_name;
+};
+
+class ObjectReader {
+public:
+ ObjectReader(Object *ob, const std::string &name) :
+ m_ob(ob),
+ m_name(name)
+ {}
+
+protected:
+ Object *m_ob;
+ std::string m_name;
+};
+
+class ParticlesWriter {
+public:
+ ParticlesWriter(Object *ob, ParticleSystem *psys, const std::string &name) :
+ m_ob(ob),
+ m_psys(psys),
+ m_name(name)
+ {}
+
+ ~ParticlesWriter()
+ {}
+
+protected:
+ Object *m_ob;
+ ParticleSystem *m_psys;
+ std::string m_name;
+};
+
+class ParticlesReader {
+public:
+ ParticlesReader(Object *ob, ParticleSystem *psys, const std::string &name) :
+ m_ob(ob),
+ m_psys(psys),
+ m_name(name),
+ m_totpoint(0)
+ {}
+
+ ~ParticlesReader()
+ {}
+
+ int totpoint() const { return m_totpoint; }
+
+protected:
+ Object *m_ob;
+ ParticleSystem *m_psys;
+ std::string m_name;
+
+ int m_totpoint;
+};
+
+struct Factory {
+ virtual const std::string &get_default_extension() = 0;
+ virtual WriterArchive *open_writer_archive(double fps, float start_frame, const std::string &name, PTCArchiveResolution resolutions,
+ const char *app_name, const char *description, const struct tm *time, struct IDProperty *metadata, ErrorHandler *error_handler) = 0;
+ virtual ReaderArchive *open_reader_archive(double fps, float start_frame, const std::string &name, ErrorHandler *error_handler) = 0;
+
+ virtual void slice(ReaderArchive *in, WriterArchive *out, float start_frame, float end_frame) = 0;
+
+ virtual Writer *create_writer_object(const std::string &name, Scene *scene, Object *ob) = 0;
+ virtual Reader *create_reader_object(const std::string &name, Object *ob) = 0;
+
+ virtual Writer *create_writer_group(const std::string &name, Group *group) = 0;
+ virtual Reader *create_reader_group(const std::string &name, Group *group) = 0;
+
+ /* Cloth */
+ virtual Writer *create_writer_cloth(const std::string &name, Object *ob, ClothModifierData *clmd) = 0;
+ virtual Reader *create_reader_cloth(const std::string &name, Object *ob, ClothModifierData *clmd) = 0;
+
+ /* Modifier Stack */
+ virtual Writer *create_writer_derived_mesh(const std::string &name, Object *ob, DerivedMesh **dm_ptr) = 0;
+ virtual Reader *create_reader_derived_mesh(const std::string &name, Object *ob) = 0;
+
+ virtual Writer *create_writer_derived_final_realtime(const std::string &name, Object *ob) = 0;
+ virtual Writer *create_writer_derived_final_render(const std::string &name, Scene *scene, Object *ob, DerivedMesh **render_dm_ptr) = 0;
+
+ virtual Writer *create_writer_dupligroup(const std::string &name, EvaluationContext *eval_ctx, Scene *scene, Group *group, CacheLibrary *cachelib) = 0;
+ virtual Writer *create_writer_duplicache(const std::string &name, Group *group, DupliCache *dupcache, int datatypes, bool do_sim_debug) = 0;
+ virtual Reader *create_reader_duplicache(const std::string &name, Group *group, DupliCache *dupcache,
+ bool read_strands_motion, bool read_strands_children, bool read_sim_debug) = 0;
+ virtual Reader *create_reader_duplicache_object(const std::string &name, Object *ob, DupliObjectData *data,
+ bool read_strands_motion, bool read_strands_children) = 0;
+
+ static Factory *alembic;
+};
+
+} /* namespace PTC */
+
+#endif /* PTC_EXPORT_H */
diff --git a/source/blender/pointcache/intern/reader.cpp b/source/blender/pointcache/intern/reader.cpp
new file mode 100644
index 00000000000..56b0f54e982
--- /dev/null
+++ b/source/blender/pointcache/intern/reader.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "reader.h"
+#include "util_error_handler.h"
+
+extern "C" {
+#include "DNA_scene_types.h"
+}
+
+namespace PTC {
+
+Reader::Reader() :
+ m_error_handler(0)
+{
+}
+
+Reader::Reader(ErrorHandler *error_handler) :
+ m_error_handler(error_handler)
+{
+}
+
+Reader::~Reader()
+{
+ if (m_error_handler)
+ delete m_error_handler;
+}
+
+void Reader::set_error_handler(ErrorHandler *handler)
+{
+ if (m_error_handler)
+ delete m_error_handler;
+
+ m_error_handler = handler;
+}
+
+bool Reader::valid() const
+{
+ return m_error_handler ? m_error_handler->max_error_level() >= PTC_ERROR_CRITICAL : true;
+}
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/intern/reader.h b/source/blender/pointcache/intern/reader.h
new file mode 100644
index 00000000000..39d0ab20197
--- /dev/null
+++ b/source/blender/pointcache/intern/reader.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_READER_H
+#define PTC_READER_H
+
+#include <string>
+
+#include "util_error_handler.h"
+#include "util_types.h"
+#include "PTC_api.h"
+
+struct ID;
+struct IDProperty;
+struct CacheArchiveInfo;
+
+namespace PTC {
+
+class ReaderArchive {
+public:
+ virtual ~ReaderArchive() {}
+
+ virtual PTCArchiveResolution get_resolutions() = 0;
+ virtual void use_render(bool enable) = 0;
+
+ virtual bool get_frame_range(int &start_frame, int &end_frame) = 0;
+ virtual void get_info_stream(void (*stream)(void *, const char *), void *userdata) = 0;
+ virtual void get_info(CacheArchiveInfo *info, IDProperty *metadata) = 0;
+ virtual void get_info_nodes(CacheArchiveInfo *info, bool calc_bytes_size) = 0;
+};
+
+class Reader {
+public:
+ Reader();
+ Reader(ErrorHandler *error_handler);
+ virtual ~Reader();
+
+ virtual void init(ReaderArchive *archive) = 0;
+
+ void set_error_handler(ErrorHandler *handler);
+ ErrorHandler *get_error_handler() const { return m_error_handler; }
+ bool valid() const;
+
+ virtual bool get_frame_range(int &start_frame, int &end_frame) = 0;
+ virtual PTCReadSampleResult test_sample(float frame) = 0;
+ virtual PTCReadSampleResult read_sample(float frame) = 0;
+
+protected:
+ ErrorHandler *m_error_handler;
+};
+
+} /* namespace PTC */
+
+#endif /* PTC_READER_H */
diff --git a/source/blender/pointcache/intern/writer.cpp b/source/blender/pointcache/intern/writer.cpp
new file mode 100644
index 00000000000..97a6b9ad405
--- /dev/null
+++ b/source/blender/pointcache/intern/writer.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "writer.h"
+
+extern "C" {
+#include "DNA_scene_types.h"
+}
+
+namespace PTC {
+
+Writer::Writer() :
+ m_error_handler(0)
+{
+}
+
+Writer::Writer(ErrorHandler *handler) :
+ m_error_handler(handler)
+{
+}
+
+Writer::~Writer()
+{
+ if (m_error_handler)
+ delete m_error_handler;
+}
+
+void Writer::set_error_handler(ErrorHandler *handler)
+{
+ if (m_error_handler)
+ delete m_error_handler;
+
+ m_error_handler = handler;
+}
+
+bool Writer::valid() const
+{
+ return m_error_handler ? m_error_handler->max_error_level() >= PTC_ERROR_CRITICAL : true;
+}
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/intern/writer.h b/source/blender/pointcache/intern/writer.h
new file mode 100644
index 00000000000..008c391bffc
--- /dev/null
+++ b/source/blender/pointcache/intern/writer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_WRITER_H
+#define PTC_WRITER_H
+
+#include <string>
+
+#include "util_error_handler.h"
+
+struct ID;
+
+namespace PTC {
+
+class WriterArchive {
+public:
+ virtual ~WriterArchive() {}
+
+ virtual void use_render(bool enable) = 0;
+};
+
+class Writer {
+public:
+ Writer();
+ Writer(ErrorHandler *handler);
+ virtual ~Writer();
+
+ void set_error_handler(ErrorHandler *handler);
+ bool valid() const;
+
+ virtual void init(WriterArchive *archive) = 0;
+
+ /* create references to other objects */
+ virtual void create_refs() {}
+
+ virtual void write_sample() = 0;
+
+protected:
+ ErrorHandler *m_error_handler;
+};
+
+} /* namespace PTC */
+
+#endif /* PTC_WRITER_H */
diff --git a/source/blender/pointcache/util/util_error_handler.cpp b/source/blender/pointcache/util/util_error_handler.cpp
new file mode 100644
index 00000000000..e1a326e1713
--- /dev/null
+++ b/source/blender/pointcache/util/util_error_handler.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <iostream>
+
+#include "util_error_handler.h"
+
+extern "C" {
+#include "BKE_modifier.h"
+}
+
+namespace PTC {
+
+ErrorHandler *ErrorHandler::m_default_handler = new StdErrorHandler(PTC_ERROR_INFO);
+
+ErrorHandler::ErrorHandler() :
+ m_max_level(PTC_ERROR_NONE)
+{
+}
+
+ErrorHandler::~ErrorHandler()
+{
+}
+
+void ErrorHandler::set_error_level(PTCErrorLevel level)
+{
+ if (level > m_max_level)
+ m_max_level = level;
+}
+
+void ErrorHandler::set_default_handler(ErrorHandler *handler)
+{
+ if (m_default_handler)
+ delete m_default_handler;
+
+ if (handler)
+ m_default_handler = handler;
+ else
+ m_default_handler = new StdErrorHandler(PTC_ERROR_INFO);
+}
+
+void ErrorHandler::clear_default_handler()
+{
+ if (m_default_handler)
+ delete m_default_handler;
+
+ m_default_handler = new StdErrorHandler(PTC_ERROR_INFO);
+}
+
+
+StdErrorHandler::StdErrorHandler(PTCErrorLevel level) :
+ m_verbosity(level)
+{
+}
+
+void StdErrorHandler::handle(PTCErrorLevel level, const char *message)
+{
+ /* ignore levels below the verbosity setting */
+ if (level >= m_verbosity) {
+ std::cerr << message << std::endl;
+ }
+}
+
+
+CallbackErrorHandler::CallbackErrorHandler(PTCErrorCallback cb, void *userdata) :
+ m_callback(cb),
+ m_userdata(userdata)
+{
+}
+
+void CallbackErrorHandler::handle(PTCErrorLevel level, const char *message)
+{
+ m_callback(m_userdata, level, message);
+}
+
+
+ModifierErrorHandler::ModifierErrorHandler(ModifierData *md) :
+ m_modifier(md)
+{
+}
+
+void ModifierErrorHandler::handle(PTCErrorLevel UNUSED(level), const char *message)
+{
+ modifier_setError(m_modifier, "%s", message);
+}
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/util/util_error_handler.h b/source/blender/pointcache/util/util_error_handler.h
new file mode 100644
index 00000000000..61baa03a357
--- /dev/null
+++ b/source/blender/pointcache/util/util_error_handler.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_UTIL_ERROR_HANDLER_H
+#define PTC_UTIL_ERROR_HANDLER_H
+
+#include <stdio.h>
+
+#ifdef WITH_ALEMBIC
+#include <Alembic/Abc/ErrorHandler.h>
+#endif
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+}
+
+#include "util_types.h"
+
+struct ModifierData;
+struct ReportList;
+
+namespace PTC {
+
+class ErrorHandler
+{
+public:
+ ErrorHandler();
+ virtual ~ErrorHandler();
+
+ virtual void handle(PTCErrorLevel level, const char *message) = 0;
+ void set_error_level(PTCErrorLevel level);
+ PTCErrorLevel max_error_level() const { return m_max_level; }
+
+ static ErrorHandler *get_default_handler() { return m_default_handler; }
+ static void set_default_handler(ErrorHandler *handler);
+ static void clear_default_handler();
+
+private:
+ PTCErrorLevel m_max_level;
+
+ static ErrorHandler *m_default_handler;
+};
+
+
+class StdErrorHandler : public ErrorHandler
+{
+public:
+ StdErrorHandler(PTCErrorLevel level);
+
+ void handle(PTCErrorLevel level, const char *message);
+
+ PTCErrorLevel get_verbosity() const { return m_verbosity; }
+ void set_verbosity(PTCErrorLevel level) { m_verbosity = level; }
+
+private:
+ PTCErrorLevel m_verbosity;
+};
+
+
+/* Use Blender reports system to log Alembic errors */
+class CallbackErrorHandler : public ErrorHandler
+{
+public:
+ CallbackErrorHandler(PTCErrorCallback cb, void *userdata);
+
+ void handle(PTCErrorLevel level, const char *message);
+
+private:
+ PTCErrorCallback m_callback;
+ void *m_userdata;
+};
+
+
+class ModifierErrorHandler : public ErrorHandler
+{
+public:
+ ModifierErrorHandler(ModifierData *md);
+
+ void handle(PTCErrorLevel level, const char *message);
+
+private:
+ ModifierData *m_modifier;
+};
+
+/* -------------------------------- */
+
+#ifdef WITH_ALEMBIC
+
+/* XXX With current Alembic version 1.5 we only get a combined error message.
+ * This function try to extract some more information and return a nicer message format.
+ */
+BLI_INLINE void split_alembic_error_message(const char *msg, const char **origin, const char **base_msg)
+{
+ const char delim[] = {'\n', '\0'};
+ char *sep, *suffix;
+
+ BLI_str_partition(msg, delim, &sep, &suffix);
+ if (suffix) {
+ *origin = msg;
+ BLI_str_partition(suffix, delim, &sep, &suffix);
+ if (suffix) {
+ *base_msg = suffix;
+ }
+ else {
+ *base_msg = msg;
+ }
+ }
+ else {
+ *origin = *base_msg = msg;
+ }
+}
+
+/* wrapper templates so the exception macro can be used with references as well as pointers */
+
+template <typename T>
+void handle_alembic_exception(T &handler, PTCErrorLevel level, const Alembic::Util::Exception &e)
+{
+ const char *origin, *msg;
+ split_alembic_error_message(e.what(), &origin, &msg);
+
+ handler.set_error_level(level);
+ handler.handle(level, msg);
+}
+
+template <typename T>
+void handle_alembic_exception(T *handler, PTCErrorLevel level, const Alembic::Util::Exception &e)
+{
+ static StdErrorHandler default_handler(PTC_ERROR_WARNING);
+ if (!handler)
+ handler = &default_handler;
+
+ const char *origin, *msg;
+ split_alembic_error_message(e.what(), &origin, &msg);
+
+ handler->set_error_level(level);
+ handler->handle(level, msg);
+}
+
+#endif
+
+/* -------------------------------- */
+
+/* macros for convenient exception handling */
+
+#define PTC_SAFE_CALL_BEGIN \
+ try {
+
+#ifdef WITH_ALEMBIC
+#define PTC_SAFE_CALL_END_HANDLER(handler) \
+ } \
+ catch (Alembic::Util::Exception e) { \
+ handle_alembic_exception((handler), PTC_ERROR_CRITICAL, e); \
+ }
+#else
+#define PTC_SAFE_CALL_END_HANDLER(handler) \
+ }
+#endif
+
+#ifdef WITH_ALEMBIC
+#define PTC_SAFE_CALL_END_HANDLER_LEVEL(handler, level) \
+ } \
+ catch (Alembic::Util::Exception e) { \
+ handle_alembic_exception((handler), (level), e); \
+ }
+#else
+#define PTC_SAFE_CALL_END_HANDLER_LEVEL(handler, level) \
+ }
+#endif
+
+#ifdef WITH_ALEMBIC
+#define PTC_SAFE_CALL_END \
+ } \
+ catch (Alembic::Util::Exception e) { \
+ handle_alembic_exception(ErrorHandler::get_default_handler(), PTC_ERROR_CRITICAL, e); \
+ }
+#else
+#define PTC_SAFE_CALL_END \
+ }
+#endif
+
+/* -------------------------------- */
+
+} /* namespace PTC */
+
+#endif /* PTC_UTIL_ERROR_HANDLER_H */
diff --git a/source/blender/pointcache/util/util_function.h b/source/blender/pointcache/util/util_function.h
new file mode 100644
index 00000000000..97f0278237d
--- /dev/null
+++ b/source/blender/pointcache/util/util_function.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_UTIL_FUNCTION
+#define PTC_UTIL_FUNCTION
+
+#if __cplusplus > 199711L
+
+#include <functional>
+
+namespace PTC {
+
+using std::function;
+using namespace std::placeholders;
+#define function_bind std::bind
+
+} /* namespace PTC */
+
+#else
+
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+
+namespace PTC {
+
+using boost::function;
+#define function_bind boost::bind
+
+} /* namespace PTC */
+
+#endif
+
+#endif /* PTC_UTIL_FUNCTION */
diff --git a/source/blender/pointcache/util/util_task.cpp b/source/blender/pointcache/util/util_task.cpp
new file mode 100644
index 00000000000..feecdd54b97
--- /dev/null
+++ b/source/blender/pointcache/util/util_task.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "util_task.h"
+
+#include "BLI_task.h"
+#include "BLI_threads.h"
+
+namespace PTC {
+
+class UtilTask {
+public:
+ explicit UtilTask(const UtilTaskFunction& run) : run_(run) {}
+ void run()
+ {
+ run_();
+ }
+protected:
+ UtilTaskFunction run_;
+};
+
+static void task_function(TaskPool * /*pool*/,
+ void *taskdata,
+ int /*threadid*/)
+{
+ UtilTask *task = reinterpret_cast<UtilTask*>(taskdata);
+ task->run();
+ delete task;
+}
+
+UtilTaskPool::UtilTaskPool()
+{
+ scheduler_ = BLI_task_scheduler_get();
+ pool_ = BLI_task_pool_create(scheduler_, NULL);
+}
+
+UtilTaskPool::~UtilTaskPool()
+{
+ BLI_task_pool_free(pool_);
+}
+
+void UtilTaskPool::push(const UtilTaskFunction& run, bool front)
+{
+ UtilTask *task = new UtilTask(run);
+ BLI_task_pool_push(pool_,
+ task_function,
+ task,
+ false,
+ front? TASK_PRIORITY_HIGH: TASK_PRIORITY_LOW);
+}
+
+void UtilTaskPool::wait_work()
+{
+ BLI_task_pool_work_and_wait(pool_);
+}
+
+void UtilTaskPool::cancel()
+{
+ BLI_task_pool_cancel(pool_);
+}
+
+void UtilTaskPool::stop()
+{
+ BLI_task_pool_stop(pool_);
+}
+
+bool UtilTaskPool::cancelled()
+{
+ return BLI_task_pool_canceled(pool_);
+}
+
+} /* namespace PTC */
diff --git a/source/blender/pointcache/util/util_task.h b/source/blender/pointcache/util/util_task.h
new file mode 100644
index 00000000000..be2f1cca84f
--- /dev/null
+++ b/source/blender/pointcache/util/util_task.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_UTIL_TASK_H
+#define PTC_UTIL_TASK_H
+
+#include "util_function.h"
+
+struct TaskScheduler;
+struct TaskPool;
+
+namespace PTC {
+
+typedef function<void(void)> UtilTaskFunction;
+
+class UtilTaskPool {
+public:
+ UtilTaskPool();
+ ~UtilTaskPool();
+
+ void push(const UtilTaskFunction& run, bool front = false);
+
+ void wait_work();
+ void cancel();
+ void stop();
+
+ bool cancelled();
+
+protected:
+ struct TaskScheduler *scheduler_;
+ struct TaskPool *pool_;
+};
+
+} /* namespace PTC */
+
+#endif /* PTC_UTIL_TASK_H */
diff --git a/source/blender/pointcache/util/util_thread.h b/source/blender/pointcache/util/util_thread.h
new file mode 100644
index 00000000000..6b41a35ee3f
--- /dev/null
+++ b/source/blender/pointcache/util/util_thread.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2015, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_UTIL_THREAD_H
+#define PTC_UTIL_THREAD_H
+
+#include "BLI_threads.h"
+
+namespace PTC {
+
+class thread_mutex {
+public:
+ thread_mutex()
+ {
+ BLI_mutex_init(&mutex_);
+ }
+
+ ~thread_mutex()
+ {
+ BLI_mutex_end(&mutex_);
+ }
+
+ void lock()
+ {
+ BLI_mutex_lock(&mutex_);
+ }
+
+ bool trylock()
+ {
+ return BLI_mutex_trylock(&mutex_);
+ }
+
+ void unlock()
+ {
+ BLI_mutex_unlock(&mutex_);
+ }
+
+protected:
+ ThreadMutex mutex_;
+};
+
+class thread_scoped_lock {
+public:
+ explicit thread_scoped_lock(thread_mutex& mutex)
+ : mutex_(mutex)
+ {
+ mutex_.lock();
+ }
+
+ ~thread_scoped_lock() {
+ mutex_.unlock();
+ }
+protected:
+ thread_mutex& mutex_;
+};
+
+} /* namespace PTC */
+
+#endif /* PTC_UTIL_THREAD_H */
diff --git a/source/blender/pointcache/util/util_types.h b/source/blender/pointcache/util/util_types.h
new file mode 100644
index 00000000000..0ee027c7700
--- /dev/null
+++ b/source/blender/pointcache/util/util_types.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PTC_UTIL_TYPES_H
+#define PTC_UTIL_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum PTCArchiveResolution {
+ PTC_RESOLUTION_NONE = 0,
+ PTC_RESOLUTION_PREVIEW = (1 << 0),
+ PTC_RESOLUTION_RENDER = (1 << 1),
+} PTCArchiveResolution;
+
+typedef enum PTCErrorLevel {
+ PTC_ERROR_NONE = 0,
+ PTC_ERROR_INFO = 1,
+ PTC_ERROR_WARNING = 2,
+ PTC_ERROR_CRITICAL = 3,
+} PTCErrorLevel;
+
+typedef void (*PTCErrorCallback)(void *userdata, PTCErrorLevel level, const char *message);
+
+typedef enum PTCReadSampleResult {
+ PTC_READ_SAMPLE_INVALID = 0, /* no valid result can be retrieved */
+ PTC_READ_SAMPLE_EARLY, /* request time before first sample */
+ PTC_READ_SAMPLE_LATE, /* request time after last sample */
+ PTC_READ_SAMPLE_EXACT, /* found sample for requested frame */
+ PTC_READ_SAMPLE_INTERPOLATED /* no exact sample, but found enclosing samples for interpolation */
+} PTCReadSampleResult;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PTC_UTIL_TYPES_H */
diff --git a/source/blender/python/bmesh/bmesh_py_api.c b/source/blender/python/bmesh/bmesh_py_api.c
index bc14e1ac3a6..f74737ba8f4 100644
--- a/source/blender/python/bmesh/bmesh_py_api.c
+++ b/source/blender/python/bmesh/bmesh_py_api.c
@@ -108,7 +108,7 @@ PyDoc_STRVAR(bpy_bm_update_edit_mesh_doc,
" :type mesh: :class:`bpy.types.Mesh`\n"
" :arg tessface: Option to recalculate n-gon tessellation.\n"
" :type tessface: boolean\n"
-" :arg destructive: Use when grometry has been added or removed.\n"
+" :arg destructive: Use when geometry has been added or removed.\n"
" :type destructive: boolean\n"
);
static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c
index 84c1031a24a..a4c057acac2 100644
--- a/source/blender/python/bmesh/bmesh_py_ops_call.c
+++ b/source/blender/python/bmesh/bmesh_py_ops_call.c
@@ -69,9 +69,10 @@ static int bpy_bm_op_as_py_error(BMesh *bm)
* \param htype Test \a value matches this type.
* \param descr Description text.
*/
-static int bpy_slot_from_py_elem_check(BPy_BMElem *value, BMesh *bm, const char htype,
- /* for error messages */
- const char *opname, const char *slot_name, const char *descr)
+static int bpy_slot_from_py_elem_check(
+ BPy_BMElem *value, BMesh *bm, const char htype,
+ /* for error messages */
+ const char *opname, const char *slot_name, const char *descr)
{
if (!BPy_BMElem_Check(value) ||
!(value->ele->head.htype & htype))
@@ -107,10 +108,11 @@ static int bpy_slot_from_py_elem_check(BPy_BMElem *value, BMesh *bm, const char
* \param htype_bmo The type(s) supported by the target slot.
* \param descr Description text.
*/
-static int bpy_slot_from_py_elemseq_check(BPy_BMGeneric *value, BMesh *bm,
- const char htype_py, const char htype_bmo,
- /* for error messages */
- const char *opname, const char *slot_name, const char *descr)
+static int bpy_slot_from_py_elemseq_check(
+ BPy_BMGeneric *value, BMesh *bm,
+ const char htype_py, const char htype_bmo,
+ /* for error messages */
+ const char *opname, const char *slot_name, const char *descr)
{
if (value->bm == NULL) {
PyErr_Format(PyExc_TypeError,
@@ -142,9 +144,10 @@ static int bpy_slot_from_py_elemseq_check(BPy_BMGeneric *value, BMesh *bm,
/**
* Use for giving py args to an operator.
*/
-static int bpy_slot_from_py(BMesh *bm, BMOperator *bmop, BMOpSlot *slot, PyObject *value,
- /* the are just for exception messages */
- const char *opname, const char *slot_name)
+static int bpy_slot_from_py(
+ BMesh *bm, BMOperator *bmop, BMOpSlot *slot, PyObject *value,
+ /* the are just for exception messages */
+ const char *opname, const char *slot_name)
{
switch (slot->slot_type) {
case BMO_OP_SLOT_BOOL:
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index 20ee872b3be..14fdada66bb 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -3251,17 +3251,17 @@ static PyObject *bpy_bmloop_repr(BPy_BMLoop *self)
/* Types
* ===== */
-PyTypeObject BPy_BMesh_Type = {{{0}}};
-PyTypeObject BPy_BMVert_Type = {{{0}}};
-PyTypeObject BPy_BMEdge_Type = {{{0}}};
-PyTypeObject BPy_BMFace_Type = {{{0}}};
-PyTypeObject BPy_BMLoop_Type = {{{0}}};
-PyTypeObject BPy_BMElemSeq_Type = {{{0}}};
-PyTypeObject BPy_BMVertSeq_Type = {{{0}}};
-PyTypeObject BPy_BMEdgeSeq_Type = {{{0}}};
-PyTypeObject BPy_BMFaceSeq_Type = {{{0}}};
-PyTypeObject BPy_BMLoopSeq_Type = {{{0}}};
-PyTypeObject BPy_BMIter_Type = {{{0}}};
+PyTypeObject BPy_BMesh_Type;
+PyTypeObject BPy_BMVert_Type;
+PyTypeObject BPy_BMEdge_Type;
+PyTypeObject BPy_BMFace_Type;
+PyTypeObject BPy_BMLoop_Type;
+PyTypeObject BPy_BMElemSeq_Type;
+PyTypeObject BPy_BMVertSeq_Type;
+PyTypeObject BPy_BMEdgeSeq_Type;
+PyTypeObject BPy_BMFaceSeq_Type;
+PyTypeObject BPy_BMLoopSeq_Type;
+PyTypeObject BPy_BMIter_Type;
@@ -3757,10 +3757,11 @@ void bpy_bm_generic_invalidate(BPy_BMGeneric *self)
*
* The 'bm_r' value is assigned when empty, and used when set.
*/
-void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_size,
- const char htype,
- const bool do_unique_check, const bool do_bm_check,
- const char *error_prefix)
+void *BPy_BMElem_PySeq_As_Array(
+ BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_size,
+ const char htype,
+ const bool do_unique_check, const bool do_bm_check,
+ const char *error_prefix)
{
BMesh *bm = (r_bm && *r_bm) ? *r_bm : NULL;
PyObject *seq_fast;
diff --git a/source/blender/python/bmesh/bmesh_py_types.h b/source/blender/python/bmesh/bmesh_py_types.h
index 66059a642d1..630afcb32c0 100644
--- a/source/blender/python/bmesh/bmesh_py_types.h
+++ b/source/blender/python/bmesh/bmesh_py_types.h
@@ -158,10 +158,11 @@ PyObject *BPy_BMIter_CreatePyObject(BMesh *bm);
PyObject *BPy_BMElem_CreatePyObject(BMesh *bm, BMHeader *ele); /* just checks type and creates v/e/f/l */
-void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_size,
- const char htype,
- const bool do_unique_check, const bool do_bm_check,
- const char *error_prefix);
+void *BPy_BMElem_PySeq_As_Array(
+ BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_size,
+ const char htype,
+ const bool do_unique_check, const bool do_bm_check,
+ const char *error_prefix);
PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_len);
PyObject *BPy_BMVert_Array_As_Tuple(BMesh *bm, BMVert **elem, Py_ssize_t elem_len);
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c
index 7fcc3813096..1d5f0d7ac37 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c
@@ -791,12 +791,12 @@ PyDoc_STRVAR(bpy_bmlayeritem_type_doc,
);
-PyTypeObject BPy_BMLayerAccessVert_Type = {{{0}}}; /* bm.verts.layers */
-PyTypeObject BPy_BMLayerAccessEdge_Type = {{{0}}}; /* bm.edges.layers */
-PyTypeObject BPy_BMLayerAccessFace_Type = {{{0}}}; /* bm.faces.layers */
-PyTypeObject BPy_BMLayerAccessLoop_Type = {{{0}}}; /* bm.loops.layers */
-PyTypeObject BPy_BMLayerCollection_Type = {{{0}}}; /* bm.loops.layers.uv */
-PyTypeObject BPy_BMLayerItem_Type = {{{0}}}; /* bm.loops.layers.uv["UVMap"] */
+PyTypeObject BPy_BMLayerAccessVert_Type; /* bm.verts.layers */
+PyTypeObject BPy_BMLayerAccessEdge_Type; /* bm.edges.layers */
+PyTypeObject BPy_BMLayerAccessFace_Type; /* bm.faces.layers */
+PyTypeObject BPy_BMLayerAccessLoop_Type; /* bm.loops.layers */
+PyTypeObject BPy_BMLayerCollection_Type; /* bm.loops.layers.uv */
+PyTypeObject BPy_BMLayerItem_Type; /* bm.loops.layers.uv["UVMap"] */
PyObject *BPy_BMLayerAccess_CreatePyObject(BMesh *bm, const char htype)
diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.c b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
index 94f38ffdec7..92c11a03433 100644
--- a/source/blender/python/bmesh/bmesh_py_types_meshdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
@@ -99,7 +99,7 @@ static PyGetSetDef bpy_bmtexpoly_getseters[] = {
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
-static PyTypeObject BPy_BMTexPoly_Type = {{{0}}}; /* bm.loops.layers.uv.active */
+static PyTypeObject BPy_BMTexPoly_Type; /* bm.loops.layers.uv.active */
static void bm_init_types_bmtexpoly(void)
{
@@ -212,7 +212,7 @@ static PyGetSetDef bpy_bmloopuv_getseters[] = {
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
-PyTypeObject BPy_BMLoopUV_Type = {{{0}}}; /* bm.loops.layers.uv.active */
+PyTypeObject BPy_BMLoopUV_Type; /* bm.loops.layers.uv.active */
static void bm_init_types_bmloopuv(void)
{
@@ -321,7 +321,7 @@ static PyGetSetDef bpy_bmvertskin_getseters[] = {
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
-static PyTypeObject BPy_BMVertSkin_Type = {{{0}}}; /* bm.loops.layers.uv.active */
+static PyTypeObject BPy_BMVertSkin_Type; /* bm.loops.layers.uv.active */
static void bm_init_types_bmvertskin(void)
{
@@ -750,7 +750,7 @@ static struct PyMethodDef bpy_bmdeformvert_methods[] = {
{NULL, NULL, 0, NULL}
};
-PyTypeObject BPy_BMDeformVert_Type = {{{0}}}; /* bm.loops.layers.uv.active */
+PyTypeObject BPy_BMDeformVert_Type; /* bm.loops.layers.uv.active */
static void bm_init_types_bmdvert(void)
{
diff --git a/source/blender/python/bmesh/bmesh_py_types_select.c b/source/blender/python/bmesh/bmesh_py_types_select.c
index 7b792e9f08e..a2dceb2a877 100644
--- a/source/blender/python/bmesh/bmesh_py_types_select.c
+++ b/source/blender/python/bmesh/bmesh_py_types_select.c
@@ -342,8 +342,8 @@ static PyObject *bpy_bmeditseliter_next(BPy_BMEditSelIter *self)
}
}
-PyTypeObject BPy_BMEditSelSeq_Type = {{{0}}};
-PyTypeObject BPy_BMEditSelIter_Type = {{{0}}};
+PyTypeObject BPy_BMEditSelSeq_Type;
+PyTypeObject BPy_BMEditSelIter_Type;
PyObject *BPy_BMEditSel_CreatePyObject(BMesh *bm)
diff --git a/source/blender/python/bmesh/bmesh_py_utils.c b/source/blender/python/bmesh/bmesh_py_utils.c
index 2e32a571e3c..b7890926a85 100644
--- a/source/blender/python/bmesh/bmesh_py_utils.c
+++ b/source/blender/python/bmesh/bmesh_py_utils.c
@@ -84,7 +84,7 @@ static PyObject *bpy_bm_utils_vert_collapse_edge(PyObject *UNUSED(self), PyObjec
return NULL;
}
- if (BM_vert_edge_count(py_vert->v) > 2) {
+ if (BM_vert_edge_count_is_over(py_vert->v, 2)) {
PyErr_SetString(PyExc_ValueError,
"vert_collapse_edge(vert, edge): vert has more than 2 connected edges");
return NULL;
@@ -150,7 +150,7 @@ static PyObject *bpy_bm_utils_vert_collapse_faces(PyObject *UNUSED(self), PyObje
return NULL;
}
- if (BM_vert_edge_count(py_vert->v) > 2) {
+ if (BM_vert_edge_count_is_over(py_vert->v, 2)) {
PyErr_SetString(PyExc_ValueError,
"vert_collapse_faces(vert, edge): vert has more than 2 connected edges");
return NULL;
@@ -253,7 +253,7 @@ static PyObject *bpy_bm_utils_vert_splice(PyObject *UNUSED(self), PyObject *args
}
/* should always succeed */
- ok = BM_vert_splice(bm, py_vert->v, py_vert_target->v);
+ ok = BM_vert_splice(bm, py_vert_target->v, py_vert->v);
BLI_assert(ok == true);
UNUSED_VARS_NDEBUG(ok);
@@ -307,7 +307,7 @@ static PyObject *bpy_bm_utils_vert_separate(PyObject *UNUSED(self), PyObject *ar
return NULL;
}
- BM_vert_separate(bm, py_vert->v, &elem, &elem_len, edge_array, edge_array_len);
+ BM_vert_separate(bm, py_vert->v, edge_array, edge_array_len, false, &elem, &elem_len);
/* return collected verts */
ret = BPy_BMVert_Array_As_Tuple(bm, elem, elem_len);
MEM_freeN(elem);
@@ -670,7 +670,7 @@ PyDoc_STRVAR(bpy_bm_utils_face_vert_separate_doc,
" :type face: :class:`bmesh.types.BMFace`\n"
" :arg vert: A vertex in the face to separate.\n"
" :type vert: :class:`bmesh.types.BMVert`\n"
-" :return vert: The newly created vertex or None of failure.\n"
+" :return vert: The newly created vertex or None on failure.\n"
" :rtype vert: :class:`bmesh.types.BMVert`\n"
"\n"
" .. note::\n"
@@ -749,9 +749,9 @@ PyDoc_STRVAR(bpy_bm_utils_loop_separate_doc,
"\n"
" Rip a vertex in a face away and add a new vertex.\n"
"\n"
-" :arg loop: The to separate.\n"
-" :type loop: :class:`bmesh.types.BMFace`\n"
-" :return vert: The newly created vertex or None of failure.\n"
+" :arg loop: The loop to separate.\n"
+" :type loop: :class:`bmesh.types.BMLoop`\n"
+" :return vert: The newly created vertex or None on failure.\n"
" :rtype vert: :class:`bmesh.types.BMVert`\n"
);
static PyObject *bpy_bm_utils_loop_separate(PyObject *UNUSED(self), BPy_BMLoop *value)
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 92ac82508e5..6443c65a50a 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -478,6 +478,34 @@ error_cleanup:
}
#endif
+PyObject *PyC_ExceptionBuffer_Simple(void)
+{
+ PyObject *string_io_buf;
+
+ PyObject *error_type, *error_value, *error_traceback;
+
+ if (!PyErr_Occurred())
+ return NULL;
+
+ PyErr_Fetch(&error_type, &error_value, &error_traceback);
+
+ if (error_value == NULL) {
+ return NULL;
+ }
+
+ string_io_buf = PyObject_Str(error_value);
+ /* Python does this too */
+ if (UNLIKELY(string_io_buf == NULL)) {
+ string_io_buf = PyUnicode_FromFormat(
+ "<unprintable %s object>", Py_TYPE(error_value)->tp_name);
+ }
+
+ PyErr_Restore(error_type, error_value, error_traceback);
+
+ PyErr_Print();
+ PyErr_Clear();
+ return string_io_buf;
+}
/* string conversion, escape non-unicode chars, coerce must be set to NULL */
const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index 398d7da9179..ab630d1d203 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -32,6 +32,7 @@ void PyC_ObSpit(const char *name, PyObject *var);
void PyC_LineSpit(void);
void PyC_StackSpit(void);
PyObject * PyC_ExceptionBuffer(void);
+PyObject * PyC_ExceptionBuffer_Simple(void);
PyObject * PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...);
PyObject * PyC_FrozenSetFromStrings(const char **strings);
PyObject * PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...);
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 8296027f044..ed04152182e 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC
../../blenloader
../../editors/include
../../gpu
+ ../../imbuf
../../makesdna
../../makesrna
../../windowmanager
@@ -69,6 +70,7 @@ set(SRC
bpy_rna_callback.c
bpy_traceback.c
bpy_util.c
+ bpy_utils_previews.c
bpy_utils_units.c
stubs.c
@@ -94,6 +96,7 @@ set(SRC
bpy_rna_callback.h
bpy_traceback.h
bpy_util.h
+ bpy_utils_previews.h
bpy_utils_units.h
../BPY_extern.h
)
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index ec3c017a7ed..9a5e488850e 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -48,6 +48,7 @@
#include "bpy_props.h"
#include "bpy_library.h"
#include "bpy_operator.h"
+#include "bpy_utils_previews.h"
#include "bpy_utils_units.h"
#include "../generic/py_capi_utils.h"
@@ -330,6 +331,7 @@ void BPy_init_modules(void)
PyModule_AddObject(mod, "ops", BPY_operator_module());
PyModule_AddObject(mod, "app", BPY_app_struct());
PyModule_AddObject(mod, "_utils_units", BPY_utils_units());
+ PyModule_AddObject(mod, "_utils_previews", BPY_utils_previews_module());
/* bpy context */
RNA_pointer_create(NULL, &RNA_Context, (void *)BPy_GetContext(), &ctx_ptr);
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index c8a4971847b..1cf0c44fd87 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -220,6 +220,33 @@ static int bpy_app_debug_set(PyObject *UNUSED(self), PyObject *value, void *clos
return 0;
}
+
+
+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))
+{
+ /* refcount is held in BlenderAppType.tp_dict */
+ static PyObject *ret = NULL;
+
+ if (ret == NULL) {
+ /* only run once */
+ char fullpath[1024];
+ BKE_appdir_program_python_search(
+ fullpath, sizeof(fullpath),
+ PY_MAJOR_VERSION, PY_MINOR_VERSION);
+ ret = PyC_UnicodeFromByte(fullpath);
+ PyDict_SetItemString(BlenderAppType.tp_dict, "binary_path_python", ret);
+ }
+ else {
+ Py_INCREF(ret);
+ }
+
+ return ret;
+
+}
+
PyDoc_STRVAR(bpy_app_debug_value_doc,
"Int, number which can be set to non-zero values for testing purposes"
);
@@ -287,6 +314,9 @@ static PyGetSetDef bpy_app_getsets[] = {
{(char *)"debug_wm", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_WM},
{(char *)"debug_depsgraph", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH},
{(char *)"debug_simdata", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_SIMDATA},
+ {(char *)"debug_gpumem", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_GPU_MEM},
+
+ {(char *)"binary_path_python", bpy_app_binary_path_python_get, NULL, (char *)bpy_app_binary_path_python_doc, NULL},
{(char *)"debug_value", bpy_app_debug_value_get, bpy_app_debug_value_set, (char *)bpy_app_debug_value_doc, NULL},
{(char *)"tempdir", bpy_app_tempdir_get, NULL, (char *)bpy_app_tempdir_doc, NULL},
diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c
index 123b111f3cb..72133badbbb 100644
--- a/source/blender/python/intern/bpy_app_translations.c
+++ b/source/blender/python/intern/bpy_app_translations.c
@@ -47,8 +47,7 @@
#include "../generic/python_utildefines.h"
-typedef struct
-{
+typedef struct {
PyObject_HEAD
/* The string used to separate context from actual message in PY_TRANSLATE RNA props. */
const char *context_separator;
@@ -821,3 +820,12 @@ PyObject *BPY_app_translations_struct(void)
return ret;
}
+
+void BPY_app_translations_end(void)
+{
+ /* Incase the object remains in a module's namespace, see T44127. */
+#ifdef WITH_INTERNATIONAL
+ _clear_translations_cache();
+#endif
+}
+
diff --git a/source/blender/python/intern/bpy_app_translations.h b/source/blender/python/intern/bpy_app_translations.h
index 704307574d0..e04c2484ecc 100644
--- a/source/blender/python/intern/bpy_app_translations.h
+++ b/source/blender/python/intern/bpy_app_translations.h
@@ -28,5 +28,6 @@
#define __BPY_APP_TRANSLATIONS_H__
PyObject *BPY_app_translations_struct(void);
+void BPY_app_translations_end(void);
#endif /* __BPY_APP_TRANSLATIONS_H__ */
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 5b4db89a41a..4be63042c1e 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -61,6 +61,8 @@
#include "bpy_traceback.h"
#include "bpy_intern_string.h"
+#include "bpy_app_translations.h"
+
#include "DNA_text_types.h"
#include "BKE_appdir.h"
@@ -358,6 +360,9 @@ void BPY_python_end(void)
bpy_intern_string_exit();
+ /* bpy.app modules that need cleanup */
+ BPY_app_translations_end();
+
#ifndef WITH_PYTHON_MODULE
BPY_atexit_unregister(); /* without this we get recursive calls to WM_exit */
@@ -590,7 +595,7 @@ int BPY_button_exec(bContext *C, const char *expr, double *value, const bool ver
if (error_ret) {
if (verbose) {
- BPy_errors_to_report(CTX_wm_reports(C));
+ BPy_errors_to_report_ex(CTX_wm_reports(C), false, false);
}
else {
PyErr_Clear();
@@ -831,7 +836,7 @@ static void bpy_module_delay_init(PyObject *bpy_proxy)
static void dealloc_obj_dealloc(PyObject *self);
-static PyTypeObject dealloc_obj_Type = {{{0}}};
+static PyTypeObject dealloc_obj_Type;
/* use our own dealloc so we can free a property if we use one */
static void dealloc_obj_dealloc(PyObject *self)
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index aad47d14b7c..8309938b632 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -100,7 +100,7 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
char *enum_str = BPy_enum_as_string(operator_context_items);
PyErr_Format(PyExc_TypeError,
"Calling operator \"bpy.ops.%s.poll\" error, "
- "expected a string enum in (%.200s)",
+ "expected a string enum in (%s)",
opname, enum_str);
MEM_freeN(enum_str);
return NULL;
@@ -186,7 +186,7 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
char *enum_str = BPy_enum_as_string(operator_context_items);
PyErr_Format(PyExc_TypeError,
"Calling operator \"bpy.ops.%s\" error, "
- "expected a string enum in (%.200s)",
+ "expected a string enum in (%s)",
opname, enum_str);
MEM_freeN(enum_str);
return NULL;
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 8370aea4c99..b0fae243182 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -68,7 +68,8 @@ static EnumPropertyItem property_flag_items[] = {
{0, NULL, 0, NULL, NULL}};
#define BPY_PROPDEF_OPTIONS_DOC \
-" :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'ANIMATABLE', 'LIBRARY_EDITABLE', 'PROPORTIONAL'].\n" \
+" :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'ANIMATABLE', 'LIBRARY_EDITABLE', 'PROPORTIONAL'," \
+ "'TEXTEDIT_UPDATE'].\n" \
" :type options: set\n" \
static EnumPropertyItem property_flag_enum_items[] = {
@@ -1480,15 +1481,26 @@ static EnumPropertyItem *bpy_prop_enum_itemf_cb(struct bContext *C, PointerRNA *
EnumPropertyItem *eitems = NULL;
int err = 0;
- bpy_context_set(C, &gilstate);
+ if (C) {
+ bpy_context_set(C, &gilstate);
+ }
+ else {
+ gilstate = PyGILState_Ensure();
+ }
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEM(args, 0, self);
/* now get the context */
- PyTuple_SET_ITEM(args, 1, (PyObject *)bpy_context_module);
- Py_INCREF(bpy_context_module);
+ if (C) {
+ PyTuple_SET_ITEM(args, 1, (PyObject *)bpy_context_module);
+ Py_INCREF(bpy_context_module);
+ }
+ else {
+ PyTuple_SET_ITEM(args, 1, Py_None);
+ Py_INCREF(Py_None);
+ }
items = PyObject_CallObject(py_func, args);
@@ -1529,8 +1541,13 @@ static EnumPropertyItem *bpy_prop_enum_itemf_cb(struct bContext *C, PointerRNA *
eitems = DummyRNA_NULL_items;
}
+ if (C) {
+ bpy_context_clear(C, &gilstate);
+ }
+ else {
+ PyGILState_Release(gilstate);
+ }
- bpy_context_clear(C, &gilstate);
return eitems;
}
@@ -2617,7 +2634,7 @@ PyDoc_STRVAR(BPy_EnumProperty_doc,
" Note the item is optional.\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)\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"
" :type items: sequence of string tuples or a function\n"
@@ -2965,9 +2982,10 @@ static struct PyMethodDef props_methods[] = {
static struct PyModuleDef props_module = {
PyModuleDef_HEAD_INIT,
"bpy.props",
- "This module defines properties to extend blenders internal data, the result of these functions"
- " is used to assign properties to classes registered with blender and can't be used directly.\n"
- ".. warning:: All parameters to these functions must be passed as keywords.",
+ "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",
-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 fadc50e3317..af5ec03c7ed 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -177,7 +177,7 @@ static GHash *id_weakref_pool_get(ID *id)
if (weakinfo_hash == NULL) {
/* we're using a ghash as a set, could use libHX's HXMAP_SINGULAR but would be an extra dep. */
weakinfo_hash = BLI_ghash_ptr_new("rna_id");
- BLI_ghash_insert(id_weakref_pool, (void *)id, weakinfo_hash);
+ BLI_ghash_insert(id_weakref_pool, id, weakinfo_hash);
}
return weakinfo_hash;
@@ -203,7 +203,7 @@ static void id_weakref_pool_add(ID *id, BPy_DummyPointerRNA *pyrna)
Py_DECREF(weakref_cb_py); /* function owned by the weakref now */
/* important to add at the end, since first removal looks at the end */
- BLI_ghash_insert(weakinfo_hash, (void *)weakref, id); /* using a hash table as a set, all 'id's are the same */
+ BLI_ghash_insert(weakinfo_hash, weakref, id); /* using a hash table as a set, all 'id's are the same */
/* weakinfo_hash owns the weakref */
}
@@ -1830,25 +1830,23 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb
RNA_property_pointer_set(ptr, prop, param->ptr);
}
else {
+ raise_error = true;
+ }
+ }
+
+ if (raise_error) {
+ if (pyrna_struct_validity_check(param) == -1) {
+ /* error set */
+ }
+ else {
PointerRNA tmp;
RNA_pointer_create(NULL, ptr_type, NULL, &tmp);
PyErr_Format(PyExc_TypeError,
- "%.200s %.200s.%.200s expected a %.200s type. not %.200s",
+ "%.200s %.200s.%.200s expected a %.200s type, not %.200s",
error_prefix, RNA_struct_identifier(ptr->type),
RNA_property_identifier(prop), RNA_struct_identifier(tmp.type),
RNA_struct_identifier(param->ptr.type));
- Py_XDECREF(value_new); return -1;
}
- }
-
- if (raise_error) {
- PointerRNA tmp;
- RNA_pointer_create(NULL, ptr_type, NULL, &tmp);
- PyErr_Format(PyExc_TypeError,
- "%.200s %.200s.%.200s expected a %.200s type, not %.200s",
- error_prefix, RNA_struct_identifier(ptr->type),
- RNA_property_identifier(prop), RNA_struct_identifier(tmp.type),
- RNA_struct_identifier(param->ptr.type));
Py_XDECREF(value_new); return -1;
}
}
diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c
index 93183a4f320..e876adfa58e 100644
--- a/source/blender/python/intern/bpy_util.c
+++ b/source/blender/python/intern/bpy_util.c
@@ -82,14 +82,9 @@ short BPy_reports_to_error(ReportList *reports, PyObject *exception, const bool
}
-short BPy_errors_to_report(ReportList *reports)
+bool BPy_errors_to_report_ex(ReportList *reports, const bool use_full, const bool use_location)
{
PyObject *pystring;
- PyObject *pystring_format = NULL; /* workaround, see below */
- const char *cstring;
-
- const char *filename;
- int lineno;
if (!PyErr_Occurred())
return 1;
@@ -101,31 +96,56 @@ short BPy_errors_to_report(ReportList *reports)
return 1;
}
- pystring = PyC_ExceptionBuffer();
+ if (use_full) {
+ pystring = PyC_ExceptionBuffer();
+ }
+ else {
+ pystring = PyC_ExceptionBuffer_Simple();
+ }
if (pystring == NULL) {
BKE_report(reports, RPT_ERROR, "Unknown py-exception, could not convert");
return 0;
}
-
- PyC_FileAndNum(&filename, &lineno);
- if (filename == NULL)
- filename = "<unknown location>";
-
- cstring = _PyUnicode_AsString(pystring);
+
+ if (use_location) {
+ const char *filename;
+ int lineno;
+
+ PyObject *pystring_format; /* workaround, see below */
+ const char *cstring;
+
+ PyC_FileAndNum(&filename, &lineno);
+ if (filename == NULL) {
+ filename = "<unknown location>";
+ }
#if 0 /* ARG!. workaround for a bug in blenders use of vsnprintf */
- BKE_reportf(reports, RPT_ERROR, "%s\nlocation: %s:%d\n", cstring, filename, lineno);
+ BKE_reportf(reports, RPT_ERROR, "%s\nlocation: %s:%d\n", _PyUnicode_AsString(pystring), filename, lineno);
#else
- pystring_format = PyUnicode_FromFormat(TIP_("%s\nlocation: %s:%d\n"), cstring, filename, lineno);
- cstring = _PyUnicode_AsString(pystring_format);
- BKE_report(reports, RPT_ERROR, cstring);
+ pystring_format = PyUnicode_FromFormat(
+ TIP_("%s\nlocation: %s:%d\n"),
+ _PyUnicode_AsString(pystring), filename, lineno);
+
+ cstring = _PyUnicode_AsString(pystring_format);
+ BKE_report(reports, RPT_ERROR, cstring);
+
+ /* not exactly needed. just for testing */
+ fprintf(stderr, TIP_("%s\nlocation: %s:%d\n"), cstring, filename, lineno);
+
+ Py_DECREF(pystring_format); /* workaround */
#endif
+ }
+ else {
+ BKE_report(reports, RPT_ERROR, _PyUnicode_AsString(pystring));
+ }
- /* not exactly needed. just for testing */
- fprintf(stderr, TIP_("%s\nlocation: %s:%d\n"), cstring, filename, lineno);
Py_DECREF(pystring);
- Py_DECREF(pystring_format); /* workaround */
return 1;
}
+
+bool BPy_errors_to_report(ReportList *reports)
+{
+ return BPy_errors_to_report_ex(reports, true, true);
+} \ No newline at end of file
diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_util.h
index d19696aa230..1ae00a7fb02 100644
--- a/source/blender/python/intern/bpy_util.h
+++ b/source/blender/python/intern/bpy_util.h
@@ -40,7 +40,8 @@ char *BPy_enum_as_string(struct EnumPropertyItem *item);
/* error reporting */
short BPy_reports_to_error(struct ReportList *reports, PyObject *exception, const bool clear);
-short BPy_errors_to_report(struct ReportList *reports);
+bool BPy_errors_to_report_ex(struct ReportList *reports, const bool use_full, const bool use_location);
+bool BPy_errors_to_report(struct ReportList *reports);
/* TODO - find a better solution! */
struct bContext *BPy_GetContext(void);
diff --git a/source/blender/python/intern/bpy_utils_previews.c b/source/blender/python/intern/bpy_utils_previews.c
new file mode 100644
index 00000000000..fed7c7210de
--- /dev/null
+++ b/source/blender/python/intern/bpy_utils_previews.c
@@ -0,0 +1,188 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_utils_previews.c
+ * \ingroup pythonintern
+ *
+ * This file defines a singleton py object accessed via 'bpy.utils.previews',
+ * which exposes low-level API for custom previews/icons.
+ * It is replaced in final API by an higher-level python wrapper, that handles previews by addon,
+ * and automatically release them on deletion.
+ */
+
+#include <Python.h>
+#include <structmember.h>
+
+#include "BLI_utildefines.h"
+
+#include "RNA_types.h"
+#include "RNA_access.h"
+
+#include "BPY_extern.h"
+#include "bpy_utils_previews.h"
+#include "bpy_rna.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_thumbs.h"
+
+#include "BKE_icons.h"
+
+#include "DNA_ID.h"
+
+#include "../generic/python_utildefines.h"
+
+#define STR_SOURCE_TYPES "'IMAGE', 'MOVIE', 'BLEND', 'FONT'"
+
+PyDoc_STRVAR(bpy_utils_previews_new_doc,
+".. method:: new(name)\n"
+"\n"
+" Generate a new empty preview, or return existing one matching ``name``.\n"
+"\n"
+" :arg name: The name (unique id) identifying the preview.\n"
+" :type name: string\n"
+" :return: The Preview matching given name, or a new empty one.\n"
+" :rtype: :class:`bpy.types.ImagePreview`\n"
+);
+static PyObject *bpy_utils_previews_new(PyObject *UNUSED(self), PyObject *args)
+{
+ char *name;
+ PreviewImage *prv;
+ PointerRNA ptr;
+
+ if (!PyArg_ParseTuple(args, "s:new", &name)) {
+ return NULL;
+ }
+
+ prv = BKE_previewimg_cached_ensure(name);
+ RNA_pointer_create(NULL, &RNA_ImagePreview, prv, &ptr);
+
+ return pyrna_struct_CreatePyObject(&ptr);
+}
+
+PyDoc_STRVAR(bpy_utils_previews_load_doc,
+".. method:: load(name, filepath, filetype, force_reload=False)\n"
+"\n"
+" Generate a new preview from given file path, or return existing one matching ``name``.\n"
+"\n"
+" :arg name: The name (unique id) identifying the preview.\n"
+" :type name: string\n"
+" :arg filepath: The file path to generate the preview from.\n"
+" :type filepath: string\n"
+" :arg filetype: The type of file, needed to generate the preview in [" STR_SOURCE_TYPES "].\n"
+" :type filetype: string\n"
+" :arg force_reload: If True, force running thumbnail manager even if preview already exists in cache.\n"
+" :type force_reload: bool\n"
+" :return: The Preview matching given name, or a new empty one.\n"
+" :rtype: :class:`bpy.types.ImagePreview`\n"
+);
+static PyObject *bpy_utils_previews_load(PyObject *UNUSED(self), PyObject *args)
+{
+ char *name, *path, *path_type_s;
+ int path_type, force_reload = false;
+
+ PreviewImage *prv;
+ PointerRNA ptr;
+
+ if (!PyArg_ParseTuple( args, "sss|p:load", &name, &path, &path_type_s, &force_reload)) {
+ return NULL;
+ }
+
+ if (STREQ(path_type_s, "IMAGE")) {
+ path_type = THB_SOURCE_IMAGE;
+ }
+ else if (STREQ(path_type_s, "MOVIE")) {
+ path_type = THB_SOURCE_MOVIE;
+ }
+ else if (STREQ(path_type_s, "BLEND")) {
+ path_type = THB_SOURCE_BLEND;
+ }
+ else if (STREQ(path_type_s, "FONT")) {
+ path_type = THB_SOURCE_FONT;
+ }
+ else {
+ PyErr_Format(PyExc_ValueError,
+ "load: invalid '%s' filetype, only [" STR_SOURCE_TYPES "] "
+ "are supported", path_type_s);
+ return NULL;
+ }
+
+ prv = BKE_previewimg_cached_thumbnail_read(name, path, path_type, force_reload);
+ RNA_pointer_create(NULL, &RNA_ImagePreview, prv, &ptr);
+
+ return pyrna_struct_CreatePyObject(&ptr);
+}
+
+PyDoc_STRVAR(bpy_utils_previews_release_doc,
+".. method:: release(name)\n"
+"\n"
+" Release (free) a previously created preview.\n"
+"\n"
+"\n"
+" :arg name: The name (unique id) identifying the preview.\n"
+" :type name: string\n"
+);
+static PyObject *bpy_utils_previews_release(PyObject *UNUSED(self), PyObject *args)
+{
+ char *name;
+
+ if (!PyArg_ParseTuple(args, "s:release", &name)) {
+ return NULL;
+ }
+
+ BKE_previewimg_cached_release(name);
+
+ Py_RETURN_NONE;
+}
+
+static struct PyMethodDef bpy_utils_previews_methods[] = {
+ /* Can't use METH_KEYWORDS alone, see http://bugs.python.org/issue11587 */
+ {"new", (PyCFunction)bpy_utils_previews_new, METH_VARARGS, bpy_utils_previews_new_doc},
+ {"load", (PyCFunction)bpy_utils_previews_load, METH_VARARGS, bpy_utils_previews_load_doc},
+ {"release", (PyCFunction)bpy_utils_previews_release, METH_VARARGS, bpy_utils_previews_release_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+PyDoc_STRVAR(bpy_utils_previews_doc,
+"This object contains basic static methods to handle cached (non-ID) previews in Blender\n"
+"(low-level API, not exposed to final users)."
+);
+static struct PyModuleDef bpy_utils_previews_module = {
+ PyModuleDef_HEAD_INIT,
+ "bpy._utils_previews",
+ bpy_utils_previews_doc,
+ 0,
+ bpy_utils_previews_methods,
+ NULL, NULL, NULL, NULL
+};
+
+
+PyObject *BPY_utils_previews_module(void)
+{
+ PyObject *submodule;
+
+ submodule = PyModule_Create(&bpy_utils_previews_module);
+
+ return submodule;
+}
diff --git a/source/blender/python/intern/bpy_utils_previews.h b/source/blender/python/intern/bpy_utils_previews.h
new file mode 100644
index 00000000000..3d7ade04b9f
--- /dev/null
+++ b/source/blender/python/intern/bpy_utils_previews.h
@@ -0,0 +1,32 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_utils_previews.h
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_UTILS_PREVIEWS_H__
+#define __BPY_UTILS_PREVIEWS_H__
+
+PyObject *BPY_utils_previews_module(void);
+
+#endif /* __BPY_UTILS_PREVIEWS_H__ */
diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c
index a6df8f54cc3..d40e7e070ac 100644
--- a/source/blender/python/intern/bpy_utils_units.c
+++ b/source/blender/python/intern/bpy_utils_units.c
@@ -155,18 +155,18 @@ static bool bpyunits_validate(const char *usys_str, const char *ucat_str, int *r
}
PyDoc_STRVAR(bpyunits_to_value_doc,
-".. method:: to_value(unit_system, unit_category, str_input, [str_ref_unit=None])\n"
+".. method:: to_value(unit_system, unit_category, str_input, str_ref_unit=None)\n"
"\n"
" Convert a given input string into a float value.\n"
"\n"
" :arg unit_system: The unit system, from :attr:`bpy.utils.units.systems`.\n"
" :type unit_system: string\n"
-" :arg unit_category: The category of data we are converting (length, area, rotation, etc.), "
+" :arg unit_category: The category of data we are converting (length, area, rotation, etc.),\n"
" from :attr:`bpy.utils.units.categories`.\n"
" :type unit_category: string\n"
" :arg str_input: The string to convert to a float value.\n"
" :type str_input: string\n"
-" :arg str_ref_unit: A reference string from which to extract a default unit, if none is found in :arg:`str_input`.\n"
+" :arg str_ref_unit: A reference string from which to extract a default unit, if none is found in ``str_input``.\n"
" :type str_ref_unit: string or None\n"
" :return: The converted/interpreted value.\n"
" :rtype: float\n"
@@ -221,13 +221,13 @@ static PyObject *bpyunits_to_value(PyObject *UNUSED(self), PyObject *args, PyObj
}
PyDoc_STRVAR(bpyunits_to_string_doc,
-".. method:: to_string(unit_system, unit_category, value, [precision=3, [split_unit=False, [compatible_unit=False]]])\n"
+".. method:: to_string(unit_system, unit_category, value, precision=3, split_unit=False, compatible_unit=False)\n"
"\n"
" Convert a given input float value into a string with units.\n"
"\n"
" :arg unit_system: The unit system, from :attr:`bpy.utils.units.systems`.\n"
" :type unit_system: string\n"
-" :arg unit_category: The category of data we are converting (length, area, rotation, etc.), "
+" :arg unit_category: The category of data we are converting (length, area, rotation, etc.),\n"
" from :attr:`bpy.utils.units.categories`.\n"
" :type unit_category: string\n"
" :arg value: The value to convert to a string.\n"
diff --git a/source/blender/python/intern/gpu.c b/source/blender/python/intern/gpu.c
index e4580e8035b..f933c02390c 100644
--- a/source/blender/python/intern/gpu.c
+++ b/source/blender/python/intern/gpu.c
@@ -79,7 +79,17 @@ static PyObject *PyInit_gpu(void)
if (m == NULL)
return NULL;
+ /* device constant groups */
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_MISC);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_LAMP);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_OBJECT);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_SAMPLER);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_MIST);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_WORLD);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_MAT);
+
/* device constants */
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_NONE);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_VIEWMAT);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_MAT);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_VIEWIMAT);
@@ -92,9 +102,30 @@ static PyObject *PyInit_gpu(void)
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNPERSMAT);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNENERGY);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNCOL);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_ATT1);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_ATT2);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DISTANCE);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTBLEND);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTSIZE);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DBUFFER);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DIMAGE);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DSHADOW);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_ENABLE);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_START);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_DISTANCE);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_INTENSITY);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_TYPE);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_COLOR);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_HORIZON_COLOR);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_AMBIENT_COLOR);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_ALPHA);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_AMB);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_DIFFRGB);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_EMIT);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_HARD);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_REF);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_SPEC);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_SPECRGB);
PY_MODULE_ADD_CONSTANT(m, GPU_DATA_1I);
PY_MODULE_ADD_CONSTANT(m, GPU_DATA_1F);
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 67905f8e340..817173c5bc6 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -1858,7 +1858,7 @@ static PyObject *Matrix_zero(MatrixObject *self)
if (BaseMath_Prepare_ForWrite(self) == -1)
return NULL;
- fill_vn_fl(self->matrix, self->num_col * self->num_row, 0.0f);
+ copy_vn_fl(self->matrix, self->num_col * self->num_row, 0.0f);
if (BaseMath_WriteCallback(self) == -1)
return NULL;
@@ -2757,7 +2757,7 @@ PyDoc_STRVAR(matrix_doc,
" matrices from 2x2 up to 4x4.\n"
"\n"
" :param rows: Sequence of rows.\n"
-" When ommitted, a 4x4 identity matrix is constructed.\n"
+" When ommitted, a 4x4 identity matrix is constructed.\n"
" :type rows: 2d number sequence\n"
);
PyTypeObject matrix_Type = {
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index a33b55c35dc..3d7a505eb12 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -76,7 +76,7 @@ static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
}
- fill_vn_fl(vec, size, 0.0f);
+ copy_vn_fl(vec, size, 0.0f);
break;
case 1:
if ((size = mathutils_array_parse_alloc(&vec, 2, PyTuple_GET_ITEM(args, 0), "mathutils.Vector()")) == -1) {
@@ -142,7 +142,7 @@ static PyObject *C_Vector_Fill(PyObject *cls, PyObject *args)
return NULL;
}
- fill_vn_fl(vec, size, fill);
+ copy_vn_fl(vec, size, fill);
return Vector_CreatePyObject_alloc(vec, size, (PyTypeObject *)cls);
}
@@ -339,7 +339,7 @@ static PyObject *Vector_zero(VectorObject *self)
if (BaseMath_Prepare_ForWrite(self) == -1)
return NULL;
- fill_vn_fl(self->vec, self->size, 0.0f);
+ copy_vn_fl(self->vec, self->size, 0.0f);
if (BaseMath_WriteCallback(self) == -1)
return NULL;
@@ -426,7 +426,7 @@ static PyObject *Vector_resize(VectorObject *self, PyObject *value)
/* If the vector has increased in length, set all new elements to 0.0f */
if (size > self->size) {
- fill_vn_fl(self->vec + self->size, size - self->size, 0.0f);
+ copy_vn_fl(self->vec + self->size, size - self->size, 0.0f);
}
self->size = size;
@@ -465,7 +465,7 @@ static PyObject *Vector_resized(VectorObject *self, PyObject *value)
return NULL;
}
- fill_vn_fl(vec, size, 0.0f);
+ copy_vn_fl(vec, size, 0.0f);
memcpy(vec, self->vec, self->size * sizeof(float));
return Vector_CreatePyObject_alloc(vec, size, NULL);
@@ -2236,7 +2236,7 @@ static int Vector_length_set(VectorObject *self, PyObject *value)
return -1;
}
if (param == 0.0) {
- fill_vn_fl(self->vec, self->size, 0.0f);
+ copy_vn_fl(self->vec, self->size, 0.0f);
return 0;
}
@@ -3030,7 +3030,7 @@ PyObject *Vector_CreatePyObject(
memcpy(self->vec, vec, size * sizeof(float));
}
else { /* new empty */
- fill_vn_fl(self->vec, size, 0.0f);
+ copy_vn_fl(self->vec, size, 0.0f);
if (size == 4) { /* do the homogeneous thing */
self->vec[3] = 1.0f;
}
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index bb4080decef..ae5c058406f 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -850,7 +850,7 @@ PyDoc_STRVAR(M_Geometry_intersect_point_quad_2d_doc,
"\n"
" Takes 5 vectors (using only the x and y coordinates): one is the point and the next 4 define the quad, \n"
" only the x and y are used from the vectors. Returns 1 if the point is within the quad, otherwise 0.\n"
-" Works only with convex quads without singular edges."
+" Works only with convex quads without singular edges.\n"
"\n"
" :arg pt: Point\n"
" :type pt: :class:`mathutils.Vector`\n"
diff --git a/source/blender/quicktime/apple/qtkit_export.m b/source/blender/quicktime/apple/qtkit_export.m
index cbc76e26aa9..db2d4e72dc5 100644
--- a/source/blender/quicktime/apple/qtkit_export.m
+++ b/source/blender/quicktime/apple/qtkit_export.m
@@ -98,8 +98,6 @@ typedef struct QuicktimeExport {
} QuicktimeExport;
-static struct QuicktimeExport *qtexport;
-
#define AUDIOOUTPUTBUFFERSIZE 65536
#pragma mark rna helper functions
@@ -219,10 +217,21 @@ static NSString *stringWithCodecType(int codecType)
return [NSString stringWithCString:str encoding:NSASCIIStringEncoding];
}
-void makeqtstring(RenderData *rd, char *string)
+void makeqtstring(RenderData *rd, char *string, bool preview)
{
+ int sfra, efra;
+
char txt[64];
+ if (preview) {
+ sfra = rd->psfra;
+ efra = rd->pefra;
+ }
+ else {
+ sfra = rd->sfra;
+ efra = rd->efra;
+ }
+
strcpy(string, rd->pic);
BLI_path_abs(string, G.main->name);
@@ -234,10 +243,21 @@ void makeqtstring(RenderData *rd, char *string)
}
}
-void filepath_qt(char *string, RenderData *rd)
+void filepath_qt(char *string, RenderData *rd, bool preview, const char *suffix)
{
+ int sfra, efra;
+
if (string == NULL) return;
+ if (preview) {
+ sfra = rd->psfra;
+ efra = rd->pefra;
+ }
+ else {
+ sfra = rd->sfra;
+ efra = rd->efra;
+ }
+
strcpy(string, rd->pic);
BLI_path_abs(string, G.main->name);
@@ -245,17 +265,32 @@ void filepath_qt(char *string, RenderData *rd)
if (rd->scemode & R_EXTENSION) {
if (!BLI_testextensie(string, ".mov")) {
- BLI_path_frame_range(string, rd->sfra, rd->efra, 4);
+ BLI_path_frame_range(string, sfra, efra, 4);
strcat(string, ".mov");
}
}
else {
if (BLI_path_frame_check_chars(string)) {
- BLI_path_frame_range(string, rd->sfra, rd->efra, 4);
+ BLI_path_frame_range(string, sfra, efra, 4);
}
}
+
+ BLI_path_suffix(string, FILE_MAX, suffix, "");
}
+void *context_create_qt(void)
+{
+ QuicktimeExport *qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport");
+ return qtexport;
+}
+
+void context_free_qt(void *context_v)
+{
+ QuicktimeExport *qtexport = context_v;
+ if (qtexport) {
+ MEM_freeN(qtexport);
+ }
+}
#pragma mark audio export functions
@@ -280,12 +315,13 @@ static OSStatus write_cookie(AudioConverterRef converter, AudioFileID outfile)
}
/* AudioConverter input stream callback */
-static OSStatus AudioConverterInputCallback(AudioConverterRef inAudioConverter,
+static OSStatus AudioConverterInputCallback(AudioConverterRef inAudioConverter,
UInt32* ioNumberDataPackets,
AudioBufferList* ioData,
AudioStreamPacketDescription** outDataPacketDescription,
void* inUserData)
-{
+{
+ QuicktimeExport *qtexport = inUserData;
if (qtexport->audioTotalExportedFrames >= qtexport->audioLastFrame) { /* EOF */
*ioNumberDataPackets = 0;
return noErr;
@@ -312,15 +348,24 @@ static OSStatus AudioConverterInputCallback(AudioConverterRef inAudioConverter,
#pragma mark export functions
-int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, ReportList *reports)
+int start_qt(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty, ReportList *reports, bool preview, const char *UNUSED(suffix))
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSError *error;
char name[1024];
int success = 1;
OSStatus err = noErr;
+ int sfra, efra;
+ QuicktimeExport *qtexport = context_v;
- if (qtexport == NULL) qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport");
+ if (preview) {
+ sfra = rd->psfra;
+ efra = rd->pefra;
+ }
+ else {
+ sfra = rd->sfra;
+ efra = rd->efra;
+ }
[QTMovie enterQTKitOnThread];
@@ -330,7 +375,7 @@ int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, R
success = 0;
}
else {
- makeqtstring(rd, name);
+ makeqtstring(rd, name, preview);
qtexport->filename = [[NSString alloc] initWithCString:name
encoding:[NSString defaultCStringEncoding]];
qtexport->movie = nil;
@@ -591,13 +636,13 @@ int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, R
specs.format = U.audioformat;
specs.rate = U.audiorate;
qtexport->audioInputDevice = AUD_openReadDevice(specs);
- AUD_playDevice(qtexport->audioInputDevice, scene->sound_scene, rd->sfra * rd->frs_sec_base / rd->frs_sec);
+ AUD_playDevice(qtexport->audioInputDevice, scene->sound_scene, sfra * rd->frs_sec_base / rd->frs_sec);
qtexport->audioOutputPktPos = 0;
qtexport->audioTotalExportedFrames = 0;
qtexport->audioTotalSavedFrames = 0;
- qtexport->audioLastFrame = (rd->efra - rd->sfra) * qtexport->audioInputFormat.mSampleRate * rd->frs_sec_base / rd->frs_sec;
+ qtexport->audioLastFrame = (efra - sfra) * qtexport->audioInputFormat.mSampleRate * rd->frs_sec_base / rd->frs_sec;
}
}
}
@@ -607,7 +652,7 @@ int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, R
return success;
}
-int append_qt(struct RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty, ReportList *reports)
+int append_qt(void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty, const char *UNUSED(suffix), ReportList *reports)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSBitmapImageRep *blBitmapFormatImage;
@@ -615,6 +660,7 @@ int append_qt(struct RenderData *rd, int start_frame, int frame, int *pixels, in
OSStatus err = noErr;
unsigned char *from_Ptr,*to_Ptr;
int y,from_i,to_i;
+ QuicktimeExport *qtexport = context_v;
/* Create bitmap image rep in blender format (32bit RGBA) */
blBitmapFormatImage = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
@@ -654,7 +700,7 @@ int append_qt(struct RenderData *rd, int start_frame, int frame, int *pixels, in
UInt32 audioPacketsConverted;
// Upper limit on total exported audio frames for this particular video frame
- const UInt64 exportedAudioFrameLimit = (frame - rd->sfra) * qtexport->audioInputFormat.mSampleRate * rd->frs_sec_base / rd->frs_sec;
+ const UInt64 exportedAudioFrameLimit = (frame - start_frame) * qtexport->audioInputFormat.mSampleRate * rd->frs_sec_base / rd->frs_sec;
/* Append audio */
while (qtexport->audioTotalExportedFrames < exportedAudioFrameLimit) {
@@ -672,7 +718,7 @@ int append_qt(struct RenderData *rd, int start_frame, int frame, int *pixels, in
audioPacketsConverted = 1;
err = AudioConverterFillComplexBuffer(qtexport->audioConverter, AudioConverterInputCallback,
- NULL, &audioPacketsConverted, &qtexport->audioBufferList, qtexport->audioOutputPktDesc);
+ qtexport, &audioPacketsConverted, &qtexport->audioBufferList, qtexport->audioOutputPktDesc);
if (audioPacketsConverted) {
AudioFileWritePackets(qtexport->audioFile, false, qtexport->audioBufferList.mBuffers[0].mDataByteSize,
qtexport->audioOutputPktDesc, qtexport->audioOutputPktPos, &audioPacketsConverted, qtexport->audioOutputBuffer);
@@ -705,9 +751,11 @@ int append_qt(struct RenderData *rd, int start_frame, int frame, int *pixels, in
}
-void end_qt(void)
+void end_qt(void *context_v)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ QuicktimeExport *qtexport = context_v;
+
if (qtexport->movie) {
if (qtexport->audioFile)
@@ -798,11 +846,6 @@ void end_qt(void)
}
[QTMovie exitQTKitOnThread];
-
- if (qtexport) {
- MEM_freeN(qtexport);
- qtexport = NULL;
- }
[pool drain];
}
diff --git a/source/blender/quicktime/quicktime_export.h b/source/blender/quicktime/quicktime_export.h
index a499cd462b7..8a10a4a05d6 100644
--- a/source/blender/quicktime/quicktime_export.h
+++ b/source/blender/quicktime/quicktime_export.h
@@ -54,12 +54,13 @@ struct ImageFormatData;
struct RenderData;
struct ReportList;
struct Scene;
-struct wmOperatorType;
-int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports); //for movie handle (BKE writeavi.c now)
-int append_qt(struct RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty, struct ReportList *reports);
-void end_qt(void);
-void filepath_qt(char *string, struct RenderData *rd);
+int start_qt(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports, bool preview, const char *suffix); //for movie handle (BKE writeavi.c now)
+int append_qt(void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty, const char *suffix, struct ReportList *reports);
+void end_qt(void *context_v);
+void filepath_qt(char *string, struct RenderData *rd, bool preview, const char *suffix);
+void *context_create_qt(void);
+void context_free_qt(void *context_v);
/*RNA helper functions */
void quicktime_verify_image_type(struct RenderData *rd, struct ImageFormatData *imf); //used by RNA for defaults values init, if needed
@@ -76,7 +77,7 @@ int quicktime_rnatmpvalue_from_audiocodectype(int codecType);
int quicktime_audiocodecType_from_rnatmpvalue(int rnatmpvalue);
void free_qtcomponentdata(void);
-void makeqtstring(struct RenderData *rd, char *string); //for playanim.c
+void makeqtstring(struct RenderData *rd, char *string, bool preview); //for playanim.c
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index 36b9f8ae362..4b54ddf7225 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC
../blenkernel
../blenlib
../imbuf
+ ../depsgraph
../makesdna
../makesrna
../physics
diff --git a/source/blender/render/SConscript b/source/blender/render/SConscript
index 0cbf188525b..4a9f32bc1ac 100644
--- a/source/blender/render/SConscript
+++ b/source/blender/render/SConscript
@@ -38,6 +38,7 @@ incs = [
'../blenkernel',
'../blenlib',
'../imbuf',
+ '../depsgraph',
'../makesdna',
'../makesrna',
'../physics',
diff --git a/source/blender/render/extern/include/RE_bake.h b/source/blender/render/extern/include/RE_bake.h
index 481da452529..0750ea1aa28 100644
--- a/source/blender/render/extern/include/RE_bake.h
+++ b/source/blender/render/extern/include/RE_bake.h
@@ -32,6 +32,7 @@
#ifndef __RE_BAKE_H__
#define __RE_BAKE_H__
+struct ImBuf;
struct Render;
struct Mesh;
@@ -49,29 +50,28 @@ typedef struct BakeImages {
} BakeImages;
typedef struct BakePixel {
- int primitive_id;
+ int primitive_id, object_id;
float uv[2];
float du_dx, du_dy;
float dv_dx, dv_dy;
} BakePixel;
typedef struct BakeHighPolyData {
- struct BakePixel *pixel_array;
struct Object *ob;
struct ModifierData *tri_mod;
struct Mesh *me;
char restrict_flag;
+ bool is_flip_object;
float obmat[4][4];
float imat[4][4];
- float rotmat[4][4];
} BakeHighPolyData;
/* external_engine.c */
bool RE_bake_has_engine(struct Render *re);
bool RE_bake_engine(
- struct Render *re, struct Object *object, const BakePixel pixel_array[],
+ struct Render *re, struct Object *object, const int object_id, const BakePixel pixel_array[],
const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]);
/* bake.c */
@@ -81,7 +81,7 @@ bool RE_bake_internal(
const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]);
bool RE_bake_pixels_populate_from_objects(
- struct Mesh *me_low, BakePixel pixel_array_from[],
+ struct Mesh *me_low, BakePixel pixel_array_from[], BakePixel pixel_array_to[],
BakeHighPolyData highpoly[], const int tot_highpoly, const size_t num_pixels, const bool is_custom_cage,
const float cage_extrusion, float mat_low[4][4], float mat_cage[4][4], struct Mesh *me_cage);
diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h
index 5edf970c129..4e48060c54f 100644
--- a/source/blender/render/extern/include/RE_engine.h
+++ b/source/blender/render/extern/include/RE_engine.h
@@ -61,6 +61,7 @@ struct BakePixel;
#define RE_USE_EXCLUDE_LAYERS 32
#define RE_USE_SAVE_BUFFERS 64
#define RE_USE_TEXTURE_PREVIEW 128
+#define RE_USE_SHADING_NODES_CUSTOM 256
/* RenderEngine.flag */
#define RE_ENGINE_ANIMATION 1
@@ -88,7 +89,7 @@ typedef struct RenderEngineType {
void (*update)(struct RenderEngine *engine, struct Main *bmain, struct Scene *scene);
void (*render)(struct RenderEngine *engine, struct Scene *scene);
- void (*bake)(struct RenderEngine *engine, struct Scene *scene, struct Object *object, const int pass_type, const struct BakePixel *pixel_array, const int num_pixels, const int depth, void *result);
+ void (*bake)(struct RenderEngine *engine, struct Scene *scene, struct Object *object, const int pass_type, const int object_id, const struct BakePixel *pixel_array, const int num_pixels, const int depth, void *result);
void (*view_update)(struct RenderEngine *engine, const struct bContext *context);
void (*view_draw)(struct RenderEngine *engine, const struct bContext *context);
@@ -135,10 +136,14 @@ void RE_engine_free(RenderEngine *engine);
void RE_layer_load_from_file(struct RenderLayer *layer, struct ReportList *reports, const char *filename, int x, int y);
void RE_result_load_from_file(struct RenderResult *result, struct ReportList *reports, const char *filename);
-struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername);
+struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname);
void RE_engine_update_result(RenderEngine *engine, struct RenderResult *result);
void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result, int cancel, int merge_results);
+void RE_engine_active_view_set(RenderEngine *engine, const char *viewname);
+float RE_engine_get_camera_shift_x(RenderEngine *engine, struct Object *camera);
+void RE_engine_get_camera_model_matrix(RenderEngine *engine, struct Object *camera, float *r_modelmat);
+
int RE_engine_test_break(RenderEngine *engine);
void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info);
void RE_engine_update_progress(RenderEngine *engine, float progress);
@@ -159,7 +164,7 @@ void RE_engines_exit(void);
RenderEngineType *RE_engines_find(const char *idname);
-void RE_engine_get_current_tiles(struct Render *re, int *total_tiles_r, rcti **tiles_r);
+rcti* RE_engine_get_current_tiles(struct Render *re, int *r_total_tiles, bool *r_needs_free);
struct RenderData *RE_engine_get_render_data(struct Render *re);
void RE_bake_engine_set_engine_parameters(struct Render *re, struct Main *bmain, struct Scene *scene);
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index d1b6673c792..9331c45237d 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -35,8 +35,10 @@
#include "DNA_listBase.h"
#include "DNA_vec_types.h"
+struct bMovieHandle;
struct bNodeTree;
struct Image;
+struct ImageFormatData;
struct Main;
struct NodeBlurData;
struct Object;
@@ -46,6 +48,8 @@ struct ReportList;
struct Scene;
struct SceneRenderLayer;
struct EnvMap;
+struct RenderResult;
+struct StampData;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* this include is what is exposed of render to outside world */
@@ -65,6 +69,19 @@ typedef struct Render Render;
* and how it's converted
*/
+typedef struct RenderView {
+ struct RenderView *next, *prev;
+ char name[64]; /* EXR_VIEW_MAXNAME */
+
+ /* if this exists, result of composited layers */
+ float *rectf;
+ /* if this exists, result of composited layers */
+ float *rectz;
+ /* optional, 32 bits version of picture, used for sequencer, ogl render and image curves */
+ int *rect32;
+
+} RenderView;
+
typedef struct RenderPass {
struct RenderPass *next, *prev;
int passtype, channels;
@@ -72,6 +89,11 @@ typedef struct RenderPass {
char chan_id[8]; /* amount defined in openexr_multi.h */
float *rect;
int rectx, recty;
+
+ char internal_name[64]; /* EXR_PASS_MAXNAME */
+ char view[64]; /* EXR_VIEW_MAXNAME */
+ int view_id; /* quick lookup */
+
int debug_type;
} RenderPass;
@@ -81,7 +103,7 @@ enum {
/* a renderlayer is a full image, but with all passes and samples */
/* size of the rects is defined in RenderResult */
-/* after render, the Combined pass is in rectf, for renderlayers read from files it is a real pass */
+/* after render, the Combined pass is in combined, for renderlayers read from files it is a real pass */
typedef struct RenderLayer {
struct RenderLayer *next, *prev;
@@ -92,8 +114,10 @@ typedef struct RenderLayer {
struct Material *mat_override;
struct Group *light_override;
-
- float *rectf; /* 4 float, standard rgba buffer (read not above!) */
+
+ /* MULTIVIEW_TODO: acolrect and scolrect are not supported by multiview at the moment.
+ * If they are really required they should be in RenderView instead */
+
float *acolrect; /* 4 float, optional transparent buffer, needs storage for display updates */
float *scolrect; /* 4 float, optional strand buffer, needs storage for display updates */
int *display_buffer; /* 4 char, optional color managed display buffer which is used when
@@ -114,6 +138,9 @@ typedef struct RenderResult {
int rectx, recty;
short crop, sample_nr;
+ /* the following rect32, rectf and rectz buffers are for temporary storage only, for RenderResult structs
+ * created in #RE_AcquireResultImage - which do not have RenderView */
+
/* optional, 32 bits version of picture, used for ogl render and image curves */
int *rect32;
/* if this exists, a copy of one of layers, or result of composited layers */
@@ -129,6 +156,9 @@ typedef struct RenderResult {
/* the main buffers */
ListBase layers;
+ /* multiView maps to a StringVector in OpenEXR */
+ ListBase views;
+
/* allowing live updates: */
volatile rcti renrect;
volatile RenderLayer *renlay;
@@ -145,6 +175,8 @@ typedef struct RenderResult {
/* render info text */
char *text;
char *error;
+
+ struct StampData *stamp_data;
} RenderResult;
@@ -183,16 +215,18 @@ void RE_FreeRenderResult(struct RenderResult *rr);
struct RenderResult *RE_AcquireResultRead(struct Render *re);
struct RenderResult *RE_AcquireResultWrite(struct Render *re);
void RE_ReleaseResult(struct Render *re);
-void RE_AcquireResultImage(struct Render *re, struct RenderResult *rr);
+void RE_AcquireResultImageViews(struct Render *re, struct RenderResult *rr);
+void RE_ReleaseResultImageViews(struct Render *re, struct RenderResult *rr);
+void RE_AcquireResultImage(struct Render *re, struct RenderResult *rr, const int view_id);
void RE_ReleaseResultImage(struct Render *re);
void RE_SwapResult(struct Render *re, struct RenderResult **rr);
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);
+void RE_AcquiredResultGet32(struct Render *re, struct RenderResult *result, unsigned int *rect, const int view_id);
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
-float *RE_RenderLayerGetPass(struct RenderLayer *rl, int passtype);
+float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, int passtype, const char *viewname);
/* obligatory initialize call, disprect is optional */
void RE_InitState(struct Render *re, struct Render *source, struct RenderData *rd,
@@ -203,6 +237,7 @@ void RE_ChangeModeFlag(struct Render *re, int flag, bool clear);
/* set up the viewplane/perspective matrix, three choices */
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);
@@ -232,6 +267,11 @@ void RE_init_threadcount(Render *re);
/* the main processor, assumes all was set OK! */
void RE_TileProcessor(struct Render *re);
+bool RE_WriteRenderViewsImage(struct ReportList *reports, struct RenderResult *rr, struct Scene *scene, const bool stamp, char *name);
+bool RE_WriteRenderViewsMovie(struct ReportList *reports, struct RenderResult *rr, struct Scene *scene, struct RenderData *rd,
+ struct bMovieHandle *mh, const size_t width, const size_t height, void **movie_ctx_arr,
+ const size_t totvideos, bool preview);
+
/* only RE_NewRender() needed, main Blender render calls */
void RE_BlenderFrame(struct Render *re, struct Main *bmain, struct Scene *scene,
struct SceneRenderLayer *srl, struct Object *camera_override,
@@ -243,6 +283,9 @@ void RE_RenderFreestyleStrokes(struct Render *re, struct Main *bmain, struct Sce
void RE_RenderFreestyleExternal(struct Render *re);
#endif
+void RE_SetActiveRenderView(struct Render *re, const char *viewname);
+const char *RE_GetActiveRenderView(struct Render *re);
+
/* error reporting */
void RE_SetReports(struct Render *re, struct ReportList *reports);
@@ -250,7 +293,7 @@ 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, int compress);
+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[];
@@ -276,6 +319,10 @@ void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nbd, int xsize, int ysize,
int RE_seq_render_active(struct Scene *scene, struct RenderData *rd);
+bool RE_layers_have_name(struct RenderResult *result);
+
+struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int passtype, const char *viewname);
+
/* shaded view or baking options */
#define RE_BAKE_LIGHT 0 /* not listed in rna_scene.c -> can't be enabled! */
#define RE_BAKE_ALL 1
@@ -297,6 +344,7 @@ void RE_Database_Baking(struct Render *re, struct Main *bmain, struct Scene *sce
void RE_DataBase_GetView(struct Render *re, float mat[4][4]);
void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, float mat[4][4]);
+void RE_GetCameraModelMatrix(struct Render *re, struct Object *camera, float r_mat[4][4]);
struct Scene *RE_GetScene(struct Render *re);
bool RE_force_single_renderlayer(struct Scene *scene);
@@ -304,5 +352,12 @@ bool RE_is_rendering_allowed(struct Scene *scene, struct Object *camera_override
bool RE_allow_render_generic_object(struct Object *ob);
+/******* defined in render_result.c *********/
+
+bool RE_HasFakeLayer(RenderResult *res);
+bool RE_RenderResult_is_stereo(RenderResult *res);
+struct RenderView *RE_RenderViewGetById(struct RenderResult *res, const int view_id);
+struct RenderView *RE_RenderViewGetByName(struct RenderResult *res, const char *viewname);
+
#endif /* __RE_PIPELINE_H__ */
diff --git a/source/blender/render/extern/include/RE_render_ext.h b/source/blender/render/extern/include/RE_render_ext.h
index d76d16a641e..9d8a1a66771 100644
--- a/source/blender/render/extern/include/RE_render_ext.h
+++ b/source/blender/render/extern/include/RE_render_ext.h
@@ -39,10 +39,8 @@
/* called by meshtools */
struct DerivedMesh;
struct ImagePool;
-struct LinkNode;
struct MTex;
struct Scene;
-struct View3D;
/* particle.c, effect.c, editmesh_modes.c and brush.c, returns 1 if rgb, 0 otherwise */
int externtex(struct MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread, struct ImagePool *pool, const bool skip_load_image);
@@ -61,6 +59,12 @@ void RE_free_sample_material(struct Material *mat);
void RE_sample_material_color(struct Material *mat, float color[3], float *alpha, const float volume_co[3], const float surface_co[3],
int face_index, short hit_quad, struct DerivedMesh *orcoDm, struct Object *ob);
+/* pointdensity.c */
+
+struct PointDensity;
+
+void RE_sample_point_density(struct Scene *scene, struct PointDensity *pd, int resolution, float *values);
+
void RE_init_texture_rng(void);
void RE_exit_texture_rng(void);
#endif /* __RE_RENDER_EXT_H__ */
diff --git a/source/blender/render/intern/include/initrender.h b/source/blender/render/intern/include/initrender.h
index 1f11cdc6729..87e2d2519d5 100644
--- a/source/blender/render/intern/include/initrender.h
+++ b/source/blender/render/intern/include/initrender.h
@@ -33,7 +33,6 @@
#ifndef __INITRENDER_H__
#define __INITRENDER_H__
-struct Object;
/* Functions */
diff --git a/source/blender/render/intern/include/occlusion.h b/source/blender/render/intern/include/occlusion.h
index 2f3ac2a7bff..4a70d691436 100644
--- a/source/blender/render/intern/include/occlusion.h
+++ b/source/blender/render/intern/include/occlusion.h
@@ -35,11 +35,8 @@
struct Render;
struct ShadeInput;
-struct ShadeResult;
struct RenderPart;
struct ShadeSample;
-struct DerivedMesh;
-struct ObjectRen;
void make_occ_tree(struct Render *re);
void free_occ(struct Render *re);
diff --git a/source/blender/render/intern/include/pixelshading.h b/source/blender/render/intern/include/pixelshading.h
index faf8c5f54f5..8f23455564f 100644
--- a/source/blender/render/intern/include/pixelshading.h
+++ b/source/blender/render/intern/include/pixelshading.h
@@ -32,7 +32,6 @@
#ifndef __PIXELSHADING_H__
#define __PIXELSHADING_H__
-struct ImagePool;
/**
* Render the pixel at (x,y) for object ap. Apply the jitter mask.
diff --git a/source/blender/render/intern/include/pointdensity.h b/source/blender/render/intern/include/pointdensity.h
index e0c293e2473..1d1e808e8d3 100644
--- a/source/blender/render/intern/include/pointdensity.h
+++ b/source/blender/render/intern/include/pointdensity.h
@@ -37,10 +37,12 @@
* Make point density kd-trees for all point density textures in the scene
*/
+struct PointDensity;
struct Render;
struct TexResult;
-void cache_pointdensity(struct Render *re, struct Tex *tex);
+void free_pointdensity(struct PointDensity *pd);
+void cache_pointdensity(struct Render *re, struct PointDensity *pd);
void make_pointdensities(struct Render *re);
void free_pointdensities(struct Render *re);
int pointdensitytex(struct Tex *tex, const float texvec[3], struct TexResult *texres);
diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h
index 90ff69dbfbe..f031be9e9c9 100644
--- a/source/blender/render/intern/include/render_result.h
+++ b/source/blender/render/intern/include/render_result.h
@@ -38,6 +38,7 @@
#define RR_USE_EXR 1
#define RR_ALL_LAYERS NULL
+#define RR_ALL_VIEWS NULL
struct ImBuf;
struct ListBase;
@@ -53,12 +54,15 @@ struct ColorManagedViewSettings;
/* New */
struct RenderResult *render_result_new(struct Render *re,
- struct rcti *partrct, int crop, int savebuffers, const char *layername);
+ struct rcti *partrct, int crop, int savebuffers, const char *layername, const char *viewname);
struct RenderResult *render_result_new_full_sample(struct Render *re,
- struct ListBase *lb, struct rcti *partrct, int crop, int savebuffers);
+ struct ListBase *lb, struct rcti *partrct, int crop, int savebuffers, const char *viewname);
struct RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
+void render_result_view_new(struct RenderResult *rr, const char *viewname);
+void render_result_views_new(struct RenderResult *rr, struct RenderData *rd);
+
/* Merge */
void render_result_merge(struct RenderResult *rr, struct RenderResult *rrpart);
@@ -78,7 +82,7 @@ void render_result_single_layer_end(struct Render *re);
void render_result_exr_file_begin(struct Render *re);
void render_result_exr_file_end(struct Render *re);
-void render_result_exr_file_merge(struct RenderResult *rr, struct RenderResult *rrpart);
+void render_result_exr_file_merge(struct RenderResult *rr, struct RenderResult *rrpart, const char *viewname);
void render_result_exr_file_path(struct Scene *scene, const char *layname, int sample, char *filepath);
int render_result_exr_file_read_sample(struct Render *re, int sample);
@@ -91,15 +95,19 @@ bool render_result_exr_file_cache_read(struct Render *re);
/* Combined Pixel Rect */
-struct ImBuf *render_result_rect_to_ibuf(struct RenderResult *rr, struct RenderData *rd);
+struct ImBuf *render_result_rect_to_ibuf(struct RenderResult *rr, struct RenderData *rd, const int view_id);
void render_result_rect_from_ibuf(struct RenderResult *rr, struct RenderData *rd,
- struct ImBuf *ibuf);
+ struct ImBuf *ibuf, const int view_id);
-void render_result_rect_fill_zero(struct RenderResult *rr);
+void render_result_rect_fill_zero(struct RenderResult *rr, const int view_id);
void render_result_rect_get_pixels(struct RenderResult *rr,
unsigned int *rect, int rectx, int recty,
const struct ColorManagedViewSettings *view_settings,
- const struct ColorManagedDisplaySettings *display_settings);
+ const struct ColorManagedDisplaySettings *display_settings,
+ const int view_id);
+
+void render_result_views_shallowcopy(struct RenderResult *dst, struct RenderResult *src);
+void render_result_views_shallowdelete(struct RenderResult *rr);
#endif /* __RENDER_RESULT_H__ */
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index 8d92fb9eec9..e12a1575992 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -58,7 +58,6 @@ struct MemArena;
struct VertTableNode;
struct VlakTableNode;
struct GHash;
-struct RenderBuckets;
struct ObjectInstanceRen;
struct RayObject;
struct RayFace;
@@ -123,8 +122,7 @@ enum {
};
/* controls state of render, everything that's read-only during render stage */
-struct Render
-{
+struct Render {
struct Render *next, *prev;
char name[RE_MAXNAME];
int slot;
@@ -194,6 +192,7 @@ struct Render
struct Object *camera_override;
unsigned int lay, layer_override;
+ ThreadRWMutex partsmutex;
ListBase parts;
/* render engine */
@@ -275,6 +274,9 @@ struct Render
struct ImagePool *pool;
struct EvaluationContext *eval_ctx;
+
+ void **movie_ctx_arr;
+ char viewname[MAX_NAME];
};
/* ------------------------------------------------------------------------- */
@@ -388,7 +390,6 @@ struct halosort {
/* ------------------------------------------------------------------------- */
struct Material;
-struct MTFace;
struct ImagePool;
typedef struct RadFace {
diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h
index 88b639c4ba9..308903c6c6d 100644
--- a/source/blender/render/intern/include/rendercore.h
+++ b/source/blender/render/intern/include/rendercore.h
@@ -34,14 +34,11 @@
#include "render_types.h"
-struct HaloRen;
struct ShadeInput;
struct ShadeResult;
struct World;
struct RenderPart;
struct RenderLayer;
-struct ObjectRen;
-struct ListBase;
struct RayObject;
/* ------------------------------------------------------------------------- */
diff --git a/source/blender/render/intern/include/shadbuf.h b/source/blender/render/intern/include/shadbuf.h
index 7c168baada7..ece6902b6b2 100644
--- a/source/blender/render/intern/include/shadbuf.h
+++ b/source/blender/render/intern/include/shadbuf.h
@@ -34,7 +34,6 @@
#include "render_types.h"
-struct ObjectRen;
/**
* Calculates shadowbuffers for a vector of shadow-giving lamps
diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h
index 4f6e005d742..11dcc9d9e80 100644
--- a/source/blender/render/intern/include/shading.h
+++ b/source/blender/render/intern/include/shading.h
@@ -33,7 +33,6 @@ struct RenderLayer;
struct PixStr;
struct LampRen;
struct VlakRen;
-struct StrandSegment;
struct StrandPoint;
struct ObjectInstanceRen;
struct Isect;
diff --git a/source/blender/render/intern/include/sss.h b/source/blender/render/intern/include/sss.h
index 91a8b91e638..0952c6bff65 100644
--- a/source/blender/render/intern/include/sss.h
+++ b/source/blender/render/intern/include/sss.h
@@ -55,7 +55,6 @@ void scatter_tree_free(ScatterTree *tree);
struct Render;
struct Material;
-struct VlakRen;
void make_sss_tree(struct Render *re);
void sss_add_points(Render *re, float (*co)[3], float (*color)[3], float *area, int totpoint);
diff --git a/source/blender/render/intern/include/strand.h b/source/blender/render/intern/include/strand.h
index fdcce687f54..5687ef3c837 100644
--- a/source/blender/render/intern/include/strand.h
+++ b/source/blender/render/intern/include/strand.h
@@ -34,9 +34,6 @@ struct StrandBuffer;
struct ShadeSample;
struct StrandPart;
struct Render;
-struct RenderPart;
-struct RenderBuckets;
-struct RenderPrimitiveIterator;
struct ZSpan;
struct ObjectInstanceRen;
struct StrandSurface;
diff --git a/source/blender/render/intern/include/texture.h b/source/blender/render/intern/include/texture.h
index ebc83984306..ed161e186b8 100644
--- a/source/blender/render/intern/include/texture.h
+++ b/source/blender/render/intern/include/texture.h
@@ -56,6 +56,11 @@
_hsv[1] *= tex->saturation; \
hsv_to_rgb(_hsv[0], _hsv[1], _hsv[2], \
&texres->tr, &texres->tg, &texres->tb); \
+ if ((tex->saturation > 1.0f) && !(tex->flag & TEX_NO_CLAMP)) { \
+ if (texres->tr < 0.0f) texres->tr= 0.0f; \
+ if (texres->tg < 0.0f) texres->tg= 0.0f; \
+ if (texres->tb < 0.0f) texres->tb= 0.0f; \
+ } \
} \
struct HaloRen;
diff --git a/source/blender/render/intern/include/zbuf.h b/source/blender/render/intern/include/zbuf.h
index ec30c3241ab..cf804d75d70 100644
--- a/source/blender/render/intern/include/zbuf.h
+++ b/source/blender/render/intern/include/zbuf.h
@@ -36,7 +36,6 @@
struct RenderPart;
struct RenderLayer;
struct LampRen;
-struct VlakRen;
struct ListBase;
struct ZSpan;
struct APixstrand;
diff --git a/source/blender/render/intern/raytrace/rayobject_instance.cpp b/source/blender/render/intern/raytrace/rayobject_instance.cpp
index 01e592cba0c..d080ddcc375 100644
--- a/source/blender/render/intern/raytrace/rayobject_instance.cpp
+++ b/source/blender/render/intern/raytrace/rayobject_instance.cpp
@@ -197,7 +197,7 @@ static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max)
//There must be a faster way than rotating all the 8 vertexs of the BB
for (i = 0; i < 8; i++) {
- for (j = 0; j < 3; j++) t[j] = i & (1 << j) ? M[j] : m[j];
+ for (j = 0; j < 3; j++) t[j] = (i & (1 << j)) ? M[j] : m[j];
mul_m4_v3(obj->target2global, t);
DO_MINMAX(t, min, max);
}
diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c
index 4aa2f4e919e..0210bec5ab4 100644
--- a/source/blender/render/intern/source/bake.c
+++ b/source/blender/render/intern/source/bake.c
@@ -34,6 +34,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -75,6 +76,8 @@ extern struct Render R;
typedef struct BakeShade {
+ int thread;
+
ShadeSample ssamp;
ObjectInstanceRen *obi;
VlakRen *vlr;
@@ -737,6 +740,9 @@ static void bake_single_vertex(BakeShade *bs, VertRen *vert, float u, float v)
MLoopCol *basevcol;
MLoop *mloop;
+ /* per vertex fixed seed */
+ BLI_thread_srandom(bs->thread, vert->index);
+
origindex = RE_vertren_get_origindex(bs->obi->obr, vert, 0);
if (!origindex || *origindex == ORIGINDEX_NONE)
return;
@@ -811,6 +817,9 @@ static void shade_tface(BakeShade *bs)
Image *ima = tface->tpage;
float vec[4][2];
int a, i1, i2, i3;
+
+ /* per face fixed seed */
+ BLI_thread_srandom(bs->thread, vlr->index);
/* check valid zspan */
if (ima != bs->ima) {
@@ -984,8 +993,12 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up
int a, vdone = false, result = BAKE_RESULT_OK;
bool use_mask = false;
bool use_displacement_buffer = false;
- bool do_manage = BKE_scene_check_color_management_enabled(re->scene);
-
+ bool do_manage = false;
+
+ if (ELEM(type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) {
+ do_manage = BKE_scene_check_color_management_enabled(re->scene);
+ }
+
re->scene_color_manage = BKE_scene_check_color_management_enabled(re->scene);
/* initialize render global */
@@ -1033,6 +1046,8 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up
/* get the threads running */
for (a = 0; a < re->r.threads; a++) {
+ handles[a].thread = a;
+
/* set defaults in handles */
handles[a].ssamp.shi[0].lay = re->lay;
diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c
index ecfb86c8d17..bc5db5b9862 100644
--- a/source/blender/render/intern/source/bake_api.c
+++ b/source/blender/render/intern/source/bake_api.c
@@ -30,10 +30,11 @@
*
* The Bake API is fully implemented with Python rna functions. The operator expects/call a function:
*
- * ``def bake(scene, object, pass_type, pixel_array, num_pixels, depth, result)``
+ * ``def bake(scene, object, pass_type, object_id, pixel_array, num_pixels, depth, result)``
* - scene: current scene (Python object)
* - object: object to render (Python object)
* - pass_type: pass to render (string, e.g., "COMBINED", "AO", "NORMAL", ...)
+ * - object_id: index of object to bake (to use with the pixel_array)
* - pixel_array: list of primitive ids and barycentric coordinates to bake(Python object, see bake_pixel)
* - num_pixels: size of pixel_array, number of pixels to bake (int)
* - depth: depth of pixels to return (int, assuming always 4 now)
@@ -47,7 +48,7 @@
*
* \code{.c}
* struct BakePixel {
- * int primitive_id;
+ * int primitive_id, object_id;
* float uv[2];
* float du_dx, du_dy;
* float dv_dx, dv_dy;
@@ -55,7 +56,7 @@
* \endcode
*
* In python you have access to:
- * - ``primitive_id``, ``uv``, ``du_dx``, ``du_dy``, ``next``
+ * - ``primitive_id``, ``object_id``, ``uv``, ``du_dx``, ``du_dy``, ``next``
* - ``next()`` is a function that returns the next #BakePixel in the array.
*
* \note Pixels that should not be baked have ``primitive_id == -1``
@@ -126,12 +127,16 @@ static void store_bake_pixel(void *handle, int x, int y, float u, float v)
pixel = &bd->pixel_array[i];
pixel->primitive_id = bd->primitive_id;
+ /* At this point object_id is always 0, since this function runs for the
+ * lowpoly mesh only. The object_id lookup indices are set afterwards. */
+
copy_v2_fl2(pixel->uv, u, v);
pixel->du_dx = bd->du_dx;
pixel->du_dy = bd->du_dy;
pixel->dv_dx = bd->dv_dx;
pixel->dv_dy = bd->dv_dy;
+ pixel->object_id = 0;
}
void RE_bake_mask_fill(const BakePixel pixel_array[], const size_t num_pixels, char *mask)
@@ -271,7 +276,7 @@ static void calc_barycentric_from_point(
* This function populates pixel_array and returns TRUE if things are correct
*/
static bool cast_ray_highpoly(
- BVHTreeFromMesh *treeData, TriTessFace *triangles[], BakeHighPolyData *highpoly,
+ BVHTreeFromMesh *treeData, TriTessFace *triangles[], BakePixel *pixel_array, BakeHighPolyData *highpoly,
const float co[3], const float dir[3], const int pixel_id, const int tot_highpoly,
const float du_dx, const float du_dy, const float dv_dx, const float dv_dy)
{
@@ -295,7 +300,7 @@ static bool cast_ray_highpoly(
mul_v3_m4v3(co_high, highpoly[i].imat, co);
/* rotates */
- mul_v3_m4v3(dir_high, highpoly[i].rotmat, dir);
+ mul_v3_mat3_m4v3(dir_high, highpoly[i].imat, dir);
normalize_v3(dir_high);
/* cast ray */
@@ -322,22 +327,22 @@ static bool cast_ray_highpoly(
}
}
- for (i = 0; i < tot_highpoly; i++) {
- if (hit_mesh == i) {
- calc_barycentric_from_point(triangles[i], hits[i].index, hits[i].co, &primitive_id, uv);
- highpoly[i].pixel_array[pixel_id].primitive_id = primitive_id;
- copy_v2_v2(highpoly[i].pixel_array[pixel_id].uv, uv);
-
- /* the differentials are relative to the UV/image space, so the highpoly differentials
- * are the same as the low poly differentials */
- highpoly[i].pixel_array[pixel_id].du_dx = du_dx;
- highpoly[i].pixel_array[pixel_id].du_dy = du_dy;
- highpoly[i].pixel_array[pixel_id].dv_dx = dv_dx;
- highpoly[i].pixel_array[pixel_id].dv_dy = dv_dy;
- }
- else {
- highpoly[i].pixel_array[pixel_id].primitive_id = -1;
- }
+ if (hit_mesh != -1) {
+ calc_barycentric_from_point(triangles[hit_mesh], hits[hit_mesh].index, hits[hit_mesh].co, &primitive_id, uv);
+ pixel_array[pixel_id].primitive_id = primitive_id;
+ pixel_array[pixel_id].object_id = hit_mesh;
+ copy_v2_v2(pixel_array[pixel_id].uv, uv);
+
+ /* the differentials are relative to the UV/image space, so the highpoly differentials
+ * are the same as the low poly differentials */
+ pixel_array[pixel_id].du_dx = du_dx;
+ pixel_array[pixel_id].du_dy = du_dy;
+ pixel_array[pixel_id].dv_dx = dv_dx;
+ pixel_array[pixel_id].dv_dy = dv_dy;
+ }
+ else {
+ pixel_array[pixel_id].primitive_id = -1;
+ pixel_array[pixel_id].object_id = -1;
}
MEM_freeN(hits);
@@ -437,7 +442,7 @@ static void mesh_calc_tri_tessface(
}
bool RE_bake_pixels_populate_from_objects(
- struct Mesh *me_low, BakePixel pixel_array_from[],
+ struct Mesh *me_low, BakePixel pixel_array_from[], BakePixel pixel_array_to[],
BakeHighPolyData highpoly[], const int tot_highpoly, const size_t num_pixels, const bool is_custom_cage,
const float cage_extrusion, float mat_low[4][4], float mat_cage[4][4], struct Mesh *me_cage)
{
@@ -508,10 +513,7 @@ bool RE_bake_pixels_populate_from_objects(
primitive_id = pixel_array_from[i].primitive_id;
if (primitive_id == -1) {
- int j;
- for (j = 0; j < tot_highpoly; j++) {
- highpoly[j].pixel_array[i].primitive_id = -1;
- }
+ pixel_array_to[i].primitive_id = -1;
continue;
}
@@ -530,7 +532,7 @@ bool RE_bake_pixels_populate_from_objects(
}
/* cast ray */
- if (!cast_ray_highpoly(treeData, tris_high, highpoly, co, dir, i, tot_highpoly,
+ if (!cast_ray_highpoly(treeData, tris_high, pixel_array_to, highpoly, co, dir, i, tot_highpoly,
pixel_array_from[i].du_dx, pixel_array_from[i].du_dy,
pixel_array_from[i].dv_dx, pixel_array_from[i].dv_dy)) {
/* if it fails mask out the original pixel array */
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 01a347e37c7..1da1a81fe95 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -577,6 +577,17 @@ static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], shor
VlakRen *vlr;
int a, totvert;
+ float rot[3][3];
+
+ /* Note: For normals, we only want rotation, not scaling component.
+ * Negative scales (aka mirroring) give wrong results, see T44102. */
+ if (lnors) {
+ float mat3[3][3], size[3];
+
+ copy_m3_m4(mat3, mat);
+ mat3_to_rot_size(rot, size, mat3);
+ }
+
if (obr->totvert == 0)
return;
@@ -611,9 +622,8 @@ static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], shor
ver = RE_findOrAddVert(obr, a);
mul_m4_v3(mat, ver->co);
if (lnors) {
- mul_mat3_m4_v3(mat, ver->n);
+ mul_m3_v3(rot, ver->n);
negate_v3(ver->n);
- normalize_v3(ver->n);
}
}
for (a = 0; a < obr->totvlak; a++) {
@@ -1199,8 +1209,7 @@ static void particle_normal_ren(short ren_as, ParticleSettings *part, Render *re
sd->time = 0.0f;
sd->size = hasize;
- copy_v3_v3(vel, state->vel);
- mul_mat3_m4_v3(re->viewmat, vel);
+ mul_v3_mat3_m4v3(vel, re->viewmat, state->vel);
normalize_v3(vel);
if (part->draw & PART_DRAW_VEL_LENGTH)
@@ -1258,7 +1267,7 @@ static void get_particle_uvco_mcol(short from, DerivedMesh *dm, float *fuv, int
/* get mcol */
if (sd->mcol && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
for (i=0; i<sd->totcol; i++) {
- if (num != DMCACHE_NOTFOUND) {
+ if (!ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
MFace *mface = dm->getTessFaceData(dm, num, CD_MFACE);
MCol *mc = (MCol*)CustomData_get_layer_n(&dm->faceData, CD_MCOL, i);
mc += num * 4;
@@ -3270,12 +3279,13 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
for (a1=0; (a1<ob->totcol || (a1==0 && ob->totcol==0)); a1++) {
ma= give_render_material(re, ob, a1+1);
-
+
/* test for 100% transparent */
ok = 1;
if ((ma->alpha == 0.0f) &&
(ma->spectra == 0.0f) &&
- (ma->filter == 0.0f) &&
+ /* No need to test filter here, it's only active with MA_RAYTRANSP and we check against it below. */
+ /* (ma->filter == 0.0f) && */
(ma->mode & MA_TRANSP) &&
(ma->mode & (MA_RAYTRANSP | MA_RAYMIRROR)) == 0)
{
@@ -3803,7 +3813,9 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
}
/* set flag for spothalo en initvars */
- if (la->type==LA_SPOT && (la->mode & LA_HALO) && (la->buftype != LA_SHADBUF_DEEP)) {
+ if ((la->type == LA_SPOT) && (la->mode & LA_HALO) &&
+ (!(la->mode & LA_SHAD_BUF) || la->buftype != LA_SHADBUF_DEEP))
+ {
if (la->haint>0.0f) {
re->flag |= R_LAMPHALO;
@@ -3822,7 +3834,7 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
lar->sh_invcampos[2]*= lar->sh_zfac;
/* halfway shadow buffer doesn't work for volumetric effects */
- if (lar->buftype == LA_SHADBUF_HALFWAY)
+ if (ELEM(lar->buftype, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP))
lar->buftype = LA_SHADBUF_REGULAR;
}
@@ -4992,7 +5004,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
* system need to have render settings set for dupli particles */
dupli_render_particle_set(re, ob, timeoffset, 0, 1);
duplilist = object_duplilist(re->eval_ctx, re->scene, ob);
- duplilist_apply_data = duplilist_apply(ob, duplilist);
+ duplilist_apply_data = duplilist_apply(ob, NULL, duplilist);
dupli_render_particle_set(re, ob, timeoffset, 0, 0);
for (dob= duplilist->first, i = 0; dob; dob= dob->next, ++i) {
@@ -5159,8 +5171,7 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
* above call to BKE_scene_update_for_newframe, fixes bug. [#22702].
* following calls don't depend on 'RE_SetCamera' */
RE_SetCamera(re, camera);
-
- normalize_m4_m4(mat, camera->obmat);
+ RE_GetCameraModelMatrix(re, camera, mat);
invert_m4(mat);
RE_SetView(re, mat);
@@ -5330,7 +5341,8 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la
/* if no camera, viewmat should have been set! */
if (camera) {
- normalize_m4_m4(mat, camera->obmat);
+ RE_GetCameraModelMatrix(re, camera, mat);
+ normalize_m4(mat);
invert_m4(mat);
RE_SetView(re, mat);
}
@@ -5841,9 +5853,11 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay,
/* renderdata setup and exceptions */
BLI_freelistN(&re->r.layers);
+ BLI_freelistN(&re->r.views);
re->r = scene->r;
BLI_duplicatelist(&re->r.layers, &scene->r.layers);
-
+ BLI_duplicatelist(&re->r.views, &scene->r.views);
+
RE_init_threadcount(re);
re->flag |= R_BAKING;
diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c
index f0268836104..23d021db848 100644
--- a/source/blender/render/intern/source/envmap.c
+++ b/source/blender/render/intern/source/envmap.c
@@ -70,7 +70,7 @@ static void envmap_split_ima(EnvMap *env, ImBuf *ibuf)
BLI_lock_thread(LOCK_IMAGE);
if (env->cube[1] == NULL) {
- BKE_free_envmapdata(env);
+ BKE_texture_envmap_free_data(env);
dx = ibuf->y;
dx /= 2;
@@ -141,6 +141,7 @@ static Render *envmap_render_copy(Render *re, EnvMap *env)
envre->r = re->r;
envre->r.mode &= ~(R_BORDER | R_PANORAMA | R_ORTHO | R_MBLUR);
BLI_listbase_clear(&envre->r.layers);
+ BLI_listbase_clear(&envre->r.views);
envre->r.filtertype = 0;
envre->r.tilex = envre->r.xsch / 2;
envre->r.tiley = envre->r.ysch / 2;
@@ -495,9 +496,11 @@ static void render_envmap(Render *re, EnvMap *env)
RenderLayer *rl = envre->result->layers.first;
int y;
float *alpha;
-
+ float *rect;
+
+ rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, re->viewname);
ibuf = IMB_allocImBuf(envre->rectx, envre->recty, 24, IB_rect | IB_rectfloat);
- memcpy(ibuf->rect_float, rl->rectf, ibuf->channels * ibuf->x * ibuf->y * sizeof(float));
+ memcpy(ibuf->rect_float, rect, ibuf->channels * ibuf->x * ibuf->y * sizeof(float));
/* envmap renders without alpha */
alpha = ibuf->rect_float + 3;
@@ -511,7 +514,7 @@ static void render_envmap(Render *re, EnvMap *env)
}
- if (re->test_break(re->tbh)) BKE_free_envmapdata(env);
+ if (re->test_break(re->tbh)) BKE_texture_envmap_free_data(env);
else {
if (envre->r.mode & R_OSA) env->ok = ENV_OSA;
else env->ok = ENV_NORMAL;
@@ -572,13 +575,13 @@ void make_envmaps(Render *re)
if (env->ok) {
/* free when OSA, and old one isn't OSA */
if ((re->r.mode & R_OSA) && env->ok == ENV_NORMAL)
- BKE_free_envmapdata(env);
+ BKE_texture_envmap_free_data(env);
/* free when size larger */
else if (env->lastsize < re->r.size)
- BKE_free_envmapdata(env);
+ BKE_texture_envmap_free_data(env);
/* free when env is in recalcmode */
else if (env->recalc)
- BKE_free_envmapdata(env);
+ BKE_texture_envmap_free_data(env);
}
if (env->ok == 0 && depth == 0) env->recalc = 1;
diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c
index 4e63a9918e1..e44dacaaad3 100644
--- a/source/blender/render/intern/source/external_engine.c
+++ b/source/blender/render/intern/source/external_engine.c
@@ -42,6 +42,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BKE_camera.h"
#include "BKE_global.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -181,7 +182,7 @@ static RenderPart *get_part_from_result(Render *re, RenderResult *result)
return NULL;
}
-RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername)
+RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname)
{
Render *re = engine->re;
RenderResult *result;
@@ -204,7 +205,7 @@ RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w,
disprect.ymin = y;
disprect.ymax = y + h;
- result = render_result_new(re, &disprect, 0, RR_USE_MEM, layername);
+ result = render_result_new(re, &disprect, 0, RR_USE_MEM, layername, viewname);
/* todo: make this thread safe */
@@ -269,7 +270,7 @@ void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel
if (!cancel || merge_results) {
if (re->result->do_exr_tile) {
if (!cancel) {
- render_result_exr_file_merge(re->result, result);
+ render_result_exr_file_merge(re->result, result, re->viewname);
}
}
else if (!(re->test_break(re->tbh) && (re->r.scemode & R_BUTS_PREVIEW)))
@@ -368,28 +369,56 @@ void RE_engine_set_error_message(RenderEngine *engine, const char *msg)
}
}
-void RE_engine_get_current_tiles(Render *re, int *total_tiles_r, rcti **tiles_r)
+void RE_engine_active_view_set(RenderEngine *engine, const char *viewname)
{
+ Render *re = engine->re;
+ RE_SetActiveRenderView(re, viewname);
+}
+
+float RE_engine_get_camera_shift_x(RenderEngine *engine, Object *camera)
+{
+ Render *re = engine->re;
+ return BKE_camera_multiview_shift_x(re ? &re->r : NULL, camera, re->viewname);
+}
+
+void RE_engine_get_camera_model_matrix(RenderEngine *engine, Object *camera, float *r_modelmat)
+{
+ Render *re = engine->re;
+ BKE_camera_multiview_model_matrix(re ? &re->r : NULL, camera, re->viewname, (float (*)[4])r_modelmat);
+}
+
+rcti* RE_engine_get_current_tiles(Render *re, int *r_total_tiles, bool *r_needs_free)
+{
+ static rcti tiles_static[BLENDER_MAX_THREADS];
+ const int allocation_step = BLENDER_MAX_THREADS;
RenderPart *pa;
int total_tiles = 0;
- rcti *tiles = NULL;
- int allocation_size = 0, allocation_step = BLENDER_MAX_THREADS;
+ rcti *tiles = tiles_static;
+ int allocation_size = BLENDER_MAX_THREADS;
+
+ BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_READ);
+
+ *r_needs_free = false;
if (re->engine && (re->engine->flag & RE_ENGINE_HIGHLIGHT_TILES) == 0) {
- *total_tiles_r = 0;
- *tiles_r = NULL;
- return;
+ *r_total_tiles = 0;
+ BLI_rw_mutex_unlock(&re->partsmutex);
+ return NULL;
}
for (pa = re->parts.first; pa; pa = pa->next) {
if (pa->status == PART_STATUS_IN_PROGRESS) {
if (total_tiles >= allocation_size) {
- if (tiles == NULL)
+ /* Just in case we're using crazy network rendering with more
+ * slaves as BLENDER_MAX_THREADS.
+ */
+ if (tiles == tiles_static)
tiles = MEM_mallocN(allocation_step * sizeof(rcti), "current engine tiles");
else
tiles = MEM_reallocN(tiles, (total_tiles + allocation_step) * sizeof(rcti));
allocation_size += allocation_step;
+ *r_needs_free = true;
}
tiles[total_tiles] = pa->disprect;
@@ -404,9 +433,9 @@ void RE_engine_get_current_tiles(Render *re, int *total_tiles_r, rcti **tiles_r)
total_tiles++;
}
}
-
- *total_tiles_r = total_tiles;
- *tiles_r = tiles;
+ BLI_rw_mutex_unlock(&re->partsmutex);
+ *r_total_tiles = total_tiles;
+ return tiles;
}
RenderData *RE_engine_get_render_data(Render *re)
@@ -425,6 +454,7 @@ void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene)
* but it potentially leaves unfreed memory blocks
* not sure how to fix this yet -- dfelinto */
BLI_listbase_clear(&re->r.layers);
+ BLI_listbase_clear(&re->r.views);
}
bool RE_bake_has_engine(Render *re)
@@ -434,7 +464,8 @@ bool RE_bake_has_engine(Render *re)
}
bool RE_bake_engine(
- Render *re, Object *object, const BakePixel pixel_array[],
+ Render *re, Object *object,
+ const int object_id, const BakePixel pixel_array[],
const size_t num_pixels, const int depth,
const ScenePassType pass_type, float result[])
{
@@ -472,12 +503,14 @@ bool RE_bake_engine(
type->update(engine, re->main, re->scene);
if (type->bake)
- type->bake(engine, re->scene, object, pass_type, pixel_array, num_pixels, depth, result);
+ type->bake(engine, re->scene, object, pass_type, object_id, pixel_array, num_pixels, depth, result);
engine->tile_x = 0;
engine->tile_y = 0;
engine->flag &= ~RE_ENGINE_RENDERING;
+ BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
+
/* re->engine becomes zero if user changed active render engine during render */
if (!persistent_data || !re->engine) {
RE_engine_free(engine);
@@ -485,6 +518,7 @@ bool RE_bake_engine(
}
RE_parts_free(re);
+ BLI_rw_mutex_unlock(&re->partsmutex);
if (BKE_reports_contain(re->reports, RPT_ERROR))
G.is_break = true;
@@ -599,7 +633,7 @@ int RE_engine_render(Render *re, int do_all)
if ((type->flag & RE_USE_SAVE_BUFFERS) && (re->r.scemode & R_EXR_TILE_FILE))
savebuffers = RR_USE_EXR;
- re->result = render_result_new(re, &re->disprect, 0, savebuffers, RR_ALL_LAYERS);
+ re->result = render_result_new(re, &re->disprect, 0, savebuffers, RR_ALL_LAYERS, RR_ALL_VIEWS);
}
BLI_rw_mutex_unlock(&re->resultmutex);
@@ -663,6 +697,8 @@ int RE_engine_render(Render *re, int do_all)
render_result_free_list(&engine->fullresult, engine->fullresult.first);
+ BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
+
/* re->engine becomes zero if user changed active render engine during render */
if (!persistent_data || !re->engine) {
RE_engine_free(engine);
@@ -682,6 +718,7 @@ int RE_engine_render(Render *re, int do_all)
}
RE_parts_free(re);
+ BLI_rw_mutex_unlock(&re->partsmutex);
if (BKE_reports_contain(re->reports, RPT_ERROR))
G.is_break = true;
diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c
index a0fcc7cdcd2..970a3937657 100644
--- a/source/blender/render/intern/source/initrender.c
+++ b/source/blender/render/intern/source/initrender.c
@@ -426,10 +426,10 @@ void make_sample_tables(Render *re)
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
struct Object *RE_GetCamera(Render *re)
{
- return re->camera_override ? re->camera_override : re->scene->camera;
+ Object *camera = re->camera_override ? re->camera_override : re->scene->camera;
+ return BKE_camera_multiview_render(re->scene, camera, re->viewname);
}
static void re_camera_params_get(Render *re, CameraParams *params, Object *cam_ob)
@@ -470,6 +470,16 @@ void RE_SetEnvmapCamera(Render *re, Object *cam_ob, float viewscale, float clips
re_camera_params_get(re, &params, cam_ob);
}
+void RE_SetOverrideCamera(Render *re, Object *camera)
+{
+ re->camera_override = camera;
+}
+
+static void re_camera_params_stereo3d(Render *re, CameraParams *params, Object *cam_ob)
+{
+ BKE_camera_multiview_params(&re->r, params, cam_ob, re->viewname);
+}
+
/* call this after InitState() */
/* per render, there's one persistent viewplane. Parts will set their own viewplanes */
void RE_SetCamera(Render *re, Object *cam_ob)
@@ -479,6 +489,7 @@ void RE_SetCamera(Render *re, Object *cam_ob)
/* setup parameters */
BKE_camera_params_init(&params);
BKE_camera_params_from_object(&params, cam_ob);
+ re_camera_params_stereo3d(re, &params, cam_ob);
params.use_fields = (re->r.mode & R_FIELDS);
params.field_second = (re->flag & R_SEC_FIELD);
@@ -505,6 +516,11 @@ void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, flo
copy_m4_m4(mat, re->winmat);
}
+void RE_GetCameraModelMatrix(Render *re, struct Object *camera, float r_mat[4][4])
+{
+ BKE_camera_multiview_model_matrix(&re->r, camera, re->viewname, r_mat);
+}
+
/* ~~~~~~~~~~~~~~~~ part (tile) calculus ~~~~~~~~~~~~~~~~~~~~~~ */
diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c
index 6ba85ea5329..de57d4e7ba6 100644
--- a/source/blender/render/intern/source/multires_bake.c
+++ b/source/blender/render/intern/source/multires_bake.c
@@ -127,9 +127,13 @@ typedef struct {
static void multiresbake_get_normal(const MResolvePixelData *data, float norm[],const int face_num, const int vert_index)
{
- unsigned int indices[] = {data->mface[face_num].v1, data->mface[face_num].v2,
- data->mface[face_num].v3, data->mface[face_num].v4};
- const int smoothnormal = (data->mface[face_num].flag & ME_SMOOTH);
+ const unsigned int indices[] = {
+ data->mface[face_num].v1,
+ data->mface[face_num].v2,
+ data->mface[face_num].v3,
+ data->mface[face_num].v4,
+ };
+ const bool smoothnormal = (data->mface[face_num].flag & ME_SMOOTH) != 0;
if (!smoothnormal) { /* flat */
if (data->precomputed_normals) {
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index d06902d093b..eb831db2847 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -70,6 +70,7 @@
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_writeavi.h" /* <------ should be replaced once with generic movie module */
+#include "BKE_object.h"
#include "PIL_time.h"
#include "IMB_colormanagement.h"
@@ -83,6 +84,8 @@
# include "FRS_freestyle.h"
#endif
+#include "DEG_depsgraph.h"
+
/* internal */
#include "render_result.h"
#include "render_types.h"
@@ -131,7 +134,7 @@ Render R;
/* ********* alloc and free ******** */
-static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const char *name_override);
+static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const size_t totvideos, const char *name_override);
static volatile int g_break = 0;
static int thread_break(void *UNUSED(arg))
@@ -190,14 +193,10 @@ void RE_FreeRenderResult(RenderResult *res)
render_result_free(res);
}
-float *RE_RenderLayerGetPass(RenderLayer *rl, int passtype)
+float *RE_RenderLayerGetPass(volatile RenderLayer *rl, int passtype, const char *viewname)
{
- RenderPass *rpass;
-
- for (rpass = rl->passes.first; rpass; rpass = rpass->next)
- if (rpass->passtype == passtype)
- return rpass->rect;
- return NULL;
+ RenderPass *rpass = RE_pass_find_by_type(rl, passtype, viewname);
+ return rpass ? rpass->rect : NULL;
}
RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name)
@@ -307,8 +306,72 @@ Scene *RE_GetScene(Render *re)
return NULL;
}
+/**
+ * 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));
+
+ if (re) {
+ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_READ);
+
+ if (re->result) {
+ RenderLayer *rl;
+ RenderView *rv, *rview;
+
+ rr->rectx = re->result->rectx;
+ rr->recty = re->result->recty;
+
+ /* creates a temporary duplication of views */
+ render_result_views_shallowcopy(rr, re->result);
+
+ rv = rr->views.first;
+
+ rr->have_combined = (rv->rectf != NULL);
+
+ /* active layer */
+ rl = render_get_active_layer(re, re->result);
+
+ if (rl) {
+ if (rv->rectf == NULL) {
+ for (rview = (RenderView *)rr->views.first; rview; rview = rview->next) {
+ rview->rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, rview->name);
+ }
+ }
+
+ if (rv->rectz == NULL) {
+ for (rview = (RenderView *)rr->views.first; rview; rview = rview->next) {
+ rview->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z, rview->name);
+ }
+ }
+ }
+
+ rr->layers = re->result->layers;
+ rr->xof = re->disprect.xmin;
+ rr->yof = re->disprect.ymin;
+ rr->stamp_data = re->result->stamp_data;
+ }
+ }
+}
+
+/* clear temporary renderresult struct */
+void RE_ReleaseResultImageViews(Render *re, RenderResult *rr)
+{
+ if (re) {
+ if (rr) {
+ render_result_views_shallowdelete(rr);
+ }
+ BLI_rw_mutex_unlock(&re->resultmutex);
+ }
+}
+
/* fill provided result struct with what's currently active or done */
-void RE_AcquireResultImage(Render *re, RenderResult *rr)
+/* this RenderResult struct is the only exception to the rule of a RenderResult */
+/* always having at least one RenderView */
+void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id)
{
memset(rr, 0, sizeof(RenderResult));
@@ -317,27 +380,33 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr)
if (re->result) {
RenderLayer *rl;
+ RenderView *rv;
rr->rectx = re->result->rectx;
rr->recty = re->result->recty;
- rr->rectf = re->result->rectf;
- rr->rectz = re->result->rectz;
- rr->rect32 = re->result->rect32;
-
+ /* actview view */
+ rv = RE_RenderViewGetById(re->result, view_id);
+
+ rr->rectf = rv->rectf;
+ rr->rectz = rv->rectz;
+ rr->rect32 = rv->rect32;
+
/* active layer */
rl = render_get_active_layer(re, re->result);
if (rl) {
- if (rr->rectf == NULL)
- rr->rectf = rl->rectf;
- if (rr->rectz == NULL)
- rr->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z);
+ if (rv->rectf == NULL)
+ rr->rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, rv->name);
+
+ if (rv->rectz == NULL)
+ rr->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z, rv->name);
}
- rr->have_combined = (re->result->rectf != NULL);
+ rr->have_combined = (rv->rectf != NULL);
rr->layers = re->result->layers;
-
+ rr->views = re->result->views;
+
rr->xof = re->disprect.xmin;
rr->yof = re->disprect.ymin;
}
@@ -354,17 +423,18 @@ void RE_ReleaseResultImage(Render *re)
void RE_ResultGet32(Render *re, unsigned int *rect)
{
RenderResult rres;
-
- RE_AcquireResultImage(re, &rres);
- render_result_rect_get_pixels(&rres, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings);
- RE_ReleaseResultImage(re);
+ const size_t view_id = BKE_scene_multiview_view_id_get(&re->r, re->viewname);
+
+ RE_AcquireResultImageViews(re, &rres);
+ render_result_rect_get_pixels(&rres, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings, view_id);
+ RE_ReleaseResultImageViews(re, &rres);
}
/* caller is responsible for allocating rect in correct size! */
/* Only for acquired results, for lock */
-void RE_AcquiredResultGet32(Render *re, RenderResult *result, unsigned int *rect)
+void RE_AcquiredResultGet32(Render *re, RenderResult *result, unsigned int *rect, const int view_id)
{
- render_result_rect_get_pixels(result, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings);
+ render_result_rect_get_pixels(result, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings, view_id);
}
RenderStats *RE_GetStats(Render *re)
@@ -385,8 +455,8 @@ Render *RE_NewRender(const char *name)
BLI_addtail(&RenderGlobal.renderlist, re);
BLI_strncpy(re->name, name, RE_MAXNAME);
BLI_rw_mutex_init(&re->resultmutex);
- re->eval_ctx = MEM_callocN(sizeof(EvaluationContext), "re->eval_ctx");
- re->eval_ctx->mode = DAG_EVAL_RENDER;
+ BLI_rw_mutex_init(&re->partsmutex);
+ re->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_RENDER);
}
RE_InitRenderCB(re);
@@ -423,9 +493,11 @@ void RE_FreeRender(Render *re)
RE_engine_free(re->engine);
BLI_rw_mutex_end(&re->resultmutex);
+ BLI_rw_mutex_end(&re->partsmutex);
BLI_freelistN(&re->r.layers);
-
+ BLI_freelistN(&re->r.views);
+
/* main dbase can already be invalid now, some database-free code checks it */
re->main = NULL;
re->scene = NULL;
@@ -572,8 +644,10 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
/* copy render data and render layers for thread safety */
BLI_freelistN(&re->r.layers);
+ BLI_freelistN(&re->r.views);
re->r = *rd;
BLI_duplicatelist(&re->r.layers, &rd->layers);
+ BLI_duplicatelist(&re->r.views, &rd->views);
if (source) {
/* reuse border flags from source renderer */
@@ -664,6 +738,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
re->result = MEM_callocN(sizeof(RenderResult), "new render result");
re->result->rectx = re->rectx;
re->result->recty = re->recty;
+ render_result_view_new(re->result, "new temporary view");
}
if (re->r.scemode & R_VIEWPORT_PREVIEW)
@@ -681,18 +756,23 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
RE_init_threadcount(re);
}
+/* This function is only called by view3d rendering, which doesn't support
+ * multiview at the moment. so handle only one view here */
static void render_result_rescale(Render *re)
{
RenderResult *result = re->result;
+ RenderView *rv;
int x, y;
float scale_x, scale_y;
float *src_rectf;
- src_rectf = result->rectf;
+ rv = RE_RenderViewGetById(result, 0);
+ src_rectf = rv->rectf;
+
if (src_rectf == NULL) {
RenderLayer *rl = render_get_active_layer(re, re->result);
if (rl != NULL) {
- src_rectf = rl->rectf;
+ src_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, NULL);
}
}
@@ -702,15 +782,16 @@ static void render_result_rescale(Render *re)
&re->disprect,
0,
RR_USE_MEM,
- RR_ALL_LAYERS);
+ RR_ALL_LAYERS,
+ "");
if (re->result != NULL) {
- dst_rectf = re->result->rectf;
+ dst_rectf = RE_RenderViewGetById(re->result, 0)->rectf;
if (dst_rectf == NULL) {
RenderLayer *rl;
rl = render_get_active_layer(re, re->result);
if (rl != NULL) {
- dst_rectf = rl->rectf;
+ dst_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, NULL);
}
}
@@ -727,9 +808,8 @@ static void render_result_rescale(Render *re)
}
}
}
+ render_result_free(result);
}
-
- render_result_free(result);
}
void RE_ChangeResolution(Render *re, int winx, int winy, rcti *disprect)
@@ -776,6 +856,10 @@ void render_update_anim_renderdata(Render *re, RenderData *rd)
/* render layers */
BLI_freelistN(&re->r.layers);
BLI_duplicatelist(&re->r.layers, &rd->layers);
+
+ /* render views */
+ BLI_freelistN(&re->r.views);
+ BLI_duplicatelist(&re->r.views, &rd->views);
}
void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend)
@@ -908,9 +992,9 @@ static void *do_part_thread(void *pa_v)
if (R.test_break(R.tbh) == 0) {
if (!R.sss_points && (R.r.scemode & R_FULL_SAMPLE))
- pa->result = render_result_new_full_sample(&R, &pa->fullresult, &pa->disprect, pa->crop, RR_USE_MEM);
+ pa->result = render_result_new_full_sample(&R, &pa->fullresult, &pa->disprect, pa->crop, RR_USE_MEM, R.viewname);
else
- pa->result = render_result_new(&R, &pa->disprect, pa->crop, RR_USE_MEM, RR_ALL_LAYERS);
+ pa->result = render_result_new(&R, &pa->disprect, pa->crop, RR_USE_MEM, RR_ALL_LAYERS, R.viewname);
/* Copy EXR tile settings, so pipeline knows whether this is a result
* for Save Buffers enabled rendering.
@@ -933,7 +1017,7 @@ static void *do_part_thread(void *pa_v)
/* merge too on break! */
if (R.result->do_exr_tile) {
- render_result_exr_file_merge(R.result, pa->result);
+ render_result_exr_file_merge(R.result, pa->result, R.viewname);
}
else if (render_display_update_enabled(&R)) {
/* on break, don't merge in result for preview renders, looks nicer */
@@ -1029,13 +1113,28 @@ static bool find_next_pano_slice(Render *re, int *slice, int *minx, rctf *viewpl
return found;
}
-static RenderPart *find_next_part(Render *re, int minx)
+typedef struct SortRenderPart {
+ RenderPart *pa;
+ long long int dist;
+} SortRenderPart;
+
+static int sort_render_part(const void *pa1, const void *pa2) {
+ const SortRenderPart *rpa1 = pa1;
+ const SortRenderPart *rpa2 = pa2;
+
+ if (rpa1->dist > rpa2->dist) return 1;
+ else if (rpa1->dist < rpa2->dist) return -1;
+
+ return 0;
+}
+
+static int sort_and_queue_parts(Render *re, int minx, ThreadQueue *workqueue)
{
- RenderPart *pa, *best = NULL;
+ RenderPart *pa;
/* long long int's needed because of overflow [#24414] */
long long int centx = re->winx / 2, centy = re->winy / 2, tot = 1;
- long long int mindist = (long long int)re->winx * (long long int)re->winy;
+ int totsort = 0;
/* find center of rendered parts, image center counts for 1 too */
for (pa = re->parts.first; pa; pa = pa->next) {
@@ -1044,31 +1143,48 @@ static RenderPart *find_next_part(Render *re, int minx)
centy += BLI_rcti_cent_y(&pa->disprect);
tot++;
}
+ else if (pa->status == PART_STATUS_NONE && pa->nr == 0) {
+ if (!(re->r.mode & R_PANORAMA) || pa->disprect.xmin == minx) {
+ totsort++;
+ }
+ }
}
centx /= tot;
centy /= tot;
- /* closest of the non-rendering parts */
- for (pa = re->parts.first; pa; pa = pa->next) {
- if (pa->status == PART_STATUS_NONE && pa->nr == 0) {
- long long int distx = centx - BLI_rcti_cent_x(&pa->disprect);
- long long int disty = centy - BLI_rcti_cent_y(&pa->disprect);
- distx = (long long int)sqrt(distx * distx + disty * disty);
- if (distx < mindist) {
- if (re->r.mode & R_PANORAMA) {
- if (pa->disprect.xmin == minx) {
- best = pa;
- mindist = distx;
- }
- }
- else {
- best = pa;
- mindist = distx;
+ if (totsort > 0) {
+ SortRenderPart *sortlist = MEM_mallocN(sizeof(*sortlist) * totsort, "renderpartsort");
+ long int i = 0;
+
+ /* prepare the list */
+ for (pa = re->parts.first; pa; pa = pa->next) {
+ if (pa->status == PART_STATUS_NONE && pa->nr == 0) {
+ if (!(re->r.mode & R_PANORAMA) || pa->disprect.xmin == minx) {
+ long long int distx = centx - BLI_rcti_cent_x(&pa->disprect);
+ long long int disty = centy - BLI_rcti_cent_y(&pa->disprect);
+ sortlist[i].dist = (long long int)sqrt(distx * distx + disty * disty);
+ sortlist[i].pa = pa;
+ i++;
}
}
}
+
+ /* Now sort it */
+ qsort(sortlist, totsort, sizeof(*sortlist), sort_render_part);
+
+ /* Finally flush it to the workqueue */
+ for (i = 0; i < totsort; i++) {
+ pa = sortlist[i].pa;
+ pa->nr = i + 1; /* for nicest part, and for stats */
+ BLI_thread_queue_push(workqueue, pa);
+ }
+
+ MEM_freeN(sortlist);
+
+ return totsort;
}
- return best;
+
+ return 0;
}
static void print_part_stats(Render *re, RenderPart *pa)
@@ -1113,16 +1229,23 @@ static void *do_render_thread(void *thread_v)
return NULL;
}
-static void threaded_tile_processor(Render *re)
+static void main_render_result_end(Render *re)
+{
+ if (re->result->do_exr_tile) {
+ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+ render_result_exr_file_end(re);
+ BLI_rw_mutex_unlock(&re->resultmutex);
+ }
+
+ if (re->r.scemode & R_EXR_CACHE_FILE) {
+ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+ render_result_exr_file_cache_write(re);
+ BLI_rw_mutex_unlock(&re->resultmutex);
+ }
+}
+
+static void main_render_result_new(Render *re)
{
- RenderThread thread[BLENDER_MAX_THREADS];
- ThreadQueue *workqueue, *donequeue;
- ListBase threads;
- RenderPart *pa;
- rctf viewplane = re->viewplane;
- double lastdraw, elapsed, redrawtime = 1.0f;
- int totpart = 0, minx = 0, slice = 0, a, wait;
-
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
/* first step; free the entire render result, make new, and/or prepare exr buffer saving */
@@ -1130,25 +1253,35 @@ static void threaded_tile_processor(Render *re)
render_result_free(re->result);
if (re->sss_points && render_display_update_enabled(re))
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
+ re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
else if (re->r.scemode & R_FULL_SAMPLE)
- re->result = render_result_new_full_sample(re, &re->fullresult, &re->disprect, 0, RR_USE_EXR);
+ re->result = render_result_new_full_sample(re, &re->fullresult, &re->disprect, 0, RR_USE_EXR, RR_ALL_VIEWS);
else
re->result = render_result_new(re, &re->disprect, 0,
- (re->r.scemode & R_EXR_TILE_FILE) ? RR_USE_EXR : RR_USE_MEM, RR_ALL_LAYERS);
+ (re->r.scemode & R_EXR_TILE_FILE) ? RR_USE_EXR : RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
}
BLI_rw_mutex_unlock(&re->resultmutex);
+
+ if (re->result->do_exr_tile)
+ render_result_exr_file_begin(re);
+}
+
+static void threaded_tile_processor(Render *re)
+{
+ RenderThread thread[BLENDER_MAX_THREADS];
+ ThreadQueue *workqueue, *donequeue;
+ ListBase threads;
+ RenderPart *pa;
+ rctf viewplane = re->viewplane;
+ double lastdraw, elapsed, redrawtime = 1.0f;
+ int totpart = 0, minx = 0, slice = 0, a, wait;
if (re->result == NULL)
return;
/* warning; no return here without closing exr file */
-
RE_parts_init(re, true);
-
- if (re->result->do_exr_tile)
- render_result_exr_file_begin(re);
/* assuming no new data gets added to dbase... */
R = *re;
@@ -1163,11 +1296,7 @@ static void threaded_tile_processor(Render *re)
/* for panorama we loop over slices */
while (find_next_pano_slice(re, &slice, &minx, &viewplane)) {
/* gather parts into queue */
- while ((pa = find_next_part(re, minx))) {
- pa->nr = totpart + 1; /* for nicest part, and for stats */
- totpart++;
- BLI_thread_queue_push(workqueue, pa);
- }
+ totpart = sort_and_queue_parts(re, minx, workqueue);
BLI_thread_queue_nowait(workqueue);
@@ -1254,26 +1383,16 @@ static void threaded_tile_processor(Render *re)
BLI_thread_queue_free(donequeue);
BLI_thread_queue_free(workqueue);
- if (re->result->do_exr_tile) {
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- render_result_exr_file_end(re);
- BLI_rw_mutex_unlock(&re->resultmutex);
- }
-
- if (re->r.scemode & R_EXR_CACHE_FILE) {
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- render_result_exr_file_cache_write(re);
- BLI_rw_mutex_unlock(&re->resultmutex);
- }
-
/* unset threadsafety */
g_break = 0;
-
+ BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
RE_parts_free(re);
+ BLI_rw_mutex_unlock(&re->partsmutex);
re->viewplane = viewplane; /* restore viewplane, modified by pano render */
}
#ifdef WITH_FREESTYLE
+static void init_freestyle(Render *re);
static void add_freestyle(Render *re, int render);
static void free_all_freestyle_renders(void);
#endif
@@ -1281,6 +1400,7 @@ static void free_all_freestyle_renders(void);
/* currently only called by preview renders and envmap */
void RE_TileProcessor(Render *re)
{
+ main_render_result_new(re);
threaded_tile_processor(re);
re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime;
@@ -1290,8 +1410,8 @@ void RE_TileProcessor(Render *re)
/* Freestyle */
if (re->r.mode & R_EDGE_FRS) {
if (!re->test_break(re->tbh)) {
+ init_freestyle(re);
add_freestyle(re, 1);
-
free_all_freestyle_renders();
re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime;
@@ -1306,6 +1426,7 @@ void RE_TileProcessor(Render *re)
static void do_render_3d(Render *re)
{
+ RenderView *rv;
int cfra_backup;
re->current_scene_update(re->suh, re->scene);
@@ -1322,40 +1443,55 @@ static void do_render_3d(Render *re)
BKE_scene_frame_set(re->scene, (double)re->scene->r.cfra + (double)re->mblur_offs + (double)re->field_offs);
- /* lock drawing in UI during data phase */
- if (re->draw_lock)
- re->draw_lock(re->dlh, 1);
-
- /* make render verts/faces/halos/lamps */
- if (render_scene_needs_vector(re)) {
- RE_Database_FromScene_Vectors(re, re->main, re->scene, re->lay);
- }
- else {
- RE_Database_FromScene(re, re->main, re->scene, re->lay, 1);
- RE_Database_Preprocess(re);
+ /* init main render result */
+ main_render_result_new(re);
+
+#ifdef WITH_FREESTYLE
+ if (re->r.mode & R_EDGE_FRS) {
+ init_freestyle(re);
}
+#endif
+
+ /* we need a new database for each view */
+ for (rv = re->result->views.first; rv; rv = rv->next) {
+ RE_SetActiveRenderView(re, rv->name);
+
+ /* lock drawing in UI during data phase */
+ if (re->draw_lock)
+ re->draw_lock(re->dlh, 1);
+
+ /* make render verts/faces/halos/lamps */
+ if (render_scene_needs_vector(re))
+ RE_Database_FromScene_Vectors(re, re->main, re->scene, re->lay);
+ else {
+ RE_Database_FromScene(re, re->main, re->scene, re->lay, 1);
+ RE_Database_Preprocess(re);
+ }
- /* clear UI drawing locks */
- if (re->draw_lock)
- re->draw_lock(re->dlh, 0);
+ /* clear UI drawing locks */
+ if (re->draw_lock)
+ re->draw_lock(re->dlh, 0);
- threaded_tile_processor(re);
+ threaded_tile_processor(re);
#ifdef WITH_FREESTYLE
- /* Freestyle */
- if (re->r.mode & R_EDGE_FRS)
- if (!re->test_break(re->tbh))
- add_freestyle(re, 1);
+ /* Freestyle */
+ if (re->r.mode & R_EDGE_FRS)
+ if (!re->test_break(re->tbh))
+ add_freestyle(re, 1);
#endif
- /* do left-over 3d post effects (flares) */
- if (re->flag & R_HALO)
- if (!re->test_break(re->tbh))
- add_halo_flare(re);
-
- /* free all render verts etc */
- RE_Database_Free(re);
-
+ /* do left-over 3d post effects (flares) */
+ if (re->flag & R_HALO)
+ if (!re->test_break(re->tbh))
+ add_halo_flare(re);
+
+ /* free all render verts etc */
+ RE_Database_Free(re);
+ }
+
+ main_render_result_end(re);
+
re->scene->r.cfra = cfra_backup;
re->scene->r.subframe = 0.f;
}
@@ -1428,19 +1564,13 @@ static void merge_renderresult_blur(RenderResult *rr, RenderResult *brr, float b
rl1 = brr->layers.first;
for (rl = rr->layers.first; rl && rl1; rl = rl->next, rl1 = rl1->next) {
-
- /* combined */
- if (rl->rectf && rl1->rectf) {
- if (key_alpha)
- addblur_rect_key(rr, rl->rectf, rl1->rectf, blurfac);
- else
- addblur_rect(rr, rl->rectf, rl1->rectf, blurfac, 4);
- }
-
/* passes are allocated in sync */
rpass1 = rl1->passes.first;
for (rpass = rl->passes.first; rpass && rpass1; rpass = rpass->next, rpass1 = rpass1->next) {
- addblur_rect(rr, rpass->rect, rpass1->rect, blurfac, rpass->channels);
+ if ((rpass->passtype & SCE_PASS_COMBINED) && key_alpha)
+ addblur_rect_key(rr, rpass->rect, rpass1->rect, blurfac);
+ else
+ addblur_rect(rr, rpass->rect, rpass1->rect, blurfac, rpass->channels);
}
}
}
@@ -1453,7 +1583,7 @@ static void do_render_blur_3d(Render *re)
int blur = re->r.mblur_samples;
/* create accumulation render result */
- rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
+ rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
/* do the blur steps */
while (blur--) {
@@ -1515,10 +1645,6 @@ static void merge_renderresult_fields(RenderResult *rr, RenderResult *rr1, Rende
rl2 = rr2->layers.first;
for (rl = rr->layers.first; rl && rl1 && rl2; rl = rl->next, rl1 = rl1->next, rl2 = rl2->next) {
- /* combined */
- if (rl->rectf && rl1->rectf && rl2->rectf)
- interleave_rect(rr, rl->rectf, rl1->rectf, rl2->rectf, 4);
-
/* passes are allocated in sync */
rpass1 = rl1->passes.first;
rpass2 = rl2->passes.first;
@@ -1586,7 +1712,7 @@ static void do_render_fields_3d(Render *re)
re->disprect.ymax *= 2;
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
+ re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
if (rr2) {
if (re->r.mode & R_ODDFIELD)
@@ -1658,7 +1784,7 @@ static void do_render_fields_blur_3d(Render *re)
/* weak is: it chances disprect from border */
render_result_disprect_to_full_resolution(re);
- rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
+ rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
render_result_merge(rres, re->result);
render_result_free(re->result);
@@ -1953,7 +2079,7 @@ static void ntree_render_scenes(Render *re)
}
/* bad call... need to think over proper method still */
-static void render_composit_stats(void *UNUSED(arg), char *str)
+static void render_composit_stats(void *UNUSED(arg), const char *str)
{
R.i.infostr = str;
R.stats_draw(R.sdh, &R.i);
@@ -1961,6 +2087,23 @@ static void render_composit_stats(void *UNUSED(arg), char *str)
}
#ifdef WITH_FREESTYLE
+/* init Freestyle renderer */
+static void init_freestyle(Render *re)
+{
+ re->freestyle_bmain = BKE_main_new();
+
+ /* We use the same window manager for freestyle bmain as
+ * real bmain uses. This is needed because freestyle's
+ * bmain could be used to tag scenes for update, which
+ * implies call of ED_render_scene_update in some cases
+ * and that function requires proper window manager
+ * to present (sergey)
+ */
+ re->freestyle_bmain->wm = re->main->wm;
+
+ FRS_init_stroke_renderer(re);
+}
+
/* invokes Freestyle stroke rendering */
static void add_freestyle(Render *re, int render)
{
@@ -1971,18 +2114,7 @@ static void add_freestyle(Render *re, int render)
actsrl = BLI_findlink(&re->r.layers, re->r.actlay);
- re->freestyle_bmain = BKE_main_new();
-
- /* We use the same window manager for freestyle bmain as
- * real bmain uses. This is needed because freestyle's
- * bmain could be used to tag scenes for update, which
- * implies call of ED_render_scene_update in some cases
- * and that function requires proper window manager
- * to present (sergey)
- */
- re->freestyle_bmain->wm = re->main->wm;
-
- FRS_init_stroke_rendering(re);
+ FRS_begin_stroke_rendering(re);
for (srl = (SceneRenderLayer *)re->r.layers.first; srl; srl = srl->next) {
if (do_link) {
@@ -1998,7 +2130,7 @@ static void add_freestyle(Render *re, int render)
}
}
- FRS_finish_stroke_rendering(re);
+ FRS_end_stroke_rendering(re);
/* restore the global R value (invalidated by nested execution of the internal renderer) */
R = *re;
@@ -2008,28 +2140,32 @@ static void add_freestyle(Render *re, int render)
static void composite_freestyle_renders(Render *re, int sample)
{
Render *freestyle_render;
+ RenderView *rv;
SceneRenderLayer *srl, *actsrl;
LinkData *link;
actsrl = BLI_findlink(&re->r.layers, re->r.actlay);
link = (LinkData *)re->freestyle_renders.first;
- for (srl= (SceneRenderLayer *)re->r.layers.first; srl; srl= srl->next) {
- if ((re->r.scemode & R_SINGLE_LAYER) && srl != actsrl)
- continue;
- if (FRS_is_freestyle_enabled(srl)) {
- freestyle_render = (Render *)link->data;
+ for (rv = re->result->views.first; rv; rv = rv->next) {
+ for (srl = (SceneRenderLayer *)re->r.layers.first; srl; srl = srl->next) {
+ if ((re->r.scemode & R_SINGLE_LAYER) && srl != actsrl)
+ continue;
- /* may be NULL in case of empty render layer */
- if (freestyle_render) {
- render_result_exr_file_read_sample(freestyle_render, sample);
- FRS_composite_result(re, srl, freestyle_render);
- RE_FreeRenderResult(freestyle_render->result);
- freestyle_render->result = NULL;
+ if (FRS_is_freestyle_enabled(srl)) {
+ freestyle_render = (Render *)link->data;
+
+ /* may be NULL in case of empty render layer */
+ if (freestyle_render) {
+ render_result_exr_file_read_sample(freestyle_render, sample);
+ FRS_composite_result(re, srl, freestyle_render);
+ RE_FreeRenderResult(freestyle_render->result);
+ freestyle_render->result = NULL;
+ }
}
+ link = link->next;
}
- link = link->next;
}
}
@@ -2065,11 +2201,14 @@ static void free_all_freestyle_renders(void)
}
#endif
-/* reads all buffers, calls optional composite, merges in first result->rectf */
+/* reads all buffers, calls optional composite, merges in first result->views rectf */
static void do_merge_fullsample(Render *re, bNodeTree *ntree)
{
+ ListBase *rectfs;
+ RenderView *rv;
float *rectf, filt[3][3];
int x, y, sample;
+ int nr, numviews;
/* interaction callbacks */
if (ntree) {
@@ -2084,9 +2223,18 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
/* filtmask needs it */
R = *re;
- /* we accumulate in here */
- rectf = MEM_mapallocN(re->rectx * re->recty * sizeof(float) * 4, "fullsample rgba");
-
+ /* temporary storage of the acccumulation buffers */
+ rectfs = MEM_callocN(sizeof(ListBase), "fullsample accumulation buffers");
+
+ numviews = BLI_listbase_count(&re->result->views);
+ for (nr = 0; nr < numviews; nr++) {
+ rv = MEM_callocN(sizeof(RenderView), "fullsample renderview");
+
+ /* we accumulate in here */
+ rv->rectf = MEM_mapallocN(re->rectx * re->recty * sizeof(float) * 4, "fullsample rgba");
+ BLI_addtail(rectfs, rv);
+ }
+
for (sample = 0; sample < re->r.osa; sample++) {
Scene *sce;
Render *re1;
@@ -2123,54 +2271,70 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
if (ntree) {
ntreeCompositTagRender(re->scene);
ntreeCompositTagAnimated(ntree);
-
- ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings);
+
+ for (rv = re->result->views.first; rv; rv = rv->next) {
+ ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings, rv->name);
+ }
}
-
- /* ensure we get either composited result or the active layer */
- RE_AcquireResultImage(re, &rres);
-
- /* accumulate with filter, and clip */
- mask = (1 << sample);
- mask_array(mask, filt);
- for (y = 0; y < re->recty; y++) {
- float *rf = rectf + 4 * y * re->rectx;
- float *col = rres.rectf + 4 * y * re->rectx;
-
- for (x = 0; x < re->rectx; x++, rf += 4, col += 4) {
- /* clamping to 1.0 is needed for correct AA */
- if (col[0] < 0.0f) col[0] = 0.0f; else if (col[0] > 1.0f) col[0] = 1.0f;
- if (col[1] < 0.0f) col[1] = 0.0f; else if (col[1] > 1.0f) col[1] = 1.0f;
- if (col[2] < 0.0f) col[2] = 0.0f; else if (col[2] > 1.0f) col[2] = 1.0f;
+ for (nr = 0, rv = rectfs->first; rv; rv = rv->next, nr++) {
+ rectf = rv->rectf;
+
+ /* ensure we get either composited result or the active layer */
+ RE_AcquireResultImage(re, &rres, nr);
+
+ /* accumulate with filter, and clip */
+ mask = (1 << sample);
+ mask_array(mask, filt);
+
+ for (y = 0; y < re->recty; y++) {
+ float *rf = rectf + 4 * y * re->rectx;
+ float *col = rres.rectf + 4 * y * re->rectx;
- add_filt_fmask_coord(filt, col, rf, re->rectx, re->recty, x, y);
+ for (x = 0; x < re->rectx; x++, rf += 4, col += 4) {
+ /* clamping to 1.0 is needed for correct AA */
+ CLAMP(col[0], 0.0f, 1.0f);
+ CLAMP(col[1], 0.0f, 1.0f);
+ CLAMP(col[2], 0.0f, 1.0f);
+
+ add_filt_fmask_coord(filt, col, rf, re->rectx, re->recty, x, y);
+ }
}
- }
- RE_ReleaseResultImage(re);
+ RE_ReleaseResultImage(re);
- /* show stuff */
- if (sample != re->osa - 1) {
- /* weak... the display callback wants an active renderlayer pointer... */
- re->result->renlay = render_get_active_layer(re, re->result);
- re->display_update(re->duh, re->result, NULL);
+ /* show stuff */
+ if (sample != re->osa - 1) {
+ /* weak... the display callback wants an active renderlayer pointer... */
+ re->result->renlay = render_get_active_layer(re, re->result);
+ RE_SetActiveRenderView(re, rv->name);
+ re->display_update(re->duh, re->result, NULL);
+ }
}
-
- if (re->test_break(re->tbh))
- break;
}
- /* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */
- for (y = 0; y < re->recty; y++) {
- float *rf = rectf + 4 * y * re->rectx;
+ for (nr = 0; nr < numviews; nr++) {
+ rectf = ((RenderView *)BLI_findlink(rectfs, nr))->rectf;
+
+ /* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */
+ for (y = 0; y < re->recty; y++) {
+ float *rf = rectf + 4 * y * re->rectx;
- for (x = 0; x < re->rectx; x++, rf += 4) {
- rf[0] = MAX2(rf[0], 0.0f);
- rf[1] = MAX2(rf[1], 0.0f);
- rf[2] = MAX2(rf[2], 0.0f);
- CLAMP(rf[3], 0.0f, 1.0f);
+ for (x = 0; x < re->rectx; x++, rf += 4) {
+ rf[0] = MAX2(rf[0], 0.0f);
+ rf[1] = MAX2(rf[1], 0.0f);
+ rf[2] = MAX2(rf[2], 0.0f);
+ CLAMP(rf[3], 0.0f, 1.0f);
+ }
}
+
+ /* store the final result */
+ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+ rv = RE_RenderViewGetById(re->result, nr);
+ if (rv->rectf)
+ MEM_freeN(rv->rectf);
+ rv->rectf = rectf;
+ BLI_rw_mutex_unlock(&re->resultmutex);
}
/* clear interaction callbacks */
@@ -2183,12 +2347,14 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
/* disable full sample print */
R.i.curfsa = 0;
-
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- if (re->result->rectf)
- MEM_freeN(re->result->rectf);
- re->result->rectf = rectf;
- BLI_rw_mutex_unlock(&re->resultmutex);
+
+ /* garbage collection */
+ while (rectfs->first) {
+ RenderView *rv = rectfs->first;
+ BLI_remlink(rectfs, rv);
+ MEM_freeN(rv);
+ }
+ MEM_freeN(rectfs);
}
/* called externally, via compositor */
@@ -2241,8 +2407,10 @@ void RE_MergeFullSample(Render *re, Main *bmain, Scene *sce, bNodeTree *ntree)
re->display_clear(re->dch, re->result);
#ifdef WITH_FREESTYLE
- if (re->r.mode & R_EDGE_FRS)
+ if (re->r.mode & R_EDGE_FRS) {
+ init_freestyle(re);
add_freestyle(re, 0);
+ }
#endif
do_merge_fullsample(re, ntree);
@@ -2264,7 +2432,11 @@ static void do_render_composite_fields_blur_3d(Render *re)
if (composite_needs_render(re->scene, 1)) {
/* save memory... free all cached images */
ntreeFreeCache(ntree);
-
+
+ /* render the frames
+ * it could be optimized to render only the needed view
+ * but what if a scene has a different number of views
+ * than the main scene? */
do_render_fields_blur_3d(re);
}
else {
@@ -2277,7 +2449,7 @@ static void do_render_composite_fields_blur_3d(Render *re)
if ((re->r.mode & R_CROP) == 0) {
render_result_disprect_to_full_resolution(re);
}
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
+ re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
BLI_rw_mutex_unlock(&re->resultmutex);
@@ -2322,7 +2494,10 @@ static void do_render_composite_fields_blur_3d(Render *re)
if (re->r.scemode & R_FULL_SAMPLE)
do_merge_fullsample(re, ntree);
else {
- ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings);
+ RenderView *rv;
+ for (rv = re->result->views.first; rv; rv = rv->next) {
+ ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings, rv->name);
+ }
}
ntree->stats_draw = NULL;
@@ -2347,13 +2522,17 @@ static void do_render_composite_fields_blur_3d(Render *re)
static void renderresult_stampinfo(Render *re)
{
RenderResult rres;
+ RenderView *rv;
+ int nr;
/* this is the basic trick to get the displayed float or char rect from render result */
- RE_AcquireResultImage(re, &rres);
- BKE_image_stamp_buf(
- re->scene, RE_GetCamera(re),
- (unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty, 4);
- RE_ReleaseResultImage(re);
+ nr = 0;
+ for (rv = re->result->views.first;rv;rv = rv->next, nr++) {
+ RE_SetActiveRenderView(re, rv->name);
+ RE_AcquireResultImage(re, &rres, nr);
+ BKE_image_stamp_buf(re->scene, RE_GetCamera(re), (unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty, 4);
+ RE_ReleaseResultImage(re);
+ }
}
int RE_seq_render_active(Scene *scene, RenderData *rd)
@@ -2377,10 +2556,12 @@ int RE_seq_render_active(Scene *scene, RenderData *rd)
static void do_render_seq(Render *re)
{
static int recurs_depth = 0;
- struct ImBuf *ibuf, *out;
+ struct ImBuf *out;
RenderResult *rr; /* don't assign re->result here as it might change during give_ibuf_seq */
int cfra = re->r.cfra;
SeqRenderData context;
+ size_t view_id, tot_views;
+ struct ImBuf **ibuf_arr;
int re_x, re_y;
re->i.cfra = cfra;
@@ -2403,45 +2584,67 @@ static void do_render_seq(Render *re)
re_y = re->result->recty;
}
+ tot_views = BKE_scene_multiview_num_views_get(&re->r);
+ ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * tot_views, "Sequencer Views ImBufs");
+
BKE_sequencer_new_render_data(
re->eval_ctx, re->main, re->scene,
re_x, re_y, 100,
&context);
- out = BKE_sequencer_give_ibuf(&context, cfra, 0);
+ /* the renderresult gets destroyed during the rendering, so we first collect all ibufs
+ * and then we populate the final renderesult */
- if (out) {
- ibuf = IMB_dupImBuf(out);
- IMB_freeImBuf(out);
- BKE_sequencer_imbuf_from_sequencer_space(re->scene, ibuf);
- }
- else {
- ibuf = NULL;
- }
+ for (view_id = 0; view_id < tot_views; view_id++) {
+ context.view_id = view_id;
+ out = BKE_sequencer_give_ibuf(&context, cfra, 0);
- recurs_depth--;
+ if (out) {
+ ibuf_arr[view_id] = IMB_dupImBuf(out);
+ IMB_freeImBuf(out);
+ BKE_sequencer_imbuf_from_sequencer_space(re->scene, ibuf_arr[view_id]);
+ }
+ else {
+ ibuf_arr[view_id] = NULL;
+ }
+ }
rr = re->result;
-
+
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+ render_result_views_new(rr, &re->r);
+ BLI_rw_mutex_unlock(&re->resultmutex);
- if (ibuf) {
- /* copy ibuf into combined pixel rect */
- render_result_rect_from_ibuf(rr, &re->r, ibuf);
-
- if (recurs_depth == 0) { /* with nested scenes, only free on toplevel... */
- Editing *ed = re->scene->ed;
- if (ed)
- BKE_sequencer_free_imbuf(re->scene, &ed->seqbase, true);
+ for (view_id = 0; view_id < tot_views; view_id++) {
+ RenderView *rv = RE_RenderViewGetById(rr, view_id);
+ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+
+ if (ibuf_arr[view_id]) {
+ /* copy ibuf into combined pixel rect */
+ render_result_rect_from_ibuf(rr, &re->r, ibuf_arr[view_id], view_id);
+
+ if (recurs_depth == 0) { /* with nested scenes, only free on toplevel... */
+ Editing *ed = re->scene->ed;
+ if (ed)
+ BKE_sequencer_free_imbuf(re->scene, &ed->seqbase, true);
+ }
+ IMB_freeImBuf(ibuf_arr[view_id]);
}
- IMB_freeImBuf(ibuf);
- }
- else {
- /* render result is delivered empty in most cases, nevertheless we handle all cases */
- render_result_rect_fill_zero(rr);
+ else {
+ /* render result is delivered empty in most cases, nevertheless we handle all cases */
+ render_result_rect_fill_zero(rr, view_id);
+ }
+
+ BLI_rw_mutex_unlock(&re->resultmutex);
+
+ /* would mark display buffers as invalid */
+ RE_SetActiveRenderView(re, rv->name);
+ re->display_update(re->duh, re->result, NULL);
}
- BLI_rw_mutex_unlock(&re->resultmutex);
+ MEM_freeN(ibuf_arr);
+
+ recurs_depth--;
/* just in case this flag went missing at some point */
re->r.scemode |= R_DOSEQ;
@@ -2451,9 +2654,6 @@ static void do_render_seq(Render *re)
re->progress(re->prh, (float)(cfra - re->r.sfra) / (re->r.efra - re->r.sfra));
else
re->progress(re->prh, 1.0f);
-
- /* would mark display buffers as invalid */
- re->display_update(re->duh, re->result, NULL);
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
@@ -2461,6 +2661,8 @@ static void do_render_seq(Render *re)
/* main loop: doing sequence + fields + blur + 3d render + compositing */
static void do_render_all_options(Render *re)
{
+ Object *camera;
+
re->current_scene_update(re->suh, re->scene);
BKE_scene_camera_switch_update(re->scene);
@@ -2494,6 +2696,10 @@ static void do_render_all_options(Render *re)
re->stats_draw(re->sdh, &re->i);
+ /* save render result stamp if needed */
+ camera = RE_GetCamera(re);
+ BKE_render_result_stamp_info(re->scene, camera, re->result);
+
/* stamp image info here */
if ((re->r.stamp & R_STAMP_ALL) && (re->r.stamp & R_STAMP_DRAW)) {
renderresult_stampinfo(re);
@@ -2540,6 +2746,42 @@ static bool check_valid_compositing_camera(Scene *scene, Object *camera_override
}
}
+static bool check_valid_camera_multiview(Scene *scene, Object *camera, ReportList *reports)
+{
+ SceneRenderView *srv;
+ bool active_view = false;
+
+ if ((scene->r.scemode & R_MULTIVIEW) == 0)
+ return true;
+
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
+ active_view = true;
+
+ if (scene->r.views_format == SCE_VIEWS_FORMAT_MULTIVIEW) {
+ Object *view_camera;
+ view_camera = BKE_camera_multiview_render(scene, camera, srv->name);
+
+ if (view_camera == camera) {
+ /* if the suffix is not in the camera, means we are using the fallback camera */
+ if (!BLI_str_endswith(view_camera->id.name + 2, srv->suffix)) {
+ BKE_reportf(reports, RPT_ERROR, "Camera \"%s\" is not a multi-view camera",
+ camera->id.name + 2);
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ if (!active_view) {
+ BKE_reportf(reports, RPT_ERROR, "No active view found in scene \"%s\"", scene->id.name + 2);
+ return false;
+ }
+
+ return true;
+}
+
static int check_valid_camera(Scene *scene, Object *camera_override, ReportList *reports)
{
const char *err_msg = "No camera found in scene \"%s\"";
@@ -2547,6 +2789,9 @@ static int check_valid_camera(Scene *scene, Object *camera_override, ReportList
if (camera_override == NULL && scene->camera == NULL)
scene->camera = BKE_scene_camera_find(scene);
+ if (!check_valid_camera_multiview(scene, scene->camera, reports))
+ return false;
+
if (RE_seq_render_active(scene, &scene->r)) {
if (scene->ed) {
Sequence *seq = scene->ed->seqbase.first;
@@ -2567,6 +2812,8 @@ static int check_valid_camera(Scene *scene, Object *camera_override, ReportList
}
}
}
+ else if (!check_valid_camera_multiview(seq->scene, seq->scene_camera, reports))
+ return false;
}
seq = seq->next;
@@ -2731,6 +2978,17 @@ static void update_physics_cache(Render *re, Scene *scene, int UNUSED(anim_init)
BKE_ptcache_bake(&baker);
}
+
+void RE_SetActiveRenderView(Render *re, const char *viewname)
+{
+ BLI_strncpy(re->viewname, viewname, sizeof(re->viewname));
+}
+
+const char *RE_GetActiveRenderView(Render *re)
+{
+ return re->viewname;
+}
+
/* evaluating scene options for general Blender render */
static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain, Scene *scene, SceneRenderLayer *srl,
Object *camera_override, unsigned int lay_override, int anim, int anim_init)
@@ -2766,7 +3024,8 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain,
re->lay = lay_override ? lay_override : scene->lay;
re->layer_override = lay_override;
re->i.localview = (re->lay & 0xFF000000) != 0;
-
+ re->viewname[0] = '\0';
+
/* not too nice, but it survives anim-border render */
if (anim) {
render_update_anim_renderdata(re, &scene->r);
@@ -2840,10 +3099,10 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr
char name[FILE_MAX];
BKE_image_path_from_imformat(
name, scene->r.pic, bmain->name, scene->r.cfra,
- &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false);
+ &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false, NULL);
/* reports only used for Movie */
- do_write_image_or_movie(re, bmain, scene, NULL, name);
+ do_write_image_or_movie(re, bmain, scene, NULL, 0, name);
}
}
@@ -2875,102 +3134,274 @@ void RE_RenderFreestyleExternal(Render *re)
if (!re->test_break(re->tbh)) {
RE_Database_FromScene(re, re->main, re->scene, re->lay, 1);
RE_Database_Preprocess(re);
+ init_freestyle(re);
add_freestyle(re, 1);
RE_Database_Free(re);
}
}
#endif
-static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const char *name_override)
+bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scene, const bool stamp, char *name)
{
- char name[FILE_MAX];
- RenderResult rres;
- Object *camera = RE_GetCamera(re);
- double render_time;
- int ok = 1;
-
- RE_AcquireResultImage(re, &rres);
+ bool is_mono;
+ bool ok = true;
+ RenderData *rd = &scene->r;
- /* write movie or image */
- if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
- bool do_free = false;
- ImBuf *ibuf = render_result_rect_to_ibuf(&rres, &scene->r);
+ if (!rr)
+ return false;
- /* note; the way it gets 32 bits rects is weak... */
- if (ibuf->rect == NULL) {
- ibuf->rect = MEM_mapallocN(sizeof(int) * rres.rectx * rres.recty, "temp 32 bits rect");
- ibuf->mall |= IB_rect;
- RE_AcquiredResultGet32(re, &rres, ibuf->rect);
- do_free = true;
- }
+ is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2;
+ if (ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) &&
+ rd->im_format.views_format == R_IMF_VIEWS_MULTIVIEW)
+ {
+ RE_WriteRenderResult(reports, rr, name, &rd->im_format, true, NULL);
+ printf("Saved: %s\n", name);
+ }
- IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings,
- &scene->display_settings, &scene->r.im_format);
+ /* mono, legacy code */
+ else if (is_mono || (rd->im_format.views_format == R_IMF_VIEWS_INDIVIDUAL))
+ {
+ RenderView *rv;
+ size_t view_id;
+ char filepath[FILE_MAX];
- ok = mh->append_movie(&re->r, scene->r.sfra, scene->r.cfra, (int *) ibuf->rect,
- ibuf->x, ibuf->y, re->reports);
- if (do_free) {
- MEM_freeN(ibuf->rect);
- ibuf->rect = NULL;
- ibuf->mall &= ~IB_rect;
- }
+ BLI_strncpy(filepath, name, sizeof(filepath));
- /* imbuf knows which rects are not part of ibuf */
- IMB_freeImBuf(ibuf);
+ for (view_id = 0, rv = rr->views.first; rv; rv = rv->next, view_id++) {
+ if (!is_mono) {
+ BKE_scene_multiview_view_filepath_get(&scene->r, filepath, rv->name, name);
+ }
- printf("Append frame %d", scene->r.cfra);
- }
- else {
- if (name_override)
- BLI_strncpy(name, name_override, sizeof(name));
- else
- BKE_image_path_from_imformat(
- name, scene->r.pic, bmain->name, scene->r.cfra,
- &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true);
-
- if (re->r.im_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
- if (re->result) {
- RE_WriteRenderResult(re->reports, re->result, name, scene->r.im_format.exr_codec);
- printf("Saved: %s", name);
+ if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
+ RE_WriteRenderResult(reports, rr, name, &rd->im_format, false, rv->name);
+ printf("Saved: %s\n", name);
+ }
+ else {
+ ImBuf *ibuf = render_result_rect_to_ibuf(rr, rd, view_id);
+
+ IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings,
+ &scene->display_settings, &rd->im_format);
+
+ if (stamp) {
+ /* writes the name of the individual cameras */
+ ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, &rd->im_format);
+ }
+ else {
+ ok = BKE_imbuf_write(ibuf, name, &rd->im_format);
+ }
+
+ if (ok == false) {
+ printf("Render error: cannot save %s\n", name);
+ }
+ else printf("Saved: %s\n", name);
+
+ /* optional preview images for exr */
+ if (ok && rd->im_format.imtype == R_IMF_IMTYPE_OPENEXR && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
+ ImageFormatData imf = rd->im_format;
+ imf.imtype = R_IMF_IMTYPE_JPEG90;
+
+ if (BLI_testextensie(name, ".exr"))
+ name[strlen(name) - 4] = 0;
+ BKE_image_path_ensure_ext_from_imformat(name, &imf);
+ ibuf->planes = 24;
+
+ IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings,
+ &scene->display_settings, &imf);
+
+ if (stamp) {
+ /* writes the name of the individual cameras */
+ ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, &imf);
+ }
+ else {
+ ok = BKE_imbuf_write(ibuf, name, &imf);
+ }
+ printf("Saved: %s\n", name);
+ }
+
+ /* imbuf knows which rects are not part of ibuf */
+ IMB_freeImBuf(ibuf);
}
}
+ }
+ else { /* R_IMF_VIEWS_STEREO_3D */
+ BLI_assert(scene->r.im_format.views_format == R_IMF_VIEWS_STEREO_3D);
+
+ if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
+ printf("Stereo 3D not support for MultiLayer image: %s\n", name);
+ }
else {
- ImBuf *ibuf = render_result_rect_to_ibuf(&rres, &scene->r);
+ ImBuf *ibuf_arr[3] = {NULL};
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
+ ibuf_arr[i] = render_result_rect_to_ibuf(rr, rd, view_id);
+ IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &scene->view_settings,
+ &scene->display_settings, &scene->r.im_format);
+ IMB_prepare_write_ImBuf(IMB_isfloat(ibuf_arr[i]), ibuf_arr[i]);
+ }
- IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings,
- &scene->display_settings, &scene->r.im_format);
+ ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]);
- ok = BKE_imbuf_write_stamp(scene, camera, ibuf, name, &scene->r.im_format);
-
- if (ok == 0) {
+ if (stamp)
+ ok = BKE_imbuf_write_stamp(scene, rr, ibuf_arr[2], name, &rd->im_format);
+ else
+ ok = BKE_imbuf_write(ibuf_arr[2], name, &rd->im_format);
+
+ if (ok == false)
printf("Render error: cannot save %s\n", name);
- }
- else printf("Saved: %s", name);
-
+ else
+ printf("Saved: %s\n", name);
+
/* optional preview images for exr */
- if (ok && scene->r.im_format.imtype == R_IMF_IMTYPE_OPENEXR && (scene->r.im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
- ImageFormatData imf = scene->r.im_format;
+ if (ok && rd->im_format.imtype == R_IMF_IMTYPE_OPENEXR &&
+ (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG))
+ {
+ ImageFormatData imf = rd->im_format;
imf.imtype = R_IMF_IMTYPE_JPEG90;
if (BLI_testextensie(name, ".exr"))
name[strlen(name) - 4] = 0;
+
BKE_image_path_ensure_ext_from_imformat(name, &imf);
- ibuf->planes = 24;
+ ibuf_arr[2]->planes = 24;
- IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings,
+ IMB_colormanagement_imbuf_for_write(ibuf_arr[2], true, false, &scene->view_settings,
&scene->display_settings, &imf);
- BKE_imbuf_write_stamp(scene, camera, ibuf, name, &imf);
- printf("\nSaved: %s", name);
+ if (stamp)
+ ok = BKE_imbuf_write_stamp(scene, rr, ibuf_arr[2], name, &rd->im_format);
+ else
+ ok = BKE_imbuf_write(ibuf_arr[2], name, &imf);
+
+ printf("Saved: %s\n", name);
}
-
+
+ /* imbuf knows which rects are not part of ibuf */
+ for (i = 0; i < 3; i++) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+ }
+
+ return ok;
+}
+
+bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scene, RenderData *rd, bMovieHandle *mh,
+ const size_t width, const size_t height, void **movie_ctx_arr, const size_t totvideos, bool preview)
+{
+ bool is_mono;
+ bool ok = true;
+
+ if (!rr)
+ return false;
+
+ is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2;
+
+ if (is_mono || (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ size_t view_id;
+ for (view_id = 0; view_id < totvideos; view_id++) {
+ bool do_free = false;
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
+ ImBuf *ibuf = render_result_rect_to_ibuf(rr, &scene->r, view_id);
+
+ /* note; the way it gets 32 bits rects is weak... */
+ if (ibuf->rect == NULL) {
+ ibuf->rect = MEM_mapallocN(sizeof(int) * rr->rectx * rr->recty, "temp 32 bits rect");
+ ibuf->mall |= IB_rect;
+ render_result_rect_get_pixels(rr, ibuf->rect, width, height, &scene->view_settings, &scene->display_settings, view_id);
+ do_free = true;
+ }
+
+ IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings,
+ &scene->display_settings, &scene->r.im_format);
+
+ ok &= mh->append_movie(movie_ctx_arr[view_id], rd, preview ? scene->r.psfra : scene->r.sfra, scene->r.cfra,
+ (int *) ibuf->rect, ibuf->x, ibuf->y, suffix, reports);
+
+ if (do_free) {
+ MEM_freeN(ibuf->rect);
+ ibuf->rect = NULL;
+ ibuf->mall &= ~IB_rect;
+ }
+
/* imbuf knows which rects are not part of ibuf */
IMB_freeImBuf(ibuf);
}
+ printf("Append frame %d\n", scene->r.cfra);
+ }
+ else { /* R_IMF_VIEWS_STEREO_3D */
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ ImBuf *ibuf_arr[3] = {NULL};
+ bool do_free[2] = {false, false};
+ size_t i;
+
+ BLI_assert((totvideos == 1) && (scene->r.im_format.views_format == R_IMF_VIEWS_STEREO_3D));
+
+ for (i = 0; i < 2; i++) {
+ int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
+ ibuf_arr[i] = render_result_rect_to_ibuf(rr, &scene->r, view_id);
+
+ /* note; the way it gets 32 bits rects is weak... */
+ if (ibuf_arr[i]->rect == NULL) {
+ ibuf_arr[i]->rect = MEM_mapallocN(sizeof(int) * width * height, "temp 32 bits rect");
+ ibuf_arr[i]->mall |= IB_rect;
+ render_result_rect_get_pixels(rr, ibuf_arr[i]->rect, width, height, &scene->view_settings, &scene->display_settings, view_id);
+ do_free[i] = true;
+ }
+
+ IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &scene->view_settings,
+ &scene->display_settings, &scene->r.im_format);
+ }
+
+ ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]);
+
+ ok = mh->append_movie(movie_ctx_arr[0], rd, preview ? scene->r.psfra : scene->r.sfra, scene->r.cfra, (int *) ibuf_arr[2]->rect,
+ ibuf_arr[2]->x, ibuf_arr[2]->y, "", reports);
+
+ for (i = 0; i < 2; i++) {
+ if (do_free[i]) {
+ MEM_freeN(ibuf_arr[i]->rect);
+ ibuf_arr[i]->rect = NULL;
+ ibuf_arr[i]->mall &= ~IB_rect;
+ }
+
+ /* imbuf knows which rects are not part of ibuf */
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+
+ return ok;
+}
+
+static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const size_t totvideos, const char *name_override)
+{
+ char name[FILE_MAX];
+ RenderResult rres;
+ double render_time;
+ bool ok = true;
+
+ RE_AcquireResultImageViews(re, &rres);
+
+ /* write movie or image */
+ if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
+ RE_WriteRenderViewsMovie(re->reports, &rres, scene, &re->r, mh, re->rectx, re->recty, re->movie_ctx_arr, totvideos, false);
+ }
+ else {
+ if (name_override)
+ BLI_strncpy(name, name_override, sizeof(name));
+ else
+ BKE_image_path_from_imformat(
+ name, scene->r.pic, bmain->name, scene->r.cfra,
+ &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL);
+
+ /* write images as individual images or stereo */
+ ok = RE_WriteRenderViewsImage(re->reports, &rres, scene, true, name);
}
- RE_ReleaseResultImage(re);
+ RE_ReleaseResultImageViews(re, &rres);
render_time = re->i.lastframetime;
re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime;
@@ -2989,20 +3420,51 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie
return ok;
}
+static void get_videos_dimensions(Render *re, RenderData *rd, size_t *r_width, size_t *r_height)
+{
+ size_t width, height;
+ if (re->r.mode & R_BORDER) {
+ if ((re->r.mode & R_CROP) == 0) {
+ width = re->winx;
+ height = re->winy;
+ }
+ else {
+ width = re->rectx;
+ height = re->recty;
+ }
+ }
+ else {
+ width = re->rectx;
+ height = re->recty;
+ }
+
+ BKE_scene_multiview_videos_dimensions_get(rd, width, height, r_width, r_height);
+}
+
/* saves images to disk */
void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_override,
unsigned int lay_override, int sfra, int efra, int tfra)
{
RenderData rd = scene->r;
- bMovieHandle *mh = BKE_movie_handle_get(scene->r.im_format.imtype);
+ bMovieHandle *mh = NULL;
int cfrao = scene->r.cfra;
int nfra, totrendered = 0, totskipped = 0;
-
+ const size_t totvideos = BKE_scene_multiview_num_videos_get(&rd);
+ const bool is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
+ const bool is_multiview_name = ((scene->r.scemode & R_MULTIVIEW) != 0 &&
+ (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL));
+
BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_INIT);
/* do not fully call for each frame, it initializes & pops output window */
if (!render_initialize_from_main(re, &rd, bmain, scene, NULL, camera_override, lay_override, 0, 1))
return;
+
+ /* we don't support Frame Server and streaming of individual views */
+ if ((rd.im_format.imtype == R_IMF_IMTYPE_FRAMESERVER) && (totvideos > 1)) {
+ BKE_report(re->reports, RPT_ERROR, "Frame Server only support stereo output for multiview rendering");
+ return;
+ }
/* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */
/* is also set by caller renderwin.c */
@@ -3010,30 +3472,33 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
re->flag |= R_ANIMATION;
- if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
- int width, height;
- if (re->r.mode & R_BORDER) {
- if ((re->r.mode & R_CROP) == 0) {
- width = re->winx;
- height = re->winy;
- }
- else {
- width = re->rectx;
- height = re->recty;
- }
- }
- else {
- width = re->rectx;
- height = re->recty;
- }
+ if (is_movie) {
+ size_t i, width, height;
+
+ get_videos_dimensions(re, &rd, &width, &height);
+
+ mh = BKE_movie_handle_get(scene->r.im_format.imtype);
+ re->movie_ctx_arr = MEM_mallocN(sizeof(void *) * totvideos, "Movies' Context");
+
+ for (i = 0; i < totvideos; i++) {
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&re->r, i);
- if (!mh->start_movie(scene, &re->r, width, height, re->reports))
- G.is_break = true;
+ re->movie_ctx_arr[i] = mh->context_create();
+
+ if (!mh->start_movie(re->movie_ctx_arr[i], scene, &re->r, width, height, re->reports, false, suffix))
+ G.is_break = true;
+ }
}
- if (mh->get_next_frame) {
+ if (mh && mh->get_next_frame) {
+ /* MULTIVIEW_TODO:
+ * in case a new video format is added that implements get_next_frame multiview has to be addressed
+ * or the error throwing for R_IMF_IMTYPE_FRAMESERVER has to be extended for those cases as well
+ */
+ BLI_assert(totvideos < 2);
+
while (!(G.is_break == 1)) {
- int nf = mh->get_next_frame(&re->r, re->reports);
+ int nf = mh->get_next_frame(re->movie_ctx_arr[0], &re->r, re->reports);
if (nf >= 0 && nf >= scene->r.sfra && nf <= scene->r.efra) {
scene->r.cfra = re->r.cfra = nf;
@@ -3043,7 +3508,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
totrendered++;
if (re->test_break(re->tbh) == 0) {
- if (!do_write_image_or_movie(re, bmain, scene, mh, NULL))
+ if (!do_write_image_or_movie(re, bmain, scene, mh, totvideos, NULL))
G.is_break = true;
}
@@ -3086,20 +3551,67 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
nfra += tfra;
/* Touch/NoOverwrite options are only valid for image's */
- if (BKE_imtype_is_movie(scene->r.im_format.imtype) == 0) {
+ if (is_movie == false) {
if (scene->r.mode & (R_NO_OVERWRITE | R_TOUCH))
BKE_image_path_from_imformat(
name, scene->r.pic, bmain->name, scene->r.cfra,
- &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true);
+ &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL);
+
+ if (scene->r.mode & R_NO_OVERWRITE) {
+ if (!is_multiview_name) {
+ if (BLI_exists(name)) {
+ printf("skipping existing frame \"%s\"\n", name);
+ totskipped++;
+ continue;
+ }
+ }
+ else {
+ SceneRenderView *srv;
+ bool is_skip = false;
+ char filepath[FILE_MAX];
+
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv))
+ continue;
- if (scene->r.mode & R_NO_OVERWRITE && BLI_exists(name)) {
- printf("skipping existing frame \"%s\"\n", name);
- totskipped++;
- continue;
+ BKE_scene_multiview_filepath_get(srv, name, filepath);
+
+ if (BLI_exists(filepath)) {
+ is_skip = true;
+ printf("skipping existing frame \"%s\" for view \"%s\"\n", filepath, srv->name);
+ }
+ }
+
+ if (is_skip) {
+ totskipped++;
+ continue;
+ }
+ }
}
- if (scene->r.mode & R_TOUCH && !BLI_exists(name)) {
- BLI_make_existing_file(name); /* makes the dir if its not there */
- BLI_file_touch(name);
+
+ if (scene->r.mode & R_TOUCH) {
+ if (!is_multiview_name) {
+ if (!BLI_exists(name)) {
+ BLI_make_existing_file(name); /* makes the dir if its not there */
+ BLI_file_touch(name);
+ }
+ }
+ else {
+ SceneRenderView *srv;
+ char filepath[FILE_MAX];
+
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv))
+ continue;
+
+ BKE_scene_multiview_filepath_get(srv, name, filepath);
+
+ if (!BLI_exists(filepath)) {
+ BLI_make_existing_file(filepath); /* makes the dir if its not there */
+ BLI_file_touch(filepath);
+ }
+ }
+ }
}
}
@@ -3114,7 +3626,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
if (re->test_break(re->tbh) == 0) {
if (!G.is_break)
- if (!do_write_image_or_movie(re, bmain, scene, mh, NULL))
+ if (!do_write_image_or_movie(re, bmain, scene, mh, totvideos, NULL))
G.is_break = true;
}
else
@@ -3122,10 +3634,30 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
if (G.is_break == true) {
/* remove touched file */
- if (BKE_imtype_is_movie(scene->r.im_format.imtype) == 0) {
- if ((scene->r.mode & R_TOUCH) && (BLI_file_size(name) == 0)) {
- /* BLI_exists(name) is implicit */
- BLI_delete(name, false, false);
+ if (is_movie == false) {
+ if ((scene->r.mode & R_TOUCH)) {
+ if (!is_multiview_name) {
+ if ((BLI_file_size(name) == 0)) {
+ /* BLI_exists(name) is implicit */
+ BLI_delete(name, false, false);
+ }
+ }
+ else {
+ SceneRenderView *srv;
+ char filepath[FILE_MAX];
+
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv))
+ continue;
+
+ BKE_scene_multiview_filepath_get(srv, name, filepath);
+
+ if ((BLI_file_size(filepath) == 0)) {
+ /* BLI_exists(filepath) is implicit */
+ BLI_delete(filepath, false, false);
+ }
+ }
+ }
}
}
@@ -3140,8 +3672,17 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
}
/* end movie */
- if (BKE_imtype_is_movie(scene->r.im_format.imtype))
- mh->end_movie();
+ if (is_movie) {
+ size_t i;
+ for (i = 0; i < totvideos; i++) {
+ mh->end_movie(re->movie_ctx_arr[i]);
+ mh->context_free(re->movie_ctx_arr[i]);
+ }
+
+ if (re->movie_ctx_arr) {
+ MEM_freeN(re->movie_ctx_arr);
+ }
+ }
if (totskipped && totrendered == 0)
BKE_report(re->reports, RPT_INFO, "No frames rendered, skipped to not overwrite");
@@ -3239,13 +3780,22 @@ void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char
{
/* OCIO_TODO: assume layer was saved in defaule color space */
ImBuf *ibuf = IMB_loadiffname(filename, IB_rect, NULL);
+ RenderPass *rpass = NULL;
+
+ /* multiview: since the API takes no 'view', we use the first combined pass found */
+ for (rpass = layer->passes.first; rpass; rpass = rpass->next)
+ if (rpass->passtype == SCE_PASS_COMBINED)
+ break;
+
+ if (rpass == NULL)
+ BKE_reportf(reports, RPT_ERROR, "%s: no Combined pass found in the render layer '%s'", __func__, filename);
if (ibuf && (ibuf->rect || ibuf->rect_float)) {
if (ibuf->x == layer->rectx && ibuf->y == layer->recty) {
if (ibuf->rect_float == NULL)
IMB_float_from_rect(ibuf);
- memcpy(layer->rectf, ibuf->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty);
+ memcpy(rpass->rect, ibuf->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty);
}
else {
if ((ibuf->x - x >= layer->rectx) && (ibuf->y - y >= layer->recty)) {
@@ -3258,29 +3808,29 @@ void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char
if (ibuf_clip) {
IMB_rectcpy(ibuf_clip, ibuf, 0, 0, x, y, layer->rectx, layer->recty);
- memcpy(layer->rectf, ibuf_clip->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty);
+ memcpy(rpass->rect, ibuf_clip->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty);
IMB_freeImBuf(ibuf_clip);
}
else {
- BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to allocate clip buffer '%s'", filename);
+ BKE_reportf(reports, RPT_ERROR, "%s: failed to allocate clip buffer '%s'", __func__, filename);
}
}
else {
- BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: incorrect dimensions for partial copy '%s'", filename);
+ BKE_reportf(reports, RPT_ERROR, "%s: incorrect dimensions for partial copy '%s'", __func__, filename);
}
}
IMB_freeImBuf(ibuf);
}
else {
- BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to load '%s'", filename);
+ BKE_reportf(reports, RPT_ERROR, "%s: failed to load '%s'", __func__, filename);
}
}
void RE_result_load_from_file(RenderResult *result, ReportList *reports, const char *filename)
{
if (!render_result_exr_file_read_path(result, NULL, filename)) {
- BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to load '%s'", filename);
+ BKE_reportf(reports, RPT_ERROR, "%s: failed to load '%s'", __func__, filename);
return;
}
}
@@ -3346,3 +3896,35 @@ bool RE_WriteEnvmapResult(struct ReportList *reports, Scene *scene, EnvMap *env,
}
}
+/* used in the interface to decide whether to show layers */
+bool RE_layers_have_name(struct RenderResult *rr)
+{
+ switch (BLI_listbase_count_ex(&rr->layers, 2)) {
+ case 0:
+ return false;
+ break;
+ case 1:
+ return (((RenderLayer *)rr->layers.first)->name[0] != '\0');
+ break;
+ default:
+ return true;
+ break;
+ }
+ return false;
+}
+
+RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const char *viewname)
+{
+ RenderPass *rp = NULL;
+
+ for (rp = rl->passes.last; rp; rp = rp->prev) {
+ if (rp->passtype == passtype) {
+
+ if (viewname == NULL || viewname[0] == '\0')
+ break;
+ else if (STREQ(rp->view, viewname))
+ break;
+ }
+ }
+ return rp;
+}
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index 1f4726809de..5cd8a739125 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -1,4 +1,4 @@
-/*
+/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -45,6 +45,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_lattice.h"
#include "BKE_main.h"
+#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
@@ -58,6 +59,8 @@
#include "texture.h"
#include "pointdensity.h"
+#include "RE_render_ext.h"
+
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
/* only to be used here in this file, it's for speed */
@@ -68,25 +71,38 @@ extern struct Render R;
static int point_data_used(PointDensity *pd)
{
int pd_bitflag = 0;
-
+
if (pd->source == TEX_PD_PSYS) {
- if ((pd->noise_influence == TEX_PD_NOISE_VEL) || (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) || (pd->color_source == TEX_PD_COLOR_PARTVEL) || (pd->color_source == TEX_PD_COLOR_PARTSPEED))
+ if ((pd->noise_influence == TEX_PD_NOISE_VEL) ||
+ (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) ||
+ (pd->color_source == TEX_PD_COLOR_PARTVEL) ||
+ (pd->color_source == TEX_PD_COLOR_PARTSPEED))
+ {
pd_bitflag |= POINT_DATA_VEL;
- if ((pd->noise_influence == TEX_PD_NOISE_AGE) || (pd->color_source == TEX_PD_COLOR_PARTAGE) || (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE))
+ }
+ if ((pd->noise_influence == TEX_PD_NOISE_AGE) ||
+ (pd->color_source == TEX_PD_COLOR_PARTAGE) ||
+ (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE))
+ {
pd_bitflag |= POINT_DATA_LIFE;
+ }
+ if ((pd->color_source == TEX_PD_COLOR_PARTTEX))
+ {
+ pd_bitflag |= POINT_DATA_COLOR;
+ }
}
-
+
return pd_bitflag;
}
-/* additional data stored alongside the point density BVH,
- * accessible by point index number to retrieve other information
+/* additional data stored alongside the point density BVH,
+ * accessible by point index number to retrieve other information
* such as particle velocity or lifetime */
static void alloc_point_data(PointDensity *pd, int total_particles, int point_data_used)
{
int data_size = 0;
-
+
if (point_data_used & POINT_DATA_VEL) {
/* store 3 channels of velocity data */
data_size += 3;
@@ -95,61 +111,86 @@ static void alloc_point_data(PointDensity *pd, int total_particles, int point_da
/* store 1 channel of lifetime data */
data_size += 1;
}
+ if (point_data_used & POINT_DATA_COLOR) {
+ /* store 3 channels of color data */
+ data_size += 3;
+ }
- if (data_size)
- pd->point_data = MEM_mallocN(sizeof(float)*data_size*total_particles, "particle point data");
+ if (data_size) {
+ pd->point_data = MEM_mallocN(sizeof(float) * data_size * total_particles,
+ "particle point data");
+ }
}
-static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, ParticleSystem *psys)
+/* offset of age and color data in the common point data array */
+static void point_data_get_offset(int total_particles, int point_data_used, int *offset_life, int *offset_color)
{
- DerivedMesh* dm;
+ *offset_life = *offset_color = 0;
+ if (point_data_used & POINT_DATA_VEL) {
+ *offset_life += total_particles * 3;
+ *offset_color += total_particles * 3;
+ }
+ if (point_data_used & POINT_DATA_LIFE) {
+ *offset_color += total_particles;
+ }
+}
+
+static void pointdensity_cache_psys(Scene *scene,
+ PointDensity *pd,
+ Object *ob,
+ ParticleSystem *psys,
+ float viewmat[4][4],
+ float winmat[4][4],
+ int winx, int winy)
+{
+ DerivedMesh *dm;
ParticleKey state;
ParticleCacheKey *cache;
- ParticleSimulationData sim= {NULL};
- ParticleData *pa=NULL;
- float cfra = BKE_scene_frame_get(re->scene);
+ ParticleSimulationData sim = {NULL};
+ ParticleData *pa = NULL;
+ float cfra = BKE_scene_frame_get(scene);
int i /*, childexists*/ /* UNUSED */;
- int total_particles, offset=0;
+ int total_particles, offset_life = 0, offset_color = 0;
int data_used = point_data_used(pd);
float partco[3];
- float obview[4][4];
-
+
/* init everything */
- if (!psys || !ob || !pd) return;
+ if (!psys || !ob || !pd) {
+ return;
+ }
- mul_m4_m4m4(obview, ob->obmat, re->viewinv);
-
/* Just to create a valid rendering context for particles */
- psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, 0);
-
- dm = mesh_create_derived_render(re->scene, ob, CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
-
+ psys_render_set(ob, psys, viewmat, winmat, winx, winy, 0);
+
+ dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
+
if ( !psys_check_enabled(ob, psys)) {
psys_render_restore(ob, psys);
return;
}
-
- sim.scene= re->scene;
- sim.ob= ob;
- sim.psys= psys;
+
+ sim.scene = scene;
+ sim.ob = ob;
+ sim.psys = psys;
+ sim.psmd = psys_get_modifier(ob, psys);
/* in case ob->imat isn't up-to-date */
invert_m4_m4(ob->imat, ob->obmat);
-
- total_particles = psys->totpart+psys->totchild;
+
+ total_particles = psys->totpart + psys->totchild;
psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
-
+
pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6);
alloc_point_data(pd, total_particles, data_used);
pd->totpoints = total_particles;
- if (data_used & POINT_DATA_VEL) offset = pd->totpoints*3;
-
+ point_data_get_offset(total_particles, data_used, &offset_life, &offset_color);
+
#if 0 /* UNUSED */
if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT))
childexists = 1;
#endif
- for (i=0, pa=psys->particles; i < total_particles; i++, pa++) {
+ for (i = 0, pa = psys->particles; i < total_particles; i++, pa++) {
if (psys->part->type == PART_HAIR) {
/* hair particles */
@@ -175,19 +216,19 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa
if (data_used & POINT_DATA_LIFE) {
if (i < psys->totpart) {
- state.time = (cfra - pa->time)/pa->lifetime;
+ state.time = (cfra - pa->time) / pa->lifetime;
}
else {
- ChildParticle *cpa= (psys->child + i) - psys->totpart;
+ ChildParticle *cpa = (psys->child + i) - psys->totpart;
float pa_birthtime, pa_dietime;
-
+
state.time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime);
}
}
}
copy_v3_v3(partco, state.co);
-
+
if (pd->psys_cache_space == TEX_PD_OBJECTSPACE)
mul_m4_v3(ob->imat, partco);
else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) {
@@ -196,48 +237,55 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa
else {
/* TEX_PD_WORLDSPACE */
}
-
+
BLI_bvhtree_insert(pd->point_tree, i, partco, 1);
-
+
if (data_used & POINT_DATA_VEL) {
- pd->point_data[i*3 + 0] = state.vel[0];
- pd->point_data[i*3 + 1] = state.vel[1];
- pd->point_data[i*3 + 2] = state.vel[2];
+ pd->point_data[i * 3 + 0] = state.vel[0];
+ pd->point_data[i * 3 + 1] = state.vel[1];
+ pd->point_data[i * 3 + 2] = state.vel[2];
}
if (data_used & POINT_DATA_LIFE) {
- pd->point_data[offset + i] = state.time;
+ pd->point_data[offset_life + i] = state.time;
+ }
+ if (data_used & POINT_DATA_COLOR) {
+ ParticleTexture ptex;
+ psys_get_texture(&sim, pa, &ptex, PAMAP_COLOR, cfra);
+ copy_v3_v3(&pd->point_data[offset_color + i * 3], ptex.color);
}
}
-
+
BLI_bvhtree_balance(pd->point_tree);
dm->release(dm);
-
+
if (psys->lattice_deform_data) {
end_latt_deform(psys->lattice_deform_data);
psys->lattice_deform_data = NULL;
}
-
+
psys_render_restore(ob, psys);
}
-static void pointdensity_cache_object(Render *re, PointDensity *pd, Object *ob)
+static void pointdensity_cache_object(Scene *scene, PointDensity *pd, Object *ob)
{
int i;
DerivedMesh *dm;
MVert *mvert = NULL;
-
- dm = mesh_create_derived_render(re->scene, ob, CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
- mvert= dm->getVertArray(dm); /* local object space */
-
- pd->totpoints= dm->getNumVerts(dm);
- if (pd->totpoints == 0) return;
+
+ dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
+ mvert = dm->getVertArray(dm); /* local object space */
+
+ pd->totpoints = dm->getNumVerts(dm);
+ if (pd->totpoints == 0) {
+ return;
+ }
pd->point_tree = BLI_bvhtree_new(pd->totpoints, 0.0, 4, 6);
-
- for (i=0; i < pd->totpoints; i++, mvert++) {
+
+ for (i = 0; i < pd->totpoints; i++, mvert++) {
float co[3];
-
+
copy_v3_v3(co, mvert->co);
switch (pd->ob_cache_space) {
@@ -255,47 +303,60 @@ static void pointdensity_cache_object(Render *re, PointDensity *pd, Object *ob)
BLI_bvhtree_insert(pd->point_tree, i, co, 1);
}
-
+
BLI_bvhtree_balance(pd->point_tree);
dm->release(dm);
}
-void cache_pointdensity(Render *re, Tex *tex)
+
+static void cache_pointdensity_ex(Scene *scene,
+ PointDensity *pd,
+ float viewmat[4][4],
+ float winmat[4][4],
+ int winx, int winy)
{
- PointDensity *pd = tex->pd;
-
- if (!pd)
+ if (pd == NULL) {
return;
+ }
if (pd->point_tree) {
BLI_bvhtree_free(pd->point_tree);
pd->point_tree = NULL;
}
-
+
if (pd->source == TEX_PD_PSYS) {
Object *ob = pd->object;
ParticleSystem *psys;
- if (!ob || !pd->psys) return;
+ if (!ob || !pd->psys) {
+ return;
+ }
+
+ psys = BLI_findlink(&ob->particlesystem, pd->psys - 1);
+ if (!psys) {
+ return;
+ }
- psys= BLI_findlink(&ob->particlesystem, pd->psys-1);
- if (!psys) return;
-
- pointdensity_cache_psys(re, pd, ob, psys);
+ pointdensity_cache_psys(scene, pd, ob, psys, viewmat, winmat, winx, winy);
}
else if (pd->source == TEX_PD_OBJECT) {
Object *ob = pd->object;
if (ob && ob->type == OB_MESH)
- pointdensity_cache_object(re, pd, ob);
+ pointdensity_cache_object(scene, pd, ob);
}
}
-static void free_pointdensity(Render *UNUSED(re), Tex *tex)
+void cache_pointdensity(Render *re, PointDensity *pd)
{
- PointDensity *pd = tex->pd;
+ cache_pointdensity_ex(re->scene, pd, re->viewmat, re->winmat, re->winx, re->winy);
+}
+
+void free_pointdensity(PointDensity *pd)
+{
+ if (pd == NULL) {
+ return;
+ }
- if (!pd) return;
-
if (pd->point_tree) {
BLI_bvhtree_free(pd->point_tree);
pd->point_tree = NULL;
@@ -308,24 +369,23 @@ static void free_pointdensity(Render *UNUSED(re), Tex *tex)
pd->totpoints = 0;
}
-
-
void make_pointdensities(Render *re)
{
Tex *tex;
-
- if (re->scene->r.scemode & R_BUTS_PREVIEW)
+
+ if (re->scene->r.scemode & R_BUTS_PREVIEW) {
return;
-
+ }
+
re->i.infostr = IFACE_("Caching Point Densities");
re->stats_draw(re->sdh, &re->i);
- for (tex= re->main->tex.first; tex; tex= tex->id.next) {
- if (tex->id.us && tex->type==TEX_POINTDENSITY) {
- cache_pointdensity(re, tex);
+ for (tex = re->main->tex.first; tex != NULL; tex = tex->id.next) {
+ if (tex->id.us && tex->type == TEX_POINTDENSITY) {
+ cache_pointdensity(re, tex->pd);
}
}
-
+
re->i.infostr = NULL;
re->stats_draw(re->sdh, &re->i);
}
@@ -333,13 +393,13 @@ void make_pointdensities(Render *re)
void free_pointdensities(Render *re)
{
Tex *tex;
-
+
if (re->scene->r.scemode & R_BUTS_PREVIEW)
return;
-
- for (tex= re->main->tex.first; tex; tex= tex->id.next) {
- if (tex->id.us && tex->type==TEX_POINTDENSITY) {
- free_pointdensity(re, tex);
+
+ for (tex = re->main->tex.first; tex != NULL; tex = tex->id.next) {
+ if (tex->id.us && tex->type == TEX_POINTDENSITY) {
+ free_pointdensity(tex->pd);
}
}
}
@@ -353,8 +413,9 @@ typedef struct PointDensityRangeData {
short falloff_type;
short noise_influence;
float *age;
+ float *col;
int point_data_used;
- int offset;
+ int offset_life, offset_color;
struct CurveMapping *density_curve;
float velscale;
} PointDensityRangeData;
@@ -364,20 +425,23 @@ static void accum_density(void *userdata, int index, float squared_dist)
PointDensityRangeData *pdr = (PointDensityRangeData *)userdata;
const float dist = (pdr->squared_radius - squared_dist) / pdr->squared_radius * 0.5f;
float density = 0.0f;
-
+
if (pdr->point_data_used & POINT_DATA_VEL) {
- pdr->vec[0] += pdr->point_data[index*3 + 0]; // * density;
- pdr->vec[1] += pdr->point_data[index*3 + 1]; // * density;
- pdr->vec[2] += pdr->point_data[index*3 + 2]; // * density;
+ pdr->vec[0] += pdr->point_data[index * 3 + 0]; // * density;
+ pdr->vec[1] += pdr->point_data[index * 3 + 1]; // * density;
+ pdr->vec[2] += pdr->point_data[index * 3 + 2]; // * density;
}
if (pdr->point_data_used & POINT_DATA_LIFE) {
- *pdr->age += pdr->point_data[pdr->offset + index]; // * density;
+ *pdr->age += pdr->point_data[pdr->offset_life + index]; // * density;
}
-
+ if (pdr->point_data_used & POINT_DATA_COLOR) {
+ add_v3_v3(pdr->col, &pdr->point_data[pdr->offset_color + index]); // * density;
+ }
+
if (pdr->falloff_type == TEX_PD_FALLOFF_STD)
density = dist;
else if (pdr->falloff_type == TEX_PD_FALLOFF_SMOOTH)
- density = 3.0f*dist*dist - 2.0f*dist*dist*dist;
+ density = 3.0f * dist * dist - 2.0f * dist * dist * dist;
else if (pdr->falloff_type == TEX_PD_FALLOFF_SOFT)
density = pow(dist, pdr->softness);
else if (pdr->falloff_type == TEX_PD_FALLOFF_CONSTANT)
@@ -386,95 +450,102 @@ static void accum_density(void *userdata, int index, float squared_dist)
density = sqrtf(dist);
else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE) {
if (pdr->point_data_used & POINT_DATA_LIFE)
- density = dist*MIN2(pdr->point_data[pdr->offset + index], 1.0f);
+ density = dist * MIN2(pdr->point_data[pdr->offset_life + index], 1.0f);
else
density = dist;
}
else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) {
if (pdr->point_data_used & POINT_DATA_VEL)
- density = dist*len_v3(pdr->point_data + index*3)*pdr->velscale;
+ density = dist * len_v3(pdr->point_data + index * 3) * pdr->velscale;
else
density = dist;
}
-
+
if (pdr->density_curve && dist != 0.0f) {
curvemapping_initialize(pdr->density_curve);
- density = curvemapping_evaluateF(pdr->density_curve, 0, density/dist)*dist;
+ density = curvemapping_evaluateF(pdr->density_curve, 0, density / dist) * dist;
}
-
+
*pdr->density += density;
}
-static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData *pdr,
- float *density, float *vec, float *age, struct CurveMapping *density_curve, float velscale)
+static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData *pdr,
+ float *density, float *vec, float *age, float *col, struct CurveMapping *density_curve, float velscale)
{
- pdr->squared_radius = pd->radius*pd->radius;
+ pdr->squared_radius = pd->radius * pd->radius;
pdr->density = density;
pdr->point_data = pd->point_data;
pdr->falloff_type = pd->falloff_type;
pdr->vec = vec;
pdr->age = age;
+ pdr->col = col;
pdr->softness = pd->falloff_softness;
pdr->noise_influence = pd->noise_influence;
pdr->point_data_used = point_data_used(pd);
- pdr->offset = (pdr->point_data_used & POINT_DATA_VEL)?pd->totpoints*3:0;
+ point_data_get_offset(pd->totpoints, pdr->point_data_used, &pdr->offset_life, &pdr->offset_color);
pdr->density_curve = density_curve;
pdr->velscale = velscale;
}
-int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres)
+static int pointdensity(PointDensity *pd,
+ const float texvec[3],
+ TexResult *texres,
+ float *r_age,
+ float r_vec[3])
{
int retval = TEX_INT;
- PointDensity *pd = tex->pd;
PointDensityRangeData pdr;
- float density=0.0f, age=0.0f, time=0.0f;
- float vec[3] = {0.0f, 0.0f, 0.0f}, co[3];
- float col[4];
+ float density = 0.0f, age = 0.0f, time = 0.0f;
+ float vec[3] = {0.0f, 0.0f, 0.0f}, color[3] = {0.0f, 0.0f, 0.0f}, co[3];
float turb, noise_fac;
- int num=0;
-
+ int num = 0;
+
texres->tin = 0.0f;
-
+
if ((!pd) || (!pd->point_tree))
return 0;
-
- init_pointdensityrangedata(pd, &pdr, &density, vec, &age,
- (pd->flag&TEX_PD_FALLOFF_CURVE ? pd->falloff_curve : NULL), pd->falloff_speed_scale*0.001f);
+
+ init_pointdensityrangedata(pd, &pdr, &density, vec, &age, color,
+ (pd->flag & TEX_PD_FALLOFF_CURVE ? pd->falloff_curve : NULL),
+ pd->falloff_speed_scale * 0.001f);
noise_fac = pd->noise_fac * 0.5f; /* better default */
-
+
copy_v3_v3(co, texvec);
-
+
if (point_data_used(pd)) {
/* does a BVH lookup to find accumulated density and additional point data *
* stores particle velocity vector in 'vec', and particle lifetime in 'time' */
num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr);
if (num > 0) {
age /= num;
- mul_v3_fl(vec, 1.0f/num);
+ mul_v3_fl(vec, 1.0f / num);
}
-
+
/* reset */
density = vec[0] = vec[1] = vec[2] = 0.0f;
}
-
+
if (pd->flag & TEX_PD_TURBULENCE) {
-
+
if (pd->noise_influence == TEX_PD_NOISE_AGE) {
- turb = BLI_gTurbulence(pd->noise_size, texvec[0]+age, texvec[1]+age, texvec[2]+age, pd->noise_depth, 0, pd->noise_basis);
+ turb = BLI_gTurbulence(pd->noise_size, texvec[0] + age, texvec[1] + age, texvec[2] + age,
+ pd->noise_depth, 0, pd->noise_basis);
}
else if (pd->noise_influence == TEX_PD_NOISE_TIME) {
time = R.r.cfra / (float)R.r.efra;
- turb = BLI_gTurbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth, 0, pd->noise_basis);
+ turb = BLI_gTurbulence(pd->noise_size, texvec[0] + time, texvec[1] + time, texvec[2] + time,
+ pd->noise_depth, 0, pd->noise_basis);
//turb = BLI_turbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth);
}
else {
- turb = BLI_gTurbulence(pd->noise_size, texvec[0]+vec[0], texvec[1]+vec[1], texvec[2]+vec[2], pd->noise_depth, 0, pd->noise_basis);
+ turb = BLI_gTurbulence(pd->noise_size, texvec[0] + vec[0], texvec[1] + vec[1], texvec[2] + vec[2],
+ pd->noise_depth, 0, pd->noise_basis);
}
turb -= 0.5f; /* re-center 0.0-1.0 range around 0 to prevent offsetting result */
-
+
/* now we have an offset coordinate to use for the density lookup */
co[0] = texvec[0] + noise_fac * turb;
co[1] = texvec[1] + noise_fac * turb;
@@ -485,17 +556,30 @@ int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres)
num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr);
if (num > 0) {
age /= num;
- mul_v3_fl(vec, 1.0f/num);
+ mul_v3_fl(vec, 1.0f / num);
}
-
+
texres->tin = density;
- BRICONT;
-
- if (pd->color_source == TEX_PD_COLOR_CONSTANT)
- return retval;
+ texres->tr = color[0];
+ texres->tg = color[1];
+ texres->tb = color[2];
+ if (r_age != NULL) {
+ *r_age = age;
+ }
+ if (r_vec != NULL) {
+ copy_v3_v3(r_vec, vec);
+ }
+
+ return retval;
+}
+
+static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, const float vec[3])
+{
+ int retval = 0;
+ float col[4];
retval |= TEX_RGB;
-
+
switch (pd->color_source) {
case TEX_PD_COLOR_PARTAGE:
if (pd->coba) {
@@ -510,7 +594,7 @@ int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres)
case TEX_PD_COLOR_PARTSPEED:
{
float speed = len_v3(vec) * pd->speed_scale;
-
+
if (pd->coba) {
if (do_colorband(pd->coba, speed, col)) {
texres->talpha = true;
@@ -523,8 +607,12 @@ int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres)
}
case TEX_PD_COLOR_PARTVEL:
texres->talpha = true;
- mul_v3_fl(vec, pd->speed_scale);
- copy_v3_v3(&texres->tr, vec);
+ mul_v3_v3fl(&texres->tr, vec, pd->speed_scale);
+ texres->ta = texres->tin;
+ break;
+ case TEX_PD_COLOR_PARTTEX:
+ /* texres already has the particle color */
+ texres->talpha = true;
texres->ta = texres->tin;
break;
case TEX_PD_COLOR_CONSTANT:
@@ -532,13 +620,128 @@ int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres)
texres->tr = texres->tg = texres->tb = texres->ta = 1.0f;
break;
}
- BRICONTRGB;
return retval;
-
+}
+
+int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres)
+{
+ PointDensity *pd = tex->pd;
+ float age = 0.0f;
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+ int retval = pointdensity(pd, texvec, texres, &age, vec);
+
+ BRICONT;
+
+ retval |= pointdensity_color(pd, texres, age, vec);
+ BRICONTRGB;
+
+ return retval;
+
#if 0
if (texres->nor!=NULL) {
texres->nor[0] = texres->nor[1] = texres->nor[2] = 0.0f;
}
#endif
}
+
+static void sample_dummy_point_density(int resolution, float *values)
+{
+ memset(values, 0, sizeof(float) * 4 * resolution * resolution * resolution);
+}
+
+static void particle_system_minmax(Object *object,
+ ParticleSystem *psys,
+ float radius,
+ float min[3], float max[3])
+{
+ ParticleSettings *part = psys->part;
+ float imat[4][4];
+ float size[3] = {radius, radius, radius};
+ PARTICLE_P;
+ INIT_MINMAX(min, max);
+ if (part->type == PART_HAIR) {
+ /* TOOD(sergey): Not supported currently. */
+ return;
+ }
+ invert_m4_m4(imat, object->obmat);
+ LOOP_PARTICLES {
+ float co_object[3], co_min[3], co_max[3];
+ mul_v3_m4v3(co_object, imat, pa->state.co);
+ sub_v3_v3v3(co_min, co_object, size);
+ add_v3_v3v3(co_max, co_object, size);
+ minmax_v3v3_v3(min, max, co_min);
+ minmax_v3v3_v3(min, max, co_max);
+ }
+}
+
+void RE_sample_point_density(Scene *scene, PointDensity *pd,
+ int resolution, float *values)
+{
+ const size_t resolution2 = resolution * resolution;
+ Object *object = pd->object;
+ size_t x, y, z;
+ float min[3], max[3], dim[3], mat[4][4];
+
+ if (object == NULL) {
+ sample_dummy_point_density(resolution, values);
+ return;
+ }
+
+ if (pd->source == TEX_PD_PSYS) {
+ ParticleSystem *psys;
+ if (pd->psys == 0) {
+ sample_dummy_point_density(resolution, values);
+ return;
+ }
+ psys = BLI_findlink(&object->particlesystem, pd->psys - 1);
+ if (psys == NULL) {
+ sample_dummy_point_density(resolution, values);
+ return;
+ }
+ particle_system_minmax(object, psys, pd->radius, min, max);
+ }
+ else {
+ float radius[3] = {pd->radius, pd->radius, pd->radius};
+ float *loc, *size;
+ BKE_object_obdata_texspace_get(pd->object, NULL, &loc, &size, NULL);
+ sub_v3_v3v3(min, loc, size);
+ add_v3_v3v3(max, loc, size);
+ /* Adjust texture space to include density points on the boundaries. */
+ sub_v3_v3(min, radius);
+ add_v3_v3(max, radius);
+ }
+
+ sub_v3_v3v3(dim, max, min);
+ if (dim[0] <= 0.0f || dim[1] <= 0.0f || dim[2] <= 0.0f) {
+ sample_dummy_point_density(resolution, values);
+ return;
+ }
+
+ /* Same matricies/resolution as dupli_render_particle_set(). */
+ unit_m4(mat);
+ cache_pointdensity_ex(scene, pd, mat, mat, 1, 1);
+
+ for (z = 0; z < resolution; ++z) {
+ for (y = 0; y < resolution; ++y) {
+ for (x = 0; x < resolution; ++x) {
+ size_t index = z * resolution2 + y * resolution + x;
+ float texvec[3];
+ float age, vec[3];
+ TexResult texres;
+
+ copy_v3_v3(texvec, min);
+ texvec[0] += dim[0] * (float)x / (float)resolution;
+ texvec[1] += dim[1] * (float)y / (float)resolution;
+ texvec[2] += dim[2] * (float)z / (float)resolution;
+
+ pointdensity(pd, texvec, &texres, &age, vec);
+ pointdensity_color(pd, &texres, age, vec);
+
+ copy_v3_v3(&values[index*4 + 0], &texres.tr);
+ values[index*4 + 3] = texres.tin;
+ }
+ }
+ }
+ free_pointdensity(pd);
+}
diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c
index 065cdeab61c..2b1d5b8c1e5 100644
--- a/source/blender/render/intern/source/rayshade.c
+++ b/source/blender/render/intern/source/rayshade.c
@@ -306,22 +306,23 @@ static void makeraytree_single(Render *re)
RayObject *raytree;
RayFace *face = NULL;
VlakPrimitive *vlakprimitive = NULL;
- int faces = 0, obs = 0, special = 0;
+ int faces = 0, special = 0;
- for (obi=re->instancetable.first; obi; obi=obi->next)
- if (is_raytraceable(re, obi)) {
- ObjectRen *obr = obi->obr;
- obs++;
-
- if (has_special_rayobject(re, obi)) {
- special++;
- }
- else {
- int v;
- for (v=0;v<obr->totvlak;v++) {
- VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
- if (is_raytraceable_vlr(re, vlr))
- faces++;
+ for (obi = re->instancetable.first; obi; obi = obi->next) {
+ if (is_raytraceable(re, obi)) {
+ ObjectRen *obr = obi->obr;
+
+ if (has_special_rayobject(re, obi)) {
+ special++;
+ }
+ else {
+ int v;
+ for (v = 0;v < obr->totvlak; v++) {
+ VlakRen *vlr = obr->vlaknodes[v >> 8].vlak + (v&255);
+ if (is_raytraceable_vlr(re, vlr)) {
+ faces++;
+ }
+ }
}
}
}
@@ -794,7 +795,7 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, con
traceray(origshi, origshr, depth-1, shi.co, shi.view, tracol, shi.obi, shi.vlr, 0);
f= shr.alpha; f1= 1.0f-f;
- nf= d * shi.mat->filter;
+ nf= (shi.mat->mode & MA_RAYTRANSP) ? d * shi.mat->filter : 0.0f;
fr= 1.0f+ nf*(shi.r-1.0f);
fg= 1.0f+ nf*(shi.g-1.0f);
fb= 1.0f+ nf*(shi.b-1.0f);
@@ -1628,9 +1629,9 @@ static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int
shade_ray(is, &shi, &shr);
if (shi.mat->material_type == MA_TYPE_SURFACE) {
- const float d= (traflag & RAY_TRA) ?
- shade_by_transmission(is, &shi, &shr) :
- 1.0f;
+ const float d = (shi.mat->mode & MA_RAYTRANSP) ?
+ ((traflag & RAY_TRA) ? shade_by_transmission(is, &shi, &shr) : 1.0f) :
+ 0.0f;
/* mix colors based on shadfac (rgb + amount of light factor) */
addAlphaLight(col, shr.diff, shr.alpha, d*shi.mat->filter);
}
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index 6486844bacf..9e722acf0d4 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -48,9 +48,8 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
-#ifdef WITH_CYCLES_DEBUG
-# include "BKE_scene.h"
-#endif
+#include "BKE_camera.h"
+#include "BKE_scene.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -63,14 +62,32 @@
/********************************** Free *************************************/
+static void render_result_views_free(RenderResult *res)
+{
+ while (res->views.first) {
+ RenderView *rv = res->views.first;
+ BLI_remlink(&res->views, rv);
+
+ if (rv->rect32)
+ MEM_freeN(rv->rect32);
+
+ if (rv->rectz)
+ MEM_freeN(rv->rectz);
+
+ if (rv->rectf)
+ MEM_freeN(rv->rectf);
+
+ MEM_freeN(rv);
+ }
+}
+
void render_result_free(RenderResult *res)
{
if (res == NULL) return;
while (res->layers.first) {
RenderLayer *rl = res->layers.first;
-
- if (rl->rectf) MEM_freeN(rl->rectf);
+
/* acolrect and scolrect are optionally allocated in shade_tile, only free here since it can be used for drawing */
if (rl->acolrect) MEM_freeN(rl->acolrect);
if (rl->scolrect) MEM_freeN(rl->scolrect);
@@ -85,7 +102,9 @@ void render_result_free(RenderResult *res)
BLI_remlink(&res->layers, rl);
MEM_freeN(rl);
}
-
+
+ render_result_views_free(res);
+
if (res->rect32)
MEM_freeN(res->rect32);
if (res->rectz)
@@ -96,7 +115,9 @@ void render_result_free(RenderResult *res)
MEM_freeN(res->text);
if (res->error)
MEM_freeN(res->error);
-
+ if (res->stamp_data)
+ MEM_freeN(res->stamp_data);
+
MEM_freeN(res);
}
@@ -115,13 +136,44 @@ void render_result_free_list(ListBase *lb, RenderResult *rr)
}
}
-/********************************* Names *************************************/
+/********************************* multiview *************************************/
-/* NOTE: OpenEXR only supports 32 chars for layer+pass names
- * In blender we now use max 10 chars for pass, max 20 for layer */
-static const char *get_pass_name(int passtype, int channel)
+/* create a new views Listbase in rr without duplicating the memory pointers */
+void render_result_views_shallowcopy(RenderResult *dst, RenderResult *src)
+{
+ RenderView *rview;
+
+ if (dst == NULL || src == NULL)
+ return;
+
+ for (rview = src->views.first; rview; rview = rview->next) {
+ RenderView *rv;
+
+ rv = MEM_mallocN(sizeof(RenderView), "new render view");
+ BLI_addtail(&dst->views, rv);
+
+ BLI_strncpy(rv->name, rview->name, sizeof(rv->name));
+ rv->rectf = rview->rectf;
+ rv->rectz = rview->rectz;
+ rv->rect32 = rview->rect32;
+ }
+}
+
+/* free the views created temporarily */
+void render_result_views_shallowdelete(RenderResult *rr)
+{
+ if (rr == NULL)
+ return;
+
+ while (rr->views.first) {
+ RenderView *rv = rr->views.first;
+ BLI_remlink(&rr->views, rv);
+ MEM_freeN(rv);
+ }
+}
+
+static const char *name_from_passtype(int passtype, int channel)
{
-
if (passtype == SCE_PASS_COMBINED) {
if (channel == -1) return "Combined";
if (channel == 0) return "Combined.R";
@@ -308,122 +360,149 @@ static const char *get_pass_name(int passtype, int channel)
static int passtype_from_name(const char *str)
{
-
- if (STREQ(str, "Combined"))
+ if (STRPREFIX(str, "Combined"))
return SCE_PASS_COMBINED;
- if (STREQ(str, "Depth"))
+ if (STRPREFIX(str, "Depth"))
return SCE_PASS_Z;
- if (STREQ(str, "Vector"))
+ if (STRPREFIX(str, "Vector"))
return SCE_PASS_VECTOR;
- if (STREQ(str, "Normal"))
+ if (STRPREFIX(str, "Normal"))
return SCE_PASS_NORMAL;
- if (STREQ(str, "UV"))
+ if (STRPREFIX(str, "UV"))
return SCE_PASS_UV;
- if (STREQ(str, "Color"))
+ if (STRPREFIX(str, "Color"))
return SCE_PASS_RGBA;
- if (STREQ(str, "Emit"))
+ if (STRPREFIX(str, "Emit"))
return SCE_PASS_EMIT;
- if (STREQ(str, "Diffuse"))
+ if (STRPREFIX(str, "Diffuse"))
return SCE_PASS_DIFFUSE;
- if (STREQ(str, "Spec"))
+ if (STRPREFIX(str, "Spec"))
return SCE_PASS_SPEC;
- if (STREQ(str, "Shadow"))
+ if (STRPREFIX(str, "Shadow"))
return SCE_PASS_SHADOW;
- if (STREQ(str, "AO"))
+ if (STRPREFIX(str, "AO"))
return SCE_PASS_AO;
- if (STREQ(str, "Env"))
+ if (STRPREFIX(str, "Env"))
return SCE_PASS_ENVIRONMENT;
- if (STREQ(str, "Indirect"))
+ if (STRPREFIX(str, "Indirect"))
return SCE_PASS_INDIRECT;
- if (STREQ(str, "Reflect"))
+ if (STRPREFIX(str, "Reflect"))
return SCE_PASS_REFLECT;
- if (STREQ(str, "Refract"))
+ if (STRPREFIX(str, "Refract"))
return SCE_PASS_REFRACT;
- if (STREQ(str, "IndexOB"))
+ if (STRPREFIX(str, "IndexOB"))
return SCE_PASS_INDEXOB;
- if (STREQ(str, "IndexMA"))
+ if (STRPREFIX(str, "IndexMA"))
return SCE_PASS_INDEXMA;
- if (STREQ(str, "Mist"))
+ if (STRPREFIX(str, "Mist"))
return SCE_PASS_MIST;
- if (STREQ(str, "RayHits"))
+ if (STRPREFIX(str, "RayHits"))
return SCE_PASS_RAYHITS;
- if (STREQ(str, "DiffDir"))
+ if (STRPREFIX(str, "DiffDir"))
return SCE_PASS_DIFFUSE_DIRECT;
- if (STREQ(str, "DiffInd"))
+ if (STRPREFIX(str, "DiffInd"))
return SCE_PASS_DIFFUSE_INDIRECT;
- if (STREQ(str, "DiffCol"))
+ if (STRPREFIX(str, "DiffCol"))
return SCE_PASS_DIFFUSE_COLOR;
- if (STREQ(str, "GlossDir"))
+ if (STRPREFIX(str, "GlossDir"))
return SCE_PASS_GLOSSY_DIRECT;
- if (STREQ(str, "GlossInd"))
+ if (STRPREFIX(str, "GlossInd"))
return SCE_PASS_GLOSSY_INDIRECT;
- if (STREQ(str, "GlossCol"))
+ if (STRPREFIX(str, "GlossCol"))
return SCE_PASS_GLOSSY_COLOR;
- if (STREQ(str, "TransDir"))
+ if (STRPREFIX(str, "TransDir"))
return SCE_PASS_TRANSM_DIRECT;
- if (STREQ(str, "TransInd"))
+ if (STRPREFIX(str, "TransInd"))
return SCE_PASS_TRANSM_INDIRECT;
- if (STREQ(str, "TransCol"))
+ if (STRPREFIX(str, "TransCol"))
return SCE_PASS_TRANSM_COLOR;
- if (STREQ(str, "SubsurfaceDir"))
+ if (STRPREFIX(str, "SubsurfaceDir"))
return SCE_PASS_SUBSURFACE_DIRECT;
- if (STREQ(str, "SubsurfaceInd"))
+ if (STRPREFIX(str, "SubsurfaceInd"))
return SCE_PASS_SUBSURFACE_INDIRECT;
- if (STREQ(str, "SubsurfaceCol"))
+ if (STRPREFIX(str, "SubsurfaceCol"))
return SCE_PASS_SUBSURFACE_COLOR;
return 0;
}
+
+static void set_pass_name(char *passname, int passtype, int channel, const char *view)
+{
+ const char *end;
+ const char *token;
+ int len;
+
+ const char *passtype_name = name_from_passtype(passtype, channel);
+
+ if (view == NULL || view[0] == '\0') {
+ BLI_strncpy(passname, passtype_name, EXR_PASS_MAXNAME);
+ return;
+ }
+
+ end = passtype_name + strlen(passtype_name);
+ len = IMB_exr_split_token(passtype_name, end, &token);
+
+ if (len == strlen(passtype_name))
+ sprintf(passname, "%s.%s", passtype_name, view);
+ else
+ sprintf(passname, "%.*s%s.%s", (int)(end-passtype_name) - len, passtype_name, view, token);
+}
+
/********************************** New **************************************/
-static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype)
+static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype, const char *viewname)
{
- const char *typestr = get_pass_name(passtype, 0);
+ const size_t view_id = BLI_findstringindex(&rr->views, viewname, offsetof(RenderView, name));
+ const char *typestr = name_from_passtype(passtype, -1);
RenderPass *rpass = MEM_callocN(sizeof(RenderPass), typestr);
- int rectsize = rr->rectx * rr->recty * channels;
+ size_t rectsize = ((size_t)rr->rectx) * rr->recty * channels;
BLI_addtail(&rl->passes, rpass);
rpass->passtype = passtype;
rpass->channels = channels;
rpass->rectx = rl->rectx;
rpass->recty = rl->recty;
- BLI_strncpy(rpass->name, get_pass_name(rpass->passtype, -1), sizeof(rpass->name));
+ rpass->view_id = view_id;
+
+ set_pass_name(rpass->name, rpass->passtype, -1, viewname);
+ BLI_strncpy(rpass->internal_name, typestr, sizeof(rpass->internal_name));
+ BLI_strncpy(rpass->view, viewname, sizeof(rpass->view));
if (rl->exrhandle) {
int a;
for (a = 0; a < channels; a++)
- IMB_exr_add_channel(rl->exrhandle, rl->name, get_pass_name(passtype, a), 0, 0, NULL);
+ IMB_exr_add_channel(rl->exrhandle, rl->name, name_from_passtype(passtype, a), viewname, 0, 0, NULL);
}
else {
float *rect;
@@ -460,9 +539,10 @@ static RenderPass *render_layer_add_debug_pass(RenderResult *rr,
RenderLayer *rl,
int channels,
int pass_type,
- int debug_type)
+ int debug_type,
+ const char *view)
{
- RenderPass *rpass = render_layer_add_pass(rr, rl, channels, pass_type);
+ RenderPass *rpass = render_layer_add_pass(rr, rl, channels, pass_type, view);
rpass->debug_type = debug_type;
BLI_strncpy(rpass->name,
debug_pass_type_name_get(debug_type),
@@ -475,12 +555,14 @@ static RenderPass *render_layer_add_debug_pass(RenderResult *rr,
/* will read info from Render *re to define layers */
/* called in threads */
/* re->winx,winy is coordinate space of entire image, partrct the part within */
-RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuffers, const char *layername)
+RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuffers, const char *layername, const char *viewname)
{
RenderResult *rr;
RenderLayer *rl;
+ RenderView *rv;
SceneRenderLayer *srl;
- int rectx, recty, nr;
+ int rectx, recty;
+ int nr;
rectx = BLI_rcti_size_x(partrct);
recty = BLI_rcti_size_y(partrct);
@@ -505,6 +587,8 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
rr->do_exr_tile = true;
}
+ render_result_views_new(rr, &re->r);
+
/* check renderdata for amount of layers */
for (nr = 0, srl = re->r.layers.first; srl; srl = srl->next, nr++) {
@@ -538,84 +622,90 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
if (rr->do_exr_tile) {
rl->display_buffer = MEM_mapallocN(rectx * recty * sizeof(unsigned int), "Combined display space rgba");
-
rl->exrhandle = IMB_exr_get_handle();
-
- IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.R", 0, 0, NULL);
- IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.G", 0, 0, NULL);
- IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.B", 0, 0, NULL);
- IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.A", 0, 0, NULL);
}
- else
- rl->rectf = MEM_mapallocN(rectx * recty * sizeof(float) * 4, "Combined rgba");
-
- if (srl->passflag & SCE_PASS_Z)
- render_layer_add_pass(rr, rl, 1, SCE_PASS_Z);
- if (srl->passflag & SCE_PASS_VECTOR)
- render_layer_add_pass(rr, rl, 4, SCE_PASS_VECTOR);
- if (srl->passflag & SCE_PASS_NORMAL)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_NORMAL);
- if (srl->passflag & SCE_PASS_UV)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_UV);
- if (srl->passflag & SCE_PASS_RGBA)
- render_layer_add_pass(rr, rl, 4, SCE_PASS_RGBA);
- if (srl->passflag & SCE_PASS_EMIT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_EMIT);
- if (srl->passflag & SCE_PASS_DIFFUSE)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE);
- if (srl->passflag & SCE_PASS_SPEC)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC);
- if (srl->passflag & SCE_PASS_AO)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_AO);
- if (srl->passflag & SCE_PASS_ENVIRONMENT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_ENVIRONMENT);
- if (srl->passflag & SCE_PASS_INDIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_INDIRECT);
- if (srl->passflag & SCE_PASS_SHADOW)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW);
- if (srl->passflag & SCE_PASS_REFLECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_REFLECT);
- if (srl->passflag & SCE_PASS_REFRACT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_REFRACT);
- if (srl->passflag & SCE_PASS_INDEXOB)
- render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXOB);
- if (srl->passflag & SCE_PASS_INDEXMA)
- render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXMA);
- if (srl->passflag & SCE_PASS_MIST)
- render_layer_add_pass(rr, rl, 1, SCE_PASS_MIST);
- if (rl->passflag & SCE_PASS_RAYHITS)
- render_layer_add_pass(rr, rl, 4, SCE_PASS_RAYHITS);
- if (srl->passflag & SCE_PASS_DIFFUSE_DIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_DIRECT);
- if (srl->passflag & SCE_PASS_DIFFUSE_INDIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_INDIRECT);
- if (srl->passflag & SCE_PASS_DIFFUSE_COLOR)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_COLOR);
- if (srl->passflag & SCE_PASS_GLOSSY_DIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_DIRECT);
- if (srl->passflag & SCE_PASS_GLOSSY_INDIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_INDIRECT);
- if (srl->passflag & SCE_PASS_GLOSSY_COLOR)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_COLOR);
- if (srl->passflag & SCE_PASS_TRANSM_DIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_DIRECT);
- if (srl->passflag & SCE_PASS_TRANSM_INDIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_INDIRECT);
- if (srl->passflag & SCE_PASS_TRANSM_COLOR)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_COLOR);
- if (srl->passflag & SCE_PASS_SUBSURFACE_DIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_DIRECT);
- if (srl->passflag & SCE_PASS_SUBSURFACE_INDIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_INDIRECT);
- if (srl->passflag & SCE_PASS_SUBSURFACE_COLOR)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_COLOR);
+
+ for (rv = rr->views.first; rv; rv = rv->next) {
+ const char *view = rv->name;
+
+ if (viewname && viewname[0])
+ if (!STREQ(view, viewname))
+ continue;
+
+ if (rr->do_exr_tile)
+ IMB_exr_add_view(rl->exrhandle, view);
+
+ /* a renderlayer should always have a Combined pass*/
+ render_layer_add_pass(rr, rl, 4, SCE_PASS_COMBINED, view);
+
+ if (srl->passflag & SCE_PASS_Z)
+ render_layer_add_pass(rr, rl, 1, SCE_PASS_Z, view);
+ if (srl->passflag & SCE_PASS_VECTOR)
+ render_layer_add_pass(rr, rl, 4, SCE_PASS_VECTOR, view);
+ if (srl->passflag & SCE_PASS_NORMAL)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_NORMAL, view);
+ if (srl->passflag & SCE_PASS_UV)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_UV, view);
+ if (srl->passflag & SCE_PASS_RGBA)
+ render_layer_add_pass(rr, rl, 4, SCE_PASS_RGBA, view);
+ if (srl->passflag & SCE_PASS_EMIT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_EMIT, view);
+ if (srl->passflag & SCE_PASS_DIFFUSE)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE, view);
+ if (srl->passflag & SCE_PASS_SPEC)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC, view);
+ if (srl->passflag & SCE_PASS_AO)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_AO, view);
+ if (srl->passflag & SCE_PASS_ENVIRONMENT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_ENVIRONMENT, view);
+ if (srl->passflag & SCE_PASS_INDIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_INDIRECT, view);
+ if (srl->passflag & SCE_PASS_SHADOW)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW, view);
+ if (srl->passflag & SCE_PASS_REFLECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_REFLECT, view);
+ if (srl->passflag & SCE_PASS_REFRACT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_REFRACT, view);
+ if (srl->passflag & SCE_PASS_INDEXOB)
+ render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXOB, view);
+ if (srl->passflag & SCE_PASS_INDEXMA)
+ render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXMA, view);
+ if (srl->passflag & SCE_PASS_MIST)
+ render_layer_add_pass(rr, rl, 1, SCE_PASS_MIST, view);
+ if (rl->passflag & SCE_PASS_RAYHITS)
+ render_layer_add_pass(rr, rl, 4, SCE_PASS_RAYHITS, view);
+ if (srl->passflag & SCE_PASS_DIFFUSE_DIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_DIRECT, view);
+ if (srl->passflag & SCE_PASS_DIFFUSE_INDIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_INDIRECT, view);
+ if (srl->passflag & SCE_PASS_DIFFUSE_COLOR)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_COLOR, view);
+ if (srl->passflag & SCE_PASS_GLOSSY_DIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_DIRECT, view);
+ if (srl->passflag & SCE_PASS_GLOSSY_INDIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_INDIRECT, view);
+ if (srl->passflag & SCE_PASS_GLOSSY_COLOR)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_COLOR, view);
+ if (srl->passflag & SCE_PASS_TRANSM_DIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_DIRECT, view);
+ if (srl->passflag & SCE_PASS_TRANSM_INDIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_INDIRECT, view);
+ if (srl->passflag & SCE_PASS_TRANSM_COLOR)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_COLOR, view);
+ if (srl->passflag & SCE_PASS_SUBSURFACE_DIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_DIRECT, view);
+ if (srl->passflag & SCE_PASS_SUBSURFACE_INDIRECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_INDIRECT, view);
+ if (srl->passflag & SCE_PASS_SUBSURFACE_COLOR)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_COLOR, view);
#ifdef WITH_CYCLES_DEBUG
- if (BKE_scene_use_new_shading_nodes(re->scene)) {
- render_layer_add_debug_pass(rr, rl, 1, SCE_PASS_DEBUG,
- RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS);
- }
+ if (BKE_scene_use_new_shading_nodes(re->scene)) {
+ render_layer_add_debug_pass(rr, rl, 1, SCE_PASS_DEBUG,
+ RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS, view);
+ }
#endif
+ }
}
/* sss, previewrender and envmap don't do layers, so we make a default one */
if (BLI_listbase_is_empty(&rr->layers) && !(layername && layername[0])) {
@@ -628,18 +718,23 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
/* duplicate code... */
if (rr->do_exr_tile) {
rl->display_buffer = MEM_mapallocN(rectx * recty * sizeof(unsigned int), "Combined display space rgba");
-
rl->exrhandle = IMB_exr_get_handle();
-
- IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.R", 0, 0, NULL);
- IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.G", 0, 0, NULL);
- IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.B", 0, 0, NULL);
- IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.A", 0, 0, NULL);
}
- else {
- rl->rectf = MEM_mapallocN(rectx * recty * sizeof(float) * 4, "Combined rgba");
+
+ for (rv = rr->views.first; rv; rv = rv->next) {
+ const char *view = rv->name;
+
+ if (viewname && viewname[0])
+ if (strcmp(view, viewname) != 0)
+ continue;
+
+ if (rr->do_exr_tile)
+ IMB_exr_add_view(rl->exrhandle, view);
+
+ /* a renderlayer should always have a Combined pass */
+ render_layer_add_pass(rr, rl, 4, SCE_PASS_COMBINED, view);
}
-
+
/* note, this has to be in sync with scene.c */
rl->lay = (1 << 20) - 1;
rl->layflag = 0x7FFF; /* solid ztra halo strand */
@@ -657,15 +752,15 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
}
/* allocate osa new results for samples */
-RenderResult *render_result_new_full_sample(Render *re, ListBase *lb, rcti *partrct, int crop, int savebuffers)
+RenderResult *render_result_new_full_sample(Render *re, ListBase *lb, rcti *partrct, int crop, int savebuffers, const char *viewname)
{
int a;
if (re->osa == 0)
- return render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS);
+ return render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS, viewname);
for (a = 0; a < re->osa; a++) {
- RenderResult *rr = render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS);
+ RenderResult *rr = render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS, viewname);
BLI_addtail(lb, rr);
rr->sample_nr = a;
}
@@ -686,28 +781,98 @@ static void *ml_addlayer_cb(void *base, const char *str)
return rl;
}
-static void ml_addpass_cb(void *UNUSED(base), void *lay, const char *str, float *rect, int totchan, const char *chan_id)
+static void ml_addpass_cb(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id, const char *view)
{
+ RenderResult *rr = base;
RenderLayer *rl = lay;
RenderPass *rpass = MEM_callocN(sizeof(RenderPass), "loaded pass");
int a;
BLI_addtail(&rl->passes, rpass);
rpass->channels = totchan;
-
rpass->passtype = passtype_from_name(str);
if (rpass->passtype == 0) printf("unknown pass %s\n", str);
rl->passflag |= rpass->passtype;
- BLI_strncpy(rpass->name, str, EXR_PASS_MAXNAME);
/* channel id chars */
for (a = 0; a < totchan; a++)
rpass->chan_id[a] = chan_id[a];
-
+
rpass->rect = rect;
+ if (view[0] != '\0') {
+ BLI_snprintf(rpass->name, sizeof(rpass->name), "%s.%s", str, view);
+ rpass->view_id = BLI_findstringindex(&rr->views, view, offsetof(RenderView, name));
+ }
+ else {
+ BLI_strncpy(rpass->name, str, sizeof(rpass->name));
+ rpass->view_id = 0;
+ }
+
+ BLI_strncpy(rpass->view, view, sizeof(rpass->view));
+ BLI_strncpy(rpass->internal_name, str, sizeof(rpass->internal_name));
+}
+
+static void *ml_addview_cb(void *base, const char *str)
+{
+ RenderResult *rr = base;
+ RenderView *rv;
+
+ rv = MEM_callocN(sizeof(RenderView), "new render view");
+ BLI_strncpy(rv->name, str, EXR_VIEW_MAXNAME);
+
+ /* For stereo drawing we need to ensure:
+ * STEREO_LEFT_NAME == STEREO_LEFT_ID and
+ * STEREO_RIGHT_NAME == STEREO_RIGHT_ID */
+
+ if (STREQ(str, STEREO_LEFT_NAME)) {
+ BLI_addhead(&rr->views, rv);
+ }
+ else if (STREQ(str, STEREO_RIGHT_NAME)) {
+ RenderView *left_rv = BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name));
+
+ if (left_rv == NULL) {
+ BLI_addhead(&rr->views, rv);
+ }
+ else {
+ BLI_insertlinkafter(&rr->views, left_rv, rv);
+ }
+ }
+ else {
+ BLI_addtail(&rr->views, rv);
+ }
+
+ return rv;
+}
+
+static int order_render_passes(const void *a, const void *b)
+{
+ // 1 if a is after b
+ RenderPass *rpa = (RenderPass *) a;
+ RenderPass *rpb = (RenderPass *) b;
+
+ if (rpa->passtype > rpb->passtype)
+ return 1;
+ else if (rpa->passtype < rpb->passtype)
+ return 0;
+
+ /* they have the same type */
+ /* left first */
+ if (STREQ(rpa->view, STEREO_LEFT_NAME))
+ return 0;
+ else if (STREQ(rpb->view, STEREO_LEFT_NAME))
+ return 1;
+
+ /* right second */
+ if (STREQ(rpa->view, STEREO_RIGHT_NAME))
+ return 0;
+ else if (STREQ(rpb->view, STEREO_RIGHT_NAME))
+ return 1;
+
+ /* remaining in ascending id order */
+ return (rpa->view_id < rpb->view_id);
}
-/* from imbuf, if a handle was returned we convert this to render result */
+/* from imbuf, if a handle was returned and it's not a singlelayer multiview we convert this to render result */
RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty)
{
RenderResult *rr = MEM_callocN(sizeof(RenderResult), __func__);
@@ -718,13 +883,17 @@ RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace
rr->rectx = rectx;
rr->recty = recty;
- IMB_exr_multilayer_convert(exrhandle, rr, ml_addlayer_cb, ml_addpass_cb);
+ IMB_exr_multilayer_convert(exrhandle, rr, ml_addview_cb, ml_addlayer_cb, ml_addpass_cb);
for (rl = rr->layers.first; rl; rl = rl->next) {
+ int c=0;
rl->rectx = rectx;
rl->recty = recty;
+ BLI_listbase_sort(&rl->passes, order_render_passes);
+
for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
+ printf("%d: %s\n", c++, rpass->name);
rpass->rectx = rectx;
rpass->recty = recty;
@@ -738,26 +907,56 @@ RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace
return rr;
}
+void render_result_view_new(RenderResult *rr, const char *viewname)
+{
+ RenderView *rv = MEM_callocN(sizeof(RenderView), "new render view");
+ BLI_addtail(&rr->views, rv);
+ BLI_strncpy(rv->name, viewname, sizeof(rv->name));
+}
+
+void render_result_views_new(RenderResult *rr, RenderData *rd)
+{
+ SceneRenderView *srv;
+
+ /* clear previously existing views - for sequencer */
+ render_result_views_free(rr);
+
+ /* check renderdata for amount of views */
+ if ((rd->scemode & R_MULTIVIEW)) {
+ for (srv = rd->views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv) == false)
+ continue;
+ render_result_view_new(rr, srv->name);
+ }
+ }
+
+ /* we always need at least one view */
+ if (BLI_listbase_count_ex(&rr->views, 1) == 0) {
+ render_result_view_new(rr, "");
+ }
+}
+
/*********************************** Merge ***********************************/
static void do_merge_tile(RenderResult *rr, RenderResult *rrpart, float *target, float *tile, int pixsize)
{
- int y, ofs, copylen, tilex, tiley;
+ int y, tilex, tiley;
+ size_t ofs, copylen;
copylen = tilex = rrpart->rectx;
tiley = rrpart->recty;
if (rrpart->crop) { /* filters add pixel extra */
- tile += pixsize * (rrpart->crop + rrpart->crop * tilex);
+ tile += pixsize * (rrpart->crop + ((size_t)rrpart->crop) * tilex);
copylen = tilex - 2 * rrpart->crop;
tiley -= 2 * rrpart->crop;
- ofs = (rrpart->tilerect.ymin + rrpart->crop) * rr->rectx + (rrpart->tilerect.xmin + rrpart->crop);
+ ofs = (((size_t)rrpart->tilerect.ymin) + rrpart->crop) * rr->rectx + (rrpart->tilerect.xmin + rrpart->crop);
target += pixsize * ofs;
}
else {
- ofs = (rrpart->tilerect.ymin * rr->rectx + rrpart->tilerect.xmin);
+ ofs = (((size_t)rrpart->tilerect.ymin) * rr->rectx + rrpart->tilerect.xmin);
target += pixsize * ofs;
}
@@ -783,16 +982,19 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
for (rl = rr->layers.first; rl; rl = rl->next) {
rlp = RE_GetRenderLayer(rrpart, rl->name);
if (rlp) {
- /* combined */
- if (rl->rectf && rlp->rectf)
- do_merge_tile(rr, rrpart, rl->rectf, rlp->rectf, 4);
-
/* passes are allocated in sync */
for (rpass = rl->passes.first, rpassp = rlp->passes.first;
rpass && rpassp;
- rpass = rpass->next, rpassp = rpassp->next)
+ rpass = rpass->next)
{
+ /* renderresult have all passes, renderpart only the active view's passes */
+ if (strcmp(rpassp->name, rpass->name) != 0)
+ continue;
+
do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, rpass->channels);
+
+ /* manually get next render pass */
+ rpassp = rpassp->next;
}
}
}
@@ -801,7 +1003,7 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
/* for passes read from files, these have names stored */
static char *make_pass_name(RenderPass *rpass, int chan)
{
- static char name[16];
+ static char name[EXR_PASS_MAXNAME];
int len;
BLI_strncpy(name, rpass->name, EXR_PASS_MAXNAME);
@@ -813,55 +1015,102 @@ static char *make_pass_name(RenderPass *rpass, int chan)
return name;
}
-/* filename already made absolute */
-/* called from within UI, saves both rendered result as a file-read result */
-bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *filename, int compress)
+/* called from within UI and render pipeline, saves both rendered result as a file-read result
+ * if multiview is true saves all views in a multiview exr
+ * else if view is not NULL saves single view
+ * else saves stereo3d
+ */
+bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *filename, ImageFormatData *imf, const bool multiview, const char *view)
{
RenderLayer *rl;
RenderPass *rpass;
+ RenderView *rview;
void *exrhandle = IMB_exr_get_handle();
bool success;
-
- BLI_make_existing_file(filename);
-
- /* composite result */
- if (rr->rectf) {
- IMB_exr_add_channel(exrhandle, "Composite", "Combined.R", 4, 4 * rr->rectx, rr->rectf);
- IMB_exr_add_channel(exrhandle, "Composite", "Combined.G", 4, 4 * rr->rectx, rr->rectf + 1);
- IMB_exr_add_channel(exrhandle, "Composite", "Combined.B", 4, 4 * rr->rectx, rr->rectf + 2);
- IMB_exr_add_channel(exrhandle, "Composite", "Combined.A", 4, 4 * rr->rectx, rr->rectf + 3);
+ int a, nr;
+ const char *chan_view = NULL;
+ int compress = (imf ? imf->exr_codec : 0);
+ size_t width, height;
+
+ const bool is_mono = view && !multiview;
+
+ width = rr->rectx;
+ height = rr->recty;
+
+ if (imf && imf->imtype == R_IMF_IMTYPE_OPENEXR && multiview) {
+ /* single layer OpenEXR */
+ const char *RGBAZ[] = {"R", "G", "B", "A", "Z"};
+ for (nr = 0, rview = rr->views.first; rview; rview = rview->next, nr++) {
+ IMB_exr_add_view(exrhandle, rview->name);
+
+ if (rview->rectf) {
+ for (a = 0; a < 4; a++)
+ IMB_exr_add_channel(exrhandle, "", RGBAZ[a],
+ rview->name, 4, 4 * width, rview->rectf + a);
+ if (rview->rectz)
+ IMB_exr_add_channel(exrhandle, "", RGBAZ[4],
+ rview->name, 1, width, rview->rectz);
+ }
+ }
}
-
- /* add layers/passes and assign channels */
- for (rl = rr->layers.first; rl; rl = rl->next) {
-
- /* combined */
- if (rl->rectf) {
- int a, xstride = 4;
- for (a = 0; a < xstride; a++) {
- IMB_exr_add_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a),
- xstride, xstride * rr->rectx, rl->rectf + a);
+ else {
+ for (nr = 0, rview = rr->views.first; rview; rview = rview->next, nr++) {
+ if (is_mono) {
+ if (!STREQ(view, rview->name)) {
+ continue;
+ }
+ chan_view = "";
+ }
+ else {
+ /* if rendered only one view, we treat as a a non-view render */
+ chan_view = rview->name;
+ }
+
+ IMB_exr_add_view(exrhandle, rview->name);
+
+ if (rview->rectf) {
+ for (a = 0; a < 4; a++)
+ IMB_exr_add_channel(exrhandle, "Composite", name_from_passtype(SCE_PASS_COMBINED, a),
+ chan_view, 4, 4 * width, rview->rectf + a);
}
}
-
- /* passes are allocated in sync */
- for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
- int a, xstride = rpass->channels;
- for (a = 0; a < xstride; a++) {
- if (rpass->passtype) {
- IMB_exr_add_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a),
- xstride, xstride * rr->rectx, rpass->rect + a);
+
+ /* add layers/passes and assign channels */
+ for (rl = rr->layers.first; rl; rl = rl->next) {
+
+ /* passes are allocated in sync */
+ for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
+ const int xstride = rpass->channels;
+
+ if (is_mono) {
+ if (!STREQ(view, rpass->view)) {
+ continue;
+ }
+ chan_view = "";
}
else {
- IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a),
- xstride, xstride * rr->rectx, rpass->rect + a);
+ /* if rendered only one view, we treat as a a non-view render */
+ chan_view = (nr > 1 ? rpass->view :"");
+ }
+
+ for (a = 0; a < xstride; a++) {
+
+ if (rpass->passtype) {
+ IMB_exr_add_channel(exrhandle, rl->name, name_from_passtype(rpass->passtype, a), chan_view,
+ xstride, xstride * width, rpass->rect + a);
+ }
+ else {
+ IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a), chan_view,
+ xstride, xstride * width, rpass->rect + a);
+ }
}
}
}
}
- /* when the filename has no permissions, this can fail */
- if (IMB_exr_begin_write(exrhandle, filename, rr->rectx, rr->recty, compress)) {
+ BLI_make_existing_file(filename);
+
+ if (IMB_exr_begin_write(exrhandle, filename, width, height, compress, rr->stamp_data)) {
IMB_exr_write_channels(exrhandle);
success = true;
}
@@ -870,8 +1119,8 @@ bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *fil
BKE_report(reports, RPT_ERROR, "Error writing render result (see console)");
success = false;
}
- IMB_exr_close(exrhandle);
+ IMB_exr_close(exrhandle);
return success;
}
@@ -932,7 +1181,7 @@ void render_result_single_layer_end(Render *re)
/************************* EXR Tile File Rendering ***************************/
-static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart)
+static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, const char *viewname)
{
RenderLayer *rlp, *rl;
RenderPass *rpassp;
@@ -955,21 +1204,17 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart)
else {
offs = 0;
}
-
- /* combined */
- if (rlp->rectf) {
- int a, xstride = 4;
- for (a = 0; a < xstride; a++) {
- IMB_exr_set_channel(rl->exrhandle, rlp->name, get_pass_name(SCE_PASS_COMBINED, a),
- xstride, xstride * rrpart->rectx, rlp->rectf + a + xstride * offs);
- }
- }
-
+
/* passes are allocated in sync */
for (rpassp = rlp->passes.first; rpassp; rpassp = rpassp->next) {
- int a, xstride = rpassp->channels;
+ const int xstride = rpassp->channels;
+ int a;
+ char passname[EXR_PASS_MAXNAME];
+
for (a = 0; a < xstride; a++) {
- IMB_exr_set_channel(rl->exrhandle, rlp->name, get_pass_name(rpassp->passtype, a),
+ set_pass_name(passname, rpassp->passtype, a, rpassp->view);
+
+ IMB_exr_set_channel(rl->exrhandle, rlp->name, passname,
xstride, xstride * rrpart->rectx, rpassp->rect + a + xstride * offs);
}
}
@@ -988,7 +1233,7 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart)
continue;
}
- IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0);
+ IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, viewname);
}
BLI_unlock_thread(LOCK_IMAGE);
@@ -1002,13 +1247,13 @@ static void save_empty_result_tiles(Render *re)
for (rr = re->result; rr; rr = rr->next) {
for (rl = rr->layers.first; rl; rl = rl->next) {
- IMB_exrtile_clear_channels(rl->exrhandle);
+ IMB_exr_clear_channels(rl->exrhandle);
for (pa = re->parts.first; pa; pa = pa->next) {
if (pa->status != PART_STATUS_READY) {
int party = pa->disprect.ymin - re->disprect.ymin + pa->crop;
int partx = pa->disprect.xmin - re->disprect.xmin + pa->crop;
- IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0);
+ IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, re->viewname);
}
}
}
@@ -1055,10 +1300,10 @@ void render_result_exr_file_end(Render *re)
}
/* save part into exr file */
-void render_result_exr_file_merge(RenderResult *rr, RenderResult *rrpart)
+void render_result_exr_file_merge(RenderResult *rr, RenderResult *rrpart, const char *viewname)
{
for (; rr && rrpart; rr = rr->next, rrpart = rrpart->next)
- save_render_result_tile(rr, rrpart);
+ save_render_result_tile(rr, rrpart, viewname);
}
/* path to temporary exr file */
@@ -1088,7 +1333,7 @@ int render_result_exr_file_read_sample(Render *re, int sample)
bool success = true;
RE_FreeRenderResult(re->result);
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
+ re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
for (rl = re->result->layers.first; rl; rl = rl->next) {
render_result_exr_file_path(re->scene, rl->name, sample, str);
@@ -1129,23 +1374,20 @@ int render_result_exr_file_read_path(RenderResult *rr, RenderLayer *rl_single, c
for (rl = rr->layers.first; rl; rl = rl->next) {
if (rl_single && rl_single != rl)
continue;
-
- /* combined */
- if (rl->rectf) {
- int a, xstride = 4;
- for (a = 0; a < xstride; a++)
- IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a),
- xstride, xstride * rectx, rl->rectf + a);
- }
/* passes are allocated in sync */
for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
- int a, xstride = rpass->channels;
- for (a = 0; a < xstride; a++)
- IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a),
+ const int xstride = rpass->channels;
+ int a;
+ char passname[EXR_PASS_MAXNAME];
+
+ for (a = 0; a < xstride; a++) {
+ set_pass_name(passname, rpass->passtype, a, rpass->view);
+ IMB_exr_set_channel(exrhandle, rl->name, passname,
xstride, xstride * rectx, rpass->rect + a);
+ }
- BLI_strncpy(rpass->name, get_pass_name(rpass->passtype, -1), sizeof(rpass->name));
+ set_pass_name(rpass->name, rpass->passtype, -1, rpass->view);
}
}
@@ -1191,7 +1433,8 @@ void render_result_exr_file_cache_write(Render *re)
render_result_exr_file_cache_path(re->scene, root, str);
printf("Caching exr file, %dx%d, %s\n", rr->rectx, rr->recty, str);
- RE_WriteRenderResult(NULL, rr, str, 0);
+
+ RE_WriteRenderResult(NULL, rr, str, NULL, true, NULL);
}
/* For cache, makes exact copy of render result */
@@ -1201,7 +1444,7 @@ bool render_result_exr_file_cache_read(Render *re)
char *root = U.render_cachedir;
RE_FreeRenderResult(re->result);
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
+ re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
/* First try cache. */
render_result_exr_file_cache_path(re->scene, root, str);
@@ -1216,15 +1459,16 @@ bool render_result_exr_file_cache_read(Render *re)
/*************************** Combined Pixel Rect *****************************/
-ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd)
+ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd, const int view_id)
{
ImBuf *ibuf = IMB_allocImBuf(rr->rectx, rr->recty, rd->im_format.planes, 0);
-
+ RenderView *rv = RE_RenderViewGetById(rr, view_id);
+
/* if not exists, BKE_imbuf_write makes one */
- ibuf->rect = (unsigned int *)rr->rect32;
- ibuf->rect_float = rr->rectf;
- ibuf->zbuf_float = rr->rectz;
-
+ ibuf->rect = (unsigned int *) rv->rect32;
+ ibuf->rect_float = rv->rectf;
+ ibuf->zbuf_float = rv->rectz;
+
/* float factor for random dither, imbuf takes care of it */
ibuf->dither = rd->dither_intensity;
@@ -1259,57 +1503,97 @@ ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd)
return ibuf;
}
-void render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), ImBuf *ibuf)
+void render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), ImBuf *ibuf, const int view_id)
{
+ RenderView *rv = RE_RenderViewGetById(rr, view_id);
+
if (ibuf->rect_float) {
- if (!rr->rectf)
- rr->rectf = MEM_mallocN(4 * sizeof(float) * rr->rectx * rr->recty, "render_seq rectf");
+ if (!rv->rectf)
+ rv->rectf = MEM_mallocN(4 * sizeof(float) * rr->rectx * rr->recty, "render_seq rectf");
- memcpy(rr->rectf, ibuf->rect_float, 4 * sizeof(float) * rr->rectx * rr->recty);
+ memcpy(rv->rectf, ibuf->rect_float, 4 * sizeof(float) * rr->rectx * rr->recty);
/* TSK! Since sequence render doesn't free the *rr render result, the old rect32
* can hang around when sequence render has rendered a 32 bits one before */
- if (rr->rect32) {
- MEM_freeN(rr->rect32);
- rr->rect32 = NULL;
- }
+ MEM_SAFE_FREE(rv->rect32);
}
else if (ibuf->rect) {
- if (!rr->rect32)
- rr->rect32 = MEM_mallocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect");
+ if (!rv->rect32)
+ rv->rect32 = MEM_mallocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect");
- memcpy(rr->rect32, ibuf->rect, 4 * rr->rectx * rr->recty);
+ memcpy(rv->rect32, ibuf->rect, 4 * rr->rectx * rr->recty);
/* Same things as above, old rectf can hang around from previous render. */
- if (rr->rectf) {
- MEM_freeN(rr->rectf);
- rr->rectf = NULL;
- }
+ MEM_SAFE_FREE(rv->rectf);
}
}
-void render_result_rect_fill_zero(RenderResult *rr)
+void render_result_rect_fill_zero(RenderResult *rr, const int view_id)
{
- if (rr->rectf)
- memset(rr->rectf, 0, 4 * sizeof(float) * rr->rectx * rr->recty);
- else if (rr->rect32)
- memset(rr->rect32, 0, 4 * rr->rectx * rr->recty);
+ RenderView *rv = RE_RenderViewGetById(rr, view_id);
+
+ if (rv->rectf)
+ memset(rv->rectf, 0, 4 * sizeof(float) * rr->rectx * rr->recty);
+ else if (rv->rect32)
+ memset(rv->rect32, 0, 4 * rr->rectx * rr->recty);
else
- rr->rect32 = MEM_callocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect");
+ rv->rect32 = MEM_callocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect");
}
void render_result_rect_get_pixels(RenderResult *rr, unsigned int *rect, int rectx, int recty,
- const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
+ const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings,
+ const int view_id)
{
- if (rr->rect32) {
- memcpy(rect, rr->rect32, sizeof(int) * rr->rectx * rr->recty);
- }
- else if (rr->rectf) {
- IMB_display_buffer_transform_apply((unsigned char *) rect, rr->rectf, rr->rectx, rr->recty, 4,
+ RenderView *rv = RE_RenderViewGetById(rr, view_id);
+
+ if (rv->rect32)
+ memcpy(rect, rv->rect32, sizeof(int) * rr->rectx * rr->recty);
+ else if (rv->rectf)
+ IMB_display_buffer_transform_apply((unsigned char *) rect, rv->rectf, rr->rectx, rr->recty, 4,
view_settings, display_settings, true);
- }
else
/* else fill with black */
memset(rect, 0, sizeof(int) * rectx * recty);
}
+
+/*************************** multiview functions *****************************/
+
+bool RE_HasFakeLayer(RenderResult *res)
+{
+ RenderView *rv;
+
+ if (res == NULL)
+ return false;
+
+ rv = res->views.first;
+ if (rv == NULL)
+ return false;
+
+ return (rv->rect32 || rv->rectf);
+}
+
+bool RE_RenderResult_is_stereo(RenderResult *res)
+{
+ if (! BLI_findstring(&res->views, STEREO_LEFT_NAME, offsetof(RenderView, name)))
+ return false;
+
+ if (! BLI_findstring(&res->views, STEREO_RIGHT_NAME, offsetof(RenderView, name)))
+ return false;
+
+ return true;
+}
+
+RenderView *RE_RenderViewGetById(RenderResult *res, const int view_id)
+{
+ RenderView *rv = BLI_findlink(&res->views, view_id);
+ BLI_assert(res->views.first);
+ return rv ? rv : res->views.first;
+}
+
+RenderView *RE_RenderViewGetByName(RenderResult *res, const char *viewname)
+{
+ RenderView *rv = BLI_findstring(&res->views, viewname, offsetof(RenderView, name));
+ BLI_assert(res->views.first);
+ return rv ? rv : res->views.first;
+}
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index 17039bca63a..6acdde6af9c 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -116,7 +116,7 @@ static void init_render_texture(Render *re, Tex *tex)
if (G.is_rendering && re) {
if (re->r.mode & R_ENVMAP)
if (tex->env->stype==ENV_ANIM)
- BKE_free_envmapdata(tex->env);
+ BKE_texture_envmap_free_data(tex->env);
}
}
}
@@ -1348,7 +1348,7 @@ int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres, struct Image
/* fact = texture strength, facg = button strength value */
void texture_rgb_blend(float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype)
{
- float facm, col;
+ float facm;
switch (blendtype) {
case MTEX_BLEND:
@@ -1435,13 +1435,10 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa
case MTEX_LIGHT:
fact*= facg;
-
- col= fact*tex[0];
- if (col > out[0]) in[0]= col; else in[0]= out[0];
- col= fact*tex[1];
- if (col > out[1]) in[1]= col; else in[1]= out[1];
- col= fact*tex[2];
- if (col > out[2]) in[2]= col; else in[2]= out[2];
+
+ in[0] = max_ff(fact * tex[0], out[0]);
+ in[1] = max_ff(fact * tex[1], out[1]);
+ in[2] = max_ff(fact * tex[2], out[2]);
break;
case MTEX_BLEND_HUE:
@@ -1982,14 +1979,14 @@ static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, T
/* use texres for the center sample, set rgbnor */
rgbnor = multitex_mtex(shi, mtex, STll, dxt, dyt, texres, pool, skip_load_image);
- Hll = (fromrgb) ? rgb_to_grayscale(&texres->tr) : texres->tin;
+ Hll = (fromrgb) ? IMB_colormanagement_get_luminance(&texres->tr) : texres->tin;
/* use ttexr for the other 2 taps */
multitex_mtex(shi, mtex, STlr, dxt, dyt, &ttexr, pool, skip_load_image);
- Hlr = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
+ Hlr = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
multitex_mtex(shi, mtex, STul, dxt, dyt, &ttexr, pool, skip_load_image);
- Hul = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
+ Hul = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
dHdx = Hscale*(Hlr - Hll);
dHdy = Hscale*(Hul - Hll);
@@ -2020,17 +2017,17 @@ static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, T
/* use texres for the center sample, set rgbnor */
rgbnor = multitex_mtex(shi, mtex, STc, dxt, dyt, texres, pool, skip_load_image);
- /* Hc = (fromrgb) ? rgb_to_grayscale(&texres->tr) : texres->tin; */ /* UNUSED */
+ /* Hc = (fromrgb) ? IMB_colormanagement_get_luminance(&texres->tr) : texres->tin; */ /* UNUSED */
/* use ttexr for the other taps */
multitex_mtex(shi, mtex, STl, dxt, dyt, &ttexr, pool, skip_load_image);
- Hl = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
+ Hl = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
multitex_mtex(shi, mtex, STr, dxt, dyt, &ttexr, pool, skip_load_image);
- Hr = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
+ Hr = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
multitex_mtex(shi, mtex, STd, dxt, dyt, &ttexr, pool, skip_load_image);
- Hd = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
+ Hd = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
multitex_mtex(shi, mtex, STu, dxt, dyt, &ttexr, pool, skip_load_image);
- Hu = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
+ Hu = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
dHdx = Hscale*(Hr - Hl);
dHdy = Hscale*(Hu - Hd);
@@ -2328,7 +2325,7 @@ void do_material_tex(ShadeInput *shi, Render *re)
/* texture output */
if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = rgb_to_grayscale(&texres.tr);
+ texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
rgbnor -= TEX_RGB;
}
if (mtex->texflag & MTEX_NEGATIVE) {
@@ -2434,7 +2431,7 @@ void do_material_tex(ShadeInput *shi, Render *re)
BKE_image_pool_release_ibuf(ima, ibuf, re->pool);
}
-
+
if (mtex->mapto & MAP_COL) {
float colfac= mtex->colfac*stencilTin;
texture_rgb_blend(&shi->r, tcol, &shi->r, texres.tin, colfac, mtex->blendtype);
@@ -2568,7 +2565,7 @@ void do_material_tex(ShadeInput *shi, Render *re)
}
if (rgbnor & TEX_RGB) {
- texres.tin = rgb_to_grayscale(&texres.tr);
+ texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
}
factt= (0.5f-texres.tin)*mtex->dispfac*stencilTin; facmm= 1.0f-factt;
@@ -2596,7 +2593,7 @@ void do_material_tex(ShadeInput *shi, Render *re)
if (rgbnor & TEX_RGB) {
if (texres.talpha) texres.tin = texres.ta;
- else texres.tin = rgb_to_grayscale(&texres.tr);
+ else texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
}
if (mtex->mapto & MAP_REF) {
@@ -2767,7 +2764,7 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_
/* texture output */
if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = rgb_to_grayscale(&texres.tr);
+ texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
rgbnor -= TEX_RGB;
}
if (mtex->texflag & MTEX_NEGATIVE) {
@@ -2836,7 +2833,7 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_
/* convert RGB to intensity if intensity info isn't provided */
if (rgbnor & TEX_RGB) {
if (texres.talpha) texres.tin = texres.ta;
- else texres.tin = rgb_to_grayscale(&texres.tr);
+ else texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
}
if ((mapto_flag & MAP_EMISSION) && (mtex->mapto & MAP_EMISSION)) {
@@ -2934,7 +2931,7 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4])
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = rgb_to_bw(&texres.tr);
+ texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
rgb= 0;
}
if (mtex->texflag & MTEX_NEGATIVE) {
@@ -3006,7 +3003,7 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4])
texres.tin = texres.ta;
}
else {
- texres.tin = rgb_to_bw(&texres.tr);
+ texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
}
}
@@ -3140,7 +3137,7 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = rgb_to_bw(&texres.tr);
+ texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
rgb= 0;
}
if (mtex->texflag & MTEX_NEGATIVE) {
@@ -3215,7 +3212,7 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h
}
}
if (mtex->mapto & WOMAP_BLEND) {
- if (rgb) texres.tin = rgb_to_bw(&texres.tr);
+ if (rgb) texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
*blend= texture_value_blend(mtex->def_var, *blend, texres.tin, mtex->blendfac, mtex->blendtype);
}
@@ -3356,7 +3353,7 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = rgb_to_bw(&texres.tr);
+ texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
rgb= 0;
}
if (mtex->texflag & MTEX_NEGATIVE) {
@@ -3455,7 +3452,7 @@ int externtex(MTex *mtex, const float vec[3], float *tin, float *tr, float *tg,
rgb = multitex(tex, texvec, dxt, dyt, 0, &texr, thread, mtex->which_output, pool, skip_load_image);
if (rgb) {
- texr.tin = rgb_to_bw(&texr.tr);
+ texr.tin = IMB_colormanagement_get_luminance(&texr.tr);
}
else {
texr.tr= mtex->r;
@@ -3493,7 +3490,7 @@ void render_realtime_texture(ShadeInput *shi, Image *ima)
if (firsttime) {
for (a=0; a<BLENDER_MAX_THREADS; a++) {
memset(&imatex[a], 0, sizeof(Tex));
- default_tex(&imatex[a]);
+ BKE_texture_default(&imatex[a]);
imatex[a].type= TEX_IMAGE;
}
@@ -3614,7 +3611,7 @@ Material *RE_init_sample_material(Material *orig_mat, Scene *scene)
}
/* copy texture */
- tex= mtex->tex = localize_texture(cur_tex);
+ tex= mtex->tex = BKE_texture_localize(cur_tex);
/* update texture anims */
BKE_animsys_evaluate_animdata(scene, &tex->id, tex->adt, BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
@@ -3631,7 +3628,7 @@ Material *RE_init_sample_material(Material *orig_mat, Scene *scene)
unit_m4(dummy_re.viewmat);
unit_m4(dummy_re.winmat);
dummy_re.winx = dummy_re.winy = 128;
- cache_pointdensity(&dummy_re, tex);
+ cache_pointdensity(&dummy_re, tex->pd);
}
/* update image sequences and movies */
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
index 5b054005bac..a634bd9780c 100644
--- a/source/blender/render/intern/source/rendercore.c
+++ b/source/blender/render/intern/source/rendercore.c
@@ -181,8 +181,10 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in
if (fullsample) {
for (sample=0; sample<totsample; sample++)
- if (ps->mask & (1 << sample))
- addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add);
+ if (ps->mask & (1 << sample)) {
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ addalphaAddfacFloat(pass + od*4, col, har->add);
+ }
}
else {
fac= ((float)amountm)/(float)R.osa;
@@ -214,8 +216,10 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in
if (fullsample) {
for (sample=0; sample<totsample; sample++)
- if (!(mask & (1 << sample)))
- addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add);
+ if (!(mask & (1 << sample))) {
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ addalphaAddfacFloat(pass + od*4, col, har->add);
+ }
}
else {
col[0]= accol[0];
@@ -223,8 +227,10 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in
col[2]= accol[2];
col[3]= accol[3];
- for (sample=0; sample<totsample; sample++)
- addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add);
+ for (sample=0; sample<totsample; sample++) {
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ addalphaAddfacFloat(pass + od*4, col, har->add);
+ }
}
}
@@ -305,8 +311,10 @@ static void halo_tile(RenderPart *pa, RenderLayer *rl)
zz= calchalo_z(har, *rz);
if ((zz> har->zs) || (har->mat && (har->mat->mode & MA_HALO_SOFT))) {
if (shadeHaloFloat(har, col, zz, dist, xn, yn, har->flarec)) {
- for (sample=0; sample<totsample; sample++)
- addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add);
+ for (sample=0; sample<totsample; sample++) {
+ float * rect= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ addalphaAddfacFloat(rect + od*4, col, har->add);
+ }
}
}
}
@@ -359,7 +367,8 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
if (fullsample) {
for (sample=0; sample<totsample; sample++) {
if (ps->mask & (1 << sample)) {
- pass= rlpp[sample]->rectf + od*4;
+ pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ pass += od * 4;
pass[0]+= col[0];
pass[1]+= col[1];
pass[2]+= col[2];
@@ -370,7 +379,8 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
}
else {
fac= ((float)count)/(float)R.osa;
- pass= rl->rectf + od*4;
+ pass = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ pass += od * 4;
pass[0]+= fac*col[0];
pass[1]+= fac*col[1];
pass[2]+= fac*col[2];
@@ -390,7 +400,9 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
if (fullsample) {
for (sample=0; sample<totsample; sample++) {
if (!(mask & (1 << sample))) {
- pass= rlpp[sample]->rectf + od*4;
+
+ pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ pass += od * 4;
pass[0]+= col[0];
pass[1]+= col[1];
pass[2]+= col[2];
@@ -401,7 +413,8 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
}
else {
fac= ((float)R.osa-totsamp)/(float)R.osa;
- pass= rl->rectf + od*4;
+ pass = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ pass += od * 4;
pass[0]+= fac*col[0];
pass[1]+= fac*col[1];
pass[2]+= fac*col[2];
@@ -420,7 +433,8 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
renderspothalo(&shi, col, 1.0f);
for (sample=0; sample<totsample; sample++) {
- pass= rlpp[sample]->rectf + od*4;
+ pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ pass += od * 4;
pass[0]+= col[0];
pass[1]+= col[1];
pass[2]+= col[2];
@@ -444,14 +458,14 @@ static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset,
{
RenderPass *rpass;
- /* combined rgb */
- add_filt_fmask(curmask, shr->combined, rl->rectf + 4*offset, rectx);
-
for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
float *fp, *col= NULL;
int pixsize= 3;
switch (rpass->passtype) {
+ case SCE_PASS_COMBINED:
+ add_filt_fmask(curmask, shr->combined, rpass->rect + 4*offset, rectx);
+ break;
case SCE_PASS_Z:
fp= rpass->rect + offset;
*fp= shr->z;
@@ -555,15 +569,16 @@ static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult
{
RenderPass *rpass;
float *fp;
-
- fp= rl->rectf + 4*offset;
- copy_v4_v4(fp, shr->combined);
-
+
for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
float *col= NULL, uvcol[3];
int a, pixsize= 3;
switch (rpass->passtype) {
+ case SCE_PASS_COMBINED:
+ /* copy combined to use for preview */
+ copy_v4_v4(rpass->rect + 4*offset, shr->combined);
+ break;
case SCE_PASS_Z:
fp= rpass->rect + offset;
*fp= shr->z;
@@ -681,7 +696,8 @@ static void sky_tile(RenderPart *pa, RenderLayer *rl)
bool done = false;
for (sample= 0; sample<totsample; sample++) {
- float *pass= rlpp[sample]->rectf + od;
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+ pass += od;
if (pass[3]<1.0f) {
@@ -742,8 +758,8 @@ static void atm_tile(RenderPart *pa, RenderLayer *rl)
int sample;
for (sample=0; sample<totsample; sample++) {
- const float *zrect= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_Z) + od;
- float *rgbrect = rlpp[sample]->rectf + 4*od;
+ const float *zrect = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_Z, R.viewname) + od;
+ float *rgbrect = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname) + 4*od;
float rgb[3] = {0};
bool done = false;
@@ -978,8 +994,8 @@ static void clamp_alpha_rgb_range(RenderPart *pa, RenderLayer *rl)
return;
for (sample= 0; sample<totsample; sample++) {
- float *rectf= rlpp[sample]->rectf;
-
+ float *rectf = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname);
+
for (y= pa->rectx*pa->recty; y>0; y--, rectf+=4) {
rectf[0] = MAX2(rectf[0], 0.0f);
rectf[1] = MAX2(rectf[1], 0.0f);
@@ -1060,7 +1076,7 @@ static void reset_sky_speed(RenderPart *pa, RenderLayer *rl)
totsample= get_sample_layers(pa, rl, rlpp);
for (sample= 0; sample<totsample; sample++) {
- fp= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_VECTOR);
+ fp= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_VECTOR, R.viewname);
if (fp==NULL) break;
for (a= 4*pa->rectx*pa->recty - 1; a>=0; a--)
@@ -1171,6 +1187,8 @@ void zbufshadeDA_tile(RenderPart *pa)
pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp");
pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
for (rl= rr->layers.first; rl; rl= rl->next) {
+ float *rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+
if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK))
pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask");
@@ -1211,7 +1229,7 @@ void zbufshadeDA_tile(RenderPart *pa)
if (R.flag & R_ZTRA || R.totstrand) {
if (rl->layflag & (SCE_LAY_ZTRA|SCE_LAY_STRAND)) {
if (pa->fullresult.first) {
- zbuffer_transp_shade(pa, rl, rl->rectf, &psmlist);
+ zbuffer_transp_shade(pa, rl, rect, &psmlist);
}
else {
unsigned short *ztramask, *solidmask= NULL; /* 16 bits, MAX_OSA */
@@ -1220,9 +1238,9 @@ void zbufshadeDA_tile(RenderPart *pa)
rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer");
/* swap for live updates, and it is used in zbuf.c!!! */
- SWAP(float *, rl->acolrect, rl->rectf);
- ztramask= zbuffer_transp_shade(pa, rl, rl->rectf, &psmlist);
- SWAP(float *, rl->acolrect, rl->rectf);
+ SWAP(float *, rl->acolrect, rect);
+ ztramask = zbuffer_transp_shade(pa, rl, rect, &psmlist);
+ SWAP(float *, rl->acolrect, rect);
/* zbuffer transp only returns ztramask if there's solid rendered */
if (ztramask)
@@ -1231,7 +1249,8 @@ void zbufshadeDA_tile(RenderPart *pa)
if (ztramask && solidmask) {
unsigned short *sps= solidmask, *spz= ztramask;
unsigned short fullmask= (1<<R.osa)-1;
- float *fcol= rl->rectf; float *acol= rl->acolrect;
+ float *fcol= rect;
+ float *acol= rl->acolrect;
int x;
for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4, sps++, spz++) {
@@ -1242,7 +1261,8 @@ void zbufshadeDA_tile(RenderPart *pa)
}
}
else {
- float *fcol= rl->rectf; float *acol= rl->acolrect;
+ float *fcol= rect;
+ float *acol= rl->acolrect;
int x;
for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) {
addAlphaOverFloat(fcol, acol);
@@ -1265,7 +1285,7 @@ void zbufshadeDA_tile(RenderPart *pa)
/* extra layers */
if (rl->layflag & SCE_LAY_EDGE)
if (R.r.mode & R_EDGE)
- edge_enhance_add(pa, rl->rectf, edgerect);
+ edge_enhance_add(pa, rect, edgerect);
if (rl->passflag & SCE_PASS_VECTOR)
reset_sky_speed(pa, rl);
@@ -1319,6 +1339,7 @@ void zbufshade_tile(RenderPart *pa)
pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
for (rl= rr->layers.first; rl; rl= rl->next) {
+ float *rect= RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK))
pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask");
@@ -1342,7 +1363,7 @@ void zbufshade_tile(RenderPart *pa)
rr->renlay= rl;
if (rl->layflag & SCE_LAY_SOLID) {
- const float *fcol= rl->rectf;
+ const float *fcol = rect;
const int *ro= pa->recto, *rp= pa->rectp, *rz= pa->rectz;
int x, y, offs=0, seed;
@@ -1405,11 +1426,11 @@ void zbufshade_tile(RenderPart *pa)
rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer");
/* swap for live updates */
- SWAP(float *, rl->acolrect, rl->rectf);
- zbuffer_transp_shade(pa, rl, rl->rectf, NULL);
- SWAP(float *, rl->acolrect, rl->rectf);
+ SWAP(float *, rl->acolrect, rect);
+ zbuffer_transp_shade(pa, rl, rect, NULL);
+ SWAP(float *, rl->acolrect, rect);
- fcol= rl->rectf; acol= rl->acolrect;
+ fcol= rect; acol= rl->acolrect;
for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) {
addAlphaOverFloat(fcol, acol);
}
@@ -1427,7 +1448,7 @@ void zbufshade_tile(RenderPart *pa)
if (!R.test_break(R.tbh)) {
if (rl->layflag & SCE_LAY_EDGE)
if (R.r.mode & R_EDGE)
- edge_enhance_add(pa, rl->rectf, edgerect);
+ edge_enhance_add(pa, rect, edgerect);
}
if (rl->passflag & SCE_PASS_VECTOR)
@@ -1654,7 +1675,7 @@ void zbufshade_sss_tile(RenderPart *pa)
return;
}
- fcol= rl->rectf;
+ fcol= RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
co= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSCo");
color= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSColor");
@@ -1938,6 +1959,7 @@ void add_halo_flare(Render *re)
RenderLayer *rl;
HaloRen *har;
int a, mode;
+ float *rect;
/* for now, we get the first renderlayer in list with halos set */
for (rl= rr->layers.first; rl; rl= rl->next) {
@@ -1945,8 +1967,11 @@ void add_halo_flare(Render *re)
if ((rl->layflag & SCE_LAY_HALO) == 0)
continue;
- if (rl->rectf==NULL)
- continue;
+
+ rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, re->viewname);
+
+ if (rl==NULL || rect)
+ return;
mode= R.r.mode;
R.r.mode &= ~R_PANORAMA;
@@ -1958,7 +1983,7 @@ void add_halo_flare(Render *re)
if (har->flarec && (har->lay & rl->lay)) {
do_draw = true;
- renderflare(rr, rl->rectf, har);
+ renderflare(rr, rect, har);
}
}
diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c
index 01055d87a38..5a5e67e1e43 100644
--- a/source/blender/render/intern/source/shadeinput.c
+++ b/source/blender/render/intern/source/shadeinput.c
@@ -423,14 +423,11 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert
}
if (texco & TEXCO_GLOB) {
- copy_v3_v3(shi->gl, shi->co);
- mul_m4_v3(R.viewinv, shi->gl);
+ mul_v3_m4v3(shi->gl, R.viewinv, shi->co);
if (shi->osatex) {
- copy_v3_v3(shi->dxgl, shi->dxco);
- mul_mat3_m4_v3(R.viewinv, shi->dxgl);
- copy_v3_v3(shi->dygl, shi->dyco);
- mul_mat3_m4_v3(R.viewinv, shi->dygl);
+ mul_v3_mat3_m4v3(shi->dxgl, R.viewinv, shi->dxco);
+ mul_v3_mat3_m4v3(shi->dygl, R.viewinv, shi->dyco);
}
}
@@ -633,7 +630,7 @@ void shade_input_calc_viewco(ShadeInput *shi, float x, float y, float z, float v
dyco[2] = 0.0f;
if (dxyview) {
- if (co[2] != 0.0f) fac = 1.0f / co[2]; else fac = 0.0f;
+ fac = (co[2] != 0.0f) ? (1.0f / co[2]) : 0.0f;
dxyview[0] = -R.viewdx * fac;
dxyview[1] = -R.viewdy * fac;
}
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index 63a97a04b39..b29038b2c34 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -55,6 +55,8 @@
#include "shading.h" /* own include */
+#include "IMB_colormanagement.h"
+
/* could enable at some point but for now there are far too many conversions */
#ifdef __GNUC__
# pragma GCC diagnostic ignored "-Wdouble-promotion"
@@ -948,7 +950,7 @@ static void ramp_diffuse_result(float *diff, ShadeInput *shi)
if (ma->ramp_col) {
if (ma->rampin_col==MA_RAMP_IN_RESULT) {
- float fac = rgb_to_grayscale(diff);
+ float fac = IMB_colormanagement_get_luminance(diff);
do_colorband(ma->ramp_col, fac, col);
/* blending method */
@@ -960,7 +962,7 @@ static void ramp_diffuse_result(float *diff, ShadeInput *shi)
}
/* r,g,b denote energy, ramp is used with different values to make new material color */
-static void add_to_diffuse(float *diff, ShadeInput *shi, float is, float r, float g, float b)
+static void add_to_diffuse(float diff[3], const ShadeInput *shi, const float is, const float rgb[3])
{
Material *ma= shi->mat;
@@ -969,9 +971,9 @@ static void add_to_diffuse(float *diff, ShadeInput *shi, float is, float r, floa
/* MA_RAMP_IN_RESULT is exceptional */
if (ma->rampin_col==MA_RAMP_IN_RESULT) {
/* normal add */
- diff[0] += r * shi->r;
- diff[1] += g * shi->g;
- diff[2] += b * shi->b;
+ diff[0] += rgb[0] * shi->r;
+ diff[1] += rgb[1] * shi->g;
+ diff[2] += rgb[2] * shi->b;
}
else {
float colt[3], col[4];
@@ -980,40 +982,37 @@ static void add_to_diffuse(float *diff, ShadeInput *shi, float is, float r, floa
/* input */
switch (ma->rampin_col) {
case MA_RAMP_IN_ENERGY:
- /* should use 'rgb_to_grayscale' but we only have a vector version */
- fac= 0.3f*r + 0.58f*g + 0.12f*b;
+ fac = IMB_colormanagement_get_luminance(rgb);
break;
case MA_RAMP_IN_SHADER:
- fac= is;
+ fac = is;
break;
case MA_RAMP_IN_NOR:
- fac= shi->view[0]*shi->vn[0] + shi->view[1]*shi->vn[1] + shi->view[2]*shi->vn[2];
+ fac = dot_v3v3(shi->view, shi->vn);
break;
default:
- fac= 0.0f;
+ fac = 0.0f;
break;
}
do_colorband(ma->ramp_col, fac, col);
/* blending method */
- fac= col[3]*ma->rampfac_col;
- colt[0]= shi->r;
- colt[1]= shi->g;
- colt[2]= shi->b;
+ fac = col[3] * ma->rampfac_col;
+ copy_v3_v3(colt, &shi->r);
ramp_blend(ma->rampblend_col, colt, fac, col);
/* output to */
- diff[0] += r * colt[0];
- diff[1] += g * colt[1];
- diff[2] += b * colt[2];
+ diff[0] += rgb[0] * colt[0];
+ diff[1] += rgb[1] * colt[1];
+ diff[2] += rgb[2] * colt[2];
}
}
else {
- diff[0] += r * shi->r;
- diff[1] += g * shi->g;
- diff[2] += b * shi->b;
+ diff[0] += rgb[0] * shi->r;
+ diff[1] += rgb[1] * shi->g;
+ diff[2] += rgb[2] * shi->b;
}
}
@@ -1023,7 +1022,7 @@ static void ramp_spec_result(float spec_col[3], ShadeInput *shi)
if (ma->ramp_spec && (ma->rampin_spec==MA_RAMP_IN_RESULT)) {
float col[4];
- float fac = rgb_to_grayscale(spec_col);
+ float fac = IMB_colormanagement_get_luminance(spec_col);
do_colorband(ma->ramp_spec, fac, col);
@@ -1482,20 +1481,42 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
/* in case 'no diffuse' we still do most calculus, spec can be in shadow.*/
if (!(lar->mode & LA_NO_DIFF)) {
if (i>0.0f) {
- if (ma->mode & MA_SHADOW_TRA)
- add_to_diffuse(shr->shad, shi, is, i*shadfac[0]*lacol[0], i*shadfac[1]*lacol[1], i*shadfac[2]*lacol[2]);
- else
- add_to_diffuse(shr->shad, shi, is, i*lacol[0], i*lacol[1], i*lacol[2]);
+ if (ma->mode & MA_SHADOW_TRA) {
+ const float tcol[3] = {
+ i * shadfac[0] * lacol[0],
+ i * shadfac[1] * lacol[1],
+ i * shadfac[2] * lacol[2],
+ };
+ add_to_diffuse(shr->shad, shi, is, tcol);
+ }
+ else {
+ const float tcol[3] = {
+ i * lacol[0],
+ i * lacol[1],
+ i * lacol[2],
+ };
+ add_to_diffuse(shr->shad, shi, is, tcol);
+ }
}
/* add light for colored shadow */
if (i_noshad>i && !(lashdw[0]==0 && lashdw[1]==0 && lashdw[2]==0)) {
- add_to_diffuse(shr->shad, shi, is, lashdw[0]*(i_noshad-i)*lacol[0], lashdw[1]*(i_noshad-i)*lacol[1], lashdw[2]*(i_noshad-i)*lacol[2]);
+ const float tcol[3] = {
+ lashdw[0] * (i_noshad - i) * lacol[0],
+ lashdw[1] * (i_noshad - i) * lacol[1],
+ lashdw[2] * (i_noshad - i) * lacol[2],
+ };
+ add_to_diffuse(shr->shad, shi, is, tcol);
}
if (i_noshad>0.0f) {
if (passflag & (SCE_PASS_DIFFUSE|SCE_PASS_SHADOW) ||
((passflag & SCE_PASS_COMBINED) && !(shi->combinedflag & SCE_PASS_SHADOW)))
{
- add_to_diffuse(shr->diff, shi, is, i_noshad*lacol[0], i_noshad*lacol[1], i_noshad*lacol[2]);
+ const float tcol[3] = {
+ i_noshad * lacol[0],
+ i_noshad * lacol[1],
+ i_noshad * lacol[2]
+ };
+ add_to_diffuse(shr->diff, shi, is, tcol);
}
else {
copy_v3_v3(shr->diff, shr->shad);
@@ -1619,10 +1640,10 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
if (shi->mat->shadowonly_flag == MA_SO_OLD) {
/* Old "Shadows Only" */
- accum+= (1.0f-visifac) + (visifac)*rgb_to_grayscale(shadfac)*shadfac[3];
+ accum+= (1.0f-visifac) + (visifac)*IMB_colormanagement_get_luminance(shadfac)*shadfac[3];
}
else {
- shaded += rgb_to_grayscale(shadfac)*shadfac[3] * visifac * lar->energy;
+ shaded += IMB_colormanagement_get_luminance(shadfac)*shadfac[3] * visifac * lar->energy;
if (shi->mat->shadowonly_flag == MA_SO_SHADOW) {
lightness += visifac * lar->energy;
@@ -1671,26 +1692,26 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
if (R.wrld.aomix==WO_AOADD) {
if (shi->mat->shadowonly_flag == MA_SO_OLD) {
- f= f*(1.0f - rgb_to_grayscale(shi->ao));
+ f= f*(1.0f - IMB_colormanagement_get_luminance(shi->ao));
shr->alpha= (shr->alpha + f)*f;
}
else {
- shr->alpha -= f*rgb_to_grayscale(shi->ao);
+ shr->alpha -= f*IMB_colormanagement_get_luminance(shi->ao);
if (shr->alpha<0.0f) shr->alpha=0.0f;
}
}
else /* AO Multiply */
- shr->alpha= (1.0f - f)*shr->alpha + f*(1.0f - (1.0f - shr->alpha)*rgb_to_grayscale(shi->ao));
+ shr->alpha= (1.0f - f)*shr->alpha + f*(1.0f - (1.0f - shr->alpha)*IMB_colormanagement_get_luminance(shi->ao));
}
if (R.wrld.mode & WO_ENV_LIGHT) {
if (shi->mat->shadowonly_flag == MA_SO_OLD) {
- f= R.wrld.ao_env_energy*shi->amb*(1.0f - rgb_to_grayscale(shi->env));
+ f= R.wrld.ao_env_energy*shi->amb*(1.0f - IMB_colormanagement_get_luminance(shi->env));
shr->alpha= (shr->alpha + f)*f;
}
else {
f= R.wrld.ao_env_energy*shi->amb;
- shr->alpha -= f*rgb_to_grayscale(shi->env);
+ shr->alpha -= f*IMB_colormanagement_get_luminance(shi->env);
if (shr->alpha<0.0f) shr->alpha=0.0f;
}
}
diff --git a/source/blender/render/intern/source/texture_ocean.c b/source/blender/render/intern/source/texture_ocean.c
index 5261374b34d..a932123243d 100644
--- a/source/blender/render/intern/source/texture_ocean.c
+++ b/source/blender/render/intern/source/texture_ocean.c
@@ -73,7 +73,7 @@ int ocean_texture(Tex *tex, const float texvec[2], TexResult *texres)
return 0;
}
else {
- const int do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS);
+ const bool do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS) != 0;
int cfra = R.r.cfra;
int retval = TEX_INT;
diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c
index d5c4c407bf6..2c0917243a3 100644
--- a/source/blender/render/intern/source/volumetric.c
+++ b/source/blender/render/intern/source/volumetric.c
@@ -41,6 +41,8 @@
#include "RE_shader_ext.h"
+#include "IMB_colormanagement.h"
+
#include "DNA_material_types.h"
#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
@@ -504,7 +506,7 @@ static void vol_shade_one_lamp(struct ShadeInput *shi, const float co[3], const
if (shi->mat->vol.shadeflag & MA_VOL_RECV_EXT_SHADOW) {
mul_v3_fl(lacol, vol_get_shadow(shi, lar, co));
- if (rgb_to_luma_y(lacol) < 0.001f) return;
+ if (IMB_colormanagement_get_luminance(lacol) < 0.001f) return;
}
/* find minimum of volume bounds, or lamp coord */
@@ -538,7 +540,7 @@ static void vol_shade_one_lamp(struct ShadeInput *shi, const float co[3], const
}
}
- if (rgb_to_luma_y(lacol) < 0.001f) return;
+ if (IMB_colormanagement_get_luminance(lacol) < 0.001f) return;
normalize_v3(lv);
p = vol_get_phasefunc(shi, shi->mat->vol.asymmetry, view, lv);
@@ -620,7 +622,7 @@ static void volumeintegrate(struct ShadeInput *shi, float col[4], const float co
if (t0 > t1 * 0.25f) {
/* only use depth cutoff after we've traced a little way into the volume */
- if (rgb_to_luma_y(tr) < shi->mat->vol.depth_cutoff) break;
+ if (IMB_colormanagement_get_luminance(tr) < shi->mat->vol.depth_cutoff) break;
}
vol_get_emission(shi, emit_col, p);
@@ -649,7 +651,7 @@ static void volumeintegrate(struct ShadeInput *shi, float col[4], const float co
add_v3_v3(col, radiance);
/* alpha <-- transmission luminance */
- col[3] = 1.0f - rgb_to_luma_y(tr);
+ col[3] = 1.0f - IMB_colormanagement_get_luminance(tr);
}
/* the main entry point for volume shading */
@@ -790,7 +792,7 @@ void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct
copy_v3_v3(shr->combined, tr);
- shr->combined[3] = 1.0f - rgb_to_luma_y(tr);
+ shr->combined[3] = 1.0f - IMB_colormanagement_get_luminance(tr);
shr->alpha = shr->combined[3];
}
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
index 7e8f0e3e9fc..b6628796e0d 100644
--- a/source/blender/render/intern/source/zbuf.c
+++ b/source/blender/render/intern/source/zbuf.c
@@ -330,8 +330,8 @@ static void zbuffillAc4(ZSpan *zspan, int obi, int zvlnr,
/* clipped */
if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
- if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
- if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+ my0 = max_ii(zspan->miny1, zspan->miny2);
+ my2 = min_ii(zspan->maxy1, zspan->maxy2);
if (my2<my0) return;
@@ -1073,8 +1073,8 @@ static void zbuffillGLinv4(ZSpan *zspan, int obi, int zvlnr,
/* clipped */
if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
- if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
- if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+ my0 = max_ii(zspan->miny1, zspan->miny2);
+ my2 = min_ii(zspan->maxy1, zspan->maxy2);
// printf("my %d %d\n", my0, my2);
if (my2<my0) return;
@@ -1196,8 +1196,8 @@ static void zbuffillGL4(ZSpan *zspan, int obi, int zvlnr,
/* clipped */
if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
- if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
- if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+ my0 = max_ii(zspan->miny1, zspan->miny2);
+ my2 = min_ii(zspan->maxy1, zspan->maxy2);
// printf("my %d %d\n", my0, my2);
if (my2<my0) return;
@@ -1324,8 +1324,8 @@ static void zbuffillGL_onlyZ(ZSpan *zspan, int UNUSED(obi), int UNUSED(zvlnr),
/* clipped */
if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
- if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
- if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+ my0 = max_ii(zspan->miny1, zspan->miny2);
+ my2 = min_ii(zspan->maxy1, zspan->maxy2);
// printf("my %d %d\n", my0, my2);
if (my2<my0) return;
@@ -1426,8 +1426,8 @@ void zspan_scanconvert_strand(ZSpan *zspan, void *handle, float *v1, float *v2,
/* clipped */
if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
- if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
- if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+ my0 = max_ii(zspan->miny1, zspan->miny2);
+ my2 = min_ii(zspan->maxy1, zspan->maxy2);
// printf("my %d %d\n", my0, my2);
if (my2<my0) return;
@@ -1513,7 +1513,7 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *
float x0, y0, x1, y1, x2, y2, z0, z1, z2;
float u, v, uxd, uyd, vxd, vyd, uy0, vy0, xx1;
const float *span1, *span2;
- int x, y, sn1, sn2, rectx= zspan->rectx, my0, my2;
+ int i, j, x, y, sn1, sn2, rectx = zspan->rectx, my0, my2;
/* init */
zbuf_init_span(zspan);
@@ -1526,8 +1526,8 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *
/* clipped */
if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
- if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
- if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+ my0 = max_ii(zspan->miny1, zspan->miny2);
+ my2 = min_ii(zspan->maxy1, zspan->maxy2);
// printf("my %d %d\n", my0, my2);
if (my2<my0) return;
@@ -1574,7 +1574,7 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *
span2= zspan->span1+my2;
}
- for (y=my2; y>=my0; y--, span1--, span2--) {
+ for (i = 0, y = my2; y >= my0; i++, y--, span1--, span2--) {
sn1= floor(*span1);
sn2= floor(*span2);
@@ -1583,14 +1583,12 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *
if (sn2>=rectx) sn2= rectx-1;
if (sn1<0) sn1= 0;
- u= (double)sn1*uxd + uy0;
- v= (double)sn1*vxd + vy0;
-
- for (x= sn1; x<=sn2; x++, u+=uxd, v+=vxd)
- func(handle, x, y, u, v);
+ u = (((double)sn1 * uxd) + uy0) - (i * uyd);
+ v = (((double)sn1 * vxd) + vy0) - (i * vyd);
- uy0 -= uyd;
- vy0 -= vyd;
+ for (j = 0, x = sn1; x <= sn2; j++, x++) {
+ func(handle, x, y, u + (j * uxd), v + (j * vxd));
+ }
}
}
@@ -2482,8 +2480,8 @@ static void zbuffill_sss(ZSpan *zspan, int obi, int zvlnr,
/* clipped */
if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
- if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
- if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+ my0 = max_ii(zspan->miny1, zspan->miny2);
+ my2 = min_ii(zspan->maxy1, zspan->maxy2);
if (my2<my0) return;
@@ -2683,8 +2681,8 @@ static void zbuf_fill_in_rgba(ZSpan *zspan, DrawBufPixel *col, float *v1, float
/* clipped */
if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
- if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
- if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+ my0 = max_ii(zspan->miny1, zspan->miny2);
+ my2 = min_ii(zspan->maxy1, zspan->maxy2);
// printf("my %d %d\n", my0, my2);
if (my2<my0) return;
@@ -3961,7 +3959,7 @@ static void reset_sky_speedvectors(RenderPart *pa, RenderLayer *rl, float *rectf
float *fp, *col;
int a;
- fp= RE_RenderLayerGetPass(rl, SCE_PASS_VECTOR);
+ fp = RE_RenderLayerGetPass(rl, SCE_PASS_VECTOR, R.viewname);
if (fp==NULL) return;
col= rectf+3;
@@ -4054,9 +4052,10 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
/* zero alpha pixels get speed vector max again */
if (addpassflag & SCE_PASS_VECTOR)
- if (rl->layflag & SCE_LAY_SOLID)
- reset_sky_speedvectors(pa, rl, rl->acolrect?rl->acolrect:rl->rectf); /* if acolrect is set we use it */
-
+ if (rl->layflag & SCE_LAY_SOLID) {
+ float *rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ reset_sky_speedvectors(pa, rl, rl->acolrect ? rl->acolrect : rect); /* if acolrect is set we use it */
+ }
/* filtered render, for now we assume only 1 filter size */
if (pa->crop) {
crop= 1;
@@ -4241,8 +4240,9 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
alpha= samp_shr[a].combined[3];
if (alpha!=0.0f) {
RenderLayer *rl= ssamp.rlpp[a];
-
- addAlphaOverFloat(rl->rectf + 4*od, samp_shr[a].combined);
+
+ float *rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ addAlphaOverFloat(rect + 4 * od, samp_shr[a].combined);
add_transp_passes(rl, od, &samp_shr[a], alpha);
if (addpassflag & SCE_PASS_VECTOR)
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index df5826338c0..d5e360de3d1 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -64,6 +64,7 @@ set(SRC
intern/wm_operators.c
intern/wm_subwindow.c
intern/wm_window.c
+ intern/wm_stereo.c
intern/wm_widgets.c
intern/wm_generic_widgets.c
3d_widgets/arrow_widget.c
@@ -83,6 +84,13 @@ set(SRC
3d_widgets/ui_widget_library.h
)
+if(WITH_AUDASPACE)
+ list(APPEND INC
+ ../../../intern/audaspace/intern
+ )
+ add_definitions(-DWITH_AUDASPACE)
+endif()
+
add_definitions(${GL_DEFINITIONS})
if(WITH_INTERNATIONAL)
diff --git a/source/blender/windowmanager/SConscript b/source/blender/windowmanager/SConscript
index cb3e9c2639d..fc9690c9076 100644
--- a/source/blender/windowmanager/SConscript
+++ b/source/blender/windowmanager/SConscript
@@ -36,6 +36,7 @@ incs = [
'#/intern/ghost',
'#/intern/guardedalloc',
'#/intern/memutil',
+ '#/intern/audaspace/intern',
'#/source/gameengine/BlenderRoutines',
env['BF_GLEW_INC'],
'#/intern/glew-mx',
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 5040e722450..c08a17396aa 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -54,7 +54,6 @@ struct wmEvent;
struct wmEventHandler;
struct wmGesture;
struct wmJob;
-struct wmNotifier;
struct wmOperatorType;
struct wmOperator;
struct wmWidget;
@@ -65,7 +64,6 @@ struct wmWidgetMapType;
struct rcti;
struct PointerRNA;
struct PropertyRNA;
-struct EnumPropertyItem;
struct MenuType;
struct wmDropBox;
struct wmDrag;
@@ -113,6 +111,7 @@ void WM_window_open_temp (struct bContext *C, struct rcti *position, int type);
/* returns true if draw method is triple buffer */
bool WM_is_draw_triple(struct wmWindow *win);
+bool WM_stereo3d_enabled(struct wmWindow *win, bool only_fullscreen_test);
/* files */
@@ -160,7 +159,7 @@ typedef void (*wmUIHandlerRemoveFunc)(struct bContext *C, void *userdata);
struct wmEventHandler *WM_event_add_ui_handler(
const struct bContext *C, ListBase *handlers,
wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove,
- void *userdata, const bool accept_dbl_click);
+ void *userdata, const char flag);
void WM_event_remove_ui_handler(
ListBase *handlers,
wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove,
@@ -174,23 +173,42 @@ void WM_event_free_ui_handler_all(
struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op);
void WM_event_remove_handlers(struct bContext *C, ListBase *handlers);
+/* handler flag */
+enum {
+ WM_HANDLER_BLOCKING = (1 << 0), /* after this handler all others are ignored */
+ WM_HANDLER_ACCEPT_DBL_CLICK = (1 << 1), /* handler accepts double key press events */
+
+ /* internal */
+ WM_HANDLER_DO_FREE = (1 << 7), /* handler tagged to be freed in wm_handlers_do() */
+};
+
struct wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes);
/* mouse */
void WM_event_add_mousemove(struct bContext *C);
bool WM_modal_tweak_exit(const struct wmEvent *event, int tweak_event);
+bool WM_event_is_absolute(const struct wmEvent *event);
/* notifiers */
void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference);
void WM_main_add_notifier(unsigned int type, void *reference);
void WM_main_remove_notifier_reference(const void *reference);
+void WM_main_remove_editor_id_reference(const struct ID *id);
/* reports */
+void WM_report_banner_show(const struct bContext *C);
void WM_report(const struct bContext *C, ReportType type, const char *message);
void WM_reportf(const struct bContext *C, ReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(3, 4);
-void wm_event_add(struct wmWindow *win, const struct wmEvent *event_to_add);
-void wm_event_init_from_window(struct wmWindow *win, struct wmEvent *event);
+void wm_event_add_ex(
+ struct wmWindow *win, const struct wmEvent *event_to_add,
+ const struct wmEvent *event_to_add_after)
+ ATTR_NONNULL(1, 2);
+void wm_event_add(
+ struct wmWindow *win, const struct wmEvent *event_to_add)
+ ATTR_NONNULL(1, 2);
+
+void wm_event_init_from_window(struct wmWindow *win, struct wmEvent *event);
/* at maximum, every timestep seconds it triggers event_type events */
@@ -291,11 +309,11 @@ bool WM_operator_last_properties_store(struct wmOperator *op);
/* flags for WM_operator_properties_filesel */
#define WM_FILESEL_RELPATH (1 << 0)
-#define WM_FILESEL_DIRECTORY (1 << 1)
-#define WM_FILESEL_FILENAME (1 << 2)
-#define WM_FILESEL_FILEPATH (1 << 3)
-#define WM_FILESEL_FILES (1 << 4)
-
+#define WM_FILESEL_DIRECTORY (1 << 1)
+#define WM_FILESEL_FILENAME (1 << 2)
+#define WM_FILESEL_FILEPATH (1 << 3)
+#define WM_FILESEL_FILES (1 << 4)
+#define WM_FILESEL_IMAGE_COLLAPSE (1 << 5)
/* operator as a python command (resultuing string must be freed) */
char *WM_operator_pystring_ex(struct bContext *C, struct wmOperator *op,
@@ -400,6 +418,8 @@ enum {
WM_JOB_TYPE_OBJECT_SIM_FLUID,
WM_JOB_TYPE_OBJECT_BAKE_TEXTURE,
WM_JOB_TYPE_OBJECT_BAKE,
+ WM_JOB_TYPE_PTCACHE_EXPORT,
+ WM_JOB_TYPE_CACHELIBRARY_BAKE,
WM_JOB_TYPE_FILESEL_THUMBNAIL,
WM_JOB_TYPE_CLIP_BUILD_PROXY,
WM_JOB_TYPE_CLIP_TRACK_MARKERS,
@@ -550,6 +570,7 @@ void WIDGET_dial_set_color(struct wmWidget *widget, float color[4]);
void WIDGET_dial_set_direction(struct wmWidget *widget, float direction[3]);
struct wmWidget *WIDGET_rect_transform_new(struct wmWidgetGroup *wgroup, int style, float width, float height);
+void WIDGET_rect_transform_set_offset(struct wmWidget *widget, float offset[2]);
struct wmWidget *WIDGET_facemap_new(struct wmWidgetGroup *wgroup, int style, struct Object *ob, int facemap);
void WIDGET_facemap_set_color(struct wmWidget *widget, float color[4]);
diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h
index c6c7314e963..fdde28c6bf1 100644
--- a/source/blender/windowmanager/WM_keymap.h
+++ b/source/blender/windowmanager/WM_keymap.h
@@ -101,7 +101,8 @@ int WM_keymap_map_type_get(struct wmKeyMapItem *kmi);
const char *WM_key_event_string(short type);
int WM_key_event_operator_id(
const struct bContext *C, const char *opname, int opcontext,
- struct IDProperty *properties, const bool is_hotkey, struct wmKeyMap **keymap_r);
+ struct IDProperty *properties, const bool is_hotkey,
+ struct wmKeyMap **r_keymap);
char *WM_key_event_operator_string(
const struct bContext *C, const char *opname, int opcontext,
struct IDProperty *properties, const bool is_strict, char *str, int len);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index b670552f982..3a984fdc4d2 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -109,7 +109,6 @@ extern "C" {
struct bContext;
struct wmEvent;
struct wmWindowManager;
-struct uiLayout;
struct wmOperator;
struct ImBuf;
@@ -124,17 +123,22 @@ struct ImBuf;
/* ************** wmOperatorType ************************ */
/* flag */
-#define OPTYPE_REGISTER 1 /* register operators in stack after finishing */
-#define OPTYPE_UNDO 2 /* do undo push after after */
-#define OPTYPE_BLOCKING 4 /* let blender grab all input from the WM (X11) */
-#define OPTYPE_MACRO 8
-#define OPTYPE_GRAB_POINTER 16 /* grabs the cursor and optionally enables continuous cursor wrapping */
-#define OPTYPE_PRESET 32 /* show preset menu */
-#define OPTYPE_INTERNAL 64 /* some operators are mainly for internal use
- * and don't make sense to be accessed from the
- * search menu, even if poll() returns true.
- * currently only used for the search toolbox */
-#define OPTYPE_LOCK_BYPASS 128 /* Allow operator to run when interface is locked */
+enum {
+ OPTYPE_REGISTER = (1 << 0), /* register operators in stack after finishing */
+ OPTYPE_UNDO = (1 << 1), /* do undo push after after */
+ OPTYPE_BLOCKING = (1 << 2), /* let blender grab all input from the WM (X11) */
+ OPTYPE_MACRO = (1 << 3),
+ OPTYPE_GRAB_CURSOR = (1 << 4), /* grabs the cursor and optionally enables continuous cursor wrapping */
+ OPTYPE_PRESET = (1 << 5), /* show preset menu */
+
+ /* some operators are mainly for internal use
+ * and don't make sense to be accessed from the
+ * search menu, even if poll() returns true.
+ * currently only used for the search toolbox */
+ OPTYPE_INTERNAL = (1 << 6),
+
+ OPTYPE_LOCK_BYPASS = (1 << 7), /* Allow operator to run when interface is locked */
+};
/* context to call operator in for WM_operator_name_call */
/* rna_ui.c contains EnumPropertyItem's of these, keep in sync */
@@ -373,6 +377,7 @@ typedef struct wmNotifier {
#define NS_EDITMODE_ARMATURE (8<<8)
#define NS_MODE_POSE (9<<8)
#define NS_MODE_PARTICLE (10<<8)
+#define NS_MODE_HAIR (11<<8)
/* subtype 3d view editing */
#define NS_VIEW3D_GPU (16<<8)
@@ -454,7 +459,7 @@ typedef struct wmEvent {
const char *keymap_idname;
/* tablet info, only use when the tablet is active */
- struct wmTabletData *tablet_data;
+ const struct wmTabletData *tablet_data;
/* custom data */
short custom; /* custom data type, stylus, 6dof, see wm_event_types.h */
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 80da6b7490f..b43425ef6cb 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -228,7 +228,7 @@ uiListType *WM_uilisttype_find(const char *idname, bool quiet)
bool WM_uilisttype_add(uiListType *ult)
{
- BLI_ghash_insert(uilisttypes_hash, (void *)ult->idname, ult);
+ BLI_ghash_insert(uilisttypes_hash, ult->idname, ult);
return 1;
}
@@ -285,7 +285,7 @@ MenuType *WM_menutype_find(const char *idname, bool quiet)
bool WM_menutype_add(MenuType *mt)
{
- BLI_ghash_insert(menutypes_hash, (void *)mt->idname, mt);
+ BLI_ghash_insert(menutypes_hash, mt->idname, mt);
return true;
}
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index 68fd32cb450..d84b65847ca 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -313,21 +313,22 @@ void WM_cursor_time(wmWindow *win, int nr)
}
-/* ******************************************************************
- * Custom Cursor Description:
+/**
+ * Custom Cursor Description
+ * =========================
*
* Each bit represents a pixel, so 1 byte = 8 pixels,
* the bytes go Left to Right. Top to bottom
* the bits in a byte go right to left
* (ie; 0x01, 0x80 represents a line of 16 pix with the first and last pix set.)
*
- * A 0 in the bitmap = bg_color, a 1 fg_color
- * a 0 in the mask = transparent pix.
+ * - A 0 in the bitmap = bg_color, a 1 fg_color
+ * - a 0 in the mask = transparent pix.
*
* Until 32x32 cursors are supported on all platforms, the size of the
* small cursors MUST be 16x16.
*
- * Large cursors have a MAXSIZE of 32x32.
+ * Large cursors have a maximum size of 32x32.
*
* Other than that, the specified size of the cursors is just a guideline,
* However, the char array that defines the BM and MASK must be byte aligned.
@@ -335,18 +336,20 @@ void WM_cursor_time(wmWindow *win, int nr)
* (3 bytes = 17 bits rounded up to nearest whole byte). Pad extra bits
* in mask with 0's.
*
- * Setting big_bm = NULL disables the large version of the cursor.
+ * Setting `big_bm = NULL` disables the large version of the cursor.
*
- * *******************************************************************
+ * ----
*
* There is a nice Python GUI utility that can be used for drawing cursors in
* this format in the Blender source distribution, in
- * blender/source/tools/MakeCursor.py . Start it with $ python MakeCursor.py
- * It will copy its output to the console when you press 'Do it'.
+ * `./source/tools/utils/make_cursor_gui.py` .
*
+ * Start it with the command `python3 make_cursor_gui.py`
+ * It will copy its output to the console when you press 'Do it'.
*/
-/* Because defining a cursor mixes declarations and executable code
+/**
+ * Because defining a cursor mixes declarations and executable code
* each cursor needs it's own scoping block or it would be split up
* over several hundred lines of code. To enforce/document this better
* I define 2 pretty brain-dead macros so it's obvious what the extra "[]"
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 7440570f4a0..16fe9ca5142 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -48,9 +48,11 @@
#include "BIF_gl.h"
#include "BKE_context.h"
+#include "BKE_image.h"
#include "GHOST_C-api.h"
+#include "ED_node.h"
#include "ED_view3d.h"
#include "ED_screen.h"
@@ -165,6 +167,7 @@ static void wm_method_draw_full(bContext *C, wmWindow *win)
if (ar->swinid) {
CTX_wm_region_set(C, ar);
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
wm_paintcursor_draw(C, ar);
CTX_wm_region_set(C, NULL);
}
@@ -175,12 +178,14 @@ static void wm_method_draw_full(bContext *C, wmWindow *win)
}
ED_screen_draw(win);
+ win->screen->do_draw = false;
/* draw overlapping regions */
for (ar = screen->regionbase.first; ar; ar = ar->next) {
if (ar->swinid) {
CTX_wm_menu_set(C, ar);
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
CTX_wm_menu_set(C, NULL);
}
}
@@ -278,6 +283,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
if (ar->do_draw) {
CTX_wm_region_set(C, ar);
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
wm_paintcursor_draw(C, ar);
CTX_wm_region_set(C, NULL);
@@ -288,6 +294,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
if (ar->swap == WIN_FRONT_OK) {
CTX_wm_region_set(C, ar);
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
wm_paintcursor_draw(C, ar);
CTX_wm_region_set(C, NULL);
@@ -300,7 +307,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
}
}
}
-
+
wm_area_mark_invalid_backbuf(sa);
CTX_wm_area_set(C, NULL);
}
@@ -308,6 +315,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
/* after area regions so we can do area 'overlay' drawing */
if (screen->do_draw) {
ED_screen_draw(win);
+ win->screen->do_draw = false;
if (exchange)
screen->swap = WIN_FRONT_OK;
@@ -315,6 +323,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
else if (exchange) {
if (screen->swap == WIN_FRONT_OK) {
ED_screen_draw(win);
+ win->screen->do_draw = false;
screen->swap = WIN_BOTH_OK;
}
else if (screen->swap == WIN_BACK_OK)
@@ -328,6 +337,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
if (ar->swinid && ar->do_draw) {
CTX_wm_menu_set(C, ar);
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
CTX_wm_menu_set(C, NULL);
}
}
@@ -360,15 +370,6 @@ static void wm_method_draw_damage(bContext *C, wmWindow *win)
/* used. if not, multiple smaller ones are used, with */
/* worst case wasted space being 23.4% for 3x3 textures */
-#define MAX_N_TEX 3
-
-typedef struct wmDrawTriple {
- GLuint bind[MAX_N_TEX * MAX_N_TEX];
- int x[MAX_N_TEX], y[MAX_N_TEX];
- int nx, ny;
- GLenum target;
-} wmDrawTriple;
-
static void split_width(int x, int n, int *splitx, int *nx)
{
int a, newnx, waste;
@@ -405,16 +406,13 @@ static void split_width(int x, int n, int *splitx, int *nx)
}
}
-static void wm_draw_triple_free(wmWindow *win)
+static void wm_draw_triple_free(wmDrawTriple *triple)
{
- if (win->drawdata) {
- wmDrawTriple *triple = win->drawdata;
+ if (triple) {
glDeleteTextures(triple->nx * triple->ny, triple->bind);
MEM_freeN(triple);
-
- win->drawdata = NULL;
}
}
@@ -499,7 +497,7 @@ static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple)
return 1;
}
-static void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
+void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
{
const int winsize_x = WM_window_pixels_x(win);
const int winsize_y = WM_window_pixels_y(win);
@@ -571,7 +569,7 @@ static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple)
glBindTexture(triple->target, 0);
}
-static void wm_draw_region_blend(wmWindow *win, ARegion *ar)
+static void wm_draw_region_blend(wmWindow *win, ARegion *ar, wmDrawTriple *triple)
{
float fac = ED_region_blend_factor(ar);
@@ -580,7 +578,7 @@ static void wm_draw_region_blend(wmWindow *win, ARegion *ar)
wmSubWindowScissorSet(win, win->screen->mainwin, &ar->winrct, true);
glEnable(GL_BLEND);
- wm_triple_draw_textures(win, win->drawdata, 1.0f - fac);
+ wm_triple_draw_textures(win, triple, 1.0f - fac);
glDisable(GL_BLEND);
}
}
@@ -589,29 +587,46 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmDrawTriple *triple;
+ wmDrawData *dd, *dd_next, *drawdata = win->drawdata.first;
bScreen *screen = win->screen;
ScrArea *sa;
ARegion *ar;
- int copytex = 0;
+ int copytex = false;
- if (win->drawdata) {
+ if (drawdata && drawdata->triple) {
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
wmSubWindowSet(win, screen->mainwin);
- wm_triple_draw_textures(win, win->drawdata, 1.0f);
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f);
}
else {
- win->drawdata = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
+ /* we run it when we start OR when we turn stereo on */
+ if (drawdata == NULL) {
+ drawdata = MEM_callocN(sizeof(wmDrawData), "wmDrawData");
+ BLI_addhead(&win->drawdata, drawdata);
+ }
+
+ drawdata->triple = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
- if (!wm_triple_gen_textures(win, win->drawdata)) {
+ if (!wm_triple_gen_textures(win, drawdata->triple)) {
wm_draw_triple_fail(C, win);
return;
}
}
- triple = win->drawdata;
+ /* it means stereo was just turned off */
+ /* note: we are removing all drawdatas that are not the first */
+ for (dd = drawdata->next; dd; dd = dd_next) {
+ dd_next = dd->next;
+
+ BLI_remlink(&win->drawdata, dd);
+ wm_draw_triple_free(dd->triple);
+ MEM_freeN(dd);
+ }
+
+ triple = drawdata->triple;
/* draw marked area regions */
for (sa = screen->areabase.first; sa; sa = sa->next) {
@@ -619,16 +634,17 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->swinid && ar->do_draw) {
-
- if (ar->overlap == 0) {
+
+ if (ar->overlap == false) {
CTX_wm_region_set(C, ar);
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
CTX_wm_region_set(C, NULL);
- copytex = 1;
+ copytex = true;
}
}
}
-
+
wm_area_mark_invalid_backbuf(sa);
CTX_wm_area_set(C, NULL);
}
@@ -662,14 +678,15 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
/* draw overlapping area regions (always like popups) */
for (sa = screen->areabase.first; sa; sa = sa->next) {
CTX_wm_area_set(C, sa);
-
+
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->swinid && ar->overlap) {
CTX_wm_region_set(C, ar);
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
CTX_wm_region_set(C, NULL);
-
- wm_draw_region_blend(win, ar);
+
+ wm_draw_region_blend(win, ar, triple);
}
}
@@ -678,12 +695,14 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
/* after area regions so we can do area 'overlay' drawing */
ED_screen_draw(win);
+ win->screen->do_draw = false;
/* draw floating regions (menus) */
for (ar = screen->regionbase.first; ar; ar = ar->next) {
if (ar->swinid) {
CTX_wm_menu_set(C, ar);
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
CTX_wm_menu_set(C, NULL);
}
}
@@ -691,13 +710,188 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
/* always draw, not only when screen tagged */
if (win->gesture.first)
wm_gesture_draw(win);
-
+
/* needs pixel coords in screen */
if (wm->drags.first) {
wm_drags_draw(C, win, NULL);
}
}
+static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, StereoViews sview)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmDrawData *drawdata;
+ wmDrawTriple *triple_data, *triple_all;
+ bScreen *screen = win->screen;
+ ScrArea *sa;
+ ARegion *ar;
+ int copytex = false;
+ int id;
+
+ /* we store the triple_data in sequence to triple_all */
+ for (id = 0; id < 2; id++) {
+ drawdata = BLI_findlink(&win->drawdata, (sview * 2) + id);
+
+ if (drawdata && drawdata->triple) {
+ if (id == 0) {
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ wmSubWindowSet(win, screen->mainwin);
+
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+ }
+ }
+ else {
+ /* we run it when we start OR when we turn stereo on */
+ if (drawdata == NULL) {
+ drawdata = MEM_callocN(sizeof(wmDrawData), "wmDrawData");
+ BLI_addtail(&win->drawdata, drawdata);
+ }
+
+ drawdata->triple = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
+
+ if (!wm_triple_gen_textures(win, drawdata->triple)) {
+ wm_draw_triple_fail(C, win);
+ return;
+ }
+ }
+ }
+
+ triple_data = ((wmDrawData *) BLI_findlink(&win->drawdata, sview * 2))->triple;
+ triple_all = ((wmDrawData *) BLI_findlink(&win->drawdata, (sview * 2) + 1))->triple;
+
+ /* draw marked area regions */
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ CTX_wm_area_set(C, sa);
+
+ switch (sa->spacetype) {
+ case SPACE_IMAGE:
+ {
+ SpaceImage *sima = sa->spacedata.first;
+ sima->iuser.multiview_eye = sview;
+ break;
+ }
+ case SPACE_VIEW3D:
+ {
+ View3D *v3d = sa->spacedata.first;
+ BGpic *bgpic = v3d->bgpicbase.first;
+ v3d->multiview_eye = sview;
+ if (bgpic) bgpic->iuser.multiview_eye = sview;
+ break;
+ }
+ case SPACE_NODE:
+ {
+ SpaceNode *snode = sa->spacedata.first;
+ if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
+ Image *ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
+ ima->eye = sview;
+ }
+ break;
+ }
+ case SPACE_SEQ:
+ {
+ SpaceSeq *sseq = sa->spacedata.first;
+ sseq->multiview_eye = sview;
+ break;
+ }
+ }
+
+ /* draw marked area regions */
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->swinid && ar->do_draw) {
+
+ if (ar->overlap == false) {
+ CTX_wm_region_set(C, ar);
+ ED_region_do_draw(C, ar);
+
+ if (sview == STEREO_RIGHT_ID)
+ ar->do_draw = false;
+
+ CTX_wm_region_set(C, NULL);
+ copytex = true;
+ }
+ }
+ }
+
+ wm_area_mark_invalid_backbuf(sa);
+ CTX_wm_area_set(C, NULL);
+ }
+
+ if (copytex) {
+ wmSubWindowSet(win, screen->mainwin);
+
+ wm_triple_copy_textures(win, triple_data);
+ }
+
+ if (wm->paintcursors.first) {
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->swinid && ar->swinid == screen->subwinactive) {
+ CTX_wm_area_set(C, sa);
+ CTX_wm_region_set(C, ar);
+
+ /* make region ready for draw, scissor, pixelspace */
+ ED_region_set(C, ar);
+ wm_paintcursor_draw(C, ar);
+
+ CTX_wm_region_set(C, NULL);
+ CTX_wm_area_set(C, NULL);
+ }
+ }
+ }
+
+ wmSubWindowSet(win, screen->mainwin);
+ }
+
+ /* draw overlapping area regions (always like popups) */
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ CTX_wm_area_set(C, sa);
+
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->swinid && ar->overlap) {
+ CTX_wm_region_set(C, ar);
+ ED_region_do_draw(C, ar);
+ if (sview == STEREO_RIGHT_ID)
+ ar->do_draw = false;
+ CTX_wm_region_set(C, NULL);
+
+ wm_draw_region_blend(win, ar, triple_data);
+ }
+ }
+
+ CTX_wm_area_set(C, NULL);
+ }
+
+ /* after area regions so we can do area 'overlay' drawing */
+ ED_screen_draw(win);
+ if (sview == STEREO_RIGHT_ID)
+ win->screen->do_draw = false;
+
+ /* draw floating regions (menus) */
+ for (ar = screen->regionbase.first; ar; ar = ar->next) {
+ if (ar->swinid) {
+ CTX_wm_menu_set(C, ar);
+ ED_region_do_draw(C, ar);
+ if (sview == STEREO_RIGHT_ID)
+ ar->do_draw = false;
+ CTX_wm_menu_set(C, NULL);
+ }
+ }
+
+ /* always draw, not only when screen tagged */
+ if (win->gesture.first)
+ wm_gesture_draw(win);
+
+ /* needs pixel coords in screen */
+ if (wm->drags.first) {
+ wm_drags_draw(C, win, NULL);
+ }
+
+ /* copy the ui + overlays */
+ wmSubWindowSet(win, screen->mainwin);
+ wm_triple_copy_textures(win, triple_all);
+}
/****************** main update call **********************/
@@ -848,8 +1042,16 @@ void wm_draw_update(bContext *C)
wm_method_draw_overlap_all(C, win, 0);
else if (drawmethod == USER_DRAW_OVERLAP_FLIP)
wm_method_draw_overlap_all(C, win, 1);
- else // if (drawmethod == USER_DRAW_TRIPLE)
- wm_method_draw_triple(C, win);
+ else { /* USER_DRAW_TRIPLE */
+ if ((WM_stereo3d_enabled(win, false)) == false) {
+ wm_method_draw_triple(C, win);
+ }
+ else {
+ wm_method_draw_triple_multiview(C, win, STEREO_LEFT_ID);
+ wm_method_draw_triple_multiview(C, win, STEREO_RIGHT_ID);
+ wm_method_draw_stereo3d(C, win);
+ }
+ }
win->screen->do_draw_gesture = false;
win->screen->do_draw_paintcursor = false;
@@ -862,15 +1064,23 @@ void wm_draw_update(bContext *C)
}
}
+void wm_draw_data_free(wmWindow *win)
+{
+ wmDrawData *dd;
+
+ for (dd = win->drawdata.first; dd; dd = dd->next) {
+ wm_draw_triple_free(dd->triple);
+ }
+ BLI_freelistN(&win->drawdata);
+}
+
void wm_draw_window_clear(wmWindow *win)
{
bScreen *screen = win->screen;
ScrArea *sa;
ARegion *ar;
- int drawmethod = wm_automatic_draw_method(win);
- if (drawmethod == USER_DRAW_TRIPLE)
- wm_draw_triple_free(win);
+ wm_draw_data_free(win);
/* clear screen swap flags */
if (screen) {
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 5ba76f2205a..893e05b2093 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -63,6 +63,7 @@
#include "ED_fileselect.h"
#include "ED_info.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "ED_util.h"
@@ -96,7 +97,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA
/* ************ event management ************** */
-void wm_event_add(wmWindow *win, const wmEvent *event_to_add)
+void wm_event_add_ex(wmWindow *win, const wmEvent *event_to_add, const wmEvent *event_to_add_after)
{
wmEvent *event = MEM_mallocN(sizeof(wmEvent), "wmEvent");
@@ -104,7 +105,18 @@ void wm_event_add(wmWindow *win, const wmEvent *event_to_add)
update_tablet_data(win, event);
- BLI_addtail(&win->queue, event);
+ if (event_to_add_after == NULL) {
+ BLI_addtail(&win->queue, event);
+ }
+ else {
+ /* note, strictly speaking this breaks const-correctness, however we're only changing 'next' member */
+ BLI_insertlinkafter(&win->queue, (void *)event_to_add_after, event);
+ }
+}
+
+void wm_event_add(wmWindow *win, const wmEvent *event_to_add)
+{
+ wm_event_add_ex(win, event_to_add, NULL);
}
void wm_event_free(wmEvent *event)
@@ -123,7 +135,7 @@ void wm_event_free(wmEvent *event)
}
if (event->tablet_data) {
- MEM_freeN(event->tablet_data);
+ MEM_freeN((void *)event->tablet_data);
}
MEM_freeN(event);
@@ -217,6 +229,7 @@ void WM_main_remove_notifier_reference(const void *reference)
{
Main *bmain = G.main;
wmWindowManager *wm = bmain->wm.first;
+
if (wm) {
wmNotifier *note, *note_next;
@@ -232,6 +245,24 @@ void WM_main_remove_notifier_reference(const void *reference)
}
}
+void WM_main_remove_editor_id_reference(const ID *id)
+{
+ Main *bmain = G.main;
+ bScreen *sc;
+
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
+ ScrArea *sa;
+
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl;
+
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ ED_spacedata_id_unref(sl, id);
+ }
+ }
+ }
+}
+
static void wm_notifier_clear(wmNotifier *note)
{
/* NULL the entire notifier, only leaving (next, prev) members intact */
@@ -293,7 +324,7 @@ void wm_event_do_notifiers(bContext *C)
do_anim = true;
}
}
- if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE, NC_WM)) {
+ if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_WM)) {
ED_info_stats_clear(win->screen->scene);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL);
}
@@ -535,10 +566,9 @@ void WM_event_print(const wmEvent *event)
RNA_enum_identifier(event_type_items, event->type, &type_id);
RNA_enum_identifier(event_value_items, event->val, &val_id);
- printf("wmEvent type:%d / %s, val:%d / %s, \n"
- " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d, \n"
- " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', "
- " keymap_idname:%s, pointer:%p\n",
+ printf("wmEvent type:%d / %s, val:%d / %s,\n"
+ " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d,\n"
+ " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', keymap_idname:%s, pointer:%p\n",
event->type, type_id, event->val, val_id,
event->shift, event->ctrl, event->alt, event->oskey, event->keymodifier,
event->x, event->y, event->ascii,
@@ -548,17 +578,19 @@ void WM_event_print(const wmEvent *event)
if (ISNDOF(event->type)) {
const wmNDOFMotionData *ndof = event->customdata;
if (event->type == NDOF_MOTION) {
- printf(" ndof: rot: (%.4f %.4f %.4f),\n"
- " tx: (%.4f %.4f %.4f),\n"
- " dt: %.4f, progress: %d\n",
- UNPACK3(ndof->rvec),
- UNPACK3(ndof->tvec),
- ndof->dt, ndof->progress);
+ printf(" ndof: rot: (%.4f %.4f %.4f), tx: (%.4f %.4f %.4f), dt: %.4f, progress: %d\n",
+ UNPACK3(ndof->rvec), UNPACK3(ndof->tvec), ndof->dt, ndof->progress);
}
else {
/* ndof buttons printed already */
}
}
+
+ if (event->tablet_data) {
+ const wmTabletData *wmtab = event->tablet_data;
+ printf(" tablet: active: %d, pressure %.4f, tilt: (%.4f %.4f)\n",
+ wmtab->Active, wmtab->Pressure, wmtab->Xtilt, wmtab->Ytilt);
+ }
}
else {
printf("wmEvent - NULL\n");
@@ -567,26 +599,40 @@ void WM_event_print(const wmEvent *event)
#endif /* NDEBUG */
+/**
+ * Show the report in the info header.
+ */
+void WM_report_banner_show(const bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ ReportList *wm_reports = CTX_wm_reports(C);
+ ReportTimerInfo *rti;
+
+ /* After adding reports to the global list, reset the report timer. */
+ WM_event_remove_timer(wm, NULL, wm_reports->reporttimer);
+
+ /* Records time since last report was added */
+ wm_reports->reporttimer = WM_event_add_timer(wm, CTX_wm_window(C), TIMERREPORT, 0.05);
+
+ rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
+ wm_reports->reporttimer->customdata = rti;
+}
+
+bool WM_event_is_absolute(const wmEvent *event)
+{
+ return (event->tablet_data != NULL);
+}
+
static void wm_add_reports(const bContext *C, ReportList *reports)
{
/* if the caller owns them, handle this */
if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) {
-
- wmWindowManager *wm = CTX_wm_manager(C);
ReportList *wm_reports = CTX_wm_reports(C);
- ReportTimerInfo *rti;
/* add reports to the global list, otherwise they are not seen */
BLI_movelisttolist(&wm_reports->list, &reports->list);
-
- /* After adding reports to the global list, reset the report timer. */
- WM_event_remove_timer(wm, NULL, wm_reports->reporttimer);
-
- /* Records time since last report was added */
- wm_reports->reporttimer = WM_event_add_timer(wm, CTX_wm_window(C), TIMERREPORT, 0.05);
-
- rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
- wm_reports->reporttimer->customdata = rti;
+
+ WM_report_banner_show(C);
}
}
@@ -662,7 +708,8 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
wm_add_reports(C, op->reports);
}
-/* this function is mainly to check that the rules for freeing
+/**
+ * This function is mainly to check that the rules for freeing
* an operator are kept in sync.
*/
static bool wm_operator_register_check(wmWindowManager *wm, wmOperatorType *ot)
@@ -781,23 +828,29 @@ int WM_operator_call(bContext *C, wmOperator *op)
return WM_operator_call_ex(C, op, false);
}
-/* this is intended to be used when an invoke operator wants to call exec on its self
+/**
+ * This is intended to be used when an invoke operator wants to call exec on its self
* and is basically like running op->type->exec() directly, no poll checks no freeing,
- * since we assume whoever called invoke will take care of that */
+ * since we assume whoever called invoke will take care of that
+ */
int WM_operator_call_notest(bContext *C, wmOperator *op)
{
return wm_operator_exec_notest(C, op);
}
-/* do this operator again, put here so it can share above code */
+/**
+ * Execute this operator again, put here so it can share above code
+ */
int WM_operator_repeat(bContext *C, wmOperator *op)
{
return wm_operator_exec(C, op, true, true);
}
-/* true if WM_operator_repeat can run
+/**
+ * \return true if #WM_operator_repeat can run
* simple check for now but may become more involved.
- * To be sure the operator can run call WM_operator_poll(C, op->type) also, since this call
- * checks if WM_operator_repeat() can run at all, not that it WILL run at any time. */
+ * To be sure the operator can run call `WM_operator_poll(C, op->type)` also, since this call
+ * checks if WM_operator_repeat() can run at all, not that it WILL run at any time.
+ */
bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op)
{
if (op->type->exec != NULL) {
@@ -1003,8 +1056,9 @@ bool WM_operator_last_properties_store(wmOperator *UNUSED(op))
#endif
-static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event,
- PointerRNA *properties, ReportList *reports, const bool poll_only)
+static int wm_operator_invoke(
+ bContext *C, wmOperatorType *ot, wmEvent *event,
+ PointerRNA *properties, ReportList *reports, const bool poll_only)
{
int retval = OPERATOR_PASS_THROUGH;
@@ -1085,11 +1139,11 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event,
if (op->opm) {
wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) &&
- ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER));
+ ((op->opm->flag & OP_IS_MODAL_GRAB_CURSOR) || (op->opm->type->flag & OPTYPE_GRAB_CURSOR));
}
else {
wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) &&
- ((op->flag & OP_GRAB_POINTER) || (ot->flag & OPTYPE_GRAB_POINTER));
+ ((op->flag & OP_IS_MODAL_GRAB_CURSOR) || (ot->flag & OPTYPE_GRAB_CURSOR));
}
/* exception, cont. grab in header is annoying */
@@ -1101,7 +1155,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event,
}
if (wrap) {
- rcti *winrect = NULL;
+ const rcti *winrect = NULL;
ARegion *ar = CTX_wm_region(C);
ScrArea *sa = CTX_wm_area(C);
@@ -1110,7 +1164,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event,
{
winrect = &ar->winrct;
}
- else if (sa) {
+ else if (sa && BLI_rcti_isect_pt_v(&sa->totrct, &event->x)) {
winrect = &sa->totrct;
}
@@ -1139,12 +1193,15 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event,
return retval;
}
-/* WM_operator_name_call is the main accessor function
+/**
+ * #WM_operator_name_call is the main accessor function
* this is for python to access since its done the operator lookup
*
- * invokes operator in context */
-static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports,
- const short context, const bool poll_only)
+ * invokes operator in context
+ */
+static int wm_operator_call_internal(
+ bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports,
+ const short context, const bool poll_only)
{
wmEvent *event;
@@ -1153,7 +1210,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA
CTX_wm_operator_poll_msg_set(C, NULL);
/* dummie test */
- if (ot && C) {
+ if (ot) {
wmWindow *window = CTX_wm_window(C);
switch (context) {
@@ -1284,13 +1341,16 @@ int WM_operator_name_call(bContext *C, const char *opstring, short context, Poin
return 0;
}
-/* Similar to WM_operator_name_call called with WM_OP_EXEC_DEFAULT context.
- * - wmOperatorType is used instead of operator name since python already has the operator type
- * - poll() must be called by python before this runs.
- * - reports can be passed to this function (so python can report them as exceptions)
+/**
+ * Similar to #WM_operator_name_call called with #WM_OP_EXEC_DEFAULT context.
+ *
+ * - #wmOperatorType is used instead of operator name since python already has the operator type.
+ * - `poll()` must be called by python before this runs.
+ * - reports can be passed to this function (so python can report them as exceptions).
*/
-int WM_operator_call_py(bContext *C, wmOperatorType *ot, short context,
- PointerRNA *properties, ReportList *reports, const bool is_undo)
+int WM_operator_call_py(
+ bContext *C, wmOperatorType *ot, short context,
+ PointerRNA *properties, ReportList *reports, const bool is_undo)
{
int retval = OPERATOR_CANCELLED;
@@ -1337,7 +1397,7 @@ void wm_event_free_handler(wmEventHandler *handler)
}
/* only set context when area/region is part of screen */
-static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
+static void wm_handler_op_context(bContext *C, wmEventHandler *handler, const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
@@ -1358,10 +1418,27 @@ static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
}
else {
ARegion *ar;
+ wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : NULL;
CTX_wm_area_set(C, sa);
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar == handler->op_region)
- break;
+
+ if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) {
+ ar = BKE_area_find_region_xy(sa, handler->op_region_type, event->x, event->y);
+ if (ar) {
+ handler->op_region = ar;
+ }
+ }
+ else {
+ ar = NULL;
+ }
+
+ if (ar == NULL) {
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar == handler->op_region) {
+ break;
+ }
+ }
+ }
+
/* XXX no warning print here, after full-area and back regions are remade */
if (ar)
CTX_wm_region_set(C, ar);
@@ -1413,11 +1490,12 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
/* C is zero on freeing database, modal handlers then already were freed */
while ((handler = BLI_pophead(handlers))) {
if (handler->op) {
+ wmWindow *win = CTX_wm_window(C);
if (handler->op->type->cancel) {
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- wm_handler_op_context(C, handler);
+ wm_handler_op_context(C, handler, win->eventstate);
if (handler->op->type->flag & OPTYPE_UNDO)
wm->op_undo_depth++;
@@ -1431,7 +1509,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
CTX_wm_region_set(C, region);
}
- WM_cursor_grab_disable(CTX_wm_window(C), NULL);
+ WM_cursor_grab_disable(win, NULL);
WM_operator_free(handler->op);
}
else if (handler->ui_remove) {
@@ -1549,7 +1627,8 @@ static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *eve
}
}
-/* Check whether operator is allowed to run in case interface is locked,
+/**
+ * Check whether operator is allowed to run in case interface is locked,
* If interface is unlocked, will always return truth.
*/
static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot)
@@ -1603,7 +1682,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
ARegion *region = CTX_wm_region(C);
bool dbl_click_disabled = false;
- wm_handler_op_context(C, handler);
+ wm_handler_op_context(C, handler, event);
wm_region_mouse_co(C, event);
wm_event_modalkeymap(C, op, event, &dbl_click_disabled);
@@ -1751,7 +1830,7 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
ED_screen_full_prevspace(C, CTX_wm_area(C));
}
- wm_handler_op_context(C, handler);
+ wm_handler_op_context(C, handler, CTX_wm_window(C)->eventstate);
/* needed for UI_popup_menu_reports */
@@ -1877,7 +1956,7 @@ static int wm_action_not_handled(int action)
static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers)
{
#ifndef NDEBUG
- const int do_debug_handler = (G.debug & G_DEBUG_HANDLERS) &&
+ const bool do_debug_handler = (G.debug & G_DEBUG_HANDLERS) &&
/* comment this out to flood the console! (if you really want to test) */
!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)
;
@@ -2322,7 +2401,7 @@ void wm_event_do_handlers(bContext *C)
Scene *scene = win->screen->scene;
if (scene) {
- int is_playing_sound = sound_scene_playing(win->screen->scene);
+ int is_playing_sound = BKE_sound_scene_playing(win->screen->scene);
if (is_playing_sound != -1) {
bool is_playing_screen;
@@ -2339,7 +2418,7 @@ void wm_event_do_handlers(bContext *C)
}
if (is_playing_sound == 0) {
- const float time = sound_sync_scene(scene);
+ const float time = BKE_sound_sync_scene(scene);
if (finite(time)) {
int ncfra = time * (float)FPS + 0.5f;
if (ncfra != scene->r.cfra) {
@@ -2429,6 +2508,11 @@ void wm_event_do_handlers(bContext *C)
break;
}
+ /* update azones if needed - done here because it needs to be independent from redraws */
+ if (sa->flag & AREA_FLAG_ACTIONZONES_UPDATE) {
+ ED_area_azones_update(sa, &event->x);
+ }
+
if (wm_event_inside_i(event, &sa->totrct)) {
CTX_wm_area_set(C, sa);
@@ -2490,7 +2574,7 @@ void wm_event_do_handlers(bContext *C)
/* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad?
* doing it on ghost queue gives errors when mousemoves go over area borders */
- if (doit && win->screen && win->screen->subwinactive != win->screen->mainwin) {
+ if (doit && win->screen->subwinactive != win->screen->mainwin) {
win->eventstate->prevx = event->x;
win->eventstate->prevy = event->y;
//printf("win->eventstate->prev = %d %d\n", event->x, event->y);
@@ -2547,11 +2631,12 @@ void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval
/* operator is supposed to have a filled "path" property */
/* optional property: filetype (XXX enum?) */
-/* Idea is to keep a handler alive on window queue, owning the operator.
+/**
+ * The idea here is to keep a handler alive on window queue, owning the operator.
* The filewindow can send event to make it execute, thus ensuring
* executing happens outside of lower level queues, with UI refreshed.
- * Should also allow multiwin solutions */
-
+ * Should also allow multiwin solutions
+ */
void WM_event_add_fileselect(bContext *C, wmOperator *op)
{
wmEventHandler *handler, *handlernext;
@@ -2628,6 +2713,7 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
handler->op_area = CTX_wm_area(C); /* means frozen screen context for modal handlers! */
handler->op_region = CTX_wm_region(C);
+ handler->op_region_type = handler->op_region ? handler->op_region->regiontype : -1;
BLI_addhead(&win->modalhandlers, handler);
@@ -2696,7 +2782,7 @@ void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
wmEventHandler *WM_event_add_ui_handler(
const bContext *C, ListBase *handlers,
wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove,
- void *userdata, const bool accept_dbl_click)
+ void *userdata, const char flag)
{
wmEventHandler *handler = MEM_callocN(sizeof(wmEventHandler), "event ui handler");
handler->ui_handle = ui_handle;
@@ -2713,9 +2799,8 @@ wmEventHandler *WM_event_add_ui_handler(
handler->ui_menu = NULL;
}
- if (accept_dbl_click) {
- handler->flag |= WM_HANDLER_ACCEPT_DBL_CLICK;
- }
+ BLI_assert((flag & WM_HANDLER_DO_FREE) == 0);
+ handler->flag = flag;
BLI_addhead(handlers, handler);
@@ -2941,52 +3026,41 @@ static int convert_key(GHOST_TKey key)
static void wm_eventemulation(wmEvent *event)
{
- /* Store last mmb event value to make emulation work when modifier keys are released first. */
- static int mmb_emulated = 0; /* this should be in a data structure somwhere */
+ /* Store last mmb/rmb event value to make emulation work when modifier keys
+ * are released first. This really should be in a data structure somewhere. */
+ static int emulating_event = EVENT_NONE;
- /* middlemouse emulation */
+ /* middlemouse and rightmouse emulation */
if (U.flag & USER_TWOBUTTONMOUSE) {
if (event->type == LEFTMOUSE) {
if (event->val == KM_PRESS && event->alt) {
event->type = MIDDLEMOUSE;
event->alt = 0;
- mmb_emulated = 1;
- }
- else if (event->val == KM_RELEASE) {
- /* only send middle-mouse release if emulated */
- if (mmb_emulated) {
- event->type = MIDDLEMOUSE;
- event->alt = 0;
- }
- mmb_emulated = 0;
+ emulating_event = MIDDLEMOUSE;
}
- }
-
- }
-
#ifdef __APPLE__
-
- /* rightmouse emulation */
- if (U.flag & USER_TWOBUTTONMOUSE) {
- if (event->type == LEFTMOUSE) {
-
- if (event->val == KM_PRESS && event->oskey) {
+ else if (event->val == KM_PRESS && event->oskey) {
event->type = RIGHTMOUSE;
event->oskey = 0;
- mmb_emulated = 1;
+ emulating_event = RIGHTMOUSE;
}
+#endif
else if (event->val == KM_RELEASE) {
- if (mmb_emulated) {
- event->oskey = RIGHTMOUSE;
+ /* only send middle-mouse release if emulated */
+ if (emulating_event == MIDDLEMOUSE) {
+ event->type = MIDDLEMOUSE;
event->alt = 0;
}
- mmb_emulated = 0;
+ else if (emulating_event == RIGHTMOUSE) {
+ event->type = RIGHTMOUSE;
+ event->oskey = 0;
+ }
+ emulating_event = EVENT_NONE;
}
}
}
-#endif
/* numpad emulation */
if (U.flag & USER_NONUMPAD) {
@@ -3208,7 +3282,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
event.x = evt->x = pd->x;
event.y = evt->y = pd->y;
- event.val = 0;
+ event.val = KM_NOTHING;
/* Use prevx/prevy so we can calculate the delta later */
event.prevx = event.x - pd->deltaX;
@@ -3436,7 +3510,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
event.type = TIMER;
event.custom = EVT_DATA_TIMER;
event.customdata = customdata;
- event.val = 0;
+ event.val = KM_NOTHING;
event.keymodifier = 0;
wm_event_add(win, &event);
@@ -3446,7 +3520,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
case GHOST_kEventNDOFMotion:
{
event.type = NDOF_MOTION;
- event.val = 0;
+ event.val = KM_NOTHING;
attach_ndof_data(&event, customdata);
wm_event_add(win, &event);
@@ -3604,7 +3678,7 @@ float WM_event_tablet_data(const wmEvent *event, int *pen_flip, float tilt[2])
zero_v2(tilt);
if (event->tablet_data) {
- wmTabletData *wmtab = event->tablet_data;
+ const wmTabletData *wmtab = event->tablet_data;
erasor = (wmtab->Active == EVT_TABLET_ERASER);
if (wmtab->Active != EVT_TABLET_NONE) {
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index f5a7ad164d6..5bd2bb88f84 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -301,7 +301,7 @@ static void wm_init_userdef(bContext *C, const bool from_memory)
UI_init_userdef();
MEM_CacheLimiter_set_maximum(((size_t)U.memcachelimit) * 1024 * 1024);
- sound_init(bmain);
+ BKE_sound_init(bmain);
/* needed so loading a file from the command line respects user-pref [#26156] */
BKE_BIT_TEST_SET(G.fileflags, U.flag & USER_FILENOUI, G_FILE_NO_UI);
@@ -506,13 +506,13 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
}
#endif
- BKE_reset_undo();
- BKE_write_undo(C, "original"); /* save current state */
+ BKE_undo_reset();
+ BKE_undo_write(C, "original"); /* save current state */
success = true;
}
else if (retval == BKE_READ_EXOTIC_OK_OTHER)
- BKE_write_undo(C, "Import file");
+ BKE_undo_write(C, "Import file");
else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) {
BKE_reportf(reports, RPT_ERROR, "Cannot read file '%s': %s", filepath,
errno ? strerror(errno) : TIP_("unable to open the file"));
@@ -660,8 +660,8 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
// refresh_interface_font();
// undo_editmode_clear();
- BKE_reset_undo();
- BKE_write_undo(C, "original"); /* save current state */
+ BKE_undo_reset();
+ BKE_undo_write(C, "original"); /* save current state */
ED_editors_init(C);
DAG_on_visible_update(CTX_data_main(C), true);
@@ -846,11 +846,11 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt)
if (scene->camera) {
ibuf = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera,
BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
- IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, err_out);
+ IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, NULL, err_out);
}
else {
ibuf = ED_view3d_draw_offscreen_imbuf(scene, v3d, ar, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
- IB_rect, false, R_ALPHAPREMUL, err_out);
+ IB_rect, false, R_ALPHAPREMUL, NULL, err_out);
}
if (ibuf) {
@@ -860,7 +860,7 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt)
IMB_scaleImBuf(ibuf, BLEN_THUMB_SIZE, BLEN_THUMB_SIZE);
/* add pretty overlay */
- IMB_overlayblend_thumb(ibuf->rect, ibuf->x, ibuf->y, aspect);
+ IMB_thumb_overlay_blend(ibuf->rect, ibuf->x, ibuf->y, aspect);
/* first write into thumb buffer */
thumb = MEM_mallocN(((2 + (BLEN_THUMB_SIZE * BLEN_THUMB_SIZE))) * sizeof(int), "write_file thumb");
@@ -951,7 +951,7 @@ int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *
/* operator now handles overwrite checks */
if (G.fileflags & G_AUTOPACK) {
- packAll(G.main, reports);
+ packAll(G.main, reports, false);
}
/* don't forget not to return without! */
@@ -991,7 +991,7 @@ int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *
/* run this function after because the file cant be written before the blend is */
if (ibuf_thumb) {
IMB_thumb_delete(filepath, THB_FAIL); /* without this a failed thumb overrides */
- ibuf_thumb = IMB_thumb_create(filepath, THB_NORMAL, THB_SOURCE_BLEND, ibuf_thumb);
+ ibuf_thumb = IMB_thumb_create(filepath, THB_LARGE, THB_SOURCE_BLEND, ibuf_thumb);
IMB_freeImBuf(ibuf_thumb);
}
@@ -1086,7 +1086,7 @@ void wm_autosave_location(char *filepath)
if (G.main && G.relbase_valid) {
const char *basename = BLI_path_basename(G.main->name);
int len = strlen(basename) - 6;
- BLI_snprintf(path, sizeof(path), "%.*s-%d.blend", len, basename, pid);
+ BLI_snprintf(path, sizeof(path), "%.*s.blend", len, basename);
}
else {
BLI_snprintf(path, sizeof(path), "%d.blend", pid);
@@ -1137,8 +1137,6 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w
}
}
- ED_editors_flush_edits(C, false);
-
wm_autosave_location(filepath);
if (U.uiflag & USER_GLOBALUNDO) {
@@ -1149,6 +1147,8 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w
/* save as regular blend file */
int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_LOCK | G_FILE_SIGN | G_FILE_HISTORY);
+ ED_editors_flush_edits(C, false);
+
/* no error reporting to console */
BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL);
}
diff --git a/source/blender/windowmanager/intern/wm_generic_widgets.c b/source/blender/windowmanager/intern/wm_generic_widgets.c
index 49287bd7ff5..247bd6a601b 100644
--- a/source/blender/windowmanager/intern/wm_generic_widgets.c
+++ b/source/blender/windowmanager/intern/wm_generic_widgets.c
@@ -657,7 +657,9 @@ static void rect_transform_draw_corners(rctf *r, float offsetx, float offsety)
static void rect_transform_draw_interaction(int highlighted, float half_w, float half_h, float w, float h)
{
float verts[4][2];
+#if 0
unsigned short elems[4] = {0, 1, 3, 2};
+#endif
switch (highlighted) {
case WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_LEFT:
@@ -1042,6 +1044,13 @@ struct wmWidget *WIDGET_rect_transform_new(struct wmWidgetGroup *wgroup, int sty
return (wmWidget *)cage;
}
+void WIDGET_rect_transform_set_offset(struct wmWidget *widget, float offset[2])
+{
+ RectTransformWidget *cage = (RectTransformWidget *)widget;
+
+ copy_v2_v2(cage->offset, offset);
+}
+
/********* Facemap widget ************/
typedef struct FacemapWidget {
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index be75b3df0b7..6c55d17dcb2 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -58,9 +58,10 @@
#include "BKE_screen.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
+#include "BKE_icons.h"
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_mball.h"
+#include "BKE_mball_tessellate.h"
#include "BKE_node.h"
#include "BKE_report.h"
@@ -149,9 +150,11 @@ void WM_init(bContext *C, int argc, const char **argv)
WM_menutype_init();
WM_uilisttype_init();
- set_free_windowmanager_cb(wm_close_and_free); /* library.c */
- set_free_notifier_reference_cb(WM_main_remove_notifier_reference); /* library.c */
- set_blender_test_break_cb(wm_window_testbreak); /* blender.c */
+ BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */
+ BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */
+ BKE_library_callback_free_editor_id_reference_set(WM_main_remove_editor_id_reference); /* library.c */
+ BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */
+ BKE_spacedata_callback_id_unref_set(ED_spacedata_id_unref); /* screen.c */
DAG_editors_update_cb(ED_render_id_flush_update, ED_render_scene_update); /* depsgraph.c */
ED_spacetypes_init(); /* editors/space_api/spacetype.c */
@@ -172,6 +175,25 @@ void WM_init(bContext *C, int argc, const char **argv)
BLF_lang_set(NULL);
+ if (!G.background) {
+ GPU_init();
+
+ GPU_set_mipmap(!(U.gameflags & USER_DISABLE_MIPMAP));
+ GPU_set_linear_mipmap(true);
+ GPU_set_anisotropic(U.anisotropic_filter);
+ GPU_set_gpu_mipmapping(U.use_gpu_mipmap);
+
+ UI_init();
+ }
+ else {
+ /* Note: Currently only inits icons, which we now want in background mode too
+ * (scripts could use those in background processing...).
+ * In case we do more later, we may need to pass a 'background' flag.
+ * Called from 'UI_init' above */
+ BKE_icons_init(1);
+ }
+
+
ED_spacemacros_init();
/* note: there is a bug where python needs initializing before loading the
@@ -197,16 +219,6 @@ void WM_init(bContext *C, int argc, const char **argv)
wm_init_reports(C); /* reports cant be initialized before the wm */
- if (!G.background) {
- GPU_init();
-
- GPU_set_mipmap(!(U.gameflags & USER_DISABLE_MIPMAP));
- GPU_set_anisotropic(U.anisotropic_filter);
- GPU_set_gpu_mipmapping(U.use_gpu_mipmap);
-
- UI_init();
- }
-
clear_matcopybuf();
ED_render_clear_mtex_copybuf();
@@ -329,7 +341,7 @@ bool WM_init_game(bContext *C)
WM_operator_name_call(C, "VIEW3D_OT_game_start", WM_OP_EXEC_DEFAULT, NULL);
- sound_exit();
+ BKE_sound_exit();
return true;
}
@@ -399,7 +411,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
{
wmWindowManager *wm = C ? CTX_wm_manager(C) : NULL;
- sound_exit();
+ BKE_sound_exit();
/* first wrap up running stuff, we assume only the active WM is running */
/* modal handlers are on window level freed, others too? */
@@ -408,7 +420,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
wmWindow *win;
if (!G.background) {
- if ((U.uiflag2 & USER_KEEP_SESSION) || BKE_undo_valid(NULL)) {
+ if ((U.uiflag2 & USER_KEEP_SESSION) || BKE_undo_is_valid(NULL)) {
/* save the undo state as quit.blend */
char filename[FILE_MAX];
bool has_edited;
@@ -521,7 +533,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
GPU_exit();
}
- BKE_reset_undo();
+ BKE_undo_reset();
ED_file_exit(); /* for fsmenu */
diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c
index 6bc858e861a..f8258d18c1a 100644
--- a/source/blender/windowmanager/intern/wm_jobs.c
+++ b/source/blender/windowmanager/intern/wm_jobs.c
@@ -157,8 +157,8 @@ static void wm_job_main_thread_yield(wmJob *wm_job, bool ending)
BLI_ticket_mutex_lock(wm_job->main_thread_mutex);
}
-/* finds:
- * if type or owner, compare for it, otherwise any matching job
+/**
+ * Finds if type or owner, compare for it, otherwise any matching job.
*/
static wmJob *wm_job_find(wmWindowManager *wm, void *owner, const int job_type)
{
@@ -185,9 +185,12 @@ static wmJob *wm_job_find(wmWindowManager *wm, void *owner, const int job_type)
/* ******************* public API ***************** */
-/* returns current or adds new job, but doesnt run it */
-/* every owner only gets a single job, adding a new one will stop running job and
- * when stopped it starts the new one */
+/**
+ * \return current job or adds new job, but doesnt run it.
+ *
+ * \note every owner only gets a single job,
+ * adding a new one will stop running job and when stopped it starts the new one.
+ */
wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, const char *name, int flag, int job_type)
{
wmJob *wm_job = wm_job_find(wm, owner, job_type);
@@ -375,8 +378,10 @@ static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test)
// if (suspend) printf("job suspended: %s\n", test->name);
}
-/* if job running, the same owner gave it a new job */
-/* if different owner starts existing startjob, it suspends itself */
+/**
+ * if job running, the same owner gave it a new job.
+ * if different owner starts existing startjob, it suspends itself
+ */
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
{
if (wm_job->running) {
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 82e46c1b333..45177903cce 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -546,7 +546,7 @@ static void wm_keymap_diff(wmKeyMap *diff_km, wmKeyMap *from_km, wmKeyMap *to_km
if (to_kmi) {
orig_kmi = WM_keymap_item_find_id(orig_km, kmi->id);
- if (!orig_kmi)
+ if (!orig_kmi && addon_km)
orig_kmi = wm_keymap_find_item_equals(addon_km, kmi);
if (orig_kmi) {
@@ -929,7 +929,8 @@ int WM_keymap_item_to_string(wmKeyMapItem *kmi, char *str, const int len)
static wmKeyMapItem *wm_keymap_item_find_handlers(
const bContext *C, ListBase *handlers, const char *opname, int UNUSED(opcontext),
- IDProperty *properties, const bool is_strict, const bool is_hotkey, wmKeyMap **keymap_r)
+ IDProperty *properties, const bool is_strict, const bool is_hotkey,
+ wmKeyMap **r_keymap)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmEventHandler *handler;
@@ -966,7 +967,7 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(
#endif
if (kmi->ptr && IDP_EqualsProperties_ex(properties, kmi->ptr->data, is_strict)) {
- if (keymap_r) *keymap_r = keymap;
+ if (r_keymap) *r_keymap = keymap;
return kmi;
}
/* Debug only, helps spotting mismatches between menu entries and shortcuts! */
@@ -989,11 +990,13 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(
"this might not be desired!\n", opname);
printf("\tkm: '%s', kmi: '%s'\n", keymap->idname, kmi_str);
#ifndef NDEBUG
+#ifdef WITH_PYTHON
printf("OPERATOR\n");
IDP_spit(properties);
printf("KEYMAP\n");
IDP_spit(kmi->ptr->data);
#endif
+#endif
printf("\n");
}
@@ -1004,7 +1007,7 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(
}
}
else {
- if (keymap_r) *keymap_r = keymap;
+ if (r_keymap) *r_keymap = keymap;
return kmi;
}
}
@@ -1013,13 +1016,14 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(
}
/* ensure un-initialized keymap is never used */
- if (keymap_r) *keymap_r = NULL;
+ if (r_keymap) *r_keymap = NULL;
return NULL;
}
static wmKeyMapItem *wm_keymap_item_find_props(
const bContext *C, const char *opname, int opcontext,
- IDProperty *properties, const bool is_strict, const bool is_hotkey, wmKeyMap **keymap_r)
+ IDProperty *properties, const bool is_strict, const bool is_hotkey,
+ wmKeyMap **r_keymap)
{
wmWindow *win = CTX_wm_window(C);
ScrArea *sa = CTX_wm_area(C);
@@ -1028,10 +1032,10 @@ static wmKeyMapItem *wm_keymap_item_find_props(
/* look into multiple handler lists to find the item */
if (win)
- found = wm_keymap_item_find_handlers(C, &win->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r);
+ found = wm_keymap_item_find_handlers(C, &win->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap);
if (sa && found == NULL)
- found = wm_keymap_item_find_handlers(C, &sa->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r);
+ found = wm_keymap_item_find_handlers(C, &sa->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap);
if (found == NULL) {
if (ELEM(opcontext, WM_OP_EXEC_REGION_WIN, WM_OP_INVOKE_REGION_WIN)) {
@@ -1040,7 +1044,7 @@ static wmKeyMapItem *wm_keymap_item_find_props(
ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
if (ar)
- found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r);
+ found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap);
}
}
else if (ELEM(opcontext, WM_OP_EXEC_REGION_CHANNELS, WM_OP_INVOKE_REGION_CHANNELS)) {
@@ -1048,18 +1052,18 @@ static wmKeyMapItem *wm_keymap_item_find_props(
ar = BKE_area_find_region_type(sa, RGN_TYPE_CHANNELS);
if (ar)
- found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r);
+ found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap);
}
else if (ELEM(opcontext, WM_OP_EXEC_REGION_PREVIEW, WM_OP_INVOKE_REGION_PREVIEW)) {
if (!(ar && ar->regiontype == RGN_TYPE_PREVIEW))
ar = BKE_area_find_region_type(sa, RGN_TYPE_PREVIEW);
if (ar)
- found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r);
+ found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap);
}
else {
if (ar)
- found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r);
+ found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap);
}
}
@@ -1068,7 +1072,8 @@ static wmKeyMapItem *wm_keymap_item_find_props(
static wmKeyMapItem *wm_keymap_item_find(
const bContext *C, const char *opname, int opcontext,
- IDProperty *properties, const bool is_hotkey, bool is_strict, wmKeyMap **keymap_r)
+ IDProperty *properties, const bool is_hotkey, bool is_strict,
+ wmKeyMap **r_keymap)
{
wmKeyMapItem *found;
@@ -1081,7 +1086,7 @@ static wmKeyMapItem *wm_keymap_item_find(
is_strict = is_strict && ((ot->flag & OPTYPE_MACRO) == 0);
}
- found = wm_keymap_item_find_props(C, opname, opcontext, properties, is_strict, is_hotkey, keymap_r);
+ found = wm_keymap_item_find_props(C, opname, opcontext, properties, is_strict, is_hotkey, r_keymap);
/* This block is *only* useful in one case: when op uses an enum menu in its prop member
* (then, we want to rerun a comparison with that 'prop' unset). Note this remains brittle,
@@ -1105,7 +1110,7 @@ static wmKeyMapItem *wm_keymap_item_find(
RNA_property_unset(&opptr, ot->prop);
found = wm_keymap_item_find_props(C, opname, opcontext, properties_temp,
- is_strict, is_hotkey, keymap_r);
+ is_strict, is_hotkey, r_keymap);
}
IDP_FreeProperty(properties_temp);
@@ -1134,11 +1139,13 @@ static wmKeyMapItem *wm_keymap_item_find(
"this might not be desired!\n", opname);
printf("\tkm: '%s', kmi: '%s'\n", km->idname, kmi_str);
#ifndef NDEBUG
+#ifdef WITH_PYTHON
printf("OPERATOR\n");
IDP_spit(properties);
printf("KEYMAP\n");
IDP_spit(kmi->ptr->data);
#endif
+#endif
printf("\n");
}
@@ -1167,9 +1174,10 @@ char *WM_key_event_operator_string(
int WM_key_event_operator_id(
const bContext *C, const char *opname, int opcontext,
- IDProperty *properties, const bool is_hotkey, wmKeyMap **keymap_r)
+ IDProperty *properties, const bool is_hotkey,
+ wmKeyMap **r_keymap)
{
- wmKeyMapItem *kmi = wm_keymap_item_find(C, opname, opcontext, properties, is_hotkey, true, keymap_r);
+ wmKeyMapItem *kmi = wm_keymap_item_find(C, opname, opcontext, properties, is_hotkey, true, r_keymap);
if (kmi)
return kmi->id;
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 6d5a5353a43..c7dc4773bfb 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -172,6 +172,7 @@ void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
RNA_def_struct_translation_context(ot->srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
+ ot->translation_context = BLF_I18NCONTEXT_OPERATOR_DEFAULT;
opfunc(ot);
if (ot->name == NULL) {
@@ -194,6 +195,7 @@ void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *
ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
RNA_def_struct_translation_context(ot->srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
+ ot->translation_context = BLF_I18NCONTEXT_OPERATOR_DEFAULT;
opfunc(ot, userdata);
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
RNA_def_struct_identifier(ot->srna, ot->idname);
@@ -339,7 +341,9 @@ static int wm_macro_modal(bContext *C, wmOperator *op, const wmEvent *event)
* */
if (op->opm->type->flag & OPTYPE_BLOCKING) {
int bounds[4] = {-1, -1, -1, -1};
- int wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER));
+ const bool wrap = (
+ (U.uiflag & USER_CONTINUOUS_MOUSE) &&
+ ((op->opm->flag & OP_IS_MODAL_GRAB_CURSOR) || (op->opm->type->flag & OPTYPE_GRAB_CURSOR)));
if (wrap) {
ARegion *ar = CTX_wm_region(C);
@@ -374,6 +378,7 @@ static void wm_macro_cancel(bContext *C, wmOperator *op)
wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *name, const char *description, int flag)
{
wmOperatorType *ot;
+ const char *i18n_context;
if (WM_operatortype_find(idname, true)) {
printf("%s: macro error: operator %s exists\n", __func__, idname);
@@ -400,8 +405,9 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
RNA_def_struct_identifier(ot->srna, ot->idname);
/* Use i18n context from ext.srna if possible (py operators). */
- RNA_def_struct_translation_context(ot->srna, ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) :
- BLF_I18NCONTEXT_OPERATOR_DEFAULT);
+ i18n_context = ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) : BLF_I18NCONTEXT_OPERATOR_DEFAULT;
+ RNA_def_struct_translation_context(ot->srna, i18n_context);
+ ot->translation_context = i18n_context;
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
@@ -427,6 +433,7 @@ void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *),
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
RNA_def_struct_translation_context(ot->srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
+ ot->translation_context = BLF_I18NCONTEXT_OPERATOR_DEFAULT;
opfunc(ot, userdata);
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
@@ -486,7 +493,7 @@ void WM_operatortype_remove_ptr(wmOperatorType *ot)
if (ot->macro.first)
wm_operatortype_free_macro(ot);
- BLI_ghash_remove(global_ops_hash, (void *)ot->idname, NULL, NULL);
+ BLI_ghash_remove(global_ops_hash, ot->idname, NULL, NULL);
WM_keyconfig_update_operatortype();
@@ -570,12 +577,13 @@ void WM_operator_bl_idname(char *to, const char *from)
to[0] = 0;
}
-/* Print a string representation of the operator, with the args that it runs so python can run it again.
+/**
+ * Print a string representation of the operator, with the args that it runs so python can run it again.
*
* When calling from an existing wmOperator, better to use simple version:
- * WM_operator_pystring(C, op);
+ * `WM_operator_pystring(C, op);`
*
- * Note: both op and opptr may be NULL (op is only used for macro operators).
+ * \note Both \a op and \a opptr may be `NULL` (\a op is only used for macro operators).
*/
char *WM_operator_pystring_ex(bContext *C, wmOperator *op, const bool all_args, const bool macro_args,
wmOperatorType *ot, PointerRNA *opptr)
@@ -1263,6 +1271,18 @@ void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type,
if (flag & WM_FILESEL_RELPATH)
RNA_def_boolean(ot->srna, "relative_path", true, "Relative Path", "Select the file relative to the blend file");
+ if (flag & WM_FILESEL_IMAGE_COLLAPSE) {
+ prop = RNA_def_boolean(ot->srna, "collapse_images", true, "Collapse Images", "Colapse Images with the same base name");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ }
+
+ if ((filter & FILE_TYPE_IMAGE) || (filter & FILE_TYPE_MOVIE)) {
+ prop = RNA_def_boolean(ot->srna, "show_multiview", 0, "Enable Multi-View", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "use_multiview", 0, "Use Multi-View", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ }
+
prop = RNA_def_enum(ot->srna, "display_type", file_display_items, display, "Display Type", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
@@ -1392,7 +1412,7 @@ bool WM_operator_check_ui_enabled(const bContext *C, const char *idname)
wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
- return !(ED_undo_valid(C, idname) == 0 || WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY));
+ return !((ED_undo_is_valid(C, idname) == false) || WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY));
}
wmOperator *WM_operator_last_redo(const bContext *C)
@@ -1539,6 +1559,9 @@ typedef struct wmOpPopUp {
/* Only invoked by OK button in popups created with wm_block_dialog_create() */
static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+
wmOpPopUp *data = arg1;
uiBlock *block = arg2;
@@ -1551,7 +1574,11 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
/* in this case, wm_operator_ui_popup_cancel wont run */
MEM_freeN(data);
- UI_popup_block_close(C, block);
+ /* check window before 'block->handle' incase the
+ * popup execution closed the window and freed the block. see T44688. */
+ if (BLI_findindex(&wm->windows, win) != -1) {
+ UI_popup_block_close(C, win, block);
+ }
}
static void dialog_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg))
@@ -1708,18 +1735,20 @@ static int wm_operator_props_popup_ex(bContext *C, wmOperator *op,
return OPERATOR_RUNNING_MODAL;
}
-/* Same as WM_operator_props_popup but don't use operator redo.
- * just wraps WM_operator_props_dialog_popup.
+/**
+ * Same as #WM_operator_props_popup but don't use operator redo.
+ * just wraps #WM_operator_props_dialog_popup.
*/
int WM_operator_props_popup_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return wm_operator_props_popup_ex(C, op, false, false);
}
-/* Same as WM_operator_props_popup but call the operator first,
+/**
+ * Same as #WM_operator_props_popup but call the operator first,
* This way - the button values correspond to the result of the operator.
- * Without this, first access to a button will make the result jump,
- * see [#32452] */
+ * Without this, first access to a button will make the result jump, see T32452.
+ */
int WM_operator_props_popup_call(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return wm_operator_props_popup_ex(C, op, true, true);
@@ -1823,7 +1852,8 @@ static void WM_OT_operator_defaults(wmOperatorType *ot)
static void wm_block_splash_close(bContext *C, void *arg_block, void *UNUSED(arg))
{
- UI_popup_block_close(C, arg_block);
+ wmWindow *win = CTX_wm_window(C);
+ UI_popup_block_close(C, win, arg_block);
}
static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *arg_unused);
@@ -1835,7 +1865,8 @@ static void wm_block_splash_refreshmenu(bContext *UNUSED(C), void *UNUSED(arg_bl
/* ugh, causes crashes in other buttons, disabling for now until
* a better fix */
#if 0
- UI_popup_block_close(C, arg_block);
+ wmWindow *win = CTX_wm_window(C);
+ UI_popup_block_close(C, win, arg_block);
UI_popup_block_invoke(C, wm_block_create_splash, NULL);
#endif
}
@@ -1985,8 +2016,10 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
split = uiLayoutSplit(layout, 0.0f, false);
col = uiLayoutColumn(split, false);
uiItemL(col, IFACE_("Links"), ICON_NONE);
+#if 0
uiItemStringO(col, IFACE_("Support an Open Animation Movie"), ICON_URL, "WM_OT_url_open", "url",
"https://cloud.blender.org/join");
+#endif
uiItemStringO(col, IFACE_("Donations"), ICON_URL, "WM_OT_url_open", "url",
"http://www.blender.org/foundation/donation-payment/");
uiItemStringO(col, IFACE_("Credits"), ICON_URL, "WM_OT_url_open", "url",
@@ -2440,18 +2473,18 @@ static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op)
struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
uiLayout *layout = op->layout;
uiLayout *col = op->layout;
- const char *autoexec_text = NULL;
+ const char *autoexec_text;
uiItemR(layout, op->ptr, "load_ui", 0, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
if (file_info->is_untrusted) {
- autoexec_text = "Trusted Source [Untrusted Path]";
+ autoexec_text = IFACE_("Trusted Source [Untrusted Path]");
uiLayoutSetActive(col, false);
uiLayoutSetEnabled(col, false);
}
else {
- autoexec_text = "Trusted Source";
+ autoexec_text = IFACE_("Trusted Source");
}
uiItemR(col, op->ptr, "use_scripts", 0, autoexec_text, ICON_NONE);
@@ -2865,30 +2898,45 @@ static void wm_filepath_default(char *filepath)
static void save_set_compress(wmOperator *op)
{
- if (!RNA_struct_property_is_set(op->ptr, "compress")) {
- if (G.save_over) /* keep flag for existing file */
- RNA_boolean_set(op->ptr, "compress", (G.fileflags & G_FILE_COMPRESS) != 0);
- else /* use userdef for new file */
- RNA_boolean_set(op->ptr, "compress", (U.flag & USER_FILECOMPRESS) != 0);
+ PropertyRNA *prop;
+
+ prop = RNA_struct_find_property(op->ptr, "compress");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ if (G.save_over) { /* keep flag for existing file */
+ RNA_property_boolean_set(op->ptr, prop, (G.fileflags & G_FILE_COMPRESS) != 0);
+ }
+ else { /* use userdef for new file */
+ RNA_property_boolean_set(op->ptr, prop, (U.flag & USER_FILECOMPRESS) != 0);
+ }
}
}
-static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static void save_set_filepath(wmOperator *op)
{
+ PropertyRNA *prop;
char name[FILE_MAX];
- save_set_compress(op);
-
- /* if not saved before, get the name of the most recently used .blend file */
- if (G.main->name[0] == 0 && G.recent_files.first) {
- struct RecentFile *recent = G.recent_files.first;
- BLI_strncpy(name, recent->filepath, FILE_MAX);
+ prop = RNA_struct_find_property(op->ptr, "filepath");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ /* if not saved before, get the name of the most recently used .blend file */
+ if (G.main->name[0] == 0 && G.recent_files.first) {
+ struct RecentFile *recent = G.recent_files.first;
+ BLI_strncpy(name, recent->filepath, FILE_MAX);
+ }
+ else {
+ BLI_strncpy(name, G.main->name, FILE_MAX);
+ }
+
+ wm_filepath_default(name);
+ RNA_property_string_set(op->ptr, prop, name);
}
- else
- BLI_strncpy(name, G.main->name, FILE_MAX);
-
- wm_filepath_default(name);
- RNA_string_set(op->ptr, "filepath", name);
+}
+
+static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+
+ save_set_compress(op);
+ save_set_filepath(op);
WM_event_add_fileselect(C, op);
@@ -2987,7 +3035,6 @@ static void WM_OT_save_as_mainfile(wmOperatorType *ot)
static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- char name[FILE_MAX];
int ret;
/* cancel if no active window */
@@ -2995,18 +3042,7 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U
return OPERATOR_CANCELLED;
save_set_compress(op);
-
- /* if not saved before, get the name of the most recently used .blend file */
- if (G.main->name[0] == 0 && G.recent_files.first) {
- struct RecentFile *recent = G.recent_files.first;
- BLI_strncpy(name, recent->filepath, FILE_MAX);
- }
- else
- BLI_strncpy(name, G.main->name, FILE_MAX);
-
- wm_filepath_default(name);
-
- RNA_string_set(op->ptr, "filepath", name);
+ save_set_filepath(op);
/* if we're saving for the first time and prefer relative paths - any existing paths will be absolute,
* enable the option to remap paths to avoid confusion [#37240] */
@@ -3018,8 +3054,11 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U
}
if (G.save_over) {
- if (BLI_exists(name)) {
- ret = WM_operator_confirm_message_ex(C, op, IFACE_("Save Over?"), ICON_QUESTION, name);
+ char path[FILE_MAX];
+
+ RNA_string_get(op->ptr, "filepath", path);
+ if (BLI_exists(path)) {
+ ret = WM_operator_confirm_message_ex(C, op, IFACE_("Save Over?"), ICON_QUESTION, path);
}
else {
ret = wm_save_as_mainfile_exec(C, op);
@@ -3144,9 +3183,10 @@ void WM_paint_cursor_end(wmWindowManager *wm, void *handle)
/* **************** Border gesture *************** */
-/* Border gesture has two types:
- * 1) WM_GESTURE_CROSS_RECT: starts a cross, on mouse click it changes to border
- * 2) WM_GESTURE_RECT: starts immediate as a border, on mouse click or release it ends
+/**
+ * Border gesture has two types:
+ * -# #WM_GESTURE_CROSS_RECT: starts a cross, on mouse click it changes to border.
+ * -# #WM_GESTURE_RECT: starts immediate as a border, on mouse click or release it ends.
*
* It stores 4 values (xmin, xmax, ymin, ymax) and event it ended with (event_type)
*/
@@ -3445,7 +3485,10 @@ static void tweak_gesture_modal(bContext *C, const wmEvent *event)
tevent.type = EVT_TWEAK_M;
tevent.val = val;
/* mouse coords! */
- wm_event_add(window, &tevent);
+
+ /* important we add immediately after this event, so future mouse releases
+ * (which may be in the queue already), are handled in order, see T44740 */
+ wm_event_add_ex(window, &tevent, event);
WM_gesture_end(C, gesture); /* frees gesture itself, and unregisters from window */
}
@@ -3828,7 +3871,7 @@ void WM_OT_straightline_gesture(wmOperatorType *ot)
#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35 * U.pixelsize)
#define WM_RADIAL_CONTROL_DISPLAY_WIDTH (WM_RADIAL_CONTROL_DISPLAY_SIZE - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE)
#define WM_RADIAL_CONTROL_HEADER_LENGTH 180
-#define WM_RADIAL_MAX_STR 6
+#define WM_RADIAL_MAX_STR 10
typedef struct {
PropertyType type;
@@ -3874,10 +3917,12 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e
switch (rc->subtype) {
case PROP_NONE:
case PROP_DISTANCE:
- case PROP_PERCENTAGE:
case PROP_PIXEL:
d[0] = rc->initial_value * U.pixelsize;
break;
+ case PROP_PERCENTAGE:
+ d[0] = (rc->initial_value) / 100.0f * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
+ break;
case PROP_FACTOR:
d[0] = (1 - rc->initial_value) * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
break;
@@ -3983,13 +4028,21 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
switch (rc->subtype) {
case PROP_NONE:
case PROP_DISTANCE:
- case PROP_PERCENTAGE:
case PROP_PIXEL:
r1 = rc->current_value * U.pixelsize;
r2 = rc->initial_value * U.pixelsize;
tex_radius = r1;
alpha = 0.75;
break;
+ case PROP_PERCENTAGE:
+ r1 = rc->current_value / 100.0f * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
+ r2 = tex_radius = WM_RADIAL_CONTROL_DISPLAY_SIZE;
+ rmin = WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
+ BLI_snprintf(str, WM_RADIAL_MAX_STR, "%3.1f%%", rc->current_value);
+ strdrawlen = BLI_strlen_utf8(str);
+ tex_radius = r1;
+ alpha = 0.75;
+ break;
case PROP_FACTOR:
r1 = (1 - rc->current_value) * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
r2 = tex_radius = WM_RADIAL_CONTROL_DISPLAY_SIZE;
@@ -4072,12 +4125,15 @@ typedef enum {
RC_PROP_REQUIRE_BOOL = 4,
} RCPropFlags;
-/* attempt to retrieve the rna pointer/property from an rna path;
- * returns 0 for failure, 1 for success, and also 1 if property is not
- * set */
-static int radial_control_get_path(PointerRNA *ctx_ptr, wmOperator *op,
- const char *name, PointerRNA *r_ptr,
- PropertyRNA **r_prop, int req_length, RCPropFlags flags)
+/**
+ * Attempt to retrieve the rna pointer/property from an rna path.
+ *
+ * \return 0 for failure, 1 for success, and also 1 if property is not set.
+ */
+static int radial_control_get_path(
+ PointerRNA *ctx_ptr, wmOperator *op,
+ const char *name, PointerRNA *r_ptr,
+ PropertyRNA **r_prop, int req_length, RCPropFlags flags)
{
PropertyRNA *unused_prop;
int len;
@@ -4293,7 +4349,7 @@ static void radial_control_cancel(bContext *C, wmOperator *op)
{
RadialControl *rc = op->customdata;
wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *sa = CTX_wm_area(C);
if (rc->dial) {
MEM_freeN(rc->dial);
@@ -4326,9 +4382,9 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
float delta[2], ret = OPERATOR_RUNNING_MODAL;
bool snap;
float angle_precision = 0.0f;
- const bool has_numInput = hasNumInput(&rc->num_input);
- bool handled = false;
- float numValue;
+ const bool has_numInput = hasNumInput(&rc->num_input);
+ bool handled = false;
+ float numValue;
/* TODO: fix hardcoded events */
snap = event->ctrl != 0;
@@ -4424,12 +4480,15 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
switch (rc->subtype) {
case PROP_NONE:
case PROP_DISTANCE:
- case PROP_PERCENTAGE:
case PROP_PIXEL:
new_value = dist;
if (snap) new_value = ((int)new_value + 5) / 10 * 10;
new_value /= U.pixelsize;
break;
+ case PROP_PERCENTAGE:
+ new_value = ((dist - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE) / WM_RADIAL_CONTROL_DISPLAY_WIDTH) * 100.0f;
+ if (snap) new_value = ((int)(new_value + 2.5)) / 5 * 5;
+ break;
case PROP_FACTOR:
new_value = (WM_RADIAL_CONTROL_DISPLAY_SIZE - dist) / WM_RADIAL_CONTROL_DISPLAY_WIDTH;
if (snap) new_value = ((int)ceil(new_value * 10.f) * 10.0f) / 100.f;
@@ -4617,8 +4676,10 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
for (a = 0; a < iter; a++) {
if (type == 0) {
- if (ar)
+ if (ar) {
ED_region_do_draw(C, ar);
+ ar->do_draw = false;
+ }
}
else if (type == 1) {
wmWindow *win = CTX_wm_window(C);
@@ -4646,6 +4707,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
if (ar_iter->swinid) {
CTX_wm_region_set(C, ar_iter);
ED_region_do_draw(C, ar_iter);
+ ar->do_draw = false;
}
}
}
@@ -4838,6 +4900,38 @@ static void WM_OT_previews_ensure(wmOperatorType *ot)
ot->exec = previews_ensure_exec;
}
+static int doc_view_manual_ui_context_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ PointerRNA ptr_props;
+ char buf[512];
+ short retval = OPERATOR_CANCELLED;
+
+ if (UI_but_online_manual_id_from_active(C, buf, sizeof(buf))) {
+ WM_operator_properties_create(&ptr_props, "WM_OT_doc_view_manual");
+ RNA_string_set(&ptr_props, "doc_id", buf);
+
+ retval = WM_operator_name_call_ptr(
+ C, WM_operatortype_find("WM_OT_doc_view_manual", false),
+ WM_OP_EXEC_DEFAULT, &ptr_props);
+
+ WM_operator_properties_free(&ptr_props);
+ }
+
+ return retval;
+}
+
+static void WM_OT_doc_view_manual_ui_context(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "View Online Manual";
+ ot->idname = "WM_OT_doc_view_manual_ui_context";
+ ot->description = "View a context based online manual in a web browser";
+
+ /* callbacks */
+ ot->poll = ED_operator_regionactive;
+ ot->exec = doc_view_manual_ui_context_exec;
+}
+
/* ******************************************************* */
static void operatortype_ghash_free_cb(wmOperatorType *ot)
@@ -4857,6 +4951,37 @@ static void operatortype_ghash_free_cb(wmOperatorType *ot)
}
/* ******************************************************* */
+/* toggle 3D for current window, turning it fullscreen if needed */
+static void WM_OT_stereo3d_set(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ ot->name = "Set Stereo 3D";
+ ot->idname = "WM_OT_set_stereo_3d";
+ ot->description = "Toggle 3D stereo support for current window (or change the display mode)";
+
+ ot->exec = wm_stereo3d_set_exec;
+ ot->invoke = wm_stereo3d_set_invoke;
+ ot->poll = WM_operator_winactive;
+ ot->ui = wm_stereo3d_set_draw;
+ ot->check = wm_stereo3d_set_check;
+ ot->cancel = wm_stereo3d_set_cancel;
+
+ prop = RNA_def_enum(ot->srna, "display_mode", stereo3d_display_items, S3D_DISPLAY_ANAGLYPH, "Display Mode", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna, "anaglyph_type", stereo3d_anaglyph_type_items, S3D_ANAGLYPH_REDCYAN, "Anaglyph Type", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna, "interlace_type", stereo3d_interlace_type_items, S3D_INTERLACE_ROW, "Interlace Type", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "use_interlace_swap", false, "Swap Left/Right",
+ "Swap left and right stereo channels");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "use_sidebyside_crosseyed", false, "Cross-Eyed",
+ "Right eye should see left image and vice-versa");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+/* ******************************************************* */
/* called on initialize WM_exit() */
void wm_operatortype_free(void)
{
@@ -4899,10 +5024,12 @@ void wm_operatortype_init(void)
WM_operatortype_append(WM_OT_call_menu_pie);
WM_operatortype_append(WM_OT_radial_control);
WM_operatortype_append(WM_OT_widget_tweak);
+ WM_operatortype_append(WM_OT_stereo3d_set);
#if defined(WIN32)
WM_operatortype_append(WM_OT_console_toggle);
#endif
WM_operatortype_append(WM_OT_previews_ensure);
+ WM_operatortype_append(WM_OT_doc_view_manual_ui_context);
}
/* circleselect-like modal operators */
@@ -5129,6 +5256,8 @@ void wm_window_keymap(wmKeyConfig *keyconf)
WM_keymap_verify_item(keymap, "WM_OT_window_fullscreen_toggle", F11KEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "WM_OT_quit_blender", QKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "WM_OT_doc_view_manual_ui_context", F1KEY, KM_PRESS, KM_ALT, 0);
+
/* debug/testing */
WM_keymap_verify_item(keymap, "WM_OT_redraw_timer", TKEY, KM_PRESS, KM_ALT | KM_CTRL, 0);
WM_keymap_verify_item(keymap, "WM_OT_debug_menu", DKEY, KM_PRESS, KM_ALT | KM_CTRL, 0);
@@ -5287,3 +5416,11 @@ EnumPropertyItem *RNA_mask_local_itemf(bContext *C, PointerRNA *ptr, PropertyRNA
return rna_id_itemf(C, ptr, r_free, C ? (ID *)CTX_data_main(C)->mask.first : NULL, true);
}
+EnumPropertyItem *RNA_cachelibrary_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ return rna_id_itemf(C, ptr, r_free, C ? (ID *)CTX_data_main(C)->cache_library.first : NULL, false);
+}
+EnumPropertyItem *RNA_cachelibrary_local_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ return rna_id_itemf(C, ptr, r_free, C ? (ID *)CTX_data_main(C)->cache_library.first : NULL, true);
+}
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index 31883cf234c..cc846584d97 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -71,6 +71,20 @@
#include "WM_api.h" /* only for WM_main_playanim */
+#ifdef WITH_AUDASPACE
+#include "AUD_C-API.h"
+
+AUD_Sound *source = NULL;
+AUD_Handle *playback_handle = NULL;
+AUD_Handle *scrub_handle = NULL;
+#endif
+
+/* simple limiter to avoid flooding memory */
+#define USE_FRAME_CACHE_LIMIT
+#ifdef USE_FRAME_CACHE_LIMIT
+# define PLAY_FRAME_CACHE_MAX 30
+#endif
+
struct PlayState;
static void playanim_window_zoom(struct PlayState *ps, const float zoom_offset);
@@ -90,6 +104,7 @@ typedef struct PlayState {
bool turbo;
bool pingpong;
bool noskip;
+ bool indicator;
bool sstep;
bool wait2;
bool stopped;
@@ -160,11 +175,11 @@ static struct WindowStateGlobal {
eWS_Qual qual;
} g_WS = {NULL};
-static void playanim_window_get_size(int *width_r, int *height_r)
+static void playanim_window_get_size(int *r_width, int *r_height)
{
GHOST_RectangleHandle bounds = GHOST_GetClientBounds(g_WS.ghost_window);
- *width_r = GHOST_GetWidthRectangle(bounds);
- *height_r = GHOST_GetHeightRectangle(bounds);
+ *r_width = GHOST_GetWidthRectangle(bounds);
+ *r_height = GHOST_GetHeightRectangle(bounds);
GHOST_DisposeRectangle(bounds);
}
@@ -222,8 +237,15 @@ typedef struct PlayAnimPict {
} PlayAnimPict;
static struct ListBase picsbase = {NULL, NULL};
+/* frames in memory - store them here to for easy deallocation later */
static bool fromdisk = false;
static double ptottime = 0.0, swaptime = 0.04;
+static double fps_movie;
+
+#ifdef USE_FRAME_CACHE_LIMIT
+static struct ListBase inmempicsbase = {NULL, NULL};
+static int added_images = 0;
+#endif
static PlayAnimPict *playanim_step(PlayAnimPict *playanim, int step)
{
@@ -322,6 +344,30 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf
BLF_draw(fontid, str, sizeof(str));
}
+ if (ps->indicator) {
+ float fac = ps->picture->frame / (double)(((PlayAnimPict *)picsbase.last)->frame - ((PlayAnimPict *)picsbase.first)->frame);
+
+ fac = 2.0f * fac - 1.0f;
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
+
+ glBegin(GL_LINES);
+ glVertex2f(fac, -1.0f);
+ glVertex2f(fac, 1.0f);
+ glEnd();
+
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ }
+
GHOST_SwapWindowBuffers(g_WS.ghost_window);
}
@@ -429,6 +475,7 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
picture->mem = mem;
picture->name = strdup(filepath);
+ picture->frame = count; /* not exact but should work for positioning */
close(file);
BLI_addtail(&picsbase, picture);
count++;
@@ -476,6 +523,76 @@ static void build_pict_list(PlayState *ps, const char *first, int totframes, int
ps->loading = false;
}
+static void update_sound_fps(void)
+{
+#ifdef WITH_AUDASPACE
+ if (playback_handle) {
+ /* swaptime stores the 1.0/fps ratio */
+ double speed = 1.0 / (swaptime * fps_movie);
+
+ AUD_setSoundPitch(playback_handle, speed);
+ }
+#endif
+}
+
+static void change_frame(PlayState *ps, int cx)
+{
+ int sizex, sizey;
+ int i;
+
+ playanim_window_get_size(&sizex, &sizey);
+ ps->picture = picsbase.first;
+ /* TODO - store in ps direct? */
+ i = 0;
+ while (ps->picture) {
+ i++;
+ ps->picture = ps->picture->next;
+ }
+ i = (i * cx) / sizex;
+
+#ifdef WITH_AUDASPACE
+ if (scrub_handle) {
+ AUD_stop(scrub_handle);
+ scrub_handle = NULL;
+ }
+
+ if (playback_handle) {
+ AUD_Status status = AUD_getStatus(playback_handle);
+ if (status != AUD_STATUS_PLAYING) {
+ AUD_stop(playback_handle);
+ playback_handle = AUD_play(source, 1);
+ if (playback_handle) {
+ AUD_seek(playback_handle, i / fps_movie);
+ scrub_handle = AUD_pauseAfter(playback_handle, 1 / fps_movie);
+ }
+ update_sound_fps();
+ }
+ else {
+ AUD_seek(playback_handle, i / fps_movie);
+ scrub_handle = AUD_pauseAfter(playback_handle, 1 / fps_movie);
+ }
+ }
+ else if (source) {
+ playback_handle = AUD_play(source, 1);
+ if (playback_handle) {
+ AUD_seek(playback_handle, i / fps_movie);
+ scrub_handle = AUD_pauseAfter(playback_handle, 1 / fps_movie);
+ }
+ update_sound_fps();
+ }
+#endif
+
+ ps->picture = picsbase.first;
+ for (; i > 0; i--) {
+ if (ps->picture->next == NULL) break;
+ ps->picture = ps->picture->next;
+ }
+
+ ps->sstep = true;
+ ps->wait2 = false;
+ ps->next_frame = 0;
+}
+
static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
{
PlayState *ps = (PlayState *)ps_void;
@@ -489,7 +606,6 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
/* convert ghost event into value keyboard or mouse */
val = ELEM(type, GHOST_kEventKeyDown, GHOST_kEventButtonDown);
-
/* first check if we're busy loading files */
if (ps->loading) {
switch (type) {
@@ -535,6 +651,9 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
case GHOST_kKeyA:
if (val) ps->noskip = !ps->noskip;
break;
+ case GHOST_kKeyI:
+ if (val) ps->indicator = !ps->indicator;
+ break;
case GHOST_kKeyP:
if (val) ps->pingpong = !ps->pingpong;
break;
@@ -548,42 +667,70 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
}
case GHOST_kKey1:
case GHOST_kKeyNumpad1:
- if (val) swaptime = ps->fstep / 60.0;
+ if (val) {
+ swaptime = ps->fstep / 60.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKey2:
case GHOST_kKeyNumpad2:
- if (val) swaptime = ps->fstep / 50.0;
+ if (val) {
+ swaptime = ps->fstep / 50.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKey3:
case GHOST_kKeyNumpad3:
- if (val) swaptime = ps->fstep / 30.0;
+ if (val) {
+ swaptime = ps->fstep / 30.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKey4:
case GHOST_kKeyNumpad4:
- if (g_WS.qual & WS_QUAL_SHIFT)
+ if (g_WS.qual & WS_QUAL_SHIFT) {
swaptime = ps->fstep / 24.0;
- else
+ update_sound_fps();
+ }
+ else {
swaptime = ps->fstep / 25.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKey5:
case GHOST_kKeyNumpad5:
- if (val) swaptime = ps->fstep / 20.0;
+ if (val) {
+ swaptime = ps->fstep / 20.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKey6:
case GHOST_kKeyNumpad6:
- if (val) swaptime = ps->fstep / 15.0;
+ if (val) {
+ swaptime = ps->fstep / 15.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKey7:
case GHOST_kKeyNumpad7:
- if (val) swaptime = ps->fstep / 12.0;
+ if (val) {
+ swaptime = ps->fstep / 12.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKey8:
case GHOST_kKeyNumpad8:
- if (val) swaptime = ps->fstep / 10.0;
+ if (val) {
+ swaptime = ps->fstep / 10.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKey9:
case GHOST_kKeyNumpad9:
- if (val) swaptime = ps->fstep / 6.0;
+ if (val) {
+ swaptime = ps->fstep / 6.0;
+ update_sound_fps();
+ }
break;
case GHOST_kKeyLeftArrow:
if (val) {
@@ -646,6 +793,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
}
else {
swaptime = ps->fstep / 5.0;
+ update_sound_fps();
}
}
break;
@@ -662,10 +810,63 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
}
}
break;
+
+ case GHOST_kKeySpace:
+ if (val) {
+ if (ps->wait2 || ps->sstep) {
+ ps->wait2 = ps->sstep = false;
+#ifdef WITH_AUDASPACE
+ {
+ PlayAnimPict *picture = picsbase.first;
+ /* TODO - store in ps direct? */
+ int i = 0;
+
+ while (picture && picture != ps->picture) {
+ i++;
+ picture = picture->next;
+ }
+ if (playback_handle)
+ AUD_stop(playback_handle);
+ playback_handle = AUD_play(source, 1);
+ if (playback_handle)
+ AUD_seek(playback_handle, i / fps_movie);
+ update_sound_fps();
+ }
+#endif
+ }
+ else {
+ ps->sstep = true;
+ ps->wait2 = true;
+#ifdef WITH_AUDASPACE
+ if (playback_handle) {
+ AUD_stop(playback_handle);
+ playback_handle = NULL;
+ }
+#endif
+ }
+ }
+ break;
case GHOST_kKeyEnter:
case GHOST_kKeyNumpadEnter:
if (val) {
ps->wait2 = ps->sstep = false;
+#ifdef WITH_AUDASPACE
+ {
+ PlayAnimPict *picture = picsbase.first;
+ /* TODO - store in ps direct? */
+ int i = 0;
+ while (picture && picture != ps->picture) {
+ i++;
+ picture = picture->next;
+ }
+ if (playback_handle)
+ AUD_stop(playback_handle);
+ playback_handle = AUD_play(source, 1);
+ if (playback_handle)
+ AUD_seek(playback_handle, i / fps_movie);
+ update_sound_fps();
+ }
+#endif
}
break;
case GHOST_kKeyPeriod:
@@ -677,6 +878,12 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
else {
ps->sstep = true;
ps->wait2 = !ps->wait2;
+#ifdef WITH_AUDASPACE
+ if (playback_handle) {
+ AUD_stop(playback_handle);
+ playback_handle = NULL;
+ }
+#endif
}
}
break;
@@ -688,7 +895,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
playanim_window_zoom(ps, 1.0f);
}
else {
- swaptime /= 1.1;
+ if (swaptime > ps->fstep / 60.0) {
+ swaptime /= 1.1;
+ update_sound_fps();
+ }
}
break;
}
@@ -700,7 +910,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
playanim_window_zoom(ps, -1.0f);
}
else {
- swaptime *= 1.1;
+ if (swaptime < ps->fstep / 5.0) {
+ swaptime *= 1.1;
+ update_sound_fps();
+ }
}
break;
}
@@ -726,8 +939,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
if (bd->button == GHOST_kButtonMaskLeft) {
if (type == GHOST_kEventButtonDown) {
- if (inside_window)
+ if (inside_window) {
g_WS.qual |= WS_QUAL_LMOUSE;
+ change_frame(ps, cx);
+ }
}
else
g_WS.qual &= ~WS_QUAL_LMOUSE;
@@ -753,31 +968,12 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
case GHOST_kEventCursorMove:
{
if (g_WS.qual & WS_QUAL_LMOUSE) {
- int sizex, sizey;
- int i;
-
GHOST_TEventCursorData *cd = GHOST_GetEventData(evt);
int cx, cy;
GHOST_ScreenToClient(g_WS.ghost_window, cd->x, cd->y, &cx, &cy);
- playanim_window_get_size(&sizex, &sizey);
- ps->picture = picsbase.first;
- /* TODO - store in ps direct? */
- i = 0;
- while (ps->picture) {
- i++;
- ps->picture = ps->picture->next;
- }
- i = (i * cx) / sizex;
- ps->picture = picsbase.first;
- for (; i > 0; i--) {
- if (ps->picture->next == NULL) break;
- ps->picture = ps->picture->next;
- }
- ps->sstep = true;
- ps->wait2 = false;
- ps->next_frame = 0;
+ change_frame(ps, cx);
}
break;
}
@@ -899,6 +1095,18 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
PlayState ps = {0};
+#ifdef WITH_AUDASPACE
+ AUD_DeviceSpecs specs;
+
+ specs.rate = AUD_RATE_44100;
+ specs.format = AUD_FORMAT_S16;
+ specs.channels = AUD_CHANNELS_STEREO;
+
+ if (!AUD_init(AUD_OPENAL_DEVICE, specs, AUD_DEFAULT_BUFFER_SIZE))
+ AUD_init(AUD_NULL_DEVICE, specs, AUD_DEFAULT_BUFFER_SIZE);
+
+#endif
+
/* ps.doubleb = true;*/ /* UNUSED */
ps.go = true;
ps.direction = true;
@@ -912,6 +1120,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
ps.stopped = false;
ps.loading = false;
ps.picture = NULL;
+ ps.indicator = false;
ps.dropped_file[0] = 0;
ps.zoom = 1.0f;
/* resetmap = false */
@@ -1069,6 +1278,23 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
build_pict_list(&ps, filepath, (efra - sfra) + 1, ps.fstep, ps.fontid);
+#ifdef WITH_AUDASPACE
+ source = AUD_load(filepath);
+ {
+ struct anim *anim_movie = ((struct PlayAnimPict *)picsbase.first)->anim;
+ if (anim_movie) {
+ short frs_sec = 25;
+ float frs_sec_base = 1.0;
+
+ IMB_anim_get_fps(anim_movie, &frs_sec, &frs_sec_base, true);
+
+ fps_movie = (double) frs_sec / (double) frs_sec_base;
+ /* enforce same fps for movie as sound */
+ swaptime = ps.fstep / fps_movie;
+ }
+ }
+#endif
+
for (i = 2; i < argc; i++) {
BLI_strncpy(filepath, argv[i], sizeof(filepath));
build_pict_list(&ps, filepath, (efra - sfra) + 1, ps.fstep, ps.fontid);
@@ -1108,6 +1334,13 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
}
if (ptottime > 0.0) ptottime = 0.0;
+#ifdef WITH_AUDASPACE
+ if (playback_handle)
+ AUD_stop(playback_handle);
+ playback_handle = AUD_play(source, 1);
+ update_sound_fps();
+#endif
+
while (ps.picture) {
int hasevent;
#ifndef USE_IMB_CACHE
@@ -1130,11 +1363,39 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
}
if (ibuf) {
+#ifdef USE_FRAME_CACHE_LIMIT
+ LinkData *node;
+#endif
#ifdef USE_IMB_CACHE
ps.picture->ibuf = ibuf;
#endif
+#ifdef USE_FRAME_CACHE_LIMIT
+ /* really basic memory conservation scheme. Keep frames in a fifo queue */
+ node = inmempicsbase.last;
+
+ while (node && added_images > PLAY_FRAME_CACHE_MAX) {
+ PlayAnimPict *pic = node->data;
+
+ if (pic->ibuf && pic->ibuf != ibuf) {
+ LinkData *node_tmp;
+ IMB_freeImBuf(pic->ibuf);
+ pic->ibuf = NULL;
+ node_tmp = node->prev;
+ BLI_freelinkN(&inmempicsbase, node);
+ added_images--;
+ node = node_tmp;
+ }
+ else {
+ node = node->prev;
+ }
+ }
+
+ BLI_addhead(&inmempicsbase, BLI_genericNodeN(ps.picture));
+ added_images++;
+#endif /* USE_FRAME_CACHE_LIMIT */
+
BLI_strncpy(ibuf->name, ps.picture->name, sizeof(ibuf->name));
/* why only windows? (from 2.4x) - campbell */
@@ -1241,6 +1502,18 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
#endif
BLI_freelistN(&picsbase);
+ BLI_freelistN(&inmempicsbase);
+ added_images = 0;
+
+#ifdef WITH_AUDASPACE
+ if (playback_handle)
+ AUD_stop(playback_handle);
+ if (scrub_handle)
+ AUD_stop(scrub_handle);
+ AUD_unload(source);
+ AUD_exit();
+#endif
+
#if 0 // XXX25
free_blender();
#else
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
new file mode 100644
index 00000000000..60863515dd1
--- /dev/null
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -0,0 +1,584 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 by Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/intern/wm_stereo.c
+ * \ingroup wm
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "DNA_listBase.h"
+
+#include "RNA_access.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_rect.h"
+#include "BLI_utildefines.h"
+
+#include "BIF_gl.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_report.h"
+
+#include "GHOST_C-api.h"
+
+#include "ED_screen.h"
+
+#include "GPU_glew.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "wm.h"
+#include "wm_draw.h" /* wmDrawTriple */
+#include "wm_window.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+static void wm_method_draw_stereo3d_pageflip(wmWindow *win)
+{
+ wmDrawData *drawdata;
+ int view;
+
+ for (view = 0; view < 2; view ++) {
+ drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
+
+ if (view == STEREO_LEFT_ID)
+ glDrawBuffer(GL_BACK_LEFT);
+ else //STEREO_RIGHT_ID
+ glDrawBuffer(GL_BACK_RIGHT);
+
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+ }
+
+ glDrawBuffer(GL_BACK);
+}
+
+static GLuint left_interlace_mask[32];
+static GLuint right_interlace_mask[32];
+static enum eStereo3dInterlaceType interlace_prev_type = -1;
+static char interlace_prev_swap = -1;
+
+static void wm_interlace_masks_create(wmWindow *win)
+{
+ GLuint pattern;
+ char i;
+ bool swap = (win->stereo3d_format->flag & S3D_INTERLACE_SWAP) != 0;
+ enum eStereo3dInterlaceType interlace_type = win->stereo3d_format->interlace_type;
+
+ if (interlace_prev_type == interlace_type && interlace_prev_swap == swap)
+ return;
+
+ switch (interlace_type) {
+ case S3D_INTERLACE_ROW:
+ pattern = 0x00000000;
+ pattern = swap ? ~pattern : pattern;
+ for (i = 0; i < 32; i += 2) {
+ left_interlace_mask[i] = pattern;
+ right_interlace_mask[i] = ~pattern;
+ }
+ for (i = 1; i < 32; i += 2) {
+ left_interlace_mask[i] = ~pattern;
+ right_interlace_mask[i] = pattern;
+ }
+ break;
+ case S3D_INTERLACE_COLUMN:
+ pattern = 0x55555555;
+ pattern = swap ? ~pattern : pattern;
+ for (i = 0; i < 32; i++) {
+ left_interlace_mask[i] = pattern;
+ right_interlace_mask[i] = ~pattern;
+ }
+ break;
+ case S3D_INTERLACE_CHECKERBOARD:
+ default:
+ pattern = 0x55555555;
+ pattern = swap ? ~pattern : pattern;
+ for (i = 0; i < 32; i += 2) {
+ left_interlace_mask[i] = pattern;
+ right_interlace_mask[i] = ~pattern;
+ }
+ for (i = 1; i < 32; i += 2) {
+ left_interlace_mask[i] = ~pattern;
+ right_interlace_mask[i] = pattern;
+ }
+ break;
+ }
+ interlace_prev_type = interlace_type;
+ interlace_prev_swap = swap;
+}
+
+static void wm_method_draw_stereo3d_interlace(wmWindow *win)
+{
+ wmDrawData *drawdata;
+ int view;
+
+ wm_interlace_masks_create(win);
+
+ for (view = 0; view < 2; view ++) {
+ drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
+
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple(view ? (GLubyte *) right_interlace_mask : (GLubyte *) left_interlace_mask);
+
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+ glDisable(GL_POLYGON_STIPPLE);
+ }
+}
+
+static void wm_method_draw_stereo3d_anaglyph(wmWindow *win)
+{
+ wmDrawData *drawdata;
+ int view, bit;
+
+ for (view = 0; view < 2; view ++) {
+ drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
+
+ bit = view + 1;
+ switch (win->stereo3d_format->anaglyph_type) {
+ case S3D_ANAGLYPH_REDCYAN:
+ glColorMask((1&bit) ? GL_TRUE : GL_FALSE,
+ (2&bit) ? GL_TRUE : GL_FALSE,
+ (2&bit) ? GL_TRUE : GL_FALSE,
+ GL_FALSE);
+ break;
+ case S3D_ANAGLYPH_GREENMAGENTA:
+ glColorMask((2&bit) ? GL_TRUE : GL_FALSE,
+ (1&bit) ? GL_TRUE : GL_FALSE,
+ (2&bit) ? GL_TRUE : GL_FALSE,
+ GL_FALSE);
+ break;
+ case S3D_ANAGLYPH_YELLOWBLUE:
+ glColorMask((1&bit) ? GL_TRUE : GL_FALSE,
+ (1&bit) ? GL_TRUE : GL_FALSE,
+ (2&bit) ? GL_TRUE : GL_FALSE,
+ GL_FALSE);
+ break;
+ }
+
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ }
+}
+
+static void wm_method_draw_stereo3d_sidebyside(wmWindow *win)
+{
+ wmDrawData *drawdata;
+ wmDrawTriple *triple;
+ float halfx, halfy, ratiox, ratioy;
+ int x, y, offx, offy;
+ float alpha = 1.0f;
+ int view;
+ int soffx;
+ bool cross_eyed = (win->stereo3d_format->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0;
+
+ for (view = 0; view < 2; view ++) {
+ drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
+ triple = drawdata->triple;
+
+ soffx = WM_window_pixels_x(win) * 0.5f;
+ if (view == STEREO_LEFT_ID) {
+ if (!cross_eyed)
+ soffx = 0;
+ }
+ else { //RIGHT_LEFT_ID
+ if (cross_eyed)
+ soffx = 0;
+ }
+
+ glEnable(triple->target);
+
+ for (y = 0, offy = 0; y < triple->ny; offy += triple->y[y], y++) {
+ for (x = 0, offx = 0; x < triple->nx; offx += triple->x[x], x++) {
+ const int sizex = triple->x[x];
+ const int sizey = triple->y[y];
+
+ /* wmOrtho for the screen has this same offset */
+ ratiox = sizex;
+ ratioy = sizey;
+ halfx = GLA_PIXEL_OFS;
+ halfy = GLA_PIXEL_OFS;
+
+ /* texture rectangle has unnormalized coordinates */
+ if (triple->target == GL_TEXTURE_2D) {
+ ratiox /= triple->x[x];
+ ratioy /= triple->y[y];
+ halfx /= triple->x[x];
+ halfy /= triple->y[y];
+ }
+
+ glBindTexture(triple->target, triple->bind[x + y * triple->nx]);
+
+ glColor4f(1.0f, 1.0f, 1.0f, alpha);
+ glBegin(GL_QUADS);
+ glTexCoord2f(halfx, halfy);
+ glVertex2f(soffx + (offx * 0.5f), offy);
+
+ glTexCoord2f(ratiox + halfx, halfy);
+ glVertex2f(soffx + ((offx + sizex) * 0.5f), offy);
+
+ glTexCoord2f(ratiox + halfx, ratioy + halfy);
+ glVertex2f(soffx + ((offx + sizex) * 0.5f), offy + sizey);
+
+ glTexCoord2f(halfx, ratioy + halfy);
+ glVertex2f(soffx + (offx * 0.5f), offy + sizey);
+ glEnd();
+ }
+ }
+
+ glBindTexture(triple->target, 0);
+ glDisable(triple->target);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ }
+}
+
+static void wm_method_draw_stereo3d_topbottom(wmWindow *win)
+{
+ wmDrawData *drawdata;
+ wmDrawTriple *triple;
+ float halfx, halfy, ratiox, ratioy;
+ int x, y, offx, offy;
+ float alpha = 1.0f;
+ int view;
+ int soffy;
+
+ for (view = 0; view < 2; view ++) {
+ drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
+ triple = drawdata->triple;
+
+ if (view == STEREO_LEFT_ID) {
+ soffy = WM_window_pixels_y(win) * 0.5f;
+ }
+ else { /* STEREO_RIGHT_ID */
+ soffy = 0;
+ }
+
+ glEnable(triple->target);
+
+ for (y = 0, offy = 0; y < triple->ny; offy += triple->y[y], y++) {
+ for (x = 0, offx = 0; x < triple->nx; offx += triple->x[x], x++) {
+ const int sizex = triple->x[x];
+ const int sizey = triple->y[y];
+
+ /* wmOrtho for the screen has this same offset */
+ ratiox = sizex;
+ ratioy = sizey;
+ halfx = GLA_PIXEL_OFS;
+ halfy = GLA_PIXEL_OFS;
+
+ /* texture rectangle has unnormalized coordinates */
+ if (triple->target == GL_TEXTURE_2D) {
+ ratiox /= triple->x[x];
+ ratioy /= triple->y[y];
+ halfx /= triple->x[x];
+ halfy /= triple->y[y];
+ }
+
+ glBindTexture(triple->target, triple->bind[x + y * triple->nx]);
+
+ glColor4f(1.0f, 1.0f, 1.0f, alpha);
+ glBegin(GL_QUADS);
+ glTexCoord2f(halfx, halfy);
+ glVertex2f(offx, soffy + (offy * 0.5f));
+
+ glTexCoord2f(ratiox + halfx, halfy);
+ glVertex2f(offx + sizex, soffy + (offy * 0.5f));
+
+ glTexCoord2f(ratiox + halfx, ratioy + halfy);
+ glVertex2f(offx + sizex, soffy + ((offy + sizey) * 0.5f));
+
+ glTexCoord2f(halfx, ratioy + halfy);
+ glVertex2f(offx, soffy + ((offy + sizey) * 0.5f));
+ glEnd();
+ }
+ }
+
+ glBindTexture(triple->target, 0);
+ glDisable(triple->target);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ }
+}
+
+void wm_method_draw_stereo3d(const bContext *UNUSED(C), wmWindow *win)
+{
+ switch (win->stereo3d_format->display_mode) {
+ case S3D_DISPLAY_ANAGLYPH:
+ wm_method_draw_stereo3d_anaglyph(win);
+ break;
+ case S3D_DISPLAY_INTERLACE:
+ wm_method_draw_stereo3d_interlace(win);
+ break;
+ case S3D_DISPLAY_PAGEFLIP:
+ wm_method_draw_stereo3d_pageflip(win);
+ break;
+ case S3D_DISPLAY_SIDEBYSIDE:
+ wm_method_draw_stereo3d_sidebyside(win);
+ break;
+ case S3D_DISPLAY_TOPBOTTOM:
+ wm_method_draw_stereo3d_topbottom(win);
+ break;
+ default:
+ break;
+ }
+}
+
+static bool wm_stereo3d_quadbuffer_supported(void)
+{
+ int gl_stereo = 0;
+ glGetBooleanv(GL_STEREO, (GLboolean *)&gl_stereo);
+ return gl_stereo != 0;
+}
+
+static bool wm_stereo3d_is_fullscreen_required(eStereoDisplayMode stereo_display)
+{
+ return ELEM(stereo_display,
+ S3D_DISPLAY_SIDEBYSIDE,
+ S3D_DISPLAY_TOPBOTTOM);
+}
+
+bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
+{
+ bScreen *screen = win->screen;
+
+ if ((skip_stereo3d_check == false) && (ED_screen_stereo3d_required(screen) == false)) {
+ return false;
+ }
+
+ if (wm_stereo3d_is_fullscreen_required(win->stereo3d_format->display_mode)) {
+ if (GHOST_GetWindowState(win->ghostwin) != GHOST_kWindowStateFullScreen) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/************************** Stereo 3D operator **********************************/
+typedef struct Stereo3dData {
+ Stereo3dFormat stereo3d_format;
+} Stereo3dData;
+
+static bool wm_stereo3d_set_properties(bContext *UNUSED(C), wmOperator *op)
+{
+ Stereo3dData *s3dd = op->customdata;
+ Stereo3dFormat *s3d = &s3dd->stereo3d_format;
+ PropertyRNA *prop;
+ bool is_set = false;
+
+ prop = RNA_struct_find_property(op->ptr, "display_mode");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ s3d->display_mode = RNA_property_enum_get(op->ptr, prop);
+ is_set = true;
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "anaglyph_type");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ s3d->anaglyph_type = RNA_property_enum_get(op->ptr, prop);
+ is_set = true;
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "interlace_type");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ s3d->interlace_type = RNA_property_enum_get(op->ptr, prop);
+ is_set = true;
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "use_interlace_swap");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ if (RNA_property_boolean_get(op->ptr, prop))
+ s3d->flag |= S3D_INTERLACE_SWAP;
+ else
+ s3d->flag &= ~S3D_INTERLACE_SWAP;
+ is_set = true;
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "use_sidebyside_crosseyed");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ if (RNA_property_boolean_get(op->ptr, prop))
+ s3d->flag |= S3D_SIDEBYSIDE_CROSSEYED;
+ else
+ s3d->flag &= ~S3D_SIDEBYSIDE_CROSSEYED;
+ is_set = true;
+ }
+
+ return is_set;
+}
+
+static void wm_stereo3d_set_init(bContext *C, wmOperator *op)
+{
+ Stereo3dData *s3dd;
+ wmWindow *win = CTX_wm_window(C);
+
+ op->customdata = s3dd = MEM_callocN(sizeof(Stereo3dData), __func__);
+
+ /* store the original win stereo 3d settings in case of cancel */
+ s3dd->stereo3d_format = *win->stereo3d_format;
+}
+
+int wm_stereo3d_set_exec(bContext *C, wmOperator *op)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+ const bool is_fullscreen = WM_window_is_fullscreen(win);
+ char prev_display_mode = win->stereo3d_format->display_mode;
+ Stereo3dData *s3dd;
+ bool ok = true;
+
+ if (G.background)
+ return OPERATOR_CANCELLED;
+
+ if (op->customdata == NULL) {
+ /* no invoke means we need to set the operator properties here */
+ wm_stereo3d_set_init(C, op);
+ wm_stereo3d_set_properties(C, op);
+ }
+
+ s3dd = op->customdata;
+ *win->stereo3d_format = s3dd->stereo3d_format;
+
+ if (prev_display_mode == S3D_DISPLAY_PAGEFLIP &&
+ prev_display_mode != win->stereo3d_format->display_mode)
+ {
+ /* in case the hardward supports pageflip but not the display */
+ if (wm_window_duplicate_exec(C, op) == OPERATOR_FINISHED) {
+ wm_window_close(C, wm, win);
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR,
+ "Failed to create a window without quad-buffer support, you may experience flickering");
+ ok = false;
+ }
+ }
+ else if (win->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP) {
+ /* pageflip requires a new window to be created with the proper OS flags */
+ if (wm_window_duplicate_exec(C, op) == OPERATOR_FINISHED) {
+ if (wm_stereo3d_quadbuffer_supported()) {
+ wm_window_close(C, wm, win);
+ BKE_report(op->reports, RPT_INFO, "Quad-buffer window successfully created");
+ }
+ else {
+ wmWindow *win_new = wm->windows.last;
+ wm_window_close(C, wm, win_new);
+ win->stereo3d_format->display_mode = prev_display_mode;
+ BKE_report(op->reports, RPT_ERROR, "Quad-buffer not supported by the system");
+ ok = false;
+ }
+ }
+ else {
+ win->stereo3d_format->display_mode = prev_display_mode;
+ BKE_report(op->reports, RPT_ERROR,
+ "Failed to create a window compatible with the time sequential display method");
+ ok = false;
+ }
+ }
+
+ if (wm_stereo3d_is_fullscreen_required(s3dd->stereo3d_format.display_mode)) {
+ if (!is_fullscreen) {
+ BKE_report(op->reports, RPT_INFO, "Stereo 3D Mode requires the window to be fullscreen");
+ }
+ }
+
+ MEM_freeN(op->customdata);
+
+ if (ok) {
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ /* without this, the popup won't be freed freed properly T44688 */
+ CTX_wm_window_set(C, win);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+int wm_stereo3d_set_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ wm_stereo3d_set_init(C, op);
+
+ if (wm_stereo3d_set_properties(C, op))
+ return wm_stereo3d_set_exec(C, op);
+ else
+ return WM_operator_props_dialog_popup(C, op, 250, 100);
+}
+
+void wm_stereo3d_set_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ Stereo3dData *s3dd = op->customdata;
+ PointerRNA stereo3d_format_ptr;
+ uiLayout *layout = op->layout;
+ uiLayout *col;
+
+ RNA_pointer_create(NULL, &RNA_Stereo3dDisplay, &s3dd->stereo3d_format, &stereo3d_format_ptr);
+
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, &stereo3d_format_ptr, "display_mode", 0, NULL, ICON_NONE);
+
+ switch (s3dd->stereo3d_format.display_mode) {
+ case S3D_DISPLAY_ANAGLYPH:
+ {
+ uiItemR(col, &stereo3d_format_ptr, "anaglyph_type", 0, NULL, ICON_NONE);
+ break;
+ }
+ case S3D_DISPLAY_INTERLACE:
+ {
+ uiItemR(col, &stereo3d_format_ptr, "interlace_type", 0, NULL, ICON_NONE);
+ uiItemR(col, &stereo3d_format_ptr, "use_interlace_swap", 0, NULL, ICON_NONE);
+ break;
+ }
+ case S3D_DISPLAY_SIDEBYSIDE:
+ {
+ uiItemR(col, &stereo3d_format_ptr, "use_sidebyside_crosseyed", 0, NULL, ICON_NONE);
+ /* fall-through */
+ }
+ case S3D_DISPLAY_PAGEFLIP:
+ case S3D_DISPLAY_TOPBOTTOM:
+ default:
+ {
+ break;
+ }
+ }
+}
+
+bool wm_stereo3d_set_check(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ /* the check function guarantees that the menu is updated to show the
+ * sub-options when an enum change (e.g., it shows the anaglyph options
+ * when anaglyph is on, and the interlace options when this is on */
+ return true;
+}
+
+void wm_stereo3d_set_cancel(bContext *UNUSED(C), wmOperator *op)
+{
+ MEM_freeN(op->customdata);
+ op->customdata = NULL;
+}
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index 4ce2415e310..d081644fa61 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -54,11 +54,12 @@
#include "WM_api.h"
#include "wm_subwindow.h"
-/* wmSubWindow stored in wmWindow... but not exposed outside this C file */
-/* it seems a bit redundant (area regions can store it too, but we keep it
- * because we can store all kind of future opengl fanciness here */
-
-/* we use indices and array because:
+/**
+ * \note #wmSubWindow stored in #wmWindow but not exposed outside this C file,
+ * it seems a bit redundant (area regions can store it too, but we keep it
+ * because we can store all kind of future opengl fanciness here.
+ *
+ * We use indices and array because:
* - index has safety, no pointers from this C file hanging around
* - fast lookups of indices with array, list would give overhead
* - old code used it this way...
diff --git a/source/blender/windowmanager/intern/wm_widgets.c b/source/blender/windowmanager/intern/wm_widgets.c
index 0ae9828ada1..ad915311015 100644
--- a/source/blender/windowmanager/intern/wm_widgets.c
+++ b/source/blender/windowmanager/intern/wm_widgets.c
@@ -100,7 +100,7 @@ static ListBase widgetmaptypes = {NULL, NULL};
struct wmWidgetGroupType *WM_widgetgrouptype_new(
int (*poll)(const struct bContext *C, struct wmWidgetGroupType *),
void (*draw)(const struct bContext *, struct wmWidgetGroup *),
- struct Main *bmain, const char *mapidname, short spaceid, short regionid,bool is_3d
+ struct Main *bmain, const char *mapidname, short spaceid, short regionid, bool is_3d
)
{
bScreen *sc;
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index e341e4900fa..f704e985f8f 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -107,25 +107,25 @@ static struct WMInitStruct {
/* XXX this one should correctly check for apple top header...
* done for Cocoa : returns window contents (and not frame) max size*/
-void wm_get_screensize(int *width_r, int *height_r)
+void wm_get_screensize(int *r_width, int *r_height)
{
unsigned int uiwidth;
unsigned int uiheight;
GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight);
- *width_r = uiwidth;
- *height_r = uiheight;
+ *r_width = uiwidth;
+ *r_height = uiheight;
}
/* size of all screens (desktop), useful since the mouse is bound by this */
-void wm_get_desktopsize(int *width_r, int *height_r)
+void wm_get_desktopsize(int *r_width, int *r_height)
{
unsigned int uiwidth;
unsigned int uiheight;
GHOST_GetAllDisplayDimensions(g_system, &uiwidth, &uiheight);
- *width_r = uiwidth;
- *height_r = uiheight;
+ *r_width = uiwidth;
+ *r_height = uiheight;
}
/* keeps offset and size within monitor bounds */
@@ -206,12 +206,13 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
wm_event_free_all(win);
wm_subwindows_free(win);
-
- if (win->drawdata)
- MEM_freeN(win->drawdata);
-
+
+ wm_draw_data_free(win);
+
wm_ghostwindow_destroy(win);
-
+
+ MEM_freeN(win->stereo3d_format);
+
MEM_freeN(win);
}
@@ -236,6 +237,8 @@ wmWindow *wm_window_new(bContext *C)
BLI_addtail(&wm->windows, win);
win->winid = find_free_winid(wm);
+ win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo 3D Format (window)");
+
return win;
}
@@ -259,8 +262,11 @@ wmWindow *wm_window_copy(bContext *C, wmWindow *winorig)
win->screen->do_draw = true;
win->drawmethod = U.wmdrawmethod;
- win->drawdata = NULL;
-
+
+ BLI_listbase_clear(&win->drawdata);
+
+ *win->stereo3d_format = *winorig->stereo3d_format;
+
return win;
}
@@ -364,7 +370,12 @@ static void wm_window_add_ghostwindow(wmWindowManager *wm, const char *title, wm
* mix it, either all windows have it, or none (tested in OSX opengl) */
if (multisamples == -1)
multisamples = U.ogl_multisamples;
- glSettings.numOfAASamples = multisamples;
+
+ glSettings.numOfAASamples = multisamples;
+
+ /* a new window is created when pageflip mode is required for a window */
+ if (win->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP)
+ glSettings.flags |= GHOST_glStereoVisual;
if (!(U.uiflag2 & USER_OPENGL_NO_WARN_SUPPORT))
glSettings.flags |= GHOST_glWarnSupport;
@@ -518,8 +529,7 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect)
win->sizey = BLI_rcti_size_y(rect);
win->drawmethod = U.wmdrawmethod;
- win->drawdata = NULL;
-
+
WM_check(C);
return win;
@@ -605,12 +615,22 @@ void WM_window_open_temp(bContext *C, rcti *position, int type)
/* operator callback */
int wm_window_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
{
- wm_window_copy(C, CTX_wm_window(C));
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win_src = CTX_wm_window(C);
+ wmWindow *win_dst;
+
+ win_dst = wm_window_copy(C, win_src);
+
WM_check(C);
-
- WM_event_add_notifier(C, NC_WINDOW | NA_ADDED, NULL);
-
- return OPERATOR_FINISHED;
+
+ if (win_dst->ghostwin) {
+ WM_event_add_notifier(C, NC_WINDOW | NA_ADDED, NULL);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ wm_window_close(C, wm, win_dst);
+ return OPERATOR_CANCELLED;
+ }
}
@@ -1097,10 +1117,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
}
-/* This timer system only gives maximum 1 timer event per redraw cycle,
+/**
+ * This timer system only gives maximum 1 timer event per redraw cycle,
* to prevent queues to get overloaded.
- * Timer handlers should check for delta to decide if they just
- * update, or follow real time.
+ * Timer handlers should check for delta to decide if they just update, or follow real time.
* Timer handlers can also set duration to match frames passed
*/
static int wm_window_timer(const bContext *C)
@@ -1131,7 +1151,7 @@ static int wm_window_timer(const bContext *C)
wm_event_init_from_window(win, &event);
event.type = wt->event_type;
- event.val = 0;
+ event.val = KM_NOTHING;
event.keymodifier = 0;
event.custom = EVT_DATA_TIMER;
event.customdata = wt;
@@ -1394,10 +1414,10 @@ void WM_progress_clear(wmWindow *win)
/* ************************************ */
-void wm_window_get_position(wmWindow *win, int *posx_r, int *posy_r)
+void wm_window_get_position(wmWindow *win, int *r_pos_x, int *r_pos_y)
{
- *posx_r = win->posx;
- *posy_r = win->posy;
+ *r_pos_x = win->posx;
+ *r_pos_y = win->posy;
}
void wm_window_set_size(wmWindow *win, int width, int height)
diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h
index 811d5ca6921..a4dad8d48ee 100644
--- a/source/blender/windowmanager/wm.h
+++ b/source/blender/windowmanager/wm.h
@@ -153,6 +153,14 @@ void wm_autosave_delete(void);
void wm_autosave_read(bContext *C, struct ReportList *reports);
void wm_autosave_location(char *filepath);
+/* wm_stereo.c */
+void wm_method_draw_stereo3d(const bContext *C, wmWindow *win);
+int wm_stereo3d_set_exec(bContext *C, wmOperator *op);
+int wm_stereo3d_set_invoke(bContext *C, wmOperator *op, const wmEvent *event);
+void wm_stereo3d_set_draw(bContext *C, wmOperator *op);
+bool wm_stereo3d_set_check(bContext *C, wmOperator *op);
+void wm_stereo3d_set_cancel(bContext *C, wmOperator *op);
+
/* init operator properties */
void wm_open_init_load_ui(wmOperator *op, bool use_prefs);
void wm_open_init_use_scripts(wmOperator *op, bool use_prefs);
diff --git a/source/blender/windowmanager/wm_draw.h b/source/blender/windowmanager/wm_draw.h
index 3d72fe17c79..5dc52b2e4fb 100644
--- a/source/blender/windowmanager/wm_draw.h
+++ b/source/blender/windowmanager/wm_draw.h
@@ -32,6 +32,23 @@
#ifndef __WM_DRAW_H__
#define __WM_DRAW_H__
+#include "GPU_glew.h"
+
+
+#define MAX_N_TEX 3
+
+typedef struct wmDrawTriple {
+ GLuint bind[MAX_N_TEX * MAX_N_TEX];
+ int x[MAX_N_TEX], y[MAX_N_TEX];
+ int nx, ny;
+ GLenum target;
+} wmDrawTriple;
+
+typedef struct wmDrawData {
+ struct wmDrawData *next, *prev;
+ wmDrawTriple *triple;
+} wmDrawData;
+
struct bContext;
struct wmWindow;
struct ARegion;
@@ -43,5 +60,9 @@ void wm_draw_region_clear (struct wmWindow *win, struct ARegion *ar);
void wm_tag_redraw_overlay (struct wmWindow *win, struct ARegion *ar);
+void wm_triple_draw_textures (struct wmWindow *win, struct wmDrawTriple *triple, float alpha);
+
+void wm_draw_data_free (struct wmWindow *win);
+
#endif /* __WM_DRAW_H__ */
diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h
index b21d2657ba6..9127d3ec6f0 100644
--- a/source/blender/windowmanager/wm_event_system.h
+++ b/source/blender/windowmanager/wm_event_system.h
@@ -47,8 +47,8 @@ struct wmWidget;
typedef struct wmEventHandler {
struct wmEventHandler *next, *prev;
- int type; /* WM_HANDLER_DEFAULT, ... */
- int flag; /* WM_HANDLER_BLOCKING, ... */
+ char type; /* WM_HANDLER_DEFAULT, ... */
+ char flag; /* WM_HANDLER_BLOCKING, ... */
/* keymap handler */
wmKeyMap *keymap; /* pointer to builtin/custom keymaps */
@@ -58,6 +58,7 @@ typedef struct wmEventHandler {
wmOperator *op; /* for derived/modal handlers */
struct ScrArea *op_area; /* for derived/modal handlers */
struct ARegion *op_region; /* for derived/modal handlers */
+ short op_region_type; /* for derived/modal handlers */
/* ui handler */
wmUIHandlerFunc ui_handle; /* callback receiving events */
@@ -80,13 +81,6 @@ enum {
WM_HANDLER_FILESELECT
};
-/* handler flag */
-enum {
- WM_HANDLER_BLOCKING = (1 << 0), /* after this handler all others are ignored */
- WM_HANDLER_DO_FREE = (1 << 1), /* handler tagged to be freed in wm_handlers_do() */
- WM_HANDLER_ACCEPT_DBL_CLICK = (1 << 2), /* handler accepts double key press events */
-};
-
/* wm_event_system.c */
void wm_event_free_all (wmWindow *win);
void wm_event_free (wmEvent *event);
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index 833234b0f13..95dc8762ae7 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -32,15 +32,14 @@
#ifndef __WM_WINDOW_H__
#define __WM_WINDOW_H__
-struct bScreen;
struct wmOperator;
/* *************** internal api ************** */
void wm_ghost_init (bContext *C);
void wm_ghost_exit(void);
-void wm_get_screensize(int *width_r, int *height_r);
-void wm_get_desktopsize(int *width_r, int *height_r);
+void wm_get_screensize(int *r_width, int *r_height);
+void wm_get_desktopsize(int *r_width, int *r_height);
wmWindow *wm_window_new (bContext *C);
void wm_window_free (bContext *C, wmWindowManager *wm, wmWindow *win);
@@ -56,7 +55,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win);
void wm_window_raise (wmWindow *win);
void wm_window_lower (wmWindow *win);
void wm_window_set_size (wmWindow *win, int width, int height);
-void wm_window_get_position (wmWindow *win, int *posx_r, int *posy_r);
+void wm_window_get_position (wmWindow *win, int *r_pos_x, int *r_pos_y);
void wm_window_swap_buffers (wmWindow *win);
void wm_window_set_swap_interval(wmWindow *win, int interval);
bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut);
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index 25ee4f2ef21..7a322c5d8d8 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -106,6 +106,7 @@ endif()
bf_intern_ghostndof3dconnexion
bf_rna
bf_blenkernel
+ bf_depsgraph
bf_physics
bf_intern_rigidbody
bf_blenloader
@@ -149,6 +150,8 @@ endif()
bf_dna
ge_videotex
bf_blenfont
+ bf_pointcache_alembic
+ bf_pointcache
bf_intern_audaspace
blenkernel_blc
bf_bmesh
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index bb45ba612e9..3310abbc64c 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -96,6 +96,7 @@ struct ScrArea;
struct SculptSession;
struct ShadeInput;
struct ShadeResult;
+struct SpaceButs;
struct SpaceClip;
struct SpaceImage;
struct SpaceNode;
@@ -225,12 +226,21 @@ void EDBM_mesh_normals_update(struct BMEditMesh *em) RET_NONE
void *g_system;
bool EDBM_mtexpoly_check(struct BMEditMesh *em) RET_ZERO
-float *RE_RenderLayerGetPass(struct RenderLayer *rl, int passtype) RET_NULL
+float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, int passtype, const char *viewname) RET_NULL
float RE_filter_value(int type, float x) RET_ZERO
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name) RET_NULL
void RE_init_texture_rng() RET_NONE
void RE_exit_texture_rng() RET_NONE
+bool RE_layers_have_name(struct RenderResult *result) {STUB_ASSERT(0); return 0;}
+void RE_engine_active_view_set(struct RenderEngine *engine, const char *viewname) {STUB_ASSERT(0);}
+void RE_engine_get_camera_model_matrix(struct RenderEngine *engine, struct Object *camera, float *r_modelmat) {STUB_ASSERT(0);}
+float RE_engine_get_camera_shift_x(struct RenderEngine *engine, struct Object *camera) RET_ZERO
+void RE_SetActiveRenderView(struct Render *re, const char *viewname) {STUB_ASSERT(0);}
+
+struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int passtype, const char *viewname) RET_NULL
+bool RE_HasFakeLayer(RenderResult *res) RET_ZERO
+
/* 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
@@ -254,6 +264,7 @@ void RE_sample_material_color(struct Material *mat, float color[3], float *alpha
/* nodes */
struct Render *RE_GetRender(const char *name) RET_NULL
+struct Object *RE_GetCamera(struct Render *re) RET_NULL
float RE_lamp_get_data(struct ShadeInput *shi, struct Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4]) RET_ZERO
/* blenkernel */
@@ -417,7 +428,7 @@ short ANIM_validate_keyingset(struct bContext *C, struct ListBase *dsources, str
int ANIM_add_driver(struct ReportList *reports, struct ID *id, const char rna_path[], int array_index, short flag, int type) RET_ZERO
bool ANIM_remove_driver(struct ReportList *reports, struct ID *id, const char rna_path[], int array_index, short flag) RET_ZERO
void ED_space_image_release_buffer(struct SpaceImage *sima, struct ImBuf *ibuf, void *lock) RET_NONE
-struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **lock_r) RET_NULL
+struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock) RET_NULL
void ED_space_image_get_zoom(struct SpaceImage *sima, struct ARegion *ar, float *zoomx, float *zoomy) RET_NONE
const char *ED_info_stats_string(struct Scene *scene) RET_NULL
void ED_area_tag_redraw(struct ScrArea *sa) RET_NONE
@@ -473,7 +484,7 @@ void uiLayoutSetEnabled(uiLayout *layout, bool enabled) RET_NONE
void uiLayoutSetAlignment(uiLayout *layout, char alignment) RET_NONE
void uiLayoutSetScaleX(struct uiLayout *layout, float scale) RET_NONE
void uiLayoutSetScaleY(struct uiLayout *layout, float scale) RET_NONE
-void uiTemplateIconView(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname) RET_NONE
+void uiTemplateIconView(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, int show_labels) RET_NONE
void ED_base_object_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Base *base) RET_NONE
void ED_mesh_update(struct Mesh *mesh, struct bContext *C, int calc_edges, int calc_tessface) RET_NONE
void ED_mesh_vertices_add(struct Mesh *mesh, struct ReportList *reports, int count) RET_NONE
@@ -489,7 +500,9 @@ int ED_mesh_uv_texture_add(struct Mesh *me, const char *name, const bool active_
bool ED_mesh_color_remove_named(struct Mesh *me, const char *name) RET_ZERO
bool ED_mesh_uv_texture_remove_named(struct Mesh *me, const char *name) RET_ZERO
void ED_object_constraint_dependency_update(struct Main *bmain, struct Object *ob) RET_NONE
+void ED_object_constraint_dependency_tag_update(struct Main *bmain, struct Object *ob, struct bConstraint *con) RET_NONE
void ED_object_constraint_update(struct Object *ob) RET_NONE
+void ED_object_constraint_tag_update(struct Object *ob, struct bConstraint *con) RET_NONE
void ED_vgroup_vert_add(struct Object *ob, struct bDeformGroup *dg, int vertnum, float weight, int assignmode) RET_NONE
void ED_vgroup_vert_remove(struct Object *ob, struct bDeformGroup *dg, int vertnum) RET_NONE
float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vertnum) RET_ZERO
@@ -531,8 +544,6 @@ struct uiLayout *uiLayoutColumn(uiLayout *layout, int align) RET_NULL
struct uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align) RET_NULL
struct uiLayout *uiLayoutBox(struct uiLayout *layout) RET_NULL
struct uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align) RET_NULL
-void uiLayoutSubblockBegin(uiLayout *layout, const char *identifier) RET_NONE
-void uiLayoutSubblockEnd(uiLayout *layout) RET_NONE
bool uiLayoutGetRedAlert(struct uiLayout *layout) RET_ZERO
void uiLayoutSetRedAlert(uiLayout *layout, bool redalert) RET_NONE
void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname) RET_NONE
@@ -599,9 +610,12 @@ void uiTemplateColormanagedViewSettings(struct uiLayout *layout, struct bContext
void uiTemplateComponentMenu(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name) RET_NONE
void uiTemplateNodeSocket(struct uiLayout *layout, struct bContext *C, float *color) RET_NONE
void uiTemplatePalette(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, int color) RET_NONE
+void uiTemplateImageStereo3d(struct uiLayout *layout, struct PointerRNA *stereo3d_format_ptr) RET_NONE
+struct uiLayout *uiTemplateCacheLibraryItem(struct uiLayout *layout, struct bContext *C, struct CacheLibrary *cachelib,
+ struct Object *ob, int type, int index, int enabled) RET_NULL
/* rna render */
-struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername) RET_NULL
+struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname) RET_NULL
struct RenderResult *RE_AcquireResultRead(struct Render *re) RET_NULL
struct RenderResult *RE_AcquireResultWrite(struct Render *re) RET_NULL
struct RenderStats *RE_GetStats(struct Render *re) RET_NULL
@@ -613,7 +627,7 @@ void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result, int
void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info) RET_NONE
void RE_layer_load_from_file(struct RenderLayer *layer, struct ReportList *reports, const char *filename, int x, int y) RET_NONE
void RE_result_load_from_file(struct RenderResult *result, struct ReportList *reports, const char *filename) RET_NONE
-void RE_AcquireResultImage(struct Render *re, struct RenderResult *rr) RET_NONE
+void RE_AcquireResultImage(struct Render *re, struct RenderResult *rr, const int view_id) RET_NONE
void RE_ReleaseResult(struct Render *re) RET_NONE
void RE_ReleaseResultImage(struct Render *re) RET_NONE
int RE_engine_test_break(struct RenderEngine *engine) RET_ZERO
@@ -627,6 +641,7 @@ void RE_engine_update_memory_stats(struct RenderEngine *engine, float mem_used,
struct RenderEngine *RE_engine_create(struct RenderEngineType *type) RET_NULL
void RE_engine_frame_set(struct RenderEngine *engine, int frame, float subframe) RET_NONE
void RE_FreePersistentData(void) RET_NONE
+void RE_sample_point_density(struct Scene *scene, struct PointDensity *pd, int resolution, float *values) RET_NONE;
/* python */
struct wmOperatorType *WM_operatortype_find(const char *idname, bool quiet) RET_NULL
@@ -728,6 +743,11 @@ struct CCLDeviceInfo *CCL_compute_device_list(int opencl) RET_NULL
/* compositor */
void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rendering,
- const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings) RET_NONE
+ const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
+ const char *viewName) RET_NONE
+
+/*multiview*/
+bool RE_RenderResult_is_stereo(RenderResult *res) RET_ZERO
+void uiTemplateImageViews(uiLayout *layout, struct PointerRNA *imfptr) RET_NONE
#endif // WITH_GAMEENGINE
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index f51b7bec7c9..c4647a86b93 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -31,11 +31,13 @@ blender_include_dirs(
../blender/blenlib
../blender/blenkernel
../blender/blenloader
+ ../blender/depsgraph
../blender/editors/include
../blender/makesrna
../blender/imbuf
../blender/render/extern/include
../blender/makesdna
+ ../blender/pointcache
../blender/gpu
../blender/windowmanager
)
@@ -239,13 +241,13 @@ if(WITH_BUILDINFO)
add_dependencies(blender buildinfo)
endif()
-# Post build steps for bundling/packaging.
set(BLENDER_TEXT_FILES
${CMAKE_SOURCE_DIR}/release/text/GPL-license.txt
${CMAKE_SOURCE_DIR}/release/text/Python-license.txt
${CMAKE_SOURCE_DIR}/release/text/copyright.txt
- ${CMAKE_SOURCE_DIR}/release/text/readme.html
+ # generate this file
+ # ${CMAKE_SOURCE_DIR}/release/text/readme.html
${CMAKE_SOURCE_DIR}/release/datafiles/LICENSE-bfont.ttf.txt
)
@@ -261,11 +263,15 @@ endif()
# Platform Specific Var: TARGETDIR_VER
if(UNIX AND NOT APPLE)
- if(WITH_INSTALL_PORTABLE)
- set(TARGETDIR_VER ${BLENDER_VERSION})
+ if(WITH_PYTHON_MODULE)
+ if(WITH_INSTALL_PORTABLE)
+ set(TARGETDIR_VER ${BLENDER_VERSION})
+ else()
+ set(TARGETDIR_VER ${PYTHON_SITE_PACKAGES}/${BLENDER_VERSION})
+ endif()
else()
- if(WITH_PYTHON_MODULE)
- set(TARGETDIR_VER ${PYTHON_LIBPATH}/python${PYTHON_VERSION}/site-packages/${BLENDER_VERSION})
+ if(WITH_INSTALL_PORTABLE)
+ set(TARGETDIR_VER ${BLENDER_VERSION})
else()
set(TARGETDIR_VER share/blender/${BLENDER_VERSION})
endif()
@@ -407,22 +413,31 @@ if(UNIX AND NOT APPLE)
endif()
# there are a few differences between portable and system install
- if(WITH_INSTALL_PORTABLE)
- if(WITH_PYTHON_MODULE)
- # pass
+ if(WITH_PYTHON_MODULE)
+ if(WITH_INSTALL_PORTABLE)
+ install(
+ TARGETS blender
+ DESTINATION "."
+ )
else()
- if(WITH_DOC_MANPAGE)
- install(
- FILES ${CMAKE_CURRENT_BINARY_DIR}/blender.1
- DESTINATION "."
- )
- endif()
+ install(
+ TARGETS blender
+ LIBRARY DESTINATION ${PYTHON_SITE_PACKAGES}
+ )
endif()
+ # none of the other files are needed currently
+ elseif(WITH_INSTALL_PORTABLE)
install(
TARGETS blender
DESTINATION "."
)
+ if(WITH_DOC_MANPAGE)
+ install(
+ FILES ${CMAKE_CURRENT_BINARY_DIR}/blender.1
+ DESTINATION "."
+ )
+ endif()
install(
FILES
${CMAKE_SOURCE_DIR}/release/freedesktop/blender.desktop
@@ -436,30 +451,19 @@ if(UNIX AND NOT APPLE)
DESTINATION "."
)
- install(
- FILES ${BLENDER_TEXT_FILES}
- DESTINATION "."
- )
-
+ set(BLENDER_TEXT_FILES_DESTINATION ".")
else()
# main blender binary
- if(WITH_PYTHON_MODULE)
- install(
- TARGETS blender
- LIBRARY DESTINATION ${PYTHON_LIBPATH}/python${PYTHON_VERSION}/site-packages
- )
- else()
+ install(
+ TARGETS blender
+ DESTINATION bin
+ )
+ if(WITH_DOC_MANPAGE)
+ # manpage only with 'blender' binary
install(
- TARGETS blender
- DESTINATION bin
+ FILES ${CMAKE_CURRENT_BINARY_DIR}/blender.1
+ DESTINATION share/man/man1
)
- if(WITH_DOC_MANPAGE)
- # manpage only with 'blender' binary
- install(
- FILES ${CMAKE_CURRENT_BINARY_DIR}/blender.1
- DESTINATION share/man/man1
- )
- endif()
endif()
# misc files
@@ -486,14 +490,17 @@ if(UNIX AND NOT APPLE)
PROGRAMS ${CMAKE_SOURCE_DIR}/release/bin/blender-thumbnailer.py
DESTINATION bin
)
- install(
- FILES ${BLENDER_TEXT_FILES}
- DESTINATION share/doc/blender
- )
+ set(BLENDER_TEXT_FILES_DESTINATION share/doc/blender)
endif()
if(WITH_PYTHON)
if(WITH_PYTHON_INSTALL)
+
+ install(
+ FILES ${PYTHON_EXECUTABLE}
+ DESTINATION ${TARGETDIR_VER}/python/bin
+ )
+
# on some platforms (like openSUSE) Python is linked
# to be used from lib64 folder.
# determine this from Python's libraries path
@@ -602,10 +609,7 @@ if(UNIX AND NOT APPLE)
endif()
elseif(WIN32)
- install(
- FILES ${BLENDER_TEXT_FILES}
- DESTINATION "."
- )
+ set(BLENDER_TEXT_FILES_DESTINATION ".")
if(WITH_PYTHON)
string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
@@ -647,9 +651,9 @@ elseif(WIN32)
execute_process(
COMMAND \${CMAKE_COMMAND} -E make_directory
- \"\${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/python/lib\"
+ \"\${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/python\"
COMMAND \${CMAKE_COMMAND} -E
- chdir \"\${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/python/lib\"
+ chdir \"\${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/python\"
\${CMAKE_COMMAND} -E
tar xzfv \"\${PYTHON_ZIP}\"
)
@@ -847,10 +851,7 @@ elseif(APPLE)
)
# install release and app files
- install(
- FILES ${BLENDER_TEXT_FILES}
- DESTINATION blender.app/Contents
- )
+ set(BLENDER_TEXT_FILES_DESTINATION ".")
install(
FILES ${OSX_APP_SOURCEDIR}/Contents/PkgInfo
@@ -867,6 +868,11 @@ elseif(APPLE)
FILES ${LIBDIR}/openmp/lib/libiomp5.dylib
DESTINATION blender.app/Contents/Resources/lib/
)
+ install(
+ FILES ${LIBDIR}/openmp/LICENSE.txt
+ DESTINATION "."
+ RENAME LICENSE-libiomp5.txt
+ )
endif()
if(WITH_LLVM AND NOT LLVM_STATIC)
@@ -968,12 +974,33 @@ endif()
# -----------------------------------------------------------------------------
# Generic Install, for all targets
+if(DEFINED BLENDER_TEXT_FILES_DESTINATION)
+
+ install(
+ CODE
+ "
+ file(READ \"${CMAKE_SOURCE_DIR}/release/text/readme.html\" DATA_SRC)
+ string(REGEX REPLACE \"BLENDER_VERSION\" \"${BLENDER_VERSION}\" DATA_DST \"\${DATA_SRC}\")
+ file(WRITE \"\${CMAKE_BINARY_DIR}/release/text/readme.html\" \"\${DATA_DST}\")
+ unset(DATA_SRC)
+ unset(DATA_DST)
+ "
+ )
+ list(APPEND BLENDER_TEXT_FILES
+ ${CMAKE_BINARY_DIR}/release/text/readme.html
+ )
+ install(
+ FILES ${BLENDER_TEXT_FILES}
+ DESTINATION "${BLENDER_TEXT_FILES_DESTINATION}"
+ )
+endif()
# install more files specified elsewhere
delayed_do_install(${TARGETDIR_VER})
unset(BLENDER_TEXT_FILES)
+unset(BLENDER_TEXT_FILES_DESTINATION)
# -----------------------------------------------------------------------------
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 47ee1ec4aec..9b88cbe2070 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -93,8 +93,12 @@
#include "BKE_image.h"
#include "BKE_particle.h"
+#include "DEG_depsgraph.h"
+
#include "IMB_imbuf.h" /* for IMB_init */
+#include "PTC_api.h"
+
#ifdef WITH_PYTHON
#include "BPY_extern.h"
#endif
@@ -320,6 +324,7 @@ static int print_help(int UNUSED(argc), const char **UNUSED(argv), void *data)
BLI_argsPrintArgDoc(ba, "--debug-jobs");
BLI_argsPrintArgDoc(ba, "--debug-python");
BLI_argsPrintArgDoc(ba, "--debug-depsgraph");
+ BLI_argsPrintArgDoc(ba, "--debug-depsgraph-no-threads");
BLI_argsPrintArgDoc(ba, "--debug-wm");
BLI_argsPrintArgDoc(ba, "--debug-all");
@@ -357,6 +362,10 @@ static int print_help(int UNUSED(argc), const char **UNUSED(argv), void *data)
printf("Other Options:\n");
BLI_argsPrintOtherDoc(ba);
+ printf("\n");
+ printf("Experimental features:\n");
+ BLI_argsPrintArgDoc(ba, "--enable-new-depsgraph");
+
printf("Argument Parsing:\n");
printf("\targuments must be separated by white space. eg\n");
printf("\t\t\"blender -ba test.blend\"\n");
@@ -598,10 +607,9 @@ static void blender_crash_handler(int signum)
}
#ifdef WIN32
-LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS * ExceptionInfo)
+LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
{
- switch(ExceptionInfo->ExceptionRecord->ExceptionCode)
- {
+ switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
case EXCEPTION_ACCESS_VIOLATION:
fputs("Error: EXCEPTION_ACCESS_VIOLATION\n", stderr);
break;
@@ -671,9 +679,12 @@ LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS * ExceptionInfo)
/* If this is a stack overflow then we can't walk the stack, so just show
* where the error happened */
- if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode)
- {
+ if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) {
+#ifdef NDEBUG
+ TerminateProcess(GetCurrentProcess(), SIGSEGV);
+#else
blender_crash_handler(SIGSEGV);
+#endif
}
return EXCEPTION_EXECUTE_HANDLER;
@@ -813,7 +824,7 @@ static int no_glsl(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(dat
static int no_audio(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
- sound_force_device(0);
+ BKE_sound_force_device(0);
return 0;
}
@@ -824,7 +835,7 @@ static int set_audio(int argc, const char **argv, void *UNUSED(data))
exit(1);
}
- sound_force_device(sound_define_from_str(argv[1]));
+ BKE_sound_force_device(BKE_sound_define_from_str(argv[1]));
return 1;
}
@@ -931,6 +942,13 @@ static int set_threads(int argc, const char **argv, void *UNUSED(data))
}
}
+static int depsgraph_use_new(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ printf("Using new dependency graph.\n");
+ DEG_depsgraph_switch_to_new();
+ return 0;
+}
+
static int set_verbosity(int argc, const char **argv, void *UNUSED(data))
{
if (argc > 1) {
@@ -1026,6 +1044,7 @@ static int set_ge_parameters(int argc, const char **argv, void *data)
}
/* linearMipMap */
if (STREQ(argv[a], "linearmipmap")) {
+ GPU_set_mipmap(1);
GPU_set_linear_mipmap(1); //linearMipMap = 1;
}
@@ -1187,19 +1206,24 @@ static int set_skip_frame(int argc, const char **argv, void *data)
#define BPY_CTX_SETUP(_cmd) \
{ \
wmWindowManager *wm = CTX_wm_manager(C); \
- wmWindow *prevwin = CTX_wm_window(C); \
- Scene *prevscene = CTX_data_scene(C); \
- if (wm->windows.first) { \
+ Scene *scene_prev = CTX_data_scene(C); \
+ wmWindow *win_prev; \
+ const bool has_win = !BLI_listbase_is_empty(&wm->windows); \
+ if (has_win) { \
+ win_prev = CTX_wm_window(C); \
CTX_wm_window_set(C, wm->windows.first); \
- _cmd; \
- CTX_wm_window_set(C, prevwin); \
} \
else { \
fprintf(stderr, "Python script \"%s\" " \
"running with missing context data.\n", argv[1]); \
+ } \
+ { \
_cmd; \
} \
- CTX_data_scene_set(C, prevscene); \
+ if (has_win) { \
+ CTX_wm_window_set(C, win_prev); \
+ } \
+ CTX_data_scene_set(C, scene_prev); \
} (void)0 \
#endif /* WITH_PYTHON */
@@ -1366,8 +1390,8 @@ static int load_file(int UNUSED(argc), const char **argv, void *data)
BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
/* happens for the UI on file reading too (huh? (ton))*/
- // XXX BKE_reset_undo();
- // BKE_write_undo("original"); /* save current state */
+ // XXX BKE_undo_reset();
+ // BKE_undo_write("original"); /* save current state */
}
else {
/* we are not running in background mode here, but start blender in UI mode with
@@ -1488,6 +1512,10 @@ static void setupArguments(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
BLI_argsAdd(ba, 1, NULL, "--debug-value", "<value>\n\tSet debug value of <value> on startup\n", set_debug_value, NULL);
BLI_argsAdd(ba, 1, NULL, "--debug-jobs", "\n\tEnable time profiling for background jobs.", debug_mode_generic, (void *)G_DEBUG_JOBS);
BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph", "\n\tEnable debug messages from dependency graph", debug_mode_generic, (void *)G_DEBUG_DEPSGRAPH);
+ BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph-no-threads", "\n\tSwitch dependency graph to a single threaded evlauation", debug_mode_generic, (void *)G_DEBUG_DEPSGRAPH_NO_THREADS);
+ BLI_argsAdd(ba, 1, NULL, "--debug-gpumem", "\n\tEnable GPU memory stats in status bar", debug_mode_generic, (void *)G_DEBUG_GPU_MEM);
+
+ BLI_argsAdd(ba, 1, NULL, "--enable-new-depsgraph", "\n\tUse new dependency graph", depsgraph_use_new, NULL);
BLI_argsAdd(ba, 1, NULL, "--verbose", "<verbose>\n\tSet logging verbosity level.", set_verbosity, NULL);
@@ -1556,13 +1584,13 @@ char **environ = NULL;
* or exit when running in background mode.
*/
int main(
- int argc,
+ int argc,
#ifdef WIN32
const char **UNUSED(argv_c)
#else
const char **argv
#endif
- )
+ )
{
bContext *C;
SYS_SystemHandle syshandle;
@@ -1572,6 +1600,14 @@ int main(
#endif
#ifdef WIN32
+ char **argv;
+ int argv_num;
+#endif
+
+ /* --- end declarations --- */
+
+
+#ifdef WIN32
/* FMA3 support in the 2013 CRT is broken on Vista and Windows 7 RTM (fixed in SP1). Just disable it. */
# if defined(_MSC_VER) && _MSC_VER >= 1800 && defined(_M_X64)
_set_FMA3_enable(0);
@@ -1581,16 +1617,15 @@ int main(
/* NOTE: cannot use guardedalloc malloc here, as it's not yet initialized
* (it depends on the args passed in, which is what we're getting here!)
*/
- wchar_t **argv_16 = CommandLineToArgvW(GetCommandLineW(), &argc);
- char **argv = malloc(argc * sizeof(char *));
- int argci = 0;
-
- for (argci = 0; argci < argc; argci++) {
- argv[argci] = alloc_utf_8_from_16(argv_16[argci], 0);
+ {
+ wchar_t **argv_16 = CommandLineToArgvW(GetCommandLineW(), &argc);
+ argv = malloc(argc * sizeof(char *));
+ for (argv_num = 0; argv_num < argc; argv_num++) {
+ argv[argv_num] = alloc_utf_8_from_16(argv_16[argv_num], 0);
+ }
+ LocalFree(argv_16);
}
-
- LocalFree(argv_16);
-#endif
+#endif /* WIN32 */
/* NOTE: Special exception for guarded allocator type switch:
* we need to perform switch from lock-free to fully
@@ -1658,7 +1693,7 @@ int main(
setCallbacks();
#if defined(__APPLE__) && !defined(WITH_PYTHON_MODULE)
-/* patch to ignore argument finder gives us (pid?) */
+ /* patch to ignore argument finder gives us (pid?) */
if (argc == 2 && STREQLEN(argv[1], "-psn_", 5)) {
extern int GHOST_HACK_getFirstFile(char buf[]);
static char firstfilebuf[512];
@@ -1691,6 +1726,9 @@ int main(
BKE_brush_system_init();
RE_init_texture_rng();
+ /* Initialize ffmpeg if built in, also needed for bg mode if videos are
+ * rendered via ffmpeg */
+ BKE_sound_init_once();
BLI_callback_global_init();
@@ -1735,6 +1773,7 @@ int main(
RE_engines_init();
init_nodesystem();
psys_init_rng();
+ PTC_alembic_init();
/* end second init */
@@ -1750,10 +1789,6 @@ int main(
/* background render uses this font too */
BKE_vfont_builtin_register(datatoc_bfont_pfb, datatoc_bfont_pfb_size);
- /* Initialize ffmpeg if built in, also needed for bg mode if videos are
- * rendered via ffmpeg */
- sound_init_once();
-
init_def_material();
if (G.background == 0) {
@@ -1816,8 +1851,8 @@ int main(
#endif
#ifdef WIN32
- while (argci) {
- free(argv[--argci]);
+ while (argv_num) {
+ free(argv[--argv_num]);
}
free(argv);
argv = NULL;
diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
index 511b61528f8..1a198920919 100644
--- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
+++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
@@ -446,7 +446,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
rasterizer->SetEyeSeparation(scene->gm.eyeseparation);
}
- rasterizer->SetBackColor(scene->gm.framing.col[0], scene->gm.framing.col[1], scene->gm.framing.col[2], 0.0f);
+ rasterizer->SetBackColor(scene->gm.framing.col);
}
if (exitrequested != KX_EXIT_REQUEST_QUIT_GAME)
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
index 3a31806fad4..e37818678d6 100644
--- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
+++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
@@ -97,6 +97,11 @@ bool KX_BlenderCanvas::GetSwapInterval(int &intervalOut)
return wm_window_get_swap_interval(m_win, &intervalOut);
}
+void KX_BlenderCanvas::GetDisplayDimensions(int &width, int &height)
+{
+ wm_get_screensize(&width, &height);
+}
+
void KX_BlenderCanvas::ResizeWindow(int width, int height)
{
// Not implemented for the embedded player
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h
index c150af21230..817a667d783 100644
--- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h
+++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h
@@ -87,6 +87,8 @@ public:
int &intervalOut
);
+ void GetDisplayDimensions(int &width, int &height);
+
void
ResizeWindow(
int width,
diff --git a/source/gameengine/CMakeLists.txt b/source/gameengine/CMakeLists.txt
index cf7895e98ea..62523175f46 100644
--- a/source/gameengine/CMakeLists.txt
+++ b/source/gameengine/CMakeLists.txt
@@ -23,6 +23,8 @@
#
# ***** END GPL LICENSE BLOCK *****
+remove_extra_strict_flags()
+
# there are too many inter-includes so best define here
if(WITH_PYTHON)
blender_include_dirs_sys("${PYTHON_INCLUDE_DIRS}")
diff --git a/source/gameengine/Converter/BL_ArmatureConstraint.cpp b/source/gameengine/Converter/BL_ArmatureConstraint.cpp
index e515574df8b..88d82e21d61 100644
--- a/source/gameengine/Converter/BL_ArmatureConstraint.cpp
+++ b/source/gameengine/Converter/BL_ArmatureConstraint.cpp
@@ -334,7 +334,7 @@ PyObject *BL_ArmatureConstraint::py_attr_getattr(void *self_v, const struct KX_P
}
switch (attr_order) {
case BCA_IKWEIGHT:
- return PyFloat_FromDouble((ikconstraint)?ikconstraint->weight : 0.0f);
+ return PyFloat_FromDouble(ikconstraint->weight);
case BCA_IKTYPE:
return PyLong_FromLong(ikconstraint->type);
case BCA_IKFLAG:
diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp
index bc2fc0179fd..795a7a9ae87 100644
--- a/source/gameengine/Converter/BL_ArmatureObject.cpp
+++ b/source/gameengine/Converter/BL_ArmatureObject.cpp
@@ -268,7 +268,7 @@ void BL_ArmatureObject::LoadConstraints(KX_BlenderSceneConverter* converter)
// get the persistent pose structure
bPoseChannel* pchan;
bConstraint* pcon;
- bConstraintTypeInfo* cti;
+ const bConstraintTypeInfo* cti;
Object* blendtarget;
KX_GameObject* gametarget;
KX_GameObject* gamesubtarget;
diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
index 7e0588fc7d0..3da0863508b 100644
--- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp
+++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
@@ -98,7 +98,7 @@
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
-#include "BlenderWorldInfo.h"
+#include "KX_WorldInfo.h"
#include "KX_KetsjiEngine.h"
#include "KX_BlenderSceneConverter.h"
@@ -995,7 +995,6 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, KX_Scene* scene,
meshobj->m_sharedvertex_map.resize(totvert);
Material* ma = 0;
- bool collider = true;
MT_Point2 uvs[4][RAS_TexVert::MAX_UNIT];
unsigned int rgb[4] = {0};
@@ -1065,29 +1064,19 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, KX_Scene* scene,
else
ma = mesh->mat ? mesh->mat[mface->mat_nr]:NULL;
- /* ckeck for texface since texface _only_ is used as a fallback */
- if (ma == NULL && tface == NULL) {
+ // Check for blender material
+ if (ma == NULL) {
ma= &defmaterial;
}
{
- bool visible = true;
- bool twoside = false;
RAS_MaterialBucket* bucket = material_from_mesh(ma, mface, tface, mcol, layers, lightlayer, rgb, uvs, tfaceName, scene, converter);
// set render flags
- if (ma)
- {
- visible = ((ma->game.flag & GEMAT_INVISIBLE)==0);
- twoside = ((ma->game.flag & GEMAT_BACKCULL)==0);
- collider = ((ma->game.flag & GEMAT_NOPHYSICS)==0);
- }
- else {
- visible = true;
- twoside = false;
- collider = true;
- }
+ bool visible = ((ma->game.flag & GEMAT_INVISIBLE)==0);
+ bool twoside = ((ma->game.flag & GEMAT_BACKCULL)==0);
+ bool collider = ((ma->game.flag & GEMAT_NOPHYSICS)==0);
/* mark face as flat, so vertices are split */
bool flat = (mface->flag & ME_SMOOTH) == 0;
@@ -1347,8 +1336,8 @@ static void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj,
if (!(blenderobject->gameflag & OB_COLLISION)) {
// Respond to all collisions so that Near sensors work on No Collision
// objects.
- gameobj->SetUserCollisionGroup(0xff);
- gameobj->SetUserCollisionMask(0xff);
+ gameobj->SetUserCollisionGroup(0xffff);
+ gameobj->SetUserCollisionMask(0xffff);
return;
}
@@ -1554,6 +1543,10 @@ static KX_GameObject *gameobject_from_blenderobject(
}
gameobj->AddLodMesh(BL_ConvertMesh(lodmesh, lodmatob, kxscene, converter, libloading));
}
+ if (blenderscene->gm.lodflag & SCE_LOD_USE_HYST) {
+ kxscene->SetLodHysteresis(true);
+ kxscene->SetLodHysteresisValue(blenderscene->gm.scehysteresis);
+ }
}
// for all objects: check whether they want to
@@ -1647,7 +1640,7 @@ static KX_GameObject *gameobject_from_blenderobject(
case OB_FONT:
{
- bool do_color_management = !(blenderscene->gm.flag & GAME_GLSL_NO_COLOR_MANAGEMENT);
+ bool do_color_management = BKE_scene_check_color_management_enabled(blenderscene);
/* font objects have no bounding box */
gameobj = new KX_FontObject(kxscene,KX_Scene::m_callbacks, rendertools, ob, do_color_management);
@@ -1741,6 +1734,16 @@ static KX_GameObject* getGameOb(STR_String busc,CListValue* sumolist)
}
+static bool bl_isConstraintInList(KX_GameObject *gameobj, set<KX_GameObject*> convertedlist)
+{
+ set<KX_GameObject*>::iterator gobit;
+ for (gobit = convertedlist.begin(); gobit != convertedlist.end(); gobit++) {
+ if ((*gobit)->GetName() == gameobj->GetName())
+ return true;
+ }
+ return false;
+}
+
/* helper for BL_ConvertBlenderObjects, avoids code duplication
* note: all var names match args are passed from the caller */
static void bl_ConvertBlenderObject_Single(
@@ -1900,6 +1903,12 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
// is not in a separate thread.
BL_Texture::GetMaxUnits();
+ /* We have to ensure that group definitions are only converted once
+ * push all converted group members to this set.
+ * This will happen when a group instance is made from a linked group instance
+ * and both are on the active layer. */
+ set<KX_GameObject*> convertedlist;
+
if (alwaysUseExpandFraming) {
frame_type = RAS_FrameSettings::e_frame_extend;
aspect_width = canvas->GetWidth();
@@ -2031,6 +2040,11 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
converter,
libloading);
+ /* Insert object to the constraint game object list
+ * so we can check later if there is a instance in the scene or
+ * an instance and its actual group definition. */
+ convertedlist.insert((KX_GameObject*)gameobj->AddRef());
+
bool isInActiveLayer = false;
if (gameobj)
{
@@ -2270,97 +2284,54 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
// create physics joints
for (i=0;i<sumolist->GetCount();i++)
{
- KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i);
- struct Object* blenderobject = gameobj->GetBlenderObject();
- ListBase *conlist;
+ PHY_IPhysicsEnvironment *physEnv = kxscene->GetPhysicsEnvironment();
+ KX_GameObject *gameobj = (KX_GameObject *)sumolist->GetValue(i);
+ struct Object *blenderobject = gameobj->GetBlenderObject();
+ ListBase *conlist = get_active_constraints2(blenderobject);
bConstraint *curcon;
- if ((gameobj->GetLayer()&activeLayerBitInfo)==0)
+ if (!conlist)
continue;
- conlist = get_active_constraints2(blenderobject);
- if (conlist) {
- for (curcon = (bConstraint *)conlist->first; curcon; curcon = (bConstraint *)curcon->next) {
- if (curcon->type==CONSTRAINT_TYPE_RIGIDBODYJOINT) {
-
- bRigidBodyJointConstraint *dat=(bRigidBodyJointConstraint *)curcon->data;
+ for (curcon = (bConstraint *)conlist->first; curcon; curcon = (bConstraint *)curcon->next) {
+ if (curcon->type != CONSTRAINT_TYPE_RIGIDBODYJOINT)
+ continue;
- if (!dat->child && !(curcon->flag & CONSTRAINT_OFF)) {
+ bRigidBodyJointConstraint *dat = (bRigidBodyJointConstraint *)curcon->data;
+
+ /* Skip if no target or a child object is selected or constraints are deactivated */
+ if (!dat->tar || dat->child || (curcon->flag & CONSTRAINT_OFF))
+ continue;
- PHY_IPhysicsController* physctr2 = 0;
+ /* Store constraints of grouped and instanced objects for all layers */
+ gameobj->AddConstraint(dat);
+
+ /* Skipped already converted constraints.
+ * This will happen when a group instance is made from a linked group instance
+ * and both are on the active layer. */
+ if (bl_isConstraintInList(gameobj, convertedlist))
+ continue;
- if (dat->tar) {
- KX_GameObject *gotar=getGameOb(dat->tar->id.name+2,sumolist);
- if (gotar && ((gotar->GetLayer()&activeLayerBitInfo)!=0) && gotar->GetPhysicsController())
- physctr2 = gotar->GetPhysicsController();
- }
+ KX_GameObject *gotar = getGameOb(dat->tar->id.name + 2, sumolist);
- if (gameobj->GetPhysicsController()) {
- PHY_IPhysicsController* physctrl = gameobj->GetPhysicsController();
- //we need to pass a full constraint frame, not just axis
-
- //localConstraintFrameBasis
- MT_Matrix3x3 localCFrame(MT_Vector3(dat->axX,dat->axY,dat->axZ));
- MT_Vector3 axis0 = localCFrame.getColumn(0);
- MT_Vector3 axis1 = localCFrame.getColumn(1);
- MT_Vector3 axis2 = localCFrame.getColumn(2);
-
- int constraintId = kxscene->GetPhysicsEnvironment()->CreateConstraint(physctrl,physctr2,(PHY_ConstraintType)dat->type,(float)dat->pivX,
- (float)dat->pivY,(float)dat->pivZ,
- (float)axis0.x(),(float)axis0.y(),(float)axis0.z(),
- (float)axis1.x(),(float)axis1.y(),(float)axis1.z(),
- (float)axis2.x(),(float)axis2.y(),(float)axis2.z(),dat->flag);
- if (constraintId) {
- //if it is a generic 6DOF constraint, set all the limits accordingly
- if (dat->type == PHY_GENERIC_6DOF_CONSTRAINT) {
- int dof;
- int dofbit=1;
- for (dof=0;dof<6;dof++) {
- if (dat->flag & dofbit) {
- kxscene->GetPhysicsEnvironment()->SetConstraintParam(constraintId,dof,dat->minLimit[dof],dat->maxLimit[dof]);
- } else {
- //minLimit > maxLimit means free(disabled limit) for this degree of freedom
- kxscene->GetPhysicsEnvironment()->SetConstraintParam(constraintId,dof,1,-1);
- }
- dofbit<<=1;
- }
- } else if (dat->type == PHY_CONE_TWIST_CONSTRAINT) {
- int dof;
- int dofbit = 1<<3; // bitflag use_angular_limit_x
-
- for (dof=3;dof<6;dof++) {
- if (dat->flag & dofbit) {
- kxscene->GetPhysicsEnvironment()->SetConstraintParam(constraintId,dof,dat->minLimit[dof],dat->maxLimit[dof]);
- } else {
- //maxLimit < 0 means free(disabled limit) for this degree of freedom
- kxscene->GetPhysicsEnvironment()->SetConstraintParam(constraintId,dof,1,-1);
- }
- dofbit<<=1;
- }
- } else if (dat->type == PHY_LINEHINGE_CONSTRAINT) {
- int dof = 3; // dof for angular x
- int dofbit = 1<<3; // bitflag use_angular_limit_x
-
- if (dat->flag & dofbit) {
- kxscene->GetPhysicsEnvironment()->SetConstraintParam(constraintId,dof,
- dat->minLimit[dof],dat->maxLimit[dof]);
- } else {
- //minLimit > maxLimit means free(disabled limit) for this degree of freedom
- kxscene->GetPhysicsEnvironment()->SetConstraintParam(constraintId,dof,1,-1);
- }
- }
- }
- }
- }
- }
+ if (gotar && (gotar->GetLayer()&activeLayerBitInfo) && gotar->GetPhysicsController() &&
+ (gameobj->GetLayer()&activeLayerBitInfo) && gameobj->GetPhysicsController())
+ {
+ physEnv->SetupObjectConstraints(gameobj, gotar, dat);
}
}
}
+ /* cleanup converted set of group objects */
+ set<KX_GameObject*>::iterator gobit;
+ for (gobit = convertedlist.begin(); gobit != convertedlist.end(); gobit++)
+ (*gobit)->Release();
+
+ convertedlist.clear();
sumolist->Release();
// convert world
- KX_WorldInfo* worldinfo = new BlenderWorldInfo(blenderscene, blenderscene->world);
+ KX_WorldInfo* worldinfo = new KX_WorldInfo(blenderscene, blenderscene->world);
converter->RegisterWorldInfo(worldinfo);
kxscene->SetWorldInfo(worldinfo);
diff --git a/source/gameengine/Converter/BlenderWorldInfo.cpp b/source/gameengine/Converter/BlenderWorldInfo.cpp
deleted file mode 100644
index 75beb5d0e0e..00000000000
--- a/source/gameengine/Converter/BlenderWorldInfo.cpp
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can [0]istribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file gameengine/Converter/BlenderWorldInfo.cpp
- * \ingroup bgeconv
- */
-
-
-#include <stdio.h> // printf()
-
-#include "BlenderWorldInfo.h"
-
-/* This little block needed for linking to Blender... */
-#ifdef WIN32
-#include "BLI_winstuff.h"
-#endif
-
-/* This list includes only data type definitions */
-#include "DNA_object_types.h"
-#include "DNA_material_types.h"
-#include "DNA_image_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_group_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_property_types.h"
-#include "DNA_text_types.h"
-#include "DNA_sensor_types.h"
-#include "DNA_controller_types.h"
-#include "DNA_actuator_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_view3d_types.h"
-#include "DNA_world_types.h"
-#include "DNA_screen_types.h"
-
-#include "BLI_math.h"
-
-#include "BKE_global.h"
-#include "BKE_scene.h"
-/* end of blender include block */
-
-
-BlenderWorldInfo::BlenderWorldInfo(struct Scene *blenderscene, struct World *blenderworld)
-{
- if (blenderworld) {
- m_hasworld = true;
-
- // do we have mist?
- if ((blenderworld->mode) & WO_MIST) {
- m_hasmist = true;
- m_miststart = blenderworld->miststa;
- m_mistdistance = blenderworld->mistdist;
- copy_v3_v3(m_mistcolor, &blenderworld->horr);
- }
- else {
- m_hasmist = false;
- m_miststart = 0.0;
- m_mistdistance = 0.0;
- zero_v3(m_mistcolor);
- }
-
- copy_v3_v3(m_backgroundcolor, &blenderworld->horr);
- copy_v3_v3(m_ambientcolor, &blenderworld->ambr);
-
- if (BKE_scene_check_color_management_enabled(blenderscene)) {
- linearrgb_to_srgb_v3_v3(m_mistcolor, m_mistcolor);
- linearrgb_to_srgb_v3_v3(m_backgroundcolor, m_backgroundcolor);
- linearrgb_to_srgb_v3_v3(m_ambientcolor, m_ambientcolor);
- }
- }
- else {
- m_hasworld = false;
- }
-}
-
-BlenderWorldInfo::~BlenderWorldInfo()
-{
-}
-
-bool BlenderWorldInfo::hasWorld()
-{
- return m_hasworld;
-}
-
-bool BlenderWorldInfo::hasMist()
-{
- return m_hasmist;
-}
-
-float BlenderWorldInfo::getBackColorRed()
-{
- return m_backgroundcolor[0];
-}
-
-float BlenderWorldInfo::getBackColorGreen()
-{
- return m_backgroundcolor[1];
-}
-
-float BlenderWorldInfo::getBackColorBlue()
-{
- return m_backgroundcolor[2];
-}
-
-float BlenderWorldInfo::getAmbientColorRed()
-{
- return m_ambientcolor[0];
-}
-
-float BlenderWorldInfo::getAmbientColorGreen()
-{
- return m_ambientcolor[1];
-}
-
-float BlenderWorldInfo::getAmbientColorBlue()
-{
- return m_ambientcolor[2];
-}
-
-float BlenderWorldInfo::getMistStart()
-{
- return m_miststart;
-}
-
-float BlenderWorldInfo::getMistDistance()
-{
- return m_mistdistance;
-}
-
-float BlenderWorldInfo::getMistColorRed()
-{
- return m_mistcolor[0];
-}
-
-float BlenderWorldInfo::getMistColorGreen()
-{
- return m_mistcolor[1];
-}
-
-float BlenderWorldInfo::getMistColorBlue()
-{
- return m_mistcolor[2];
-}
-
-void BlenderWorldInfo::setBackColor(float r, float g, float b)
-{
- m_backgroundcolor[0] = r;
- m_backgroundcolor[1] = g;
- m_backgroundcolor[2] = b;
-}
-
-void BlenderWorldInfo::setMistStart(float d)
-{
- m_miststart = d;
-}
-
-void BlenderWorldInfo::setMistDistance(float d)
-{
- m_mistdistance = d;
-}
-
-void BlenderWorldInfo::setMistColorRed(float d)
-{
- m_mistcolor[0] = d;
-}
-
-void BlenderWorldInfo::setMistColorGreen(float d)
-{
- m_mistcolor[1] = d;
-}
-
-void BlenderWorldInfo::setMistColorBlue(float d)
-{
- m_mistcolor[2] = d;
-}
diff --git a/source/gameengine/Converter/BlenderWorldInfo.h b/source/gameengine/Converter/BlenderWorldInfo.h
deleted file mode 100644
index 2ac2d70b5d1..00000000000
--- a/source/gameengine/Converter/BlenderWorldInfo.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file BlenderWorldInfo.h
- * \ingroup bgeconv
- */
-
-#ifndef __BLENDERWORLDINFO_H__
-#define __BLENDERWORLDINFO_H__
-#include "MT_CmMatrix4x4.h"
-#include "KX_WorldInfo.h"
-
-class BlenderWorldInfo : public KX_WorldInfo
-{
- bool m_hasworld;
- float m_backgroundcolor[3];
-
- bool m_hasmist;
- float m_miststart;
- float m_mistdistance;
- float m_mistcolor[3];
-
- float m_ambientcolor[3];
-
-public:
- BlenderWorldInfo(struct Scene *blenderscene, struct World *blenderworld);
- ~BlenderWorldInfo();
-
- bool hasWorld();
- bool hasMist();
- float getBackColorRed();
- float getBackColorGreen();
- float getBackColorBlue();
-
- float getAmbientColorRed();
- float getAmbientColorGreen();
- float getAmbientColorBlue();
-
- float getMistStart();
- float getMistDistance();
- float getMistColorRed();
- float getMistColorGreen();
- float getMistColorBlue();
-
- void setBackColor(float r, float g, float b);
- void setMistStart(float d);
- void setMistDistance(float d);
- void setMistColorRed(float d);
- void setMistColorGreen(float d);
- void setMistColorBlue(float d);
-
-
-#ifdef WITH_CXX_GUARDEDALLOC
- MEM_CXX_CLASS_ALLOC_FUNCS("GE:BlenderWorldInfo")
-#endif
-};
-
-#endif /* __BLENDERWORLDINFO_H__ */
diff --git a/source/gameengine/Converter/CMakeLists.txt b/source/gameengine/Converter/CMakeLists.txt
index 9c0d25e56ff..6d681dd166e 100644
--- a/source/gameengine/Converter/CMakeLists.txt
+++ b/source/gameengine/Converter/CMakeLists.txt
@@ -56,7 +56,7 @@ set(INC
set(INC_SYS
../../../intern/moto/include
../../../extern/recastnavigation/Detour/Include
- ../../../extern/Eigen3
+ ${EIGEN3_INCLUDE_DIRS}
${PTHREADS_INCLUDE_DIRS}
${BOOST_INCLUDE_DIR}
)
@@ -74,7 +74,6 @@ set(SRC
BL_ShapeActionActuator.cpp
BL_ShapeDeformer.cpp
BL_SkinDeformer.cpp
- BlenderWorldInfo.cpp
KX_BlenderScalarInterpolator.cpp
KX_BlenderSceneConverter.cpp
KX_ConvertActuators.cpp
@@ -96,7 +95,6 @@ set(SRC
BL_ShapeActionActuator.h
BL_ShapeDeformer.h
BL_SkinDeformer.h
- BlenderWorldInfo.h
KX_BlenderScalarInterpolator.h
KX_BlenderSceneConverter.h
KX_ConvertActuators.h
diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
index 09cc74d717f..9e53d9e1569 100644
--- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
+++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
@@ -58,7 +58,7 @@
#include "KX_LibLoadStatus.h"
#include "KX_BlenderScalarInterpolator.h"
#include "BL_BlenderDataConversion.h"
-#include "BlenderWorldInfo.h"
+#include "KX_WorldInfo.h"
/* This little block needed for linking to Blender... */
#ifdef WIN32
@@ -117,11 +117,9 @@ typedef struct ThreadInfo {
} ThreadInfo;
KX_BlenderSceneConverter::KX_BlenderSceneConverter(
- struct Main* maggie,
- class KX_KetsjiEngine* engine
- )
- : m_maggie(maggie),
- /*m_maggie_dyn(NULL),*/
+ Main *maggie,
+ KX_KetsjiEngine *engine)
+ :m_maggie(maggie),
m_ketsjiEngine(engine),
m_alwaysUseExpandFraming(false),
m_usemat(false),
@@ -134,13 +132,11 @@ KX_BlenderSceneConverter::KX_BlenderSceneConverter(
pthread_mutex_init(&m_threadinfo->merge_lock, NULL);
}
-
KX_BlenderSceneConverter::~KX_BlenderSceneConverter()
{
// clears meshes, and hashmaps from blender to gameengine data
- int i;
// delete sumoshapes
-
+
if (m_threadinfo) {
vector<pthread_t>::iterator pit = m_threadinfo->threads.begin();
while (pit != m_threadinfo->threads.end()) {
@@ -153,104 +149,83 @@ KX_BlenderSceneConverter::~KX_BlenderSceneConverter()
}
int numAdtLists = m_map_blender_to_gameAdtList.size();
- for (i=0; i<numAdtLists; i++) {
- BL_InterpolatorList *adtList= *m_map_blender_to_gameAdtList.at(i);
+ for (int i = 0; i < numAdtLists; i++) {
+ BL_InterpolatorList *adtList = *m_map_blender_to_gameAdtList.at(i);
delete (adtList);
}
- vector<pair<KX_Scene*,KX_WorldInfo*> >::iterator itw = m_worldinfos.begin();
+ vector<pair<KX_Scene *, KX_WorldInfo *> >::iterator itw = m_worldinfos.begin();
while (itw != m_worldinfos.end()) {
delete (*itw).second;
itw++;
}
m_worldinfos.clear();
- vector<pair<KX_Scene*,RAS_IPolyMaterial*> >::iterator itp = m_polymaterials.begin();
+ vector<pair<KX_Scene *,RAS_IPolyMaterial *> >::iterator itp = m_polymaterials.begin();
while (itp != m_polymaterials.end()) {
- //m_polymat_cache.erase((*itp).second->GetBlenderMaterial());
delete (*itp).second;
itp++;
}
m_polymaterials.clear();
// delete after RAS_IPolyMaterial
- vector<pair<KX_Scene*,BL_Material *> >::iterator itmat = m_materials.begin();
+ vector<pair<KX_Scene *,BL_Material *> >::iterator itmat = m_materials.begin();
while (itmat != m_materials.end()) {
- //m_mat_cache.erase((*itmat).second->material);
delete (*itmat).second;
itmat++;
}
m_materials.clear();
-
- vector<pair<KX_Scene*,RAS_MeshObject*> >::iterator itm = m_meshobjects.begin();
+ vector<pair<KX_Scene *,RAS_MeshObject *> >::iterator itm = m_meshobjects.begin();
while (itm != m_meshobjects.end()) {
delete (*itm).second;
itm++;
}
m_meshobjects.clear();
-
/* free any data that was dynamically loaded */
- while (m_DynamicMaggie.size() != 0)
- {
+ while (m_DynamicMaggie.size() != 0) {
FreeBlendFile(m_DynamicMaggie[0]);
}
m_DynamicMaggie.clear();
}
-void KX_BlenderSceneConverter::SetNewFileName(const STR_String& filename)
+void KX_BlenderSceneConverter::SetNewFileName(const STR_String &filename)
{
m_newfilename = filename;
}
-
-
bool KX_BlenderSceneConverter::TryAndLoadNewFile()
{
bool result = false;
- // find the file
-/* if ()
- {
- result = true;
- }
- // if not, clear the newfilename
- else
- {
- m_newfilename = "";
- }
-*/
return result;
}
-Scene *KX_BlenderSceneConverter::GetBlenderSceneForName(const STR_String& name)
+Scene *KX_BlenderSceneConverter::GetBlenderSceneForName(const STR_String &name)
{
Scene *sce;
/**
* Find the specified scene by name, or NULL if nothing matches.
*/
- if ((sce= (Scene *)BLI_findstring(&m_maggie->scene, name.ReadPtr(), offsetof(ID, name) + 2)))
+ if ((sce = (Scene *)BLI_findstring(&m_maggie->scene, name.ReadPtr(), offsetof(ID, name) + 2)))
return sce;
- for (vector<Main*>::iterator it=m_DynamicMaggie.begin(); !(it==m_DynamicMaggie.end()); it++) {
- Main *main= *it;
+ for (vector<Main *>::iterator it=m_DynamicMaggie.begin(); !(it == m_DynamicMaggie.end()); it++) {
+ Main *main = *it;
if ((sce= (Scene *)BLI_findstring(&main->scene, name.ReadPtr(), offsetof(ID, name) + 2)))
return sce;
}
return NULL;
-
}
-void KX_BlenderSceneConverter::ConvertScene(class KX_Scene* destinationscene,
- class RAS_IRasterizer* rendertools,
- class RAS_ICanvas* canvas,
- bool libloading)
+void KX_BlenderSceneConverter::ConvertScene(KX_Scene *destinationscene, RAS_IRasterizer *rendertools,
+ RAS_ICanvas *canvas, bool libloading)
{
//find out which physics engine
Scene *blenderscene = destinationscene->GetBlenderScene();
@@ -266,13 +241,12 @@ void KX_BlenderSceneConverter::ConvertScene(class KX_Scene* destinationscene,
// when doing threaded conversion, so it's disabled for now.
// SG_SetActiveStage(SG_STAGE_CONVERTER);
- switch (blenderscene->gm.physicsEngine)
- {
+ switch (blenderscene->gm.physicsEngine) {
#ifdef WITH_BULLET
case WOPHY_BULLET:
{
SYS_SystemHandle syshandle = SYS_GetSystem(); /*unused*/
- int visualizePhysics = SYS_GetCommandLineInt(syshandle,"show_physics",0);
+ int visualizePhysics = SYS_GetCommandLineInt(syshandle, "show_physics", 0);
phy_env = CcdPhysicsEnvironment::Create(blenderscene, visualizePhysics);
physics_engine = UseBullet;
@@ -291,7 +265,8 @@ void KX_BlenderSceneConverter::ConvertScene(class KX_Scene* destinationscene,
destinationscene->SetPhysicsEnvironment(phy_env);
- BL_ConvertBlenderObjects(m_maggie,
+ BL_ConvertBlenderObjects(
+ m_maggie,
destinationscene,
m_ketsjiEngine,
physics_engine,
@@ -299,8 +274,7 @@ void KX_BlenderSceneConverter::ConvertScene(class KX_Scene* destinationscene,
canvas,
this,
m_alwaysUseExpandFraming,
- libloading
- );
+ libloading);
//These lookup are not needed during game
m_map_blender_to_gameactuator.clear();
@@ -326,30 +300,32 @@ void KX_BlenderSceneConverter::RemoveScene(KX_Scene *scene)
// delete the scene first as it will stop the use of entities
delete scene;
// delete the entities of this scene
- vector<pair<KX_Scene*,KX_WorldInfo*> >::iterator worldit;
+ vector<pair<KX_Scene *, KX_WorldInfo *> >::iterator worldit;
size = m_worldinfos.size();
- for (i=0, worldit=m_worldinfos.begin(); i<size; ) {
+ for (i = 0, worldit = m_worldinfos.begin(); i < size; ) {
if ((*worldit).first == scene) {
delete (*worldit).second;
*worldit = m_worldinfos.back();
m_worldinfos.pop_back();
size--;
- } else {
+ }
+ else {
i++;
worldit++;
}
}
- vector<pair<KX_Scene*,RAS_IPolyMaterial*> >::iterator polymit;
+ vector<pair<KX_Scene *, RAS_IPolyMaterial *> >::iterator polymit;
size = m_polymaterials.size();
- for (i=0, polymit=m_polymaterials.begin(); i<size; ) {
+ for (i = 0, polymit = m_polymaterials.begin(); i < size; ) {
if ((*polymit).first == scene) {
m_polymat_cache[scene].erase((*polymit).second->GetBlenderMaterial());
delete (*polymit).second;
*polymit = m_polymaterials.back();
m_polymaterials.pop_back();
size--;
- } else {
+ }
+ else {
i++;
polymit++;
}
@@ -357,16 +333,17 @@ void KX_BlenderSceneConverter::RemoveScene(KX_Scene *scene)
m_polymat_cache.erase(scene);
- vector<pair<KX_Scene*,BL_Material*> >::iterator matit;
+ vector<pair<KX_Scene *, BL_Material *> >::iterator matit;
size = m_materials.size();
- for (i=0, matit=m_materials.begin(); i<size; ) {
+ for (i = 0, matit = m_materials.begin(); i < size; ) {
if ((*matit).first == scene) {
m_mat_cache[scene].erase((*matit).second->material);
delete (*matit).second;
*matit = m_materials.back();
m_materials.pop_back();
size--;
- } else {
+ }
+ else {
i++;
matit++;
}
@@ -374,15 +351,16 @@ void KX_BlenderSceneConverter::RemoveScene(KX_Scene *scene)
m_mat_cache.erase(scene);
- vector<pair<KX_Scene*,RAS_MeshObject*> >::iterator meshit;
+ vector<pair<KX_Scene *, RAS_MeshObject *> >::iterator meshit;
size = m_meshobjects.size();
- for (i=0, meshit=m_meshobjects.begin(); i<size; ) {
+ for (i = 0, meshit = m_meshobjects.begin(); i < size; ) {
if ((*meshit).first == scene) {
delete (*meshit).second;
*meshit = m_meshobjects.back();
m_meshobjects.pop_back();
size--;
- } else {
+ }
+ else {
i++;
meshit++;
}
@@ -425,43 +403,34 @@ bool KX_BlenderSceneConverter::GetCacheMaterials()
void KX_BlenderSceneConverter::RegisterBlenderMaterial(BL_Material *mat)
{
// First make sure we don't register the material twice
- vector<pair<KX_Scene*,BL_Material*> >::iterator it;
+ vector<pair<KX_Scene *, BL_Material *> >::iterator it;
for (it = m_materials.begin(); it != m_materials.end(); ++it)
if (it->second == mat)
return;
- m_materials.push_back(pair<KX_Scene*,BL_Material *>(m_currentScene,mat));
+ m_materials.push_back(pair<KX_Scene *, BL_Material *> (m_currentScene, mat));
}
-
-
-void KX_BlenderSceneConverter::SetAlwaysUseExpandFraming(
- bool to_what)
+void KX_BlenderSceneConverter::SetAlwaysUseExpandFraming(bool to_what)
{
m_alwaysUseExpandFraming= to_what;
}
-
-
-void KX_BlenderSceneConverter::RegisterGameObject(
- KX_GameObject *gameobject,
- struct Object *for_blenderobject)
+void KX_BlenderSceneConverter::RegisterGameObject(KX_GameObject *gameobject, Object *for_blenderobject)
{
/* only maintained while converting, freed during game runtime */
- m_map_blender_to_gameobject.insert(CHashedPtr(for_blenderobject),gameobject);
+ m_map_blender_to_gameobject.insert(CHashedPtr(for_blenderobject), gameobject);
}
/* only need to run this during conversion since
* m_map_blender_to_gameobject is freed after conversion */
-void KX_BlenderSceneConverter::UnregisterGameObject(
- KX_GameObject *gameobject)
+void KX_BlenderSceneConverter::UnregisterGameObject(KX_GameObject *gameobject)
{
- struct Object *bobp= gameobject->GetBlenderObject();
+ Object *bobp = gameobject->GetBlenderObject();
if (bobp) {
CHashedPtr bptr(bobp);
- KX_GameObject **gobp= m_map_blender_to_gameobject[bptr];
- if (gobp && *gobp == gameobject)
- {
+ KX_GameObject **gobp = m_map_blender_to_gameobject[bptr];
+ if (gobp && *gobp == gameobject) {
// also maintain m_map_blender_to_gameobject if the gameobject
// being removed is matching the blender object
m_map_blender_to_gameobject.remove(bptr);
@@ -469,47 +438,41 @@ void KX_BlenderSceneConverter::UnregisterGameObject(
}
}
-KX_GameObject *KX_BlenderSceneConverter::FindGameObject(
- struct Object *for_blenderobject)
+KX_GameObject *KX_BlenderSceneConverter::FindGameObject(Object *for_blenderobject)
{
- KX_GameObject **obp= m_map_blender_to_gameobject[CHashedPtr(for_blenderobject)];
-
- return obp?*obp:NULL;
+ KX_GameObject **obp = m_map_blender_to_gameobject[CHashedPtr(for_blenderobject)];
+
+ return obp ? *obp : NULL;
}
-void KX_BlenderSceneConverter::RegisterGameMesh(
- RAS_MeshObject *gamemesh,
- struct Mesh *for_blendermesh)
+void KX_BlenderSceneConverter::RegisterGameMesh(RAS_MeshObject *gamemesh, Mesh *for_blendermesh)
{
if (for_blendermesh) { /* dynamically loaded meshes we don't want to keep lookups for */
m_map_mesh_to_gamemesh.insert(CHashedPtr(for_blendermesh),gamemesh);
}
- m_meshobjects.push_back(pair<KX_Scene*,RAS_MeshObject*>(m_currentScene,gamemesh));
+ m_meshobjects.push_back(pair<KX_Scene *, RAS_MeshObject *> (m_currentScene,gamemesh));
}
-
-
-RAS_MeshObject *KX_BlenderSceneConverter::FindGameMesh(
- struct Mesh *for_blendermesh/*,
- unsigned int onlayer*/)
+RAS_MeshObject *KX_BlenderSceneConverter::FindGameMesh(Mesh *for_blendermesh)
{
- RAS_MeshObject** meshp = m_map_mesh_to_gamemesh[CHashedPtr(for_blendermesh)];
-
- if (meshp/* && onlayer==(*meshp)->GetLightLayer()*/) {
+ RAS_MeshObject **meshp = m_map_mesh_to_gamemesh[CHashedPtr(for_blendermesh)];
+
+ if (meshp) {
return *meshp;
- } else {
+ }
+ else {
return NULL;
}
-}
+}
void KX_BlenderSceneConverter::RegisterPolyMaterial(RAS_IPolyMaterial *polymat)
{
// First make sure we don't register the material twice
- vector<pair<KX_Scene*,RAS_IPolyMaterial*> >::iterator it;
+ vector<pair<KX_Scene *, RAS_IPolyMaterial *> >::iterator it;
for (it = m_polymaterials.begin(); it != m_polymaterials.end(); ++it)
if (it->second == polymat)
return;
- m_polymaterials.push_back(pair<KX_Scene*,RAS_IPolyMaterial*>(m_currentScene,polymat));
+ m_polymaterials.push_back(pair<KX_Scene *, RAS_IPolyMaterial *> (m_currentScene, polymat));
}
void KX_BlenderSceneConverter::CachePolyMaterial(KX_Scene *scene, Material *mat, RAS_IPolyMaterial *polymat)
@@ -518,94 +481,82 @@ void KX_BlenderSceneConverter::CachePolyMaterial(KX_Scene *scene, Material *mat,
m_polymat_cache[scene][mat] = polymat;
}
-RAS_IPolyMaterial *KX_BlenderSceneConverter::FindCachedPolyMaterial(KX_Scene *scene, struct Material *mat)
+RAS_IPolyMaterial *KX_BlenderSceneConverter::FindCachedPolyMaterial(KX_Scene *scene, Material *mat)
{
return (m_use_mat_cache) ? m_polymat_cache[scene][mat] : NULL;
}
-void KX_BlenderSceneConverter::CacheBlenderMaterial(KX_Scene *scene, struct Material *mat, BL_Material *blmat)
+void KX_BlenderSceneConverter::CacheBlenderMaterial(KX_Scene *scene, Material *mat, BL_Material *blmat)
{
if (m_use_mat_cache && mat)
m_mat_cache[scene][mat] = blmat;
}
-
-BL_Material *KX_BlenderSceneConverter::FindCachedBlenderMaterial(KX_Scene *scene, struct Material *mat)
+BL_Material *KX_BlenderSceneConverter::FindCachedBlenderMaterial(KX_Scene *scene, Material *mat)
{
return (m_use_mat_cache) ? m_mat_cache[scene][mat] : NULL;
}
-
-void KX_BlenderSceneConverter::RegisterInterpolatorList(BL_InterpolatorList *actList, struct bAction *for_act)
+void KX_BlenderSceneConverter::RegisterInterpolatorList(BL_InterpolatorList *actList, bAction *for_act)
{
m_map_blender_to_gameAdtList.insert(CHashedPtr(for_act), actList);
}
-BL_InterpolatorList *KX_BlenderSceneConverter::FindInterpolatorList(struct bAction *for_act)
+BL_InterpolatorList *KX_BlenderSceneConverter::FindInterpolatorList(bAction *for_act)
{
BL_InterpolatorList **listp = m_map_blender_to_gameAdtList[CHashedPtr(for_act)];
- return listp?*listp:NULL;
+ return listp ? *listp : NULL;
}
-
-void KX_BlenderSceneConverter::RegisterGameActuator(SCA_IActuator *act, struct bActuator *for_actuator)
+void KX_BlenderSceneConverter::RegisterGameActuator(SCA_IActuator *act, bActuator *for_actuator)
{
m_map_blender_to_gameactuator.insert(CHashedPtr(for_actuator), act);
}
-SCA_IActuator *KX_BlenderSceneConverter::FindGameActuator(struct bActuator *for_actuator)
+SCA_IActuator *KX_BlenderSceneConverter::FindGameActuator(bActuator *for_actuator)
{
SCA_IActuator **actp = m_map_blender_to_gameactuator[CHashedPtr(for_actuator)];
- return actp?*actp:NULL;
+ return actp ? *actp : NULL;
}
-
-void KX_BlenderSceneConverter::RegisterGameController(SCA_IController *cont, struct bController *for_controller)
+void KX_BlenderSceneConverter::RegisterGameController(SCA_IController *cont, bController *for_controller)
{
m_map_blender_to_gamecontroller.insert(CHashedPtr(for_controller), cont);
}
-SCA_IController *KX_BlenderSceneConverter::FindGameController(struct bController *for_controller)
+SCA_IController *KX_BlenderSceneConverter::FindGameController(bController *for_controller)
{
SCA_IController **contp = m_map_blender_to_gamecontroller[CHashedPtr(for_controller)];
- return contp?*contp:NULL;
+ return contp ? *contp : NULL;
}
-
-
void KX_BlenderSceneConverter::RegisterWorldInfo(KX_WorldInfo *worldinfo)
{
- m_worldinfos.push_back(pair<KX_Scene*,KX_WorldInfo*>(m_currentScene,worldinfo));
+ m_worldinfos.push_back(pair<KX_Scene *, KX_WorldInfo *> (m_currentScene, worldinfo));
}
-void KX_BlenderSceneConverter::ResetPhysicsObjectsAnimationIpo(bool clearIpo)
+void KX_BlenderSceneConverter::ResetPhysicsObjectsAnimationIpo(bool clearIpo)
{
//TODO this entire function is deprecated, written for 2.4x
//the functionality should be rewritten, currently it does nothing
- KX_SceneList* scenes = m_ketsjiEngine->CurrentScenes();
+ KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes();
int numScenes = scenes->size();
int i;
- for (i=0;i<numScenes;i++)
- {
- KX_Scene* scene = scenes->at(i);
- //PHY_IPhysicsEnvironment* physEnv = scene->GetPhysicsEnvironment();
- CListValue* parentList = scene->GetRootParentList();
+ for (i = 0; i < numScenes; i++) {
+ KX_Scene *scene = scenes->at(i);
+ CListValue *parentList = scene->GetRootParentList();
int numObjects = parentList->GetCount();
int g;
- for (g=0;g<numObjects;g++)
- {
- KX_GameObject* gameObj = (KX_GameObject*)parentList->GetValue(g);
+ for (g = 0; g < numObjects; g++) {
+ KX_GameObject *gameObj = (KX_GameObject *)parentList->GetValue(g);
if (gameObj->IsRecordAnimation()) {
-
- Object* blenderObject = gameObj->GetBlenderObject();
- if (blenderObject)
- {
+ Object *blenderObject = gameObj->GetBlenderObject();
+ if (blenderObject) {
#if 0
//erase existing ipo's
Ipo* ipo = blenderObject->ipo;//findIpoForName(blenderObject->id.name+2);
- if (ipo)
- { //clear the curve data
+ if (ipo) { //clear the curve data
if (clearIpo) {//rcruiz
IpoCurve *icu1;
@@ -630,64 +581,52 @@ void KX_BlenderSceneConverter::ResetPhysicsObjectsAnimationIpo(bool clearIpo)
localDel_ipoCurve( tmpicu );
}
}
- } else
- { ipo = NULL; // XXX add_ipo(blenderObject->id.name+2, ID_OB);
+ }
+ else {
+ ipo = NULL; // XXX add_ipo(blenderObject->id.name+2, ID_OB);
blenderObject->ipo = ipo;
-
}
#endif
}
}
-
}
-
-
}
-
-
-
}
-void KX_BlenderSceneConverter::resetNoneDynamicObjectToIpo()
+void KX_BlenderSceneConverter::resetNoneDynamicObjectToIpo()
{
//TODO the functionality should be rewritten
}
-
- ///this generates ipo curves for position, rotation, allowing to use game physics in animation
-void KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber)
+// this generates ipo curves for position, rotation, allowing to use game physics in animation
+void KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber)
{
-
- KX_SceneList* scenes = m_ketsjiEngine->CurrentScenes();
+ KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes();
int numScenes = scenes->size();
int i;
- for (i=0;i<numScenes;i++)
- {
- KX_Scene* scene = scenes->at(i);
+ for (i = 0; i < numScenes; i++) {
+ KX_Scene *scene = scenes->at(i);
//PHY_IPhysicsEnvironment* physEnv = scene->GetPhysicsEnvironment();
- CListValue* parentList = scene->GetObjectList();
+ CListValue *parentList = scene->GetObjectList();
int numObjects = parentList->GetCount();
int g;
- for (g=0;g<numObjects;g++)
- {
- KX_GameObject* gameObj = (KX_GameObject*)parentList->GetValue(g);
- Object* blenderObject = gameObj->GetBlenderObject();
- if (blenderObject && blenderObject->parent==NULL && gameObj->IsRecordAnimation()) {
-
- if (blenderObject->adt==NULL)
- BKE_id_add_animdata(&blenderObject->id);
-
- if (blenderObject->adt)
- {
- const MT_Point3& position = gameObj->NodeGetWorldPosition();
+ for (g = 0; g < numObjects; g++) {
+ KX_GameObject *gameObj = (KX_GameObject *)parentList->GetValue(g);
+ Object *blenderObject = gameObj->GetBlenderObject();
+ if (blenderObject && blenderObject->parent == NULL && gameObj->IsRecordAnimation()) {
+ if (blenderObject->adt == NULL)
+ BKE_animdata_add_id(&blenderObject->id);
+
+ if (blenderObject->adt) {
+ const MT_Point3 &position = gameObj->NodeGetWorldPosition();
//const MT_Vector3& scale = gameObj->NodeGetWorldScaling();
- const MT_Matrix3x3& orn = gameObj->NodeGetWorldOrientation();
+ const MT_Matrix3x3 &orn = gameObj->NodeGetWorldOrientation();
position.getValue(blenderObject->loc);
float tmat[3][3];
- for (int r=0;r<3;r++)
- for (int c=0;c<3;c++)
+ for (int r = 0; r < 3; r++)
+ for (int c = 0; c < 3; c++)
tmat[r][c] = (float)orn[c][r];
mat3_to_compatible_eul(blenderObject->rot, blenderObject->rot, tmat);
@@ -772,27 +711,22 @@ void KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber)
}
}
-
-void KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo()
+void KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo()
{
-
- KX_SceneList* scenes = m_ketsjiEngine->CurrentScenes();
+ KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes();
int numScenes = scenes->size();
int i;
- for (i=0;i<numScenes;i++)
- {
- KX_Scene* scene = scenes->at(i);
+ for (i = 0; i < numScenes; i++) {
+ KX_Scene *scene = scenes->at(i);
//PHY_IPhysicsEnvironment* physEnv = scene->GetPhysicsEnvironment();
- CListValue* parentList = scene->GetRootParentList();
+ CListValue *parentList = scene->GetRootParentList();
int numObjects = parentList->GetCount();
int g;
- for (g=0;g<numObjects;g++)
- {
- KX_GameObject* gameObj = (KX_GameObject*)parentList->GetValue(g);
+ for (g = 0; g < numObjects; g++) {
+ KX_GameObject *gameObj = (KX_GameObject *)parentList->GetValue(g);
if (gameObj->IsRecordAnimation()) {
- Object* blenderObject = gameObj->GetBlenderObject();
- if (blenderObject && blenderObject->adt)
- {
+ Object *blenderObject = gameObj->GetBlenderObject();
+ if (blenderObject && blenderObject->adt) {
bAction *act = verify_adt_action(&blenderObject->id, false);
FCurve *fcu;
@@ -832,14 +766,14 @@ PyObject *KX_BlenderSceneConverter::GetPyNamespace()
}
#endif
-vector<Main*> &KX_BlenderSceneConverter::GetMainDynamic()
+vector<Main *> &KX_BlenderSceneConverter::GetMainDynamic()
{
return m_DynamicMaggie;
}
-Main* KX_BlenderSceneConverter::GetMainDynamicPath(const char *path)
+Main *KX_BlenderSceneConverter::GetMainDynamicPath(const char *path)
{
- for (vector<Main*>::iterator it=m_DynamicMaggie.begin(); !(it==m_DynamicMaggie.end()); it++)
+ for (vector<Main *>::iterator it = m_DynamicMaggie.begin(); !(it == m_DynamicMaggie.end()); it++)
if (BLI_path_cmp((*it)->name, path) == 0)
return *it;
@@ -848,22 +782,21 @@ Main* KX_BlenderSceneConverter::GetMainDynamicPath(const char *path)
void KX_BlenderSceneConverter::MergeAsyncLoads()
{
- vector<KX_Scene*> *merge_scenes;
+ vector<KX_Scene *> *merge_scenes;
- vector<KX_LibLoadStatus*>::iterator mit;
- vector<KX_Scene*>::iterator sit;
+ vector<KX_LibLoadStatus *>::iterator mit;
+ vector<KX_Scene *>::iterator sit;
pthread_mutex_lock(&m_threadinfo->merge_lock);
- for (mit=m_mergequeue.begin(); mit!=m_mergequeue.end(); ++mit) {
- merge_scenes = (vector<KX_Scene*>*)(*mit)->GetData();
+ for (mit = m_mergequeue.begin(); mit != m_mergequeue.end(); ++mit) {
+ merge_scenes = (vector<KX_Scene *> *)(*mit)->GetData();
for (sit=merge_scenes->begin(); sit!=merge_scenes->end(); ++sit) {
(*mit)->GetMergeScene()->MergeScene(*sit);
delete (*sit);
}
-
delete merge_scenes;
(*mit)->SetData(NULL);
@@ -885,17 +818,17 @@ void KX_BlenderSceneConverter::AddScenesToMergeQueue(KX_LibLoadStatus *status)
static void *async_convert(void *ptr)
{
KX_Scene *new_scene = NULL;
- KX_LibLoadStatus *status = (KX_LibLoadStatus*)ptr;
- vector<Scene*> *scenes = (vector<Scene*>*)status->GetData();
- vector<KX_Scene*> *merge_scenes = new vector<KX_Scene*>(); // Deleted in MergeAsyncLoads
+ KX_LibLoadStatus *status = (KX_LibLoadStatus *)ptr;
+ vector<Scene *> *scenes = (vector<Scene *> *)status->GetData();
+ vector<KX_Scene *> *merge_scenes = new vector<KX_Scene *>(); // Deleted in MergeAsyncLoads
- for (unsigned int i=0; i<scenes->size(); ++i) {
+ for (unsigned int i = 0; i < scenes->size(); ++i) {
new_scene = status->GetEngine()->CreateScene((*scenes)[i], true);
if (new_scene)
merge_scenes->push_back(new_scene);
- status->AddProgress((1.f/scenes->size())*0.9f); // We'll call conversion 90% and merging 10% for now
+ status->AddProgress((1.0f / scenes->size()) * 0.9f); // We'll call conversion 90% and merging 10% for now
}
delete scenes;
@@ -922,28 +855,21 @@ KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFilePath(const char *filepa
return LinkBlendFile(bpy_openlib, filepath, group, scene_merge, err_str, options);
}
-static void load_datablocks(Main *main_newlib, BlendHandle *bpy_openlib, const char *path, int idcode)
+static void load_datablocks(Main *main_tmp, BlendHandle *bpy_openlib, const char *path, int idcode)
{
- Main *main_tmp= NULL; /* created only for linking, then freed */
LinkNode *names = NULL;
- short flag= 0; /* don't need any special options */
-
- /* here appending/linking starts */
- main_tmp = BLO_library_append_begin(main_newlib, &bpy_openlib, (char *)path);
int totnames_dummy;
- names = BLO_blendhandle_get_datablock_names( bpy_openlib, idcode, &totnames_dummy);
+ names = BLO_blendhandle_get_datablock_names(bpy_openlib, idcode, &totnames_dummy);
- int i=0;
- LinkNode *n= names;
+ int i = 0;
+ LinkNode *n = names;
while (n) {
BLO_library_append_named_part(main_tmp, &bpy_openlib, (char *)n->link, idcode);
- n= (LinkNode *)n->next;
+ n = (LinkNode *)n->next;
i++;
}
BLI_linklist_free(names, free); /* free linklist *and* each node's data */
-
- BLO_library_append_end(NULL, main_tmp, &bpy_openlib, idcode, flag);
}
KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openlib, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options)
@@ -956,42 +882,48 @@ KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openl
// TIMEIT_START(bge_link_blend_file);
KX_LibLoadStatus *status;
-
+
/* only scene and mesh supported right now */
- if (idcode!=ID_SCE && idcode!=ID_ME &&idcode!=ID_AC) {
+ if (idcode != ID_SCE && idcode != ID_ME && idcode != ID_AC) {
snprintf(err_local, sizeof(err_local), "invalid ID type given \"%s\"\n", group);
- *err_str= err_local;
+ *err_str = err_local;
BLO_blendhandle_close(bpy_openlib);
return NULL;
}
if (GetMainDynamicPath(path)) {
snprintf(err_local, sizeof(err_local), "blend file already open \"%s\"\n", path);
- *err_str= err_local;
+ *err_str = err_local;
BLO_blendhandle_close(bpy_openlib);
return NULL;
}
- if (bpy_openlib==NULL) {
+ if (bpy_openlib == NULL) {
snprintf(err_local, sizeof(err_local), "could not open blendfile \"%s\"\n", path);
- *err_str= err_local;
+ *err_str = err_local;
return NULL;
}
-
+
main_newlib = BKE_main_new();
BKE_reports_init(&reports, RPT_STORE);
- load_datablocks(main_newlib, bpy_openlib, path, idcode);
+ short flag = 0; /* don't need any special options */
+ /* created only for linking, then freed */
+ Main *main_tmp = BLO_library_append_begin(main_newlib, &bpy_openlib, (char *)path);
+
+ load_datablocks(main_tmp, bpy_openlib, path, idcode);
- if (idcode==ID_SCE && options & LIB_LOAD_LOAD_SCRIPTS) {
- load_datablocks(main_newlib, bpy_openlib, path, ID_TXT);
+ if (idcode == ID_SCE && options & LIB_LOAD_LOAD_SCRIPTS) {
+ load_datablocks(main_tmp, bpy_openlib, path, ID_TXT);
}
/* now do another round of linking for Scenes so all actions are properly loaded */
- if (idcode==ID_SCE && options & LIB_LOAD_LOAD_ACTIONS) {
- load_datablocks(main_newlib, bpy_openlib, path, ID_AC);
+ if (idcode == ID_SCE && options & LIB_LOAD_LOAD_ACTIONS) {
+ load_datablocks(main_tmp, bpy_openlib, path, ID_AC);
}
-
+
+ BLO_library_append_end(NULL, main_tmp, &bpy_openlib, idcode, flag);
+
BLO_blendhandle_close(bpy_openlib);
BKE_reports_clear(&reports);
@@ -1004,42 +936,43 @@ KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openl
status = new KX_LibLoadStatus(this, m_ketsjiEngine, scene_merge, path);
- if (idcode==ID_ME) {
+ if (idcode == ID_ME) {
/* Convert all new meshes into BGE meshes */
- ID* mesh;
+ ID *mesh;
- for (mesh= (ID *)main_newlib->mesh.first; mesh; mesh= (ID *)mesh->next ) {
+ for (mesh = (ID *)main_newlib->mesh.first; mesh; mesh = (ID *)mesh->next ) {
if (options & LIB_LOAD_VERBOSE)
- printf("MeshName: %s\n", mesh->name+2);
+ printf("MeshName: %s\n", mesh->name + 2);
RAS_MeshObject *meshobj = BL_ConvertMesh((Mesh *)mesh, NULL, scene_merge, this, false); // For now only use the libloading option for scenes, which need to handle materials/shaders
- scene_merge->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj);
+ scene_merge->GetLogicManager()->RegisterMeshName(meshobj->GetName(), meshobj);
}
}
- else if (idcode==ID_AC) {
+ else if (idcode == ID_AC) {
/* Convert all actions */
ID *action;
- for (action= (ID *)main_newlib->action.first; action; action= (ID *)action->next) {
+ for (action= (ID *)main_newlib->action.first; action; action = (ID *)action->next) {
if (options & LIB_LOAD_VERBOSE)
- printf("ActionName: %s\n", action->name+2);
- scene_merge->GetLogicManager()->RegisterActionName(action->name+2, action);
+ printf("ActionName: %s\n", action->name + 2);
+ scene_merge->GetLogicManager()->RegisterActionName(action->name + 2, action);
}
}
- else if (idcode==ID_SCE) {
+ else if (idcode == ID_SCE) {
/* Merge all new linked in scene into the existing one */
ID *scene;
// scenes gets deleted by the thread when it's done using it (look in async_convert())
- vector<Scene*> *scenes = (options & LIB_LOAD_ASYNC) ? new vector<Scene*>() : NULL;
+ vector<Scene *> *scenes = (options & LIB_LOAD_ASYNC) ? new vector<Scene *>() : NULL;
- for (scene= (ID *)main_newlib->scene.first; scene; scene= (ID *)scene->next ) {
+ for (scene = (ID *)main_newlib->scene.first; scene; scene = (ID *)scene->next ) {
if (options & LIB_LOAD_VERBOSE)
- printf("SceneName: %s\n", scene->name+2);
+ printf("SceneName: %s\n", scene->name + 2);
if (options & LIB_LOAD_ASYNC) {
- scenes->push_back((Scene*)scene);
- } else {
+ scenes->push_back((Scene *)scene);
+ }
+ else {
/* merge into the base scene */
- KX_Scene* other= m_ketsjiEngine->CreateScene((Scene *)scene, true);
+ KX_Scene* other = m_ketsjiEngine->CreateScene((Scene *)scene, true);
scene_merge->MergeScene(other);
// RemoveScene(other); // Don't run this, it frees the entire scene converter data, just delete the scene
@@ -1050,7 +983,7 @@ KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openl
if (options & LIB_LOAD_ASYNC) {
pthread_t id;
status->SetData(scenes);
- pthread_create(&id, NULL, &async_convert, (void*)status);
+ pthread_create(&id, NULL, &async_convert, (void *)status);
m_threadinfo->threads.push_back(id);
}
@@ -1064,17 +997,16 @@ KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openl
if (options & LIB_LOAD_LOAD_ACTIONS) {
ID *action;
- for (action= (ID *)main_newlib->action.first; action; action= (ID *)action->next) {
+ for (action = (ID *)main_newlib->action.first; action; action = (ID *)action->next) {
if (options & LIB_LOAD_VERBOSE)
- printf("ActionName: %s\n", action->name+2);
- scene_merge->GetLogicManager()->RegisterActionName(action->name+2, action);
+ printf("ActionName: %s\n", action->name + 2);
+ scene_merge->GetLogicManager()->RegisterActionName(action->name + 2, action);
}
}
}
if (!(options & LIB_LOAD_ASYNC))
status->Finish();
-
// TIMEIT_END(bge_link_blend_file);
@@ -1084,22 +1016,22 @@ KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openl
/* Note m_map_*** are all ok and don't need to be freed
* most are temp and NewRemoveObject frees m_map_gameobject_to_blender */
-bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
+bool KX_BlenderSceneConverter::FreeBlendFile(Main *maggie)
{
- int maggie_index= -1;
- int i=0;
+ int maggie_index = -1;
+ int i = 0;
- if (maggie==NULL)
+ if (maggie == NULL)
return false;
/* tag all false except the one we remove */
- for (vector<Main*>::iterator it=m_DynamicMaggie.begin(); !(it==m_DynamicMaggie.end()); it++) {
- Main *main= *it;
+ for (vector<Main *>::iterator it = m_DynamicMaggie.begin(); !(it == m_DynamicMaggie.end()); it++) {
+ Main *main = *it;
if (main != maggie) {
BKE_main_id_tag_all(main, false);
}
else {
- maggie_index= i;
+ maggie_index = i;
}
i++;
}
@@ -1111,15 +1043,12 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
m_DynamicMaggie.erase(m_DynamicMaggie.begin() + maggie_index);
BKE_main_id_tag_all(maggie, true);
-
/* free all tagged objects */
- KX_SceneList* scenes = m_ketsjiEngine->CurrentScenes();
+ KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes();
int numScenes = scenes->size();
-
- for (int scene_idx=0;scene_idx<numScenes;scene_idx++)
- {
- KX_Scene* scene = scenes->at(scene_idx);
+ for (int scene_idx = 0; scene_idx < numScenes; scene_idx++) {
+ KX_Scene *scene = scenes->at(scene_idx);
if (IS_TAGGED(scene->GetBlenderScene())) {
m_ketsjiEngine->RemoveScene(scene->GetName());
m_mat_cache.erase(scene);
@@ -1128,16 +1057,13 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
numScenes--;
}
else {
-
/* in case the mesh might be refered to later */
{
- CTR_Map<STR_HashedString,void*> &mapStringToMeshes = scene->GetLogicManager()->GetMeshMap();
+ CTR_Map<STR_HashedString, void *> &mapStringToMeshes = scene->GetLogicManager()->GetMeshMap();
- for (int i=0; i<mapStringToMeshes.size(); i++)
- {
- RAS_MeshObject *meshobj= (RAS_MeshObject *) *mapStringToMeshes.at(i);
- if (meshobj && IS_TAGGED(meshobj->GetMesh()))
- {
+ for (int i = 0; i < mapStringToMeshes.size(); i++) {
+ RAS_MeshObject *meshobj = (RAS_MeshObject *) *mapStringToMeshes.at(i);
+ if (meshobj && IS_TAGGED(meshobj->GetMesh())) {
STR_HashedString mn = meshobj->GetName();
mapStringToMeshes.remove(mn);
m_map_mesh_to_gamemesh.remove(CHashedPtr(meshobj->GetMesh()));
@@ -1148,15 +1074,13 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
/* Now unregister actions */
{
- CTR_Map<STR_HashedString,void*> &mapStringToActions = scene->GetLogicManager()->GetActionMap();
+ CTR_Map<STR_HashedString, void *> &mapStringToActions = scene->GetLogicManager()->GetActionMap();
- for (int i=0; i<mapStringToActions.size(); i++)
- {
- ID *action= (ID*) *mapStringToActions.at(i);
+ for (int i = 0; i < mapStringToActions.size(); i++) {
+ ID *action = (ID*) *mapStringToActions.at(i);
- if (IS_TAGGED(action))
- {
- STR_HashedString an = action->name+2;
+ if (IS_TAGGED(action)) {
+ STR_HashedString an = action->name + 2;
mapStringToActions.remove(an);
i--;
}
@@ -1166,16 +1090,13 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
//scene->FreeTagged(); /* removed tagged objects and meshes*/
CListValue *obj_lists[] = {scene->GetObjectList(), scene->GetInactiveList(), NULL};
- for (int ob_ls_idx=0; obj_lists[ob_ls_idx]; ob_ls_idx++)
- {
- CListValue *obs= obj_lists[ob_ls_idx];
- RAS_MeshObject* mesh;
+ for (int ob_ls_idx = 0; obj_lists[ob_ls_idx]; ob_ls_idx++) {
+ CListValue *obs = obj_lists[ob_ls_idx];
+ RAS_MeshObject *mesh;
- for (int ob_idx = 0; ob_idx < obs->GetCount(); ob_idx++)
- {
- KX_GameObject* gameobj = (KX_GameObject*)obs->GetValue(ob_idx);
+ for (int ob_idx = 0; ob_idx < obs->GetCount(); ob_idx++) {
+ KX_GameObject *gameobj = (KX_GameObject*)obs->GetValue(ob_idx);
if (IS_TAGGED(gameobj->GetBlenderObject())) {
-
int size_before = obs->GetCount();
/* Eventually calls RemoveNodeDestructObject
@@ -1190,9 +1111,9 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
}
else {
/* free the mesh, we could be referecing a linked one! */
- int mesh_index= gameobj->GetMeshCount();
+ int mesh_index = gameobj->GetMeshCount();
while (mesh_index--) {
- mesh= gameobj->GetMesh(mesh_index);
+ mesh = gameobj->GetMesh(mesh_index);
if (IS_TAGGED(mesh->GetMesh())) {
gameobj->RemoveMeshes(); /* XXX - slack, should only remove meshes that are library items but mostly objects only have 1 mesh */
break;
@@ -1210,11 +1131,9 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
}
/* make sure action actuators are not referencing tagged actions */
- for (unsigned int act_idx=0; act_idx<gameobj->GetActuators().size(); act_idx++)
- {
- if (gameobj->GetActuators()[act_idx]->IsType(SCA_IActuator::KX_ACT_ACTION))
- {
- BL_ActionActuator *act = (BL_ActionActuator*)gameobj->GetActuators()[act_idx];
+ for (unsigned int act_idx = 0; act_idx < gameobj->GetActuators().size(); act_idx++) {
+ if (gameobj->GetActuators()[act_idx]->IsType(SCA_IActuator::KX_ACT_ACTION)) {
+ BL_ActionActuator *act = (BL_ActionActuator *)gameobj->GetActuators()[act_idx];
if (IS_TAGGED(act->GetAction()))
act->SetAction(NULL);
}
@@ -1225,7 +1144,6 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
}
}
-
int size;
// delete the entities of this scene
@@ -1248,24 +1166,24 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
/* Worlds don't reference original blender data so we need to make a set from them */
- typedef std::set<KX_WorldInfo*> KX_WorldInfoSet;
+ typedef std::set<KX_WorldInfo *> KX_WorldInfoSet;
KX_WorldInfoSet worldset;
- for (int scene_idx=0;scene_idx<numScenes;scene_idx++)
- {
- KX_Scene* scene = scenes->at(scene_idx);
+ for (int scene_idx = 0; scene_idx < numScenes; scene_idx++) {
+ KX_Scene *scene = scenes->at(scene_idx);
if (scene->GetWorldInfo())
- worldset.insert( scene->GetWorldInfo() );
+ worldset.insert(scene->GetWorldInfo());
}
- vector<pair<KX_Scene*,KX_WorldInfo*> >::iterator worldit;
+ vector<pair<KX_Scene *, KX_WorldInfo *> >::iterator worldit;
size = m_worldinfos.size();
- for (i=0, worldit=m_worldinfos.begin(); i<size; ) {
+ for (i = 0, worldit = m_worldinfos.begin(); i < size;) {
if ((*worldit).second && (worldset.count((*worldit).second)) == 0) {
delete (*worldit).second;
*worldit = m_worldinfos.back();
m_worldinfos.pop_back();
size--;
- } else {
+ }
+ else {
i++;
worldit++;
}
@@ -1273,20 +1191,15 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
worldset.clear();
/* done freeing the worlds */
-
-
-
- vector<pair<KX_Scene*,RAS_IPolyMaterial*> >::iterator polymit;
+ vector<pair<KX_Scene *, RAS_IPolyMaterial *> >::iterator polymit;
size = m_polymaterials.size();
+ for (i = 0, polymit = m_polymaterials.begin(); i < size; ) {
+ RAS_IPolyMaterial *mat = (*polymit).second;
+ Material *bmat = NULL;
-
- for (i=0, polymit=m_polymaterials.begin(); i<size; ) {
- RAS_IPolyMaterial *mat= (*polymit).second;
- Material *bmat= NULL;
-
- KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial*>(mat);
- bmat= bl_mat->GetBlenderMaterial();
+ KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial *>(mat);
+ bmat = bl_mat->GetBlenderMaterial();
if (IS_TAGGED(bmat)) {
/* only remove from bucket */
@@ -1297,63 +1210,57 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
polymit++;
}
-
-
- for (i=0, polymit=m_polymaterials.begin(); i<size; ) {
- RAS_IPolyMaterial *mat= (*polymit).second;
- Material *bmat= NULL;
+ for (i = 0, polymit = m_polymaterials.begin(); i < size; ) {
+ RAS_IPolyMaterial *mat = (*polymit).second;
+ Material *bmat = NULL;
KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial*>(mat);
- bmat= bl_mat->GetBlenderMaterial();
-
- if (bmat) {
- //printf("FOUND MAT '%s' !!! ", ((ID*)bmat)->name+2);
- }
- else {
- //printf("LOST MAT !!!");
- }
+ bmat = bl_mat->GetBlenderMaterial();
if (IS_TAGGED(bmat)) {
+ // Remove the poly material coresponding to this Blender Material.
+ m_polymat_cache[polymit->first].erase(bmat);
delete (*polymit).second;
*polymit = m_polymaterials.back();
m_polymaterials.pop_back();
size--;
- //printf("tagged !\n");
} else {
i++;
polymit++;
- //printf("(un)tagged !\n");
}
}
- vector<pair<KX_Scene*,BL_Material*> >::iterator matit;
+ vector<pair<KX_Scene *, BL_Material *> >::iterator matit;
size = m_materials.size();
- for (i=0, matit=m_materials.begin(); i<size; ) {
- BL_Material *mat= (*matit).second;
+ for (i = 0, matit = m_materials.begin(); i < size; ) {
+ BL_Material *mat = (*matit).second;
if (IS_TAGGED(mat->material)) {
+ // Remove the bl material coresponding to this Blender Material.
+ m_mat_cache[matit->first].erase(mat->material);
delete (*matit).second;
*matit = m_materials.back();
m_materials.pop_back();
size--;
- } else {
+ }
+ else {
i++;
matit++;
}
}
- vector<pair<KX_Scene*,RAS_MeshObject*> >::iterator meshit;
+ vector<pair<KX_Scene *, RAS_MeshObject *> >::iterator meshit;
RAS_BucketManager::BucketList::iterator bit;
list<RAS_MeshSlot>::iterator msit;
RAS_BucketManager::BucketList buckets;
size = m_meshobjects.size();
- for (i=0, meshit=m_meshobjects.begin(); i<size; ) {
- RAS_MeshObject *me= (*meshit).second;
+ for (i = 0, meshit = m_meshobjects.begin(); i < size;) {
+ RAS_MeshObject *me = (*meshit).second;
if (IS_TAGGED(me->GetMesh())) {
// Before deleting the mesh object, make sure the rasterizer is
// no longer referencing it.
buckets = meshit->first->GetBucketManager()->GetSolidBuckets();
- for (bit=buckets.begin(); bit!=buckets.end(); bit++) {
+ for (bit = buckets.begin(); bit != buckets.end(); bit++) {
msit = (*bit)->msBegin();
while (msit != (*bit)->msEnd()) {
@@ -1366,7 +1273,7 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
// And now the alpha buckets
buckets = meshit->first->GetBucketManager()->GetAlphaBuckets();
- for (bit=buckets.begin(); bit!=buckets.end(); bit++) {
+ for (bit = buckets.begin(); bit != buckets.end(); bit++) {
msit = (*bit)->msBegin();
while (msit != (*bit)->msEnd()) {
@@ -1382,7 +1289,8 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
*meshit = m_meshobjects.back();
m_meshobjects.pop_back();
size--;
- } else {
+ }
+ else {
i++;
meshit++;
}
@@ -1409,24 +1317,23 @@ bool KX_BlenderSceneConverter::FreeBlendFile(const char *path)
bool KX_BlenderSceneConverter::MergeScene(KX_Scene *to, KX_Scene *from)
{
-
{
- vector<pair<KX_Scene*,KX_WorldInfo*> >::iterator itp = m_worldinfos.begin();
+ vector<pair<KX_Scene *, KX_WorldInfo *> >::iterator itp = m_worldinfos.begin();
while (itp != m_worldinfos.end()) {
- if ((*itp).first==from)
- (*itp).first= to;
+ if ((*itp).first == from)
+ (*itp).first = to;
itp++;
}
}
{
- vector<pair<KX_Scene*,RAS_IPolyMaterial*> >::iterator itp = m_polymaterials.begin();
+ vector<pair<KX_Scene *, RAS_IPolyMaterial *> >::iterator itp = m_polymaterials.begin();
while (itp != m_polymaterials.end()) {
- if ((*itp).first==from) {
- (*itp).first= to;
+ if ((*itp).first == from) {
+ (*itp).first = to;
/* also switch internal data */
- RAS_IPolyMaterial*mat= (*itp).second;
+ RAS_IPolyMaterial *mat = (*itp).second;
mat->Replace_IScene(to);
}
itp++;
@@ -1434,29 +1341,39 @@ bool KX_BlenderSceneConverter::MergeScene(KX_Scene *to, KX_Scene *from)
}
{
- vector<pair<KX_Scene*,RAS_MeshObject*> >::iterator itp = m_meshobjects.begin();
+ vector<pair<KX_Scene *, RAS_MeshObject *> >::iterator itp = m_meshobjects.begin();
while (itp != m_meshobjects.end()) {
- if ((*itp).first==from)
- (*itp).first= to;
+ if ((*itp).first == from)
+ (*itp).first = to;
itp++;
}
}
{
- vector<pair<KX_Scene*,BL_Material*> >::iterator itp = m_materials.begin();
+ vector<pair<KX_Scene *, BL_Material *> >::iterator itp = m_materials.begin();
while (itp != m_materials.end()) {
- if ((*itp).first==from)
- (*itp).first= to;
+ if ((*itp).first == from)
+ (*itp).first = to;
itp++;
}
}
-
+
+ MaterialCache::iterator matcacheit = m_mat_cache.find(from);
+ // Merge cached BL_Material map.
+ m_mat_cache[to].insert(matcacheit->second.begin(), matcacheit->second.end());
+ m_mat_cache.erase(matcacheit);
+
+ PolyMaterialCache::iterator polymatcacheit = m_polymat_cache.find(from);
+ // Merge cached RAS_IPolyMaterial map.
+ m_polymat_cache[to].insert(polymatcacheit->second.begin(), polymatcacheit->second.end());
+ m_polymat_cache.erase(polymatcacheit);
+
return true;
}
/* This function merges a mesh from the current scene into another main
* it does not convert */
-RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene* kx_scene, Main *maggie, const char *name)
+RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene *kx_scene, Main *maggie, const char *name)
{
/* Find a mesh in the current main */
ID *me= static_cast<ID *>(BLI_findstring(&m_maggie->mesh, name, offsetof(ID, name) + 2));
@@ -1464,7 +1381,7 @@ RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene* kx_scene,
if (me == NULL) {
// The mesh wasn't in the current main, try any dynamic (i.e., LibLoaded) ones
- vector<Main*>::iterator it;
+ vector<Main *>::iterator it;
for (it = GetMainDynamic().begin(); it != GetMainDynamic().end(); it++) {
me = static_cast<ID *>(BLI_findstring(&(*it)->mesh, name, offsetof(ID, name) + 2));
@@ -1474,12 +1391,12 @@ RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene* kx_scene,
break;
}
}
-
- if (me==NULL) {
+
+ if (me == NULL) {
printf("Could not be found \"%s\"\n", name);
return NULL;
}
-
+
/* Watch this!, if its used in the original scene can cause big troubles */
if (me->us > 0) {
#ifdef DEBUG
@@ -1491,34 +1408,32 @@ RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene* kx_scene,
BLI_remlink(&from_maggie->mesh, me); /* even if we made the copy it needs to be removed */
BLI_addtail(&maggie->mesh, me);
-
/* Must copy the materials this uses else we cant free them */
{
- Mesh *mesh= (Mesh *)me;
-
+ Mesh *mesh = (Mesh *)me;
+
/* ensure all materials are tagged */
- for (int i=0; i<mesh->totcol; i++)
+ for (int i = 0; i < mesh->totcol; i++) {
if (mesh->mat[i])
mesh->mat[i]->id.flag &= ~LIB_DOIT;
-
- for (int i=0; i<mesh->totcol; i++)
- {
- Material *mat_old= mesh->mat[i];
-
+ }
+
+ for (int i = 0; i < mesh->totcol; i++) {
+ Material *mat_old = mesh->mat[i];
+
/* if its tagged its a replaced material */
- if (mat_old && (mat_old->id.flag & LIB_DOIT)==0)
- {
- Material *mat_old= mesh->mat[i];
- Material *mat_new= BKE_material_copy( mat_old );
-
+ if (mat_old && (mat_old->id.flag & LIB_DOIT) == 0) {
+ Material *mat_old = mesh->mat[i];
+ Material *mat_new = BKE_material_copy(mat_old);
+
mat_new->id.flag |= LIB_DOIT;
mat_old->id.us--;
-
+
BLI_remlink(&G.main->mat, mat_new); // BKE_material_copy uses G.main, and there is no BKE_material_copy_ex
BLI_addtail(&maggie->mat, mat_new);
-
+
mesh->mat[i] = mat_new;
-
+
/* the same material may be used twice */
for (int j = i + 1; j < mesh->totcol; j++) {
if (mesh->mat[j] == mat_old) {
diff --git a/source/gameengine/Converter/KX_ConvertSensors.cpp b/source/gameengine/Converter/KX_ConvertSensors.cpp
index 0d706fcd924..854ae5b28dc 100644
--- a/source/gameengine/Converter/KX_ConvertSensors.cpp
+++ b/source/gameengine/Converter/KX_ConvertSensors.cpp
@@ -105,7 +105,7 @@ void BL_ConvertSensors(struct Object* blenderobject,
bSensor* sens = (bSensor*)blenderobject->sensors.first;
bool pos_pulsemode = false;
bool neg_pulsemode = false;
- int frequency = 0;
+ int skipped_ticks = 0;
bool invert = false;
bool level = false;
bool tap = false;
@@ -119,542 +119,542 @@ void BL_ConvertSensors(struct Object* blenderobject,
sens = (bSensor*)blenderobject->sensors.first;
while (sens) {
- SCA_ISensor* gamesensor=NULL;
- /* All sensors have a pulse toggle, frequency, and invert field. */
- /* These are extracted here, and set when the sensor is added to the */
- /* list. */
- pos_pulsemode = (sens->pulse & SENS_PULSE_REPEAT)!=0;
- neg_pulsemode = (sens->pulse & SENS_NEG_PULSE_MODE)!=0;
-
- frequency = sens->freq;
- invert = !(sens->invert == 0);
- level = !(sens->level == 0);
- tap = !(sens->tap == 0);
-
- switch (sens->type)
- {
- case SENS_ALWAYS:
- {
-
- SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR);
- if (eventmgr)
- {
- gamesensor = new SCA_AlwaysSensor(eventmgr, gameobj);
- }
-
- break;
- }
-
- case SENS_DELAY:
+ if (!(sens->flag & SENS_DEACTIVATE)) {
+ SCA_ISensor* gamesensor=NULL;
+ /* All sensors have a pulse toggle, skipped ticks parameter, and invert field. */
+ /* These are extracted here, and set when the sensor is added to the */
+ /* list. */
+ pos_pulsemode = (sens->pulse & SENS_PULSE_REPEAT)!=0;
+ neg_pulsemode = (sens->pulse & SENS_NEG_PULSE_MODE)!=0;
+
+ skipped_ticks = sens->freq;
+ invert = !(sens->invert == 0);
+ level = !(sens->level == 0);
+ tap = !(sens->tap == 0);
+
+ switch (sens->type)
{
- // we can reuse the Always event manager for the delay sensor
- SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR);
- if (eventmgr)
+ case SENS_ALWAYS:
{
- bDelaySensor* delaysensor = (bDelaySensor*)sens->data;
- gamesensor = new SCA_DelaySensor(eventmgr,
- gameobj,
- delaysensor->delay,
- delaysensor->duration,
- (delaysensor->flag & SENS_DELAY_REPEAT) != 0);
+
+ SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR);
+ if (eventmgr)
+ {
+ gamesensor = new SCA_AlwaysSensor(eventmgr, gameobj);
+ }
+
+ break;
}
- break;
- }
- case SENS_COLLISION:
- {
- SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR);
- if (eventmgr)
+ case SENS_DELAY:
{
- // collision sensor can sense both materials and properties.
-
- bool bFindMaterial = false, bTouchPulse = false;
-
- bCollisionSensor* blendertouchsensor = (bCollisionSensor*)sens->data;
-
- bFindMaterial = (blendertouchsensor->mode & SENS_COLLISION_MATERIAL);
- bTouchPulse = (blendertouchsensor->mode & SENS_COLLISION_PULSE);
-
-
- const STR_String touchPropOrMatName = bFindMaterial ?
- blendertouchsensor->materialName : blendertouchsensor->name;
-
-
- if (gameobj->GetPhysicsController())
+ // we can reuse the Always event manager for the delay sensor
+ SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR);
+ if (eventmgr)
{
- gamesensor = new KX_TouchSensor(eventmgr,
+ bDelaySensor* delaysensor = (bDelaySensor*)sens->data;
+ gamesensor = new SCA_DelaySensor(eventmgr,
gameobj,
- bFindMaterial,
- bTouchPulse,
- touchPropOrMatName);
+ delaysensor->delay,
+ delaysensor->duration,
+ (delaysensor->flag & SENS_DELAY_REPEAT) != 0);
}
-
- }
-
- break;
- }
- case SENS_MESSAGE:
- {
- KX_NetworkEventManager* eventmgr = (KX_NetworkEventManager*)
- logicmgr->FindEventManager(SCA_EventManager::NETWORK_EVENTMGR);
- if (eventmgr) {
- bMessageSensor* msgSens = (bMessageSensor*) sens->data;
-
- /* Get our NetworkScene */
- NG_NetworkScene *NetworkScene = kxscene->GetNetworkScene();
- /* filter on the incoming subjects, might be empty */
- const STR_String subject = msgSens->subject;
-
- gamesensor = new KX_NetworkMessageSensor(
- eventmgr, // our eventmanager
- NetworkScene, // our NetworkScene
- gameobj, // the sensor controlling object
- subject); // subject to filter on
+ break;
}
- break;
- }
- case SENS_NEAR:
- {
-
- SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR);
- if (eventmgr)
+
+ case SENS_COLLISION:
{
- bNearSensor* blendernearsensor = (bNearSensor*)sens->data;
- const STR_String nearpropertyname = (char *)blendernearsensor->name;
-
- //DT_ShapeHandle shape = DT_Sphere(0.0);
-
- // this sumoObject is not deleted by a gameobj, so delete it ourself
- // later (memleaks)!
- float radius = blendernearsensor->dist;
- const MT_Vector3& wpos = gameobj->NodeGetWorldPosition();
- bool bFindMaterial = false;
- PHY_IPhysicsController* physCtrl = kxscene->GetPhysicsEnvironment()->CreateSphereController(radius,wpos);
-
- //will be done in KX_TouchEventManager::RegisterSensor()
- //if (isInActiveLayer)
- // kxscene->GetPhysicsEnvironment()->addSensor(physCtrl);
-
-
-
- gamesensor = new KX_NearSensor(eventmgr,gameobj,
- blendernearsensor->dist,
- blendernearsensor->resetdist,
- bFindMaterial,
- nearpropertyname,
- physCtrl);
-
+ SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR);
+ if (eventmgr)
+ {
+ // collision sensor can sense both materials and properties.
+
+ bool bFindMaterial = false, bTouchPulse = false;
+
+ bCollisionSensor* blendertouchsensor = (bCollisionSensor*)sens->data;
+
+ bFindMaterial = (blendertouchsensor->mode & SENS_COLLISION_MATERIAL);
+ bTouchPulse = (blendertouchsensor->mode & SENS_COLLISION_PULSE);
+
+
+ const STR_String touchPropOrMatName = bFindMaterial ?
+ blendertouchsensor->materialName : blendertouchsensor->name;
+
+
+ if (gameobj->GetPhysicsController())
+ {
+ gamesensor = new KX_TouchSensor(eventmgr,
+ gameobj,
+ bFindMaterial,
+ bTouchPulse,
+ touchPropOrMatName);
+ }
+
+ }
+
+ break;
}
- break;
- }
-
-
- case SENS_KEYBOARD:
- {
- /* temporary input device, for converting the code for the keyboard sensor */
-
- bKeyboardSensor* blenderkeybdsensor = (bKeyboardSensor*)sens->data;
- SCA_KeyboardManager* eventmgr = (SCA_KeyboardManager*) logicmgr->FindEventManager(SCA_EventManager::KEYBOARD_EVENTMGR);
- if (eventmgr)
+ case SENS_MESSAGE:
{
- gamesensor = new SCA_KeyboardSensor(eventmgr,
- ConvertKeyCode(blenderkeybdsensor->key),
- ConvertKeyCode(blenderkeybdsensor->qual),
- ConvertKeyCode(blenderkeybdsensor->qual2),
- (blenderkeybdsensor->type == SENS_ALL_KEYS),
- blenderkeybdsensor->targetName,
- blenderkeybdsensor->toggleName,
- gameobj,
- KX_KetsjiEngine::GetExitKey()); // blenderkeybdsensor->pad);
-
- }
-
- break;
- }
- case SENS_MOUSE:
- {
- int keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_NODEF;
- int trackfocus = 0;
- bMouseSensor *bmouse = (bMouseSensor *)sens->data;
-
- /* There are two main types of mouse sensors. If there is
- * no focus-related behavior requested, we can make do
- * with a basic sensor. This cuts down memory usage and
- * gives a slight performance gain. */
-
- SCA_MouseManager *eventmgr
- = (SCA_MouseManager*) logicmgr->FindEventManager(SCA_EventManager::MOUSE_EVENTMGR);
- if (eventmgr) {
-
- /* Determine key mode. There is at most one active mode. */
- switch (bmouse->type) {
- case BL_SENS_MOUSE_LEFT_BUTTON:
- keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_LEFTBUTTON;
- break;
- case BL_SENS_MOUSE_MIDDLE_BUTTON:
- keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_MIDDLEBUTTON;
- break;
- case BL_SENS_MOUSE_RIGHT_BUTTON:
- keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_RIGHTBUTTON;
- break;
- case BL_SENS_MOUSE_WHEEL_UP:
- keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_WHEELUP;
- break;
- case BL_SENS_MOUSE_WHEEL_DOWN:
- keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_WHEELDOWN;
- break;
- case BL_SENS_MOUSE_MOVEMENT:
- keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_MOVEMENT;
- break;
- case BL_SENS_MOUSE_MOUSEOVER:
- trackfocus = 1;
- break;
- case BL_SENS_MOUSE_MOUSEOVER_ANY:
- trackfocus = 2;
- break;
-
- default:
- ; /* error */
+ KX_NetworkEventManager* eventmgr = (KX_NetworkEventManager*)
+ logicmgr->FindEventManager(SCA_EventManager::NETWORK_EVENTMGR);
+ if (eventmgr) {
+ bMessageSensor* msgSens = (bMessageSensor*) sens->data;
+
+ /* Get our NetworkScene */
+ NG_NetworkScene *NetworkScene = kxscene->GetNetworkScene();
+ /* filter on the incoming subjects, might be empty */
+ const STR_String subject = msgSens->subject;
+
+ gamesensor = new KX_NetworkMessageSensor(
+ eventmgr, // our eventmanager
+ NetworkScene, // our NetworkScene
+ gameobj, // the sensor controlling object
+ subject); // subject to filter on
}
-
- /* initial mouse position */
- int startx = canvas->GetWidth()/2;
- int starty = canvas->GetHeight()/2;
-
- if (!trackfocus) {
- /* plain, simple mouse sensor */
- gamesensor = new SCA_MouseSensor(eventmgr,
- startx,starty,
- keytype,
- gameobj);
- } else {
- /* give us a focus-aware sensor */
- bool bFindMaterial = (bmouse->mode & SENS_COLLISION_MATERIAL);
- bool bXRay = (bmouse->flag & SENS_RAY_XRAY);
- STR_String checkname = (bFindMaterial? bmouse->matname : bmouse->propname);
-
- gamesensor = new KX_MouseFocusSensor(eventmgr,
- startx,
- starty,
- keytype,
- trackfocus,
- (bmouse->flag & SENS_MOUSE_FOCUS_PULSE) ? true:false,
- checkname,
+ break;
+ }
+ case SENS_NEAR:
+ {
+
+ SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR);
+ if (eventmgr)
+ {
+ bNearSensor* blendernearsensor = (bNearSensor*)sens->data;
+ const STR_String nearpropertyname = (char *)blendernearsensor->name;
+
+ //DT_ShapeHandle shape = DT_Sphere(0.0);
+
+ // this sumoObject is not deleted by a gameobj, so delete it ourself
+ // later (memleaks)!
+ float radius = blendernearsensor->dist;
+ const MT_Vector3& wpos = gameobj->NodeGetWorldPosition();
+ bool bFindMaterial = false;
+ PHY_IPhysicsController* physCtrl = kxscene->GetPhysicsEnvironment()->CreateSphereController(radius,wpos);
+
+ //will be done in KX_TouchEventManager::RegisterSensor()
+ //if (isInActiveLayer)
+ // kxscene->GetPhysicsEnvironment()->addSensor(physCtrl);
+
+
+
+ gamesensor = new KX_NearSensor(eventmgr,gameobj,
+ blendernearsensor->dist,
+ blendernearsensor->resetdist,
bFindMaterial,
- bXRay,
- kxscene,
- kxengine,
- gameobj);
+ nearpropertyname,
+ physCtrl);
+
}
- } else {
- // cout << "\n Could't find mouse event manager..."; - should throw an error here...
+ break;
}
- break;
- }
- case SENS_PROPERTY:
- {
- bPropertySensor* blenderpropsensor = (bPropertySensor*) sens->data;
- SCA_EventManager* eventmgr
- = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR);
- if (eventmgr)
+
+
+ case SENS_KEYBOARD:
{
- STR_String propname=blenderpropsensor->name;
- STR_String propval=blenderpropsensor->value;
- STR_String propmaxval=blenderpropsensor->maxvalue;
-
- SCA_PropertySensor::KX_PROPSENSOR_TYPE
- propchecktype = SCA_PropertySensor::KX_PROPSENSOR_NODEF;
-
- /* Better do an explicit conversion here! (was implicit */
- /* before...) */
- switch (blenderpropsensor->type) {
- case SENS_PROP_EQUAL:
- propchecktype = SCA_PropertySensor::KX_PROPSENSOR_EQUAL;
- break;
- case SENS_PROP_NEQUAL:
- propchecktype = SCA_PropertySensor::KX_PROPSENSOR_NOTEQUAL;
- break;
- case SENS_PROP_INTERVAL:
- propchecktype = SCA_PropertySensor::KX_PROPSENSOR_INTERVAL;
- break;
- case SENS_PROP_CHANGED:
- propchecktype = SCA_PropertySensor::KX_PROPSENSOR_CHANGED;
- break;
- case SENS_PROP_EXPRESSION:
- propchecktype = SCA_PropertySensor::KX_PROPSENSOR_EXPRESSION;
- /* error */
- break;
- case SENS_PROP_LESSTHAN:
- propchecktype = SCA_PropertySensor::KX_PROPSENSOR_LESSTHAN;
- break;
- case SENS_PROP_GREATERTHAN:
- propchecktype = SCA_PropertySensor::KX_PROPSENSOR_GREATERTHAN;
- break;
- default:
- ; /* error */
+ /* temporary input device, for converting the code for the keyboard sensor */
+
+ bKeyboardSensor* blenderkeybdsensor = (bKeyboardSensor*)sens->data;
+ SCA_KeyboardManager* eventmgr = (SCA_KeyboardManager*) logicmgr->FindEventManager(SCA_EventManager::KEYBOARD_EVENTMGR);
+ if (eventmgr)
+ {
+ gamesensor = new SCA_KeyboardSensor(eventmgr,
+ ConvertKeyCode(blenderkeybdsensor->key),
+ ConvertKeyCode(blenderkeybdsensor->qual),
+ ConvertKeyCode(blenderkeybdsensor->qual2),
+ (blenderkeybdsensor->type == SENS_ALL_KEYS),
+ blenderkeybdsensor->targetName,
+ blenderkeybdsensor->toggleName,
+ gameobj,
+ KX_KetsjiEngine::GetExitKey()); // blenderkeybdsensor->pad);
+
}
- gamesensor = new SCA_PropertySensor(eventmgr,gameobj,propname,propval,propmaxval,propchecktype);
+
+ break;
}
-
- break;
- }
- case SENS_ACTUATOR:
- {
- bActuatorSensor* blenderactsensor = (bActuatorSensor*) sens->data;
- // we will reuse the property event manager, there is nothing special with this sensor
- SCA_EventManager* eventmgr
- = logicmgr->FindEventManager(SCA_EventManager::ACTUATOR_EVENTMGR);
- if (eventmgr)
+ case SENS_MOUSE:
+ {
+ int keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_NODEF;
+ int trackfocus = 0;
+ bMouseSensor *bmouse = (bMouseSensor *)sens->data;
+
+ /* There are two main types of mouse sensors. If there is
+ * no focus-related behavior requested, we can make do
+ * with a basic sensor. This cuts down memory usage and
+ * gives a slight performance gain. */
+
+ SCA_MouseManager *eventmgr
+ = (SCA_MouseManager*) logicmgr->FindEventManager(SCA_EventManager::MOUSE_EVENTMGR);
+ if (eventmgr) {
+
+ /* Determine key mode. There is at most one active mode. */
+ switch (bmouse->type) {
+ case BL_SENS_MOUSE_LEFT_BUTTON:
+ keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_LEFTBUTTON;
+ break;
+ case BL_SENS_MOUSE_MIDDLE_BUTTON:
+ keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_MIDDLEBUTTON;
+ break;
+ case BL_SENS_MOUSE_RIGHT_BUTTON:
+ keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_RIGHTBUTTON;
+ break;
+ case BL_SENS_MOUSE_WHEEL_UP:
+ keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_WHEELUP;
+ break;
+ case BL_SENS_MOUSE_WHEEL_DOWN:
+ keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_WHEELDOWN;
+ break;
+ case BL_SENS_MOUSE_MOVEMENT:
+ keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_MOVEMENT;
+ break;
+ case BL_SENS_MOUSE_MOUSEOVER:
+ trackfocus = 1;
+ break;
+ case BL_SENS_MOUSE_MOUSEOVER_ANY:
+ trackfocus = 2;
+ break;
+
+ default:
+ ; /* error */
+ }
+
+ /* initial mouse position */
+ int startx = canvas->GetWidth()/2;
+ int starty = canvas->GetHeight()/2;
+
+ if (!trackfocus) {
+ /* plain, simple mouse sensor */
+ gamesensor = new SCA_MouseSensor(eventmgr,
+ startx,starty,
+ keytype,
+ gameobj);
+ } else {
+ /* give us a focus-aware sensor */
+ bool bFindMaterial = (bmouse->mode & SENS_COLLISION_MATERIAL);
+ bool bXRay = (bmouse->flag & SENS_RAY_XRAY);
+ STR_String checkname = (bFindMaterial? bmouse->matname : bmouse->propname);
+
+ gamesensor = new KX_MouseFocusSensor(eventmgr,
+ startx,
+ starty,
+ keytype,
+ trackfocus,
+ (bmouse->flag & SENS_MOUSE_FOCUS_PULSE) ? true:false,
+ checkname,
+ bFindMaterial,
+ bXRay,
+ kxscene,
+ kxengine,
+ gameobj);
+ }
+ } else {
+ // cout << "\n Could't find mouse event manager..."; - should throw an error here...
+ }
+ break;
+ }
+ case SENS_PROPERTY:
{
- STR_String propname=blenderactsensor->name;
- gamesensor = new SCA_ActuatorSensor(eventmgr,gameobj,propname);
+ bPropertySensor* blenderpropsensor = (bPropertySensor*) sens->data;
+ SCA_EventManager* eventmgr
+ = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR);
+ if (eventmgr)
+ {
+ STR_String propname=blenderpropsensor->name;
+ STR_String propval=blenderpropsensor->value;
+ STR_String propmaxval=blenderpropsensor->maxvalue;
+
+ SCA_PropertySensor::KX_PROPSENSOR_TYPE
+ propchecktype = SCA_PropertySensor::KX_PROPSENSOR_NODEF;
+
+ /* Better do an explicit conversion here! (was implicit */
+ /* before...) */
+ switch (blenderpropsensor->type) {
+ case SENS_PROP_EQUAL:
+ propchecktype = SCA_PropertySensor::KX_PROPSENSOR_EQUAL;
+ break;
+ case SENS_PROP_NEQUAL:
+ propchecktype = SCA_PropertySensor::KX_PROPSENSOR_NOTEQUAL;
+ break;
+ case SENS_PROP_INTERVAL:
+ propchecktype = SCA_PropertySensor::KX_PROPSENSOR_INTERVAL;
+ break;
+ case SENS_PROP_CHANGED:
+ propchecktype = SCA_PropertySensor::KX_PROPSENSOR_CHANGED;
+ break;
+ case SENS_PROP_EXPRESSION:
+ propchecktype = SCA_PropertySensor::KX_PROPSENSOR_EXPRESSION;
+ /* error */
+ break;
+ case SENS_PROP_LESSTHAN:
+ propchecktype = SCA_PropertySensor::KX_PROPSENSOR_LESSTHAN;
+ break;
+ case SENS_PROP_GREATERTHAN:
+ propchecktype = SCA_PropertySensor::KX_PROPSENSOR_GREATERTHAN;
+ break;
+ default:
+ ; /* error */
+ }
+ gamesensor = new SCA_PropertySensor(eventmgr,gameobj,propname,propval,propmaxval,propchecktype);
+ }
+
+ break;
}
- break;
- }
-
- case SENS_ARMATURE:
- {
- bArmatureSensor* blenderarmsensor = (bArmatureSensor*) sens->data;
- // we will reuse the property event manager, there is nothing special with this sensor
- SCA_EventManager* eventmgr
- = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR);
- if (eventmgr)
+ case SENS_ACTUATOR:
{
- STR_String bonename=blenderarmsensor->posechannel;
- STR_String constraintname=blenderarmsensor->constraint;
- gamesensor = new KX_ArmatureSensor(eventmgr,gameobj,bonename,constraintname, blenderarmsensor->type, blenderarmsensor->value);
+ bActuatorSensor* blenderactsensor = (bActuatorSensor*) sens->data;
+ // we will reuse the property event manager, there is nothing special with this sensor
+ SCA_EventManager* eventmgr
+ = logicmgr->FindEventManager(SCA_EventManager::ACTUATOR_EVENTMGR);
+ if (eventmgr)
+ {
+ STR_String propname=blenderactsensor->name;
+ gamesensor = new SCA_ActuatorSensor(eventmgr,gameobj,propname);
+ }
+ break;
}
- break;
- }
- case SENS_RADAR:
- {
-
- SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR);
- if (eventmgr)
+ case SENS_ARMATURE:
{
- bRadarSensor* blenderradarsensor = (bRadarSensor*) sens->data;
- const STR_String radarpropertyname = blenderradarsensor->name;
-
- int radaraxis = blenderradarsensor->axis;
-
- MT_Scalar coneheight = blenderradarsensor->range;
-
- // janco: the angle was doubled, so should I divide the factor in 2
- // or the blenderradarsensor->angle?
- // nzc: the angle is the opening angle. We need to init with
- // the axis-hull angle,so /2.0.
- MT_Scalar factor = tan(blenderradarsensor->angle * 0.5f);
- //MT_Scalar coneradius = coneheight * (factor / 2);
- MT_Scalar coneradius = coneheight * factor;
-
-
- // this sumoObject is not deleted by a gameobj, so delete it ourself
- // later (memleaks)!
- MT_Scalar smallmargin = 0.0;
- MT_Scalar largemargin = 0.0;
-
- bool bFindMaterial = false;
- PHY_IPhysicsController* ctrl = kxscene->GetPhysicsEnvironment()->CreateConeController((float)coneradius, (float)coneheight);
-
- gamesensor = new KX_RadarSensor(
- eventmgr,
- gameobj,
- ctrl,
- coneradius,
- coneheight,
- radaraxis,
- smallmargin,
- largemargin,
- bFindMaterial,
- radarpropertyname);
-
+ bArmatureSensor* blenderarmsensor = (bArmatureSensor*) sens->data;
+ // we will reuse the property event manager, there is nothing special with this sensor
+ SCA_EventManager* eventmgr
+ = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR);
+ if (eventmgr)
+ {
+ STR_String bonename=blenderarmsensor->posechannel;
+ STR_String constraintname=blenderarmsensor->constraint;
+ gamesensor = new KX_ArmatureSensor(eventmgr,gameobj,bonename,constraintname, blenderarmsensor->type, blenderarmsensor->value);
+ }
+ break;
}
-
- break;
- }
- case SENS_RAY:
- {
- bRaySensor* blenderraysensor = (bRaySensor*) sens->data;
-
- //blenderradarsensor->angle;
- SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR);
- if (eventmgr)
+
+ case SENS_RADAR:
{
- bool bFindMaterial = (blenderraysensor->mode & SENS_COLLISION_MATERIAL);
- bool bXRay = (blenderraysensor->mode & SENS_RAY_XRAY);
-
- STR_String checkname = (bFindMaterial? blenderraysensor->matname : blenderraysensor->propname);
-
- // don't want to get rays of length 0.0 or so
- double distance = (blenderraysensor->range < 0.01f ? 0.01f : blenderraysensor->range);
- int axis = blenderraysensor->axisflag;
-
-
- gamesensor = new KX_RaySensor(eventmgr,
- gameobj,
- checkname,
- bFindMaterial,
- bXRay,
- distance,
- axis,
- kxscene);
+ SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR);
+ if (eventmgr)
+ {
+ bRadarSensor* blenderradarsensor = (bRadarSensor*) sens->data;
+ const STR_String radarpropertyname = blenderradarsensor->name;
+
+ int radaraxis = blenderradarsensor->axis;
+
+ MT_Scalar coneheight = blenderradarsensor->range;
+
+ // janco: the angle was doubled, so should I divide the factor in 2
+ // or the blenderradarsensor->angle?
+ // nzc: the angle is the opening angle. We need to init with
+ // the axis-hull angle,so /2.0.
+ MT_Scalar factor = tan(blenderradarsensor->angle * 0.5f);
+ //MT_Scalar coneradius = coneheight * (factor / 2);
+ MT_Scalar coneradius = coneheight * factor;
+
+
+ // this sumoObject is not deleted by a gameobj, so delete it ourself
+ // later (memleaks)!
+ MT_Scalar smallmargin = 0.0;
+ MT_Scalar largemargin = 0.0;
+
+ bool bFindMaterial = false;
+ PHY_IPhysicsController* ctrl = kxscene->GetPhysicsEnvironment()->CreateConeController((float)coneradius, (float)coneheight);
+
+ gamesensor = new KX_RadarSensor(
+ eventmgr,
+ gameobj,
+ ctrl,
+ coneradius,
+ coneheight,
+ radaraxis,
+ smallmargin,
+ largemargin,
+ bFindMaterial,
+ radarpropertyname);
+
+ }
+
+ break;
}
- break;
- }
-
- case SENS_RANDOM:
- {
- bRandomSensor* blenderrndsensor = (bRandomSensor*) sens->data;
- // some files didn't write randomsensor, avoid crash now for NULL ptr's
- if (blenderrndsensor)
+ case SENS_RAY:
{
+ bRaySensor* blenderraysensor = (bRaySensor*) sens->data;
+
+ //blenderradarsensor->angle;
SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR);
if (eventmgr)
{
- int randomSeed = blenderrndsensor->seed;
- if (randomSeed == 0)
+ bool bFindMaterial = (blenderraysensor->mode & SENS_COLLISION_MATERIAL);
+ bool bXRay = (blenderraysensor->mode & SENS_RAY_XRAY);
+
+ STR_String checkname = (bFindMaterial? blenderraysensor->matname : blenderraysensor->propname);
+
+ // don't want to get rays of length 0.0 or so
+ double distance = (blenderraysensor->range < 0.01f ? 0.01f : blenderraysensor->range);
+ int axis = blenderraysensor->axisflag;
+
+
+ gamesensor = new KX_RaySensor(eventmgr,
+ gameobj,
+ checkname,
+ bFindMaterial,
+ bXRay,
+ distance,
+ axis,
+ kxscene);
+
+ }
+ break;
+ }
+
+ case SENS_RANDOM:
+ {
+ bRandomSensor* blenderrndsensor = (bRandomSensor*) sens->data;
+ // some files didn't write randomsensor, avoid crash now for NULL ptr's
+ if (blenderrndsensor)
+ {
+ SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR);
+ if (eventmgr)
{
- randomSeed = (int)(kxengine->GetRealTime()*100000.0);
- randomSeed ^= (intptr_t)blenderrndsensor;
+ int randomSeed = blenderrndsensor->seed;
+ if (randomSeed == 0)
+ {
+ randomSeed = (int)(kxengine->GetRealTime()*100000.0);
+ randomSeed ^= (intptr_t)blenderrndsensor;
+ }
+ gamesensor = new SCA_RandomSensor(eventmgr, gameobj, randomSeed);
}
- gamesensor = new SCA_RandomSensor(eventmgr, gameobj, randomSeed);
}
+ break;
}
- break;
- }
- case SENS_JOYSTICK:
- {
- int joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_NODEF;
-
- bJoystickSensor* bjoy = (bJoystickSensor*) sens->data;
-
- SCA_JoystickManager *eventmgr
- = (SCA_JoystickManager*) logicmgr->FindEventManager(SCA_EventManager::JOY_EVENTMGR);
- if (eventmgr)
+ case SENS_JOYSTICK:
{
- int axis =0;
- int axisf =0;
- int button =0;
- int hat =0;
- int hatf =0;
- int prec =0;
-
- switch (bjoy->type) {
- case SENS_JOY_AXIS:
- axis = bjoy->axis;
- axisf = bjoy->axisf;
- prec = bjoy->precision;
- joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_AXIS;
- break;
- case SENS_JOY_BUTTON:
- button = bjoy->button;
- joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_BUTTON;
- break;
- case SENS_JOY_HAT:
- hat = bjoy->hat;
- hatf = bjoy->hatf;
- joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_HAT;
- break;
- case SENS_JOY_AXIS_SINGLE:
- axis = bjoy->axis_single;
- prec = bjoy->precision;
- joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_AXIS_SINGLE;
- break;
- default:
- printf("Error: bad case statement\n");
- break;
+ int joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_NODEF;
+
+ bJoystickSensor* bjoy = (bJoystickSensor*) sens->data;
+
+ SCA_JoystickManager *eventmgr
+ = (SCA_JoystickManager*) logicmgr->FindEventManager(SCA_EventManager::JOY_EVENTMGR);
+ if (eventmgr)
+ {
+ int axis =0;
+ int axisf =0;
+ int button =0;
+ int hat =0;
+ int hatf =0;
+ int prec =0;
+
+ switch (bjoy->type) {
+ case SENS_JOY_AXIS:
+ axis = bjoy->axis;
+ axisf = bjoy->axisf;
+ prec = bjoy->precision;
+ joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_AXIS;
+ break;
+ case SENS_JOY_BUTTON:
+ button = bjoy->button;
+ joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_BUTTON;
+ break;
+ case SENS_JOY_HAT:
+ hat = bjoy->hat;
+ hatf = bjoy->hatf;
+ joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_HAT;
+ break;
+ case SENS_JOY_AXIS_SINGLE:
+ axis = bjoy->axis_single;
+ prec = bjoy->precision;
+ joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_AXIS_SINGLE;
+ break;
+ default:
+ printf("Error: bad case statement\n");
+ break;
+ }
+ gamesensor = new SCA_JoystickSensor(
+ eventmgr,
+ gameobj,
+ bjoy->joyindex,
+ joysticktype,
+ axis,axisf,
+ prec,
+ button,
+ hat,hatf,
+ (bjoy->flag & SENS_JOY_ANY_EVENT));
}
- gamesensor = new SCA_JoystickSensor(
- eventmgr,
- gameobj,
- bjoy->joyindex,
- joysticktype,
- axis,axisf,
- prec,
- button,
- hat,hatf,
- (bjoy->flag & SENS_JOY_ANY_EVENT));
- }
- else
+ else
+ {
+ printf("Error there was a problem finding the event manager\n");
+ }
+
+ break;
+ }
+ default:
{
- printf("Error there was a problem finding the event manager\n");
}
-
- break;
}
- default:
- {
- }
- }
- if (gamesensor && !(sens->flag & SENS_DEACTIVATE))
- {
- gamesensor->SetExecutePriority(executePriority++);
- STR_String uniquename = sens->name;
- uniquename += "#SENS#";
- uniqueint++;
- CIntValue* uniqueval = new CIntValue(uniqueint);
- uniquename += uniqueval->GetText();
- uniqueval->Release();
-
- /* Conversion succeeded, so we can set the generic props here. */
- gamesensor->SetPulseMode(pos_pulsemode,
- neg_pulsemode,
- frequency);
- gamesensor->SetInvert(invert);
- gamesensor->SetLevel(level);
- gamesensor->SetTap(tap);
- gamesensor->SetName(sens->name);
-
- gameobj->AddSensor(gamesensor);
-
- // only register to manager if it's in an active layer
- // Make registration dynamic: only when sensor is activated
- //if (isInActiveLayer)
- // gamesensor->RegisterToManager();
-
- gamesensor->ReserveController(sens->totlinks);
- for (int i=0;i<sens->totlinks;i++)
+ if (gamesensor)
{
- bController* linkedcont = (bController*) sens->links[i];
- if (linkedcont) {
- // If the controller is deactived doesn't register it
- if (!(linkedcont->flag & CONT_DEACTIVATE)) {
- SCA_IController* gamecont = converter->FindGameController(linkedcont);
-
- if (gamecont) {
- logicmgr->RegisterToSensor(gamecont,gamesensor);
- }
- else {
- printf("Warning, sensor \"%s\" could not find its controller "
- "(link %d of %d) from object \"%s\"\n"
- "\tthere has been an error converting the blender controller for the game engine,"
- "logic may be incorrect\n", sens->name, i+1, sens->totlinks, blenderobject->id.name+2);
+ gamesensor->SetExecutePriority(executePriority++);
+ STR_String uniquename = sens->name;
+ uniquename += "#SENS#";
+ uniqueint++;
+ CIntValue* uniqueval = new CIntValue(uniqueint);
+ uniquename += uniqueval->GetText();
+ uniqueval->Release();
+
+ /* Conversion succeeded, so we can set the generic props here. */
+ gamesensor->SetPulseMode(pos_pulsemode,
+ neg_pulsemode,
+ skipped_ticks);
+ gamesensor->SetInvert(invert);
+ gamesensor->SetLevel(level);
+ gamesensor->SetTap(tap);
+ gamesensor->SetName(sens->name);
+
+ gameobj->AddSensor(gamesensor);
+
+ // only register to manager if it's in an active layer
+ // Make registration dynamic: only when sensor is activated
+ //if (isInActiveLayer)
+ // gamesensor->RegisterToManager();
+
+ gamesensor->ReserveController(sens->totlinks);
+ for (int i=0;i<sens->totlinks;i++)
+ {
+ bController* linkedcont = (bController*) sens->links[i];
+ if (linkedcont) {
+ // If the controller is deactived doesn't register it
+ if (!(linkedcont->flag & CONT_DEACTIVATE)) {
+ SCA_IController* gamecont = converter->FindGameController(linkedcont);
+
+ if (gamecont) {
+ logicmgr->RegisterToSensor(gamecont,gamesensor);
+ }
+ else {
+ printf("Warning, sensor \"%s\" could not find its controller "
+ "(link %d of %d) from object \"%s\"\n"
+ "\tthere has been an error converting the blender controller for the game engine,"
+ "logic may be incorrect\n", sens->name, i+1, sens->totlinks, blenderobject->id.name+2);
+ }
}
}
+ else {
+ printf("Warning, sensor \"%s\" has lost a link to a controller "
+ "(link %d of %d) from object \"%s\"\n"
+ "\tpossible causes are partially appended objects or an error reading the file,"
+ "logic may be incorrect\n", sens->name, i+1, sens->totlinks, blenderobject->id.name+2);
+ }
}
- else {
- printf("Warning, sensor \"%s\" has lost a link to a controller "
- "(link %d of %d) from object \"%s\"\n"
- "\tpossible causes are partially appended objects or an error reading the file,"
- "logic may be incorrect\n", sens->name, i+1, sens->totlinks, blenderobject->id.name+2);
+ // special case: Keyboard sensor with no link
+ // this combination is usually used for key logging.
+ if (sens->type == SENS_KEYBOARD && sens->totlinks == 0) {
+ // Force the registration so that the sensor runs
+ gamesensor->IncLink();
}
+
+ // done with gamesensor
+ gamesensor->Release();
+
}
- // special case: Keyboard sensor with no link
- // this combination is usually used for key logging.
- if (sens->type == SENS_KEYBOARD && sens->totlinks == 0) {
- // Force the registration so that the sensor runs
- gamesensor->IncLink();
- }
-
- // done with gamesensor
- gamesensor->Release();
-
}
- else if (gamesensor)
- gamesensor->Release();
sens=sens->next;
}
diff --git a/source/gameengine/Expressions/CMakeLists.txt b/source/gameengine/Expressions/CMakeLists.txt
index 6907f314503..48c10d75a17 100644
--- a/source/gameengine/Expressions/CMakeLists.txt
+++ b/source/gameengine/Expressions/CMakeLists.txt
@@ -55,6 +55,7 @@ set(SRC
StringValue.cpp
Value.cpp
VectorValue.cpp
+ KX_PythonCallBack.cpp
BoolValue.h
ConstExpr.h
@@ -77,6 +78,7 @@ set(SRC
Value.h
VectorValue.h
VoidValue.h
+ KX_PythonCallBack.h
)
blender_add_lib(ge_logic_expressions "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/gameengine/Expressions/KX_PythonCallBack.cpp b/source/gameengine/Expressions/KX_PythonCallBack.cpp
new file mode 100644
index 00000000000..fbc250a1b3d
--- /dev/null
+++ b/source/gameengine/Expressions/KX_PythonCallBack.cpp
@@ -0,0 +1,119 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Porteries Tristan.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file gameengine/Expressions/KX_PythonCallBack.cpp
+ * \ingroup expressions
+ */
+
+#include "KX_PythonCallBack.h"
+#include <iostream>
+#include <stdarg.h>
+
+#include "BLI_alloca.h"
+
+/** Check if a python value is a function and have the correct number of arguments.
+ * \param value The python value to check.
+ * \param minargcount The minimum of arguments possible.
+ * \param maxargcount The maximum of arguments possible.
+ * \param r_argcount The number of argument of this function, this variable will be
+ * changed in the function.
+ */
+static PyObject *CheckPythonFunction(PyObject *value, unsigned int minargcount, unsigned int maxargcount, unsigned int &r_argcount)
+{
+ if (PyMethod_Check(value)) {
+ PyCodeObject *code = ((PyCodeObject *)PyFunction_GET_CODE(PyMethod_GET_FUNCTION(value)));
+ // *args support
+ r_argcount = (code->co_flags & CO_VARARGS) ? maxargcount : (code->co_argcount - 1);
+ }
+ else if (PyFunction_Check(value)) {
+ PyCodeObject *code = ((PyCodeObject *)PyFunction_GET_CODE(value));
+ // *args support
+ r_argcount = (code->co_flags & CO_VARARGS) ? maxargcount : code->co_argcount;
+ }
+ else { // is not a methode or a function
+ PyErr_Format(PyExc_TypeError, "items must be functions or methodes, not %s",
+ Py_TYPE(value)->tp_name);
+ return NULL;
+ }
+
+ if (r_argcount < minargcount || r_argcount > maxargcount) {
+ // wrong number of arguments
+ PyErr_Format(PyExc_TypeError, "methode or function (%s) has invalid number of arguments (%i) must be between %i and %i",
+ Py_TYPE(value)->tp_name, r_argcount, minargcount, maxargcount);
+ return NULL;
+ }
+
+ return value;
+}
+
+/** Create a python tuple to call a python function
+ * \param argcount The lenght of the tuple.
+ * \param arglist The fully list of python arguments [size >= argcount].
+ */
+static PyObject *CreatePythonTuple(unsigned int argcount, PyObject **arglist)
+{
+ PyObject *tuple = PyTuple_New(argcount);
+
+ for (unsigned int i = 0; i < argcount; ++i) {
+ PyObject *item = arglist[i];
+ // increment reference and copy it in a new tuple
+ Py_INCREF(item);
+ PyTuple_SET_ITEM(tuple, i, item);
+ }
+
+ return tuple;
+}
+
+void RunPythonCallBackList(PyObject *functionlist, PyObject **arglist, unsigned int minargcount, unsigned int maxargcount)
+{
+ unsigned int size = PyList_Size(functionlist);
+ PyObject **argTuples = (PyObject **)BLI_array_alloca(argTuples, maxargcount - minargcount + 1);
+ memset(argTuples, 0, sizeof(PyObject *) * (maxargcount - minargcount + 1));
+
+ for (unsigned int i = 0; i < size; ++i) {
+ unsigned int funcargcount = 0;
+
+ PyObject *item = PyList_GET_ITEM(functionlist, i);
+ PyObject *func = CheckPythonFunction(item, minargcount, maxargcount, funcargcount);
+ if (!func) { // this item fails the check
+ PyErr_Print();
+ PyErr_Clear();
+ continue;
+ }
+
+ // get correct argument tuple.
+ PyObject *tuple = argTuples[funcargcount - minargcount];
+ if (!tuple)
+ argTuples[funcargcount - minargcount] = tuple = CreatePythonTuple(funcargcount, arglist);
+
+ PyObject *ret = PyObject_Call(func, tuple, NULL);
+ if (!ret) { // if ret is NULL this seems that the function doesn't work !
+ PyErr_Print();
+ PyErr_Clear();
+ }
+ else
+ Py_DECREF(ret);
+ }
+
+ for (unsigned int i = 0; i <= (maxargcount - minargcount); ++i)
+ Py_XDECREF(argTuples[i]);
+}
diff --git a/source/gameengine/Expressions/KX_PythonCallBack.h b/source/gameengine/Expressions/KX_PythonCallBack.h
new file mode 100644
index 00000000000..2ff6e305d67
--- /dev/null
+++ b/source/gameengine/Expressions/KX_PythonCallBack.h
@@ -0,0 +1,40 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Porteries Tristan.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file KX_PythonCallBack.h
+ * \ingroup expressions
+ */
+
+#ifndef __KX_PYTHON_CALLBACK_H__
+#define __KX_PYTHON_CALLBACK_H__
+
+#include "KX_Python.h"
+
+/** Execute each functions with at least one argument
+ * \param functionlist The python list which contains callbacks.
+ * \param arglist The first item in the tuple to execute callbacks (can be NULL for no arguments).
+ * \param minargcount The minimum of quantity of arguments possible.
+ * \param maxargcount The maximum of quantity of arguments possible.
+ */
+void RunPythonCallBackList(PyObject *functionlist, PyObject **arglist, unsigned int minargcount, unsigned int maxargcount);
+
+#endif // __KX_PYTHON_CALLBACK_H__
diff --git a/source/gameengine/Expressions/PyObjectPlus.cpp b/source/gameengine/Expressions/PyObjectPlus.cpp
index a65d61bc98b..31a17bd0cbf 100644
--- a/source/gameengine/Expressions/PyObjectPlus.cpp
+++ b/source/gameengine/Expressions/PyObjectPlus.cpp
@@ -148,12 +148,18 @@ PyObject *PyObjectPlus::py_base_repr(PyObject *self) // This should be the ent
PyObject *PyObjectPlus::py_base_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyTypeObject *base_type;
- PyObjectPlus_Proxy *base = NULL;
- if (!PyArg_ParseTuple(args, "O:Base PyObjectPlus", &base))
+ /* one or more args is needed */
+ if (!PyTuple_GET_SIZE(args)) {
+ PyErr_SetString(PyExc_TypeError,
+ "Expected at least one argument");
return NULL;
+ }
+
+ PyObjectPlus_Proxy *base = (PyObjectPlus_Proxy *)PyTuple_GET_ITEM(args, 0);
- /* the 'base' PyObject may be subclassed (multiple times even)
+ /**
+ * the 'base' PyObject may be subclassed (multiple times even)
* we need to find the first C++ defined class to check 'type'
* is a subclass of the base arguments type.
*
@@ -162,12 +168,13 @@ PyObject *PyObjectPlus::py_base_new(PyTypeObject *type, PyObject *args, PyObject
* eg.
*
* # CustomOb is called 'type' in this C code
+ * \code{.py}
* class CustomOb(GameTypes.KX_GameObject):
* pass
*
* # this calls py_base_new(...), the type of 'CustomOb' is checked to be a subclass of the 'cont.owner' type
* ob = CustomOb(cont.owner)
- *
+ * \endcode
* */
base_type= Py_TYPE(base);
while (base_type && !BGE_PROXY_CHECK_TYPE(base_type))
diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h
index 34b814d7416..c3ce98ed27a 100644
--- a/source/gameengine/Expressions/PyObjectPlus.h
+++ b/source/gameengine/Expressions/PyObjectPlus.h
@@ -111,6 +111,8 @@ typedef struct PyObjectPlus_Proxy {
/* Opposite of BGE_PROXY_REF */
#define BGE_PROXY_FROM_REF(_self) (((PyObjectPlus *)_self)->GetProxy())
+/* Same as 'BGE_PROXY_REF' but doesn't incref. */
+#define BGE_PROXY_FROM_REF_BORROW(_self) _bge_proxy_from_ref_borrow((void *)_self)
// This must be the first line of each
@@ -631,6 +633,17 @@ public:
#ifdef WITH_PYTHON
PyObject *PyUnicode_From_STR_String(const STR_String& str);
+
+inline PyObject *_bge_proxy_from_ref_borrow(void *self_v)
+{
+ PyObject *self_proxy = BGE_PROXY_FROM_REF(self_v);
+ /* this is typically _very_ bad practice,
+ * however we know the proxy is owned by 'self_v' */
+ self_proxy->ob_refcnt--;
+ return self_proxy;
+}
+
#endif
+
#endif /* __PYOBJECTPLUS_H__ */
diff --git a/source/gameengine/GameLogic/SCA_IObject.h b/source/gameengine/GameLogic/SCA_IObject.h
index 3ffe128c3b3..21e2c1cbcfc 100644
--- a/source/gameengine/GameLogic/SCA_IObject.h
+++ b/source/gameengine/GameLogic/SCA_IObject.h
@@ -221,6 +221,7 @@ public:
OBJ_ARMATURE=0,
OBJ_CAMERA=1,
OBJ_LIGHT=2,
+ OBJ_TEXT=3
} ObjectTypes;
};
diff --git a/source/gameengine/GameLogic/SCA_ISensor.cpp b/source/gameengine/GameLogic/SCA_ISensor.cpp
index 1cb17af8325..66dd69f93c4 100644
--- a/source/gameengine/GameLogic/SCA_ISensor.cpp
+++ b/source/gameengine/GameLogic/SCA_ISensor.cpp
@@ -67,7 +67,7 @@ SCA_ISensor::SCA_ISensor(SCA_IObject* gameobj,
m_neg_ticks = 0;
m_pos_pulsemode = false;
m_neg_pulsemode = false;
- m_pulse_frequency = 0;
+ m_skipped_ticks = 0;
m_state = false;
m_prev_state = false;
@@ -102,11 +102,11 @@ bool SCA_ISensor::IsPositiveTrigger()
void SCA_ISensor::SetPulseMode(bool posmode,
bool negmode,
- int freq)
+ int skippedticks)
{
m_pos_pulsemode = posmode;
m_neg_pulsemode = negmode;
- m_pulse_frequency = freq;
+ m_skipped_ticks = skippedticks;
}
void SCA_ISensor::SetInvert(bool inv)
@@ -263,7 +263,7 @@ void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr)
* not set :( */
if (m_pos_pulsemode) {
m_pos_ticks++;
- if (m_pos_ticks > m_pulse_frequency) {
+ if (m_pos_ticks > m_skipped_ticks) {
if ( m_state )
{
ActivateControllers(logicmgr);
@@ -276,7 +276,7 @@ void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr)
if (m_neg_pulsemode && !m_tap)
{
m_neg_ticks++;
- if (m_neg_ticks > m_pulse_frequency) {
+ if (m_neg_ticks > m_skipped_ticks) {
if (!m_state )
{
ActivateControllers(logicmgr);
@@ -367,7 +367,7 @@ PyMethodDef SCA_ISensor::Methods[] = {
PyAttributeDef SCA_ISensor::Attributes[] = {
KX_PYATTRIBUTE_BOOL_RW("usePosPulseMode",SCA_ISensor,m_pos_pulsemode),
KX_PYATTRIBUTE_BOOL_RW("useNegPulseMode",SCA_ISensor,m_neg_pulsemode),
- KX_PYATTRIBUTE_INT_RW("frequency",0,100000,true,SCA_ISensor,m_pulse_frequency),
+ KX_PYATTRIBUTE_INT_RW("skippedTicks",0,100000,true,SCA_ISensor,m_skipped_ticks),
KX_PYATTRIBUTE_BOOL_RW("invert",SCA_ISensor,m_invert),
KX_PYATTRIBUTE_BOOL_RW_CHECK("level",SCA_ISensor,m_level,pyattr_check_level),
KX_PYATTRIBUTE_BOOL_RW_CHECK("tap",SCA_ISensor,m_tap,pyattr_check_tap),
@@ -376,6 +376,7 @@ PyAttributeDef SCA_ISensor::Attributes[] = {
KX_PYATTRIBUTE_RO_FUNCTION("status", SCA_ISensor, pyattr_get_status),
KX_PYATTRIBUTE_RO_FUNCTION("pos_ticks", SCA_ISensor, pyattr_get_posTicks),
KX_PYATTRIBUTE_RO_FUNCTION("neg_ticks", SCA_ISensor, pyattr_get_negTicks),
+ KX_PYATTRIBUTE_RW_FUNCTION("frequency", SCA_ISensor, pyattr_get_frequency, pyattr_set_frequency),
{ NULL } //Sentinel
};
@@ -444,6 +445,27 @@ int SCA_ISensor::pyattr_check_tap(void *self_v, const KX_PYATTRIBUTE_DEF *attrde
self->m_level = false;
return 0;
}
+
+PyObject *SCA_ISensor::pyattr_get_frequency(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ SCA_ISensor *self = static_cast<SCA_ISensor*>(self_v);
+ ShowDeprecationWarning("SCA_ISensor.frequency", "SCA_ISensor.skippedTicks");
+ return PyLong_FromLong(self->m_skipped_ticks);
+}
+
+int SCA_ISensor::pyattr_set_frequency(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ SCA_ISensor *self = static_cast<SCA_ISensor*>(self_v);
+ ShowDeprecationWarning("SCA_ISensor.frequency", "SCA_ISensor.skippedTicks");
+ if (PyLong_Check(value)) {
+ self->m_skipped_ticks = PyLong_AsLong(value);
+ return PY_SET_ATTR_SUCCESS;
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "sensor.frequency = int: Sensor, expected an integer");
+ return PY_SET_ATTR_FAIL;
+ }
+}
#endif // WITH_PYTHON
/* eof */
diff --git a/source/gameengine/GameLogic/SCA_ISensor.h b/source/gameengine/GameLogic/SCA_ISensor.h
index 7bbba7aaafe..1e82f3ab11f 100644
--- a/source/gameengine/GameLogic/SCA_ISensor.h
+++ b/source/gameengine/GameLogic/SCA_ISensor.h
@@ -57,8 +57,8 @@ protected:
/** Pulse negative pulses? */
bool m_neg_pulsemode;
- /** Repeat frequency in pulse mode. */
- int m_pulse_frequency;
+ /** Number of skipped ticks between two active pulses. */
+ int m_skipped_ticks;
/** Number of ticks since the last positive pulse. */
int m_pos_ticks;
@@ -125,7 +125,7 @@ public:
*/
void SetPulseMode(bool posmode,
bool negmode,
- int freq);
+ int skippedticks);
/** Set inversion of pulses on or off. */
void SetInvert(bool inv);
@@ -201,6 +201,8 @@ public:
static PyObject* pyattr_get_status(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_posTicks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_negTicks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static PyObject* pyattr_get_frequency(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static int pyattr_set_frequency(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
static int pyattr_check_level(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_check_tap(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
index 6f34f8710c1..6841d2a8ea1 100644
--- a/source/gameengine/GameLogic/SCA_PropertySensor.cpp
+++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
@@ -265,13 +265,8 @@ bool SCA_PropertySensor::CheckPropertyCondition()
//the concept of Edge and Level triggering has unwanted effect for KX_PROPSENSOR_CHANGED
//see Game Engine bugtracker [ #3809 ]
- if (m_checktype != KX_PROPSENSOR_CHANGED)
- {
- m_recentresult=result;
- } else
- {
- m_recentresult=result;//true;
- }
+ m_recentresult = result;
+
return result;
}
diff --git a/source/gameengine/GameLogic/SCA_RandomSensor.cpp b/source/gameengine/GameLogic/SCA_RandomSensor.cpp
index 4e93556453a..2fe4d18a7fc 100644
--- a/source/gameengine/GameLogic/SCA_RandomSensor.cpp
+++ b/source/gameengine/GameLogic/SCA_RandomSensor.cpp
@@ -107,7 +107,7 @@ bool SCA_RandomSensor::Evaluate()
bool evaluateResult = false;
- if (++m_interval > m_pulse_frequency) {
+ if (++m_interval > m_skipped_ticks) {
bool drawResult = false;
m_interval = 0;
if (m_iteration > 31) {
diff --git a/source/gameengine/GamePlayer/common/GPC_Canvas.h b/source/gameengine/GamePlayer/common/GPC_Canvas.h
index acbea477e38..34cc9759a08 100644
--- a/source/gameengine/GamePlayer/common/GPC_Canvas.h
+++ b/source/gameengine/GamePlayer/common/GPC_Canvas.h
@@ -71,6 +71,8 @@ public:
virtual void ResizeWindow(int width, int height) {}
+ virtual void GetDisplayDimensions(int &width, int &height) {}
+
/**
* \section Methods inherited from abstract base class RAS_ICanvas.
*/
diff --git a/source/gameengine/GamePlayer/ghost/CMakeLists.txt b/source/gameengine/GamePlayer/ghost/CMakeLists.txt
index a1bc7e88840..dfa115e085c 100644
--- a/source/gameengine/GamePlayer/ghost/CMakeLists.txt
+++ b/source/gameengine/GamePlayer/ghost/CMakeLists.txt
@@ -46,6 +46,7 @@ set(INC
../../../blender/imbuf
../../../blender/makesdna
../../../blender/makesrna
+ ../../../blender/pointcache
../../../../intern/container
../../../../intern/ghost
../../../../intern/glew-mx
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
index 6b69a991968..b8ce67743de 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
@@ -636,7 +636,7 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
if (!m_networkdevice)
goto initFailed;
- sound_init(m_maggie);
+ BKE_sound_init(m_maggie);
// create a ketsjisystem (only needed for timing and stuff)
m_kxsystem = new GPG_System (m_system);
@@ -672,7 +672,7 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
return m_engineInitialized;
initFailed:
- sound_exit();
+ BKE_sound_exit();
delete m_kxsystem;
delete m_networkdevice;
delete m_mouse;
@@ -847,7 +847,7 @@ void GPG_Application::exitEngine()
if (!m_engineInitialized)
return;
- sound_exit();
+ BKE_sound_exit();
if (m_ketsjiengine)
{
stopEngine();
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp b/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp
index 556f85804ea..09eb1691dae 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp
@@ -121,6 +121,18 @@ bool GPG_Canvas::GetSwapInterval(int& intervalOut)
return false;
}
+void GPG_Canvas::GetDisplayDimensions(int &width, int &height)
+ {
+ unsigned int uiwidth;
+ unsigned int uiheight;
+
+ GHOST_ISystem *system = GHOST_ISystem::getSystem();
+ system->getMainDisplayDimensions(uiwidth, uiheight);
+
+ width = uiwidth;
+ height = uiheight;
+}
+
void GPG_Canvas::ResizeWindow(int width, int height)
{
if (m_window->getState() == GHOST_kWindowStateFullScreen)
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Canvas.h b/source/gameengine/GamePlayer/ghost/GPG_Canvas.h
index 337c2cedf55..18afbf6cd9e 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_Canvas.h
+++ b/source/gameengine/GamePlayer/ghost/GPG_Canvas.h
@@ -63,6 +63,8 @@ public:
virtual float GetMouseNormalizedX(int x);
virtual float GetMouseNormalizedY(int y);
+ virtual void GetDisplayDimensions(int &width, int &height);
+
virtual void ResizeWindow(int width, int height);
virtual void SetFullScreen(bool enable);
virtual bool GetFullScreen();
diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
index 915fe614957..6d97447dff0 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
@@ -74,11 +74,14 @@ extern "C"
#include "BKE_report.h"
#include "BKE_library.h"
#include "BKE_modifier.h"
+#include "BKE_material.h"
#include "BKE_text.h"
#include "BKE_sound.h"
#include "IMB_imbuf.h"
#include "IMB_moviecache.h"
+
+#include "PTC_api.h"
#ifdef __APPLE__
int GHOST_HACK_getFirstFile(char buf[]);
@@ -451,6 +454,7 @@ int main(int argc, char** argv)
RNA_init();
init_nodesystem();
+ PTC_alembic_init();
initglobals();
@@ -517,9 +521,12 @@ int main(int argc, char** argv)
// enable fast mipmap generation
U.use_gpu_mipmap = 1;
- sound_init_once();
+ BKE_sound_init_once();
+
+ // Initialize a default material for meshes without materials.
+ init_def_material();
- set_free_windowmanager_cb(wm_free);
+ BKE_library_callback_free_window_manager_set(wm_free);
/* if running blenderplayer the last argument can't be parsed since it has to be the filename. else it is bundled */
isBlenderPlayer = !BLO_is_a_runtime(argv[0]);
diff --git a/source/gameengine/GamePlayer/ghost/SConscript b/source/gameengine/GamePlayer/ghost/SConscript
index 610abcd0357..27adc000413 100644
--- a/source/gameengine/GamePlayer/ghost/SConscript
+++ b/source/gameengine/GamePlayer/ghost/SConscript
@@ -57,6 +57,7 @@ incs = [
'#source/blender/include',
'#source/blender/makesdna',
'#source/blender/makesrna',
+ '#source/blender/pointcache',
'#source/gameengine/Rasterizer',
'#source/gameengine/GameLogic',
'#source/gameengine/Expressions',
diff --git a/source/gameengine/Ketsji/BL_Action.cpp b/source/gameengine/Ketsji/BL_Action.cpp
index a50c07a486a..9bae119107e 100644
--- a/source/gameengine/Ketsji/BL_Action.cpp
+++ b/source/gameengine/Ketsji/BL_Action.cpp
@@ -49,6 +49,7 @@ extern "C" {
// Needed for material IPOs
#include "BKE_material.h"
#include "DNA_material_types.h"
+#include "DNA_scene_types.h"
}
#include "MEM_guardedalloc.h"
@@ -162,6 +163,14 @@ bool BL_Action::Play(const char* name,
m_obj->GetSGNode()->AddSGController(sg_contr);
sg_contr->SetObject(m_obj->GetSGNode());
+ // World
+ sg_contr = BL_CreateWorldIPO(m_action, kxscene->GetBlenderScene()->world, kxscene->GetSceneConverter());
+ if (sg_contr) {
+ m_sg_contr_list.push_back(sg_contr);
+ m_obj->GetSGNode()->AddSGController(sg_contr);
+ sg_contr->SetObject(m_obj->GetSGNode());
+ }
+
// Try obcolor
sg_contr = BL_CreateObColorIPO(m_action, m_obj, kxscene->GetSceneConverter());
if (sg_contr) {
diff --git a/source/gameengine/Ketsji/BL_Texture.cpp b/source/gameengine/Ketsji/BL_Texture.cpp
index 58739e7ef81..e1a28961a68 100644
--- a/source/gameengine/Ketsji/BL_Texture.cpp
+++ b/source/gameengine/Ketsji/BL_Texture.cpp
@@ -203,9 +203,21 @@ void BL_Texture::InitGLTex(unsigned int *pix,int x,int y,bool mipmap)
glBindTexture(GL_TEXTURE_2D, mTexture );
if ( mipmap ) {
+ int i;
+ ImBuf *ibuf;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, x, y, GL_RGBA, GL_UNSIGNED_BYTE, pix );
+
+ ibuf = IMB_allocFromBuffer(pix, NULL, x, y);
+
+ IMB_makemipmap(ibuf, true);
+
+ for (i = 0; i < ibuf->miptot; i++) {
+ ImBuf *mip = IMB_getmipmap(ibuf, i);
+
+ glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect);
+ }
+ IMB_freeImBuf(ibuf);
}
else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -245,9 +257,17 @@ void BL_Texture::InitNonPow2Tex(unsigned int *pix,int x,int y,bool mipmap)
glBindTexture(GL_TEXTURE_2D, mTexture );
if ( mipmap ) {
+ int i;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, nx, ny, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect );
+
+ IMB_makemipmap(ibuf, true);
+
+ for (i = 0; i < ibuf->miptot; i++) {
+ ImBuf *mip = IMB_getmipmap(ibuf, i);
+
+ glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect);
+ }
}
else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
index 9f0b582045f..7ec2673bf1f 100644
--- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
+++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
@@ -94,6 +94,21 @@ void KX_BlenderMaterial::Initialize(
((data->ras_mode &TEX)),
game
);
+ Material *ma = data->material;
+
+ // Save material data to restore on exit
+ mSavedData.r = ma->r;
+ mSavedData.g = ma->g;
+ mSavedData.b = ma->b;
+ mSavedData.a = ma->alpha;
+ mSavedData.specr = ma->specr;
+ mSavedData.specg = ma->specg;
+ mSavedData.specb = ma->specb;
+ mSavedData.spec = ma->spec;
+ mSavedData.ref = ma->ref;
+ mSavedData.hardness = ma->har;
+ mSavedData.emit = ma->emit;
+
mMaterial = data;
mShader = 0;
mBlenderShader = 0;
@@ -124,6 +139,20 @@ void KX_BlenderMaterial::Initialize(
KX_BlenderMaterial::~KX_BlenderMaterial()
{
+ Material *ma = mMaterial->material;
+ // Restore Blender material data
+ ma->r = mSavedData.r;
+ ma->g = mSavedData.g;
+ ma->b = mSavedData.b;
+ ma->alpha = mSavedData.a;
+ ma->specr = mSavedData.specr;
+ ma->specg = mSavedData.specg;
+ ma->specb = mSavedData.specb;
+ ma->spec = mSavedData.spec;
+ ma->ref = mSavedData.ref;
+ ma->har = mSavedData.hardness;
+ ma->emit = mSavedData.emit;
+
// cleanup work
if (mConstructed)
// clean only if material was actually used
@@ -793,17 +822,19 @@ void KX_BlenderMaterial::UpdateIPO(
)
{
// only works one deep now
- mMaterial->speccolor[0] = (float)(specrgb)[0];
- mMaterial->speccolor[1] = (float)(specrgb)[1];
- mMaterial->speccolor[2] = (float)(specrgb)[2];
- mMaterial->matcolor[0] = (float)(rgba[0]);
- mMaterial->matcolor[1] = (float)(rgba[1]);
- mMaterial->matcolor[2] = (float)(rgba[2]);
- mMaterial->alpha = (float)(alpha);
- mMaterial->hard = (float)(hard);
- mMaterial->emit = (float)(emit);
- mMaterial->spec_f = (float)(spec);
- mMaterial->ref = (float)(ref);
+
+ // GLSL Multitexture Input
+ mMaterial->material->specr = mMaterial->speccolor[0] = (float)(specrgb)[0];
+ mMaterial->material->specg = mMaterial->speccolor[1] = (float)(specrgb)[1];
+ mMaterial->material->specb = mMaterial->speccolor[2] = (float)(specrgb)[2];
+ mMaterial->material->r = mMaterial->matcolor[0] = (float)(rgba[0]);
+ mMaterial->material->g = mMaterial->matcolor[1] = (float)(rgba[1]);
+ mMaterial->material->b = mMaterial->matcolor[2] = (float)(rgba[2]);
+ mMaterial->material->alpha = mMaterial->alpha = (float)(rgba[3]);
+ mMaterial->material->har = mMaterial->hard = (float)(hard);
+ mMaterial->material->emit = mMaterial->emit = (float)(emit);
+ mMaterial->material->spec = mMaterial->spec_f = (float)(spec);
+ mMaterial->material->ref = mMaterial->ref = (float)(ref);
}
void KX_BlenderMaterial::Replace_IScene(SCA_IScene *val)
diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.h b/source/gameengine/Ketsji/KX_BlenderMaterial.h
index b7c64215eaf..23921588d6a 100644
--- a/source/gameengine/Ketsji/KX_BlenderMaterial.h
+++ b/source/gameengine/Ketsji/KX_BlenderMaterial.h
@@ -134,6 +134,15 @@ private:
bool mConstructed; // if false, don't clean on exit
int mLightLayer;
+ struct {
+ float r, g, b, a;
+ float specr, specg, specb;
+ float spec;
+ float ref;
+ float hardness;
+ float emit;
+ } mSavedData;
+
void InitTextures();
void SetBlenderGLSLShader();
diff --git a/source/gameengine/Ketsji/KX_Camera.cpp b/source/gameengine/Ketsji/KX_Camera.cpp
index ce2fe5f5ad8..4456345e1d9 100644
--- a/source/gameengine/Ketsji/KX_Camera.cpp
+++ b/source/gameengine/Ketsji/KX_Camera.cpp
@@ -463,6 +463,7 @@ bool KX_Camera::GetFrustumCulling() const
void KX_Camera::EnableViewport(bool viewport)
{
+ InvalidateProjectionMatrix(false); // We need to reset projection matrix
m_camdata.m_viewport = viewport;
}
@@ -885,7 +886,7 @@ int KX_Camera::pyattr_set_projection_matrix(void *self_v, const KX_PYATTRIBUTE_D
PyObject *KX_Camera::pyattr_get_modelview_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_Camera* self = static_cast<KX_Camera*>(self_v);
- return PyObjectFrom(self->GetModelviewMatrix());
+ return PyObjectFrom(self->GetWorldToCamera());
}
PyObject *KX_Camera::pyattr_get_camera_to_world(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
@@ -994,7 +995,7 @@ KX_PYMETHODDEF_DOC_O(KX_Camera, getScreenPosition,
GLdouble modelmatrix[16];
GLdouble projmatrix[16];
- MT_Matrix4x4 m_modelmatrix = this->GetModelviewMatrix();
+ MT_Matrix4x4 m_modelmatrix = this->GetWorldToCamera();
MT_Matrix4x4 m_projmatrix = this->GetProjectionMatrix();
m_modelmatrix.getValue(modelmatrix);
@@ -1037,7 +1038,7 @@ KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, getScreenVect,
GLdouble modelmatrix[16];
GLdouble projmatrix[16];
- MT_Matrix4x4 m_modelmatrix = this->GetModelviewMatrix();
+ MT_Matrix4x4 m_modelmatrix = this->GetWorldToCamera();
MT_Matrix4x4 m_projmatrix = this->GetProjectionMatrix();
m_modelmatrix.getValue(modelmatrix);
diff --git a/source/gameengine/Ketsji/KX_Camera.h b/source/gameengine/Ketsji/KX_Camera.h
index 454c4a54ec1..eeb836c44b8 100644
--- a/source/gameengine/Ketsji/KX_Camera.h
+++ b/source/gameengine/Ketsji/KX_Camera.h
@@ -192,7 +192,7 @@ public:
void InvalidateProjectionMatrix(bool valid = false);
/** Gets the modelview matrix that is used by the rasterizer.
- * \warning If the Camera is a dynamic object then this method may return garbage. Use GetCameraToWorld() instead.
+ * \warning If the Camera is a dynamic object then this method may return garbage. Use GetWorldToCamera() instead.
*/
const MT_Matrix4x4& GetModelviewMatrix() const;
diff --git a/source/gameengine/Ketsji/KX_FontObject.cpp b/source/gameengine/Ketsji/KX_FontObject.cpp
index 9789a8294ee..f3b098f407a 100644
--- a/source/gameengine/Ketsji/KX_FontObject.cpp
+++ b/source/gameengine/Ketsji/KX_FontObject.cpp
@@ -118,7 +118,6 @@ CValue* KX_FontObject::GetReplica()
void KX_FontObject::ProcessReplica()
{
KX_GameObject::ProcessReplica();
- KX_GetActiveScene()->AddFont(this);
}
int GetFontId(VFont *vfont)
diff --git a/source/gameengine/Ketsji/KX_FontObject.h b/source/gameengine/Ketsji/KX_FontObject.h
index 209ab6ca69f..bf70eedfde6 100644
--- a/source/gameengine/Ketsji/KX_FontObject.h
+++ b/source/gameengine/Ketsji/KX_FontObject.h
@@ -54,6 +54,7 @@ public:
*/
virtual CValue* GetReplica();
virtual void ProcessReplica();
+ virtual int GetGameObjectType() { return OBJ_TEXT; }
protected:
std::vector<STR_String> m_text;
diff --git a/source/gameengine/Ketsji/KX_GameActuator.cpp b/source/gameengine/Ketsji/KX_GameActuator.cpp
index c6087ac676d..a23af680104 100644
--- a/source/gameengine/Ketsji/KX_GameActuator.cpp
+++ b/source/gameengine/Ketsji/KX_GameActuator.cpp
@@ -178,6 +178,11 @@ bool KX_GameActuator::Update()
// obtain file size:
fseek (fp , 0 , SEEK_END);
marshal_length = ftell(fp);
+ if (marshal_length == -1) {
+ printf("warning: could not read position of '%s'\n", mashal_path);
+ fclose(fp);
+ break;
+ }
rewind(fp);
marshal_buffer = (char*) malloc (sizeof(char)*marshal_length);
diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp
index 8d22c9132fd..e77960b99b1 100644
--- a/source/gameengine/Ketsji/KX_GameObject.cpp
+++ b/source/gameengine/Ketsji/KX_GameObject.cpp
@@ -47,6 +47,7 @@
#include "KX_MeshProxy.h"
#include "KX_PolyProxy.h"
#include <stdio.h> // printf
+#include <climits> // USHRT_MAX
#include "SG_Controller.h"
#include "PHY_IGraphicController.h"
#include "SG_Node.h"
@@ -68,6 +69,7 @@
#include "BL_ActionManager.h"
#include "BL_Action.h"
+#include "KX_PythonCallBack.h"
#include "PyObjectPlus.h" /* python stuff */
#include "BLI_utildefines.h"
#include "python_utildefines.h"
@@ -91,9 +93,10 @@ KX_GameObject::KX_GameObject(
: SCA_IObject(),
m_bDyna(false),
m_layer(0),
+ m_currentLodLevel(0),
+ m_previousLodLevel(0),
m_pBlenderObject(NULL),
m_pBlenderGroupObject(NULL),
- m_bSuspendDynamics(false),
m_bUseObjectColor(false),
m_bIsNegativeScaling(false),
m_objectColor(1.0, 1.0, 1.0, 1.0),
@@ -291,6 +294,21 @@ void KX_GameObject::SetDupliGroupObject(KX_GameObject* obj)
m_pDupliGroupObject = obj;
}
+void KX_GameObject::AddConstraint(bRigidBodyJointConstraint *cons)
+{
+ m_constraints.push_back(cons);
+}
+
+std::vector<bRigidBodyJointConstraint*> KX_GameObject::GetConstraints()
+{
+ return m_constraints;
+}
+
+void KX_GameObject::ClearConstraints()
+{
+ m_constraints.clear();
+}
+
KX_GameObject* KX_GameObject::GetParent()
{
KX_GameObject* result = NULL;
@@ -545,13 +563,26 @@ void KX_GameObject::ActivateGraphicController(bool recurse)
}
}
-void KX_GameObject::SetUserCollisionGroup(short group)
+void KX_GameObject::SetUserCollisionGroup(unsigned short group)
{
m_userCollisionGroup = group;
+ if (m_pPhysicsController)
+ m_pPhysicsController->RefreshCollisions();
}
-void KX_GameObject::SetUserCollisionMask(short mask)
+void KX_GameObject::SetUserCollisionMask(unsigned short mask)
{
m_userCollisionMask = mask;
+ if (m_pPhysicsController)
+ m_pPhysicsController->RefreshCollisions();
+}
+
+unsigned short KX_GameObject::GetUserCollisionGroup()
+{
+ return m_userCollisionGroup;
+}
+unsigned short KX_GameObject::GetUserCollisionMask()
+{
+ return m_userCollisionMask;
}
bool KX_GameObject::CheckCollision(KX_GameObject* other)
@@ -569,6 +600,13 @@ CValue* KX_GameObject::GetReplica()
return replica;
}
+bool KX_GameObject::IsDynamicsSuspended() const
+{
+ if (m_pPhysicsController)
+ return m_pPhysicsController->IsSuspended();
+ return false;
+}
+
float KX_GameObject::getLinearDamping() const
{
if (m_pPhysicsController)
@@ -768,35 +806,74 @@ void KX_GameObject::AddLodMesh(RAS_MeshObject* mesh)
m_lodmeshes.push_back(mesh);
}
+
+static float calcHysteresis(KX_Scene *kxscene, LodLevel *lod)
+{
+ float hystvariance = 0.0f;
+
+ if (!kxscene->IsActivedLodHysteresis())
+ return hystvariance;
+
+ short hysteresis = 0;
+ // if exists, LoD level hysteresis will override scene hysteresis
+ if (lod->next->flags & OB_LOD_USE_HYST)
+ hysteresis = lod->next->obhysteresis;
+ else
+ hysteresis = kxscene->GetLodHysteresisValue();
+
+ return hystvariance = MT_abs(lod->next->distance - lod->distance) * hysteresis / 100;
+}
+
void KX_GameObject::UpdateLod(MT_Vector3 &cam_pos)
{
// Handle dupligroups
- if (this->m_pInstanceObjects) {
- KX_GameObject * instob;
- int count = this->m_pInstanceObjects->GetCount();
+ if (m_pInstanceObjects) {
+ KX_GameObject *instob;
+ int count = m_pInstanceObjects->GetCount();
for (int i = 0; i < count; i++) {
- instob = (KX_GameObject*)this->m_pInstanceObjects->GetValue(i);
+ instob = (KX_GameObject*)m_pInstanceObjects->GetValue(i);
instob->UpdateLod(cam_pos);
}
}
- if (this->m_lodmeshes.empty()) return;
+ if (m_lodmeshes.empty())
+ return;
- MT_Vector3 delta = this->NodeGetWorldPosition() - cam_pos;
+ MT_Vector3 delta = NodeGetWorldPosition() - cam_pos;
float distance2 = delta.length2();
int level = 0;
- Object *bob = this->GetBlenderObject();
- LodLevel *lod = (LodLevel*) bob->lodlevels.first;
+ float hystvariance = 0.0f;
+ Object *bob = GetBlenderObject();
+ LodLevel *lod = (LodLevel *)bob->lodlevels.first;
+ KX_Scene *kxscene = GetScene();
+
for (; lod; lod = lod->next, level++) {
- if (!lod->source || lod->source->type != OB_MESH) level--;
- if (!lod->next || lod->next->distance * lod->next->distance > distance2) break;
- }
+ if (!lod->source || lod->source->type != OB_MESH)
+ level--;
- RAS_MeshObject *mesh = this->m_lodmeshes[level];
+ if (!lod->next)
+ break;
- if (mesh != this->m_meshes[0]) {
- this->GetScene()->ReplaceMesh(this, mesh, true, false);
+ if (level == m_previousLodLevel || level == (m_previousLodLevel + 1)) {
+ hystvariance = calcHysteresis(kxscene, lod);
+ float newdistance = lod->next->distance + hystvariance;
+ if (newdistance * newdistance > distance2)
+ break;
+ }
+ else if (level == (m_previousLodLevel - 1)) {
+ hystvariance = calcHysteresis(kxscene, lod);
+ float newdistance = lod->next->distance - hystvariance;
+ if (newdistance * newdistance > distance2)
+ break;
+ }
+ }
+
+ RAS_MeshObject *mesh = m_lodmeshes[level];
+ m_currentLodLevel = level;
+ if (mesh != m_meshes[0]) {
+ m_previousLodLevel = level;
+ GetScene()->ReplaceMesh(this, mesh, true, false);
}
}
@@ -1494,70 +1571,17 @@ void KX_GameObject::RegisterCollisionCallbacks()
}
void KX_GameObject::RunCollisionCallbacks(KX_GameObject *collider, const MT_Vector3 &point, const MT_Vector3 &normal)
{
- #ifdef WITH_PYTHON
- Py_ssize_t len;
- PyObject* collision_callbacks = m_collisionCallbacks;
-
- if (collision_callbacks && (len=PyList_GET_SIZE(collision_callbacks)))
- {
- // Argument tuples are created lazily, only when they are needed.
- PyObject *args_3 = NULL;
- PyObject *args_1 = NULL; // Only for compatibility with pre-2.74 callbacks that take 1 argument.
-
- PyObject *func;
- PyObject *ret;
- int co_argcount;
-
- // Iterate the list and run the callbacks
- for (Py_ssize_t pos=0; pos < len; pos++)
- {
- func = PyList_GET_ITEM(collision_callbacks, pos);
-
- // Get the number of arguments, supporting functions, methods and generic callables.
- if (PyMethod_Check(func)) {
- // Take away the 'self' argument for methods.
- co_argcount = ((PyCodeObject *)PyFunction_GET_CODE(PyMethod_GET_FUNCTION(func)))->co_argcount - 1;
- } else if (PyFunction_Check(func)) {
- co_argcount = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_argcount;
- } else {
- // We'll just assume the callable takes the correct number of arguments.
- co_argcount = 3;
- }
+#ifdef WITH_PYTHON
+ if (!m_collisionCallbacks || PyList_GET_SIZE(m_collisionCallbacks) == 0)
+ return;
- // Check whether the function expects the colliding object only,
- // or also the point and normal.
- if (co_argcount <= 1) {
- // One argument, or *args (which gives co_argcount == 0)
- if (args_1 == NULL) {
- args_1 = PyTuple_New(1);
- PyTuple_SET_ITEMS(args_1, collider->GetProxy());
- }
- ret = PyObject_Call(func, args_1, NULL);
- } else {
- // More than one argument, assume we can give point & normal.
- if (args_3 == NULL) {
- args_3 = PyTuple_New(3);
- PyTuple_SET_ITEMS(args_3,
- collider->GetProxy(),
- PyObjectFrom(point),
- PyObjectFrom(normal));
- }
- ret = PyObject_Call(func, args_3, NULL);
- }
+ PyObject *args[] = {collider->GetProxy(), PyObjectFrom(point), PyObjectFrom(normal)};
+ RunPythonCallBackList(m_collisionCallbacks, args, 1, ARRAY_SIZE(args));
- if (ret == NULL) {
- PyErr_Print();
- PyErr_Clear();
- }
- else {
- Py_DECREF(ret);
- }
- }
-
- if (args_3) Py_DECREF(args_3);
- if (args_1) Py_DECREF(args_1);
+ for (unsigned int i = 0; i < ARRAY_SIZE(args); ++i) {
+ Py_DECREF(args[i]);
}
- #endif
+#endif
}
/* Suspend/ resume: for the dynamic behavior, there is a simple
@@ -1889,7 +1913,7 @@ PyMethodDef KX_GameObject::Methods[] = {
{"getReactionForce", (PyCFunction) KX_GameObject::sPyGetReactionForce, METH_NOARGS},
{"alignAxisToVect",(PyCFunction) KX_GameObject::sPyAlignAxisToVect, METH_VARARGS},
{"getAxisVect",(PyCFunction) KX_GameObject::sPyGetAxisVect, METH_O},
- {"suspendDynamics", (PyCFunction)KX_GameObject::sPySuspendDynamics,METH_NOARGS},
+ {"suspendDynamics", (PyCFunction)KX_GameObject::sPySuspendDynamics, METH_VARARGS},
{"restoreDynamics", (PyCFunction)KX_GameObject::sPyRestoreDynamics,METH_NOARGS},
{"enableRigidBody", (PyCFunction)KX_GameObject::sPyEnableRigidBody,METH_NOARGS},
{"disableRigidBody", (PyCFunction)KX_GameObject::sPyDisableRigidBody,METH_NOARGS},
@@ -1927,6 +1951,7 @@ PyMethodDef KX_GameObject::Methods[] = {
};
PyAttributeDef KX_GameObject::Attributes[] = {
+ KX_PYATTRIBUTE_INT_RO("currentLodLevel", KX_GameObject, m_currentLodLevel),
KX_PYATTRIBUTE_RO_FUNCTION("name", KX_GameObject, pyattr_get_name),
KX_PYATTRIBUTE_RO_FUNCTION("parent", KX_GameObject, pyattr_get_parent),
KX_PYATTRIBUTE_RO_FUNCTION("groupMembers", KX_GameObject, pyattr_get_group_members),
@@ -1934,6 +1959,7 @@ PyAttributeDef KX_GameObject::Attributes[] = {
KX_PYATTRIBUTE_RO_FUNCTION("scene", KX_GameObject, pyattr_get_scene),
KX_PYATTRIBUTE_RO_FUNCTION("life", KX_GameObject, pyattr_get_life),
KX_PYATTRIBUTE_RW_FUNCTION("mass", KX_GameObject, pyattr_get_mass, pyattr_set_mass),
+ KX_PYATTRIBUTE_RO_FUNCTION("isSuspendDynamics", KX_GameObject, pyattr_get_is_suspend_dynamics),
KX_PYATTRIBUTE_RW_FUNCTION("linVelocityMin", KX_GameObject, pyattr_get_lin_vel_min, pyattr_set_lin_vel_min),
KX_PYATTRIBUTE_RW_FUNCTION("linVelocityMax", KX_GameObject, pyattr_get_lin_vel_max, pyattr_set_lin_vel_max),
KX_PYATTRIBUTE_RW_FUNCTION("visible", KX_GameObject, pyattr_get_visible, pyattr_set_visible),
@@ -1945,6 +1971,8 @@ PyAttributeDef KX_GameObject::Attributes[] = {
KX_PYATTRIBUTE_RW_FUNCTION("scaling", KX_GameObject, pyattr_get_worldScaling, pyattr_set_localScaling),
KX_PYATTRIBUTE_RW_FUNCTION("timeOffset",KX_GameObject, pyattr_get_timeOffset,pyattr_set_timeOffset),
KX_PYATTRIBUTE_RW_FUNCTION("collisionCallbacks", KX_GameObject, pyattr_get_collisionCallbacks, pyattr_set_collisionCallbacks),
+ KX_PYATTRIBUTE_RW_FUNCTION("collisionGroup", KX_GameObject, pyattr_get_collisionGroup, pyattr_set_collisionGroup),
+ KX_PYATTRIBUTE_RW_FUNCTION("collisionMask", KX_GameObject, pyattr_get_collisionMask, pyattr_set_collisionMask),
KX_PYATTRIBUTE_RW_FUNCTION("state", KX_GameObject, pyattr_get_state, pyattr_set_state),
KX_PYATTRIBUTE_RO_FUNCTION("meshes", KX_GameObject, pyattr_get_meshes),
KX_PYATTRIBUTE_RW_FUNCTION("localOrientation",KX_GameObject,pyattr_get_localOrientation,pyattr_set_localOrientation),
@@ -2291,6 +2319,56 @@ int KX_GameObject::pyattr_set_collisionCallbacks(void *self_v, const KX_PYATTRIB
return PY_SET_ATTR_SUCCESS;
}
+PyObject *KX_GameObject::pyattr_get_collisionGroup(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
+ return PyLong_FromLong(self->GetUserCollisionGroup());
+}
+
+int KX_GameObject::pyattr_set_collisionGroup(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
+ int val = PyLong_AsLong(value);
+
+ if (val == -1 && PyErr_Occurred()) {
+ PyErr_SetString(PyExc_TypeError, "gameOb.collisionGroup = int: KX_GameObject, expected an int bit field");
+ return PY_SET_ATTR_FAIL;
+ }
+
+ if (val < 0 || val > USHRT_MAX) {
+ PyErr_Format(PyExc_AttributeError, "gameOb.collisionGroup = int: KX_GameObject, expected a int bit field between 0 and %i", USHRT_MAX);
+ return PY_SET_ATTR_FAIL;
+ }
+
+ self->SetUserCollisionGroup(val);
+ return PY_SET_ATTR_SUCCESS;
+}
+
+PyObject *KX_GameObject::pyattr_get_collisionMask(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
+ return PyLong_FromLong(self->GetUserCollisionMask());
+}
+
+int KX_GameObject::pyattr_set_collisionMask(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
+ int val = PyLong_AsLong(value);
+
+ if (val == -1 && PyErr_Occurred()) {
+ PyErr_SetString(PyExc_TypeError, "gameOb.collisionMask = int: KX_GameObject, expected an int bit field");
+ return PY_SET_ATTR_FAIL;
+ }
+
+ if (val < 0 || val > USHRT_MAX) {
+ PyErr_Format(PyExc_AttributeError, "gameOb.collisionMask = int: KX_GameObject, expected a int bit field between 0 and %i", USHRT_MAX);
+ return PY_SET_ATTR_FAIL;
+ }
+
+ self->SetUserCollisionMask(val);
+ return PY_SET_ATTR_SUCCESS;
+}
+
PyObject* KX_GameObject::pyattr_get_scene(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_GameObject *self = static_cast<KX_GameObject*>(self_v);
@@ -2347,6 +2425,19 @@ int KX_GameObject::pyattr_set_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrd
return PY_SET_ATTR_SUCCESS;
}
+PyObject *KX_GameObject::pyattr_get_is_suspend_dynamics(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
+
+ // Only objects with a physics controller can be suspended
+ if (!self->GetPhysicsController()) {
+ PyErr_SetString(PyExc_AttributeError, "This object has not Physics Controller");
+ return NULL;
+ }
+
+ return PyBool_FromLong(self->IsDynamicsSuspended());
+}
+
PyObject *KX_GameObject::pyattr_get_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
@@ -2439,7 +2530,9 @@ int KX_GameObject::pyattr_set_record_animation(void *self_v, const KX_PYATTRIBUT
PyObject *KX_GameObject::pyattr_get_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
#ifdef USE_MATHUTILS
- return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_GLOBAL);
+ return Vector_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v), 3,
+ mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_GLOBAL);
#else
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
return PyObjectFrom(self->NodeGetWorldPosition());
@@ -2461,7 +2554,9 @@ int KX_GameObject::pyattr_set_worldPosition(void *self_v, const KX_PYATTRIBUTE_D
PyObject *KX_GameObject::pyattr_get_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
#ifdef USE_MATHUTILS
- return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_LOCAL);
+ return Vector_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v), 3,
+ mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_LOCAL);
#else
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
return PyObjectFrom(self->NodeGetLocalPosition());
@@ -2483,7 +2578,9 @@ int KX_GameObject::pyattr_set_localPosition(void *self_v, const KX_PYATTRIBUTE_D
PyObject *KX_GameObject::pyattr_get_localInertia(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
#ifdef USE_MATHUTILS
- return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_INERTIA_LOCAL);
+ return Vector_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v), 3,
+ mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_INERTIA_LOCAL);
#else
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
if (self->GetPhysicsController1())
@@ -2495,7 +2592,9 @@ PyObject *KX_GameObject::pyattr_get_localInertia(void *self_v, const KX_PYATTRIB
PyObject *KX_GameObject::pyattr_get_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
#ifdef USE_MATHUTILS
- return Matrix_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, 3, mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_GLOBAL);
+ return Matrix_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v), 3, 3,
+ mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_GLOBAL);
#else
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
return PyObjectFrom(self->NodeGetWorldOrientation());
@@ -2520,7 +2619,9 @@ int KX_GameObject::pyattr_set_worldOrientation(void *self_v, const KX_PYATTRIBUT
PyObject *KX_GameObject::pyattr_get_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
#ifdef USE_MATHUTILS
- return Matrix_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, 3, mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_LOCAL);
+ return Matrix_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v), 3, 3,
+ mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_LOCAL);
#else
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
return PyObjectFrom(self->NodeGetLocalOrientation());
@@ -2544,7 +2645,9 @@ int KX_GameObject::pyattr_set_localOrientation(void *self_v, const KX_PYATTRIBUT
PyObject *KX_GameObject::pyattr_get_worldScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
#ifdef USE_MATHUTILS
- return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_GLOBAL);
+ return Vector_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v), 3,
+ mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_GLOBAL);
#else
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
return PyObjectFrom(self->NodeGetWorldScaling());
@@ -2566,7 +2669,9 @@ int KX_GameObject::pyattr_set_worldScaling(void *self_v, const KX_PYATTRIBUTE_DE
PyObject *KX_GameObject::pyattr_get_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
#ifdef USE_MATHUTILS
- return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_LOCAL);
+ return Vector_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v), 3,
+ mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_LOCAL);
#else
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
return PyObjectFrom(self->NodeGetLocalScaling());
@@ -2668,7 +2773,9 @@ int KX_GameObject::pyattr_set_worldTransform(void *self_v, const KX_PYATTRIBUTE_
PyObject *KX_GameObject::pyattr_get_worldLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
#ifdef USE_MATHUTILS
- return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_GLOBAL);
+ return Vector_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v), 3,
+ mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_GLOBAL);
#else
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
return PyObjectFrom(GetLinearVelocity(false));
@@ -2690,7 +2797,9 @@ int KX_GameObject::pyattr_set_worldLinearVelocity(void *self_v, const KX_PYATTRI
PyObject *KX_GameObject::pyattr_get_localLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
#ifdef USE_MATHUTILS
- return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_LOCAL);
+ return Vector_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v), 3,
+ mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_LOCAL);
#else
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
return PyObjectFrom(GetLinearVelocity(true));
@@ -2712,7 +2821,9 @@ int KX_GameObject::pyattr_set_localLinearVelocity(void *self_v, const KX_PYATTRI
PyObject *KX_GameObject::pyattr_get_worldAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
#ifdef USE_MATHUTILS
- return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_GLOBAL);
+ return Vector_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v), 3,
+ mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_GLOBAL);
#else
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
return PyObjectFrom(GetAngularVelocity(false));
@@ -2734,7 +2845,9 @@ int KX_GameObject::pyattr_set_worldAngularVelocity(void *self_v, const KX_PYATTR
PyObject *KX_GameObject::pyattr_get_localAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
#ifdef USE_MATHUTILS
- return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_LOCAL);
+ return Vector_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v), 3,
+ mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_LOCAL);
#else
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
return PyObjectFrom(GetAngularVelocity(true));
@@ -2855,7 +2968,9 @@ PyObject *KX_GameObject::pyattr_get_meshes(void *self_v, const KX_PYATTRIBUTE_DE
PyObject *KX_GameObject::pyattr_get_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
#ifdef USE_MATHUTILS
- return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 4, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_OBJECT_COLOR);
+ return Vector_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v), 4,
+ mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_OBJECT_COLOR);
#else
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
return PyObjectFrom(self->GetObjectColor());
@@ -3233,10 +3348,16 @@ PyObject *KX_GameObject::PyApplyImpulse(PyObject *args)
-PyObject *KX_GameObject::PySuspendDynamics()
+PyObject *KX_GameObject::PySuspendDynamics(PyObject *args)
{
+ bool ghost = false;
+
+ if (!PyArg_ParseTuple(args, "|b", &ghost))
+ return NULL;
+
if (GetPhysicsController())
- GetPhysicsController()->SuspendDynamics();
+ GetPhysicsController()->SuspendDynamics(ghost);
+
Py_RETURN_NONE;
}
diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h
index 5800cbc6834..9c081b449ec 100644
--- a/source/gameengine/Ketsji/KX_GameObject.h
+++ b/source/gameengine/Ketsji/KX_GameObject.h
@@ -49,6 +49,7 @@
#include "CTR_HashedPtr.h"
#include "KX_Scene.h"
#include "KX_KetsjiEngine.h" /* for m_anim_framerate */
+#include "DNA_constraint_types.h" /* for constraint replication */
#include "DNA_object_types.h"
#include "SCA_LogicManager.h" /* for ConvertPythonToGameObject to search object names */
@@ -88,18 +89,19 @@ protected:
int m_layer;
std::vector<RAS_MeshObject*> m_meshes;
std::vector<RAS_MeshObject*> m_lodmeshes;
+ int m_currentLodLevel;
+ short m_previousLodLevel;
SG_QList m_meshSlots; // head of mesh slots of this
struct Object* m_pBlenderObject;
struct Object* m_pBlenderGroupObject;
- bool m_bSuspendDynamics;
bool m_bUseObjectColor;
bool m_bIsNegativeScaling;
MT_Vector4 m_objectColor;
// Bit fields for user control over physics collisions
- short m_userCollisionGroup;
- short m_userCollisionMask;
+ unsigned short m_userCollisionGroup;
+ unsigned short m_userCollisionMask;
// visible = user setting
// culled = while rendering, depending on camera
@@ -116,6 +118,7 @@ protected:
SG_Node* m_pSGNode;
MT_CmMatrix4x4 m_OpenGL_4x4Matrix;
+ std::vector<bRigidBodyJointConstraint*> m_constraints;
KX_ObstacleSimulation* m_pObstacleSimulation;
@@ -192,6 +195,14 @@ public:
void
UpdateBlenderObjectMatrix(Object* blendobj=NULL);
+ /**
+ * Used for constraint replication for group instances.
+ * The list of constraints is filled during data conversion.
+ */
+ void AddConstraint(bRigidBodyJointConstraint *cons);
+ std::vector<bRigidBodyJointConstraint*> GetConstraints();
+ void ClearConstraints();
+
/**
* Get a pointer to the game object that is the parent of
* this object. Or NULL if there is no parent. The returned
@@ -506,8 +517,17 @@ public:
*/
void ActivateGraphicController(bool recurse);
- void SetUserCollisionGroup(short filter);
- void SetUserCollisionMask(short mask);
+ /** Set the object's collison group
+ * \param filter The group bitfield
+ */
+ void SetUserCollisionGroup(unsigned short filter);
+
+ /** Set the object's collison mask
+ * \param filter The mask bitfield
+ */
+ void SetUserCollisionMask(unsigned short mask);
+ unsigned short GetUserCollisionGroup();
+ unsigned short GetUserCollisionMask();
/**
* Extra broadphase check for user controllable collisions
*/
@@ -607,6 +627,8 @@ public:
return m_bDyna;
}
+ bool IsDynamicsSuspended() const;
+
/**
* Should we record animation for this object?
*/
@@ -892,7 +914,7 @@ public:
* Change the layer of the object (when it is added in another layer
* than the original layer)
*/
- void
+ virtual void
SetLayer(
int l
);
@@ -983,7 +1005,7 @@ public:
KX_PYMETHOD_O(KX_GameObject,SetState);
KX_PYMETHOD_VARARGS(KX_GameObject,AlignAxisToVect);
KX_PYMETHOD_O(KX_GameObject,GetAxisVect);
- KX_PYMETHOD_NOARGS(KX_GameObject,SuspendDynamics);
+ KX_PYMETHOD_VARARGS(KX_GameObject,SuspendDynamics);
KX_PYMETHOD_NOARGS(KX_GameObject,RestoreDynamics);
KX_PYMETHOD_NOARGS(KX_GameObject,EnableRigidBody);
KX_PYMETHOD_NOARGS(KX_GameObject,DisableRigidBody);
@@ -1027,6 +1049,7 @@ public:
static PyObject* pyattr_get_life(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+ static PyObject* pyattr_get_is_suspend_dynamics(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
static PyObject* pyattr_get_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
@@ -1073,6 +1096,10 @@ public:
static int pyattr_set_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
static PyObject* pyattr_get_collisionCallbacks(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_collisionCallbacks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+ static PyObject* pyattr_get_collisionGroup(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static int pyattr_set_collisionGroup(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+ static PyObject* pyattr_get_collisionMask(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static int pyattr_set_collisionMask(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
static PyObject* pyattr_get_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
static PyObject* pyattr_get_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
diff --git a/source/gameengine/Ketsji/KX_IpoConvert.cpp b/source/gameengine/Ketsji/KX_IpoConvert.cpp
index 57130bf57b2..7b00760ee7b 100644
--- a/source/gameengine/Ketsji/KX_IpoConvert.cpp
+++ b/source/gameengine/Ketsji/KX_IpoConvert.cpp
@@ -269,52 +269,80 @@ SG_Controller *BL_CreateCameraIPO(struct bAction *action, KX_GameObject* camera
return ipocontr;
}
-void BL_ConvertWorldIpos(struct World* blenderworld,KX_BlenderSceneConverter *converter)
-{
-
- if (blenderworld->adt) {
- KX_WorldIpoController* ipocontr = new KX_WorldIpoController();
-
-// Erwin, hook up the world ipo controller here
-// Gino: hook it up to what ?
-// is there a userinterface element for that ?
-// for now, we have some new python hooks to access the data, for a work-around
-
- ipocontr->m_mist_start = blenderworld->miststa;
- ipocontr->m_mist_dist = blenderworld->mistdist;
- ipocontr->m_mist_rgb[0] = blenderworld->horr;
- ipocontr->m_mist_rgb[1] = blenderworld->horg;
- ipocontr->m_mist_rgb[2] = blenderworld->horb;
+SG_Controller * BL_CreateWorldIPO( bAction *action, struct World *blenderworld, KX_BlenderSceneConverter *converter )
+{
+ KX_WorldIpoController *ipocontr = NULL;
- BL_InterpolatorList *adtList= GetAdtList(blenderworld->adt->action, converter);
+ if (blenderworld) {
+ BL_InterpolatorList *adtList = GetAdtList(action, converter);
- // For each active channel in the adtList add an
- // interpolator to the game object.
-
+ // For each active channel in the adtList add an interpolator to the game object.
KX_IInterpolator *interpolator;
KX_IScalarInterpolator *interp;
-
+
+ for (int i=0; i<3; i++) {
+ if ((interp = adtList->GetScalarInterpolator("ambient_color", i))) {
+ if (!ipocontr) {
+ ipocontr = new KX_WorldIpoController();
+ }
+ interpolator = new KX_ScalarInterpolator(&ipocontr->m_ambi_rgb[i], interp);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyAmbientColor(true);
+ }
+ }
+
for (int i=0; i<3; i++) {
if ((interp = adtList->GetScalarInterpolator("horizon_color", i))) {
- interpolator= new KX_ScalarInterpolator(&ipocontr->m_mist_rgb[i], interp);
+ if (!ipocontr) {
+ ipocontr = new KX_WorldIpoController();
+ }
+ interpolator = new KX_ScalarInterpolator(&ipocontr->m_hori_rgb[i], interp);
ipocontr->AddInterpolator(interpolator);
- ipocontr->SetModifyMistColor(true);
+ ipocontr->SetModifyHorizonColor(true);
}
}
- if ((interp = adtList->GetScalarInterpolator("mist.depth", 0))) {
- interpolator= new KX_ScalarInterpolator(&ipocontr->m_mist_dist, interp);
+ if ((interp = adtList->GetScalarInterpolator("mist_settings.start", 0))) {
+ if (!ipocontr) {
+ ipocontr = new KX_WorldIpoController();
+ }
+ interpolator = new KX_ScalarInterpolator(&ipocontr->m_mist_start, interp);
+ ipocontr->AddInterpolator(interpolator);
+ ipocontr->SetModifyMistStart(true);
+ }
+
+ if ((interp = adtList->GetScalarInterpolator("mist_settings.depth", 0))) {
+ if (!ipocontr) {
+ ipocontr = new KX_WorldIpoController();
+ }
+ interpolator = new KX_ScalarInterpolator(&ipocontr->m_mist_dist, interp);
ipocontr->AddInterpolator(interpolator);
ipocontr->SetModifyMistDist(true);
}
- if ((interp = adtList->GetScalarInterpolator("mist.start", 0))) {
- interpolator= new KX_ScalarInterpolator(&ipocontr->m_mist_start, interp);
+ if ((interp = adtList->GetScalarInterpolator("mist_settings.intensity", 0))) {
+ if (!ipocontr) {
+ ipocontr = new KX_WorldIpoController();
+ }
+ interpolator = new KX_ScalarInterpolator(&ipocontr->m_mist_intensity, interp);
ipocontr->AddInterpolator(interpolator);
- ipocontr->SetModifyMistStart(true);
+ ipocontr->SetModifyMistIntensity(true);
+ }
+
+ if (ipocontr) {
+ ipocontr->m_mist_start = blenderworld->miststa;
+ ipocontr->m_mist_dist = blenderworld->mistdist;
+ ipocontr->m_mist_intensity = blenderworld->misi;
+ ipocontr->m_hori_rgb[0] = blenderworld->horr;
+ ipocontr->m_hori_rgb[1] = blenderworld->horg;
+ ipocontr->m_hori_rgb[2] = blenderworld->horb;
+ ipocontr->m_ambi_rgb[0] = blenderworld->ambr;
+ ipocontr->m_ambi_rgb[1] = blenderworld->ambg;
+ ipocontr->m_ambi_rgb[2] = blenderworld->ambb;
}
}
+ return ipocontr;
}
SG_Controller *BL_CreateMaterialIpo(
@@ -368,7 +396,7 @@ SG_Controller *BL_CreateMaterialIpo(
ipocontr->AddInterpolator(interpolator);
}
- if ((sinterp = adtList->GetScalarInterpolator("specularity", 0))) {
+ if ((sinterp = adtList->GetScalarInterpolator("specular_intensity", 0))) {
if (!ipocontr) {
ipocontr = new KX_MaterialIpoController(matname_hash);
}
@@ -376,7 +404,7 @@ SG_Controller *BL_CreateMaterialIpo(
ipocontr->AddInterpolator(interpolator);
}
- if ((sinterp = adtList->GetScalarInterpolator("diffuse_reflection", 0))) {
+ if ((sinterp = adtList->GetScalarInterpolator("diffuse_intensity", 0))) {
if (!ipocontr) {
ipocontr = new KX_MaterialIpoController(matname_hash);
}
diff --git a/source/gameengine/Ketsji/KX_IpoConvert.h b/source/gameengine/Ketsji/KX_IpoConvert.h
index a653e4e110b..6db43552811 100644
--- a/source/gameengine/Ketsji/KX_IpoConvert.h
+++ b/source/gameengine/Ketsji/KX_IpoConvert.h
@@ -50,7 +50,8 @@ SG_Controller *BL_CreateLampIPO(bAction *action,
KX_GameObject* lightobj,
KX_BlenderSceneConverter *converter);
-void BL_ConvertWorldIpos(struct World* blenderworld,
+SG_Controller *BL_CreateWorldIPO(bAction *action,
+ struct World *blenderworld,
KX_BlenderSceneConverter *converter);
SG_Controller *BL_CreateCameraIPO(bAction *action,
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
index e453b757b7e..40af9b4ca39 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
@@ -312,10 +312,11 @@ void KX_KetsjiEngine::RenderDome()
// for each scene, call the proceed functions
{
scene = *sceneit;
+ KX_SetActiveScene(scene);
KX_Camera* cam = scene->GetActiveCamera();
// pass the scene's worldsettings to the rasterizer
- SetWorldSettings(scene->GetWorldInfo());
+ scene->GetWorldInfo()->UpdateWorldSettings();
// shadow buffers
if (i == 0) {
@@ -389,8 +390,10 @@ void KX_KetsjiEngine::RenderDome()
);
}
m_dome->Draw();
+
// Draw Callback for the last scene
#ifdef WITH_PYTHON
+ PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
scene->RunDrawingCallbacks(scene->GetPostDrawCB());
#endif
EndFrame();
@@ -475,7 +478,7 @@ void KX_KetsjiEngine::ClearFrame()
if (doclear) {
KX_Scene* firstscene = *m_scenes.begin();
- SetBackGround(firstscene->GetWorldInfo());
+ firstscene->GetWorldInfo()->UpdateBackGround();
m_canvas->SetViewPort(clearvp.GetLeft(), clearvp.GetBottom(),
clearvp.GetRight(), clearvp.GetTop());
@@ -825,7 +828,7 @@ void KX_KetsjiEngine::Render()
KX_Scene* scene = *sceneit;
KX_Camera* cam = scene->GetActiveCamera();
// pass the scene's worldsettings to the rasterizer
- SetWorldSettings(scene->GetWorldInfo());
+ scene->GetWorldInfo()->UpdateWorldSettings();
// this is now done incrementatlly in KX_Scene::CalculateVisibleMeshes
//scene->UpdateMeshTransformations();
@@ -882,7 +885,7 @@ void KX_KetsjiEngine::Render()
KX_Camera* cam = scene->GetActiveCamera();
// pass the scene's worldsettings to the rasterizer
- SetWorldSettings(scene->GetWorldInfo());
+ scene->GetWorldInfo()->UpdateWorldSettings();
if (scene->IsClearingZBuffer())
m_rasterizer->ClearDepthBuffer();
@@ -962,54 +965,6 @@ const STR_String& KX_KetsjiEngine::GetExitString()
return m_exitstring;
}
-
-void KX_KetsjiEngine::SetBackGround(KX_WorldInfo* wi)
-{
- if (wi->hasWorld())
- {
- if (m_rasterizer->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED)
- {
- m_rasterizer->SetBackColor(
- wi->getBackColorRed(),
- wi->getBackColorGreen(),
- wi->getBackColorBlue(),
- 0.0
- );
- }
- }
-}
-
-
-
-void KX_KetsjiEngine::SetWorldSettings(KX_WorldInfo* wi)
-{
- if (wi->hasWorld())
- {
- // ...
- m_rasterizer->SetAmbientColor(
- wi->getAmbientColorRed(),
- wi->getAmbientColorGreen(),
- wi->getAmbientColorBlue()
- );
-
- if (m_rasterizer->GetDrawingMode() >= RAS_IRasterizer::KX_SOLID)
- {
- if (wi->hasMist())
- {
- m_rasterizer->SetFog(
- wi->getMistStart(),
- wi->getMistDistance(),
- wi->getMistColorRed(),
- wi->getMistColorGreen(),
- wi->getMistColorBlue()
- );
- }
- }
- }
-}
-
-
-
void KX_KetsjiEngine::EnableCameraOverride(const STR_String& forscene)
{
m_overrideCam = true;
@@ -1150,6 +1105,13 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
if (!cam)
return;
+
+ KX_SetActiveScene(scene);
+
+#ifdef WITH_PYTHON
+ scene->RunDrawingCallbacks(scene->GetPreDrawSetupCB());
+#endif
+
GetSceneViewport(scene, cam, area, viewport);
// store the computed viewport in the scene
@@ -1262,6 +1224,7 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
SG_SetActiveStage(SG_STAGE_RENDER);
#ifdef WITH_PYTHON
+ PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
// Run any pre-drawing python callbacks
scene->RunDrawingCallbacks(scene->GetPreDrawCB());
#endif
@@ -1280,12 +1243,16 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
*/
void KX_KetsjiEngine::PostRenderScene(KX_Scene* scene)
{
+ KX_SetActiveScene(scene);
+
// We need to first make sure our viewport is correct (enabling multiple viewports can mess this up)
m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight());
m_rasterizer->FlushDebugShapes();
scene->Render2DFilters(m_canvas);
+
#ifdef WITH_PYTHON
+ PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
scene->RunDrawingCallbacks(scene->GetPostDrawCB());
#endif
}
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h
index e18b203b675..4392769ed02 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.h
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h
@@ -205,14 +205,12 @@ private:
void PostRenderScene(KX_Scene* scene);
void RenderDebugProperties();
void RenderShadowBuffers(KX_Scene *scene);
- void SetBackGround(KX_WorldInfo* worldinfo);
public:
KX_KetsjiEngine(class KX_ISystem* system);
virtual ~KX_KetsjiEngine();
// set the devices and stuff. the client must take care of creating these
- void SetWorldSettings(KX_WorldInfo* worldinfo);
void SetKeyboardDevice(SCA_IInputDevice* keyboarddevice);
void SetMouseDevice(SCA_IInputDevice* mousedevice);
void SetNetworkDevice(NG_NetworkDeviceInterface* networkdevice);
diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp
index 33cfec57fc0..0dec5715588 100644
--- a/source/gameengine/Ketsji/KX_Light.cpp
+++ b/source/gameengine/Ketsji/KX_Light.cpp
@@ -108,6 +108,7 @@ void KX_LightObject::UpdateScene(KX_Scene *kxscene)
void KX_LightObject::SetLayer(int layer)
{
+ KX_GameObject::SetLayer(layer);
m_lightobj->m_layer = layer;
}
@@ -166,27 +167,31 @@ PyAttributeDef KX_LightObject::Attributes[] = {
PyObject *KX_LightObject::pyattr_get_layer(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
- KX_LightObject* self = static_cast<KX_LightObject*>(self_v);
+ KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
return PyLong_FromLong(self->m_lightobj->m_layer);
}
int KX_LightObject::pyattr_set_layer(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
{
- KX_LightObject* self = static_cast<KX_LightObject*>(self_v);
+ KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+ int layer = PyLong_AsLong(value);
- if (PyLong_Check(value)) {
- int val = PyLong_AsLong(value);
- if (val < 1)
- val = 1;
- else if (val > 20)
- val = 20;
+ if (layer == -1 && PyErr_Occurred()) {
+ PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name);
+ return PY_SET_ATTR_FAIL;
+ }
- self->m_lightobj->m_layer = val;
- return PY_SET_ATTR_SUCCESS;
+ if (layer < 1) {
+ PyErr_Format(PyExc_TypeError, "expected an integer greater than 1 for attribute \"%s\"", attrdef->m_name);
+ return PY_SET_ATTR_FAIL;
+ }
+ else if(layer > MAX_LIGHT_LAYERS) {
+ PyErr_Format(PyExc_TypeError, "expected an integer less than %i for attribute \"%s\"", MAX_LIGHT_LAYERS, attrdef->m_name);
+ return PY_SET_ATTR_FAIL;
}
- PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name);
- return PY_SET_ATTR_FAIL;
+ self->SetLayer(layer);
+ return PY_SET_ATTR_SUCCESS;
}
PyObject *KX_LightObject::pyattr_get_energy(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
diff --git a/source/gameengine/Ketsji/KX_Light.h b/source/gameengine/Ketsji/KX_Light.h
index 503ed7411e9..3a58584223d 100644
--- a/source/gameengine/Ketsji/KX_Light.h
+++ b/source/gameengine/Ketsji/KX_Light.h
@@ -34,6 +34,8 @@
#include "KX_GameObject.h"
+#define MAX_LIGHT_LAYERS ((1 << 20) - 1)
+
struct GPULamp;
struct Scene;
struct Base;
@@ -58,7 +60,7 @@ public:
RAS_ILightObject* GetLightData() { return m_lightobj;}
void UpdateScene(class KX_Scene *kxscene);
- void SetLayer(int layer);
+ virtual void SetLayer(int layer);
virtual int GetGameObjectType() { return OBJ_LIGHT; }
diff --git a/source/gameengine/Ketsji/KX_MaterialIpoController.cpp b/source/gameengine/Ketsji/KX_MaterialIpoController.cpp
index a9617aa47b8..1faf8f17d54 100644
--- a/source/gameengine/Ketsji/KX_MaterialIpoController.cpp
+++ b/source/gameengine/Ketsji/KX_MaterialIpoController.cpp
@@ -32,21 +32,6 @@ bool KX_MaterialIpoController::Update(double currentTime)
{
if (m_modified)
{
- m_rgba[0]=0;
- m_rgba[1]=0;
- m_rgba[2]=0;
- m_rgba[3]=0;
-
- m_specrgb[0] =0;
- m_specrgb[1] =0;
- m_specrgb[2] =0;
- m_hard =0;
- m_spec=0;
- m_ref=0;
- m_emit=0;
- m_alpha = 0;
-
-
T_InterpolatorList::iterator i;
for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
(*i)->Execute(m_ipotime);
diff --git a/source/gameengine/Ketsji/KX_MouseActuator.cpp b/source/gameengine/Ketsji/KX_MouseActuator.cpp
index 62417b4df81..c372e6e9ce2 100644
--- a/source/gameengine/Ketsji/KX_MouseActuator.cpp
+++ b/source/gameengine/Ketsji/KX_MouseActuator.cpp
@@ -278,7 +278,10 @@ bool KX_MouseActuator::Update()
setposition[1] = center_y;
}
- setMousePosition(setposition[0], setposition[1]);
+ // only trigger mouse event when it is necessary
+ if (m_oldposition[0] != position[0] || m_oldposition[1] != position[1]) {
+ setMousePosition(setposition[0], setposition[1]);
+ }
m_oldposition[0] = position[0];
m_oldposition[1] = position[1];
diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.cpp b/source/gameengine/Ketsji/KX_ObjectActuator.cpp
index 0eec86987be..12abcb250a7 100644
--- a/source/gameengine/Ketsji/KX_ObjectActuator.cpp
+++ b/source/gameengine/Ketsji/KX_ObjectActuator.cpp
@@ -75,7 +75,8 @@ KX_ObjectActuator(
m_reference(refobj),
m_active_combined_velocity (false),
m_linear_damping_active(false),
- m_angular_damping_active(false)
+ m_angular_damping_active(false),
+ m_jumping(false)
{
if (m_bitLocalFlag.ServoControl)
{
@@ -140,6 +141,7 @@ bool KX_ObjectActuator::Update()
m_angular_damping_active = false;
m_error_accumulator.setValue(0.0,0.0,0.0);
m_previous_error.setValue(0.0,0.0,0.0);
+ m_jumping = false;
return false;
} else if (parent)
@@ -223,6 +225,11 @@ bool KX_ObjectActuator::Update()
else if (m_bitLocalFlag.CharacterMotion) {
MT_Vector3 dir = m_dloc;
+ if (m_bitLocalFlag.DLoc) {
+ MT_Matrix3x3 basis = parent->GetPhysicsController()->GetOrientation();
+ dir = basis * dir;
+ }
+
if (m_bitLocalFlag.AddOrSetCharLoc) {
MT_Vector3 old_dir = character->GetWalkDirection();
@@ -236,21 +243,20 @@ bool KX_ObjectActuator::Update()
}
// We always want to set the walk direction since a walk direction of (0, 0, 0) should stop the character
- if (m_bitLocalFlag.DLoc)
- {
- MT_Matrix3x3 basis = parent->GetPhysicsController()->GetOrientation();
- dir = basis*dir;
- }
character->SetWalkDirection(dir/parent->GetScene()->GetPhysicsEnvironment()->GetNumTimeSubSteps());
if (!m_bitLocalFlag.ZeroDRot)
{
parent->ApplyRotation(m_drot,(m_bitLocalFlag.DRot) != 0);
}
- if (m_bitLocalFlag.CharacterJump)
- {
- character->Jump();
+ if (m_bitLocalFlag.CharacterJump) {
+ if (!m_jumping) {
+ character->Jump();
+ m_jumping = true;
+ }
+ else if (character->OnGround())
+ m_jumping = false;
}
}
else {
@@ -516,7 +522,9 @@ static Mathutils_Callback mathutils_obactu_vector_cb = {
PyObject *KX_ObjectActuator::pyattr_get_linV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
- return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_LINV);
+ return Vector_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v), 3,
+ mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_LINV);
}
int KX_ObjectActuator::pyattr_set_linV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
@@ -532,7 +540,9 @@ int KX_ObjectActuator::pyattr_set_linV(void *self_v, const KX_PYATTRIBUTE_DEF *a
PyObject *KX_ObjectActuator::pyattr_get_angV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
- return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_ANGV);
+ return Vector_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v), 3,
+ mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_ANGV);
}
int KX_ObjectActuator::pyattr_set_angV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.h b/source/gameengine/Ketsji/KX_ObjectActuator.h
index 1f2453e3700..b5622d97611 100644
--- a/source/gameengine/Ketsji/KX_ObjectActuator.h
+++ b/source/gameengine/Ketsji/KX_ObjectActuator.h
@@ -116,7 +116,8 @@ class KX_ObjectActuator : public SCA_IActuator
bool m_active_combined_velocity;
bool m_linear_damping_active;
bool m_angular_damping_active;
-
+ bool m_jumping;
+
public:
enum KX_OBJECT_ACT_VEC_TYPE {
KX_OBJECT_ACT_NODEF = 0,
diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
index 94f5064261f..065251f5676 100644
--- a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
+++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
@@ -496,78 +496,46 @@ static PyObject *gPyCreateConstraint(PyObject *self,
{
/* FIXME - physicsid is a long being cast to a pointer, should at least use PyCapsule */
unsigned long long physicsid = 0, physicsid2 = 0;
- int constrainttype=0, extrainfo=0;
- int len = PyTuple_Size(args);
- int success = 1;
+ int constrainttype = 0;
int flag = 0;
+ float pivotX = 0.0f, pivotY = 0.0f, pivotZ = 0.0f, axisX = 0.0f, axisY = 0.0f, axisZ = 0.0f;
- float pivotX=1,pivotY=1,pivotZ=1,axisX=0,axisY=0,axisZ=1;
- if (len == 3)
- {
- success = PyArg_ParseTuple(args, "KKi", &physicsid, &physicsid2, &constrainttype);
- }
- else if (len == 6)
- {
- success = PyArg_ParseTuple(args, "KKifff", &physicsid, &physicsid2, &constrainttype,
- &pivotX, &pivotY, &pivotZ);
- }
- else if (len == 9)
- {
- success = PyArg_ParseTuple(args, "KKiffffff", &physicsid, &physicsid2, &constrainttype,
- &pivotX, &pivotY, &pivotZ, &axisX, &axisY, &axisZ);
- }
- else if (len == 10)
- {
- success = PyArg_ParseTuple(args, "KKiffffffi", &physicsid, &physicsid2, &constrainttype,
- &pivotX, &pivotY, &pivotZ, &axisX, &axisY, &axisZ, &flag);
- }
+ static const char *kwlist[] = {"physicsid_1", "physicsid_2", "constraint_type", "pivot_x", "pivot_y", "pivot_z",
+ "axis_X", "axis_y", "axis_z", "flag", NULL};
- /* XXX extrainfo seems to be nothing implemented. right now it works as a pivot with [X,0,0] */
- else if (len == 4)
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "KKi|ffffffi:createConstraint", (char **)kwlist,
+ &physicsid, &physicsid2, &constrainttype,
+ &pivotX, &pivotY, &pivotZ, &axisX, &axisY, &axisZ, &flag))
{
- success = PyArg_ParseTuple(args,"KKii", &physicsid, &physicsid2, &constrainttype, &extrainfo);
- pivotX=extrainfo;
+ return NULL;
}
- if (success)
- {
- if (PHY_GetActiveEnvironment())
- {
-
- PHY_IPhysicsController* physctrl = (PHY_IPhysicsController*) physicsid;
- PHY_IPhysicsController* physctrl2 = (PHY_IPhysicsController*) physicsid2;
- if (physctrl) //TODO:check for existence of this pointer!
- {
- int constraintid =0;
-
- //convert from euler angle into axis
- float radsPerDeg = 6.283185307179586232f / 360.f;
+ if (PHY_GetActiveEnvironment()) {
+ PHY_IPhysicsController *physctrl = (PHY_IPhysicsController*)physicsid;
+ PHY_IPhysicsController *physctrl2 = (PHY_IPhysicsController*)physicsid2;
+ if (physctrl) { //TODO:check for existence of this pointer!
+ //convert from euler angle into axis
+ const float deg2rad = 0.017453292f;
- //we need to pass a full constraint frame, not just axis
- //localConstraintFrameBasis
- MT_Matrix3x3 localCFrame(MT_Vector3(radsPerDeg*axisX,radsPerDeg*axisY,radsPerDeg*axisZ));
- MT_Vector3 axis0 = localCFrame.getColumn(0);
- MT_Vector3 axis1 = localCFrame.getColumn(1);
- MT_Vector3 axis2 = localCFrame.getColumn(2);
+ //we need to pass a full constraint frame, not just axis
+ //localConstraintFrameBasis
+ MT_Matrix3x3 localCFrame(MT_Vector3(deg2rad*axisX, deg2rad*axisY, deg2rad*axisZ));
+ MT_Vector3 axis0 = localCFrame.getColumn(0);
+ MT_Vector3 axis1 = localCFrame.getColumn(1);
+ MT_Vector3 axis2 = localCFrame.getColumn(2);
- constraintid = PHY_GetActiveEnvironment()->CreateConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype,
- pivotX,pivotY,pivotZ,
- (float)axis0.x(),(float)axis0.y(),(float)axis0.z(),
- (float)axis1.x(),(float)axis1.y(),(float)axis1.z(),
- (float)axis2.x(),(float)axis2.y(),(float)axis2.z(),flag);
+ int constraintid = PHY_GetActiveEnvironment()->CreateConstraint(
+ physctrl, physctrl2, (enum PHY_ConstraintType)constrainttype, pivotX, pivotY, pivotZ,
+ (float)axis0.x(), (float)axis0.y(), (float)axis0.z(),
+ (float)axis1.x(), (float)axis1.y(), (float)axis1.z(),
+ (float)axis2.x(), (float)axis2.y(), (float)axis2.z(), flag);
- KX_ConstraintWrapper* wrap = new KX_ConstraintWrapper((enum PHY_ConstraintType)constrainttype,constraintid,PHY_GetActiveEnvironment());
+ KX_ConstraintWrapper *wrap = new KX_ConstraintWrapper(
+ (enum PHY_ConstraintType)constrainttype, constraintid, PHY_GetActiveEnvironment());
- return wrap->NewProxy(true);
- }
-
-
+ return wrap->NewProxy(true);
}
}
- else {
- return NULL;
- }
-
Py_RETURN_NONE;
}
@@ -680,7 +648,7 @@ static struct PyMethodDef physicsconstraints_methods[] = {
{"createConstraint",(PyCFunction) gPyCreateConstraint,
- METH_VARARGS, (const char *)gPyCreateConstraint__doc__},
+ METH_VARARGS|METH_KEYWORDS, (const char *)gPyCreateConstraint__doc__},
{"getVehicleConstraint",(PyCFunction) gPyGetVehicleConstraint,
METH_VARARGS, (const char *)gPyGetVehicleConstraint__doc__},
diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp
index d7dd3fe5253..6fdc53f9c64 100644
--- a/source/gameengine/Ketsji/KX_PythonInit.cpp
+++ b/source/gameengine/Ketsji/KX_PythonInit.cpp
@@ -51,6 +51,8 @@
# include <Python.h>
extern "C" {
+ # include "BLI_utildefines.h"
+ # include "python_utildefines.h"
# include "bpy_internal_import.h" /* from the blender python api, but we want to import text too! */
# include "py_capi_utils.h"
# include "mathutils.h" // 'mathutils' module copied here so the blenderlayer can use.
@@ -354,7 +356,7 @@ static PyObject *gPyLoadGlobalDict(PyObject *)
{
char marshal_path[512];
char *marshal_buffer = NULL;
- size_t marshal_length;
+ int marshal_length;
FILE *fp = NULL;
int result;
@@ -365,7 +367,12 @@ static PyObject *gPyLoadGlobalDict(PyObject *)
if (fp) {
// obtain file size:
fseek (fp, 0, SEEK_END);
- marshal_length = (size_t)ftell(fp);
+ marshal_length = ftell(fp);
+ if (marshal_length == -1) {
+ printf("Warning: could not read position of '%s'\n", marshal_path);
+ fclose(fp);
+ Py_RETURN_NONE;
+ }
rewind(fp);
marshal_buffer = (char*)malloc (sizeof(char)*marshal_length);
@@ -1029,109 +1036,22 @@ static PyObject *gPyGetStereoEye(PyObject *, PyObject *, PyObject *)
static PyObject *gPySetBackgroundColor(PyObject *, PyObject *value)
{
-
MT_Vector4 vec;
if (!PyVecTo(value, vec))
return NULL;
-
- if (gp_Canvas)
- {
- gp_Rasterizer->SetBackColor((float)vec[0], (float)vec[1], (float)vec[2], (float)vec[3]);
- }
KX_WorldInfo *wi = gp_KetsjiScene->GetWorldInfo();
- if (wi->hasWorld())
- wi->setBackColor((float)vec[0], (float)vec[1], (float)vec[2]);
-
- Py_RETURN_NONE;
-}
-
-
-
-static PyObject *gPySetMistColor(PyObject *, PyObject *value)
-{
-
- MT_Vector3 vec;
- if (!PyVecTo(value, vec))
- return NULL;
-
- if (!gp_Rasterizer) {
- PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMistColor(color), Rasterizer not available");
+ if (!wi->hasWorld()) {
+ PyErr_SetString(PyExc_RuntimeError, "bge.render.SetBackgroundColor(color), World not available");
return NULL;
}
- gp_Rasterizer->SetFogColor((float)vec[0], (float)vec[1], (float)vec[2]);
-
- Py_RETURN_NONE;
-}
-
-static PyObject *gPyDisableMist(PyObject *)
-{
-
- if (!gp_Rasterizer) {
- PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMistColor(color), Rasterizer not available");
- return NULL;
- }
- gp_Rasterizer->DisableFog();
-
- Py_RETURN_NONE;
-}
-static PyObject *gPySetMistStart(PyObject *, PyObject *args)
-{
+ ShowDeprecationWarning("setBackgroundColor()", "KX_WorldInfo.background_color");
+ wi->setBackColor((float)vec[0], (float)vec[1], (float)vec[2]);
- float miststart;
- if (!PyArg_ParseTuple(args,"f:setMistStart",&miststart))
- return NULL;
-
- if (!gp_Rasterizer) {
- PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMistStart(float), Rasterizer not available");
- return NULL;
- }
-
- gp_Rasterizer->SetFogStart(miststart);
-
Py_RETURN_NONE;
}
-
-
-static PyObject *gPySetMistEnd(PyObject *, PyObject *args)
-{
-
- float mistend;
- if (!PyArg_ParseTuple(args,"f:setMistEnd",&mistend))
- return NULL;
-
- if (!gp_Rasterizer) {
- PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMistEnd(float), Rasterizer not available");
- return NULL;
- }
-
- gp_Rasterizer->SetFogEnd(mistend);
-
- Py_RETURN_NONE;
-}
-
-
-static PyObject *gPySetAmbientColor(PyObject *, PyObject *value)
-{
-
- MT_Vector3 vec;
- if (!PyVecTo(value, vec))
- return NULL;
-
- if (!gp_Rasterizer) {
- PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setAmbientColor(color), Rasterizer not available");
- return NULL;
- }
- gp_Rasterizer->SetAmbientColor((float)vec[0], (float)vec[1], (float)vec[2]);
-
- Py_RETURN_NONE;
-}
-
-
-
-
static PyObject *gPyMakeScreenshot(PyObject *, PyObject *args)
{
char* filename;
@@ -1490,6 +1410,21 @@ static PyObject *gPyClearDebugList(PyObject *)
Py_RETURN_NONE;
}
+static PyObject *gPyGetDisplayDimensions(PyObject *)
+{
+ PyObject *result;
+ int width, height;
+
+ gp_Canvas->GetDisplayDimensions(width, height);
+
+ result = PyTuple_New(2);
+ PyTuple_SET_ITEMS(result,
+ PyLong_FromLong(width),
+ PyLong_FromLong(height));
+
+ return result;
+}
+
PyDoc_STRVAR(Rasterizer_module_documentation,
"This is the Python API for the game engine of Rasterizer"
);
@@ -1508,11 +1443,6 @@ static struct PyMethodDef rasterizer_methods[] = {
{"setMousePosition",(PyCFunction) gPySetMousePosition,
METH_VARARGS, "setMousePosition(int x,int y)"},
{"setBackgroundColor",(PyCFunction)gPySetBackgroundColor,METH_O,"set Background Color (rgb)"},
- {"setAmbientColor",(PyCFunction)gPySetAmbientColor,METH_O,"set Ambient Color (rgb)"},
- {"disableMist",(PyCFunction)gPyDisableMist,METH_NOARGS,"turn off mist"},
- {"setMistColor",(PyCFunction)gPySetMistColor,METH_O,"set Mist Color (rgb)"},
- {"setMistStart",(PyCFunction)gPySetMistStart,METH_VARARGS,"set Mist Start(rgb)"},
- {"setMistEnd",(PyCFunction)gPySetMistEnd,METH_VARARGS,"set Mist End(rgb)"},
{"enableMotionBlur",(PyCFunction)gPyEnableMotionBlur,METH_VARARGS,"enable motion blur"},
{"disableMotionBlur",(PyCFunction)gPyDisableMotionBlur,METH_NOARGS,"disable motion blur"},
@@ -1538,6 +1468,8 @@ static struct PyMethodDef rasterizer_methods[] = {
{"setWindowSize", (PyCFunction) gPySetWindowSize, METH_VARARGS, ""},
{"setFullScreen", (PyCFunction) gPySetFullScreen, METH_O, ""},
{"getFullScreen", (PyCFunction) gPyGetFullScreen, METH_NOARGS, ""},
+ {"getDisplayDimensions", (PyCFunction) gPyGetDisplayDimensions, METH_NOARGS,
+ "Get the actual dimensions, in pixels, of the physical display (e.g., the monitor)."},
{"setMipmapping", (PyCFunction) gPySetMipmapping, METH_VARARGS, ""},
{"getMipmapping", (PyCFunction) gPyGetMipmapping, METH_NOARGS, ""},
{"setVsync", (PyCFunction) gPySetVsync, METH_VARARGS, ""},
@@ -2149,14 +2081,14 @@ PyObject *initGamePlayerPythonScripting(Main *maggie, int argc, char** argv)
Py_SetProgramName(program_path_wchar);
/* Update, Py3.3 resolves attempting to parse non-existing header */
- #if 0
+#if 0
/* Python 3.2 now looks for '2.xx/python/include/python3.2d/pyconfig.h' to
* parse from the 'sysconfig' module which is used by 'site',
* so for now disable site. alternatively we could copy the file. */
if (py_path_bundle != NULL) {
Py_NoSiteFlag = 1; /* inhibits the automatic importing of 'site' */
}
- #endif
+#endif
Py_FrozenFlag = 1;
diff --git a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp
index 828fd62f205..b3511e4e61a 100644
--- a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp
+++ b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp
@@ -40,6 +40,7 @@
#include "BL_ArmatureConstraint.h"
#include "BL_ArmatureObject.h"
#include "BL_ArmatureChannel.h"
+#include "KX_WorldInfo.h"
#include "KX_ArmatureSensor.h"
#include "KX_BlenderMaterial.h"
#include "KX_CameraActuator.h"
@@ -231,6 +232,7 @@ PyMODINIT_FUNC initGameTypesPythonBinding(void)
PyType_Ready_Attr(dict, KX_SCA_EndObjectActuator, init_getset);
PyType_Ready_Attr(dict, KX_SCA_ReplaceMeshActuator, init_getset);
PyType_Ready_Attr(dict, KX_Scene, init_getset);
+ PyType_Ready_Attr(dict, KX_WorldInfo, init_getset);
PyType_Ready_Attr(dict, KX_NavMeshObject, init_getset);
PyType_Ready_Attr(dict, KX_SceneActuator, init_getset);
PyType_Ready_Attr(dict, KX_SoundActuator, init_getset);
@@ -279,6 +281,7 @@ PyMODINIT_FUNC initGameTypesPythonBinding(void)
/* Init mathutils callbacks */
KX_GameObject_Mathutils_Callback_Init();
KX_ObjectActuator_Mathutils_Callback_Init();
+ KX_WorldInfo_Mathutils_Callback_Init();
#endif
return m;
diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp
index 97ebd6d40a9..25755f7127b 100644
--- a/source/gameengine/Ketsji/KX_Scene.cpp
+++ b/source/gameengine/Ketsji/KX_Scene.cpp
@@ -43,6 +43,7 @@
#include "KX_FontObject.h"
#include "RAS_IPolygonMaterial.h"
#include "ListValue.h"
+#include "KX_PythonCallBack.h"
#include "SCA_LogicManager.h"
#include "SCA_TimeEventManager.h"
//#include "SCA_AlwaysEventManager.h"
@@ -156,7 +157,9 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
m_networkDeviceInterface(ndi),
m_active_camera(NULL),
m_ueberExecutionPriority(0),
- m_blenderScene(scene)
+ m_blenderScene(scene),
+ m_isActivedHysteresis(false),
+ m_lodHysteresisValue(0)
{
m_suspendedtime = 0.0;
m_suspendeddelta = 0.0;
@@ -235,6 +238,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
m_attr_dict = NULL;
m_draw_call_pre = NULL;
m_draw_call_post = NULL;
+ m_draw_setup_call_pre = NULL;
#endif
}
@@ -532,6 +536,8 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal
m_objectlist->Add(newobj->AddRef());
if (newobj->GetGameObjectType()==SCA_IObject::OBJ_LIGHT)
m_lightlist->Add(newobj->AddRef());
+ else if (newobj->GetGameObjectType()==SCA_IObject::OBJ_TEXT)
+ AddFont((KX_FontObject*)newobj);
newobj->AddMeshUser();
// logic cannot be replicated, until the whole hierarchy is replicated.
@@ -803,13 +809,6 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level)
// we can now add the graphic controller to the physic engine
replica->ActivateGraphicController(true);
- // set references for dupli-group
- // groupobj holds a list of all objects, that belongs to this group
- groupobj->AddInstanceObjects(replica);
-
- // every object gets the reference to its dupli-group object
- replica->SetDupliGroupObject(groupobj);
-
// done with replica
replica->Release();
}
@@ -817,38 +816,38 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level)
// the logic must be replicated first because we need
// the new logic bricks before relinking
vector<KX_GameObject*>::iterator git;
- for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
- {
- (*git)->ReParentLogic();
- }
-
- // relink any pointers as necessary, sort of a temporary solution
- for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
- {
+ for (git = m_logicHierarchicalGameObjects.begin(); git != m_logicHierarchicalGameObjects.end(); ++git) {
+ KX_GameObject *gameobj = *git;
+
+ if (gameobj->GetBlenderGroupObject() == blgroupobj) {
+ // set references for dupli-group
+ // groupobj holds a list of all objects, that belongs to this group
+ groupobj->AddInstanceObjects(gameobj);
+ // every object gets the reference to its dupli-group object
+ gameobj->SetDupliGroupObject(groupobj);
+ }
+
+ gameobj->ReParentLogic();
+
+ // relink any pointers as necessary, sort of a temporary solution
// this will also relink the actuator to objects within the hierarchy
- (*git)->Relink(&m_map_gameobject_to_replica);
+ gameobj->Relink(&m_map_gameobject_to_replica);
// add the object in the layer of the parent
- (*git)->SetLayer(groupobj->GetLayer());
- // If the object was a light, we need to update it's RAS_LightObject as well
- if ((*git)->GetGameObjectType()==SCA_IObject::OBJ_LIGHT)
- {
- KX_LightObject* lightobj = static_cast<KX_LightObject*>(*git);
- lightobj->SetLayer(groupobj->GetLayer());
- }
- }
+ gameobj->SetLayer(groupobj->GetLayer());
- // replicate crosslinks etc. between logic bricks
- for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
- {
- ReplicateLogic((*git));
- }
+ // replicate crosslinks etc. between logic bricks
+ ReplicateLogic(gameobj);
- // now look if object in the hierarchy have dupli group and recurse
- for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
- {
- if ((*git) != groupobj && (*git)->IsDupliGroup())
+ // now look if object in the hierarchy have dupli group and recurse
+ /* Replicate all constraints. */
+ if (gameobj->GetPhysicsController()) {
+ gameobj->GetPhysicsController()->ReplicateConstraints(gameobj, m_logicHierarchicalGameObjects);
+ gameobj->ClearConstraints();
+ }
+
+ if (gameobj != groupobj && gameobj->IsDupliGroup())
// can't instantiate group immediately as it destroys m_logicHierarchicalGameObjects
- duplilist.push_back((*git));
+ duplilist.push_back(gameobj);
}
for (git = duplilist.begin(); !(git == duplilist.end()); ++git)
@@ -859,7 +858,7 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level)
SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
- class CValue* parentobject,
+ class CValue* referenceobject,
int lifespan)
{
@@ -868,7 +867,7 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
m_groupGameObjects.clear();
KX_GameObject* originalobj = (KX_GameObject*) originalobject;
- KX_GameObject* parentobj = (KX_GameObject*) parentobject;
+ KX_GameObject* referenceobj = (KX_GameObject*) referenceobject;
m_ueberExecutionPriority++;
@@ -904,18 +903,20 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
replica->GetSGNode()->AddChild(childreplicanode);
}
- // At this stage all the objects in the hierarchy have been duplicated,
- // we can update the scenegraph, we need it for the duplication of logic
- MT_Point3 newpos = ((KX_GameObject*) parentobject)->NodeGetWorldPosition();
- replica->NodeSetLocalPosition(newpos);
+ if (referenceobj) {
+ // At this stage all the objects in the hierarchy have been duplicated,
+ // we can update the scenegraph, we need it for the duplication of logic
+ MT_Point3 newpos = referenceobj->NodeGetWorldPosition();
+ replica->NodeSetLocalPosition(newpos);
- MT_Matrix3x3 newori = ((KX_GameObject*) parentobject)->NodeGetWorldOrientation();
- replica->NodeSetLocalOrientation(newori);
-
- // get the rootnode's scale
- MT_Vector3 newscale = parentobj->GetSGNode()->GetRootSGParent()->GetLocalScale();
- // set the replica's relative scale with the rootnode's scale
- replica->NodeSetRelativeScale(newscale);
+ MT_Matrix3x3 newori = referenceobj->NodeGetWorldOrientation();
+ replica->NodeSetLocalOrientation(newori);
+
+ // get the rootnode's scale
+ MT_Vector3 newscale = referenceobj->GetSGNode()->GetRootSGParent()->GetLocalScale();
+ // set the replica's relative scale with the rootnode's scale
+ replica->NodeSetRelativeScale(newscale);
+ }
replica->GetSGNode()->UpdateWorldData(0);
replica->GetSGNode()->SetBBox(originalobj->GetSGNode()->BBox());
@@ -935,13 +936,13 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
{
// this will also relink the actuators in the hierarchy
(*git)->Relink(&m_map_gameobject_to_replica);
- // add the object in the layer of the parent
- (*git)->SetLayer(parentobj->GetLayer());
- // If the object was a light, we need to update it's RAS_LightObject as well
- if ((*git)->GetGameObjectType()==SCA_IObject::OBJ_LIGHT)
- {
- KX_LightObject* lightobj = static_cast<KX_LightObject*>(*git);
- lightobj->SetLayer(parentobj->GetLayer());
+ if (referenceobj) {
+ // add the object in the layer of the reference object
+ (*git)->SetLayer(referenceobj->GetLayer());
+ }
+ else {
+ // We don't know what layer set, so we set all visible layers in the blender scene.
+ (*git)->SetLayer(m_blenderScene->lay);
}
}
@@ -1755,6 +1756,26 @@ void KX_Scene::UpdateObjectLods(void)
}
}
+void KX_Scene::SetLodHysteresis(bool active)
+{
+ m_isActivedHysteresis = active;
+}
+
+bool KX_Scene::IsActivedLodHysteresis(void)
+{
+ return m_isActivedHysteresis;
+}
+
+void KX_Scene::SetLodHysteresisValue(int hysteresisvalue)
+{
+ m_lodHysteresisValue = hysteresisvalue;
+}
+
+int KX_Scene::GetLodHysteresisValue(void)
+{
+ return m_lodHysteresisValue;
+}
+
void KX_Scene::UpdateObjectActivity(void)
{
if (m_activity_culling) {
@@ -1871,15 +1892,6 @@ static void MergeScene_LogicBrick(SCA_ILogicBrick* brick, KX_Scene *from, KX_Sce
brick->Replace_IScene(to);
brick->Replace_NetworkScene(to->GetNetworkScene());
- /* near sensors have physics controllers */
- KX_TouchSensor *touch_sensor = dynamic_cast<class KX_TouchSensor *>(brick);
- if (touch_sensor) {
- KX_TouchEventManager *tmgr = (KX_TouchEventManager*)from->GetLogicManager()->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR);
- touch_sensor->UnregisterSumo(tmgr);
- touch_sensor->GetPhysicsController()->SetPhysicsEnvironment(to->GetPhysicsEnvironment());
- touch_sensor->RegisterSumo(tmgr);
- }
-
// If we end up replacing a KX_TouchEventManager, we need to make sure
// physics controllers are properly in place. In other words, do this
// after merging physics controllers!
@@ -1938,17 +1950,6 @@ static void MergeScene_GameObject(KX_GameObject* gameobj, KX_Scene *to, KX_Scene
{
SCA_IController *cont= *itc;
MergeScene_LogicBrick(cont, from, to);
-
- vector<SCA_ISensor*> linkedsensors = cont->GetLinkedSensors();
- vector<SCA_IActuator*> linkedactuators = cont->GetLinkedActuators();
-
- for (vector<SCA_IActuator*>::iterator ita = linkedactuators.begin();!(ita==linkedactuators.end());++ita) {
- MergeScene_LogicBrick(*ita, from, to);
- }
-
- for (vector<SCA_ISensor*>::iterator its = linkedsensors.begin();!(its==linkedsensors.end());++its) {
- MergeScene_LogicBrick(*its, from, to);
- }
}
}
@@ -2102,30 +2103,10 @@ void KX_Scene::Render2DFilters(RAS_ICanvas* canvas)
void KX_Scene::RunDrawingCallbacks(PyObject *cb_list)
{
- Py_ssize_t len;
-
- if (cb_list && (len=PyList_GET_SIZE(cb_list)))
- {
- PyObject *args = PyTuple_New(0); // save python creating each call
- PyObject *func;
- PyObject *ret;
-
- // Iterate the list and run the callbacks
- for (Py_ssize_t pos=0; pos < len; pos++)
- {
- func= PyList_GET_ITEM(cb_list, pos);
- ret= PyObject_Call(func, args, NULL);
- if (ret==NULL) {
- PyErr_Print();
- PyErr_Clear();
- }
- else {
- Py_DECREF(ret);
- }
- }
+ if (!cb_list || PyList_GET_SIZE(cb_list) == 0)
+ return;
- Py_DECREF(args);
- }
+ RunPythonCallBackList(cb_list, NULL, 0, 0);
}
//----------------------------------------------------------------------------
@@ -2311,6 +2292,19 @@ PyObject *KX_Scene::pyattr_get_lights(void *self_v, const KX_PYATTRIBUTE_DEF *at
return self->GetLightList()->GetProxy();
}
+PyObject *KX_Scene::pyattr_get_world(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_Scene* self = static_cast<KX_Scene*>(self_v);
+ KX_WorldInfo *world = self->GetWorldInfo();
+
+ if (world->GetName() != "") {
+ return world->GetProxy();
+ }
+ else {
+ Py_RETURN_NONE;
+ }
+}
+
PyObject *KX_Scene::pyattr_get_cameras(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
/* With refcounts in this case...
@@ -2375,6 +2369,17 @@ PyObject *KX_Scene::pyattr_get_drawing_callback_post(void *self_v, const KX_PYAT
return self->m_draw_call_post;
}
+PyObject *KX_Scene::pyattr_get_drawing_setup_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_Scene* self = static_cast<KX_Scene*>(self_v);
+
+ if (self->m_draw_setup_call_pre == NULL)
+ self->m_draw_setup_call_pre = PyList_New(0);
+
+ Py_INCREF(self->m_draw_setup_call_pre);
+ return self->m_draw_setup_call_pre;
+}
+
int KX_Scene::pyattr_set_drawing_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
{
KX_Scene* self = static_cast<KX_Scene*>(self_v);
@@ -2409,6 +2414,22 @@ int KX_Scene::pyattr_set_drawing_callback_post(void *self_v, const KX_PYATTRIBUT
return PY_SET_ATTR_SUCCESS;
}
+int KX_Scene::pyattr_set_drawing_setup_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ KX_Scene* self = static_cast<KX_Scene*>(self_v);
+
+ if (!PyList_CheckExact(value)) {
+ PyErr_SetString(PyExc_ValueError, "Expected a list");
+ return PY_SET_ATTR_FAIL;
+ }
+
+ Py_XDECREF(self->m_draw_setup_call_pre);
+ Py_INCREF(value);
+
+ self->m_draw_setup_call_pre = value;
+ return PY_SET_ATTR_SUCCESS;
+}
+
PyObject *KX_Scene::pyattr_get_gravity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_Scene* self = static_cast<KX_Scene*>(self_v);
@@ -2434,9 +2455,11 @@ PyAttributeDef KX_Scene::Attributes[] = {
KX_PYATTRIBUTE_RO_FUNCTION("objectsInactive", KX_Scene, pyattr_get_objects_inactive),
KX_PYATTRIBUTE_RO_FUNCTION("lights", KX_Scene, pyattr_get_lights),
KX_PYATTRIBUTE_RO_FUNCTION("cameras", KX_Scene, pyattr_get_cameras),
+ KX_PYATTRIBUTE_RO_FUNCTION("world", KX_Scene, pyattr_get_world),
KX_PYATTRIBUTE_RW_FUNCTION("active_camera", KX_Scene, pyattr_get_active_camera, pyattr_set_active_camera),
KX_PYATTRIBUTE_RW_FUNCTION("pre_draw", KX_Scene, pyattr_get_drawing_callback_pre, pyattr_set_drawing_callback_pre),
KX_PYATTRIBUTE_RW_FUNCTION("post_draw", KX_Scene, pyattr_get_drawing_callback_post, pyattr_set_drawing_callback_post),
+ KX_PYATTRIBUTE_RW_FUNCTION("pre_draw_setup", KX_Scene, pyattr_get_drawing_setup_callback_pre, pyattr_set_drawing_setup_callback_pre),
KX_PYATTRIBUTE_RW_FUNCTION("gravity", KX_Scene, pyattr_get_gravity, pyattr_set_gravity),
KX_PYATTRIBUTE_BOOL_RO("suspended", KX_Scene, m_suspend),
KX_PYATTRIBUTE_BOOL_RO("activity_culling", KX_Scene, m_activity_culling),
@@ -2449,23 +2472,23 @@ KX_PYMETHODDEF_DOC(KX_Scene, addObject,
"addObject(object, other, time=0)\n"
"Returns the added object.\n")
{
- PyObject *pyob, *pyother;
- KX_GameObject *ob, *other;
+ PyObject *pyob, *pyreference = Py_None;
+ KX_GameObject *ob, *reference;
int time = 0;
- if (!PyArg_ParseTuple(args, "OO|i:addObject", &pyob, &pyother, &time))
+ if (!PyArg_ParseTuple(args, "O|Oi:addObject", &pyob, &pyreference, &time))
return NULL;
- if ( !ConvertPythonToGameObject(pyob, &ob, false, "scene.addObject(object, other, time): KX_Scene (first argument)") ||
- !ConvertPythonToGameObject(pyother, &other, false, "scene.addObject(object, other, time): KX_Scene (second argument)") )
+ if (!ConvertPythonToGameObject(pyob, &ob, false, "scene.addObject(object, reference, time): KX_Scene (first argument)") ||
+ !ConvertPythonToGameObject(pyreference, &reference, true, "scene.addObject(object, reference, time): KX_Scene (second argument)"))
return NULL;
if (!m_inactivelist->SearchValue(ob)) {
- PyErr_Format(PyExc_ValueError, "scene.addObject(object, other, time): KX_Scene (first argument): object must be in an inactive layer");
+ PyErr_Format(PyExc_ValueError, "scene.addObject(object, reference, time): KX_Scene (first argument): object must be in an inactive layer");
return NULL;
}
- SCA_IObject* replica = AddReplicaObject((SCA_IObject*)ob, other, time);
+ SCA_IObject *replica = AddReplicaObject((SCA_IObject*)ob, reference, time);
// release here because AddReplicaObject AddRef's
// the object is added to the scene so we don't want python to own a reference
diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h
index 2e1ee9f101d..a5645ea6448 100644
--- a/source/gameengine/Ketsji/KX_Scene.h
+++ b/source/gameengine/Ketsji/KX_Scene.h
@@ -107,6 +107,7 @@ class KX_Scene : public PyObjectPlus, public SCA_IScene
PyObject* m_attr_dict;
PyObject* m_draw_call_pre;
PyObject* m_draw_call_post;
+ PyObject* m_draw_setup_call_pre;
#endif
struct CullingInfo {
@@ -295,6 +296,12 @@ protected:
KX_ObstacleSimulation* m_obstacleSimulation;
+ /**
+ * LOD Hysteresis settings
+ */
+ bool m_isActivedHysteresis;
+ int m_lodHysteresisValue;
+
public:
KX_Scene(class SCA_IInputDevice* keyboarddevice,
class SCA_IInputDevice* mousedevice,
@@ -546,6 +553,12 @@ public:
// Update the mesh for objects based on level of detail settings
void UpdateObjectLods(void);
+
+ // LoD Hysteresis functions
+ void SetLodHysteresis(bool active);
+ bool IsActivedLodHysteresis();
+ void SetLodHysteresisValue(int hysteresisvalue);
+ int GetLodHysteresisValue();
// Update the activity box settings for objects in this scene, if needed.
void UpdateObjectActivity(void);
@@ -612,12 +625,15 @@ public:
static PyObject* pyattr_get_objects_inactive(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_lights(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_cameras(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static PyObject* pyattr_get_world(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_active_camera(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_active_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
static PyObject* pyattr_get_drawing_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_drawing_callback_pre(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
static PyObject* pyattr_get_drawing_callback_post(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_drawing_callback_post(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+ static PyObject* pyattr_get_drawing_setup_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static int pyattr_set_drawing_setup_callback_pre(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
static PyObject* pyattr_get_gravity(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_gravity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
@@ -634,6 +650,7 @@ public:
PyObject *GetPreDrawCB() { return m_draw_call_pre; }
PyObject *GetPostDrawCB() { return m_draw_call_post; }
+ PyObject *GetPreDrawSetupCB() { return m_draw_setup_call_pre; }
#endif
/**
diff --git a/source/gameengine/Ketsji/KX_SteeringActuator.cpp b/source/gameengine/Ketsji/KX_SteeringActuator.cpp
index 10d4273a2b4..83597f9125a 100644
--- a/source/gameengine/Ketsji/KX_SteeringActuator.cpp
+++ b/source/gameengine/Ketsji/KX_SteeringActuator.cpp
@@ -263,12 +263,12 @@ bool KX_SteeringActuator::Update(double curtime, bool frame)
if (apply_steerforce)
{
- MT_Vector3 newvel;
bool isdyna = obj->IsDynamic();
if (isdyna)
m_steerVec.z() = 0;
if (!m_steerVec.fuzzyZero())
m_steerVec.normalize();
+ MT_Vector3 newvel = m_velocity * m_steerVec;
//adjust velocity to avoid obstacles
if (m_simulation && m_obstacle /*&& !newvel.fuzzyZero()*/)
@@ -284,13 +284,10 @@ bool KX_SteeringActuator::Update(double curtime, bool frame)
HandleActorFace(newvel);
if (isdyna)
{
- //TODO: Take into account angular velocity on turns
+ //temporary solution: set 2D steering velocity directly to obj
+ //correct way is to apply physical force
MT_Vector3 curvel = obj->GetLinearVelocity();
- newvel = (curvel.length() * m_steerVec) + (m_acceleration * delta) * m_steerVec;
- if (newvel.length2() >= (m_velocity * m_velocity))
- newvel = m_velocity * m_steerVec;
-
if (m_lockzvel)
newvel.z() = 0.0f;
else
diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
index d10e51a491a..b42200783e4 100644
--- a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
+++ b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
@@ -54,19 +54,20 @@ KX_VehicleWrapper::~KX_VehicleWrapper()
#ifdef WITH_PYTHON
-static bool raise_exc_wheel(PHY_IVehicle* vehicle, int i, const char *method)
+static bool raise_exc_wheel(PHY_IVehicle *vehicle, int i, const char *method)
{
- if ( i < 0 || i >= vehicle->GetNumWheels() ) {
+ if (i < 0 || i >= vehicle->GetNumWheels()) {
PyErr_Format(PyExc_ValueError,
- "%s(...): wheel index %d out of range (0 to %d).", method, i, vehicle->GetNumWheels()-1);
- return -1;
- } else {
- return 0;
+ "%s(...): wheel index %d out of range (0 to %d).", method, i, vehicle->GetNumWheels() - 1);
+ return true;
+ }
+ else {
+ return false;
}
}
#define WHEEL_INDEX_CHECK_OR_RETURN(i, method) \
- if (raise_exc_wheel(m_vehicle, i, method) == -1) { return NULL; } (void)0
+ if (raise_exc_wheel(m_vehicle, i, method)) {return NULL;} (void)0
PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args)
@@ -86,8 +87,6 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args)
if (gameOb->GetSGNode())
{
- PHY_IMotionState* motionState = new KX_MotionState(gameOb->GetSGNode());
-
MT_Vector3 attachPos,attachDir,attachAxle;
if(!PyVecTo(pylistPos,attachPos)) {
PyErr_SetString(PyExc_AttributeError,
@@ -114,6 +113,7 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args)
return NULL;
}
+ PHY_IMotionState *motionState = new KX_MotionState(gameOb->GetSGNode());
m_vehicle->AddWheel(motionState,attachPos,attachDir,attachAxle,suspensionRestLength,wheelRadius,hasSteering);
}
diff --git a/source/gameengine/Ketsji/KX_WorldInfo.cpp b/source/gameengine/Ketsji/KX_WorldInfo.cpp
index 444d6b0771b..8678b058761 100644
--- a/source/gameengine/Ketsji/KX_WorldInfo.cpp
+++ b/source/gameengine/Ketsji/KX_WorldInfo.cpp
@@ -31,8 +31,464 @@
#include "KX_WorldInfo.h"
+#include "KX_PythonInit.h"
+#include "KX_PyMath.h"
+#include "RAS_IRasterizer.h"
+#include "GPU_material.h"
+
+/* This little block needed for linking to Blender... */
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+
+/* This list includes only data type definitions */
+#include "DNA_scene_types.h"
+#include "DNA_world_types.h"
+
+#include "BLI_math.h"
+
+#include "BKE_global.h"
+#include "BKE_scene.h"
+/* end of blender include block */
+
+
+KX_WorldInfo::KX_WorldInfo(Scene *blenderscene, World *blenderworld)
+{
+ if (blenderworld) {
+ m_name = blenderworld->id.name + 2;
+ m_do_color_management = BKE_scene_check_color_management_enabled(blenderscene);
+ m_hasworld = true;
+ m_hasmist = ((blenderworld->mode) & WO_MIST ? true : false);
+ m_misttype = blenderworld->mistype;
+ m_miststart = blenderworld->miststa;
+ m_mistdistance = blenderworld->mistdist;
+ m_mistintensity = blenderworld->misi;
+ setMistColor(blenderworld->horr, blenderworld->horg, blenderworld->horb);
+ setBackColor(blenderworld->horr, blenderworld->horg, blenderworld->horb);
+ setAmbientColor(blenderworld->ambr, blenderworld->ambg, blenderworld->ambb);
+ }
+ else {
+ m_hasworld = false;
+ }
+}
KX_WorldInfo::~KX_WorldInfo()
{
}
+const STR_String& KX_WorldInfo::GetName()
+{
+ return m_name;
+}
+
+bool KX_WorldInfo::hasWorld()
+{
+ return m_hasworld;
+}
+
+void KX_WorldInfo::setBackColor(float r, float g, float b)
+{
+ m_backgroundcolor[0] = r;
+ m_backgroundcolor[1] = g;
+ m_backgroundcolor[2] = b;
+
+ if (m_do_color_management) {
+ linearrgb_to_srgb_v3_v3(m_con_backgroundcolor, m_backgroundcolor);
+ }
+ else {
+ copy_v3_v3(m_con_backgroundcolor, m_backgroundcolor);
+ }
+}
+
+const float *KX_WorldInfo::getBackColor(void) const
+{
+ return m_backgroundcolor;
+}
+
+void KX_WorldInfo::setMistType(short type)
+{
+ m_misttype = type;
+}
+
+void KX_WorldInfo::setUseMist(bool enable)
+{
+ m_hasmist = enable;
+}
+
+void KX_WorldInfo::setMistStart(float d)
+{
+ m_miststart = d;
+}
+
+void KX_WorldInfo::setMistDistance(float d)
+{
+ m_mistdistance = d;
+}
+
+void KX_WorldInfo::setMistIntensity(float intensity)
+{
+ m_mistintensity = intensity;
+}
+void KX_WorldInfo::setMistColor(float r, float g, float b)
+{
+ m_mistcolor[0] = r;
+ m_mistcolor[1] = g;
+ m_mistcolor[2] = b;
+
+ if (m_do_color_management) {
+ linearrgb_to_srgb_v3_v3(m_con_mistcolor, m_mistcolor);
+ }
+ else {
+ copy_v3_v3(m_con_mistcolor, m_mistcolor);
+ }
+}
+
+void KX_WorldInfo::setAmbientColor(float r, float g, float b)
+{
+ m_ambientcolor[0] = r;
+ m_ambientcolor[1] = g;
+ m_ambientcolor[2] = b;
+
+ if (m_do_color_management) {
+ linearrgb_to_srgb_v3_v3(m_con_ambientcolor, m_ambientcolor);
+ }
+ else {
+ copy_v3_v3(m_con_ambientcolor, m_ambientcolor);
+ }
+}
+
+void KX_WorldInfo::UpdateBackGround()
+{
+ if (m_hasworld) {
+ RAS_IRasterizer *m_rasterizer = KX_GetActiveEngine()->GetRasterizer();
+
+ if (m_rasterizer->GetDrawingMode() >= RAS_IRasterizer::KX_SOLID) {
+ m_rasterizer->SetBackColor(m_con_backgroundcolor);
+ GPU_horizon_update_color(m_backgroundcolor);
+ }
+ }
+}
+
+void KX_WorldInfo::UpdateWorldSettings()
+{
+ if (m_hasworld) {
+ RAS_IRasterizer *m_rasterizer = KX_GetActiveEngine()->GetRasterizer();
+
+ if (m_rasterizer->GetDrawingMode() >= RAS_IRasterizer::KX_SOLID) {
+ m_rasterizer->SetAmbientColor(m_con_ambientcolor);
+ GPU_ambient_update_color(m_ambientcolor);
+
+ if (m_hasmist) {
+ m_rasterizer->SetFog(m_misttype, m_miststart, m_mistdistance, m_mistintensity, m_con_mistcolor);
+ GPU_mist_update_values(m_misttype, m_miststart, m_mistdistance, m_mistintensity, m_mistcolor);
+ m_rasterizer->EnableFog(true);
+ GPU_mist_update_enable(true);
+ }
+ else {
+ m_rasterizer->EnableFog(false);
+ GPU_mist_update_enable(false);
+ }
+ }
+ }
+}
+
+#ifdef WITH_PYTHON
+
+/* -------------------------------------------------------------------------
+ * Python functions
+ * ------------------------------------------------------------------------- */
+PyObject *KX_WorldInfo::py_repr(void)
+{
+ return PyUnicode_From_STR_String(GetName());
+}
+
+/* -------------------------------------------------------------------------
+ * Python Integration Hooks
+ * ------------------------------------------------------------------------- */
+PyTypeObject KX_WorldInfo::Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "KX_WorldInfo",
+ sizeof(PyObjectPlus_Proxy),
+ 0,
+ py_base_dealloc,
+ 0,
+ 0,
+ 0,
+ 0,
+ py_base_repr,
+ 0,0,0,0,0,0,0,0,0,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ 0,0,0,0,0,0,0,
+ Methods,
+ 0,
+ 0,
+ &PyObjectPlus::Type,
+ 0,0,0,0,0,0,
+ py_base_new
+};
+
+PyMethodDef KX_WorldInfo::Methods[] = {
+ {NULL,NULL} /* Sentinel */
+};
+
+PyAttributeDef KX_WorldInfo::Attributes[] = {
+ KX_PYATTRIBUTE_BOOL_RW("mistEnable", KX_WorldInfo, m_hasmist),
+ KX_PYATTRIBUTE_FLOAT_RW("mistStart", 0.0f, 10000.0f, KX_WorldInfo, m_miststart),
+ KX_PYATTRIBUTE_FLOAT_RW("mistDistance", 0.001f, 10000.0f, KX_WorldInfo, m_mistdistance),
+ KX_PYATTRIBUTE_FLOAT_RW("mistIntensity", 0.0f, 1.0f, KX_WorldInfo, m_mistintensity),
+ KX_PYATTRIBUTE_SHORT_RW("mistType", 0, 2, true, KX_WorldInfo, m_misttype),
+ KX_PYATTRIBUTE_RO_FUNCTION("KX_MIST_QUADRATIC", KX_WorldInfo, pyattr_get_mist_typeconst),
+ KX_PYATTRIBUTE_RO_FUNCTION("KX_MIST_LINEAR", KX_WorldInfo, pyattr_get_mist_typeconst),
+ KX_PYATTRIBUTE_RO_FUNCTION("KX_MIST_INV_QUADRATIC", KX_WorldInfo, pyattr_get_mist_typeconst),
+ KX_PYATTRIBUTE_RW_FUNCTION("mistColor", KX_WorldInfo, pyattr_get_mist_color, pyattr_set_mist_color),
+ KX_PYATTRIBUTE_RW_FUNCTION("backgroundColor", KX_WorldInfo, pyattr_get_back_color, pyattr_set_back_color),
+ KX_PYATTRIBUTE_RW_FUNCTION("ambientColor", KX_WorldInfo, pyattr_get_ambient_color, pyattr_set_ambient_color),
+ { NULL } /* Sentinel */
+};
+
+/* Attribute get/set functions */
+
+#ifdef USE_MATHUTILS
+
+/*----------------------mathutils callbacks ----------------------------*/
+
+/* subtype */
+#define MATHUTILS_VEC_CB_MIST_COLOR 1
+#define MATHUTILS_VEC_CB_BACK_COLOR 2
+#define MATHUTILS_VEC_CB_AMBIENT_COLOR 3
+
+static unsigned char mathutils_world_vector_cb_index = -1; /* index for our callbacks */
+
+static int mathutils_world_generic_check(BaseMathObject *bmo)
+{
+ KX_WorldInfo *self = static_cast<KX_WorldInfo*>BGE_PROXY_REF(bmo->cb_user);
+ if (self == NULL)
+ return -1;
+
+ return 0;
+}
+
+static int mathutils_world_vector_get(BaseMathObject *bmo, int subtype)
+{
+ KX_WorldInfo *self = static_cast<KX_WorldInfo*>BGE_PROXY_REF(bmo->cb_user);
+ if (self == NULL)
+ return -1;
+
+ switch (subtype) {
+ case MATHUTILS_VEC_CB_MIST_COLOR:
+ copy_v3_v3(bmo->data, self->m_mistcolor);
+ break;
+ case MATHUTILS_VEC_CB_BACK_COLOR:
+ copy_v3_v3(bmo->data, self->m_backgroundcolor);
+ break;
+ case MATHUTILS_VEC_CB_AMBIENT_COLOR:
+ copy_v3_v3(bmo->data, self->m_ambientcolor);
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static int mathutils_world_vector_set(BaseMathObject *bmo, int subtype)
+{
+ KX_WorldInfo *self = static_cast<KX_WorldInfo*>BGE_PROXY_REF(bmo->cb_user);
+
+ if (self == NULL)
+ return -1;
+
+ switch (subtype) {
+ case MATHUTILS_VEC_CB_MIST_COLOR:
+ self->setMistColor(bmo->data[0], bmo->data[1], bmo->data[2]);
+ break;
+ case MATHUTILS_VEC_CB_BACK_COLOR:
+ self->setBackColor(bmo->data[0], bmo->data[1], bmo->data[2]);
+ break;
+ case MATHUTILS_VEC_CB_AMBIENT_COLOR:
+ self->setAmbientColor(bmo->data[0], bmo->data[1], bmo->data[2]);
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static int mathutils_world_vector_get_index(BaseMathObject *bmo, int subtype, int index)
+{
+ KX_WorldInfo *self = static_cast<KX_WorldInfo*>BGE_PROXY_REF(bmo->cb_user);
+
+ if (self == NULL)
+ return -1;
+
+ switch (subtype) {
+ case MATHUTILS_VEC_CB_MIST_COLOR:
+ {
+ const float *color = self->m_mistcolor;
+ bmo->data[index] = color[index];
+ }
+ break;
+ case MATHUTILS_VEC_CB_BACK_COLOR:
+ {
+ const float *color = self->m_backgroundcolor;
+ bmo->data[index] = color[index];
+ }
+ break;
+ case MATHUTILS_VEC_CB_AMBIENT_COLOR:
+ {
+ const float *color = self->m_ambientcolor;
+ bmo->data[index] = color[index];
+ }
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static int mathutils_world_vector_set_index(BaseMathObject *bmo, int subtype, int index)
+{
+ KX_WorldInfo *self = static_cast<KX_WorldInfo*>BGE_PROXY_REF(bmo->cb_user);
+
+ if (self == NULL)
+ return -1;
+
+ float color[4];
+ switch (subtype) {
+ case MATHUTILS_VEC_CB_MIST_COLOR:
+ copy_v3_v3(color, self->m_mistcolor);
+ color[index] = bmo->data[index];
+ self->setMistColor(color[0], color[1], color[2]);
+ break;
+ case MATHUTILS_VEC_CB_BACK_COLOR:
+ copy_v3_v3(color, self->m_backgroundcolor);
+ color[index] = bmo->data[index];
+ self->setBackColor(color[0], color[1], color[2]);
+ break;
+ case MATHUTILS_VEC_CB_AMBIENT_COLOR:
+ copy_v3_v3(color, self->m_ambientcolor);
+ color[index] = bmo->data[index];
+ self->setAmbientColor(color[0], color[1], color[2]);
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static Mathutils_Callback mathutils_world_vector_cb = {
+ mathutils_world_generic_check,
+ mathutils_world_vector_get,
+ mathutils_world_vector_set,
+ mathutils_world_vector_get_index,
+ mathutils_world_vector_set_index
+};
+
+void KX_WorldInfo_Mathutils_Callback_Init()
+{
+ // register mathutils callbacks, ok to run more than once.
+ mathutils_world_vector_cb_index = Mathutils_RegisterCallback(&mathutils_world_vector_cb);
+}
+#endif // USE_MATHUTILS
+
+
+PyObject *KX_WorldInfo::pyattr_get_mist_typeconst(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ PyObject *retvalue;
+
+ const char* type = attrdef->m_name;
+
+ if (!strcmp(type, "KX_MIST_QUADRATIC")) {
+ retvalue = PyLong_FromLong(KX_MIST_QUADRATIC);
+ }
+ else if (!strcmp(type, "KX_MIST_LINEAR")) {
+ retvalue = PyLong_FromLong(KX_MIST_LINEAR);
+ }
+ else if (!strcmp(type, "KX_MIST_INV_QUADRATIC")) {
+ retvalue = PyLong_FromLong(KX_MIST_INV_QUADRATIC);
+ }
+ else {
+ /* should never happen */
+ PyErr_SetString(PyExc_TypeError, "invalid mist type");
+ retvalue = NULL;
+ }
+
+ return retvalue;
+}
+
+PyObject *KX_WorldInfo::pyattr_get_mist_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+#ifdef USE_MATHUTILS
+ return Vector_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v), 3,
+ mathutils_world_vector_cb_index, MATHUTILS_VEC_CB_MIST_COLOR);
+#else
+ KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v);
+ return PyObjectFrom(MT_Vector3(self->m_mistcolor));
+#endif
+}
+
+int KX_WorldInfo::pyattr_set_mist_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v);
+
+ MT_Vector3 color;
+ if (PyVecTo(value, color))
+ {
+ self->setMistColor(color[0], color[1], color[2]);
+ return PY_SET_ATTR_SUCCESS;
+ }
+ return PY_SET_ATTR_FAIL;
+}
+
+PyObject *KX_WorldInfo::pyattr_get_back_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+
+#ifdef USE_MATHUTILS
+ return Vector_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v), 3,
+ mathutils_world_vector_cb_index, MATHUTILS_VEC_CB_BACK_COLOR);
+#else
+ KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v);
+ return PyObjectFrom(MT_Vector3(self->m_backgroundcolor));
+#endif
+}
+
+int KX_WorldInfo::pyattr_set_back_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v);
+
+ MT_Vector3 color;
+ if (PyVecTo(value, color))
+ {
+ self->setBackColor(color[0], color[1], color[2]);
+ return PY_SET_ATTR_SUCCESS;
+ }
+ return PY_SET_ATTR_FAIL;
+}
+
+PyObject *KX_WorldInfo::pyattr_get_ambient_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+#ifdef USE_MATHUTILS
+ return Vector_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v), 3,
+ mathutils_world_vector_cb_index, MATHUTILS_VEC_CB_AMBIENT_COLOR);
+#else
+ KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v);
+ return PyObjectFrom(MT_Vector3(self->m_ambientcolor));
+#endif
+}
+
+int KX_WorldInfo::pyattr_set_ambient_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v);
+
+ MT_Vector3 color;
+ if (PyVecTo(value, color))
+ {
+ self->setAmbientColor(color[0], color[1], color[2]);
+ return PY_SET_ATTR_SUCCESS;
+ }
+ return PY_SET_ATTR_FAIL;
+}
+
+#endif /* WITH_PYTHON */
diff --git a/source/gameengine/Ketsji/KX_WorldInfo.h b/source/gameengine/Ketsji/KX_WorldInfo.h
index 90b16fe1242..0e8fe3c730a 100644
--- a/source/gameengine/Ketsji/KX_WorldInfo.h
+++ b/source/gameengine/Ketsji/KX_WorldInfo.h
@@ -33,41 +33,77 @@
#define __KX_WORLDINFO_H__
#include "MT_Scalar.h"
+#include "KX_KetsjiEngine.h"
+#include "PyObjectPlus.h"
#ifdef WITH_CXX_GUARDEDALLOC
#include "MEM_guardedalloc.h"
#endif
-class MT_CmMatrix4x4;
+#ifdef USE_MATHUTILS
+void KX_WorldInfo_Mathutils_Callback_Init(void);
+#endif
+
+struct Scene;
+struct World;
-class KX_WorldInfo
+class KX_WorldInfo : public PyObjectPlus
{
-public:
- KX_WorldInfo() {}
- virtual ~KX_WorldInfo();
+ Py_Header
- virtual bool hasWorld() = 0;
- virtual bool hasMist() = 0;
- virtual float getBackColorRed() = 0;
- virtual float getBackColorGreen() = 0;
- virtual float getBackColorBlue() = 0;
- virtual float getMistStart() = 0;
- virtual float getMistDistance() = 0;
- virtual float getMistColorRed() = 0;
- virtual float getMistColorGreen() = 0;
- virtual float getMistColorBlue() = 0;
+ STR_String m_name;
+ bool m_do_color_management;
+ bool m_hasworld;
+ bool m_hasmist;
+ short m_misttype;
+ float m_miststart;
+ float m_mistdistance;
+ float m_mistintensity;
+ float m_mistcolor[3];
+ float m_backgroundcolor[3];
+ float m_ambientcolor[3];
+ float m_con_mistcolor[3];
+ float m_con_backgroundcolor[3];
+ float m_con_ambientcolor[3];
- virtual float getAmbientColorRed() = 0;
- virtual float getAmbientColorGreen() = 0;
- virtual float getAmbientColorBlue() = 0;
+public:
+ /**
+ * Mist options
+ */
+ enum MistType {
+ KX_MIST_QUADRATIC,
+ KX_MIST_LINEAR,
+ KX_MIST_INV_QUADRATIC,
+ };
+
+ KX_WorldInfo(Scene *blenderscene, World *blenderworld);
+ ~KX_WorldInfo();
- virtual void setBackColor(float, float, float) = 0;
- virtual void setMistStart(float) = 0;
- virtual void setMistDistance(float) = 0;
- virtual void setMistColorRed(float) = 0;
- virtual void setMistColorGreen(float) = 0;
- virtual void setMistColorBlue(float) = 0;
+ const STR_String &GetName();
+ bool hasWorld();
+ void setUseMist(bool enable);
+ void setMistType(short type);
+ void setMistStart(float d);
+ void setMistDistance(float d);
+ void setMistIntensity(float intensity);
+ void setMistColor(float r, float g, float b);
+ void setBackColor(float r, float g, float b);
+ const float *getBackColor() const;
+ void setAmbientColor(float r, float g, float b);
+ void UpdateBackGround();
+ void UpdateWorldSettings();
+#ifdef WITH_PYTHON
+ /* attributes */
+ static PyObject *pyattr_get_mist_typeconst(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static PyObject *pyattr_get_mist_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static int pyattr_set_mist_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+ static PyObject *pyattr_get_back_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static int pyattr_set_back_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+ static PyObject *pyattr_get_ambient_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static int pyattr_set_ambient_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+ virtual PyObject *py_repr(void);
+#endif
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_WorldInfo")
diff --git a/source/gameengine/Ketsji/KX_WorldIpoController.cpp b/source/gameengine/Ketsji/KX_WorldIpoController.cpp
index 7f83a155643..1123e07ebcc 100644
--- a/source/gameengine/Ketsji/KX_WorldIpoController.cpp
+++ b/source/gameengine/Ketsji/KX_WorldIpoController.cpp
@@ -33,6 +33,8 @@
#include "KX_WorldIpoController.h"
#include "KX_ScalarInterpolator.h"
#include "KX_WorldInfo.h"
+#include "KX_PythonInit.h"
+#include "KX_Scene.h"
#if defined(_WIN64)
typedef unsigned __int64 uint_ptr;
@@ -42,31 +44,36 @@ typedef unsigned long uint_ptr;
bool KX_WorldIpoController::Update(double currentTime)
{
- if (m_modified)
- {
+ if (m_modified) {
T_InterpolatorList::iterator i;
for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
- (*i)->Execute(m_ipotime);//currentTime);
+ (*i)->Execute(m_ipotime);
}
- /* TODO, this will crash! */
- KX_WorldInfo *world = NULL;
+ KX_WorldInfo *world = KX_GetActiveScene()->GetWorldInfo();
if (m_modify_mist_start) {
world->setMistStart(m_mist_start);
}
- if (m_modify_mist_color) {
- world->setMistColorRed(m_mist_rgb[0]);
- world->setMistColorGreen(m_mist_rgb[1]);
- world->setMistColorBlue(m_mist_rgb[2]);
- }
-
if (m_modify_mist_dist) {
world->setMistDistance(m_mist_dist);
}
- m_modified=false;
+ if (m_modify_mist_intensity) {
+ world->setMistIntensity(m_mist_intensity);
+ }
+
+ if (m_modify_horizon_color) {
+ world->setBackColor(m_hori_rgb[0], m_hori_rgb[1], m_hori_rgb[2]);
+ world->setMistColor(m_hori_rgb[0], m_hori_rgb[1], m_hori_rgb[2]);
+ }
+
+ if (m_modify_ambient_color) {
+ world->setAmbientColor(m_ambi_rgb[0], m_ambi_rgb[1], m_ambi_rgb[2]);
+ }
+
+ m_modified = false;
}
return false;
}
diff --git a/source/gameengine/Ketsji/KX_WorldIpoController.h b/source/gameengine/Ketsji/KX_WorldIpoController.h
index 63983b3129b..704f421573e 100644
--- a/source/gameengine/Ketsji/KX_WorldIpoController.h
+++ b/source/gameengine/Ketsji/KX_WorldIpoController.h
@@ -39,24 +39,30 @@
class KX_WorldIpoController : public SG_Controller
{
public:
- MT_Scalar m_mist_rgb[3];
MT_Scalar m_mist_start;
MT_Scalar m_mist_dist;
+ MT_Scalar m_mist_intensity;
+ MT_Scalar m_hori_rgb[3];
+ MT_Scalar m_ambi_rgb[3];
private:
T_InterpolatorList m_interpolators;
- unsigned short m_modify_mist_color : 1;
unsigned short m_modify_mist_start : 1;
unsigned short m_modify_mist_dist : 1;
+ unsigned short m_modify_mist_intensity : 1;
+ unsigned short m_modify_horizon_color : 1;
+ unsigned short m_modify_ambient_color : 1;
bool m_modified;
double m_ipotime;
public:
KX_WorldIpoController() :
- m_modify_mist_color(false),
m_modify_mist_start(false),
m_modify_mist_dist(false),
+ m_modify_mist_intensity(false),
+ m_modify_horizon_color(false),
+ m_modify_ambient_color(false),
m_modified(true),
m_ipotime(0.0)
{}
@@ -76,14 +82,22 @@ public:
m_modify_mist_start = modify;
}
- void SetModifyMistColor(bool modify) {
- m_modify_mist_color = modify;
- }
-
void SetModifyMistDist(bool modify) {
m_modify_mist_dist = modify;
}
+ void SetModifyMistIntensity(bool modify) {
+ m_modify_mist_intensity = modify;
+ }
+
+ void SetModifyHorizonColor(bool modify) {
+ m_modify_horizon_color = modify;
+ }
+
+ void SetModifyAmbientColor(bool modify) {
+ m_modify_ambient_color = modify;
+ }
+
void
SetOption(
int option,
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
index 44c4e284e7c..8ea2b4f299d 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
@@ -39,7 +39,6 @@ subject to the following restrictions:
#include "LinearMath/btConvexHull.h"
#include "BulletCollision/Gimpact/btGImpactShape.h"
-
#include "BulletSoftBody/btSoftRigidDynamicsWorld.h"
#include "DNA_mesh_types.h"
@@ -65,7 +64,6 @@ extern bool gDisableDeactivation;
float gLinearSleepingTreshold;
float gAngularSleepingTreshold;
-
BlenderBulletCharacterController::BlenderBulletCharacterController(btMotionState *motionState, btPairCachingGhostObject *ghost, btConvexShape* shape, float stepHeight)
: btKinematicCharacterController(ghost,shape,stepHeight,2),
m_motionState(motionState),
@@ -118,6 +116,18 @@ const btVector3& BlenderBulletCharacterController::getWalkDirection()
return m_walkDirection;
}
+bool CleanPairCallback::processOverlap(btBroadphasePair &pair)
+{
+ if ((pair.m_pProxy0 == m_cleanProxy) || (pair.m_pProxy1 == m_cleanProxy)) {
+ m_pairCache->cleanOverlappingPair(pair, m_dispatcher);
+ CcdPhysicsController *ctrl0 = (CcdPhysicsController*)(((btCollisionObject*)pair.m_pProxy0->m_clientObject)->getUserPointer());
+ CcdPhysicsController *ctrl1 = (CcdPhysicsController*)(((btCollisionObject*)pair.m_pProxy1->m_clientObject)->getUserPointer());
+ ctrl0->GetCollisionObject()->activate(false);
+ ctrl1->GetCollisionObject()->activate(false);
+ }
+ return false;
+}
+
CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci)
:m_cci(ci)
{
@@ -588,20 +598,13 @@ void CcdPhysicsController::CreateRigidbody()
static void DeleteBulletShape(btCollisionShape* shape, bool free)
{
- if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE)
- {
- // shapes based on meshes use an interface that contains the vertices.
- btTriangleMeshShape* meshShape = static_cast<btTriangleMeshShape*>(shape);
- btStridingMeshInterface* meshInterface = meshShape->getMeshInterface();
- if (meshInterface)
- delete meshInterface;
- }
- else if (shape->getShapeType() == GIMPACT_SHAPE_PROXYTYPE)
- {
- btGImpactMeshShape* meshShape = static_cast<btGImpactMeshShape*>(shape);
- btStridingMeshInterface* meshInterface = meshShape->getMeshInterface();
- if (meshInterface)
- delete meshInterface;
+ if (shape->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE) {
+ /* If we use Bullet scaled shape (btScaledBvhTriangleMeshShape) we have to
+ * free the child of the unscaled shape (btTriangleMeshShape) here.
+ */
+ btTriangleMeshShape *meshShape = ((btScaledBvhTriangleMeshShape *)shape)->getChildShape();
+ if (meshShape)
+ delete meshShape;
}
if (free) {
delete shape;
@@ -634,48 +637,41 @@ bool CcdPhysicsController::DeleteControllerShape( )
bool CcdPhysicsController::ReplaceControllerShape(btCollisionShape *newShape)
{
-
- /* Note, deleting the previous collision shape must be done already */
- /* if (m_collisionShape) DeleteControllerShape(); */
+ if (m_collisionShape)
+ DeleteControllerShape();
+
+ // If newShape is NULL it means to create a new Bullet shape.
+ if (!newShape)
+ newShape = m_shapeInfo->CreateBulletShape(m_cci.m_margin, m_cci.m_bGimpact, !m_cci.m_bSoft);
m_object->setCollisionShape(newShape);
- m_collisionShape= newShape;
- m_cci.m_collisionShape= newShape;
-
- if (GetSoftBody()) {
+ m_collisionShape = newShape;
+ m_cci.m_collisionShape = newShape;
+
+ btSoftBody *softBody = GetSoftBody();
+ if (softBody) {
+ btSoftRigidDynamicsWorld *world = GetPhysicsEnvironment()->GetDynamicsWorld();
+ // remove the old softBody
+ world->removeSoftBody(softBody);
+
// soft body must be recreated
- m_cci.m_physicsEnv->RemoveCcdPhysicsController(this);
delete m_object;
m_object = NULL;
// force complete reinitialization
m_softbodyMappingDone = false;
m_prototypeTransformInitialized = false;
m_softBodyTransformInitialized = false;
+
CreateSoftbody();
assert(m_object);
- // reinsert the new body
- m_cci.m_physicsEnv->AddCcdPhysicsController(this);
- }
-
- /* Copied from CcdPhysicsEnvironment::addCcdPhysicsController() */
-
- /* without this, an object can rest on the old physics mesh
- * and not move to account for the physics mesh, even with 'nosleep' */
- btSoftRigidDynamicsWorld* dw= GetPhysicsEnvironment()->GetDynamicsWorld();
- btCollisionObjectArray &obarr= dw->getCollisionObjectArray();
- btCollisionObject *ob;
- btBroadphaseProxy* proxy;
-
- for (int i= 0; i < obarr.size(); i++) {
- ob= obarr[i];
- if (ob->getCollisionShape() == newShape) {
- proxy = ob->getBroadphaseHandle();
-
- if (proxy)
- dw->getPairCache()->cleanProxyFromPairs(proxy,dw->getDispatcher());
- }
+
+ btSoftBody *newSoftBody = GetSoftBody();
+ // set the user
+ newSoftBody->setUserPointer(this);
+ // add the new softbody
+ world->addSoftBody(newSoftBody);
}
-
+
return true;
}
@@ -850,36 +846,6 @@ void CcdPhysicsController::PostProcessReplica(class PHY_IMotionState* motionsta
m_cci.m_physicsEnv->AddCcdPhysicsController(this);
-/* SM_Object* dynaparent=0;
- SumoPhysicsController* sumoparentctrl = (SumoPhysicsController* )parentctrl;
-
- if (sumoparentctrl)
- {
- dynaparent = sumoparentctrl->GetSumoObject();
- }
-
- SM_Object* orgsumoobject = m_sumoObj;
-
-
- m_sumoObj = new SM_Object(
- orgsumoobject->getShapeHandle(),
- orgsumoobject->getMaterialProps(),
- orgsumoobject->getShapeProps(),
- dynaparent);
-
- m_sumoObj->setRigidBody(orgsumoobject->isRigidBody());
-
- m_sumoObj->setMargin(orgsumoobject->getMargin());
- m_sumoObj->setPosition(orgsumoobject->getPosition());
- m_sumoObj->setOrientation(orgsumoobject->getOrientation());
- //if it is a dyna, register for a callback
- m_sumoObj->registerCallback(*this);
-
- m_sumoScene->add(* (m_sumoObj));
- */
-
-
-
}
void CcdPhysicsController::SetPhysicsEnvironment(class PHY_IPhysicsEnvironment *env)
@@ -1082,6 +1048,25 @@ void CcdPhysicsController::ResolveCombinedVelocities(float linvelX,float linvel
{
}
+void CcdPhysicsController::RefreshCollisions()
+{
+ // the object is in an inactive layer so it's useless to update it and can cause problems
+ if (!GetPhysicsEnvironment()->IsActiveCcdPhysicsController(this))
+ return;
+
+ btSoftRigidDynamicsWorld *dw = GetPhysicsEnvironment()->GetDynamicsWorld();
+ btBroadphaseProxy *proxy = m_object->getBroadphaseHandle();
+ btDispatcher *dispatcher = dw->getDispatcher();
+ btOverlappingPairCache *pairCache = dw->getPairCache();
+
+ CleanPairCallback cleanPairs(proxy, pairCache, dispatcher);
+ pairCache->processAllOverlappingPairs(&cleanPairs, dispatcher);
+
+ // Forcibly recreate the physics object
+ btBroadphaseProxy* handle = m_object->getBroadphaseHandle();
+ GetPhysicsEnvironment()->UpdateCcdPhysicsController(this, GetMass(), m_object->getCollisionFlags(), handle->m_collisionFilterGroup, handle->m_collisionFilterMask);
+}
+
void CcdPhysicsController::SuspendDynamics(bool ghost)
{
btRigidBody *body = GetRigidBody();
@@ -1546,8 +1531,7 @@ void CcdPhysicsController::AddCompoundChild(PHY_IPhysicsController* child)
const btCollisionShape* childShape = childBody->getCollisionShape();
if (!rootShape ||
!childShape ||
- rootShape->getShapeType() != COMPOUND_SHAPE_PROXYTYPE ||
- childShape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE)
+ rootShape->getShapeType() != COMPOUND_SHAPE_PROXYTYPE)
return;
btCompoundShape* compoundShape = (btCompoundShape*)rootShape;
// compute relative transformation between parent and child
@@ -1597,7 +1581,7 @@ void CcdPhysicsController::AddCompoundChild(PHY_IPhysicsController* child)
// must update the broadphase cache,
GetPhysicsEnvironment()->RefreshCcdPhysicsController(this);
// remove the children
- GetPhysicsEnvironment()->DisableCcdPhysicsController(childCtrl);
+ GetPhysicsEnvironment()->RemoveCcdPhysicsController(childCtrl);
}
/* Reverse function of the above, it will remove a shape from a compound shape
@@ -1653,7 +1637,7 @@ void CcdPhysicsController::RemoveCompoundChild(PHY_IPhysicsController* child)
// must update the broadphase cache,
GetPhysicsEnvironment()->RefreshCcdPhysicsController(this);
// reactivate the children
- GetPhysicsEnvironment()->EnableCcdPhysicsController(childCtrl);
+ GetPhysicsEnvironment()->AddCcdPhysicsController(childCtrl);
}
PHY_IPhysicsController* CcdPhysicsController::GetReplica()
@@ -1713,33 +1697,50 @@ PHY_IPhysicsController* CcdPhysicsController::GetReplicaForSensors()
* 2) from_gameobj - creates the phys mesh from the DerivedMesh where possible, else the RAS_MeshObject
* 3) this - update the phys mesh from DerivedMesh or RAS_MeshObject
*
- * Most of the logic behind this is in shapeInfo->UpdateMesh(...)
+ * Most of the logic behind this is in m_shapeInfo->UpdateMesh(...)
*/
bool CcdPhysicsController::ReinstancePhysicsShape(KX_GameObject *from_gameobj, RAS_MeshObject *from_meshobj)
{
- CcdShapeConstructionInfo *shapeInfo;
-
- shapeInfo = this->GetShapeInfo();
-
- if (shapeInfo->m_shapeType != PHY_SHAPE_MESH/* || spc->GetSoftBody()*/)
+ if (m_shapeInfo->m_shapeType != PHY_SHAPE_MESH)
return false;
- this->DeleteControllerShape();
-
- if (from_gameobj==NULL && from_meshobj==NULL)
- from_gameobj = KX_GameObject::GetClientObject((KX_ClientObjectInfo*)this->GetNewClientInfo());
+ if (!from_gameobj && !from_meshobj)
+ from_gameobj = KX_GameObject::GetClientObject((KX_ClientObjectInfo*)GetNewClientInfo());
/* updates the arrays used for making the new bullet mesh */
- shapeInfo->UpdateMesh(from_gameobj, from_meshobj);
+ m_shapeInfo->UpdateMesh(from_gameobj, from_meshobj);
/* create the new bullet mesh */
- CcdConstructionInfo& cci = this->GetConstructionInfo();
- btCollisionShape* bm= shapeInfo->CreateBulletShape(cci.m_margin, cci.m_bGimpact, !cci.m_bSoft);
+ GetPhysicsEnvironment()->UpdateCcdPhysicsControllerShape(m_shapeInfo);
- this->ReplaceControllerShape(bm);
return true;
}
+void CcdPhysicsController::ReplicateConstraints(KX_GameObject *replica, std::vector<KX_GameObject*> constobj)
+{
+ if (replica->GetConstraints().size() == 0 || !replica->GetPhysicsController())
+ return;
+
+ PHY_IPhysicsEnvironment *physEnv = GetPhysicsEnvironment();
+
+ vector<bRigidBodyJointConstraint*> constraints = replica->GetConstraints();
+ vector<bRigidBodyJointConstraint*>::iterator consit;
+
+ /* Object could have some constraints, iterate over all of theme to ensure that every constraint is recreated. */
+ for (consit = constraints.begin(); consit != constraints.end(); ++consit) {
+ /* Try to find the constraint targets in the list of group objects. */
+ bRigidBodyJointConstraint *dat = (*consit);
+ vector<KX_GameObject*>::iterator memit;
+ for (memit = constobj.begin(); memit != constobj.end(); ++memit) {
+ KX_GameObject *member = (*memit);
+ /* If the group member is the actual target for the constraint. */
+ if (dat->tar->id.name + 2 == member->GetName() && member->GetPhysicsController())
+ physEnv->SetupObjectConstraints(replica, member, dat);
+ }
+ }
+
+}
+
///////////////////////////////////////////////////////////
///A small utility class, DefaultMotionState
///
@@ -1821,7 +1822,7 @@ CcdShapeConstructionInfo* CcdShapeConstructionInfo::FindMesh(RAS_MeshObject* mes
return NULL;
}
-bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, bool polytope)
+bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject *meshobj, DerivedMesh *dm, bool polytope)
{
int numpolys, numverts;
@@ -1833,7 +1834,7 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm,
bool free_dm = false;
// No mesh object or mesh has no polys
- if (!meshobj || meshobj->HasColliderPolygon()==false) {
+ if (!meshobj || !meshobj->HasColliderPolygon()) {
m_vertexArray.clear();
m_polygonIndexArray.clear();
m_triFaceArray.clear();
@@ -1856,80 +1857,83 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm,
/* double lookup */
const int *index_mf_to_mpoly = (const int *)dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
const int *index_mp_to_orig = (const int *)dm->getPolyDataArray(dm, CD_ORIGINDEX);
- if (index_mf_to_mpoly == NULL) {
+ if (!index_mf_to_mpoly) {
index_mp_to_orig = NULL;
}
m_shapeType = (polytope) ? PHY_SHAPE_POLYTOPE : PHY_SHAPE_MESH;
/* Convert blender geometry into bullet mesh, need these vars for mapping */
- vector<bool> vert_tag_array(numverts, false);
- unsigned int tot_bt_verts= 0;
+ std::vector<bool> vert_tag_array(numverts, false);
+ unsigned int tot_bt_verts = 0;
- if (polytope)
- {
+ if (polytope) {
// Tag verts we're using
- for (int p2=0; p2<numpolys; p2++)
- {
- MFace* mf = &mface[p2];
+ for (int p2 = 0; p2 < numpolys; p2++) {
+ MFace *mf = &mface[p2];
const int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, p2) : p2;
- RAS_Polygon* poly = meshobj->GetPolygon(origi);
+ RAS_Polygon *poly = meshobj->GetPolygon(origi);
// only add polygons that have the collision flag set
- if (poly->IsCollider())
- {
- if (vert_tag_array[mf->v1] == false) {vert_tag_array[mf->v1] = true; tot_bt_verts++;}
- if (vert_tag_array[mf->v2] == false) {vert_tag_array[mf->v2] = true; tot_bt_verts++;}
- if (vert_tag_array[mf->v3] == false) {vert_tag_array[mf->v3] = true; tot_bt_verts++;}
- if (mf->v4 && vert_tag_array[mf->v4] == false) {vert_tag_array[mf->v4] = true; tot_bt_verts++;}
+ if (poly->IsCollider()) {
+ if (!vert_tag_array[mf->v1]) {
+ vert_tag_array[mf->v1] = true;
+ tot_bt_verts++;
+ }
+ if (!vert_tag_array[mf->v2]) {
+ vert_tag_array[mf->v2] = true;
+ tot_bt_verts++;
+ }
+ if (!vert_tag_array[mf->v3]) {
+ vert_tag_array[mf->v3] = true;
+ tot_bt_verts++;
+ }
+ if (mf->v4 && !vert_tag_array[mf->v4]) {
+ vert_tag_array[mf->v4] = true;
+ tot_bt_verts++;
+ }
}
}
-
+
/* Can happen with ngons */
if (!tot_bt_verts) {
goto cleanup_empty_mesh;
}
- m_vertexArray.resize(tot_bt_verts*3);
+ m_vertexArray.resize(tot_bt_verts * 3);
- btScalar *bt= &m_vertexArray[0];
+ btScalar *bt = &m_vertexArray[0];
- for (int p2=0; p2<numpolys; p2++)
- {
- MFace* mf = &mface[p2];
+ for (int p2 = 0; p2 < numpolys; p2++) {
+ MFace *mf = &mface[p2];
const int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, p2) : p2;
- RAS_Polygon* poly= meshobj->GetPolygon(origi);
+ RAS_Polygon *poly = meshobj->GetPolygon(origi);
// only add polygons that have the collisionflag set
- if (poly->IsCollider())
- {
- if (vert_tag_array[mf->v1]==true)
- {
- const float* vtx = mvert[mf->v1].co;
+ if (poly->IsCollider()) {
+ if (vert_tag_array[mf->v1]) {
+ const float *vtx = mvert[mf->v1].co;
vert_tag_array[mf->v1] = false;
*bt++ = vtx[0];
*bt++ = vtx[1];
*bt++ = vtx[2];
}
- if (vert_tag_array[mf->v2]==true)
- {
- const float* vtx = mvert[mf->v2].co;
+ if (vert_tag_array[mf->v2]) {
+ const float *vtx = mvert[mf->v2].co;
vert_tag_array[mf->v2] = false;
*bt++ = vtx[0];
*bt++ = vtx[1];
*bt++ = vtx[2];
}
- if (vert_tag_array[mf->v3]==true)
- {
- const float* vtx = mvert[mf->v3].co;
+ if (vert_tag_array[mf->v3]) {
+ const float *vtx = mvert[mf->v3].co;
vert_tag_array[mf->v3] = false;
*bt++ = vtx[0];
*bt++ = vtx[1];
*bt++ = vtx[2];
}
- if (mf->v4 && vert_tag_array[mf->v4]==true)
- {
- const float* vtx = mvert[mf->v4].co;
+ if (mf->v4 && vert_tag_array[mf->v4]) {
+ const float *vtx = mvert[mf->v4].co;
vert_tag_array[mf->v4] = false;
*bt++ = vtx[0];
*bt++ = vtx[1];
@@ -1939,28 +1943,38 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm,
}
}
else {
- unsigned int tot_bt_tris= 0;
- vector<int> vert_remap_array(numverts, 0);
-
+ unsigned int tot_bt_tris = 0;
+ std::vector<int> vert_remap_array(numverts, 0);
+
// Tag verts we're using
- for (int p2=0; p2<numpolys; p2++)
- {
- MFace* mf = &mface[p2];
+ for (int p2 = 0; p2 < numpolys; p2++) {
+ MFace *mf = &mface[p2];
const int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, p2) : p2;
- RAS_Polygon* poly= meshobj->GetPolygon(origi);
+ RAS_Polygon *poly = meshobj->GetPolygon(origi);
// only add polygons that have the collision flag set
- if (poly->IsCollider())
- {
- if (vert_tag_array[mf->v1]==false)
- {vert_tag_array[mf->v1] = true;vert_remap_array[mf->v1] = tot_bt_verts;tot_bt_verts++;}
- if (vert_tag_array[mf->v2]==false)
- {vert_tag_array[mf->v2] = true;vert_remap_array[mf->v2] = tot_bt_verts;tot_bt_verts++;}
- if (vert_tag_array[mf->v3]==false)
- {vert_tag_array[mf->v3] = true;vert_remap_array[mf->v3] = tot_bt_verts;tot_bt_verts++;}
- if (mf->v4 && vert_tag_array[mf->v4]==false)
- {vert_tag_array[mf->v4] = true;vert_remap_array[mf->v4] = tot_bt_verts;tot_bt_verts++;}
- tot_bt_tris += (mf->v4 ? 2:1); /* a quad or a tri */
+ if (poly->IsCollider()) {
+ if (!vert_tag_array[mf->v1]) {
+ vert_tag_array[mf->v1] = true;
+ vert_remap_array[mf->v1] = tot_bt_verts;
+ tot_bt_verts++;
+ }
+ if (!vert_tag_array[mf->v2]) {
+ vert_tag_array[mf->v2] = true;
+ vert_remap_array[mf->v2] = tot_bt_verts;
+ tot_bt_verts++;
+ }
+ if (!vert_tag_array[mf->v3]) {
+ vert_tag_array[mf->v3] = true;
+ vert_remap_array[mf->v3] = tot_bt_verts;
+ tot_bt_verts++;
+ }
+ if (mf->v4 && !vert_tag_array[mf->v4]) {
+ vert_tag_array[mf->v4] = true;
+ vert_remap_array[mf->v4] = tot_bt_verts;
+ tot_bt_verts++;
+ }
+ tot_bt_tris += (mf->v4 ? 2 : 1); /* a quad or a tri */
}
}
@@ -1969,43 +1983,39 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm,
goto cleanup_empty_mesh;
}
- m_vertexArray.resize(tot_bt_verts*3);
+ m_vertexArray.resize(tot_bt_verts * 3);
m_polygonIndexArray.resize(tot_bt_tris);
- m_triFaceArray.resize(tot_bt_tris*3);
- btScalar *bt= &m_vertexArray[0];
- int *poly_index_pt= &m_polygonIndexArray[0];
- int *tri_pt= &m_triFaceArray[0];
+ m_triFaceArray.resize(tot_bt_tris * 3);
+ btScalar *bt = &m_vertexArray[0];
+ int *poly_index_pt = &m_polygonIndexArray[0];
+ int *tri_pt = &m_triFaceArray[0];
UVco *uv_pt = NULL;
- if (tface)
- {
- m_triFaceUVcoArray.resize(tot_bt_tris*3);
+ if (tface) {
+ m_triFaceUVcoArray.resize(tot_bt_tris * 3);
uv_pt = &m_triFaceUVcoArray[0];
- }
- else
+ }
+ else
m_triFaceUVcoArray.clear();
- for (int p2=0; p2<numpolys; p2++)
- {
- MFace* mf = &mface[p2];
- MTFace* tf = (tface) ? &tface[p2] : NULL;
+ for (int p2 = 0; p2 < numpolys; p2++) {
+ MFace *mf = &mface[p2];
+ MTFace *tf = (tface) ? &tface[p2] : NULL;
const int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, p2) : p2;
- RAS_Polygon* poly= meshobj->GetPolygon(origi);
+ RAS_Polygon *poly = meshobj->GetPolygon(origi);
// only add polygons that have the collisionflag set
- if (poly->IsCollider())
- {
- MVert *v1= &mvert[mf->v1];
- MVert *v2= &mvert[mf->v2];
- MVert *v3= &mvert[mf->v3];
+ if (poly->IsCollider()) {
+ MVert *v1 = &mvert[mf->v1];
+ MVert *v2 = &mvert[mf->v2];
+ MVert *v3 = &mvert[mf->v3];
// the face indices
tri_pt[0] = vert_remap_array[mf->v1];
tri_pt[1] = vert_remap_array[mf->v2];
tri_pt[2] = vert_remap_array[mf->v3];
- tri_pt= tri_pt+3;
- if (tf)
- {
+ tri_pt = tri_pt + 3;
+ if (tf) {
uv_pt[0].uv[0] = tf->uv[0][0];
uv_pt[0].uv[1] = tf->uv[0][1];
uv_pt[1].uv[0] = tf->uv[1][0];
@@ -2020,19 +2030,19 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm,
poly_index_pt++;
// the vertex location
- if (vert_tag_array[mf->v1]==true) { /* *** v1 *** */
+ if (vert_tag_array[mf->v1]) { /* *** v1 *** */
vert_tag_array[mf->v1] = false;
*bt++ = v1->co[0];
*bt++ = v1->co[1];
*bt++ = v1->co[2];
}
- if (vert_tag_array[mf->v2]==true) { /* *** v2 *** */
+ if (vert_tag_array[mf->v2]) { /* *** v2 *** */
vert_tag_array[mf->v2] = false;
*bt++ = v2->co[0];
*bt++ = v2->co[1];
*bt++ = v2->co[2];
}
- if (vert_tag_array[mf->v3]==true) { /* *** v3 *** */
+ if (vert_tag_array[mf->v3]) { /* *** v3 *** */
vert_tag_array[mf->v3] = false;
*bt++ = v3->co[0];
*bt++ = v3->co[1];
@@ -2041,12 +2051,12 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm,
if (mf->v4)
{
- MVert *v4= &mvert[mf->v4];
+ MVert *v4 = &mvert[mf->v4];
tri_pt[0] = vert_remap_array[mf->v1];
tri_pt[1] = vert_remap_array[mf->v3];
tri_pt[2] = vert_remap_array[mf->v4];
- tri_pt= tri_pt+3;
+ tri_pt = tri_pt + 3;
if (tf)
{
uv_pt[0].uv[0] = tf->uv[0][0];
@@ -2063,7 +2073,7 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm,
poly_index_pt++;
// the vertex location
- if (vert_tag_array[mf->v4] == true) { /* *** v4 *** */
+ if (vert_tag_array[mf->v4]) { /* *** v4 *** */
vert_tag_array[mf->v4] = false;
*bt++ = v4->co[0];
*bt++ = v4->co[1];
@@ -2077,27 +2087,27 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm,
/* If this ever gets confusing, print out an OBJ file for debugging */
#if 0
printf("# vert count %d\n", m_vertexArray.size());
- for (i=0; i<m_vertexArray.size(); i+=1) {
+ for (i = 0; i < m_vertexArray.size(); i += 1) {
printf("v %.6f %.6f %.6f\n", m_vertexArray[i].x(), m_vertexArray[i].y(), m_vertexArray[i].z());
}
printf("# face count %d\n", m_triFaceArray.size());
- for (i=0; i<m_triFaceArray.size(); i+=3) {
- printf("f %d %d %d\n", m_triFaceArray[i]+1, m_triFaceArray[i+1]+1, m_triFaceArray[i+2]+1);
+ for (i = 0; i < m_triFaceArray.size(); i += 3) {
+ printf("f %d %d %d\n", m_triFaceArray[i] + 1, m_triFaceArray[i + 1] + 1, m_triFaceArray[i + 2] + 1);
}
#endif
}
#if 0
- if (validpolys==false)
+ if (validpolys == false)
{
// should not happen
m_shapeType = PHY_SHAPE_NONE;
return false;
}
#endif
-
+
m_meshObject = meshobj;
if (free_dm) {
dm->release(dm);
@@ -2105,10 +2115,9 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm,
}
// sharing only on static mesh at present, if you change that, you must also change in FindMesh
- if (!polytope && !dm)
- {
+ if (!polytope && !dm) {
// triangle shape can be shared, store the mesh object in the map
- m_meshShapeMap.insert(std::pair<RAS_MeshObject*,CcdShapeConstructionInfo*>(meshobj,this));
+ m_meshShapeMap.insert(std::pair<RAS_MeshObject *, CcdShapeConstructionInfo *>(meshobj, this));
}
return true;
@@ -2131,51 +2140,50 @@ cleanup_empty_mesh:
/* Updates the arrays used by CreateBulletShape(),
* take care that recalcLocalAabb() runs after CreateBulletShape is called.
* */
-bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RAS_MeshObject* meshobj)
+bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject *gameobj, class RAS_MeshObject *meshobj)
{
int numpolys;
int numverts;
- unsigned int tot_bt_tris= 0;
- unsigned int tot_bt_verts= 0;
+ unsigned int tot_bt_tris = 0;
+ unsigned int tot_bt_verts = 0;
int i, j;
int v_orig;
/* Use for looping over verts in a face as a try or 2 tris */
- const int quad_verts[7]= {0,1,2, 0,2,3, -1};
- const int tri_verts[4]= {0,1,2, -1};
+ const int quad_verts[7] = {0, 1, 2, 0, 2, 3, -1};
+ const int tri_verts[4] = {0, 1, 2, -1};
const int *fv_pt;
- if (gameobj==NULL && meshobj==NULL)
+ if (!gameobj && !meshobj)
return false;
-
+
if (m_shapeType != PHY_SHAPE_MESH)
return false;
- RAS_Deformer *deformer= gameobj ? gameobj->GetDeformer():NULL;
- DerivedMesh* dm = NULL;
+ RAS_Deformer *deformer = gameobj ? gameobj->GetDeformer() : NULL;
+ DerivedMesh *dm = NULL;
if (deformer)
dm = deformer->GetPhysicsMesh();
-
+
/* get the mesh from the object if not defined */
- if (meshobj==NULL) {
-
+ if (!meshobj) {
/* modifier mesh */
if (dm)
- meshobj= deformer->GetRasMesh();
-
+ meshobj = deformer->GetRasMesh();
+
/* game object first mesh */
- if (meshobj==NULL) {
+ if (!meshobj) {
if (gameobj->GetMeshCount() > 0) {
- meshobj= gameobj->GetMesh(0);
+ meshobj = gameobj->GetMesh(0);
}
}
}
-
- if (dm && deformer->GetRasMesh() == meshobj)
- { /*
+
+ if (dm && deformer->GetRasMesh() == meshobj) {
+ /*
* Derived Mesh Update
*
* */
@@ -2187,41 +2195,38 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA
/* double lookup */
const int *index_mf_to_mpoly = (const int *)dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
- const int *index_mp_to_orig = (const int *)dm->getPolyDataArray(dm, CD_ORIGINDEX);
- if (index_mf_to_mpoly == NULL) {
+ const int *index_mp_to_orig = (const int *)dm->getPolyDataArray(dm, CD_ORIGINDEX);
+ if (!index_mf_to_mpoly) {
index_mp_to_orig = NULL;
}
MFace *mf;
MVert *mv;
- int flen;
-
- if (CustomData_has_layer(&dm->faceData, CD_MTFACE))
- {
+ if (CustomData_has_layer(&dm->faceData, CD_MTFACE)) {
MTFace *tface = (MTFace *)dm->getTessFaceDataArray(dm, CD_MTFACE);
MTFace *tf;
- vector<bool> vert_tag_array(numverts, false);
- vector<int> vert_remap_array(numverts, 0);
+ std::vector<bool> vert_tag_array(numverts, false);
+ std::vector<int> vert_remap_array(numverts, 0);
+
+ for (mf = mface, tf = tface, i = 0; i < numpolys; mf++, tf++, i++) {
+ if (tf->mode & TF_DYNAMIC) {
+ int flen;
- for (mf= mface, tf= tface, i=0; i < numpolys; mf++, tf++, i++) {
- if (tf->mode & TF_DYNAMIC)
- {
if (mf->v4) {
- tot_bt_tris+= 2;
- flen= 4;
- } else {
+ tot_bt_tris += 2;
+ flen = 4;
+ }
+ else {
tot_bt_tris++;
- flen= 3;
+ flen = 3;
}
- for (j=0; j<flen; j++)
- {
+ for (j = 0; j < flen; j++) {
v_orig = (*(&mf->v1 + j));
- if (vert_tag_array[v_orig]==false)
- {
+ if (!vert_tag_array[v_orig]) {
vert_tag_array[v_orig] = true;
vert_remap_array[v_orig] = tot_bt_verts;
tot_bt_verts++;
@@ -2230,42 +2235,38 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA
}
}
- m_vertexArray.resize(tot_bt_verts*3);
- btScalar *bt= &m_vertexArray[0];
+ m_vertexArray.resize(tot_bt_verts * 3);
+ btScalar *bt = &m_vertexArray[0];
- m_triFaceArray.resize(tot_bt_tris*3);
- int *tri_pt= &m_triFaceArray[0];
+ m_triFaceArray.resize(tot_bt_tris * 3);
+ int *tri_pt = &m_triFaceArray[0];
- m_triFaceUVcoArray.resize(tot_bt_tris*3);
- UVco *uv_pt= &m_triFaceUVcoArray[0];
+ m_triFaceUVcoArray.resize(tot_bt_tris * 3);
+ UVco *uv_pt = &m_triFaceUVcoArray[0];
m_polygonIndexArray.resize(tot_bt_tris);
- int *poly_index_pt= &m_polygonIndexArray[0];
+ int *poly_index_pt = &m_polygonIndexArray[0];
- for (mf= mface, tf= tface, i=0; i < numpolys; mf++, tf++, i++)
- {
- if (tf->mode & TF_DYNAMIC)
- {
+ for (mf = mface, tf = tface, i = 0; i < numpolys; mf++, tf++, i++) {
+ if (tf->mode & TF_DYNAMIC) {
int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, i) : i;
if (mf->v4) {
- fv_pt= quad_verts;
+ fv_pt = quad_verts;
*poly_index_pt++ = origi;
*poly_index_pt++ = origi;
- flen= 4;
- } else {
- fv_pt= tri_verts;
+ }
+ else {
+ fv_pt = tri_verts;
*poly_index_pt++ = origi;
- flen= 3;
}
- for (; *fv_pt > -1; fv_pt++)
- {
+ for (; *fv_pt > -1; fv_pt++) {
v_orig = (*(&mf->v1 + (*fv_pt)));
if (vert_tag_array[v_orig])
{
- mv= mvert + v_orig;
+ mv = mvert + v_orig;
*bt++ = mv->co[0];
*bt++ = mv->co[1];
*bt++ = mv->co[2];
@@ -2283,37 +2284,37 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA
else {
/* no need for a vertex mapping. simple/fast */
- tot_bt_verts= numverts;
+ tot_bt_verts = numverts;
- for (mf= mface, i=0; i < numpolys; mf++, i++) {
- tot_bt_tris += (mf->v4 ? 2:1);
+ for (mf = mface, i = 0; i < numpolys; mf++, i++) {
+ tot_bt_tris += (mf->v4 ? 2 : 1);
}
- m_vertexArray.resize(tot_bt_verts*3);
- btScalar *bt= &m_vertexArray[0];
+ m_vertexArray.resize(tot_bt_verts * 3);
+ btScalar *bt = &m_vertexArray[0];
- m_triFaceArray.resize(tot_bt_tris*3);
- int *tri_pt= &m_triFaceArray[0];
+ m_triFaceArray.resize(tot_bt_tris * 3);
+ int *tri_pt = &m_triFaceArray[0];
m_polygonIndexArray.resize(tot_bt_tris);
- int *poly_index_pt= &m_polygonIndexArray[0];
+ int *poly_index_pt = &m_polygonIndexArray[0];
m_triFaceUVcoArray.clear();
- for (mv= mvert, i=0; i < numverts; mv++, i++) {
+ for (mv = mvert, i = 0; i < numverts; mv++, i++) {
*bt++ = mv->co[0]; *bt++ = mv->co[1]; *bt++ = mv->co[2];
}
- for (mf= mface, i=0; i < numpolys; mf++, i++) {
+ for (mf = mface, i = 0; i < numpolys; mf++, i++) {
int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, i) : i;
if (mf->v4) {
- fv_pt= quad_verts;
+ fv_pt = quad_verts;
*poly_index_pt++ = origi;
*poly_index_pt++ = origi;
}
else {
- fv_pt= tri_verts;
+ fv_pt = tri_verts;
*poly_index_pt++ = origi;
}
@@ -2322,51 +2323,46 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA
}
}
}
- else { /*
- * RAS Mesh Update
- *
- * */
-
+ else { /*
+ * RAS Mesh Update
+ *
+ * */
/* Note!, gameobj can be NULL here */
/* transverts are only used for deformed RAS_Meshes, the RAS_TexVert data
* is too hard to get at, see below for details */
- float (*transverts)[3] = NULL;
- int transverts_tot= 0; /* with deformed meshes - should always be greater than the max orginal index, or we get crashes */
+ float(*transverts)[3] = NULL;
+ int transverts_tot = 0; /* with deformed meshes - should always be greater than the max orginal index, or we get crashes */
if (deformer) {
/* map locations from the deformed array
*
* Could call deformer->Update(); but rely on redraw updating.
* */
- transverts= deformer->GetTransVerts(&transverts_tot);
+ transverts = deformer->GetTransVerts(&transverts_tot);
}
// Tag verts we're using
- numpolys= meshobj->NumPolygons();
- numverts= meshobj->m_sharedvertex_map.size();
+ numpolys = meshobj->NumPolygons();
+ numverts = meshobj->m_sharedvertex_map.size();
const float *xyz;
- vector<bool> vert_tag_array(numverts, false);
- vector<int> vert_remap_array(numverts, 0);
+ std::vector<bool> vert_tag_array(numverts, false);
+ std::vector<int> vert_remap_array(numverts, 0);
- for (int p=0; p<numpolys; p++)
- {
- RAS_Polygon* poly= meshobj->GetPolygon(p);
- if (poly->IsCollider())
- {
- for (i=0; i < poly->VertexCount(); i++)
- {
- v_orig= poly->GetVertex(i)->getOrigIndex();
- if (vert_tag_array[v_orig]==false)
- {
+ for (int p = 0; p < numpolys; p++) {
+ RAS_Polygon *poly = meshobj->GetPolygon(p);
+ if (poly->IsCollider()) {
+ for (i = 0; i < poly->VertexCount(); i++) {
+ v_orig = poly->GetVertex(i)->getOrigIndex();
+ if (!vert_tag_array[v_orig]) {
vert_tag_array[v_orig] = true;
vert_remap_array[v_orig] = tot_bt_verts;
tot_bt_verts++;
}
}
- tot_bt_tris += (poly->VertexCount()==4 ? 2:1);
+ tot_bt_tris += (poly->VertexCount() == 4 ? 2 : 1);
}
}
@@ -2374,32 +2370,29 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA
if (tot_bt_tris == 0 || tot_bt_verts == 0)
return false;
- m_vertexArray.resize(tot_bt_verts*3);
- btScalar *bt= &m_vertexArray[0];
+ m_vertexArray.resize(tot_bt_verts * 3);
+ btScalar *bt = &m_vertexArray[0];
- m_triFaceArray.resize(tot_bt_tris*3);
- int *tri_pt= &m_triFaceArray[0];
+ m_triFaceArray.resize(tot_bt_tris * 3);
+ int *tri_pt = &m_triFaceArray[0];
/* cant be used for anything useful in this case, since we don't rely on the original mesh
* will just be an array like pythons range(tot_bt_tris) */
m_polygonIndexArray.resize(tot_bt_tris);
- for (int p=0; p<numpolys; p++)
- {
- RAS_Polygon* poly= meshobj->GetPolygon(p);
+ int p = 0;
+ int t = 0;
+ while (t < tot_bt_tris) {
+ RAS_Polygon *poly = meshobj->GetPolygon(p);
- if (poly->IsCollider())
- {
+ if (poly->IsCollider()) {
/* quad or tri loop */
- fv_pt= (poly->VertexCount()==3 ? tri_verts:quad_verts);
+ fv_pt = (poly->VertexCount() == 3 ? tri_verts : quad_verts);
- for (; *fv_pt > -1; fv_pt++)
- {
- v_orig= poly->GetVertex(*fv_pt)->getOrigIndex();
-
- if (vert_tag_array[v_orig])
- {
+ for (; *fv_pt > -1; fv_pt++) {
+ v_orig = poly->GetVertex(*fv_pt)->getOrigIndex();
+ if (vert_tag_array[v_orig]) {
if (transverts) {
/* deformed mesh, using RAS_TexVert locations would be too troublesome
* because they are use the gameob as a hash in the material slot */
@@ -2409,55 +2402,60 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA
}
else {
/* static mesh python may have modified */
- xyz= meshobj->GetVertexLocation( v_orig );
+ xyz = meshobj->GetVertexLocation(v_orig);
*bt++ = xyz[0];
*bt++ = xyz[1];
*bt++ = xyz[2];
}
-
vert_tag_array[v_orig] = false;
}
-
*tri_pt++ = vert_remap_array[v_orig];
}
}
-
- m_polygonIndexArray[p] = p; /* dumb counting */
+ // first triangle
+ m_polygonIndexArray[t] = p;
+
+ // if the poly is a quad we transform it in two triangles
+ if (poly->VertexCount() == 4) {
+ t++;
+ // second triangle
+ m_polygonIndexArray[t] = p;
+ }
+ t++;
+ p++;
}
}
-
+
#if 0
/* needs #include <cstdio> */
printf("# vert count %d\n", m_vertexArray.size());
- for (int i=0; i<m_vertexArray.size(); i+=3) {
- printf("v %.6f %.6f %.6f\n", m_vertexArray[i], m_vertexArray[i+1], m_vertexArray[i+2]);
+ for (int i = 0; i < m_vertexArray.size(); i += 3) {
+ printf("v %.6f %.6f %.6f\n", m_vertexArray[i], m_vertexArray[i + 1], m_vertexArray[i + 2]);
}
printf("# face count %d\n", m_triFaceArray.size());
- for (int i=0; i<m_triFaceArray.size(); i+=3) {
- printf("f %d %d %d\n", m_triFaceArray[i]+1, m_triFaceArray[i+1]+1, m_triFaceArray[i+2]+1);
+ for (int i = 0; i < m_triFaceArray.size(); i += 3) {
+ printf("f %d %d %d\n", m_triFaceArray[i] + 1, m_triFaceArray[i + 1] + 1, m_triFaceArray[i + 2] + 1);
}
#endif
- /* force recreation of the m_unscaledShape.
+ /* force recreation of the m_triangleIndexVertexArray.
* If this has multiple users we cant delete */
- if (m_unscaledShape) {
- // don't free now so it can re-allocate under the same location and not break pointers.
- // DeleteBulletShape(m_unscaledShape);
- m_forceReInstance= true;
+ if (m_triangleIndexVertexArray) {
+ m_forceReInstance = true;
}
// Make sure to also replace the mesh in the shape map! Otherwise we leave dangling references when we free.
// Note, this whole business could cause issues with shared meshes. If we update one mesh, do we replace
// them all?
- std::map<RAS_MeshObject*,CcdShapeConstructionInfo*>::iterator mit = m_meshShapeMap.find(m_meshObject);
+ std::map<RAS_MeshObject *, CcdShapeConstructionInfo *>::iterator mit = m_meshShapeMap.find(m_meshObject);
if (mit != m_meshShapeMap.end()) {
m_meshShapeMap.erase(mit);
m_meshShapeMap[meshobj] = this;
}
- m_meshObject= meshobj;
-
+ m_meshObject = meshobj;
+
if (dm) {
dm->needsFree = 1;
dm->release(dm);
@@ -2465,8 +2463,6 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA
return true;
}
-
-
bool CcdShapeConstructionInfo::SetProxy(CcdShapeConstructionInfo* shapeInfo)
{
if (shapeInfo == NULL)
@@ -2529,74 +2525,61 @@ btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape(btScalar margin, b
// 9 multiplications/additions and one function call for each triangle that passes the mid phase filtering
// One possible optimization is to use directly the btBvhTriangleMeshShape when the scale is 1,1,1
// and btScaledBvhTriangleMeshShape otherwise.
- if (useGimpact)
- {
- btTriangleIndexVertexArray* indexVertexArrays = new btTriangleIndexVertexArray(
+ if (useGimpact) {
+ if (!m_triangleIndexVertexArray || m_forceReInstance) {
+ if (m_triangleIndexVertexArray)
+ delete m_triangleIndexVertexArray;
+
+ m_triangleIndexVertexArray = new btTriangleIndexVertexArray(
m_polygonIndexArray.size(),
- &m_triFaceArray[0],
- 3*sizeof(int),
- m_vertexArray.size()/3,
+ m_triFaceArray.data(),
+ 3 * sizeof(int),
+ m_vertexArray.size() / 3,
&m_vertexArray[0],
- 3*sizeof(btScalar)
- );
- btGImpactMeshShape* gimpactShape = new btGImpactMeshShape(indexVertexArrays);
- gimpactShape->setMargin(margin);
- gimpactShape->updateBound();
- collisionShape = gimpactShape;
-
-
- } else
- {
- if (!m_unscaledShape || m_forceReInstance)
- {
-
- btTriangleIndexVertexArray* indexVertexArrays = 0;
+ 3 * sizeof(btScalar));
+ m_forceReInstance = false;
+ }
+ btGImpactMeshShape *gimpactShape = new btGImpactMeshShape(m_triangleIndexVertexArray);
+ gimpactShape->setMargin(margin);
+ gimpactShape->updateBound();
+ collisionShape = gimpactShape;
+ }
+ else {
+ if (!m_triangleIndexVertexArray || m_forceReInstance) {
///enable welding, only for the objects that need it (such as soft bodies)
- if (0.f != m_weldingThreshold1)
- {
- btTriangleMesh* collisionMeshData = new btTriangleMesh(true,false);
+ if (0.0f != m_weldingThreshold1) {
+ btTriangleMesh *collisionMeshData = new btTriangleMesh(true, false);
collisionMeshData->m_weldingThreshold = m_weldingThreshold1;
- bool removeDuplicateVertices=true;
+ bool removeDuplicateVertices = true;
// m_vertexArray not in multiple of 3 anymore, use m_triFaceArray
- for (unsigned int i=0; i<m_triFaceArray.size(); i+=3) {
- btScalar *bt = &m_vertexArray[3*m_triFaceArray[i]];
+ for (unsigned int i = 0; i < m_triFaceArray.size(); i += 3) {
+ btScalar *bt = &m_vertexArray[3 * m_triFaceArray[i]];
btVector3 v1(bt[0], bt[1], bt[2]);
- bt = &m_vertexArray[3*m_triFaceArray[i+1]];
+ bt = &m_vertexArray[3 * m_triFaceArray[i + 1]];
btVector3 v2(bt[0], bt[1], bt[2]);
- bt = &m_vertexArray[3*m_triFaceArray[i+2]];
+ bt = &m_vertexArray[3 * m_triFaceArray[i + 2]];
btVector3 v3(bt[0], bt[1], bt[2]);
collisionMeshData->addTriangle(v1, v2, v3, removeDuplicateVertices);
}
- indexVertexArrays = collisionMeshData;
-
- } else
- {
- indexVertexArrays = new btTriangleIndexVertexArray(
+ m_triangleIndexVertexArray = collisionMeshData;
+ }
+ else {
+ m_triangleIndexVertexArray = new btTriangleIndexVertexArray(
m_polygonIndexArray.size(),
- &m_triFaceArray[0],
- 3*sizeof(int),
- m_vertexArray.size()/3,
+ m_triFaceArray.data(),
+ 3 * sizeof(int),
+ m_vertexArray.size() / 3,
&m_vertexArray[0],
- 3*sizeof(btScalar));
- }
-
- // this shape will be shared and not deleted until shapeInfo is deleted
-
- // for UpdateMesh, reuse the last memory location so instancing wont crash.
- if (m_unscaledShape) {
- DeleteBulletShape(m_unscaledShape, false);
- m_unscaledShape->~btBvhTriangleMeshShape();
- m_unscaledShape = new(m_unscaledShape) btBvhTriangleMeshShape( indexVertexArrays, true, useBvh );
- } else {
- m_unscaledShape = new btBvhTriangleMeshShape( indexVertexArrays, true, useBvh );
+ 3 * sizeof(btScalar));
}
- m_forceReInstance= false;
- } else if (useBvh && m_unscaledShape->getOptimizedBvh() == NULL) {
- // the existing unscaledShape was not build with Bvh, do it now
- m_unscaledShape->buildOptimizedBvh();
+
+ m_forceReInstance = false;
}
- collisionShape = new btScaledBvhTriangleMeshShape(m_unscaledShape, btVector3(1.0f,1.0f,1.0f));
+
+ btBvhTriangleMeshShape *unscaledShape = new btBvhTriangleMeshShape(m_triangleIndexVertexArray, true, useBvh);
+ unscaledShape->setMargin(margin);
+ collisionShape = new btScaledBvhTriangleMeshShape(unscaledShape, btVector3(1.0f, 1.0f, 1.0f));
collisionShape->setMargin(margin);
}
break;
@@ -2638,10 +2621,9 @@ CcdShapeConstructionInfo::~CcdShapeConstructionInfo()
(*sit)->Release();
}
m_shapeArray.clear();
- if (m_unscaledShape)
- {
- DeleteBulletShape(m_unscaledShape, true);
- }
+
+ if (m_triangleIndexVertexArray)
+ delete m_triangleIndexVertexArray;
m_vertexArray.clear();
if (m_shapeType == PHY_SHAPE_MESH && m_meshObject != NULL)
{
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h
index de40624d7bb..b1d38763fbb 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h
@@ -79,7 +79,7 @@ public:
m_userData(NULL),
m_refCount(1),
m_meshObject(NULL),
- m_unscaledShape(NULL),
+ m_triangleIndexVertexArray(NULL),
m_forceReInstance(false),
m_weldingThreshold1(0.f),
m_shapeProxy(NULL)
@@ -110,10 +110,11 @@ public:
void AddShape(CcdShapeConstructionInfo* shapeInfo);
- btTriangleMeshShape* GetMeshShape(void)
+ btStridingMeshInterface *GetMeshInterface()
{
- return (m_unscaledShape);
+ return m_triangleIndexVertexArray;
}
+
CcdShapeConstructionInfo* GetChildShape(int i)
{
if (i < 0 || i >= (int)m_shapeArray.size())
@@ -195,8 +196,8 @@ protected:
int m_refCount; // this class is shared between replicas
// keep track of users so that we can release it
RAS_MeshObject* m_meshObject; // Keep a pointer to the original mesh
- btBvhTriangleMeshShape* m_unscaledShape;// holds the shared unscale BVH mesh shape,
- // the actual shape is of type btScaledBvhTriangleMeshShape
+ // The list of vertexes and indexes for the triangle mesh, shared between Bullet shape.
+ btTriangleIndexVertexArray *m_triangleIndexVertexArray;
std::vector<CcdShapeConstructionInfo*> m_shapeArray; // for compound shapes
bool m_forceReInstance; //use gimpact for concave dynamic/moving collision detection
float m_weldingThreshold1; //welding closeby vertices together can improve softbody stability etc.
@@ -447,6 +448,23 @@ public:
#endif
};
+class CleanPairCallback : public btOverlapCallback
+{
+ btBroadphaseProxy *m_cleanProxy;
+ btOverlappingPairCache *m_pairCache;
+ btDispatcher *m_dispatcher;
+
+public:
+ CleanPairCallback(btBroadphaseProxy *cleanProxy, btOverlappingPairCache *pairCache, btDispatcher *dispatcher)
+ :m_cleanProxy(cleanProxy),
+ m_pairCache(pairCache),
+ m_dispatcher(dispatcher)
+ {
+ }
+
+ virtual bool processOverlap(btBroadphasePair &pair);
+};
+
///CcdPhysicsController is a physics object that supports continuous collision detection and time of impact based physics resolution.
class CcdPhysicsController : public PHY_IPhysicsController
{
@@ -498,6 +516,11 @@ protected:
return (--m_registerCount == 0) ? true : false;
}
+ bool Registered() const
+ {
+ return (m_registerCount != 0);
+ }
+
void addCcdConstraintRef(btTypedConstraint* c);
void removeCcdConstraintRef(btTypedConstraint* c);
btTypedConstraint* getCcdConstraintRef(int index);
@@ -513,7 +536,15 @@ protected:
CcdPhysicsController (const CcdConstructionInfo& ci);
+ /**
+ * Delete the current Bullet shape used in the rigid body.
+ */
bool DeleteControllerShape();
+
+ /**
+ * Delete the old Bullet shape and set the new Bullet shape : newShape
+ * \param newShape The new Bullet shape to set, if is NULL we create a new Bullet shape
+ */
bool ReplaceControllerShape(btCollisionShape *newShape);
virtual ~CcdPhysicsController();
@@ -598,7 +629,7 @@ protected:
virtual void ResolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ);
-
+ virtual void RefreshCollisions();
virtual void SuspendDynamics(bool ghost);
virtual void RestoreDynamics();
@@ -626,8 +657,12 @@ protected:
virtual void CalcXform() {}
virtual void SetMargin(float margin)
{
- if (m_collisionShape)
- m_collisionShape->setMargin(btScalar(margin));
+ if (m_collisionShape) {
+ m_collisionShape->setMargin(margin);
+ // if the shape use a unscaled shape we have also to set the correct margin in it
+ if (m_collisionShape->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE)
+ ((btScaledBvhTriangleMeshShape *)m_collisionShape)->getChildShape()->setMargin(margin);
+ }
}
virtual float GetMargin() const
{
@@ -712,6 +747,11 @@ protected:
return GetConstructionInfo().m_bDyna;
}
+ virtual bool IsSuspended() const
+ {
+ return m_suspended;
+ }
+
virtual bool IsCompound()
{
return GetConstructionInfo().m_shapeInfo->m_shapeType == PHY_SHAPE_COMPOUND;
@@ -719,6 +759,9 @@ protected:
virtual bool ReinstancePhysicsShape(KX_GameObject *from_gameobj, RAS_MeshObject* from_meshobj);
+ /* Method to replicate rigid body joint contraints for group instances. */
+ virtual void ReplicateConstraints(KX_GameObject *gameobj, std::vector<KX_GameObject*> constobj);
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GE:CcdPhysicsController")
#endif
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
index ac74029fbe3..3670d79a01e 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
@@ -461,6 +461,19 @@ m_scalingPropagated(false)
void CcdPhysicsEnvironment::AddCcdPhysicsController(CcdPhysicsController* ctrl)
{
+ // the controller is already added we do nothing
+ if (!m_controllers.insert(ctrl).second) {
+ return;
+ }
+
+ /* In the case of compound child controller (see also RemoveCcdPhysicsController)
+ * we add the controller to the trigger controlers list : m_triggerControllers
+ * if it use collision callbacks.
+ */
+ if (ctrl->Registered()) {
+ m_triggerControllers.insert(ctrl);
+ }
+
btRigidBody* body = ctrl->GetRigidBody();
btCollisionObject* obj = ctrl->GetCollisionObject();
@@ -469,8 +482,6 @@ void CcdPhysicsEnvironment::AddCcdPhysicsController(CcdPhysicsController* ctrl)
if (body)
body->setGravity( m_gravity );
- m_controllers.insert(ctrl);
-
if (body)
{
//use explicit group/filter for finer control over collision in bullet => near/radar sensor
@@ -505,10 +516,32 @@ void CcdPhysicsEnvironment::AddCcdPhysicsController(CcdPhysicsController* ctrl)
bool CcdPhysicsEnvironment::RemoveCcdPhysicsController(CcdPhysicsController* ctrl)
{
+ // if the physics controller is already removed we do nothing
+ if (!m_controllers.erase(ctrl)) {
+ return false;
+ }
+
+ /* In the case of compound child controller which use collision callbacks
+ * we remove it from the m_triggerControllers list but leave m_registerCount
+ * to know in AddCcdPhysicsController if we have to add it in m_triggerControllers
+ * and to avoid an useless added in RequestCollisionCallback, indeed we can't register
+ * more than one time a controller.
+ */
+ if (ctrl->Registered()) {
+ m_triggerControllers.erase(ctrl);
+ }
+
//also remove constraint
btRigidBody* body = ctrl->GetRigidBody();
if (body)
{
+ btBroadphaseProxy *proxy = ctrl->GetCollisionObject()->getBroadphaseHandle();
+ btDispatcher *dispatcher = m_dynamicsWorld->getDispatcher();
+ btOverlappingPairCache *pairCache = m_dynamicsWorld->getPairCache();
+
+ CleanPairCallback cleanPairs(proxy, pairCache, dispatcher);
+ pairCache->processAllOverlappingPairs(&cleanPairs, dispatcher);
+
for (int i = ctrl->getNumCcdConstraintRefs() - 1; i >= 0; i--)
{
btTypedConstraint* con = ctrl->getCcdConstraintRef(i);
@@ -548,13 +581,8 @@ bool CcdPhysicsEnvironment::RemoveCcdPhysicsController(CcdPhysicsController* ctr
}
}
}
- if (ctrl->m_registerCount != 0)
- printf("Warning: removing controller with non-zero m_registerCount: %d\n", ctrl->m_registerCount);
-
- //remove it from the triggers
- m_triggerControllers.erase(ctrl);
- return (m_controllers.erase(ctrl) != 0);
+ return true;
}
void CcdPhysicsEnvironment::UpdateCcdPhysicsController(CcdPhysicsController* ctrl, btScalar newMass, int newCollisionFlags, short int newCollisionGroup, short int newCollisionMask)
@@ -562,6 +590,7 @@ void CcdPhysicsEnvironment::UpdateCcdPhysicsController(CcdPhysicsController* ctr
// this function is used when the collisionning group of a controller is changed
// remove and add the collistioning object
btRigidBody* body = ctrl->GetRigidBody();
+ btSoftBody *softBody = ctrl->GetSoftBody();
btCollisionObject* obj = ctrl->GetCollisionObject();
if (obj)
{
@@ -575,6 +604,9 @@ void CcdPhysicsEnvironment::UpdateCcdPhysicsController(CcdPhysicsController* ctr
body->setMassProps(newMass, inertia);
m_dynamicsWorld->addRigidBody(body, newCollisionGroup, newCollisionMask);
}
+ else if (softBody) {
+ m_dynamicsWorld->addSoftBody(softBody);
+ }
else {
m_dynamicsWorld->addCollisionObject(obj, newCollisionGroup, newCollisionMask);
}
@@ -586,43 +618,6 @@ void CcdPhysicsEnvironment::UpdateCcdPhysicsController(CcdPhysicsController* ctr
ctrl->m_cci.m_collisionFlags = newCollisionFlags;
}
-void CcdPhysicsEnvironment::EnableCcdPhysicsController(CcdPhysicsController* ctrl)
-{
- if (m_controllers.insert(ctrl).second)
- {
- btCollisionObject* obj = ctrl->GetCollisionObject();
- obj->setUserPointer(ctrl);
- // update the position of the object from the user
- if (ctrl->GetMotionState())
- {
- btTransform xform = CcdPhysicsController::GetTransformFromMotionState(ctrl->GetMotionState());
- ctrl->SetCenterOfMassTransform(xform);
- }
- m_dynamicsWorld->addCollisionObject(obj,
- ctrl->GetCollisionFilterGroup(), ctrl->GetCollisionFilterMask());
- }
-}
-
-void CcdPhysicsEnvironment::DisableCcdPhysicsController(CcdPhysicsController* ctrl)
-{
- if (m_controllers.erase(ctrl))
- {
- btRigidBody* body = ctrl->GetRigidBody();
- if (body)
- {
- m_dynamicsWorld->removeRigidBody(body);
- } else
- {
- if (ctrl->GetSoftBody())
- {
- } else
- {
- m_dynamicsWorld->removeCollisionObject(ctrl->GetCollisionObject());
- }
- }
- }
-}
-
void CcdPhysicsEnvironment::RefreshCcdPhysicsController(CcdPhysicsController* ctrl)
{
btCollisionObject* obj = ctrl->GetCollisionObject();
@@ -636,6 +631,11 @@ void CcdPhysicsEnvironment::RefreshCcdPhysicsController(CcdPhysicsController* ct
}
}
+bool CcdPhysicsEnvironment::IsActiveCcdPhysicsController(CcdPhysicsController *ctrl)
+{
+ return (m_controllers.find(ctrl) != m_controllers.end());
+}
+
void CcdPhysicsEnvironment::AddCcdGraphicController(CcdGraphicController* ctrl)
{
if (m_cullingTree && !ctrl->GetBroadphaseHandle())
@@ -671,6 +671,19 @@ void CcdPhysicsEnvironment::RemoveCcdGraphicController(CcdGraphicController* ctr
}
}
+void CcdPhysicsEnvironment::UpdateCcdPhysicsControllerShape(CcdShapeConstructionInfo *shapeInfo)
+{
+ for (std::set<CcdPhysicsController *>::iterator it = m_controllers.begin(); it != m_controllers.end(); ++it) {
+ CcdPhysicsController *ctrl = *it;
+
+ if (ctrl->GetShapeInfo() != shapeInfo)
+ continue;
+
+ ctrl->ReplaceControllerShape(NULL);
+ RefreshCcdPhysicsController(ctrl);
+ }
+}
+
void CcdPhysicsEnvironment::BeginFrame()
{
@@ -752,8 +765,8 @@ public:
void CcdPhysicsEnvironment::ProcessFhSprings(double curTime,float interval)
{
std::set<CcdPhysicsController*>::iterator it;
- // dynamic of Fh spring is based on a timestep of 1/60
- int numIter = (int)(interval*60.0001f);
+ // Add epsilon to the tick rate for numerical stability
+ int numIter = (int)(interval*(KX_KetsjiEngine::GetTicRate() + 0.001f));
for (it=m_controllers.begin(); it!=m_controllers.end(); it++)
{
@@ -1156,17 +1169,8 @@ static bool GetHitTriangle(btCollisionShape* shape, CcdShapeConstructionInfo* sh
int indexstride;
int numfaces;
PHY_ScalarType indicestype;
- btStridingMeshInterface* meshInterface = NULL;
- btTriangleMeshShape* triangleShape = shapeInfo->GetMeshShape();
+ btStridingMeshInterface* meshInterface = shapeInfo->GetMeshInterface();
- if (triangleShape)
- meshInterface = triangleShape->getMeshInterface();
- else
- {
- // other possibility is gImpact
- if (shape->getShapeType() == GIMPACT_SHAPE_PROXYTYPE)
- meshInterface = (static_cast<btGImpactMeshShape*>(shape))->getMeshInterface();
- }
if (!meshInterface)
return false;
@@ -2188,15 +2192,8 @@ btTypedConstraint* CcdPhysicsEnvironment::GetConstraintById(int constraintId)
void CcdPhysicsEnvironment::AddSensor(PHY_IPhysicsController* ctrl)
{
-
CcdPhysicsController* ctrl1 = (CcdPhysicsController* )ctrl;
- // addSensor() is a "light" function for bullet because it is used
- // dynamically when the sensor is activated. Use enableCcdPhysicsController() instead
- //if (m_controllers.insert(ctrl1).second)
- //{
- // addCcdPhysicsController(ctrl1);
- //}
- EnableCcdPhysicsController(ctrl1);
+ AddCcdPhysicsController(ctrl1);
}
bool CcdPhysicsEnvironment::RemoveCollisionCallback(PHY_IPhysicsController* ctrl)
@@ -2211,7 +2208,7 @@ bool CcdPhysicsEnvironment::RemoveCollisionCallback(PHY_IPhysicsController* ctrl
void CcdPhysicsEnvironment::RemoveSensor(PHY_IPhysicsController* ctrl)
{
- DisableCcdPhysicsController((CcdPhysicsController*)ctrl);
+ RemoveCcdPhysicsController((CcdPhysicsController*)ctrl);
}
void CcdPhysicsEnvironment::AddTouchCallback(int response_class, PHY_ResponseCallback callback, void *user)
@@ -2644,9 +2641,6 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl
if (!rb0)
return 0;
- // If either of the controllers is missing, we can't do anything.
- if (!c0 || !c1) return 0;
-
btVector3 pivotInB = rb1 ? rb1->getCenterOfMassTransform().inverse()(rb0->getCenterOfMassTransform()(pivotInA)) :
rb0->getCenterOfMassTransform() * pivotInA;
btVector3 axisInA(axisX,axisY,axisZ);
@@ -2658,6 +2652,8 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl
{
case PHY_POINT2POINT_CONSTRAINT:
{
+ // If either of the controllers is missing, we can't do anything.
+ if (!c0 || !c1) return 0;
btPoint2PointConstraint* p2p = 0;
@@ -2686,6 +2682,9 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl
case PHY_GENERIC_6DOF_CONSTRAINT:
{
+ // If either of the controllers is missing, we can't do anything.
+ if (!c0 || !c1) return 0;
+
btGeneric6DofConstraint* genericConstraint = 0;
if (rb1)
@@ -2739,7 +2738,7 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl
*rb0,s_fixedObject2,
frameInA,frameInB,useReferenceFrameA);
}
-
+
if (genericConstraint)
{
//m_constraints.push_back(genericConstraint);
@@ -2756,6 +2755,9 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl
}
case PHY_CONE_TWIST_CONSTRAINT:
{
+ // If either of the controllers is missing, we can't do anything.
+ if (!c0 || !c1) return 0;
+
btConeTwistConstraint* coneTwistContraint = 0;
@@ -2807,7 +2809,7 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl
*rb0,s_fixedObject2,
frameInA,frameInB);
}
-
+
if (coneTwistContraint)
{
//m_constraints.push_back(genericConstraint);
@@ -2830,6 +2832,9 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl
case PHY_LINEHINGE_CONSTRAINT:
{
+ // If either of the controllers is missing, we can't do anything.
+ if (!c0 || !c1) return 0;
+
btHingeConstraint* hinge = 0;
if (rb1)
@@ -3517,20 +3522,23 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject
if (isbulletdyna)
gameobj->SetRecordAnimation(true);
+ physicscontroller->SetNewClientInfo(gameobj->getClientInfo());
+
// don't add automatically sensor object, they are added when a collision sensor is registered
if (!isbulletsensor && (blenderobject->lay & activeLayerBitInfo) != 0)
{
this->AddCcdPhysicsController( physicscontroller);
}
- physicscontroller->SetNewClientInfo(gameobj->getClientInfo());
+
{
btRigidBody* rbody = physicscontroller->GetRigidBody();
if (rbody)
{
+ rbody->setLinearFactor(ci.m_linearFactor);
+
if (isbulletrigidbody)
{
- rbody->setLinearFactor(ci.m_linearFactor);
rbody->setAngularFactor(ci.m_angularFactor);
}
@@ -3591,3 +3599,79 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject
}
#endif
}
+
+
+void CcdPhysicsEnvironment::SetupObjectConstraints(KX_GameObject *obj_src, KX_GameObject *obj_dest,
+ bRigidBodyJointConstraint *dat)
+{
+ PHY_IPhysicsController *phy_src = obj_src->GetPhysicsController();
+ PHY_IPhysicsController *phy_dest = obj_dest->GetPhysicsController();
+ PHY_IPhysicsEnvironment *phys_env = obj_src->GetScene()->GetPhysicsEnvironment();
+
+ /* We need to pass a full constraint frame, not just axis. */
+ MT_Matrix3x3 localCFrame(MT_Vector3(dat->axX,dat->axY,dat->axZ));
+ MT_Vector3 axis0 = localCFrame.getColumn(0);
+ MT_Vector3 axis1 = localCFrame.getColumn(1);
+ MT_Vector3 axis2 = localCFrame.getColumn(2);
+ MT_Vector3 scale = obj_src->NodeGetWorldScaling();
+
+ /* Apply not only the pivot and axis values, but also take scale into count
+ * this is not working well, if only one or two axis are scaled, but works ok on
+ * homogeneous scaling. */
+ int constraintId = phys_env->CreateConstraint(
+ phy_src, phy_dest, (PHY_ConstraintType)dat->type,
+ (float)(dat->pivX * scale.x()), (float)(dat->pivY * scale.y()), (float)(dat->pivZ * scale.z()),
+ (float)(axis0.x() * scale.x()), (float)(axis0.y() * scale.y()), (float)(axis0.z() * scale.z()),
+ (float)(axis1.x() * scale.x()), (float)(axis1.y() * scale.y()), (float)(axis1.z() * scale.z()),
+ (float)(axis2.x() * scale.x()), (float)(axis2.y() * scale.y()), (float)(axis2.z() * scale.z()),
+ dat->flag);
+
+ /* PHY_POINT2POINT_CONSTRAINT = 1,
+ * PHY_LINEHINGE_CONSTRAINT = 2,
+ * PHY_ANGULAR_CONSTRAINT = 3,
+ * PHY_CONE_TWIST_CONSTRAINT = 4,
+ * PHY_VEHICLE_CONSTRAINT = 11,
+ * PHY_GENERIC_6DOF_CONSTRAINT = 12 */
+
+ if (!constraintId)
+ return;
+
+ int dof = 0;
+ int dof_max = 0;
+ int dofbit = 0;
+
+ switch (dat->type) {
+ /* Set all the limits for generic 6DOF constraint. */
+ case PHY_GENERIC_6DOF_CONSTRAINT:
+ dof_max = 6;
+ dofbit = 1;
+ break;
+ /* Set XYZ angular limits for cone twist constraint. */
+ case PHY_CONE_TWIST_CONSTRAINT:
+ dof = 3;
+ dof_max = 6;
+ dofbit = 1 << 3;
+ break;
+ /* Set only X angular limits for line hinge and angular constraint. */
+ case PHY_LINEHINGE_CONSTRAINT:
+ case PHY_ANGULAR_CONSTRAINT:
+ dof = 3;
+ dof_max = 4;
+ dofbit = 1 << 3;
+ break;
+ default:
+ break;
+ }
+
+ for (; dof < dof_max; dof++) {
+ if (dat->flag & dofbit) {
+ phys_env->SetConstraintParam(constraintId, dof, dat->minLimit[dof], dat->maxLimit[dof]);
+ }
+ else {
+ /* minLimit > maxLimit means free (no limit) for this degree of freedom. */
+ phys_env->SetConstraintParam(constraintId, dof, 1.0f, -1.0f);
+ }
+ dofbit <<= 1;
+ }
+
+}
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
index ff8a3f4f9f9..94aea215478 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
@@ -22,6 +22,8 @@ subject to the following restrictions:
#define __CCDPHYSICSENVIRONMENT_H__
#include "PHY_IPhysicsEnvironment.h"
+#include "KX_KetsjiEngine.h"
+
#include <vector>
#include <set>
#include <map>
@@ -52,6 +54,7 @@ class btOverlappingPairCache;
class btIDebugDraw;
class PHY_IVehicle;
class CcdOverlapFilterCallBack;
+class CcdShapeConstructionInfo;
/** CcdPhysicsEnvironment is an experimental mainloop for physics simulation using optional continuous collision detection.
* Physics Environment takes care of stepping the simulation and is a container for physics entities.
@@ -131,8 +134,7 @@ protected:
virtual void SetFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep)
{
- //based on DEFAULT_PHYSICS_TIC_RATE of 60 hertz
- SetNumTimeSubSteps((int)(fixedTimeStep / 60.f));
+ SetNumTimeSubSteps((int)(fixedTimeStep / KX_KetsjiEngine::GetTicRate()));
}
//returns 0.f if no fixed timestep is used
@@ -220,16 +222,22 @@ protected:
void UpdateCcdPhysicsController(CcdPhysicsController* ctrl, btScalar newMass, int newCollisionFlags, short int newCollisionGroup, short int newCollisionMask);
- void DisableCcdPhysicsController(CcdPhysicsController* ctrl);
-
- void EnableCcdPhysicsController(CcdPhysicsController* ctrl);
-
void RefreshCcdPhysicsController(CcdPhysicsController* ctrl);
+ bool IsActiveCcdPhysicsController(CcdPhysicsController *ctrl);
+
void AddCcdGraphicController(CcdGraphicController* ctrl);
void RemoveCcdGraphicController(CcdGraphicController* ctrl);
+ /**
+ * Update all physics controllers shape which use the same shape construction info.
+ * Call RecreateControllerShape on controllers which use the same shape
+ * construction info that argument shapeInfo.
+ * You need to call this function when the shape construction info changed.
+ */
+ void UpdateCcdPhysicsControllerShape(CcdShapeConstructionInfo *shapeInfo);
+
btBroadphaseInterface* GetBroadphase();
btDbvtBroadphase* GetCullingTree() { return m_cullingTree; }
@@ -274,6 +282,10 @@ protected:
bool isCompoundChild,
bool hasCompoundChildren);
+ /* Set the rigid body joints constraints values for converted objects and replicated group instances. */
+ virtual void SetupObjectConstraints(KX_GameObject *obj_src, KX_GameObject *obj_dest,
+ bRigidBodyJointConstraint *dat);
+
protected:
diff --git a/source/gameengine/Physics/common/PHY_IPhysicsController.h b/source/gameengine/Physics/common/PHY_IPhysicsController.h
index 1717f8d90cb..3e2337f01ea 100644
--- a/source/gameengine/Physics/common/PHY_IPhysicsController.h
+++ b/source/gameengine/Physics/common/PHY_IPhysicsController.h
@@ -32,6 +32,7 @@
#ifndef __PHY_IPHYSICSCONTROLLER_H__
#define __PHY_IPHYSICSCONTROLLER_H__
+#include <vector>
#include "PHY_IController.h"
class PHY_IMotionState;
@@ -95,6 +96,7 @@ class PHY_IPhysicsController : public PHY_IController
virtual void SetAngularDamping(float damping)=0;
virtual void SetDamping(float linear, float angular)=0;
+ virtual void RefreshCollisions() = 0;
virtual void SuspendDynamics(bool ghost=false)=0;
virtual void RestoreDynamics()=0;
@@ -132,9 +134,12 @@ class PHY_IPhysicsController : public PHY_IController
virtual bool IsDynamic() = 0;
virtual bool IsCompound() = 0;
+ virtual bool IsSuspended() const = 0;
virtual bool ReinstancePhysicsShape(KX_GameObject *from_gameobj, RAS_MeshObject* from_meshobj) = 0;
+ /* Method to replicate rigid body joint contraints for group instances. */
+ virtual void ReplicateConstraints(KX_GameObject *gameobj, std::vector<KX_GameObject*> constobj) = 0;
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GE:PHY_IPhysicsController")
diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
index dd762b02b4e..44b61136d3f 100644
--- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
+++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
@@ -55,6 +55,7 @@ class KX_Scene;
struct PHY_ShapeProps;
struct PHY_MaterialProps;
class PHY_IMotionState;
+struct bRigidBodyJointConstraint;
/**
* pass back information from rayTest
@@ -213,6 +214,9 @@ class PHY_IPhysicsEnvironment
bool isCompoundChild,
bool hasCompoundChildren) = 0;
+ /* Set the rigid body joints constraints values for converted objects and replicated group instances. */
+ virtual void SetupObjectConstraints(KX_GameObject *obj_src, KX_GameObject *obj_dest,
+ bRigidBodyJointConstraint *dat) {}
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GE:PHY_IPhysicsEnvironment")
diff --git a/source/gameengine/Rasterizer/RAS_ICanvas.h b/source/gameengine/Rasterizer/RAS_ICanvas.h
index d90cbea286e..471c2c97fa1 100644
--- a/source/gameengine/Rasterizer/RAS_ICanvas.h
+++ b/source/gameengine/Rasterizer/RAS_ICanvas.h
@@ -237,6 +237,8 @@ public:
const char* filename
)=0;
+ virtual void GetDisplayDimensions(int &width, int &height) = 0;
+
virtual
void
ResizeWindow(
diff --git a/source/gameengine/Rasterizer/RAS_IRasterizer.h b/source/gameengine/Rasterizer/RAS_IRasterizer.h
index d7b52213191..aadecd56992 100644
--- a/source/gameengine/Rasterizer/RAS_IRasterizer.h
+++ b/source/gameengine/Rasterizer/RAS_IRasterizer.h
@@ -297,15 +297,11 @@ public:
/**
* Fog
*/
- virtual void SetFog(float start, float dist, float r, float g, float b) = 0;
- virtual void SetFogColor(float r, float g,float b) = 0;
- virtual void SetFogStart(float start) = 0;
- virtual void SetFogEnd(float end) = 0;
+ virtual void SetFog(short type, float start, float dist, float intensity, float color[3]) = 0;
virtual void DisplayFog() = 0;
- virtual void DisableFog() = 0;
- virtual bool IsFogEnabled() = 0;
+ virtual void EnableFog(bool enable) = 0;
- virtual void SetBackColor(float red, float green, float blue, float alpha) = 0;
+ virtual void SetBackColor(float color[3]) = 0;
/**
* \param drawingmode = KX_BOUNDINGBOX, KX_WIREFRAME, KX_SOLID, KX_SHADED or KX_TEXTURED.
@@ -380,7 +376,7 @@ public:
*/
virtual void SetEmissive(float eX, float eY, float eZ, float e) = 0;
- virtual void SetAmbientColor(float red, float green, float blue) = 0;
+ virtual void SetAmbientColor(float color[3]) = 0;
virtual void SetAmbient(float factor) = 0;
/**
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
index b3da5e1f812..34184f73953 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
@@ -79,10 +79,6 @@ void RAS_ListSlot::RemoveList()
void RAS_ListSlot::DrawList()
{
- if (m_flag &LIST_STREAM || m_flag& LIST_NOCREATE) {
- RemoveList();
- return;
- }
if (m_flag &LIST_MODIFY) {
if (m_flag &LIST_CREATE) {
if (m_list == 0) {
@@ -115,7 +111,7 @@ void RAS_ListSlot::SetModified(bool mod)
if (mod && !(m_flag & LIST_MODIFY)) {
spit("Modifying list (" << m_list << ")");
m_flag = m_flag &~ LIST_END;
- m_flag |= LIST_STREAM;
+ m_flag |= LIST_MODIFY;
}
}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h
index d394c72b2a2..5e1c662bc17 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h
@@ -35,12 +35,9 @@ public:
enum RAS_ListSlotFlags {
LIST_CREATE =1,
LIST_MODIFY =2,
- LIST_STREAM =4,
- LIST_NOCREATE =8,
- LIST_BEGIN =16,
- LIST_END =32,
- LIST_REGEN =64,
- LIST_DERIVEDMESH=128,
+ LIST_BEGIN =4,
+ LIST_END =8,
+ LIST_DERIVEDMESH=16,
};
struct DerivedMesh;
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
index 116a11339d9..95c153a7e2a 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
@@ -194,113 +194,52 @@ bool RAS_OpenGLRasterizer::Init()
}
-void RAS_OpenGLRasterizer::SetAmbientColor(float red, float green, float blue)
+void RAS_OpenGLRasterizer::SetAmbientColor(float color[3])
{
- m_ambr = red;
- m_ambg = green;
- m_ambb = blue;
+ m_ambr = color[0];
+ m_ambg = color[1];
+ m_ambb = color[2];
}
-
void RAS_OpenGLRasterizer::SetAmbient(float factor)
{
- float ambient[] = { m_ambr*factor, m_ambg*factor, m_ambb*factor, 1.0f };
+ float ambient[] = {m_ambr * factor, m_ambg * factor, m_ambb * factor, 1.0f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
}
-
-void RAS_OpenGLRasterizer::SetBackColor(float red,
- float green,
- float blue,
- float alpha)
-{
- m_redback = red;
- m_greenback = green;
- m_blueback = blue;
- m_alphaback = alpha;
-}
-
-
-
-void RAS_OpenGLRasterizer::SetFogColor(float r,
- float g,
- float b)
-{
- m_fogr = r;
- m_fogg = g;
- m_fogb = b;
- m_fogenabled = true;
-}
-
-
-
-void RAS_OpenGLRasterizer::SetFogStart(float start)
+void RAS_OpenGLRasterizer::SetBackColor(float color[3])
{
- m_fogstart = start;
- m_fogenabled = true;
+ m_redback = color[0];
+ m_greenback = color[1];
+ m_blueback = color[2];
+ m_alphaback = 1.0f;
}
-
-
-void RAS_OpenGLRasterizer::SetFogEnd(float fogend)
+void RAS_OpenGLRasterizer::SetFog(short type, float start, float dist, float intensity, float color[3])
{
- m_fogdist = fogend;
- m_fogenabled = true;
+ float params[4] = {color[0], color[1], color[2], 1.0f};
+ glFogi(GL_FOG_MODE, GL_LINEAR);
+ glFogf(GL_FOG_DENSITY, intensity / 10.0f);
+ glFogf(GL_FOG_START, start);
+ glFogf(GL_FOG_END, start + dist);
+ glFogfv(GL_FOG_COLOR, params);
}
-
-
-void RAS_OpenGLRasterizer::SetFog(float start,
- float dist,
- float r,
- float g,
- float b)
+void RAS_OpenGLRasterizer::EnableFog(bool enable)
{
- m_fogstart = start;
- m_fogdist = dist;
- m_fogr = r;
- m_fogg = g;
- m_fogb = b;
- m_fogenabled = true;
+ m_fogenabled = enable;
}
-
-
-void RAS_OpenGLRasterizer::DisableFog()
-{
- m_fogenabled = false;
-}
-
-bool RAS_OpenGLRasterizer::IsFogEnabled()
-{
- return m_fogenabled;
-}
-
-
void RAS_OpenGLRasterizer::DisplayFog()
{
- if ((m_drawingmode >= KX_SOLID) && m_fogenabled)
- {
- float params[5];
- glFogi(GL_FOG_MODE, GL_LINEAR);
- glFogf(GL_FOG_DENSITY, 0.1f);
- glFogf(GL_FOG_START, m_fogstart);
- glFogf(GL_FOG_END, m_fogstart + m_fogdist);
- params[0] = m_fogr;
- params[1] = m_fogg;
- params[2] = m_fogb;
- params[3] = 0.0;
- glFogfv(GL_FOG_COLOR, params);
+ if ((m_drawingmode >= KX_SOLID) && m_fogenabled) {
glEnable(GL_FOG);
- }
- else
- {
+ }
+ else {
glDisable(GL_FOG);
}
}
-
-
bool RAS_OpenGLRasterizer::SetMaterial(const RAS_IPolyMaterial& mat)
{
return mat.Activate(this, m_materialCachingInfo);
@@ -1135,12 +1074,17 @@ void RAS_OpenGLRasterizer::SetMipmapping(MipmapOption val)
RAS_IRasterizer::MipmapOption RAS_OpenGLRasterizer::GetMipmapping()
{
- if (GPU_get_linear_mipmap())
- return RAS_IRasterizer::RAS_MIPMAP_LINEAR;
- else if (GPU_get_mipmap())
- return RAS_IRasterizer::RAS_MIPMAP_NEAREST;
- else
+ if (GPU_get_mipmap()) {
+ if (GPU_get_linear_mipmap()) {
+ return RAS_IRasterizer::RAS_MIPMAP_LINEAR;
+ }
+ else {
+ return RAS_IRasterizer::RAS_MIPMAP_NEAREST;
+ }
+ }
+ else {
return RAS_IRasterizer::RAS_MIPMAP_NONE;
+ }
}
void RAS_OpenGLRasterizer::SetUsingOverrideShader(bool val)
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
index 1334ddb2a26..b034315e3d6 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
@@ -80,12 +80,7 @@ class RAS_OpenGLRasterizer : public RAS_IRasterizer
/* fogging vars */
bool m_fogenabled;
- float m_fogstart;
- float m_fogdist;
- float m_fogr;
- float m_fogg;
- float m_fogb;
-
+
float m_redback;
float m_greenback;
float m_blueback;
@@ -198,16 +193,12 @@ public:
virtual const MT_Point3& GetCameraPosition();
virtual bool GetCameraOrtho();
- virtual void SetFog(float start, float dist, float r, float g, float b);
- virtual void SetFogColor(float r, float g, float b);
- virtual void SetFogStart(float fogstart);
- virtual void SetFogEnd(float fogend);
- void DisableFog();
+ virtual void SetFog(short type, float start, float dist, float intensity, float color[3]);
+ virtual void EnableFog(bool enable);
virtual void DisplayFog();
- virtual bool IsFogEnabled();
- virtual void SetBackColor(float red, float green, float blue, float alpha);
-
+ virtual void SetBackColor(float color[3]);
+
virtual void SetDrawingMode(int drawingmode);
virtual int GetDrawingMode();
@@ -227,7 +218,7 @@ public:
virtual void SetDiffuse(float difX, float difY, float difZ, float diffuse);
virtual void SetEmissive(float eX, float eY, float eZ, float e);
- virtual void SetAmbientColor(float red, float green, float blue);
+ virtual void SetAmbientColor(float color[3]);
virtual void SetAmbient(float factor);
virtual void SetPolygonOffset(float mult, float add);
diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp
index 57b2e85845c..2b2a6e0778b 100644
--- a/source/gameengine/VideoTexture/ImageRender.cpp
+++ b/source/gameengine/VideoTexture/ImageRender.cpp
@@ -75,8 +75,8 @@ ImageRender::ImageRender (KX_Scene *scene, KX_Camera * camera) :
m_mirrorHalfWidth(0.f),
m_mirrorHalfHeight(0.f)
{
- // initialize background color
- setBackground(0, 0, 255, 255);
+ // initialize background color to scene background color as default
+ setBackgroundFromScene(m_scene);
// retrieve rendering objects
m_engine = KX_GetActiveEngine();
m_rasterizer = m_engine->GetRasterizer();
@@ -100,6 +100,18 @@ void ImageRender::setBackground (int red, int green, int blue, int alpha)
m_background[3] = (alpha < 0) ? 0.f : (alpha > 255) ? 1.f : float(alpha)/255.f;
}
+// set background color from scene
+void ImageRender::setBackgroundFromScene (KX_Scene *scene)
+{
+ if (scene) {
+ const float *background_color = scene->GetWorldInfo()->getBackColor();
+ setBackground((int) (background_color[0] * 255.0f), (int) (background_color[1] * 255.0f), (int) (background_color[2] * 255.0f), 255);
+ }
+ else {
+ setBackground(0, 0, 255, 255);
+ }
+}
+
// capture image from viewport
void ImageRender::calcImage (unsigned int texId, double ts)
@@ -200,7 +212,7 @@ void ImageRender::Render()
m_canvas->ClearColor(m_background[0], m_background[1], m_background[2], m_background[3]);
m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);
m_rasterizer->BeginFrame(m_engine->GetClockTime());
- m_engine->SetWorldSettings(m_scene->GetWorldInfo());
+ m_scene->GetWorldInfo()->UpdateWorldSettings();
m_rasterizer->SetAuxilaryClientInfo(m_scene);
m_rasterizer->DisplayFog();
// matrix calculation, don't apply any of the stereo mode
@@ -272,6 +284,12 @@ void ImageRender::Render()
// restore the stereo mode now that the matrix is computed
m_rasterizer->SetStereoMode(stereomode);
+ if (stereomode == RAS_IRasterizer::RAS_STEREO_QUADBUFFERED) {
+ // In QUAD buffer stereo mode, the GE render pass ends with the right eye on the right buffer
+ // but we need to draw on the left buffer to capture the render
+ // TODO: implement an explicit function in rasterizer to restore the left buffer.
+ m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_LEFTEYE);
+ }
m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera);
m_scene->RenderBuckets(camtrans, m_rasterizer);
@@ -727,7 +745,8 @@ ImageRender::ImageRender (KX_Scene *scene, KX_GameObject *observer, KX_GameObjec
m_mirrorX = m_mirrorY.cross(m_mirrorZ);
m_render = true;
- setBackground(0, 0, 255, 255);
+ // set mirror background color to scene background color as default
+ setBackgroundFromScene(m_scene);
}
diff --git a/source/gameengine/VideoTexture/ImageRender.h b/source/gameengine/VideoTexture/ImageRender.h
index 98dceeaafe1..bdf442c82d0 100644
--- a/source/gameengine/VideoTexture/ImageRender.h
+++ b/source/gameengine/VideoTexture/ImageRender.h
@@ -100,7 +100,7 @@ protected:
void Render();
void SetupRenderFrame(KX_Scene *scene, KX_Camera* cam);
void RenderFrame(KX_Scene* scene, KX_Camera* cam);
- void SetBackGround(KX_WorldInfo* wi);
+ void setBackgroundFromScene(KX_Scene *scene);
void SetWorldSettings(KX_WorldInfo* wi);
};
diff --git a/source/gameengine/VideoTexture/Texture.cpp b/source/gameengine/VideoTexture/Texture.cpp
index 9640c5544da..c31faf5a463 100644
--- a/source/gameengine/VideoTexture/Texture.cpp
+++ b/source/gameengine/VideoTexture/Texture.cpp
@@ -79,9 +79,21 @@ void loadTexture(unsigned int texId, unsigned int *texture, short *size,
glBindTexture(GL_TEXTURE_2D, texId);
if (mipmap)
{
+ int i;
+ ImBuf *ibuf;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE, texture);
+
+ ibuf = IMB_allocFromBuffer(texture, NULL, size[0], size[1]);
+
+ IMB_makemipmap(ibuf, true);
+
+ for (i = 0; i < ibuf->miptot; i++) {
+ ImBuf *mip = IMB_getmipmap(ibuf, i);
+
+ glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect);
+ }
+ IMB_freeImBuf(ibuf);
}
else
{
diff --git a/tests/gtests/blenlib/BLI_ghash_performance_test.cc b/tests/gtests/blenlib/BLI_ghash_performance_test.cc
new file mode 100644
index 00000000000..ef17349268c
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_ghash_performance_test.cc
@@ -0,0 +1,415 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+#include "BLI_ressource_strings.h"
+
+#define GHASH_INTERNAL_API
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_rand.h"
+#include "BLI_string.h"
+#include "PIL_time_utildefines.h"
+}
+
+/* Using http://corpora.uni-leipzig.de/downloads/eng_wikipedia_2010_1M-text.tar.gz
+ * (1 million of words, about 122MB of text) from http://corpora.informatik.uni-leipzig.de/download.html */
+//#define TEXT_CORPUS_PATH "/path/to/Téléchargements/eng_wikipedia_2010_1M-text/eng_wikipedia_2010_1M-sentences.txt"
+
+/* Resizing the hash has a huge cost over global filling operation! */
+//#define GHASH_RESERVE
+
+#define PRINTF_GHASH_STATS(_gh) \
+{ \
+ double q, lf, var, pempty, poverloaded; \
+ int bigb; \
+ q = BLI_ghash_calc_quality_ex((_gh), &lf, &var, &pempty, &poverloaded, &bigb); \
+ printf("GHash stats (%d entries):\n\t" \
+ "Quality (the lower the better): %f\n\tVariance (the lower the better): %f\n\tLoad: %f\n\t" \
+ "Empty buckets: %.2f%%\n\tOverloaded buckets: %.2f%% (biggest bucket: %d)\n", \
+ BLI_ghash_size(_gh), q, var, lf, pempty * 100.0, poverloaded * 100.0, bigb); \
+} void (0)
+
+
+/* Str: whole text, lines and words from a 'corpus' text. */
+
+static void str_ghash_tests(GHash *ghash, const char *id)
+{
+ printf("\n========== STARTING %s ==========\n", id);
+
+#ifdef TEXT_CORPUS_PATH
+ size_t sz = 0;
+ char *data;
+ {
+ struct stat st;
+ if (stat(TEXT_CORPUS_PATH, &st) == 0)
+ sz = st.st_size;
+ }
+ if (sz != 0) {
+ FILE *f = fopen(TEXT_CORPUS_PATH, "r");
+
+ data = (char *)MEM_mallocN(sz + 1, __func__);
+ if (fread(data, sizeof(*data), sz, f) != sz) {
+ printf("ERROR in reading file %s!", TEXT_CORPUS_PATH);
+ MEM_freeN(data);
+ data = BLI_strdup(words10k);
+ }
+ data[sz] = '\0';
+ fclose(f);
+ }
+ else {
+ data = BLI_strdup(words10k);
+ }
+#else
+ char *data = BLI_strdup(words10k);
+#endif
+ char *data_p = BLI_strdup(data);
+ char *data_w = BLI_strdup(data);
+ char *data_bis = BLI_strdup(data);
+
+ {
+ char *p, *w, *c_p, *c_w;
+
+ TIMEIT_START(string_insert);
+
+#ifdef GHASH_RESERVE
+ BLI_ghash_reserve(ghash, strlen(data) / 32); /* rough estimation... */
+#endif
+
+ BLI_ghash_insert(ghash, data, SET_INT_IN_POINTER(data[0]));
+
+ for (p = c_p = data_p, w = c_w = data_w; *c_w; c_w++, c_p++) {
+ if (*c_p == '.') {
+ *c_p = *c_w = '\0';
+ if (!BLI_ghash_haskey(ghash, p)) {
+ BLI_ghash_insert(ghash, p, SET_INT_IN_POINTER(p[0]));
+ }
+ if (!BLI_ghash_haskey(ghash, w)) {
+ BLI_ghash_insert(ghash, w, SET_INT_IN_POINTER(w[0]));
+ }
+ p = c_p + 1;
+ w = c_w + 1;
+ }
+ else if (*c_w == ' ') {
+ *c_w = '\0';
+ if (!BLI_ghash_haskey(ghash, w)) {
+ BLI_ghash_insert(ghash, w, SET_INT_IN_POINTER(w[0]));
+ }
+ w = c_w + 1;
+ }
+ }
+
+ TIMEIT_END(string_insert);
+ }
+
+ PRINTF_GHASH_STATS(ghash);
+
+ {
+ char *p, *w, *c;
+ void *v;
+
+ TIMEIT_START(string_lookup);
+
+ v = BLI_ghash_lookup(ghash, data_bis);
+ EXPECT_EQ(data_bis[0], GET_INT_FROM_POINTER(v));
+
+ for (p = w = c = data_bis; *c; c++) {
+ if (*c == '.') {
+ *c = '\0';
+ v = BLI_ghash_lookup(ghash, w);
+ EXPECT_EQ(w[0], GET_INT_FROM_POINTER(v));
+ v = BLI_ghash_lookup(ghash, p);
+ EXPECT_EQ(p[0], GET_INT_FROM_POINTER(v));
+ p = w = c + 1;
+ }
+ else if (*c == ' ') {
+ *c = '\0';
+ v = BLI_ghash_lookup(ghash, w);
+ EXPECT_EQ(w[0], GET_INT_FROM_POINTER(v));
+ w = c + 1;
+ }
+ }
+
+ TIMEIT_END(string_lookup);
+ }
+
+ BLI_ghash_free(ghash, NULL, NULL);
+ MEM_freeN(data);
+ MEM_freeN(data_p);
+ MEM_freeN(data_w);
+ MEM_freeN(data_bis);
+
+ printf("========== ENDED %s ==========\n\n", id);
+}
+
+TEST(ghash, TextGHash)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
+
+ str_ghash_tests(ghash, "StrGHash - GHash");
+}
+
+TEST(ghash, TextMurmur2a)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_strhash_p_murmur, BLI_ghashutil_strcmp, __func__);
+
+ str_ghash_tests(ghash, "StrGHash - Murmur");
+}
+
+
+/* Int: uniform 100M first integers. */
+
+static void int_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr)
+{
+ printf("\n========== STARTING %s ==========\n", id);
+
+ {
+ unsigned int i = nbr;
+
+ TIMEIT_START(int_insert);
+
+#ifdef GHASH_RESERVE
+ BLI_ghash_reserve(ghash, nbr);
+#endif
+
+ while (i--) {
+ BLI_ghash_insert(ghash, SET_UINT_IN_POINTER(i), SET_UINT_IN_POINTER(i));
+ }
+
+ TIMEIT_END(int_insert);
+ }
+
+ PRINTF_GHASH_STATS(ghash);
+
+ {
+ unsigned int i = nbr;
+
+ TIMEIT_START(int_lookup);
+
+ while (i--) {
+ void *v = BLI_ghash_lookup(ghash, SET_UINT_IN_POINTER(i));
+ EXPECT_EQ(i, GET_UINT_FROM_POINTER(v));
+ }
+
+ TIMEIT_END(int_lookup);
+ }
+
+ BLI_ghash_free(ghash, NULL, NULL);
+
+ printf("========== ENDED %s ==========\n\n", id);
+}
+
+TEST(ghash, IntGHash12000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
+
+ int_ghash_tests(ghash, "IntGHash - GHash - 12000", 12000);
+}
+
+TEST(ghash, IntGHash100000000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
+
+ int_ghash_tests(ghash, "IntGHash - GHash - 100000000", 100000000);
+}
+
+TEST(ghash, IntMurmur2a12000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
+
+ int_ghash_tests(ghash, "IntGHash - Murmur - 12000", 12000);
+}
+
+TEST(ghash, IntMurmur2a100000000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
+
+ int_ghash_tests(ghash, "IntGHash - Murmur - 100000000", 100000000);
+}
+
+
+/* Int: random 50M integers. */
+
+static void randint_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr)
+{
+ printf("\n========== STARTING %s ==========\n", id);
+
+ unsigned int *data = (unsigned int *)MEM_mallocN(sizeof(*data) * (size_t)nbr, __func__);
+ unsigned int *dt;
+ unsigned int i;
+
+ {
+ RNG *rng = BLI_rng_new(0);
+ for (i = nbr, dt = data; i--; dt++) {
+ *dt = BLI_rng_get_uint(rng);
+ }
+ BLI_rng_free(rng);
+ }
+
+ {
+ TIMEIT_START(int_insert);
+
+#ifdef GHASH_RESERVE
+ BLI_ghash_reserve(ghash, nbr);
+#endif
+
+ for (i = nbr, dt = data; i--; dt++) {
+ BLI_ghash_insert(ghash, SET_UINT_IN_POINTER(*dt), SET_UINT_IN_POINTER(*dt));
+ }
+
+ TIMEIT_END(int_insert);
+ }
+
+ PRINTF_GHASH_STATS(ghash);
+
+ {
+ TIMEIT_START(int_lookup);
+
+ for (i = nbr, dt = data; i--; dt++) {
+ void *v = BLI_ghash_lookup(ghash, SET_UINT_IN_POINTER(*dt));
+ EXPECT_EQ(*dt, GET_UINT_FROM_POINTER(v));
+ }
+
+ TIMEIT_END(int_lookup);
+ }
+
+ BLI_ghash_free(ghash, NULL, NULL);
+
+ printf("========== ENDED %s ==========\n\n", id);
+}
+
+TEST(ghash, IntRandGHash12000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
+
+ randint_ghash_tests(ghash, "RandIntGHash - GHash - 12000", 12000);
+}
+
+TEST(ghash, IntRandGHash50000000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
+
+ randint_ghash_tests(ghash, "RandIntGHash - GHash - 50000000", 50000000);
+}
+
+TEST(ghash, IntRandMurmur2a12000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
+
+ randint_ghash_tests(ghash, "RandIntGHash - Murmur - 12000", 12000);
+}
+
+TEST(ghash, IntRandMurmur2a50000000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
+
+ randint_ghash_tests(ghash, "RandIntGHash - Murmur - 50000000", 50000000);
+}
+
+static unsigned int ghashutil_tests_nohash_p(const void *p)
+{
+ return GET_UINT_FROM_POINTER(p);
+}
+
+static bool ghashutil_tests_cmp_p(const void *a, const void *b)
+{
+ return a != b;
+}
+
+TEST(ghash, Int4NoHash12000)
+{
+ GHash *ghash = BLI_ghash_new(ghashutil_tests_nohash_p, ghashutil_tests_cmp_p, __func__);
+
+ randint_ghash_tests(ghash, "RandIntGHash - No Hash - 12000", 12000);
+}
+
+TEST(ghash, Int4NoHash50000000)
+{
+ GHash *ghash = BLI_ghash_new(ghashutil_tests_nohash_p, ghashutil_tests_cmp_p, __func__);
+
+ randint_ghash_tests(ghash, "RandIntGHash - No Hash - 50000000", 50000000);
+}
+
+
+/* Int_v4: 20M of randomly-generated integer vectors. */
+
+static void int4_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr)
+{
+ printf("\n========== STARTING %s ==========\n", id);
+
+ unsigned int (*data)[4] = (unsigned int (*)[4])MEM_mallocN(sizeof(*data) * (size_t)nbr, __func__);
+ unsigned int (*dt)[4];
+ unsigned int i, j;
+
+ {
+ RNG *rng = BLI_rng_new(0);
+ for (i = nbr, dt = data; i--; dt++) {
+ for (j = 4; j--; ) {
+ (*dt)[j] = BLI_rng_get_uint(rng);
+ }
+ }
+ BLI_rng_free(rng);
+ }
+
+ {
+ TIMEIT_START(int_v4_insert);
+
+#ifdef GHASH_RESERVE
+ BLI_ghash_reserve(ghash, nbr);
+#endif
+
+ for (i = nbr, dt = data; i--; dt++) {
+ BLI_ghash_insert(ghash, *dt, SET_UINT_IN_POINTER(i));
+ }
+
+ TIMEIT_END(int_v4_insert);
+ }
+
+ PRINTF_GHASH_STATS(ghash);
+
+ {
+ TIMEIT_START(int_v4_lookup);
+
+ for (i = nbr, dt = data; i--; dt++) {
+ void *v = BLI_ghash_lookup(ghash, (void *)(*dt));
+ EXPECT_EQ(i, GET_UINT_FROM_POINTER(v));
+ }
+
+ TIMEIT_END(int_v4_lookup);
+ }
+
+ BLI_ghash_free(ghash, NULL, NULL);
+ MEM_freeN(data);
+
+ printf("========== ENDED %s ==========\n\n", id);
+}
+
+TEST(ghash, Int4GHash2000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__);
+
+ int4_ghash_tests(ghash, "Int4GHash - GHash - 2000", 2000);
+}
+
+TEST(ghash, Int4GHash20000000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__);
+
+ int4_ghash_tests(ghash, "Int4GHash - GHash - 20000000", 20000000);
+}
+
+TEST(ghash, Int4Murmur2a2000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_uinthash_v4_p_murmur, BLI_ghashutil_uinthash_v4_cmp, __func__);
+
+ int4_ghash_tests(ghash, "Int4GHash - Murmur - 2000", 2000);
+}
+
+TEST(ghash, Int4Murmur2a20000000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_uinthash_v4_p_murmur, BLI_ghashutil_uinthash_v4_cmp, __func__);
+
+ int4_ghash_tests(ghash, "Int4GHash - Murmur - 20000000", 20000000);
+}
diff --git a/tests/gtests/blenlib/BLI_ghash_test.cc b/tests/gtests/blenlib/BLI_ghash_test.cc
new file mode 100644
index 00000000000..5fe43d14cbe
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_ghash_test.cc
@@ -0,0 +1,158 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#define GHASH_INTERNAL_API
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_rand.h"
+}
+
+#define TESTCASE_SIZE 10000
+
+/* Only keeping this in case here, for now. */
+#define PRINTF_GHASH_STATS(_gh) \
+{ \
+ double q, lf, var, pempty, poverloaded; \
+ int bigb; \
+ q = BLI_ghash_calc_quality_ex((_gh), &lf, &var, &pempty, &poverloaded, &bigb); \
+ printf("GHash stats (%d entries):\n\t" \
+ "Quality (the lower the better): %f\n\tVariance (the lower the better): %f\n\tLoad: %f\n\t" \
+ "Empty buckets: %.2f%%\n\tOverloaded buckets: %.2f%% (biggest bucket: %d)\n", \
+ BLI_ghash_size(_gh), q, var, lf, pempty * 100.0, poverloaded * 100.0, bigb); \
+} void (0)
+
+/* Note: for pure-ghash testing, nature of the keys and data have absolutely no importance! So here we just use mere
+ * random integers stored in pointers. */
+
+static void init_keys(unsigned int keys[TESTCASE_SIZE], const int seed)
+{
+ RNG *rng = BLI_rng_new(seed);
+ unsigned int *k;
+ int i;
+
+ for (i = 0, k = keys; i < TESTCASE_SIZE; ) {
+ /* Risks of collision are low, but they do exist.
+ * And we cannot use a GSet, since we test that here! */
+ int j, t = BLI_rng_get_uint(rng);
+ for (j = i; j--; ) {
+ if (keys[j] == t) {
+ continue;
+ }
+ }
+ *k = t;
+ i++;
+ k++;
+ }
+ BLI_rng_free(rng);
+}
+
+/* Here we simply insert and then lookup all keys, ensuring we do get back the expected stored 'data'. */
+TEST(ghash, InsertLookup)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
+ unsigned int keys[TESTCASE_SIZE], *k;
+ int i;
+
+ init_keys(keys, 0);
+
+ for (i = TESTCASE_SIZE, k = keys; i--; k++) {
+ BLI_ghash_insert(ghash, SET_UINT_IN_POINTER(*k), SET_UINT_IN_POINTER(*k));
+ }
+
+ EXPECT_EQ(TESTCASE_SIZE, BLI_ghash_size(ghash));
+
+ for (i = TESTCASE_SIZE, k = keys; i--; k++) {
+ void *v = BLI_ghash_lookup(ghash, SET_UINT_IN_POINTER(*k));
+ EXPECT_EQ(*k, GET_UINT_FROM_POINTER(v));
+ }
+
+ BLI_ghash_free(ghash, NULL, NULL);
+}
+
+/* Here we simply insert and then remove all keys, ensuring we do get an empty, unshrinked ghash. */
+TEST(ghash, InsertRemove)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
+ unsigned int keys[TESTCASE_SIZE], *k;
+ int i, bkt_size;
+
+ init_keys(keys, 10);
+
+ for (i = TESTCASE_SIZE, k = keys; i--; k++) {
+ BLI_ghash_insert(ghash, SET_UINT_IN_POINTER(*k), SET_UINT_IN_POINTER(*k));
+ }
+
+ EXPECT_EQ(TESTCASE_SIZE, BLI_ghash_size(ghash));
+ bkt_size = BLI_ghash_buckets_size(ghash);
+
+ for (i = TESTCASE_SIZE, k = keys; i--; k++) {
+ void *v = BLI_ghash_popkey(ghash, SET_UINT_IN_POINTER(*k), NULL);
+ EXPECT_EQ(*k, GET_UINT_FROM_POINTER(v));
+ }
+
+ EXPECT_EQ(0, BLI_ghash_size(ghash));
+ EXPECT_EQ(bkt_size, BLI_ghash_buckets_size(ghash));
+
+ BLI_ghash_free(ghash, NULL, NULL);
+}
+
+/* Same as above, but this time we allow ghash to shrink. */
+TEST(ghash, InsertRemoveShrink)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
+ unsigned int keys[TESTCASE_SIZE], *k;
+ int i, bkt_size;
+
+ BLI_ghash_flag_set(ghash, GHASH_FLAG_ALLOW_SHRINK);
+ init_keys(keys, 20);
+
+ for (i = TESTCASE_SIZE, k = keys; i--; k++) {
+ BLI_ghash_insert(ghash, SET_UINT_IN_POINTER(*k), SET_UINT_IN_POINTER(*k));
+ }
+
+ EXPECT_EQ(TESTCASE_SIZE, BLI_ghash_size(ghash));
+ bkt_size = BLI_ghash_buckets_size(ghash);
+
+ for (i = TESTCASE_SIZE, k = keys; i--; k++) {
+ void *v = BLI_ghash_popkey(ghash, SET_UINT_IN_POINTER(*k), NULL);
+ EXPECT_EQ(*k, GET_UINT_FROM_POINTER(v));
+ }
+
+ EXPECT_EQ(0, BLI_ghash_size(ghash));
+ EXPECT_LT(BLI_ghash_buckets_size(ghash), bkt_size);
+
+ BLI_ghash_free(ghash, NULL, NULL);
+}
+
+/* Check copy. */
+TEST(ghash, Copy)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
+ GHash *ghash_copy;
+ unsigned int keys[TESTCASE_SIZE], *k;
+ int i;
+
+ init_keys(keys, 30);
+
+ for (i = TESTCASE_SIZE, k = keys; i--; k++) {
+ BLI_ghash_insert(ghash, SET_UINT_IN_POINTER(*k), SET_UINT_IN_POINTER(*k));
+ }
+
+ EXPECT_EQ(TESTCASE_SIZE, BLI_ghash_size(ghash));
+
+ ghash_copy = BLI_ghash_copy(ghash, NULL, NULL);
+
+ EXPECT_EQ(TESTCASE_SIZE, BLI_ghash_size(ghash_copy));
+ EXPECT_EQ(BLI_ghash_buckets_size(ghash), BLI_ghash_buckets_size(ghash_copy));
+
+ for (i = TESTCASE_SIZE, k = keys; i--; k++) {
+ void *v = BLI_ghash_lookup(ghash_copy, SET_UINT_IN_POINTER(*k));
+ EXPECT_EQ(*k, GET_UINT_FROM_POINTER(v));
+ }
+
+ BLI_ghash_free(ghash, NULL, NULL);
+ BLI_ghash_free(ghash_copy, NULL, NULL);
+}
diff --git a/tests/gtests/blenlib/BLI_ressource_strings.h b/tests/gtests/blenlib/BLI_ressource_strings.h
new file mode 100644
index 00000000000..b823f14af53
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_ressource_strings.h
@@ -0,0 +1,602 @@
+/* Apache License, Version 2.0 */
+
+#ifndef __BLENDER_TESTING_BLI_RESSOURCE_STRING_H__
+#define __BLENDER_TESTING_BLI_RESSOURCE_STRING_H__
+
+const char *words10k =
+"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam auctor ultrices purus tincidunt mollis. Vestibulum "
+"tincidunt imperdiet molestie. Vivamus posuere, risus ut mollis rutrum, lacus nulla mollis velit, consectetur auctor "
+"erat est in odio. Proin quis lobortis ex. Ut id quam lacus. Morbi ultrices orci quis sem suscipit tincidunt. Nullam "
+"ut molestie justo, vulputate placerat diam. Nunc tincidunt auctor venenatis. Phasellus placerat, odio ac dictum "
+"pretium, nisi odio tristique sem, sit amet hendrerit odio tortor eu felis. Duis placerat tristique neque, sit amet "
+"ornare nulla fermentum vel. Vivamus vitae rhoncus ante. Sed a dolor mauris. Nullam bibendum vehicula semper. Duis ut "
+"commodo nibh. Nulla sit amet eros feugiat, accumsan nisl a, ornare quam. In non magna orci. Curabitur finibus tempus "
+"semper. Aliquam fringilla arcu consectetur blandit vestibulum. Mauris mollis est arcu. Praesent pellentesque lacus "
+"bibendum massa commodo commodo. Aenean facilisis lobortis varius. Ut semper ullamcorper dui, at pellentesque felis. "
+"Duis accumsan sapien ut malesuada lacinia. Praesent elementum venenatis arcu in mattis. Nunc sagittis mauris risus, "
+"quis rutrum nisi egestas quis. Maecenas pharetra posuere auctor. Suspendisse mollis sollicitudin elit, id cursus "
+"massa bibendum eu. Integer tincidunt dolor non porttitor tempus. Donec lacinia sapien eu enim feugiat suscipit non "
+"malesuada diam. Suspendisse nec convallis elit. Nulla eu augue ultrices, consequat lorem at, malesuada magna. "
+"Aliquam sed tempor ipsum. Sed hendrerit nec lectus et pharetra. In felis sem, cursus at nunc in, tristique convallis "
+"purus. Praesent augue turpis, porttitor consequat risus ornare, laoreet commodo dui. Nulla congue ultrices sapien a "
+"cursus. Nulla facilisi. Integer lacinia enim sodales sem mattis, sit amet egestas lectus tincidunt. Ut quis nisl ut "
+"ex luctus fermentum quis et diam. Maecenas lectus leo, hendrerit eu facilisis et, mattis ut sem. Duis imperdiet nisl "
+"vitae urna consequat suscipit. Suspendisse sed viverra massa, dapibus condimentum sem. Morbi suscipit congue odio. "
+"Nullam eleifend fringilla nisl et semper. Sed eu neque ante. Sed eget viverra urna. Duis tempor laoreet interdum. "
+"Nunc fringilla aliquet urna sit amet commodo. Curabitur non orci nec libero egestas ullamcorper nec nec velit. Nam "
+"vitae ligula lobortis, vehicula nulla id, lacinia urna. Morbi id dignissim eros. Etiam eu risus in sem vestibulum "
+"dapibus ut mollis sem. Quisque ultricies pulvinar maximus. Proin risus turpis, auctor eget molestie nec, molestie a "
+"ipsum. Donec dapibus dui in lorem rhoncus, non rutrum neque convallis. Donec at tincidunt turpis, nec scelerisque "
+"lorem. Donec ac sapien mi. Sed commodo efficitur tempus. Maecenas eu lobortis diam. Phasellus enim nulla, ornare ac "
+"laoreet egestas, vestibulum ac arcu. Pellentesque ultrices mauris sem, a iaculis diam tristique id. Proin sed "
+"facilisis mauris. Aliquam nibh ex, varius in consequat laoreet, sollicitudin id diam. Vivamus semper ultrices sem "
+"non tempor. Sed hendrerit maximus malesuada. In ex orci, elementum non magna eget, congue sagittis tellus. Donec "
+"malesuada sem leo, quis malesuada risus blandit et. Praesent porta malesuada metus eget pretium. Vestibulum "
+"venenatis tempor tellus at varius. Donec mauris arcu, elementum vitae aliquet nec, ullamcorper vitae neque. Nunc eu "
+"viverra justo, sit amet viverra elit. Proin urna elit, luctus ut placerat quis, blandit vitae diam. Vestibulum id "
+"fringilla enim. Ut eleifend augue ante, ac euismod sapien luctus sit amet. Pellentesque mattis tortor ac rutrum "
+"malesuada. Sed et nulla id metus faucibus condimentum. Vestibulum cursus posuere vestibulum. Proin auctor arcu erat, "
+"quis porta sem dignissim a. Donec sed finibus ante. Integer porttitor pretium nunc, eu semper elit. Nam sit amet "
+"ornare urna. Suspendisse porta augue id massa luctus maximus. Fusce tellus ligula, finibus sed lacus eget, tristique "
+"mollis libero. Vivamus velit diam, faucibus vel fringilla vitae, ornare id lacus. Pellentesque vel sem quis nunc "
+"semper porta ut sit amet sapien. Integer nec leo at tortor ullamcorper pulvinar at ut ante. Fusce velit nisl, "
+"fermentum in tempus ac, gravida ac tellus. In aliquet sollicitudin erat, non vestibulum diam aliquam in. Duis purus "
+"justo, aliquet ut libero vel, egestas mollis nibh. Praesent sed tempor mauris, vel tempor augue. Morbi eu eros vel "
+"velit condimentum porttitor nec sit amet odio. Nunc suscipit risus at ex aliquam, in pretium mi maximus. Mauris "
+"sollicitudin sit amet arcu luctus maximus. Curabitur vehicula condimentum porta. Nunc consequat vitae urna vel "
+"gravida. Vivamus vitae mattis augue, sit amet blandit enim. Phasellus odio leo, cursus eget lacus sit amet, "
+"facilisis mattis tortor. Duis venenatis ante libero, eu condimentum urna viverra fermentum. Suspendisse libero leo, "
+"pretium eu leo at, imperdiet ultricies nunc. Fusce ante neque, feugiat id lacus sed, fringilla suscipit ligula. "
+"Phasellus cursus malesuada urna, vel ullamcorper massa suscipit vitae. In eu bibendum augue. Duis auctor posuere "
+"turpis nec vestibulum. Vestibulum nec dui in mi consequat auctor sed at nisl. Suspendisse tellus elit, congue ut "
+"facilisis vel, ornare id mauris. Integer rutrum fermentum neque, vitae pharetra metus consectetur in. Duis vitae "
+"lacus scelerisque, rhoncus nisl id, sagittis elit. Praesent lacinia libero ac ultricies tempus. Etiam ut maximus "
+"sapien. Maecenas sit amet ante auctor, feugiat diam non, vulputate diam. Nulla facilisi. Vestibulum id augue velit. "
+"Donec at elementum urna. Morbi elementum nunc in neque ornare, sit amet tempor mauris vulputate. Nunc mauris mauris, "
+"lobortis non nibh sed, gravida sollicitudin nunc. Nunc vel dolor non augue venenatis semper vitae non turpis. "
+"Praesent mattis elit eu interdum porttitor. Etiam quis magna magna. Praesent a ipsum est. Aenean at ligula vel leo "
+"faucibus pulvinar sed eget mauris. Nam accumsan blandit nibh, nec tincidunt nisl eleifend sit amet. Etiam ornare, "
+"arcu nec dictum volutpat, nulla orci porttitor orci, vel venenatis mi massa at erat. Maecenas eget accumsan nisl, "
+"quis ullamcorper turpis. Pellentesque sit amet mi aliquet, feugiat felis in, dictum urna. Cras nulla leo, congue vel "
+"consequat gravida, aliquet a nulla. Nulla commodo, nisi eu ultricies feugiat, justo velit tempor ligula, a tincidunt "
+"nisi tellus ut sapien. Sed eget ornare magna. Cras ut vehicula sapien. Quisque id malesuada urna, vitae congue ante. "
+"Donec nec leo pretium, finibus nibh a, porta lectus. Fusce arcu tellus, tempor semper sem id, aliquam fringilla "
+"ipsum. Ut massa ante, placerat quis sapien quis, sollicitudin blandit turpis. Aenean posuere ullamcorper massa. Nam "
+"faucibus egestas arcu. Vivamus vehicula auctor diam, eu placerat diam ullamcorper at. Nulla eu consequat elit, vel "
+"semper turpis. Curabitur rhoncus nunc vel vestibulum interdum. Nam augue neque, pharetra vel nisi dignissim, "
+"vehicula dapibus risus. Cras eget mattis nisi. Sed tempor posuere gravida. Proin sagittis a nisl eget gravida. "
+"Curabitur viverra dapibus arcu, sit amet rutrum nibh fringilla euismod. Donec vitae risus non lorem facilisis cursus "
+"eu eu quam. Donec quis lacus blandit, consectetur elit ut, sagittis ligula. Etiam dapibus ex sit amet elit commodo "
+"finibus. Suspendisse non finibus felis, non cursus libero. Vivamus semper aliquet velit vel elementum. Phasellus "
+"dictum, tortor id sagittis ultrices, ex dui porttitor tortor, nec mattis dolor sem nec mi. Ut aliquam consequat eros "
+"sit amet mollis. Nullam mollis venenatis porttitor. Donec sit amet velit at velit luctus auctor dictum in neque. Ut "
+"vulputate ultricies mollis. Pellentesque elementum augue dolor, non varius ligula tristique ac. Nullam eget mauris "
+"urna. Integer elementum eleifend pulvinar. Morbi gravida ante eget ornare faucibus. Mauris pulvinar consequat nunc "
+"vel accumsan. Curabitur egestas urna elit, ut accumsan magna dictum in. Nam neque mi, ornare sed leo at, tempor "
+"vulputate nunc. Nunc dignissim mauris id dui iaculis fringilla. Praesent malesuada tellus in dapibus feugiat. "
+"Vivamus posuere, nisi et consequat euismod, lorem augue iaculis velit, eget iaculis neque quam eu mi. Nullam ac "
+"hendrerit felis, non elementum ipsum. Aliquam erat volutpat. Proin vel molestie felis. Nullam luctus vel ante nec "
+"facilisis. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis et metus "
+"justo. Interdum et malesuada fames ac ante ipsum primis in faucibus. Ut tristique sit amet elit et congue. Aenean "
+"quis elementum enim, vitae pharetra sem. Vestibulum vel finibus nisl, at consequat eros. In vitae mollis lacus, et "
+"pharetra elit. Mauris varius sapien quis tincidunt blandit. Proin non semper nibh. Aliquam non elit id felis laoreet "
+"interdum eget a risus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. "
+"Suspendisse nisl tellus, mollis id erat vel, hendrerit volutpat nunc. Quisque scelerisque cursus tellus, nec "
+"placerat quam imperdiet in. Sed porttitor arcu vel ligula finibus, a vestibulum enim ultrices. Fusce imperdiet augue "
+"eget est vehicula porttitor. Quisque convallis odio vitae lorem porttitor iaculis. Ut dictum velit ac tortor "
+"lobortis ultrices. Vestibulum tincidunt vestibulum mauris, at fermentum elit imperdiet nec. Nunc finibus ornare "
+"lorem vel malesuada. Praesent arcu turpis, pulvinar sit amet accumsan quis, tincidunt vel justo. Pellentesque "
+"volutpat nec enim sit amet pulvinar. Nam eu libero dignissim, volutpat elit ut, semper tortor. Morbi pellentesque "
+"nisl lectus. In vel tellus sed sem luctus lobortis ut nec diam. Phasellus id semper sem. Phasellus in purus "
+"consequat, rhoncus mi mollis, finibus ligula. Fusce feugiat dictum consequat. Mauris egestas, est ut euismod "
+"consequat, arcu dui dignissim quam, pharetra dignissim orci dolor quis nisl. Nunc dapibus blandit urna non feugiat. "
+"Suspendisse non maximus augue. Quisque ut orci aliquet, vulputate massa eget, mattis diam. Etiam efficitur "
+"consectetur viverra. Nulla massa augue, elementum at turpis et, cursus ultricies risus. Suspendisse vel nibh "
+"placerat, imperdiet elit et, viverra ligula. Donec lorem lorem, hendrerit nec aliquam sit amet, scelerisque sit amet "
+"massa. Mauris convallis ullamcorper tortor sed malesuada. Fusce ultricies a turpis eu ornare. Suspendisse potenti. "
+"Sed non nulla condimentum, vulputate nisi nec, tincidunt arcu. Morbi erat leo, lobortis id odio ac, hendrerit "
+"sodales sem. Ut malesuada, lectus at posuere molestie, orci metus vehicula justo, mattis tincidunt arcu risus quis "
+"odio. Fusce non sem sed nisi consectetur finibus vitae quis diam. Vivamus a lacinia nisl. Praesent tempus nunc "
+"gravida, lacinia lacus in, lobortis massa. Aliquam gravida consequat nisi at fringilla. Quisque tortor tortor, "
+"tincidunt cursus lorem eget, ultrices ultricies lacus. Phasellus mattis iaculis elit, eget mattis nisl bibendum sed. "
+"Integer faucibus gravida nisl, ac consequat ex tempor at. Sed tempus elementum vestibulum. Suspendisse vitae enim "
+"semper, pulvinar diam eget, suscipit turpis. Maecenas ultricies, diam sed consectetur sagittis, diam sem cursus "
+"nisl, nec aliquet tellus augue quis ipsum. Cras vel lorem convallis, mattis risus at, placerat massa. Curabitur vel "
+"rutrum ligula. Quisque in nibh libero. Pellentesque diam tellus, consectetur eget quam ac, faucibus imperdiet odio. "
+"Sed tortor nulla, scelerisque non turpis nec, fringilla bibendum est. Etiam a urna eget erat tincidunt ultrices. "
+"Maecenas lorem odio, volutpat nec ligula id, hendrerit aliquam nulla. Aenean congue lacinia fermentum. Suspendisse "
+"sed interdum lacus. Fusce scelerisque posuere sagittis. Ut at semper tellus. Donec condimentum orci nunc, non "
+"fermentum purus volutpat eget. Maecenas elementum dapibus ante, eu suscipit quam imperdiet ut. Integer non congue "
+"elit. Sed venenatis, turpis varius commodo euismod, libero magna fringilla lacus, quis venenatis velit lectus sed "
+"augue. Morbi gravida orci odio, ut ornare massa sollicitudin a. Donec convallis mi et sapien tempor, non dapibus "
+"dolor fringilla. Aenean euismod rutrum turpis, et facilisis orci porttitor eu. Suspendisse in neque leo. Nulla "
+"facilisi. Etiam mollis orci nisl, quis scelerisque metus efficitur vehicula. Nam porta molestie tortor, sit amet "
+"consectetur leo vestibulum vel. Pellentesque a volutpat augue. Maecenas vel elementum ex, eget elementum leo. "
+"Curabitur at maximus metus, quis porttitor orci. Praesent auctor commodo elit, a dapibus tortor volutpat et. "
+"Praesent dictum posuere dolor sit amet molestie. Sed viverra augue nec eros mattis blandit. In quis sodales dolor. "
+"Donec sed purus ex. Fusce erat magna, efficitur ac tempus ac, lacinia quis augue. Aliquam porta efficitur est vel "
+"placerat. Phasellus egestas vel nunc eu consequat. Maecenas ligula arcu, molestie ut dui ut, ornare finibus felis. "
+"Duis condimentum non augue ut posuere. Aenean mattis eros ut ligula ornare finibus. Aliquam feugiat ut turpis a "
+"feugiat. Vestibulum eget sollicitudin orci, nec fermentum justo. Praesent efficitur est a metus bibendum, eget "
+"feugiat diam suscipit. Suspendisse sit amet ipsum ut purus feugiat pretium. Morbi nisl risus, ultricies sit amet "
+"ullamcorper euismod, commodo eu libero. Aenean fringilla ipsum nec orci rutrum aliquet. Aenean lacus ante, eleifend "
+"eu eleifend fringilla, elementum ac justo. Vestibulum tincidunt interdum lectus sit amet fermentum. Etiam rhoncus eu "
+"ante lacinia sagittis. Maecenas iaculis ut erat quis feugiat. Maecenas sed est vel tellus bibendum rutrum volutpat "
+"nec odio. Vivamus euismod augue nec purus euismod, mattis finibus nisi finibus. Donec quis ultrices massa. Quisque "
+"at nisl faucibus, facilisis tellus ut, ultricies dui. Class aptent taciti sociosqu ad litora torquent per conubia "
+"nostra, per inceptos himenaeos. Donec et arcu eros. Etiam dapibus bibendum felis eu viverra. Integer a lacus "
+"venenatis elit lacinia facilisis non non felis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed "
+"ultricies augue at sapien mattis aliquam. Quisque nec semper purus. Cras auctor aliquet lacus, sed facilisis urna "
+"sollicitudin non. Vivamus eget erat purus. Sed a risus augue. Donec non sem sed sapien accumsan lacinia. Ut mauris "
+"odio, vehicula id accumsan at, tincidunt non odio. Nunc porttitor luctus ante ac cursus. Cras et dapibus ex, id "
+"pretium ligula. Proin volutpat rhoncus ex vitae venenatis. Pellentesque imperdiet, magna non tempus auctor, metus "
+"dolor scelerisque dui, id tempor purus est in risus. Suspendisse vehicula imperdiet sapien, nec pulvinar dolor "
+"ornare ac. Nulla luctus, nisl in aliquam blandit, risus orci placerat nunc, id tempus sem neque vitae leo. Aenean at "
+"elit elit. Suspendisse finibus dictum interdum. Nunc consectetur eget quam vitae egestas. Pellentesque tellus augue, "
+"aliquet at faucibus ac, imperdiet ut nulla. Maecenas quis lorem velit. Donec porta ligula et suscipit luctus. "
+"Aliquam sed pretium nunc. Nunc quis posuere tortor. Fusce in lectus nec turpis rhoncus pellentesque eu at quam. "
+"Nulla facilisi. Sed ante nulla, posuere ac ullamcorper vel, rhoncus vitae nisl. Nam non pellentesque arcu. Vivamus "
+"nibh leo, pellentesque a mollis non, gravida ut erat. Donec purus urna, pulvinar eu iaculis blandit, rutrum eget "
+"nulla. Fusce quis fermentum diam, faucibus volutpat lorem. Maecenas aliquet nisi nisl, eget sollicitudin ipsum "
+"facilisis at. Mauris nec sapien nisi. Duis ac laoreet sapien, a condimentum nisi. Nam vitae sapien sed sem convallis "
+"ornare. Pellentesque neque diam, ullamcorper et dolor sit amet, faucibus venenatis tortor. Nunc vel erat malesuada, "
+"vulputate odio sit amet, aliquam dui. Donec tincidunt arcu ut risus laoreet, id malesuada leo ultrices. Praesent a "
+"scelerisque libero, vitae suscipit massa. Quisque faucibus mauris rhoncus turpis vestibulum rhoncus. Donec vel "
+"molestie magna. Aenean et lorem dui. Nam iaculis ante sapien, semper tincidunt tortor hendrerit id. Nulla sed orci "
+"mi. Aliquam hendrerit libero erat, ac aliquam massa rutrum non. Suspendisse eleifend, elit in aliquet hendrerit, "
+"tellus erat sodales neque, quis rhoncus tellus sem vitae est. Interdum et malesuada fames ac ante ipsum primis in "
+"faucibus. Etiam quis mauris non ipsum tristique interdum sit amet eget mi. Ut velit risus, gravida ut efficitur sit "
+"amet, commodo at diam. Sed consectetur dui porttitor quam feugiat, et auctor mauris maximus. Nullam lobortis ac mi "
+"lacinia egestas. Proin ante massa, malesuada ut nulla elementum, venenatis mollis ante. Cum sociis natoque penatibus "
+"et magnis dis parturient montes, nascetur ridiculus mus. Mauris eget gravida eros, non varius velit. Integer "
+"consectetur lectus nec arcu scelerisque, scelerisque vulputate mauris suscipit. Aliquam orci dui, faucibus et rutrum "
+"in, rhoncus quis dolor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; "
+"Maecenas ante nunc, placerat id lectus sit amet, luctus cursus ante. Nulla nec placerat arcu. Fusce ac dictum ex. "
+"Vivamus semper nulla vitae neque volutpat, auctor vestibulum arcu tempus. Pellentesque aliquam tincidunt arcu, et "
+"pharetra neque. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nunc "
+"risus augue, malesuada quis risus a, suscipit semper metus. Suspendisse ac rhoncus felis. Aliquam orci lectus, "
+"elementum at nulla at, ullamcorper pellentesque leo. Quisque nisi tellus, pharetra in pellentesque in, facilisis "
+"vitae velit. In ex ex, sagittis at dolor vel, congue ultricies velit. Duis quis gravida mi. Aenean tempor efficitur "
+"lectus. Fusce sodales, ex eu efficitur iaculis, metus sem eleifend purus, ut commodo arcu tortor eget urna. Etiam "
+"nisi nisl, malesuada convallis ex at, malesuada elementum nunc. Vivamus commodo mi id ligula tincidunt posuere. "
+"Integer eget arcu cursus, sagittis quam eu, aliquam leo. In auctor eget mauris et elementum. Aenean sagittis euismod "
+"tellus sed accumsan. Aliquam erat volutpat. Aliquam erat volutpat. Ut consectetur porta ipsum sit amet porttitor. "
+"Nam ut nunc a turpis auctor finibus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac "
+"turpis egestas. Donec non nisl condimentum, fermentum augue in, egestas libero. Pellentesque ut odio rhoncus, "
+"sollicitudin felis vitae, pellentesque est. Suspendisse tincidunt eros eget ex vestibulum elementum. Vivamus mollis "
+"scelerisque diam, quis dignissim dolor venenatis at. Ut gravida sapien vitae risus efficitur, ut auctor justo "
+"gravida. Cras arcu elit, interdum vel purus sit amet, venenatis molestie tellus. Integer consectetur tempor velit a "
+"varius. Praesent congue, massa non congue blandit, tortor purus imperdiet elit, sit amet pharetra arcu lacus egestas "
+"neque. Maecenas in erat arcu. In varius, risus vitae mollis sodales, nisi velit bibendum tortor, vitae sagittis "
+"augue tortor quis nunc. Fusce posuere dolor ac tincidunt facilisis. Phasellus in lacus diam. Fusce mattis sapien "
+"tellus, scelerisque pharetra leo eleifend nec. Cras libero diam, convallis in luctus a, iaculis a ipsum. Duis arcu "
+"leo, volutpat non mauris et, scelerisque suscipit diam. Ut vulputate placerat velit quis placerat. Duis commodo non "
+"turpis et convallis. Duis nec pulvinar metus, ac tristique leo. Fusce vehicula augue ac placerat elementum. Nulla "
+"dapibus nisi pretium lectus sodales, ac congue sapien ornare. Vestibulum sagittis orci ut purus efficitur, eu mollis "
+"libero placerat. Vestibulum ullamcorper odio non quam mollis, eget rhoncus metus eleifend. Mauris scelerisque, massa "
+"rutrum sodales malesuada, elit dolor blandit lectus, quis faucibus felis odio feugiat lacus. Nunc bibendum congue "
+"efficitur. Nunc a purus neque. In lobortis metus nisi, vel pellentesque mi facilisis sed. Donec in pretium neque, in "
+"maximus metus. Integer faucibus diam sed tristique sagittis. Nullam eget maximus leo, eget malesuada leo. Vestibulum "
+"ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean porttitor risus eget eros "
+"euismod molestie. Integer tristique tincidunt elit, non posuere libero pretium vel. Fusce dapibus, nisi nec egestas "
+"dapibus, lectus arcu maximus leo, a finibus diam arcu ut mauris. Vivamus tincidunt lectus ut augue ultrices, et "
+"cursus sem cursus. Proin in quam mauris. Maecenas vel magna dapibus, interdum ipsum mattis, posuere tortor. Cras eu "
+"massa ex. Donec eget massa vel dui gravida luctus vel a quam. Etiam eu lobortis neque. Etiam ligula dui, dictum ut "
+"turpis ac, eleifend pretium turpis. Vestibulum convallis finibus commodo. Morbi fermentum ante nunc, a rhoncus lacus "
+"ultricies quis. Suspendisse finibus quam blandit odio elementum, non efficitur diam laoreet. Cras aliquet ligula "
+"eget magna scelerisque, ut ornare nisi elementum. Duis nisl massa, suscipit id nibh a, venenatis auctor risus. Nulla "
+"luctus eget odio quis ultrices. Etiam consequat sapien ut nisl mollis cursus. Pellentesque a lacinia odio, id varius "
+"lorem. Curabitur scelerisque in urna eget pretium. Class aptent taciti sociosqu ad litora torquent per conubia "
+"nostra, per inceptos himenaeos. Sed leo metus, fermentum vitae quam ut, suscipit efficitur purus. Sed facilisis "
+"dapibus pulvinar. Cras sed eleifend mi. Sed quis nibh in sapien venenatis interdum ac nec orci. Sed non tortor urna. "
+"Nam rutrum lacinia diam id vehicula. Quisque vitae lobortis nibh, at tempor purus. Suspendisse dictum interdum nisi, "
+"quis maximus ipsum commodo tempus. Nulla semper congue gravida. Aenean at nibh in eros aliquam egestas. Nulla "
+"fermentum efficitur laoreet. Donec non lorem nec augue porttitor cursus eu in quam. Aenean laoreet quam neque, at "
+"tempus nisi ultrices id. Quisque in diam lacinia nulla scelerisque rhoncus vitae eget nulla. Donec vel est metus. "
+"Nullam suscipit odio eu enim lacinia facilisis eget in tellus. Vestibulum vehicula risus nec odio consectetur, a "
+"cursus massa imperdiet. Duis facilisis felis quis nunc mattis, nec volutpat libero tempor. Nulla nec leo sed tellus "
+"maximus lobortis. Suspendisse at urna nibh. Vestibulum eget turpis nisl. Donec scelerisque neque auctor erat tempor "
+"elementum sed id lacus. Sed metus nulla, dictum non luctus vel, suscipit et ex. Quisque laoreet sapien non neque "
+"iaculis, at aliquam massa viverra. Nullam nibh diam, imperdiet eu nunc sed, congue cursus leo. Morbi tristique diam "
+"metus, at faucibus magna mollis at. Sed eget nibh nunc. Nam nec elementum sem, sit amet tincidunt lorem. In viverra "
+"elit et interdum fermentum. Integer imperdiet orci ac justo molestie ullamcorper. Pellentesque fringilla tortor "
+"erat, scelerisque maximus nisl sollicitudin a. Integer nisi elit, pharetra eget lacinia non, congue sit amet ex. "
+"Phasellus tempus suscipit ultrices. Quisque ac nibh dignissim erat bibendum cursus vel a enim. Curabitur a augue sit "
+"amet lorem pharetra feugiat. Donec euismod, massa at venenatis bibendum, elit libero pellentesque velit, eget congue "
+"metus risus a enim. Aenean pretium vestibulum enim, sit amet vulputate urna auctor vitae. Praesent porttitor erat eu "
+"mi cursus venenatis. Maecenas ut ultrices neque, ac feugiat libero. Nulla finibus sit amet sem in auctor. Nam "
+"fermentum maximus ex, et consequat velit lobortis id. Aliquam eu feugiat est. Donec quis leo ex. Suspendisse "
+"convallis eget nulla eu aliquet. Quisque aliquet tortor vitae ipsum fermentum tristique. Sed convallis rutrum augue, "
+"ac viverra est pharetra quis. Ut porttitor magna massa, placerat maximus lectus scelerisque quis. Sed viverra urna "
+"in neque feugiat rhoncus. Donec ut viverra odio, laoreet dignissim dui. Aenean tristique feugiat diam vel luctus. "
+"Cras sit amet condimentum neque, ut faucibus ante. Aenean vitae elit id est laoreet efficitur in sit amet magna. "
+"Praesent ante felis, blandit id nisl ut, porta fringilla orci. Aenean vel accumsan metus, vel vehicula metus. Nulla "
+"placerat nibh et auctor convallis. Maecenas magna metus, pretium ac sodales ac, eleifend quis eros. Praesent "
+"volutpat quam a pulvinar pharetra. Sed arcu dolor, aliquet nec magna in, faucibus consequat lorem. In tincidunt, ex "
+"a finibus rutrum, metus dui fringilla ex, ac mollis elit leo eget augue. Nunc vehicula facilisis nibh, quis "
+"ultricies sem. Praesent nulla est, finibus in lorem in, mattis placerat urna. Proin hendrerit risus nunc, id congue "
+"ex posuere id. Aenean ullamcorper tortor quis lorem consectetur, et euismod leo fermentum. Praesent vulputate congue "
+"lectus sit amet pulvinar. Vestibulum vel vestibulum quam, in convallis diam. Maecenas sollicitudin magna odio, eget "
+"mollis purus posuere eu. Curabitur molestie mattis ligula, a maximus dui fermentum ut. Fusce justo velit, eleifend "
+"ut tellus vitae, volutpat maximus risus. Pellentesque suscipit mauris non purus placerat porta. Nunc in malesuada "
+"mi, vel bibendum felis. Aenean pretium nunc id efficitur porttitor. Mauris malesuada, tortor sit amet blandit "
+"tincidunt, tellus est ullamcorper diam, sit amet aliquet ex velit interdum quam. In hac habitasse platea dictumst. "
+"Sed vitae est eu elit posuere mattis nec a mauris. Morbi id ligula sed nunc sagittis finibus vitae eu nisi. Cras "
+"dignissim sagittis tellus a suscipit. Nunc semper erat nec libero vestibulum, at mattis purus scelerisque. "
+"Pellentesque egestas volutpat eleifend. Nullam venenatis erat id diam venenatis, sed rhoncus felis hendrerit. Nullam "
+"luctus facilisis risus. Mauris sed urna nisi. Ut tempus feugiat metus. Integer at purus velit. Praesent neque felis, "
+"pellentesque vitae sem nec, tempor commodo urna. Morbi malesuada ante sit amet purus tincidunt pellentesque. Aenean "
+"commodo lectus sit amet dignissim hendrerit. Phasellus auctor tellus ligula, eu ultrices ex egestas non. Mauris eget "
+"nisl dictum, scelerisque sapien et, dapibus felis. Aenean in dignissim leo. Sed semper, ex at euismod molestie, ex "
+"odio ullamcorper nisi, et facilisis lectus eros non magna. In hac habitasse platea dictumst. Pellentesque sed "
+"maximus mauris. Cras luctus dapibus nunc, sit amet suscipit dui viverra nec. Donec gravida tortor porttitor orci "
+"malesuada porttitor. Nunc condimentum eu libero sit amet varius. Curabitur mollis urna eu porta tincidunt. Nullam "
+"ultricies magna libero, et dapibus tellus tempus eu. Nullam pretium lectus nec iaculis pretium. Maecenas at arcu "
+"lobortis, ornare ante nec, euismod metus. Pellentesque volutpat tellus nulla. Aenean mattis efficitur velit vitae "
+"blandit. Duis vel egestas eros. Pellentesque aliquam placerat elit, eu congue sem ullamcorper sit amet. Ut erat "
+"nisl, luctus vitae pellentesque ut, tristique eu odio. Pellentesque nec fermentum ex, rhoncus varius dui. Mauris "
+"lobortis nunc nec dui volutpat consequat. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur "
+"ridiculus mus. Aliquam dignissim purus sed ligula pretium placerat. In vestibulum ultricies mauris. Curabitur "
+"aliquet lorem quis libero auctor, ut rhoncus purus lobortis. Nulla elementum erat nec rhoncus posuere. Integer "
+"faucibus quam sed elementum fringilla. In in lobortis sapien, nec commodo tortor. Aenean euismod ipsum nisi, vitae "
+"fringilla leo imperdiet ut. Donec a semper odio, et tempor magna. Cras cursus vel augue quis egestas. Nam nec tortor "
+"blandit, mattis quam imperdiet, finibus quam. Pellentesque tincidunt eros urna, ut tristique diam faucibus "
+"condimentum. Ut dictum risus mi, non sollicitudin turpis facilisis sit amet. Morbi finibus scelerisque mattis. Fusce "
+"vel tempor purus, nec pharetra augue. Curabitur dapibus, orci eu consectetur ultrices, diam mauris sodales urna, non "
+"euismod diam lacus luctus risus. Mauris commodo accumsan sapien. Proin vel blandit sapien. Donec porta tortor vel "
+"nibh faucibus molestie. Pellentesque placerat justo erat, vitae tristique felis fringilla eget. Quisque facilisis "
+"justo at orci lobortis, ut commodo diam egestas. Etiam non tristique nisl. Cras varius, massa a sollicitudin ornare, "
+"turpis arcu fringilla leo, non euismod ligula arcu id lacus. Suspendisse potenti. Morbi pharetra dolor eget porta "
+"tristique. Nullam sem tortor, lobortis eget hendrerit a, efficitur sit amet sapien. Fusce sit amet condimentum odio, "
+"aliquet rutrum velit. Morbi vel rhoncus ante. In blandit eros ut lectus varius, quis tempor arcu iaculis. In massa "
+"leo, venenatis nec lobortis non, pulvinar non nunc. Nunc vehicula, erat vitae placerat eleifend, eros ipsum "
+"consectetur odio, eu ornare velit mauris nec sapien. Integer a consequat libero. Quisque velit augue, blandit eu "
+"luctus sit amet, laoreet sit amet odio. Etiam in enim lacus. Interdum et malesuada fames ac ante ipsum primis in "
+"faucibus. In rutrum a tortor id pulvinar. Donec pretium lorem sed sem eleifend fringilla. Fusce sollicitudin ac "
+"ligula eget pharetra. Sed cursus diam non sem ullamcorper efficitur. Vivamus congue ligula iaculis justo iaculis "
+"elementum. Integer tempor nisl arcu, ut tincidunt erat vestibulum et. Suspendisse rutrum aliquet eros non "
+"pellentesque. Mauris laoreet, diam id tincidunt faucibus, risus velit venenatis risus, in venenatis justo diam et "
+"orci. Etiam pulvinar pulvinar nisi, id efficitur erat vulputate ut. Sed suscipit sodales ante, a blandit orci "
+"maximus vel. Vestibulum at aliquet orci. Proin tincidunt nisi quis eros consequat consectetur. Praesent congue "
+"lobortis laoreet. Donec imperdiet risus erat, eu volutpat justo posuere id. Fusce placerat sollicitudin eros vitae "
+"tincidunt. Sed orci ante, ultricies sed dapibus vel, sagittis ac massa. Pellentesque vel mauris nec est hendrerit "
+"posuere. Integer sagittis diam sed felis facilisis ultrices. Aliquam erat volutpat. Nulla pharetra justo in ipsum "
+"dapibus, nec viverra nunc euismod. Nulla massa ante, euismod at interdum vel, dapibus ut ex. Etiam consequat mauris "
+"a suscipit lobortis. Donec commodo convallis velit, eget commodo urna vulputate ac. Sed molestie vel dui ut feugiat. "
+"Donec orci purus, placerat vitae egestas sed, sodales nec ex. Sed egestas turpis non malesuada semper. Donec et mi a "
+"nisi volutpat sagittis. Suspendisse potenti. Phasellus mollis sapien ac tellus imperdiet tempus. Praesent nec sapien "
+"sit amet ipsum interdum interdum non eget nunc. Aenean fringilla lorem a viverra rutrum. Donec at maximus nibh. "
+"Phasellus facilisis justo sit amet metus pharetra sagittis. Quisque mollis metus laoreet ipsum tincidunt "
+"sollicitudin. Maecenas sit amet dictum ligula. Fusce molestie iaculis dui, et gravida libero hendrerit in. Praesent "
+"euismod libero metus, vitae rhoncus velit ultrices eget. Vestibulum ac massa bibendum, gravida dolor vel, dapibus "
+"est. Etiam non elit varius, mollis purus eget, placerat velit. Nullam lectus dui, mattis at pulvinar eu, elementum "
+"et lorem. Sed vel auctor orci, nec semper neque. Nullam cursus commodo quam, in ultricies tellus rhoncus vulputate. "
+"Mauris dapibus ipsum ipsum, dapibus euismod purus pellentesque at. Nullam euismod lectus non risus consequat "
+"vulputate. Quisque finibus a turpis eu convallis. Nam magna turpis, feugiat ut urna in, tempus facilisis elit. Duis "
+"dignissim purus sagittis porttitor posuere. Suspendisse varius ligula at egestas scelerisque. Duis placerat sagittis "
+"nisi, et molestie tortor posuere condimentum. Morbi hendrerit, ante ornare tempus finibus, ex ipsum laoreet dui, vel "
+"ornare felis tortor sit amet metus. Vivamus laoreet placerat massa, non suscipit nisl faucibus eget. Vestibulum ante "
+"ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Pellentesque orci lacus, vulputate cursus ex "
+"eu, porta aliquam massa. Proin dolor massa, faucibus vel rhoncus et, venenatis a nisi. Vivamus venenatis enim mi. "
+"Sed viverra augue vitae lectus lobortis vulputate. Phasellus ac ligula congue, sagittis est non, aliquet tortor. "
+"Suspendisse faucibus euismod neque, ac congue felis. Curabitur maximus neque sit amet odio varius gravida. Proin "
+"egestas nulla eget mi bibendum luctus. Ut non mollis mi. Quisque finibus, eros non lobortis interdum, diam nisi "
+"faucibus diam, non imperdiet leo velit et dolor. Nam est massa, vehicula sed diam sed, laoreet convallis nisi. Donec "
+"enim ligula, dignissim non sem ut, pulvinar cursus mi. In at dignissim nulla, ac fringilla neque. In hac habitasse "
+"platea dictumst. Quisque luctus mattis orci, consequat egestas nisi. Vivamus et metus et quam porttitor elementum. "
+"Suspendisse auctor mauris eu sollicitudin sagittis. Vivamus ac ante non augue iaculis consectetur quis quis dui. In "
+"bibendum risus tristique ligula iaculis finibus. Phasellus non ante risus. Maecenas ac leo cursus, molestie purus "
+"sed, tristique purus. Etiam sem nulla, aliquam nec laoreet nec, iaculis quis nulla. Maecenas id dui id neque "
+"venenatis gravida. Etiam vestibulum felis at diam porta ultrices. Ut finibus tortor et augue ornare, et efficitur "
+"purus scelerisque. Phasellus et ultricies arcu, vel lacinia lacus. Aenean tincidunt eleifend nunc, sit amet mattis "
+"purus venenatis sit amet. Curabitur eleifend sem nisl, et feugiat diam pharetra sit amet. Mauris ullamcorper mi vel "
+"condimentum egestas. Nulla pulvinar purus vel sagittis posuere. Nulla quis enim bibendum, iaculis quam in, tincidunt "
+"quam. Vestibulum rhoncus volutpat risus. Nulla ultricies bibendum est non malesuada. Nunc porta erat est, a "
+"tincidunt magna gravida vel. Maecenas sit amet aliquet odio. Vestibulum egestas, tortor scelerisque consectetur "
+"pharetra, nisi tellus feugiat justo, et bibendum libero mi in diam. Aliquam tempus sapien nec tristique convallis. "
+"Nullam congue, lacus quis bibendum dignissim, nisl purus molestie dolor, a tempor dolor nibh pretium tellus. In hac "
+"habitasse platea dictumst. Cras at est turpis. Nam nec lacus posuere, mattis mi eu, viverra ex. Nullam eleifend "
+"ornare orci, vel tempor tellus. Ut nec eros eget tortor tempus tristique commodo sed lorem. Donec quis scelerisque "
+"nibh, non tincidunt velit. Fusce in eleifend sapien. Nunc sodales sem ut nunc pellentesque, eget pharetra justo "
+"tempor. Proin pretium velit et vehicula interdum. Maecenas luctus venenatis tincidunt. Donec hendrerit, ligula non "
+"volutpat porta, dui ante facilisis massa, at congue orci mi sed quam. Donec lorem ipsum, malesuada quis purus in, "
+"commodo malesuada justo. Etiam luctus, lorem vel rutrum tristique, mauris urna volutpat felis, a laoreet urna nunc "
+"et neque. Morbi a diam tincidunt augue cursus commodo nec ut ligula. Maecenas ultrices purus fermentum ullamcorper "
+"aliquet. Maecenas mi enim, semper nec metus at, posuere tristique ligula. Suspendisse est elit, porta quis massa id, "
+"gravida commodo ante. Nullam maximus mauris sit amet dolor tempus posuere. Phasellus purus mi, interdum in ipsum "
+"quis, tristique venenatis dolor. Suspendisse potenti. Phasellus odio erat, varius sed aliquet vestibulum, laoreet "
+"sed mauris. Vivamus sapien erat, maximus tristique elementum ac, eleifend in enim. Morbi accumsan elementum neque, a "
+"facilisis enim laoreet non. Donec auctor condimentum fringilla. Proin id urna nec tellus maximus maximus tincidunt "
+"et libero. Integer ultricies venenatis odio, ut volutpat odio laoreet non. Donec in scelerisque justo. Integer "
+"mauris libero, fringilla vel sapien sit amet, laoreet tincidunt dolor. Nam efficitur sagittis arcu, vel lobortis dui "
+"gravida non. Curabitur lobortis feugiat finibus. Vestibulum dictum tortor nec magna fringilla blandit. Nulla "
+"facilisi. Sed cursus laoreet neque vitae pulvinar. Ut iaculis euismod ullamcorper. Nunc in hendrerit lectus, sed "
+"venenatis mi. Suspendisse et est dui. Sed elementum augue non ornare cursus. Quisque varius facilisis magna nec "
+"laoreet. Suspendisse consequat, risus sed tempus egestas, velit felis faucibus erat, eu pharetra erat nisl sed "
+"turpis. Sed ultricies ac quam id mollis. In consequat et erat vitae interdum. Pellentesque malesuada feugiat ligula "
+"eu consectetur. Vestibulum tempor mi quis purus luctus dictum. Etiam condimentum ac ligula eget imperdiet. Ut "
+"placerat, tortor eu lacinia imperdiet, enim nibh aliquam nibh, quis faucibus enim odio eu arcu. Nullam sagittis, "
+"diam a ornare congue, ipsum eros scelerisque est, sit amet sagittis nisl tellus in felis. Nam eget ornare turpis. "
+"Sed tempor ac enim a vestibulum. Pellentesque eleifend lacus non libero accumsan, ut consectetur sapien lacinia. "
+"Etiam ut arcu non mi feugiat accumsan ut sit amet risus. Donec consequat eros sapien, malesuada imperdiet justo "
+"bibendum sit amet. Nulla pretium varius lectus, in eleifend quam fringilla in. Quisque eu pretium velit. Sed eget "
+"lectus sit amet tortor blandit tempus vel at sapien. Sed at velit porta, venenatis lorem sed, dapibus arcu. Donec "
+"pellentesque tortor id massa interdum pretium. Praesent id diam quis nunc dictum finibus quis quis ipsum. Quisque "
+"consectetur risus eu elit viverra, eget laoreet odio efficitur. In congue turpis iaculis ullamcorper bibendum. Duis "
+"at elit et velit varius vulputate ut ac turpis. Nunc posuere, urna id lobortis ornare, neque ex ultricies erat, id "
+"sollicitudin ante quam sed magna. Nunc ultrices quam erat, eget dictum libero sollicitudin in. Nulla facilisi. "
+"Pellentesque eleifend risus non justo imperdiet aliquet. Donec finibus auctor ornare. Duis in arcu lacinia, "
+"fermentum tellus vel, efficitur justo. Morbi nec nunc leo. Proin lacinia erat vel elementum dapibus. Proin diam "
+"ipsum, mollis eu lobortis a, facilisis consectetur est. Vestibulum rutrum pellentesque urna, a laoreet justo dictum "
+"vitae. Nullam dictum, mi elementum dictum interdum, sem nisl fermentum est, nec mattis enim ante aliquam tortor. "
+"Phasellus eu quam magna. Vivamus augue enim, dictum in nibh non, condimentum tristique lorem. Suspendisse potenti. "
+"Sed nibh lacus, auctor ut arcu sollicitudin, posuere tempor urna. Phasellus at odio euismod ipsum congue auctor. "
+"Fusce vestibulum elementum nunc, vel feugiat nibh bibendum at. Quisque felis ligula, fermentum a metus ac, pulvinar "
+"hendrerit est. Proin vitae tincidunt purus, vestibulum eleifend ipsum. Ut rhoncus et elit ut varius. Praesent eu "
+"pharetra tellus. Suspendisse varius, dui quis efficitur fermentum, est lectus ultricies ex, a fermentum orci nunc eu "
+"lorem. Integer aliquet nunc ullamcorper lacinia elementum. In cursus tortor nisi, ut pharetra tortor venenatis eu. "
+"Duis tincidunt, libero sed varius dictum, neque velit facilisis enim, eget bibendum mi eros et nisl. Nam turpis "
+"neque, lobortis eget ante ac, tristique congue lacus. Aenean dictum vitae tortor sed tristique. Donec sodales in "
+"arcu ut tristique. Curabitur in facilisis nisi, non vulputate odio. Phasellus ut fringilla nunc, nec dapibus turpis. "
+"Sed ut erat tempor sem vulputate gravida at at dui. Aenean id dolor ante. Morbi auctor interdum nisi, id pretium "
+"eros ultrices vel. Nulla eget justo fringilla, finibus quam et, accumsan ex. In nisl neque, pharetra nec volutpat "
+"at, mattis nec odio. Nam et sapien sed libero lacinia tempor sit amet vitae turpis. Praesent vel porta lacus, porta "
+"dignissim nunc. Aenean vitae vulputate purus. Ut at elit arcu. Integer risus neque, varius ac elit maximus, "
+"ultricies sagittis nisi. Pellentesque sapien magna, malesuada tincidunt ornare sed, malesuada tempor odio. Morbi id "
+"neque velit. Pellentesque at velit sed elit eleifend auctor. Quisque tincidunt tempus justo, venenatis dapibus sem "
+"pellentesque quis. Suspendisse finibus feugiat est id consectetur. Nulla commodo, massa auctor vulputate egestas, "
+"arcu massa tincidunt leo, quis ullamcorper sapien augue in nibh. Pellentesque ultrices ligula tincidunt urna "
+"fringilla, ac ultricies eros convallis. Ut nec massa diam. Maecenas justo nulla, dapibus id justo sollicitudin, "
+"fermentum tempor dui. Vivamus laoreet auctor mi non venenatis. Nulla commodo libero ac ex volutpat tincidunt. Donec "
+"vestibulum blandit purus bibendum laoreet. Morbi in porta orci. Nam commodo ex eget diam maximus cursus. Proin "
+"bibendum quis felis eget euismod. Praesent neque neque, pulvinar eu sem non, gravida ornare tortor. Ut tortor nisi, "
+"suscipit in lectus ac, volutpat pretium nisi. Nam rutrum nec dui quis vulputate. Duis in velit enim. Fusce porttitor "
+"vitae nisi a tincidunt. Ut enim purus, venenatis ut purus ut, iaculis dignissim ex. Aliquam erat volutpat. "
+"Suspendisse potenti. Maecenas ut malesuada elit. Maecenas tellus neque, pulvinar non metus ut, viverra finibus diam. "
+"Sed ac porttitor dui. Fusce sit amet ligula metus. Integer id aliquet libero. Sed tempor nisl in porttitor "
+"ultricies. Maecenas molestie orci sed sapien molestie interdum non id felis. Nullam sagittis elementum erat in "
+"pretium. Nunc pellentesque, ex sit amet fringilla dignissim, augue quam dictum leo, eget tristique turpis mauris sed "
+"metus. Praesent vel mauris risus. Etiam eleifend metus ut risus tempor, ac ultrices dolor dictum. Nulla sagittis non "
+"urna vitae feugiat. In venenatis arcu vel finibus volutpat. Nam non bibendum magna, nec eleifend ex. Etiam sit amet "
+"nisl euismod, mattis nisi quis, commodo nisl. Nunc eget mauris vulputate, cursus neque in, hendrerit ante. Cras non "
+"nisl in nisl laoreet aliquam. Sed vestibulum, nunc vitae molestie varius, lectus justo vehicula est, nec placerat "
+"ipsum lectus quis leo. Maecenas efficitur semper eros, sed pretium arcu blandit eu. Aliquam eget purus cursus, "
+"sollicitudin augue quis, cursus purus. Maecenas sed finibus ligula. Curabitur at diam quis eros mollis semper. Nulla "
+"commodo nisi libero, id feugiat nisl tincidunt bibendum. Mauris convallis tincidunt justo eu sodales. Quisque arcu "
+"lacus, finibus sed hendrerit at, convallis ut diam. Nulla enim nulla, efficitur quis tincidunt et, pulvinar sit amet "
+"enim. Aenean mattis urna id mauris maximus tincidunt. In hac habitasse platea dictumst. Morbi ornare porta congue. "
+"Aliquam hendrerit efficitur mi at aliquet. Vivamus rutrum lectus vel turpis volutpat, consectetur congue sem "
+"consectetur. Sed rhoncus elit sed orci tincidunt, ut condimentum diam ornare. Nulla facilisi. Ut placerat et massa "
+"nec malesuada. Praesent dapibus condimentum augue, at imperdiet lacus facilisis sed. Praesent at metus nunc. Morbi "
+"accumsan eros et turpis viverra, nec sagittis odio iaculis. Aenean rhoncus, nibh a consectetur sodales, massa lorem "
+"commodo dui, sit amet consequat ex arcu eget augue. Praesent quis nibh urna. Cras eu congue ligula, in ultricies "
+"ante. Etiam interdum, est tincidunt euismod sollicitudin, lectus felis mollis ex, pretium fringilla magna lorem non "
+"libero. Fusce aliquam tellus eget sodales commodo. Sed sapien lectus, dapibus quis elit at, ultricies tincidunt "
+"eros. Nulla suscipit orci sit amet aliquam pellentesque. Cras sed eleifend ligula, quis vehicula ligula. Integer "
+"quis tortor in mauris dictum malesuada sed non turpis. Nulla faucibus quis arcu molestie vulputate. Proin fermentum "
+"tellus feugiat, imperdiet mi sit amet, tempor sem. Mauris hendrerit augue a vulputate vulputate. Vivamus sagittis at "
+"odio non venenatis. Nunc a molestie dolor. Nunc erat nisi, consequat et tristique in, blandit non tortor. Vivamus "
+"euismod bibendum augue, ut aliquam lorem mattis quis. Duis laoreet odio at justo ultricies, nec scelerisque enim "
+"euismod. Sed eu turpis a lorem cursus feugiat. Duis ultrices molestie nulla non pharetra. Morbi faucibus est auctor "
+"faucibus placerat. Donec blandit quis ex ac pulvinar. Vestibulum a consequat quam. Fusce vitae facilisis ex. Etiam a "
+"risus eu orci tincidunt interdum. Proin interdum eros nec nibh venenatis, sed luctus sapien tincidunt. In cursus, "
+"ante nec dapibus bibendum, augue tortor venenatis felis, eu aliquam erat est vitae diam. Cras lacinia placerat quam, "
+"eu finibus purus. Aenean et augue purus. Praesent efficitur ornare magna in cursus. Nunc quis tempor ante, ac "
+"accumsan ligula. Nullam elit diam, tempus in sollicitudin at, fermentum tincidunt mi. Vestibulum accumsan, nisi at "
+"rutrum scelerisque, justo mauris cursus nulla, finibus cursus nulla elit quis augue. Aliquam lacus ante, ullamcorper "
+"quis varius vitae, ullamcorper eget magna. Phasellus mollis nisl eu nulla eleifend, non tempus tellus faucibus. "
+"Curabitur molestie eros id eleifend accumsan. Suspendisse tristique sem ante, non blandit eros accumsan ac. Ut sit "
+"amet ante justo. Nam condimentum felis quis urna sagittis hendrerit. Cras condimentum est ac massa aliquet finibus. "
+"Donec faucibus malesuada fermentum. Aliquam malesuada augue vitae dolor rutrum pellentesque. Nullam vulputate "
+"rhoncus porta. Quisque vulputate dignissim felis sit amet aliquet. Nam elementum odio velit, eget fringilla mi "
+"dignissim at. Mauris mollis diam orci, vel porta risus tempor a. Nullam quis dolor volutpat, ornare est at, "
+"fermentum urna. Fusce mollis nisl a augue condimentum, eu dictum dolor posuere. Mauris et egestas sem. Sed pretium "
+"lectus laoreet velit feugiat luctus. Nullam sodales at augue vel semper. Pellentesque vehicula dictum augue, eget "
+"tristique orci interdum a. Aenean non est eleifend, tristique urna sed, elementum nunc. Sed consectetur id lorem "
+"quis mollis. Ut et blandit velit, et lobortis dolor. Quisque nec odio sed mi ullamcorper pellentesque. Ut vitae "
+"eleifend nisi, vitae dapibus est. Vivamus ornare eleifend volutpat. Sed et tincidunt nisi. Praesent maximus risus a "
+"bibendum consequat. Vestibulum quis ex vitae ante ultricies ultricies. Maecenas dictum tellus eget enim tincidunt "
+"imperdiet. Quisque vel libero gravida, mollis erat id, placerat dolor. Etiam ante eros, bibendum vitae ultricies in, "
+"rhoncus nec turpis. Pellentesque gravida nunc sit amet iaculis condimentum. Phasellus in ultricies libero, et "
+"maximus justo. Donec ut ultrices elit. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque "
+"rhoncus, nunc at iaculis dictum, magna lectus rhoncus augue, vel aliquam sem mauris in metus. Morbi commodo purus "
+"mi, ut faucibus dui luctus et. Suspendisse accumsan placerat tortor. Cras dignissim blandit leo, non tincidunt leo. "
+"Nulla euismod turpis ac malesuada aliquam. Ut ultrices bibendum elit sed elementum. Donec auctor aliquam vehicula. "
+"Mauris lacinia dignissim leo, ullamcorper egestas nibh rutrum eget. In semper sit amet libero eget ultricies. Proin "
+"et imperdiet odio. In hac habitasse platea dictumst. In hac habitasse platea dictumst. Integer sed dolor quis tortor "
+"pretium euismod at vel dolor. Donec aliquet et urna at porta. Vestibulum tincidunt eget sapien elementum mattis. "
+"Proin lacinia faucibus orci, sed eleifend augue mollis et. Vestibulum ante ipsum primis in faucibus orci luctus et "
+"ultrices posuere cubilia Curae; Cras pellentesque, dolor eget bibendum tincidunt, turpis ante pharetra tortor, quis "
+"interdum tellus tellus sit amet nisl. Nulla convallis tempus egestas. Curabitur quis condimentum metus, eu placerat "
+"metus. Nunc ligula nunc, posuere at iaculis nec, convallis id tellus. Curabitur pretium libero lorem, quis placerat "
+"nunc fringilla interdum. Vestibulum et finibus ante. Duis quis nisi neque. Curabitur ornare lorem nec ex fringilla, "
+"et porta massa consequat. Nulla malesuada turpis nec eleifend tincidunt. Praesent ultricies dolor vitae mauris "
+"lacinia tempor. Sed blandit sapien a odio scelerisque consequat. Mauris non dictum eros. Vestibulum ante ipsum "
+"primis in faucibus orci luctus et ultrices posuere cubilia Curae; Pellentesque habitant morbi tristique senectus et "
+"netus et malesuada fames ac turpis egestas. In ut sollicitudin tellus. Suspendisse ultrices vitae erat non pharetra. "
+"Nulla pellentesque at diam venenatis sollicitudin. Vestibulum sed finibus sapien. Curabitur a metus convallis, "
+"euismod est id, iaculis nunc. Vestibulum laoreet ornare turpis. Integer rhoncus, felis nec fermentum suscipit, dui "
+"lacus sagittis ligula, vitae vestibulum urna elit aliquam est. Sed sit amet mi tortor. Suspendisse a dapibus velit. "
+"Cras eget imperdiet turpis. Maecenas at lorem condimentum, elementum augue mattis, rutrum purus. Duis imperdiet "
+"pellentesque nunc, eu tristique lectus malesuada commodo. Vivamus aliquet congue eros ac dapibus. Nunc quis "
+"porttitor odio. Nulla quis dui luctus, vestibulum enim malesuada, imperdiet elit. Donec facilisis mollis diam ut "
+"posuere. Nulla facilisi. Duis nec magna lacus. Vestibulum consequat ut tortor ut ornare. Curabitur nec felis sit "
+"amet dui finibus rutrum. Phasellus sit amet lectus nec nisl egestas posuere. Etiam nec euismod magna, vitae "
+"ullamcorper enim. Vestibulum pretium cursus semper. Cras vel lorem ut urna molestie elementum. Mauris luctus vel "
+"arcu quis egestas. Suspendisse potenti. Nullam viverra sollicitudin lacus luctus sodales. Maecenas eget diam cursus "
+"quam tincidunt ultricies vitae nec lacus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec urna "
+"sapien, porta a efficitur vitae, imperdiet vel ligula. Nulla volutpat massa sit amet est aliquet, ut iaculis tellus "
+"convallis. Sed justo tortor, sodales non nisi quis, laoreet commodo quam. Cras tempus purus a tempor malesuada. "
+"Curabitur enim nibh, viverra in enim eget, viverra euismod nunc. Mauris nunc leo, faucibus blandit condimentum nec, "
+"rutrum sit amet leo. Quisque nec tortor sed felis pretium imperdiet. Morbi lobortis, dolor nec lobortis maximus, "
+"turpis justo aliquet massa, eget aliquet nunc mauris a lectus. Phasellus dignissim, est nec luctus consequat, ex "
+"nisi euismod lacus, a viverra nulla eros et est. Suspendisse in egestas dolor. Etiam non placerat lorem. "
+"Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aliquam ut enim "
+"tristique, porta nulla quis, placerat eros. Integer eget feugiat mi, ac condimentum felis. Fusce auctor ligula ut "
+"est placerat efficitur. Nam hendrerit condimentum ante eget tincidunt. Phasellus vel convallis neque. Vivamus sit "
+"amet elit eu enim iaculis scelerisque. Donec imperdiet lacus id magna luctus, vitae dapibus quam condimentum. Donec "
+"laoreet vehicula tellus. Nullam nec neque at massa ultricies dignissim. Suspendisse potenti. Cras convallis nunc "
+"urna, a tempor metus volutpat ut. Fusce viverra lorem vitae quam ullamcorper cursus. Mauris maximus et mi eget "
+"tincidunt. Proin molestie suscipit felis at ultricies. Duis varius rhoncus metus vehicula bibendum. Aliquam "
+"consequat non tellus at aliquam. Vivamus nec turpis facilisis, dapibus lacus in, congue tortor. Curabitur at "
+"interdum mi, sed rhoncus nibh. Morbi facilisis purus laoreet, tincidunt justo sit amet, elementum lectus. Vestibulum "
+"pellentesque sem lacus, in condimentum purus consequat at. Integer pharetra rhoncus aliquam. Duis nec sem ac elit "
+"suscipit laoreet. Integer vel est commodo, feugiat sapien eget, cursus quam. Aenean elit leo, interdum a posuere "
+"nec, laoreet eu magna. Nam sit amet felis faucibus, porttitor justo eget, commodo mi. Maecenas a eleifend nibh. "
+"Donec ut ornare augue. Aliquam pellentesque aliquet eros in hendrerit. Nullam consectetur odio id lectus ullamcorper "
+"facilisis. Donec pulvinar, magna non sollicitudin commodo, erat lacus egestas massa, a egestas nibh nulla ac lorem. "
+"Maecenas at mi posuere, fringilla lectus sed, fringilla eros. Vivamus mattis at magna ac suscipit. Proin varius mi a "
+"quam efficitur ullamcorper. Curabitur venenatis turpis lacus, vitae volutpat velit ultricies sed. Sed faucibus id "
+"neque in consequat. Nulla imperdiet fermentum placerat. Donec rutrum libero ac lorem commodo pellentesque in tempor "
+"augue. Maecenas sodales cursus ex, ac elementum felis consectetur vel. Cras ante nulla, porttitor nec ex non, "
+"venenatis consectetur justo. Nam vitae enim eget augue euismod suscipit et in nulla. Morbi eu sollicitudin libero, "
+"ut lobortis purus. Pellentesque sodales tempor diam, a luctus dui vehicula tempus. Cum sociis natoque penatibus et "
+"magnis dis parturient montes, nascetur ridiculus mus. Vestibulum dignissim sagittis diam ac aliquam. Integer iaculis "
+"ac est eu molestie. Vivamus convallis arcu nec rutrum molestie. Vestibulum mollis ipsum neque. Vestibulum "
+"condimentum neque quis tellus elementum, in facilisis neque venenatis. Donec quis ultrices risus. Cras mattis felis "
+"eget erat iaculis, id scelerisque mauris pharetra. Vivamus condimentum tempor ipsum, porta commodo erat dictum ut. "
+"Fusce et ligula sed arcu tincidunt efficitur nec ut felis. Donec eu justo pellentesque, finibus diam quis, iaculis "
+"erat. Fusce a tempus urna, at fermentum est. Sed pretium orci dapibus ante laoreet, a consequat erat scelerisque. "
+"Etiam nisi tortor, vulputate quis sapien sit amet, lobortis blandit felis. Morbi urna purus, pellentesque quis orci "
+"id, suscipit consequat velit. Donec vehicula ipsum felis. Donec at elit ipsum. Fusce purus sapien, convallis quis "
+"faucibus et, tempus at dolor. Vivamus commodo sem ac congue imperdiet. Vivamus convallis eget est eu vulputate. "
+"Aliquam vehicula augue ac urna imperdiet interdum. Praesent euismod arcu quis purus vestibulum, et placerat metus "
+"hendrerit. Fusce semper lacus sit amet ligula scelerisque scelerisque. Vestibulum neque ex, aliquam non lorem a, "
+"aliquam fringilla enim. Aenean consectetur vestibulum tortor. Donec et elit consectetur, tincidunt augue feugiat, "
+"condimentum diam. In luctus tellus at massa euismod faucibus. Ut tempus dui hendrerit, vehicula ex ut, facilisis "
+"lacus. Pellentesque bibendum enim auctor, vulputate justo vel, ultricies est. Praesent interdum turpis in convallis "
+"luctus. Duis vel enim venenatis, mollis elit vitae, mattis velit. In eu posuere nibh. Duis a est est. Nam semper "
+"tincidunt nulla id dignissim. Fusce consectetur maximus eros quis posuere. Sed efficitur, enim quis ultrices "
+"eleifend, est diam commodo dui, nec euismod augue velit sit amet ante. Integer fringilla vehicula faucibus. "
+"Curabitur non placerat turpis. Integer malesuada quam eget sapien tristique aliquet. In hac habitasse platea "
+"dictumst. Cras dignissim mauris neque, in facilisis nulla pulvinar ac. Phasellus sagittis ligula non sem aliquet "
+"iaculis. Integer interdum elit in dolor vehicula, non condimentum justo pretium. Aliquam eget feugiat tellus. "
+"Suspendisse condimentum dui at erat elementum semper. Aliquam vitae cursus lorem. Ut vestibulum porttitor purus ut "
+"dapibus. Curabitur posuere nunc quis nisi rhoncus, ac mollis enim eleifend. Aenean tristique at justo ut tempor. "
+"Proin posuere condimentum arcu ac lobortis. Proin euismod posuere ipsum, nec dignissim velit eleifend gravida. "
+"Quisque quis sem mi. Proin scelerisque consequat lectus nec sodales. Fusce id sapien a erat cursus sodales. Morbi ac "
+"magna vitae lorem dictum luctus in et lacus. Morbi imperdiet mi interdum, molestie sem in, accumsan leo. Sed lacinia "
+"enim et sem egestas, a pulvinar velit ullamcorper. Aenean laoreet, erat eu viverra dictum, eros odio venenatis mi, "
+"tincidunt blandit odio mauris id augue. Donec pretium mauris nibh, ut eleifend velit auctor vitae. Morbi tincidunt "
+"lacus id ullamcorper egestas. Proin vel porttitor purus, eu fermentum dui. Aliquam a interdum mi. Aliquam ut rhoncus "
+"nibh. Morbi nulla libero, commodo quis eros eu, scelerisque gravida ligula. Aliquam sed arcu nunc. Sed egestas "
+"hendrerit orci, nec rhoncus arcu fringilla quis. Pellentesque lobortis nulla arcu. Integer aliquam vel quam sed "
+"tempor. Morbi viverra tempus risus vel convallis. Cras eget neque ex. Mauris porta, risus at rhoncus hendrerit, "
+"libero metus pharetra sapien, quis viverra tortor nunc tincidunt magna. Aenean a tellus ullamcorper, convallis urna "
+"quis, suscipit sem. Vivamus eu eleifend est. Duis venenatis metus eget ex consequat molestie. In ullamcorper a dolor "
+"vitae feugiat. Morbi ultrices vestibulum venenatis. Phasellus luctus enim id aliquet pharetra. Aenean mauris felis, "
+"finibus eu dolor at, tempor sodales diam. Sed nisl nibh, tincidunt quis fringilla vel, congue eu dui. Duis viverra "
+"justo eu sem ultricies dignissim. Morbi et sollicitudin erat. Proin id porttitor odio, et sagittis ex. Aenean "
+"laoreet leo sit amet risus vestibulum, mollis ultrices tortor porttitor. Sed vestibulum varius ligula quis accumsan. "
+"Duis fermentum, dolor iaculis condimentum tincidunt, purus nunc bibendum nibh, ac sodales tortor odio non ante. Sed "
+"leo mauris, consequat molestie quam eu, vulputate volutpat metus. Cras fringilla risus sed arcu consequat luctus. "
+"Nam malesuada, turpis at luctus blandit, velit elit fringilla metus, eu mollis odio felis id tortor. Aliquam erat "
+"tellus, pulvinar nec iaculis et, consequat sit amet diam. Sed vestibulum, leo ut vehicula suscipit, quam justo "
+"maximus lectus, nec lobortis urna tortor nec nisi. Vestibulum eget ornare arcu, sed viverra turpis. Sed posuere "
+"tellus iaculis, scelerisque dui id, convallis lectus. Aliquam sodales at mi consectetur dignissim. In fringilla, "
+"urna id placerat mattis, diam magna commodo dui, at elementum arcu elit et libero. Duis venenatis vulputate nisl "
+"congue pharetra. Fusce sapien velit, cursus a consectetur quis, auctor gravida sem. Maecenas malesuada metus quis "
+"elit congue accumsan. Vivamus scelerisque euismod malesuada. Vestibulum purus metus, tempor eget faucibus a, cursus "
+"eu arcu. Morbi dictum urna vitae velit pellentesque facilisis. Sed arcu est, tempor ac turpis sit amet, ultricies "
+"venenatis augue. Nunc laoreet leo gravida facilisis dapibus. Aliquam convallis ullamcorper felis, sit amet tempor "
+"libero euismod sit amet. Quisque leo augue, finibus et euismod non, venenatis sed libero. Cras pharetra rhoncus "
+"odio, in pharetra lacus porttitor scelerisque. Maecenas eleifend felis vitae diam blandit viverra. Fusce at "
+"ultricies arcu, pharetra finibus enim. Etiam pellentesque semper ligula, sed tincidunt purus. Sed fermentum metus "
+"varius, aliquet libero eget, vehicula erat. Sed ac finibus metus. Pellentesque libero leo, semper et eros nec, "
+"gravida condimentum urna. Cras nec turpis convallis, efficitur lacus at, ultricies ex. Fusce eu neque elementum leo "
+"gravida semper. Duis sed tellus vitae magna fringilla maximus ac ut nisl. Integer id ligula ullamcorper, ultricies "
+"quam sit amet, ullamcorper diam. Maecenas rhoncus nulla eu dui vulputate scelerisque. Vestibulum porttitor eget nibh "
+"a mattis. Mauris tempus at urna blandit dignissim. Proin turpis leo, mattis ut turpis eget, aliquet tempor ante. "
+"Nunc in mollis nunc, et interdum nisi. Cras tristique sollicitudin tortor sit amet ultrices. Proin rhoncus neque "
+"urna. Maecenas bibendum, massa sit amet suscipit suscipit, justo tortor maximus dolor, posuere facilisis nisi tellus "
+"elementum diam. Quisque id eros vel lectus malesuada tincidunt. Donec at orci ac ligula venenatis dignissim sit amet "
+"nec purus. Sed eu neque finibus, tristique ex a, feugiat ante. Pellentesque tincidunt luctus mollis. Nullam blandit "
+"faucibus gravida. Ut sit amet malesuada nibh, vel tincidunt ipsum. Donec suscipit lorem in dui luctus, viverra "
+"imperdiet magna placerat. Pellentesque venenatis eros quis urna efficitur facilisis. Cras ligula magna, tempus "
+"facilisis tincidunt at, varius quis lectus. Sed quam neque, facilisis vel facilisis vel, lobortis ac orci. Nullam "
+"pretium interdum erat ac ultrices. Etiam enim mauris, vehicula nec rhoncus quis, volutpat vel erat. Morbi imperdiet "
+"rhoncus rutrum. Nullam auctor condimentum diam nec faucibus. Etiam sit amet porta nulla, sit amet lobortis enim. "
+"Aenean tincidunt condimentum accumsan. Vestibulum mollis diam risus, vitae ornare enim iaculis non. Nullam vitae "
+"risus tristique, imperdiet augue ut, egestas dolor. Sed sit amet leo eu diam commodo vestibulum id in dolor. Vivamus "
+"tristique molestie faucibus. Duis tempor porttitor turpis ac consectetur. Curabitur condimentum, ipsum eu dignissim "
+"semper, ipsum erat pretium quam, ut maximus erat ligula eu felis. Sed viverra, mauris id tempus tempor, nisi leo "
+"consectetur arcu, ac vulputate lorem mauris non sapien. Maecenas rhoncus magna mauris, in luctus nulla dapibus at. "
+"Sed magna est, ultrices sit amet erat nec, dapibus lacinia massa. Morbi cursus ex in elit auctor egestas. Quisque id "
+"placerat nibh, at mollis tortor. Proin fringilla sodales sapien, ac ullamcorper sem bibendum eget. Donec dui ligula, "
+"viverra eget leo ac, tincidunt fringilla mauris. Quisque vel lectus eget metus feugiat laoreet. Morbi eget "
+"vestibulum enim, ac ultricies lorem. Nam at mollis magna. Etiam vitae orci eu leo facilisis vestibulum. Ut sed "
+"turpis ut nibh iaculis rhoncus. Phasellus sit amet risus pellentesque, gravida eros a, porta nibh. Suspendisse at "
+"tincidunt ligula. Vivamus id libero diam. Morbi viverra ipsum turpis, in ullamcorper enim pellentesque nec. Sed "
+"ultricies, lectus quis pellentesque sodales, arcu diam commodo massa, a vestibulum purus sapien eget risus. Duis "
+"rhoncus in velit in dignissim. Aliquam sit amet metus in quam finibus cursus. Pellentesque eget aliquam justo. Fusce "
+"imperdiet, tellus non venenatis facilisis, diam mi lobortis dolor, at consectetur est massa id elit. Vivamus ante "
+"ex, faucibus et mollis eget, dignissim vel massa. Duis ultricies diam commodo purus facilisis pharetra. Curabitur "
+"pretium massa sed enim vehicula, id vehicula neque vehicula. In quis lectus non mauris pulvinar fermentum. Aliquam "
+"condimentum aliquet dui et congue. Maecenas quis augue eget leo gravida aliquet. Praesent sit amet fermentum odio, "
+"ut placerat nulla. Curabitur sit amet iaculis erat, eu volutpat odio. Ut iaculis ex quis tempus commodo. "
+"Pellentesque cursus eros at velit vulputate, id luctus massa pretium. Morbi ex dui, sodales id finibus id, aliquet a "
+"justo. Maecenas semper leo eget dolor rutrum, at imperdiet nibh eleifend. Aliquam eget purus tortor. Cras rutrum "
+"tortor massa, vel bibendum nunc aliquam vel. Nullam vestibulum, metus vel fermentum elementum, nulla sapien egestas "
+"justo, ac feugiat ex justo nec eros. Donec sit amet nibh mollis, commodo quam sit amet, semper magna. In tortor "
+"magna, elementum nec auctor sed, pellentesque at augue. Sed gravida arcu ac aliquet convallis. Nulla facilisi. Duis "
+"nunc quam, gravida non interdum id, cursus ac leo. Suspendisse vel ipsum nisl. Aliquam at gravida libero. Maecenas "
+"sit amet efficitur orci. Fusce id vehicula sapien. Proin euismod diam non laoreet ultricies. Nunc ullamcorper, nibh "
+"id cursus vehicula, ex purus tempor urna, et euismod orci est sed elit. Duis ut blandit mauris. Ut blandit cursus "
+"eros, sed laoreet nisl efficitur ac. Phasellus dui elit, fringilla sit amet cursus nec, pharetra quis odio. Ut ut "
+"lorem sit amet sem dapibus accumsan. Aenean a laoreet dolor. Donec eu laoreet velit. Etiam id nisi vel nibh dapibus "
+"congue a quis odio. Donec velit risus, semper quis porta non, elementum quis lorem. Interdum et malesuada fames ac "
+"ante ipsum primis in faucibus. Nullam sit amet dolor magna. Maecenas quis sapien sit amet est pulvinar lobortis "
+"efficitur cursus orci. Phasellus tristique mauris lorem, eu ultricies justo ornare condimentum. Integer urna enim, "
+"lobortis id malesuada ut, mattis eget libero. Sed commodo tincidunt eleifend. Fusce sed velit ut dui pellentesque "
+"pellentesque eget vel diam. Aenean nec turpis at tortor consectetur consectetur. Vestibulum ultrices elit at nisl "
+"pellentesque molestie. Maecenas diam dolor, faucibus eget posuere ut, sodales ut eros. Nam vulputate mollis diam nec "
+"gravida. Nam et ullamcorper diam. Aenean non nulla non lorem ullamcorper sagittis non quis erat. Pellentesque "
+"habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In hac habitasse platea dictumst. "
+"Donec quis mauris ac nibh vestibulum eleifend placerat sed lacus. Suspendisse mi elit, viverra non velit ut, "
+"tincidunt tempus felis. Fusce ullamcorper, arcu nec aliquet porttitor, odio lacus mollis mi, id malesuada tortor "
+"velit aliquet turpis. Sed hendrerit felis nec faucibus ornare. Nulla ut metus eget augue malesuada posuere eget eu "
+"tortor. Cras ultrices odio sit amet porttitor vehicula. Sed vulputate leo vitae justo viverra, nec volutpat eros "
+"consectetur. Nunc nunc tellus, porta in arcu in, vulputate ultricies tellus. Fusce commodo efficitur lorem, sit amet "
+"lacinia sapien sollicitudin at. Etiam aliquet non mi vitae ornare. Cras condimentum imperdiet elit eu dictum. Donec "
+"sed enim sed massa tempor porta et sit amet felis. Nam interdum ornare sem, in tincidunt risus consectetur vel. Ut "
+"convallis purus mauris, in consequat ligula ullamcorper ut. Quisque elit ipsum, accumsan eget ligula vitae, "
+"sollicitudin luctus tellus. Nunc pretium turpis ligula, id dignissim lorem suscipit eu. Nulla facilisi. Sed lectus "
+"odio, vehicula vel vulputate id, ultrices non ipsum. Donec arcu quam, consequat eget aliquet sit amet, ullamcorper "
+"non nibh. Etiam finibus, mi id lobortis sagittis, leo leo lobortis lectus, sit amet aliquam dui odio sit amet massa. "
+"Suspendisse iaculis urna ac lectus gravida, iaculis efficitur tellus hendrerit. Sed tellus enim, condimentum in "
+"augue eget, sagittis ullamcorper sem. Suspendisse vitae aliquet libero. Aenean quis purus in sapien dapibus "
+"suscipit. Sed commodo nunc in lacus bibendum, vel tincidunt ante ornare. Ut tristique luctus volutpat. Class aptent "
+"taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Quisque a ultricies orci, eu porta "
+"odio. Vivamus sapien arcu, ultrices vel dui ut, luctus viverra purus. Praesent fringilla sed odio quis pretium. "
+"Vestibulum ullamcorper nisi tortor, id sollicitudin lectus tempor a. Ut malesuada sapien eu sapien posuere, non "
+"euismod eros porta. Nunc vel tincidunt ligula. Cras dolor ante, tristique tempor metus quis, mollis vulputate orci. "
+"Curabitur vitae nisl euismod, elementum purus vel, dictum lorem. Nunc eu mauris at metus porttitor dignissim ut eu "
+"neque. In tempor rhoncus neque sit amet commodo. Maecenas sed lacus semper, tempus enim ac, fermentum lorem. Nullam "
+"sollicitudin convallis turpis. Curabitur finibus placerat viverra. Pellentesque convallis condimentum tortor id "
+"efficitur. Proin semper pretium est, et vehicula ex cursus a. Nam ut felis purus. Phasellus eget felis eget leo "
+"dapibus vestibulum. Nulla eleifend malesuada turpis, quis faucibus eros. Nam aliquet euismod viverra. Ut quis semper "
+"felis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Pellentesque at nulla "
+"arcu. Integer ut tellus ac sapien maximus tincidunt sed vitae risus. Nulla viverra, nibh eget eleifend aliquam, quam "
+"quam tempor massa, eu semper ipsum lacus in turpis. Nulla sed purus enim. Nullam sed fermentum ipsum. Sed dui nisi, "
+"elementum a auctor at, ultrices et nibh. Phasellus aliquam nulla ut lacinia accumsan. Phasellus sed arcu ligula. "
+"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam fermentum magna vitae dui sagittis tempor. Vivamus "
+"eu ligula blandit, imperdiet arcu at, rutrum sem. Aliquam erat volutpat. Quisque luctus enim quis volutpat lobortis. "
+"Vestibulum eget sodales libero. Aenean at condimentum est. Proin eget massa vel nulla efficitur tempor eget at enim. "
+"Integer enim sapien, ornare luctus nisl non, pretium facilisis ex. Donec pretium ligula ligula, a facilisis turpis "
+"hendrerit at. Nullam eget malesuada justo, at molestie quam. Sed consequat massa eu faucibus maximus. Curabitur "
+"placerat orci sapien, sit amet semper magna sodales non. Ut fermentum accumsan odio in consectetur. Morbi neque mi, "
+"vulputate nec mi ut, cursus scelerisque lectus. Nulla sapien enim, finibus id ipsum luctus, consequat ullamcorper "
+"lectus. Sed volutpat sed massa in sodales. Morbi lacinia diam eu commodo vulputate. Fusce aliquet pulvinar dolor in "
+"egestas. Fusce molestie commodo leo eu ultricies. Nulla mollis rhoncus pharetra. Pellentesque rutrum mauris ac lorem "
+"posuere, a eleifend mi rutrum. Nulla porta turpis aliquet felis congue rutrum. Fusce quis arcu in sem placerat "
+"condimentum a ut turpis. Quisque quis porttitor nulla. Donec sit amet quam tincidunt, pulvinar erat id, molestie "
+"dolor. Praesent luctus vitae nunc vitae pellentesque. Praesent faucibus sed urna ut lacinia. Vivamus id justo quis "
+"dolor porta rutrum nec nec odio. Cras euismod tortor quis diam ultrices, eu mattis nisi consectetur. Fusce mattis "
+"nisi vel condimentum molestie. Fusce fringilla ut nibh volutpat elementum. Mauris posuere consectetur leo a aliquet. "
+"Donec quis sodales sapien. Maecenas ut felis tempus, eleifend mauris et, faucibus mi. Quisque fringilla orci arcu, "
+"sit amet porta risus hendrerit non. Aenean id sem nisi. Nullam non nisl vestibulum, pellentesque nisl et, imperdiet "
+"ligula. Sed laoreet fringilla felis. Proin ac dolor viverra tellus mollis aliquet eget et neque. Suspendisse mattis "
+"nulla vitae nulla sagittis blandit. Sed at tortor rutrum, ornare magna nec, pellentesque nisi. Etiam non aliquet "
+"tellus. Aliquam at ex suscipit, posuere sem sit amet, tincidunt.";
+
+#endif /* __BLENDER_TESTING_BLI_RESSOURCE_STRING_H__ */
diff --git a/tests/gtests/blenlib/BLI_stack_test.cc b/tests/gtests/blenlib/BLI_stack_test.cc
index 08701356816..44956a589dc 100644
--- a/tests/gtests/blenlib/BLI_stack_test.cc
+++ b/tests/gtests/blenlib/BLI_stack_test.cc
@@ -11,6 +11,14 @@ extern "C" {
#define SIZE 1024
+/* number of items per chunk. use a small value to expose bugs */
+#define STACK_CHUNK_SIZE 8
+
+/* Ensure block size is set to #STACK_NEW_EX_ARGS */
+#define BLI_stack_new(esize, descr) \
+ BLI_stack_new_ex(esize, descr, esize * STACK_CHUNK_SIZE)
+
+
TEST(stack, Empty)
{
BLI_Stack *stack;
@@ -110,18 +118,60 @@ TEST(stack, Peek)
EXPECT_EQ(BLI_stack_is_empty(stack), true);
}
+/* Check that clearing the stack leaves in it a correct state. */
+TEST(stack, Clear)
+{
+ const int tot_rerun = 4;
+ int rerun;
+
+ /* based on range test */
+ int tot = SIZE;
+ BLI_Stack *stack;
+ int in, out;
+
+ /* use a small chunk size to ensure we test */
+ stack = BLI_stack_new(sizeof(in), __func__);
+
+ for (rerun = 0; rerun < tot_rerun; rerun++) {
+ for (in = 0; in < tot; in++) {
+ BLI_stack_push(stack, (void *)&in);
+ }
+
+ BLI_stack_clear(stack);
+ EXPECT_EQ(BLI_stack_is_empty(stack), true);
+
+ /* and again, this time check its valid */
+ for (in = 0; in < tot; in++) {
+ BLI_stack_push(stack, (void *)&in);
+ }
+
+ for (in = tot - 1; in >= 0; in--) {
+ EXPECT_EQ(BLI_stack_is_empty(stack), false);
+ BLI_stack_pop(stack, (void *)&out);
+ EXPECT_EQ(in, out);
+ }
+
+ EXPECT_EQ(BLI_stack_is_empty(stack), true);
+
+ /* without this, we wont test case when mixed free/used */
+ tot /= 2;
+ }
+
+ BLI_stack_free(stack);
+}
+
TEST(stack, Reuse)
{
const int sizes[] = {3, 11, 81, 400, 999, 12, 1, 9721, 7, 99, 5, 0};
int sizes_test[ARRAY_SIZE(sizes)];
const int *s;
- int in, out, i;
+ int out, i;
int sum, sum_test;
BLI_Stack *stack;
- stack = BLI_stack_new(sizeof(in), __func__);
+ stack = BLI_stack_new(sizeof(i), __func__);
/* add a bunch of numbers, ensure we get same sum out */
sum = 0;
diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt
index 3a86d3f770d..20b876053d9 100644
--- a/tests/gtests/blenlib/CMakeLists.txt
+++ b/tests/gtests/blenlib/CMakeLists.txt
@@ -43,3 +43,8 @@ BLENDER_TEST(BLI_path_util "bf_blenlib;extern_wcwidth;${ZLIB_LIBRARIES}")
BLENDER_TEST(BLI_polyfill2d "bf_blenlib")
BLENDER_TEST(BLI_listbase "bf_blenlib")
BLENDER_TEST(BLI_hash_mm2a "bf_blenlib")
+BLENDER_TEST(BLI_ghash "bf_blenlib")
+
+if(WITH_TESTS_PERFORMANCE)
+ BLENDER_TEST(BLI_ghash_performance "bf_blenlib")
+endif()
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index fd47bba4182..81438d357e4 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -395,6 +395,12 @@ if(WITH_CYCLES)
-testdir "${TEST_SRC_DIR}/cycles/ctests/reports"
-idiff "${OPENIMAGEIO_IDIFF}"
)
+ add_test(cycles_render_test
+ ${CMAKE_CURRENT_LIST_DIR}/cycles_render_tests.py
+ -blender "${TEST_BLENDER_EXE_BARE}"
+ -testdir "${TEST_SRC_DIR}/cycles/ctests/render"
+ -idiff "${OPENIMAGEIO_IDIFF}"
+ )
add_test(cycles_shaders_test
${CMAKE_CURRENT_LIST_DIR}/cycles_render_tests.py
-blender "${TEST_BLENDER_EXE_BARE}"
diff --git a/tests/python/bl_load_addons.py b/tests/python/bl_load_addons.py
index 227edf4164d..6bb0eaecd3d 100644
--- a/tests/python/bl_load_addons.py
+++ b/tests/python/bl_load_addons.py
@@ -34,11 +34,29 @@ import imp
BLACKLIST_DIRS = (
os.path.join(bpy.utils.resource_path('USER'), "scripts"),
) + tuple(addon_utils.paths()[1:])
+BLACKLIST_ADDONS = set()
+
+
+def _init_addon_blacklist():
+
+ # in case we built without cycles
+ if not bpy.app.build_options.cycles:
+ BLACKLIST_ADDONS.add("cycles")
+
+ # in case we built without freestyle
+ if not bpy.app.build_options.freestyle:
+ BLACKLIST_ADDONS.add("render_freestyle_svg")
+
+ # netrender has known problems re-registering
+ BLACKLIST_ADDONS.add("netrender")
def addon_modules_sorted():
modules = addon_utils.modules({})
- modules[:] = [mod for mod in modules if not mod.__file__.startswith(BLACKLIST_DIRS)]
+ modules[:] = [
+ mod for mod in modules
+ if not (mod.__file__.startswith(BLACKLIST_DIRS))
+ if not (mod.__name__ in BLACKLIST_ADDONS)]
modules.sort(key=lambda mod: mod.__name__)
return modules
@@ -64,7 +82,7 @@ def test_load_addons():
mod_name = mod.__name__
print("\tenabling:", mod_name)
addon_utils.enable(mod_name, default_set=True)
- if mod_name not in addons:
+ if (mod_name not in addons) and (mod_name not in BLACKLIST_ADDONS):
addons_fail.append(mod_name)
if addons_fail:
@@ -106,6 +124,9 @@ def reload_addons(do_reload=True, do_reverse=True):
def main():
+
+ _init_addon_blacklist()
+
# first load addons, print a list of all addons that fail
test_load_addons()
diff --git a/tests/python/bl_rna_defaults.py b/tests/python/bl_rna_defaults.py
new file mode 100644
index 00000000000..1d6f82b06c2
--- /dev/null
+++ b/tests/python/bl_rna_defaults.py
@@ -0,0 +1,117 @@
+# Apache License, Version 2.0
+
+# ./blender.bin --background -noaudio --factory-startup --python tests/python/bl_rna_defaults.py
+
+import bpy
+
+DUMMY_NAME = "Untitled"
+DUMMY_PATH = __file__
+GLOBALS = {
+ "error_num": 0,
+ }
+
+
+def validate_defaults(test_id, o):
+
+ def warning(prop_id, val_real, val_default):
+ print("Error %s: '%s.%s' is:%r, expected:%r" %
+ (test_id, o.__class__.__name__, prop_id, val_real, val_default))
+ GLOBALS["error_num"] += 1
+
+ properties = type(o).bl_rna.properties.items()
+ for prop_id, prop in properties:
+ if prop_id == "rna_type":
+ continue
+ prop_type = prop.type
+ if prop_type in {'STRING', 'COLLECTION'}:
+ continue
+
+ if prop_type == 'POINTER':
+ # traverse down pointers if they're set
+ val_real = getattr(o, prop_id)
+ if (val_real is not None) and (not isinstance(val_real, bpy.types.ID)):
+ validate_defaults("%s.%s" % (test_id, prop_id), val_real)
+ elif prop_type in {'INT', 'BOOL'}:
+ array_length = prop.array_length
+ if array_length == 0:
+ val_real = getattr(o, prop_id)
+ val_default = prop.default
+ if val_real != val_default:
+ warning(prop_id, val_real, val_default)
+ else:
+ pass # TODO, array defaults
+ elif prop_type == 'FLOAT':
+ array_length = prop.array_length
+ if array_length == 0:
+ val_real = getattr(o, prop_id)
+ val_default = prop.default
+ if val_real != val_default:
+ warning(prop_id, val_real, val_default)
+ else:
+ pass # TODO, array defaults
+ elif prop_type == 'ENUM':
+ val_real = getattr(o, prop_id)
+ if prop.is_enum_flag:
+ val_default = prop.default_flag
+ else:
+ val_default = prop.default
+ if val_real != val_default:
+ warning(prop_id, val_real, val_default)
+
+ # print(prop_id, prop_type)
+
+
+def _test_id_gen(data_attr, args_create=(DUMMY_NAME,), create_method="new"):
+ def test_gen(test_id):
+ id_collection = getattr(bpy.data, data_attr)
+ create_fn = getattr(id_collection, create_method)
+ o = create_fn(*args_create)
+ o.user_clear()
+ validate_defaults(test_id, o)
+ id_collection.remove(o)
+ return test_gen
+
+
+test_Action = _test_id_gen("actions")
+test_Armature = _test_id_gen("armatures")
+test_Camera = _test_id_gen("cameras")
+test_Group = _test_id_gen("groups")
+test_Lattice = _test_id_gen("lattices")
+test_LineStyle = _test_id_gen("linestyles")
+test_Mask = _test_id_gen("masks")
+test_Material = _test_id_gen("materials")
+test_Mesh = _test_id_gen("meshes")
+test_MetaBall = _test_id_gen("metaballs")
+test_MovieClip = _test_id_gen("movieclips", args_create=(DUMMY_PATH,), create_method="load")
+test_Object = _test_id_gen("objects", args_create=(DUMMY_NAME, None))
+test_Palette = _test_id_gen("palettes")
+test_Particle = _test_id_gen("particles")
+test_Scene = _test_id_gen("scenes")
+test_Sound = _test_id_gen("sounds", args_create=(DUMMY_PATH,), create_method="load")
+test_Speaker = _test_id_gen("speakers")
+test_Text = _test_id_gen("texts")
+test_VectorFont = _test_id_gen("fonts", args_create=("<builtin>",), create_method="load")
+test_World = _test_id_gen("worlds")
+
+ns = globals()
+for t in bpy.data.curves.bl_rna.functions["new"].parameters["type"].enum_items.keys():
+ ns["test_Curve_%s" % t] = _test_id_gen("curves", args_create=(DUMMY_NAME, t))
+for t in bpy.data.lamps.bl_rna.functions["new"].parameters["type"].enum_items.keys():
+ ns["test_Lamp_%s" % t] = _test_id_gen("lamps", args_create=(DUMMY_NAME, t))
+# types are a dynamic enum, have to hard-code.
+for t in "ShaderNodeTree", "CompositorNodeTree", "TextureNodeTree":
+ ns["test_NodeGroup_%s" % t] = _test_id_gen("node_groups", args_create=(DUMMY_NAME, t))
+for t in bpy.data.textures.bl_rna.functions["new"].parameters["type"].enum_items.keys():
+ ns["test_Texture_%s" % t] = _test_id_gen("textures", args_create=(DUMMY_NAME, t))
+del ns
+
+
+def main():
+ for fn_id, fn_val in sorted(globals().items()):
+ if fn_id.startswith("test_") and callable(fn_val):
+ fn_val(fn_id)
+
+ print("Error (total): %d" % GLOBALS["error_num"])
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/python/bl_rna_wiki_reference.py b/tests/python/bl_rna_manual_reference.py
index 5781c53c045..c67b6c1532b 100644
--- a/tests/python/bl_rna_wiki_reference.py
+++ b/tests/python/bl_rna_manual_reference.py
@@ -18,8 +18,8 @@
# <pep8 compliant>
-# Use for validating our wiki interlinking.
-# ./blender.bin --background -noaudio --python tests/python/bl_rna_wiki_reference.py
+# Use for validating our manual interlinking.
+# ./blender.bin --background -noaudio --python tests/python/bl_rna_manual_reference.py
#
# 1) test_data() -- ensure the data we have is correct format
# 2) test_lookup_coverage() -- ensure that we have lookups for _every_ RNA path
@@ -31,10 +31,10 @@ import bpy
def test_data():
- import rna_wiki_reference
+ import rna_manual_reference
- assert(isinstance(rna_wiki_reference.url_manual_mapping, tuple))
- for i, value in enumerate(rna_wiki_reference.url_manual_mapping):
+ assert(isinstance(rna_manual_reference.url_manual_mapping, tuple))
+ for i, value in enumerate(rna_manual_reference.url_manual_mapping):
try:
assert(len(value) == 2)
assert(isinstance(value[0], str))
@@ -92,14 +92,19 @@ def test_language_coverage():
def test_urls():
+ import os
import sys
- import rna_wiki_reference
+ import rna_manual_reference
import urllib.error
from urllib.request import urlopen
- prefix = rna_wiki_reference.url_manual_prefix
- urls = {suffix for (rna_id, suffix) in rna_wiki_reference.url_manual_mapping}
+ # avoid URL lookups if possible
+ LOCAL_PREFIX = os.environ.get("LOCAL_PREFIX")
+ if LOCAL_PREFIX is None:
+ prefix = rna_manual_reference.url_manual_prefix
+
+ urls = {suffix for (rna_id, suffix) in rna_manual_reference.url_manual_mapping}
urls_len = "%d" % len(urls)
print("")
@@ -113,16 +118,26 @@ def test_urls():
urls_fail = []
- for url in sorted(urls):
- url_full = prefix + url
- print(" %s ... " % url_full, end="")
- sys.stdout.flush()
- try:
- urlopen(url_full)
- print(color_green + "OK" + color_normal)
- except urllib.error.HTTPError:
- print(color_red + "FAIL!" + color_normal)
- urls_fail.append(url)
+ if LOCAL_PREFIX:
+ for url in sorted(urls):
+ url_full = os.path.join(LOCAL_PREFIX, url.partition("#")[0])
+ print(" %s ... " % url_full, end="")
+ if os.path.exists(url_full):
+ print(color_green + "OK" + color_normal)
+ else:
+ print(color_red + "FAIL!" + color_normal)
+ urls_fail.append(url)
+ else:
+ for url in sorted(urls):
+ url_full = prefix + url
+ print(" %s ... " % url_full, end="")
+ sys.stdout.flush()
+ try:
+ urlopen(url_full)
+ print(color_green + "OK" + color_normal)
+ except urllib.error.HTTPError:
+ print(color_red + "FAIL!" + color_normal)
+ urls_fail.append(url)
if urls_fail:
urls_len = "%d" % len(urls_fail)
diff --git a/tests/python/bl_rst_completeness.py b/tests/python/bl_rst_completeness.py
index d0ba2c552cf..d8dfac66d13 100644
--- a/tests/python/bl_rst_completeness.py
+++ b/tests/python/bl_rst_completeness.py
@@ -62,7 +62,7 @@ def is_directive_pydata(filepath, directive):
return True
elif directive.type in {"module", "note", "warning", "code-block", "hlist", "seealso"}:
return False
- elif directive.type in {"literalinclude"}: # TODO
+ elif directive.type == "literalinclude": # TODO
return False
else:
print(directive_to_str(filepath, directive), end=" ")
diff --git a/tests/python/bl_run_operators.py b/tests/python/bl_run_operators.py
index f7fafe833aa..f3c553cf3ef 100644
--- a/tests/python/bl_run_operators.py
+++ b/tests/python/bl_run_operators.py
@@ -34,6 +34,10 @@ RANDOM_SEED = [1] # so we can redo crashes
RANDOM_RESET = 0.1 # 10% chance of resetting on each new operator
RANDOM_MULTIPLY = 10
+STATE = {
+ "counter": 0,
+ }
+
op_blacklist = (
"script.reload",
@@ -75,6 +79,7 @@ op_blacklist = (
"wm.properties_context_change",
"wm.operator_cheat_sheet",
"wm.interface_theme_*",
+ "wm.previews_ensure", # slow - but harmless
"wm.appconfig_*", # just annoying - but harmless
"wm.keyitem_add", # just annoying - but harmless
"wm.keyconfig_activate", # just annoying - but harmless
@@ -158,7 +163,7 @@ if USE_ATTRSET:
if issubclass(cls, skip_classes):
continue
- ## to support skip-save we cant get all props
+ # # to support skip-save we cant get all props
# properties = cls.bl_rna.properties.keys()
properties = []
for prop_id, prop in cls.bl_rna.properties.items():
@@ -248,7 +253,8 @@ def run_ops(operators, setup_func=None, reset=True):
# first invoke
for op_id, op in operators:
if op.poll():
- print(" operator:", op_id)
+ print(" operator: %4d, %s" % (STATE["counter"], op_id))
+ STATE["counter"] += 1
sys.stdout.flush() # in case of crash
# disable will get blender in a bad state and crash easy!
diff --git a/tests/python/pep8.py b/tests/python/pep8.py
index 551e2a87e9b..0d6db729767 100644
--- a/tests/python/pep8.py
+++ b/tests/python/pep8.py
@@ -117,7 +117,18 @@ def main():
# these are very picky and often hard to follow
# while keeping common script formatting.
- ignore = "E122", "E123", "E124", "E125", "E126", "E127", "E128"
+ ignore = (
+ "E122",
+ "E123",
+ "E124",
+ "E125",
+ "E126",
+ "E127",
+ "E128",
+ # "imports not at top of file."
+ # prefer to load as needed (lazy load addons etc).
+ "E402",
+ )
for f, pep8_type in files:
diff --git a/tests/python/rst_to_doctree_mini.py b/tests/python/rst_to_doctree_mini.py
index 6a885a108f8..dfc6cd57db6 100644
--- a/tests/python/rst_to_doctree_mini.py
+++ b/tests/python/rst_to_doctree_mini.py
@@ -28,13 +28,14 @@
import collections
-Directive = collections.namedtuple('Directive',
- ("type",
- "value",
- "value_strip",
- "line",
- "indent",
- "members"))
+Directive = collections.namedtuple(
+ "Directive",
+ ("type",
+ "value",
+ "value_strip",
+ "line",
+ "indent",
+ "members"))
def parse_rst_py(filepath):
@@ -80,7 +81,7 @@ def parse_rst_py(filepath):
return tree[0]
-if __name__ == "__main__":
+def main():
# not intended use, but may as well print rst files passed as a test.
import sys
for arg in sys.argv:
@@ -88,3 +89,7 @@ if __name__ == "__main__":
items = parse_rst_py(arg)
for i in items:
print(i)
+
+
+if __name__ == "__main__":
+ main()